all database operations now take a context.Context, which is propagated through from sources

This commit is contained in:
2025-12-20 22:29:26 -07:00
parent 9e6bf2feda
commit 5c8bb8dd5e
39 changed files with 605 additions and 504 deletions
+4 -3
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"fmt"
"time"
@@ -113,12 +114,12 @@ func AmNewAudit(rectype int32, uid int32, ip string, data ...string) *AuditRecor
}
// Store stores the audit record in the database.
func (ar *AuditRecord) Store() error {
func (ar *AuditRecord) Store(ctx context.Context) error {
if ar.Record > 0 {
return fmt.Errorf("audit record %d already stored", ar.Record)
}
moment := time.Now().UTC()
rs, err := amdb.Exec(`INSERT INTO audit (on_date, event, uid, commid, ip, data1, data2, data3, data4)
rs, err := amdb.ExecContext(ctx, `INSERT INTO audit (on_date, event, uid, commid, ip, data1, data2, data3, data4)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);`, moment, ar.Event, ar.Uid, ar.CommId, ar.IP,
ar.Data1, ar.Data2, ar.Data3, ar.Data4)
if err != nil {
@@ -132,7 +133,7 @@ func (ar *AuditRecord) Store() error {
// auditWriter is the routine that stores audit records in trhe background.
func auditWriter(workChan chan *AuditRecord, doneChan chan bool) {
for ar := range workChan {
err := ar.Store()
err := ar.Store(context.Background())
if err != nil {
log.Errorf("dropped audit record (%+v) on the floor: %v", *ar, err)
}
+26 -21
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"errors"
"slices"
"strings"
@@ -45,12 +46,12 @@ var categoryIdMap map[int32]*Category = make(map[int32]*Category)
var categoryMutex sync.Mutex
// isCatEnabled determines if category features are enabled.
func isCatEnabled() (bool, error) {
g, err := AmGlobals()
func isCatEnabled(ctx context.Context) (bool, error) {
g, err := AmGlobals(ctx)
if err != nil {
return false, err
}
set, err := g.Flags()
set, err := g.Flags(ctx)
if err != nil {
return false, err
}
@@ -58,11 +59,11 @@ func isCatEnabled() (bool, error) {
}
// loadCategories loads the categories list from the database.
func loadCategories() error {
func loadCategories(ctx context.Context) error {
categoryMutex.Lock()
defer categoryMutex.Unlock()
if allCategories == nil {
rs, err := amdb.Query("SELECT COUNT(*) FROM refcategory")
rs, err := amdb.QueryContext(ctx, "SELECT COUNT(*) FROM refcategory")
if err != nil {
return err
}
@@ -72,7 +73,7 @@ func loadCategories() error {
var ncats int32
rs.Scan(&ncats)
allCategories = make([]Category, 0, ncats)
err = amdb.Select(&allCategories, "SELECT * FROM refcategory ORDER BY parent, name")
err = amdb.SelectContext(ctx, &allCategories, "SELECT * FROM refcategory ORDER BY parent, name")
if err != nil {
return err
}
@@ -85,20 +86,21 @@ func loadCategories() error {
/* AmGetCategory returns the category for the given name.
* Parameters:
* ctx - Standard Go context value.
* catid - The ID of the category to get.
* Returns:
* Pointer to the appropriate Category, or nil.
* Standard Go error status.
*/
func AmGetCategory(catid int32) (*Category, error) {
ok, err := isCatEnabled()
func AmGetCategory(ctx context.Context, catid int32) (*Category, error) {
ok, err := isCatEnabled(ctx)
if err != nil {
return nil, err
}
if !ok {
return nil, errors.New("category feature not supported")
}
err = loadCategories()
err = loadCategories(ctx)
if err != nil {
return nil, err
}
@@ -116,20 +118,21 @@ func AmGetCategory(catid int32) (*Category, error) {
/* AmGetCategoryHierarchy returns the category hierarchy for the given ID.
* Parameters:
* ctx - Standard Go context value.
* catid - The ID of the category to get.
* Returns:
* Array of pointers to the categories in hierarchical order, or nil.
* Standard Go error status.
*/
func AmGetCategoryHierarchy(catid int32) ([]*Category, error) {
ok, err := isCatEnabled()
func AmGetCategoryHierarchy(ctx context.Context, catid int32) ([]*Category, error) {
ok, err := isCatEnabled(ctx)
if err != nil {
return nil, err
}
if !ok {
return nil, errors.New("category feature not supported")
}
err = loadCategories()
err = loadCategories(ctx)
if err != nil {
return nil, err
}
@@ -154,20 +157,21 @@ func AmGetCategoryHierarchy(catid int32) ([]*Category, error) {
/* AmGetSubCategories returns a list of all subcategories of the given category ID.
* Parameters:
* ctx - Standard Go context value.
* catid - The parent category ID to use. May be -1 to return all "top level" categories.
* Returns:
* List of subcategories of this category.
* Standard Go error status.
*/
func AmGetSubCategories(catid int32) ([]*Category, error) {
ok, err := isCatEnabled()
func AmGetSubCategories(ctx context.Context, catid int32) ([]*Category, error) {
ok, err := isCatEnabled(ctx)
if err != nil {
return nil, err
}
if !ok {
return nil, errors.New("category feature not supported")
}
err = loadCategories()
err = loadCategories(ctx)
if err != nil {
return nil, err
}
@@ -185,6 +189,7 @@ func AmGetSubCategories(catid int32) ([]*Category, error) {
/* AmSearchCategories searches for categories matching certain criteria.
* Parameters:
* ctx - Standard Go context value.
* oper - The operation to perform on the category name:
* SearchCatOperPrefix - The category name has the string "term" as a prefix.
* SearchCatOperSubstring - The category name contains the string "term".
@@ -197,8 +202,8 @@ func AmGetSubCategories(catid int32) ([]*Category, error) {
* The total number of categories matching this query (could be greater than max)
* Standard Go error status.
*/
func AmSearchCategories(oper int, term string, offset int, max int, showAll bool, searchAll bool) ([]*Category, int, error) {
ok, err := isCatEnabled()
func AmSearchCategories(ctx context.Context, oper int, term string, offset int, max int, showAll bool, searchAll bool) ([]*Category, int, error) {
ok, err := isCatEnabled(ctx)
if err != nil {
return nil, -1, err
}
@@ -230,7 +235,7 @@ func AmSearchCategories(oper int, term string, offset int, max int, showAll bool
queryString.WriteString(" AND hide_search = 0")
}
q := queryString.String()
rs, err := amdb.Query("SELECT COUNT(*) FROM refcategory WHERE " + q)
rs, err := amdb.QueryContext(ctx, "SELECT COUNT(*) FROM refcategory WHERE "+q)
if err != nil {
return nil, -1, err
}
@@ -243,9 +248,9 @@ func AmSearchCategories(oper int, term string, offset int, max int, showAll bool
return make([]*Category, 0), 0, nil
}
if offset > 0 {
rs, err = amdb.Query("SELECT catid FROM refcategory WHERE "+q+" ORDER BY parent, name LIMIT ? OFFSET ?", max, offset)
rs, err = amdb.QueryContext(ctx, "SELECT catid FROM refcategory WHERE "+q+" ORDER BY parent, name LIMIT ? OFFSET ?", max, offset)
} else {
rs, err = amdb.Query("SELECT catid FROM refcategory WHERE "+q+" ORDER BY parent, name LIMIT ?", max)
rs, err = amdb.QueryContext(ctx, "SELECT catid FROM refcategory WHERE "+q+" ORDER BY parent, name LIMIT ?", max)
}
if err != nil {
return nil, total, err
@@ -254,7 +259,7 @@ func AmSearchCategories(oper int, term string, offset int, max int, showAll bool
for rs.Next() {
var catid int32
rs.Scan(&catid)
c, err := AmGetCategory(catid)
c, err := AmGetCategory(ctx, catid)
if err == nil {
rc = append(rc, c)
}
+107 -90
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"database/sql"
"errors"
"fmt"
@@ -151,27 +152,27 @@ func (c *Community) Public() bool {
}
// ContactInfo returns the contact info structure for the community.
func (c *Community) ContactInfo() (*ContactInfo, error) {
func (c *Community) ContactInfo(ctx context.Context) (*ContactInfo, error) {
if c.ContactId < 0 {
return nil, nil
}
return AmGetContactInfo(c.ContactId)
return AmGetContactInfo(ctx, c.ContactId)
}
// Host returns the reference to the host of the community.
func (c *Community) Host() (*User, error) {
func (c *Community) Host(ctx context.Context) (*User, error) {
if c.HostUid == nil {
return nil, nil
}
return AmGetUser(*c.HostUid)
return AmGetUser(ctx, *c.HostUid)
}
// HostQ returns the reference to the community's host, quietly.
func (c *Community) HostQ() *User {
func (c *Community) HostQ(ctx context.Context) *User {
if c.HostUid == nil {
return nil
}
u, err := AmGetUser(*c.HostUid)
u, err := AmGetUser(ctx, *c.HostUid)
if err != nil {
return nil
}
@@ -192,6 +193,7 @@ func (c *Community) LanguageTag() (*language.Tag, error) {
/* Membership returns the details of the specified user's membership in the community.
* Parameters:
* ctxt - Standard Go context value.
* u - The user to check the membership of.
* Returns:
* true if the user is a member, false if not.
@@ -199,7 +201,7 @@ func (c *Community) LanguageTag() (*language.Tag, error) {
* User's access level in the community, or 0 if the user is not a member.
* Standard Go error status.
*/
func (c *Community) Membership(u *User) (bool, bool, uint16, error) {
func (c *Community) Membership(ctx context.Context, u *User) (bool, bool, uint16, error) {
key := fmt.Sprintf("%d:%d", c.Id, u.Uid)
memberMutex.Lock()
defer memberMutex.Unlock()
@@ -212,7 +214,7 @@ func (c *Community) Membership(u *User) (bool, bool, uint16, error) {
// "no join required" - they are effectively a member, but don't cache that
return true, false, u.BaseLevel, nil
}
rs, err := amdb.Query("SELECT locked, granted_lvl FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
rs, err := amdb.QueryContext(ctx, "SELECT locked, granted_lvl FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
if err == nil {
if rs.Next() {
var locked bool
@@ -227,13 +229,13 @@ func (c *Community) Membership(u *User) (bool, bool, uint16, error) {
}
// MemberCount returns the number of members in the community.
func (c *Community) MemberCount(hidden bool) (int, error) {
func (c *Community) MemberCount(ctx context.Context, hidden bool) (int, error) {
var rs *sql.Rows
var err error
if hidden {
rs, err = amdb.Query("SELECT COUNT(*) FROM commmember WHERE commid = ?", c.Id)
rs, err = amdb.QueryContext(ctx, "SELECT COUNT(*) FROM commmember WHERE commid = ?", c.Id)
} else {
rs, err = amdb.Query("SELECT COUNT(*) FROM commmember WHERE commid = ? AND hidden = 0", c.Id)
rs, err = amdb.QueryContext(ctx, "SELECT COUNT(*) FROM commmember WHERE commid = ? AND hidden = 0", c.Id)
}
if err != nil {
return -1, err
@@ -248,6 +250,7 @@ func (c *Community) MemberCount(hidden bool) (int, error) {
/* ListMembers lists or searches for community members matching certain criteria.
* Parameters:
* ctx - Standard Go context value.
* field - A value indicating which field to search:
* ListMembersFieldNone - Do not search, just return all community members.
* ListMembersFieldName - The user name.
@@ -267,7 +270,7 @@ func (c *Community) MemberCount(hidden bool) (int, error) {
* The total number of members matching this query (could be greater than max)
* Standard Go error status.
*/
func (c *Community) ListMembers(field int, oper int, term string, offset int, max int, showHidden bool) ([]*User, int, error) {
func (c *Community) ListMembers(ctx context.Context, field int, oper int, term string, offset int, max int, showHidden bool) ([]*User, int, error) {
var query strings.Builder
if field != ListMembersFieldNone && oper != ListMembersOperNone {
query.WriteString(" AND ")
@@ -304,7 +307,7 @@ func (c *Community) ListMembers(field int, oper int, term string, offset int, ma
query.WriteString(" AND m.hidden = 0")
}
q := query.String()
rs, err := amdb.Query(`SELECT COUNT(*) FROM commmember m, users u, contacts c WHERE m.commid = ? AND m.uid = u.uid
rs, err := amdb.QueryContext(ctx, `SELECT COUNT(*) FROM commmember m, users u, contacts c WHERE m.commid = ? AND m.uid = u.uid
AND u.contactid = c.contactid`+q, c.Id)
if err != nil {
return nil, -1, err
@@ -315,10 +318,10 @@ func (c *Community) ListMembers(field int, oper int, term string, offset int, ma
var total int
rs.Scan(&total)
if offset > 0 {
rs, err = amdb.Query(`SELECT m.uid FROM commmember m, users u, contacts c WHERE m.commid = ? AND m.uid = u.uid
rs, err = amdb.QueryContext(ctx, `SELECT m.uid FROM commmember m, users u, contacts c WHERE m.commid = ? AND m.uid = u.uid
AND u.contactid = c.contactid`+q+" ORDER BY u.username LIMIT ? OFFSET ?", c.Id, max, offset)
} else {
rs, err = amdb.Query(`SELECT m.uid FROM commmember m, users u, contacts c WHERE m.commid = ? AND m.uid = u.uid
rs, err = amdb.QueryContext(ctx, `SELECT m.uid FROM commmember m, users u, contacts c WHERE m.commid = ? AND m.uid = u.uid
AND u.contactid = c.contactid`+q+" ORDER BY u.username LIMIT ?", c.Id, max)
}
if err != nil {
@@ -328,7 +331,7 @@ func (c *Community) ListMembers(field int, oper int, term string, offset int, ma
for rs.Next() {
var uid int32
rs.Scan(&uid)
u, err := AmGetUser(uid)
u, err := AmGetUser(ctx, uid)
if err == nil {
rc = append(rc, u)
}
@@ -338,6 +341,7 @@ func (c *Community) ListMembers(field int, oper int, term string, offset int, ma
/* SetMembership sets a user's membership status within the community.
* Parameters:
* ctx - Standard Go context value.
* u - The user to change the membership status of.
* level - Their membership level. If this is 0, they are removed from membership.
* locked - Whether they can unjoin the community themselves. Ignored if removing them.
@@ -346,7 +350,7 @@ func (c *Community) ListMembers(field int, oper int, term string, offset int, ma
* Returns:
* Standard Go error status.
*/
func (c *Community) SetMembership(u *User, level uint16, locked bool, personUID int32, ipaddr string) error {
func (c *Community) SetMembership(ctx context.Context, u *User, level uint16, locked bool, personUID int32, ipaddr string) error {
success := false
tx := amdb.MustBegin()
defer func() {
@@ -355,20 +359,20 @@ func (c *Community) SetMembership(u *User, level uint16, locked bool, personUID
}
}()
if level == 0 {
res, err := tx.Exec("DELETE FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
res, err := tx.ExecContext(ctx, "DELETE FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
if err != nil {
return err
}
stuffMembership(c.Id, u.Uid, false, false, 0)
ra, err := res.RowsAffected()
if err == nil && ra > 0 {
err = AmOnUserLeaveCommunityServices(tx, c, u)
err = AmOnUserLeaveCommunityServices(ctx, tx, c, u)
if err != nil {
return err
}
}
} else {
rs, err := tx.Query("SELECT granted_lvl, locked FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
rs, err := tx.QueryContext(ctx, "SELECT granted_lvl, locked FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
if err != nil {
return err
}
@@ -377,7 +381,7 @@ func (c *Community) SetMembership(u *User, level uint16, locked bool, personUID
var lockStatus bool
rs.Scan(&oldLevel, &lockStatus)
if level != oldLevel || lockStatus != locked {
_, err := tx.Exec("UPDATE commmember SET granted_lvl = ?, locked = ? WHERE commid = ? AND uid = ?",
_, err := tx.ExecContext(ctx, "UPDATE commmember SET granted_lvl = ?, locked = ? WHERE commid = ? AND uid = ?",
level, locked, c.Id, u.Uid)
if err != nil {
return err
@@ -385,19 +389,19 @@ func (c *Community) SetMembership(u *User, level uint16, locked bool, personUID
stuffMembership(c.Id, u.Uid, true, locked, level)
}
} else {
_, err := tx.Exec("INSERT INTO commmember (commid, uid, granted_lvl, locked) VALUES (?, ?, ?, ?)",
_, err := tx.ExecContext(ctx, "INSERT INTO commmember (commid, uid, granted_lvl, locked) VALUES (?, ?, ?, ?)",
c.Id, u.Uid, level, locked)
if err != nil {
return err
}
stuffMembership(c.Id, u.Uid, true, locked, level)
err = AmOnUserJoinCommunityServices(tx, c, u)
err = AmOnUserJoinCommunityServices(ctx, tx, c, u)
if err != nil {
return err
}
}
}
err := c.TouchUpdateTx(tx)
err := c.TouchUpdateTx(ctx, tx)
if err == nil {
ar := AmNewAudit(AuditCommunitySetMembership, personUID, ipaddr, fmt.Sprintf("cid=%d", c.Id),
fmt.Sprintf("uid=%d", u.Uid), fmt.Sprintf("level=%d", level))
@@ -450,11 +454,11 @@ func (c *Community) PermissionLevel(perm string) uint16 {
}
// GetFlags retrieves the flags from the properties.
func (c *Community) Flags() (*util.OptionSet, error) {
func (c *Community) Flags(ctx context.Context) (*util.OptionSet, error) {
c.Mutex.Lock()
defer c.Mutex.Unlock()
if c.flags == nil {
s, err := AmGetCommunityProperty(c.Id, CommunityPropFlags)
s, err := AmGetCommunityProperty(ctx, c.Id, CommunityPropFlags)
if err != nil {
return nil, err
}
@@ -468,11 +472,11 @@ func (c *Community) Flags() (*util.OptionSet, error) {
}
// SaveFlags writes the flags to the database and stores them.
func (c *Community) SaveFlags(f *util.OptionSet) error {
func (c *Community) SaveFlags(ctx context.Context, f *util.OptionSet) error {
s := f.AsString()
c.Mutex.Lock()
defer c.Mutex.Unlock()
err := AmSetCommunityProperty(c.Id, CommunityPropFlags, &s)
err := AmSetCommunityProperty(ctx, c.Id, CommunityPropFlags, &s)
if err == nil {
c.flags = f
}
@@ -480,12 +484,12 @@ func (c *Community) SaveFlags(f *util.OptionSet) error {
}
// SetProfileData sets all the "settable" profile data
func (c *Community) SetProfileData(name string, alias string, synopsis *string, rules *string, language *string,
func (c *Community) SetProfileData(ctx context.Context, name string, alias string, synopsis *string, rules *string, language *string,
joinkey *string, membersonly bool, hideDirectory bool, hideSearch bool, read_lvl uint16, write_lvl uint16,
create_lvl uint16, delete_lvl uint16, join_lvl uint16) error {
c.Mutex.Lock()
defer c.Mutex.Unlock()
_, err := amdb.Exec(`UPDATE communities SET commname = ?, alias = ?, synopsis = ?, rules = ?, language = ?,
_, err := amdb.ExecContext(ctx, `UPDATE communities SET commname = ?, alias = ?, synopsis = ?, rules = ?, language = ?,
joinkey = ?, membersonly = ?, hide_dir = ?, hide_search = ?, read_lvl = ?, write_lvl = ?, create_lvl = ?,
delete_lvl = ?, join_lvl = ?, lastupdate = NOW() WHERE commid = ?`,
name, alias, synopsis, rules, language, joinkey, membersonly, hideDirectory, hideSearch, read_lvl, write_lvl,
@@ -505,7 +509,7 @@ func (c *Community) SetProfileData(name string, alias string, synopsis *string,
c.CreateLevel = create_lvl
c.DeleteLevel = delete_lvl
c.JoinLevel = join_lvl
rs, err2 := amdb.Query("SELECT lastupdate FROM communities WHERE commid = ?", c.Id)
rs, err2 := amdb.QueryContext(ctx, "SELECT lastupdate FROM communities WHERE commid = ?", c.Id)
if err2 != nil {
rs.Next()
rs.Scan(&c.LastUpdate)
@@ -515,10 +519,10 @@ func (c *Community) SetProfileData(name string, alias string, synopsis *string,
}
// SetContactID sets the contact ID for the community.
func (c *Community) SetContactID(cid int32) error {
func (c *Community) SetContactID(ctx context.Context, cid int32) error {
c.Mutex.Lock()
defer c.Mutex.Unlock()
if _, err := amdb.Exec("UPDATE communities SET contactid = ? WHERE commid = ?", cid, c.Id); err != nil {
if _, err := amdb.ExecContext(ctx, "UPDATE communities SET contactid = ? WHERE commid = ?", cid, c.Id); err != nil {
return err
}
c.ContactId = cid
@@ -526,12 +530,12 @@ func (c *Community) SetContactID(cid int32) error {
}
// Touch updates the last access time of the community.
func (c *Community) Touch() error {
func (c *Community) Touch(ctx context.Context) error {
c.Mutex.Lock()
defer c.Mutex.Unlock()
_, err := amdb.Exec("UPDATE communities SET lastaccess = NOW() WHERE commid = ?", c.Id)
_, err := amdb.ExecContext(ctx, "UPDATE communities SET lastaccess = NOW() WHERE commid = ?", c.Id)
if err == nil {
rs, err := amdb.Query("SELECT lastaccess FROM communities WHERE commid = ?", c.Id)
rs, err := amdb.QueryContext(ctx, "SELECT lastaccess FROM communities WHERE commid = ?", c.Id)
if err == nil {
rs.Next()
var na time.Time
@@ -543,12 +547,12 @@ func (c *Community) Touch() error {
}
// TouchUpdateTx updates the last access and last update times of the community.
func (c *Community) TouchUpdateTx(tx *sqlx.Tx) error {
func (c *Community) TouchUpdateTx(ctx context.Context, tx *sqlx.Tx) error {
c.Mutex.Lock()
defer c.Mutex.Unlock()
_, err := tx.Exec("UPDATE communities SET lastaccess = NOW(), lastupdate = NOW() WHERE commid = ?", c.Id)
_, err := tx.ExecContext(ctx, "UPDATE communities SET lastaccess = NOW(), lastupdate = NOW() WHERE commid = ?", c.Id)
if err == nil {
rs, err := tx.Query("SELECT lastaccess, lastupdate FROM communities WHERE commid = ?", c.Id)
rs, err := tx.QueryContext(ctx, "SELECT lastaccess, lastupdate FROM communities WHERE commid = ?", c.Id)
if err != nil {
rs.Next()
var na, nu time.Time
@@ -561,9 +565,9 @@ func (c *Community) TouchUpdateTx(tx *sqlx.Tx) error {
}
// TouchUpdateTx updates the last access and last update times of the community.
func (c *Community) TouchUpdate() error {
func (c *Community) TouchUpdate(ctx context.Context) error {
tx := amdb.MustBegin()
err := c.TouchUpdateTx(tx)
err := c.TouchUpdateTx(ctx, tx)
if err != nil {
err = tx.Commit()
}
@@ -575,18 +579,19 @@ func (c *Community) TouchUpdate() error {
/* AmGetCommunity returns a reference to the specified community.
* Parameters:
* ctx - Standard Go context value.
* id - The ID of the community.
* Returns:
* Pointer to Community containing community data, or nil
* Standard Go error status
*/
func AmGetCommunity(id int32) (*Community, error) {
func AmGetCommunity(ctx context.Context, id int32) (*Community, error) {
getCommunityMutex.Lock()
defer getCommunityMutex.Unlock()
rc, ok := communityCache.Get(id)
if !ok {
var dbdata []Community
err := amdb.Select(&dbdata, "SELECT * from communities WHERE commid = ?", id)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * from communities WHERE commid = ?", id)
if err != nil {
return nil, err
}
@@ -603,19 +608,20 @@ func AmGetCommunity(id int32) (*Community, error) {
/* AmGetCommunityTx returns a reference to the specified community, in a transaction.
* Parameters:
* ctx - Standard Go context value.
* tx - The transaction to use.
* id - The ID of the community.
* Returns:
* Pointer to Community containing community data, or nil
* Standard Go error status
*/
func AmGetCommunityTx(tx *sqlx.Tx, id int32) (*Community, error) {
func AmGetCommunityTx(ctx context.Context, tx *sqlx.Tx, id int32) (*Community, error) {
getCommunityMutex.Lock()
defer getCommunityMutex.Unlock()
rc, ok := communityCache.Get(id)
if !ok {
var dbdata []Community
err := tx.Select(&dbdata, "SELECT * from communities WHERE commid = ?", id)
err := tx.SelectContext(ctx, &dbdata, "SELECT * from communities WHERE commid = ?", id)
if err != nil {
return nil, err
}
@@ -632,18 +638,19 @@ func AmGetCommunityTx(tx *sqlx.Tx, id int32) (*Community, error) {
/* AmGetCommunityByAlias returns a reference to the specified community.
* Parameters:
* ctx - Standard Go context value.
* alias - The alias for the community.
* Returns:
* Pointer to Community containing community data, or nil
* Standard Go error status (nil if community not found)
*/
func AmGetCommunityByAlias(alias string) (*Community, error) {
rs, err := amdb.Query("SELECT commid FROM communities WHERE alias = ?", alias)
func AmGetCommunityByAlias(ctx context.Context, alias string) (*Community, error) {
rs, err := amdb.QueryContext(ctx, "SELECT commid FROM communities WHERE alias = ?", alias)
if err == nil {
if rs.Next() {
var cid int32
rs.Scan(&cid)
return AmGetCommunity(cid)
return AmGetCommunity(ctx, cid)
} else {
return nil, nil
}
@@ -653,19 +660,20 @@ func AmGetCommunityByAlias(alias string) (*Community, error) {
/* AmGetCommunityByAliasTx returns a reference to the specified community, within a transaction.
* Parameters:
* ctx - Standard Go context value.
* tx - The transaction to use.
* alias - The alias for the community.
* Returns:
* Pointer to Community containing community data, or nil
* Standard Go error status (nil if community not found)
*/
func AmGetCommunityByAliasTx(tx *sqlx.Tx, alias string) (*Community, error) {
rs, err := tx.Query("SELECT commid FROM communities WHERE alias = ?", alias)
func AmGetCommunityByAliasTx(ctx context.Context, tx *sqlx.Tx, alias string) (*Community, error) {
rs, err := tx.QueryContext(ctx, "SELECT commid FROM communities WHERE alias = ?", alias)
if err == nil {
if rs.Next() {
var cid int32
rs.Scan(&cid)
return AmGetCommunityTx(tx, cid)
return AmGetCommunityTx(ctx, tx, cid)
} else {
return nil, nil
}
@@ -677,21 +685,22 @@ func AmGetCommunityByAliasTx(tx *sqlx.Tx, alias string) (*Community, error) {
* If the parameter is numeric, it's interpreted as a community ID. Otherwise, it's interpreted
* as a community alias.
* Parameters:
* ctx - Standard Go context value.
* id - The ID of the community.
* Returns:
* Pointer to Community containing community data, or nil
* Standard Go error status
*/
func AmGetCommunityFromParam(param string) (*Community, error) {
func AmGetCommunityFromParam(ctx context.Context, param string) (*Community, error) {
if util.IsNumeric(param) {
v, _ := strconv.Atoi(param)
c, err := AmGetCommunity(int32(v))
c, err := AmGetCommunity(ctx, int32(v))
if err == nil {
return c, nil
}
// else fall through to trying as alias
}
rc, err := AmGetCommunityByAlias(param)
rc, err := AmGetCommunityByAlias(ctx, param)
if err == nil {
if rc == nil {
return nil, fmt.Errorf("community with alias \"%s\" not found", param)
@@ -702,18 +711,19 @@ func AmGetCommunityFromParam(param string) (*Community, error) {
/* AmGetCommunitiesForUser returns a list of communities the user is a member of.
* Parameters:
* ctx - Standard Go context value.
* uid - The ID of the user.
* Returns:
* Array of pointers to communities for the user
* Standard Go error status
*/
func AmGetCommunitiesForUser(uid int32) ([]*Community, error) {
func AmGetCommunitiesForUser(ctx context.Context, uid int32) ([]*Community, error) {
var rc []*Community = make([]*Community, 0)
var ids []int32 = make([]int32, 0)
err := amdb.Select(&ids, "SELECT commid FROM commmember WHERE uid = ?", uid)
err := amdb.SelectContext(ctx, &ids, "SELECT commid FROM commmember WHERE uid = ?", uid)
if err == nil {
for _, id := range ids {
c, err := AmGetCommunity(id)
c, err := AmGetCommunity(ctx, id)
if err == nil {
rc = append(rc, c)
} else {
@@ -727,15 +737,16 @@ func AmGetCommunitiesForUser(uid int32) ([]*Community, error) {
/* AmGetCommunityAccessLevel returns the access level of the specified user with respect to the community.
* This may reflect the user's admin status as well as their status within the community.
* Parameters:
* ctx - Standard Go context value.
* uid - The UID of the user.
* commid - The ID of the community.
* Returns:
* Access level within the community, or 0 if the user is not a member.
* Standard Go error status.
*/
func AmGetCommunityAccessLevel(uid int32, commid int32) (uint16, error) {
func AmGetCommunityAccessLevel(ctx context.Context, uid int32, commid int32) (uint16, error) {
var rc uint16 = 0
rows, err := amdb.Queryx(`SELECT GREATEST(m.granted_lvl, u.base_lvl) AS level FROM users u, commmember m
rows, err := amdb.QueryxContext(ctx, `SELECT GREATEST(m.granted_lvl, u.base_lvl) AS level FROM users u, commmember m
WHERE u.uid = m.uid AND m.uid = ? AND m.commid = ?`, uid, commid)
if err == nil {
defer rows.Close()
@@ -748,21 +759,22 @@ func AmGetCommunityAccessLevel(uid int32, commid int32) (uint16, error) {
/* AmAutoJoinCommunities joins the specified user to any communities they're not yet a part of.
* Parameters:
* ctx - Standard Go context value.
* tx - The current transaction to be used for database access.
* user - The user to be auto-joined to communities.
* Returns:
* Standard Go error status.
*/
func AmAutoJoinCommunities(tx *sqlx.Tx, user *User) error {
func AmAutoJoinCommunities(ctx context.Context, tx *sqlx.Tx, user *User) error {
// get list of current communities
var current []int32 = make([]int32, 0)
err := tx.Select(&current, "SELECT commid FROM commmember WHERE uid = ?", user.Uid)
err := tx.SelectContext(ctx, &current, "SELECT commid FROM commmember WHERE uid = ?", user.Uid)
if err != nil {
return err
}
// look for candidate communities
rows, err := tx.Queryx(`SELECT m.commid, m.locked FROM users u, communities c, commmember m
rows, err := tx.QueryxContext(ctx, `SELECT m.commid, m.locked FROM users u, communities c, commmember m
WHERE m.uid = u.uid AND m.commid = c.commid AND u.is_anon = 1 AND c.join_lvl <= ?`, user.BaseLevel)
if err == nil {
defer rows.Close()
@@ -772,7 +784,7 @@ func AmAutoJoinCommunities(tx *sqlx.Tx, user *User) error {
var lock bool
rows.Scan(&cid, &lock)
if !slices.Contains(current, cid) {
_, err = tx.Exec("INSERT INTO commmember (commid, uid, granted_lvl, locked) VALUES (?, ?, ?, ?)",
_, err = tx.ExecContext(ctx, "INSERT INTO commmember (commid, uid, granted_lvl, locked) VALUES (?, ?, ?, ?)",
cid, user.Uid, grantLevel, lock)
if err != nil {
break
@@ -785,7 +797,7 @@ func AmAutoJoinCommunities(tx *sqlx.Tx, user *User) error {
}
// internalGetProp is a helper used by the property functions.
func internalGetCommProp(cid int32, ndx int32) (*CommunityProperties, error) {
func internalGetCommProp(ctx context.Context, cid int32, ndx int32) (*CommunityProperties, error) {
var err error = nil
key := fmt.Sprintf("%d:%d", cid, ndx)
getCommunityPropMutex.Lock()
@@ -793,7 +805,7 @@ func internalGetCommProp(cid int32, ndx int32) (*CommunityProperties, error) {
rc, ok := communityPropCache.Get(key)
if !ok {
var dbdata []CommunityProperties
err = amdb.Select(&dbdata, "SELECT * from propcomm WHERE cid = ? AND ndx = ?", cid, ndx)
err = amdb.SelectContext(ctx, &dbdata, "SELECT * from propcomm WHERE cid = ? AND ndx = ?", cid, ndx)
if err != nil {
return nil, err
}
@@ -811,14 +823,15 @@ func internalGetCommProp(cid int32, ndx int32) (*CommunityProperties, error) {
/* AmGetCommunityProperty retrieves the value of a user property.
* Parameters:
* ctx - Standard Go context value.
* cid - The ID of the community to get the property for.
* ndx - The index of the property to retrieve.
* Returns:
* Value of the property string.
* Standard Go error status.
*/
func AmGetCommunityProperty(cid int32, ndx int32) (*string, error) {
p, err := internalGetCommProp(cid, ndx)
func AmGetCommunityProperty(ctx context.Context, cid int32, ndx int32) (*string, error) {
p, err := internalGetCommProp(ctx, cid, ndx)
if err != nil {
return nil, err
} else if p == nil {
@@ -829,27 +842,28 @@ func AmGetCommunityProperty(cid int32, ndx int32) (*string, error) {
/* AmSetCommunityProperty sets the value of a community property.
* Parameters:
* ctx - Standard Go context value.
* cid - The ID of the community to set the property for.
* ndx - The index of the property to set.
* val - The new value of the property.
* Returns:
* Standard Go error status.
*/
func AmSetCommunityProperty(cid int32, ndx int32, val *string) error {
p, err := internalGetCommProp(cid, ndx)
func AmSetCommunityProperty(ctx context.Context, cid int32, ndx int32, val *string) error {
p, err := internalGetCommProp(ctx, cid, ndx)
if err != nil {
return err
}
getCommunityPropMutex.Lock()
defer getCommunityPropMutex.Unlock()
if p != nil {
_, err = amdb.Exec("UPDATE propcomm SET data = ? WHERE cid = ? AND ndx = ?", val, cid, ndx)
_, err = amdb.ExecContext(ctx, "UPDATE propcomm SET data = ? WHERE cid = ? AND ndx = ?", val, cid, ndx)
if err == nil {
p.Data = val
}
} else {
prop := CommunityProperties{Cid: cid, Index: ndx, Data: val}
_, err := amdb.NamedExec("INSERT INTO propcomm (cid, ndx, data) VALUES(:cid, :ndx, :data)", prop)
_, err := amdb.NamedExecContext(ctx, "INSERT INTO propcomm (cid, ndx, data) VALUES(:cid, :ndx, :data)", prop)
if err == nil {
communityPropCache.Add(fmt.Sprintf("%d:%d", cid, ndx), prop)
}
@@ -859,6 +873,7 @@ func AmSetCommunityProperty(cid int32, ndx int32, val *string) error {
/* AmCreateCommunity creates a new community.
* Parameters:
* ctx - Standard Go context value.
* name - The name for the new community.
* alias - The alias for the new community. Must be unique.
* hostUid - The UID of the creator and new host of the community.
@@ -873,7 +888,7 @@ func AmSetCommunityProperty(cid int32, ndx int32, val *string) error {
* Pointer to new Community record, or nil.
* Standard Go error status.
*/
func AmCreateCommunity(name string, alias string, hostUid int32, language *string, synopsis *string,
func AmCreateCommunity(ctx context.Context, name string, alias string, hostUid int32, language *string, synopsis *string,
rules *string, joinkey *string, hideDirectory bool, hideSearch bool, remoteIP string) (*Community, error) {
var ar *AuditRecord = nil
defer func() {
@@ -888,7 +903,7 @@ func AmCreateCommunity(name string, alias string, hostUid int32, language *strin
}()
// validate alias does not already exist
rs, err := tx.Query("SELECT commid FROM communities WHERE alias = ?", alias)
rs, err := tx.QueryContext(ctx, "SELECT commid FROM communities WHERE alias = ?", alias)
if err != nil {
return nil, err
}
@@ -897,7 +912,7 @@ func AmCreateCommunity(name string, alias string, hostUid int32, language *strin
}
// establish the community record
_, err = tx.Exec(`INSERT INTO communities (createdate, lastaccess, lastupdate, read_lvl, write_lvl,
_, err = tx.ExecContext(ctx, `INSERT INTO communities (createdate, lastaccess, lastupdate, read_lvl, write_lvl,
create_lvl, delete_lvl, join_lvl, host_uid, hide_dir, hide_search, commname, language,
synopsis, rules, joinkey, alias) VALUES (NOW(), NOW(), NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
AmRoleList("Community.Read").Default().Level(), AmRoleList("Community.Write").Default().Level(),
@@ -909,7 +924,7 @@ func AmCreateCommunity(name string, alias string, hostUid int32, language *strin
}
// Read back the community, which also puts it in the cache.
comm, err := AmGetCommunityByAliasTx(tx, alias)
comm, err := AmGetCommunityByAliasTx(ctx, tx, alias)
if err != nil {
return nil, err
} else if comm == nil {
@@ -918,7 +933,7 @@ func AmCreateCommunity(name string, alias string, hostUid int32, language *strin
// Ensure the new host has host privileges in the community. The host's membership is "locked" so they
// can't unjoin and leave the community hostless.
_, err = tx.Exec("INSERT INTO commmember (commid, uid, granted_lvl, locked) VALUES (?, ?, ?, 1)", comm.Id, hostUid,
_, err = tx.ExecContext(ctx, "INSERT INTO commmember (commid, uid, granted_lvl, locked) VALUES (?, ?, ?, 1)", comm.Id, hostUid,
AmDefaultRole("Community.Creator").Level())
if err != nil {
return nil, err
@@ -926,7 +941,7 @@ func AmCreateCommunity(name string, alias string, hostUid int32, language *strin
stuffMembership(comm.Id, hostUid, true, true, AmDefaultRole("Community.Creator").Level())
// Establish the community services.
err = AmEstablishCommunityServices(tx, comm)
err = AmEstablishCommunityServices(ctx, tx, comm)
if err != nil {
return nil, err
}
@@ -945,6 +960,7 @@ func AmCreateCommunity(name string, alias string, hostUid int32, language *strin
/* AmGetCommunitiesForCategory returns a list of communities for the specified category.
* Parameters:
* ctx - Standard Go context value.
* catid - Category ID to search for.
* offset - Number of communities to skip at beginning of list.
* max - Maximum number of communities to return.
@@ -954,13 +970,13 @@ func AmCreateCommunity(name string, alias string, hostUid int32, language *strin
* The total number of communities matching this query (could be greater than max)
* Standard Go error status.
*/
func AmGetCommunitiesForCategory(catid int32, offset int, max int, showAll bool) ([]*Community, int, error) {
func AmGetCommunitiesForCategory(ctx context.Context, catid int32, offset int, max int, showAll bool) ([]*Community, int, error) {
var rs *sql.Rows
var err error
if showAll {
rs, err = amdb.Query("SELECT COUNT(*) FROM communities WHERE catid = ?", catid)
rs, err = amdb.QueryContext(ctx, "SELECT COUNT(*) FROM communities WHERE catid = ?", catid)
} else {
rs, err = amdb.Query("SELECT COUNT(*) FROM communities WHERE catid = ? AND hide_dir = 0", catid)
rs, err = amdb.QueryContext(ctx, "SELECT COUNT(*) FROM communities WHERE catid = ? AND hide_dir = 0", catid)
}
if err != nil {
return nil, -1, err
@@ -975,17 +991,17 @@ func AmGetCommunitiesForCategory(catid int32, offset int, max int, showAll bool)
}
if showAll {
if offset > 0 {
rs, err = amdb.Query("SELECT commid FROM communities WHERE catid = ? ORDER BY commname LIMIT ? OFFSET ?",
rs, err = amdb.QueryContext(ctx, "SELECT commid FROM communities WHERE catid = ? ORDER BY commname LIMIT ? OFFSET ?",
catid, max, offset)
} else {
rs, err = amdb.Query("SELECT commid FROM communities WHERE catid = ? ORDER BY commname LIMIT ?", catid, max)
rs, err = amdb.QueryContext(ctx, "SELECT commid FROM communities WHERE catid = ? ORDER BY commname LIMIT ?", catid, max)
}
} else {
if offset > 0 {
rs, err = amdb.Query("SELECT commid FROM communities WHERE catid = ? AND hide_dir = 0 ORDER BY commname LIMIT ? OFFSET ?",
rs, err = amdb.QueryContext(ctx, "SELECT commid FROM communities WHERE catid = ? AND hide_dir = 0 ORDER BY commname LIMIT ? OFFSET ?",
catid, max, offset)
} else {
rs, err = amdb.Query("SELECT commid FROM communities WHERE catid = ? AND hide_dir = 0 ORDER BY commname LIMIT ?", catid, max)
rs, err = amdb.QueryContext(ctx, "SELECT commid FROM communities WHERE catid = ? AND hide_dir = 0 ORDER BY commname LIMIT ?", catid, max)
}
}
if err != nil {
@@ -995,7 +1011,7 @@ func AmGetCommunitiesForCategory(catid int32, offset int, max int, showAll bool)
for rs.Next() {
var commid int32
rs.Scan(&commid)
c, err := AmGetCommunity(commid)
c, err := AmGetCommunity(ctx, commid)
if err == nil {
rc = append(rc, c)
}
@@ -1005,6 +1021,7 @@ func AmGetCommunitiesForCategory(catid int32, offset int, max int, showAll bool)
/* AmSearchCommunities searches for communities matching certain criteria.
* Parameters:
* ctx - Standard Go context value.
* field - A value indicating which field to search:
* SearchCommFieldName - The community name.
* SearchCommFieldSynopsis - The communty synopsis.
@@ -1021,7 +1038,7 @@ func AmGetCommunitiesForCategory(catid int32, offset int, max int, showAll bool)
* The total number of communities matching this query (could be greater than max)
* Standard Go error status.
*/
func AmSearchCommunities(field int, oper int, term string, offset int, max int, showAll bool) ([]*Community, int, error) {
func AmSearchCommunities(ctx context.Context, field int, oper int, term string, offset int, max int, showAll bool) ([]*Community, int, error) {
var queryPortion strings.Builder
queryPortion.WriteString("WHERE ")
switch field {
@@ -1052,7 +1069,7 @@ func AmSearchCommunities(field int, oper int, term string, offset int, max int,
queryPortion.WriteString(" AND hide_search = 0")
}
q := queryPortion.String()
rs, err := amdb.Query("SELECT COUNT(*) FROM communities " + q)
rs, err := amdb.QueryContext(ctx, "SELECT COUNT(*) FROM communities "+q)
if err != nil {
return nil, -1, err
}
@@ -1065,9 +1082,9 @@ func AmSearchCommunities(field int, oper int, term string, offset int, max int,
return make([]*Community, 0), 0, nil // short-circuit return
}
if offset > 0 {
rs, err = amdb.Query("SELECT commid FROM communities "+q+" ORDER BY commname LIMIT ? OFFSET ?", max, offset)
rs, err = amdb.QueryContext(ctx, "SELECT commid FROM communities "+q+" ORDER BY commname LIMIT ? OFFSET ?", max, offset)
} else {
rs, err = amdb.Query("SELECT commid FROM communities "+q+" ORDER BY commname LIMIT ?", max)
rs, err = amdb.QueryContext(ctx, "SELECT commid FROM communities "+q+" ORDER BY commname LIMIT ?", max)
}
if err != nil {
return nil, total, err
@@ -1076,7 +1093,7 @@ func AmSearchCommunities(field int, oper int, term string, offset int, max int,
for rs.Next() {
var commid int32
rs.Scan(&commid)
c, err := AmGetCommunity(commid)
c, err := AmGetCommunity(ctx, commid)
if err == nil {
rc = append(rc, c)
}
+40 -35
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"errors"
"fmt"
"sync"
@@ -66,8 +67,8 @@ func init() {
}
// Aliases returns the list of aliases for this conference.
func (c *Conference) Aliases() ([]string, error) {
rs, err := amdb.Query("SELECT alias FROM confalias WHERE confid = ? ORDER BY alias", c.ConfId)
func (c *Conference) Aliases(ctx context.Context) ([]string, error) {
rs, err := amdb.QueryContext(ctx, "SELECT alias FROM confalias WHERE confid = ? ORDER BY alias", c.ConfId)
if err != nil {
return nil, err
}
@@ -81,14 +82,14 @@ func (c *Conference) Aliases() ([]string, error) {
}
// AliasesQ returns the list of aliases for this conference, quietly.
func (c *Conference) AliasesQ() []string {
rc, _ := c.Aliases()
func (c *Conference) AliasesQ(ctx context.Context) []string {
rc, _ := c.Aliases(ctx)
return rc
}
// Hosts returns the list of users that host this conference.
func (c *Conference) Hosts() ([]*User, error) {
rs, err := amdb.Query("SELECT uid FROM confmember WHERE confid = ? AND granted_lvl = ?",
func (c *Conference) Hosts(ctx context.Context) ([]*User, error) {
rs, err := amdb.QueryContext(ctx, "SELECT uid FROM confmember WHERE confid = ? AND granted_lvl = ?",
c.ConfId, AmRole("Conference.Host").Level())
if err != nil {
return nil, err
@@ -97,7 +98,7 @@ func (c *Conference) Hosts() ([]*User, error) {
for rs.Next() {
var uid int32
rs.Scan(&uid)
u, err := AmGetUser(uid)
u, err := AmGetUser(ctx, uid)
if err == nil {
rc = append(rc, u)
}
@@ -106,14 +107,14 @@ func (c *Conference) Hosts() ([]*User, error) {
}
// Hosts returns the list of users that host this conference, quietly.
func (c *Conference) HostsQ() []*User {
rc, _ := c.Hosts()
func (c *Conference) HostsQ(ctx context.Context) []*User {
rc, _ := c.Hosts(ctx)
return rc
}
// Membership returns a membership flag and granted level for the user in this conference.
func (c *Conference) Membership(u *User) (bool, uint16, error) {
rs, err := amdb.Query("SELECT granted_lvl FROM confmember WHERE confid = ? AND uid = ?", c.ConfId, u.Uid)
func (c *Conference) Membership(ctx context.Context, u *User) (bool, uint16, error) {
rs, err := amdb.QueryContext(ctx, "SELECT granted_lvl FROM confmember WHERE confid = ? AND uid = ?", c.ConfId, u.Uid)
if err != nil {
return false, 0, err
}
@@ -155,9 +156,9 @@ func (c *Conference) TestPermission(perm string, level uint16) bool {
}
// Settings returns the settings for a user.
func (c *Conference) Settings(u *User) (*ConferenceSettings, error) {
func (c *Conference) Settings(ctx context.Context, u *User) (*ConferenceSettings, error) {
var dbdata []ConferenceSettings
err := amdb.Select(&dbdata, "SELECT * FROM confsettings WHERE confid = ? AND uid = ?", c.ConfId, u.Uid)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM confsettings WHERE confid = ? AND uid = ?", c.ConfId, u.Uid)
if err != nil {
return nil, err
}
@@ -171,24 +172,24 @@ func (c *Conference) Settings(u *User) (*ConferenceSettings, error) {
}
// TouchRead updates the "last posted" date/time in the conference for the user.
func (c *Conference) TouchRead(tx *sqlx.Tx, u *User) (*ConferenceSettings, error) {
cs, err := c.Settings(u)
func (c *Conference) TouchRead(ctx context.Context, tx *sqlx.Tx, u *User) (*ConferenceSettings, error) {
cs, err := c.Settings(ctx, u)
if err != nil {
return nil, err
}
if !u.IsAnon { // anon user can't update squat
if cs == nil {
ci, cerr := u.ContactInfo()
ci, cerr := u.ContactInfo(ctx)
if cerr != nil {
return nil, cerr
}
_, err = tx.Exec("INSERT INTO confsettings (confid, uid, default_pseud, last_read) VALUES (?, ?, ?, NOW())",
_, err = tx.ExecContext(ctx, "INSERT INTO confsettings (confid, uid, default_pseud, last_read) VALUES (?, ?, ?, NOW())",
c.ConfId, u.Uid, ci.FullName(false))
} else {
_, err = tx.Exec("UPDATE confsettings SET last_read = NOW() WHERE confid = ? AND uid = ?", c.ConfId, u.Uid)
_, err = tx.ExecContext(ctx, "UPDATE confsettings SET last_read = NOW() WHERE confid = ? AND uid = ?", c.ConfId, u.Uid)
}
if err == nil {
cs, err = c.Settings(u) // reread to get updated or inserted values
cs, err = c.Settings(ctx, u) // reread to get updated or inserted values
}
if err != nil {
return nil, err
@@ -198,14 +199,14 @@ func (c *Conference) TouchRead(tx *sqlx.Tx, u *User) (*ConferenceSettings, error
}
// TouchPost updates the "last posted" date/time in the conference for the user.
func (c *Conference) TouchPost(tx *sqlx.Tx, u *User, lastPost time.Time) (*ConferenceSettings, error) {
cs, err := c.Settings(u)
func (c *Conference) TouchPost(ctx context.Context, tx *sqlx.Tx, u *User, lastPost time.Time) (*ConferenceSettings, error) {
cs, err := c.Settings(ctx, u)
if err != nil {
return nil, err
}
if !u.IsAnon { // anon user can't update squat
if cs == nil {
ci, cerr := u.ContactInfo()
ci, cerr := u.ContactInfo(ctx)
if cerr != nil {
return nil, cerr
}
@@ -217,10 +218,10 @@ func (c *Conference) TouchPost(tx *sqlx.Tx, u *User, lastPost time.Time) (*Confe
LastRead: &lastPost,
LastPost: &lastPost,
}
_, err = tx.Exec("INSERT INTO confsettings (confid, uid, default_pseud, last_read, last_post) VALUES (?, ?, ?, ?, ?)",
_, err = tx.ExecContext(ctx, "INSERT INTO confsettings (confid, uid, default_pseud, last_read, last_post) VALUES (?, ?, ?, ?, ?)",
c.ConfId, u.Uid, defaultPseud, lastPost, lastPost)
} else {
_, err = tx.Exec("UPDATE confsettings SET last_post = ? WHERE confid = ? AND uid = ?", lastPost, c.ConfId, u.Uid)
_, err = tx.ExecContext(ctx, "UPDATE confsettings SET last_post = ? WHERE confid = ? AND uid = ?", lastPost, c.ConfId, u.Uid)
cs.LastPost = &lastPost
}
if err != nil {
@@ -232,19 +233,20 @@ func (c *Conference) TouchPost(tx *sqlx.Tx, u *User, lastPost time.Time) (*Confe
/* AmGetConference returns a conference given its ID.
* Parameters:
* ctx - Standard Go context value.
* id - The ID of the conference.
* Returns:
* Pointer to the conference, or nil.
* Standard Go error status.
*/
func AmGetConference(id int32) (*Conference, error) {
func AmGetConference(ctx context.Context, id int32) (*Conference, error) {
var err error = nil
getConferenceMutex.Lock()
defer getConferenceMutex.Unlock()
rc, ok := conferenceCache.Get(id)
if !ok {
var dbdata []Conference
err = amdb.Select(&dbdata, "SELECT * from confs where confid = ?", id)
err = amdb.SelectContext(ctx, &dbdata, "SELECT * from confs where confid = ?", id)
if err != nil {
return nil, err
}
@@ -261,18 +263,19 @@ func AmGetConference(id int32) (*Conference, error) {
/* AmGetConferenceByAlias returns a conference given its alias.
* Parameters:
* ctx - Standard Go context value.
* alias - The alias to look up.
* Returns:
* Pointer to the conference, or nil.
* Standard Go error status.
*/
func AmGetConferenceByAlias(alias string) (*Conference, error) {
func AmGetConferenceByAlias(ctx context.Context, alias string) (*Conference, error) {
var confid int32
xconf, ok := conferenceAliasMap.Load(alias)
if ok {
confid = xconf.(int32)
} else {
rs, err := amdb.Query("SELECT confid FROM confalias WHERE alias = ?", alias)
rs, err := amdb.QueryContext(ctx, "SELECT confid FROM confalias WHERE alias = ?", alias)
if err != nil {
return nil, err
}
@@ -282,19 +285,20 @@ func AmGetConferenceByAlias(alias string) (*Conference, error) {
rs.Scan(&confid)
conferenceAliasMap.Store(alias, confid)
}
return AmGetConference(confid)
return AmGetConference(ctx, confid)
}
/* AmGetConferenceByAliasInCommunity returns a conference in a community given its alias.
* Parameters:
* ctx - Standard Go context value.
* cid - The community to look inside.
* alias - The alias to look up.
* Returns:
* Pointer to the conference, or nil.
* Standard Go error status.
*/
func AmGetConferenceByAliasInCommunity(cid int32, alias string) (*Conference, error) {
rs, err := amdb.Query(`SELECT c.confid FROM commtoconf c, confalias a WHERE c.confid = a.confid
func AmGetConferenceByAliasInCommunity(ctx context.Context, cid int32, alias string) (*Conference, error) {
rs, err := amdb.QueryContext(ctx, `SELECT c.confid FROM commtoconf c, confalias a WHERE c.confid = a.confid
AND c.commid = ? AND a.alias = ?`, cid, alias)
if err != nil {
return nil, err
@@ -304,23 +308,24 @@ func AmGetConferenceByAliasInCommunity(cid int32, alias string) (*Conference, er
}
var confid int32
rs.Scan(&confid)
return AmGetConference(confid)
return AmGetConference(ctx, confid)
}
/* AmGetCommunityConferences returns all conferences for a given community.
* Parameters:
* ctx - Standard Go context value.
* cid - Community ID to get conferences for.
* showHidden - true to show hidden conferences.
* Returns:
* Array containing the COnference pointers, or nil.
* Stanbard Go error status.
*/
func AmGetCommunityConferences(cid int32, showHidden bool) ([]*Conference, error) {
func AmGetCommunityConferences(ctx context.Context, cid int32, showHidden bool) ([]*Conference, error) {
q := ""
if !showHidden {
q = " AND x.hide_list = 0"
}
rs, err := amdb.Query(`SELECT x.confid FROM commtoconf x, confs c WHERE x.confid = c.confid
rs, err := amdb.QueryContext(ctx, `SELECT x.confid FROM commtoconf x, confs c WHERE x.confid = c.confid
AND x.commid = ?`+q+" ORDER BY x.sequence, c.name", cid)
if err != nil {
return nil, err
@@ -329,7 +334,7 @@ func AmGetCommunityConferences(cid int32, showHidden bool) ([]*Conference, error
for rs.Next() {
var confid int32
rs.Scan(&confid)
conf, err := AmGetConference(confid)
conf, err := AmGetConference(ctx, confid)
if err == nil {
rc = append(rc, conf)
}
+19 -15
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"errors"
"fmt"
"strings"
@@ -51,9 +52,9 @@ type ContactInfo struct {
}
// lookupCommunityContact looks up the ID of a contact for a community.
func lookupCommunityContact(id int32) (int32, error) {
func lookupCommunityContact(ctx context.Context, id int32) (int32, error) {
var rc int32 = -1
rs, err := amdb.Query("SELECT contactid FROM contacts WHERE owner_commid = ?", id)
rs, err := amdb.QueryContext(ctx, "SELECT contactid FROM contacts WHERE owner_commid = ?", id)
if err == nil {
if rs.Next() {
rs.Scan(&rc)
@@ -63,9 +64,9 @@ func lookupCommunityContact(id int32) (int32, error) {
}
// lookupUserContact looks up the ID of a contact for a user.
func lookupUserContact(uid int32) (int32, error) {
func lookupUserContact(ctx context.Context, uid int32) (int32, error) {
var rc int32 = -1
rs, err := amdb.Query("SELECT contactid FROM contacts WHERE owner_uid = ? AND owner_commid = -1", uid)
rs, err := amdb.QueryContext(ctx, "SELECT contactid FROM contacts WHERE owner_uid = ? AND owner_commid = -1", uid)
if err == nil {
if rs.Next() {
rs.Scan(&rc)
@@ -114,11 +115,13 @@ func (ci *ContactInfo) FullName(ps bool) string {
}
/* Save saves the contact info to the database.
* Parameters:
* ctx - Standard Go context value.
* Returns:
* true if the E-mail address on this account has been changed, false if not.
* Standard Go error status.
*/
func (ci *ContactInfo) Save() (bool, error) {
func (ci *ContactInfo) Save(ctx context.Context) (bool, error) {
ci.Mutex.Lock()
defer ci.Mutex.Unlock()
@@ -129,9 +132,9 @@ func (ci *ContactInfo) Save() (bool, error) {
var nx int32
var err error
if ci.OwnerCommId > 0 {
nx, err = lookupCommunityContact(ci.OwnerCommId)
nx, err = lookupCommunityContact(ctx, ci.OwnerCommId)
} else {
nx, err = lookupUserContact(ci.OwnerUid)
nx, err = lookupUserContact(ctx, ci.OwnerUid)
}
if err != nil {
return false, err
@@ -147,7 +150,7 @@ func (ci *ContactInfo) Save() (bool, error) {
}
if !emailChange {
// we don't THINK the E-mail address is changing, but we could be wrong...
rs, err := amdb.Query("SELECT contactid FROM contacts WHERE contactid = ? AND email = ?", ci.ContactId, ci.Email)
rs, err := amdb.QueryContext(ctx, "SELECT contactid FROM contacts WHERE contactid = ? AND email = ?", ci.ContactId, ci.Email)
if err != nil {
return false, err
}
@@ -157,7 +160,7 @@ func (ci *ContactInfo) Save() (bool, error) {
}
// Handle the database heavy lifting.
if updateMode {
_, err := amdb.NamedExec(`UPDATE contacts SET given_name = :given_name, family_name = :family_name, middle_init = :middle_init,
_, err := amdb.NamedExecContext(ctx, `UPDATE contacts SET given_name = :given_name, family_name = :family_name, middle_init = :middle_init,
prefix = :prefix, suffix = :suffix, company = :company, addr1 = :addr1, addr2 = :addr2, locality = :locality, region = :region,
pcode = :pcode, country = :country, phone = :phone, fax = :fax, mobile = :mobile, email = :email, pvt_addr = :pvt_addr,
pvt_phone = :pvt_phone, pvt_fax = :pvt_fax, pvt_email = :pvt_email, photo_url = :photo_url, url = :url, lastupdate = NOW()
@@ -167,7 +170,7 @@ func (ci *ContactInfo) Save() (bool, error) {
}
contactCache.Add(ci.ContactId, ci)
} else {
res, err := amdb.NamedExec(`INSERT INTO contacts (given_name, family_name, middle_init, prefix, suffix, company, addr1,
res, err := amdb.NamedExecContext(ctx, `INSERT INTO contacts (given_name, family_name, middle_init, prefix, suffix, company, addr1,
addr2, locality, region, pcode, country, phone, fax, mobile, email, pvt_addr, pvt_phone, pvt_fax,
pvt_email, owner_uid, owner_commid, photo_url, url, lastupdate)
VALUES (:given_name, :family_name, :middle_init, :prefix, :suffix, :company, :addr1, :addr2, :locality,
@@ -181,7 +184,7 @@ func (ci *ContactInfo) Save() (bool, error) {
contactCache.Add(ci.ContactId, ci)
}
// Refresh the last update date.
rs, err := amdb.Query("SELECT lastupdate FROM contacts WHERE contactid = ?", ci.ContactId)
rs, err := amdb.QueryContext(ctx, "SELECT lastupdate FROM contacts WHERE contactid = ?", ci.ContactId)
if err != nil {
return false, err
}
@@ -241,9 +244,9 @@ func init() {
}
// internalContactInfo retrieves the contact info from the database.
func internalContactInfo(id int32) (*ContactInfo, error) {
func internalContactInfo(ctx context.Context, id int32) (*ContactInfo, error) {
var dbdata []ContactInfo
err := amdb.Select(&dbdata, "SELECT * from contacts WHERE contactid = ?", id)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * from contacts WHERE contactid = ?", id)
if err == nil {
if len(dbdata) > 1 {
err = fmt.Errorf("internalContactInfo(%d): Too many responses (%d)", id, len(dbdata))
@@ -258,19 +261,20 @@ func internalContactInfo(id int32) (*ContactInfo, error) {
/* AmGetContactInfo retrieves the contact info for a given identifier.
* Parameters:
* ctx - Standard Go context value.
* id - The contact info ID top retrieve.
* Returns:
* ContactInfo retrieved, or nil.
* Standard Go error status.
*/
func AmGetContactInfo(id int32) (*ContactInfo, error) {
func AmGetContactInfo(ctx context.Context, id int32) (*ContactInfo, error) {
getContactMutex.Lock()
defer getContactMutex.Unlock()
rc, ok := contactCache.Get(id)
if ok {
return rc.(*ContactInfo), nil
}
rc2, err := internalContactInfo(id)
rc2, err := internalContactInfo(ctx, id)
if err == nil {
if rc2 != nil {
contactCache.Add(id, rc2)
+5 -2
View File
@@ -9,15 +9,18 @@
// The database package contains database management and storage logic.
package database
import "context"
/* AmIsEmailAddressBanned returns true if the given E-mail address is on the "banned" list.
* Parameters:
* ctx - Standard Go context value.
* address - The E-mail address to be checked.
* Returns:
* true if the address is banned, false if not.
* Standard Go error status.
*/
func AmIsEmailAddressBanned(address string) (bool, error) {
rs, err := amdb.Query("SELECT by_uid FROM emailban WHERE address = ?", address)
func AmIsEmailAddressBanned(ctx context.Context, address string) (bool, error) {
rs, err := amdb.QueryContext(ctx, "SELECT by_uid FROM emailban WHERE address = ?", address)
if err != nil {
return false, err
}
+15 -12
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"errors"
"sync"
@@ -60,11 +61,11 @@ var globalProps map[int32]string = make(map[int32]string)
var globalPropMutex sync.Mutex
// Flags returns the global flags.
func (g *Globals) Flags() (*util.OptionSet, error) {
func (g *Globals) Flags(ctx context.Context) (*util.OptionSet, error) {
g.Mutex.Lock()
defer g.Mutex.Unlock()
if g.flags == nil {
s, err := AmGetGlobalProperty(GlobalPropFlags)
s, err := AmGetGlobalProperty(ctx, GlobalPropFlags)
if err != nil {
return nil, err
}
@@ -74,11 +75,11 @@ func (g *Globals) Flags() (*util.OptionSet, error) {
}
// SaveFlags saves off the global flags.
func (g *Globals) SaveFlags(f *util.OptionSet) error {
func (g *Globals) SaveFlags(ctx context.Context, f *util.OptionSet) error {
s := f.AsString()
g.Mutex.Lock()
defer g.Mutex.Unlock()
err := AmSetGlobalProperty(GlobalPropFlags, s)
err := AmSetGlobalProperty(ctx, GlobalPropFlags, s)
if err == nil {
g.flags = f
}
@@ -86,12 +87,12 @@ func (g *Globals) SaveFlags(f *util.OptionSet) error {
}
// AmGlobals returns trhe pointer to the singleton Globals instance.
func AmGlobals() (*Globals, error) {
func AmGlobals(ctx context.Context) (*Globals, error) {
globalsMutex.Lock()
defer globalsMutex.Unlock()
if theGlobals == nil {
var dbdata []Globals
err := amdb.Select(&dbdata, "SELECT * FROM globals")
err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM globals")
if err != nil {
return nil, err
}
@@ -105,17 +106,18 @@ func AmGlobals() (*Globals, error) {
/* 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(index int32) (string, error) {
func AmGetGlobalProperty(ctx context.Context, index int32) (string, error) {
globalPropMutex.Lock()
defer globalPropMutex.Unlock()
rc, ok := globalProps[index]
if !ok {
rs, err := amdb.Query("SELECT data FROM propglobal WHERE ndx = ?", index)
rs, err := amdb.QueryContext(ctx, "SELECT data FROM propglobal WHERE ndx = ?", index)
if err != nil {
return "", err
}
@@ -131,17 +133,18 @@ func AmGetGlobalProperty(index int32) (string, error) {
/* 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(index int32, value string) error {
func AmSetGlobalProperty(ctx context.Context, index int32, value string) error {
globalPropMutex.Lock()
defer globalPropMutex.Unlock()
_, updateMode := globalProps[index]
if !updateMode {
rs, err := amdb.Query("SELECT data FROM propglobal WHERE ndx = ?", index)
rs, err := amdb.QueryContext(ctx, "SELECT data FROM propglobal WHERE ndx = ?", index)
if err != nil {
return err
}
@@ -149,9 +152,9 @@ func AmSetGlobalProperty(index int32, value string) error {
}
var err error = nil
if updateMode {
_, err = amdb.Exec("UPDATE propglobal SET data = ? WHERE ndx = ?", value, index)
_, err = amdb.ExecContext(ctx, "UPDATE propglobal SET data = ? WHERE ndx = ?", value, index)
} else {
_, err = amdb.Exec("INSERT INTO propglobal (ndx, data) VALUES (?, ?)", index, value)
_, err = amdb.ExecContext(ctx, "INSERT INTO propglobal (ndx, data) VALUES (?, ?)", index, value)
}
if err == nil {
globalProps[index] = value
+15 -11
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"database/sql"
"fmt"
)
@@ -31,14 +32,14 @@ const (
)
// Save persists the ImageStore record to the database.
func (img *ImageStore) Save() error {
func (img *ImageStore) Save(ctx context.Context) error {
var err error
if img.ImgId > 0 {
_, err = amdb.NamedExec(`UPDATE imagestore SET typecode = :typecode, ownerid = :ownerid, mimetype = :mimetype,
_, err = amdb.NamedExecContext(ctx, `UPDATE imagestore SET typecode = :typecode, ownerid = :ownerid, mimetype = :mimetype,
length = :length, data = :data WHERE imgid = :imgid`, img)
} else {
var rs sql.Result
rs, err = amdb.NamedExec(`INSERT INTO imagestore (typecode, ownerid, mimetype, length, data)
rs, err = amdb.NamedExecContext(ctx, `INSERT INTO imagestore (typecode, ownerid, mimetype, length, data)
VALUES (:typecode, :ownerid, :mimetype, :length, :data)`, img)
if err == nil {
var lii int64
@@ -53,14 +54,15 @@ func (img *ImageStore) Save() error {
/* AmLoadImage loads an image from the database.
* Parameters:
* ctx - Standard Go context value.
* id - The ID of the image to be loaded.
* Returns:
* Pointer to ImageStore, or nil.
* Standard Go error status.
*/
func AmLoadImage(id int32) (*ImageStore, error) {
func AmLoadImage(ctx context.Context, id int32) (*ImageStore, error) {
var dbdata []ImageStore
err := amdb.Select(&dbdata, "SELECT * FROM imagestore WHERE imgid = ?", id)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM imagestore WHERE imgid = ?", id)
if err != nil {
return nil, err
}
@@ -74,6 +76,7 @@ func AmLoadImage(id int32) (*ImageStore, error) {
/* AmStoreImage stores an image in the database, overwriting one with the same type code and owner if it exists.
* Parameters:
* ctx - Standard Go context value.
* typecode - Type code for the image.
* owner - Owner Id for the image (UID or community ID)
* mimetype - MIME type of the image.
@@ -82,8 +85,8 @@ func AmLoadImage(id int32) (*ImageStore, error) {
* Pointer to ImageStore, or nil.
* Standard Go error status.
*/
func AmStoreImage(typecode int16, owner int32, mimetype string, data []byte) (*ImageStore, error) {
rs, err := amdb.Query("SELECT imgid FROM imagestore WHERE typecode = ? AND ownerid = ?", typecode, owner)
func AmStoreImage(ctx context.Context, typecode int16, owner int32, mimetype string, data []byte) (*ImageStore, error) {
rs, err := amdb.QueryContext(ctx, "SELECT imgid FROM imagestore WHERE typecode = ? AND ownerid = ?", typecode, owner)
if err != nil {
return nil, err
}
@@ -91,7 +94,7 @@ func AmStoreImage(typecode int16, owner int32, mimetype string, data []byte) (*I
if rs.Next() {
var id int32
rs.Scan(&id)
img, err = AmLoadImage(id)
img, err = AmLoadImage(ctx, id)
if err != nil {
return nil, err
}
@@ -108,7 +111,7 @@ func AmStoreImage(typecode int16, owner int32, mimetype string, data []byte) (*I
Data: data,
}
}
err = img.Save()
err = img.Save(ctx)
if err != nil {
return nil, err
}
@@ -117,11 +120,12 @@ func AmStoreImage(typecode int16, owner int32, mimetype string, data []byte) (*I
/* AmDeleteImage erases an image from the database.
* Parameters:
* ctx - Standard Go context value.
* id - The ID of the image to be deleted.
* Returns:
* Standard Go error status.
*/
func AmDeleteImage(id int32) error {
_, err := amdb.Exec("DELETE FROM imagestore WHERE imgid = ?", id)
func AmDeleteImage(ctx context.Context, id int32) error {
_, err := amdb.ExecContext(ctx, "DELETE FROM imagestore WHERE imgid = ?", id)
return err
}
+4 -3
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"fmt"
"math/big"
"net"
@@ -40,12 +41,13 @@ func init() {
/* AmTestIPBan tests an IP address to see if it's on the banned list.
* Parameters:
* ctx - Standard Go context parameter.
* ip_address - The IP address to be tested.
* Returns:
* Ban message if the address is banned, or empty string if it isn't.
* Standard Go error status.
*/
func AmTestIPBan(ip_address string) (string, error) {
func AmTestIPBan(ctx context.Context, ip_address string) (string, error) {
banMutex.Lock()
defer banMutex.Unlock()
rc := knownBans[ip_address]
@@ -63,8 +65,7 @@ func AmTestIPBan(ip_address string) (string, error) {
iv.SetBytes(addr)
iv_lo := big.NewInt(0).And(iv, low64mask).Uint64()
iv_hi := big.NewInt(0).Rsh(iv, 64).Uint64()
rows, err := amdb.Query(`
SELECT message FROM ipban WHERE (address_lo & mask_lo) = (? & mask_lo)
rows, err := amdb.QueryContext(ctx, `SELECT message FROM ipban WHERE (address_lo & mask_lo) = (? & mask_lo)
AND (address_hi & mask_hi) = (? & mask_hi) AND (expire IS NULL OR expire >= ?)
AND enable <> 0 ORDER BY mask_hi DESC, mask_lo DESC`, iv_lo, iv_hi, time.Now().UTC())
if err != nil {
+10 -8
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"errors"
"fmt"
"time"
@@ -43,6 +44,7 @@ func (p *PostHeader) IsScribbled() bool {
/* SetAttachment sets the attachment data for a post.
* Parameters:
* ctx - Standard Go context value.
* fileName - Name of the original attachment file.
* mimeType - MIME type of the attachment data.
* length - Length of the attachment data in bytes.
@@ -50,16 +52,16 @@ func (p *PostHeader) IsScribbled() bool {
* Returns:
* Standard Go error status.
*/
func (p *PostHeader) SetAttachment(fileName string, mimeType string, length int32, data []byte) error {
_, err := amdb.Exec("INSERT INTO postattach (postid, datalen, filename, mimetype, data) VALUES (?, ?, ?, ?, ?)",
func (p *PostHeader) SetAttachment(ctx context.Context, fileName string, mimeType string, length int32, data []byte) error {
_, err := amdb.ExecContext(ctx, "INSERT INTO postattach (postid, datalen, filename, mimetype, data) VALUES (?, ?, ?, ?, ?)",
p.PostId, length, fileName, mimeType, data)
return err
}
// Text returns the text associated with a post.
func (p *PostHeader) Text() (string, error) {
func (p *PostHeader) Text(ctx context.Context) (string, error) {
var dbdata []PostData
err := amdb.Select(&dbdata, "SELECT * FROM postdata WHERE postid = ?", p.PostId)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM postdata WHERE postid = ?", p.PostId)
if err != nil {
return "", err
}
@@ -72,9 +74,9 @@ func (p *PostHeader) Text() (string, error) {
return *dbdata[0].Data, nil
}
func AmGetPost(postId int64) (*PostHeader, error) {
func AmGetPost(ctx context.Context, postId int64) (*PostHeader, error) {
var dbdata []PostHeader
err := amdb.Select(&dbdata, "SELECT * FROM posts WHERE postid = ?", postId)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM posts WHERE postid = ?", postId)
if err != nil {
return nil, err
}
@@ -87,9 +89,9 @@ func AmGetPost(postId int64) (*PostHeader, error) {
return &(dbdata[0]), nil
}
func AmGetPostRange(topic *Topic, first, last int32) ([]PostHeader, error) {
func AmGetPostRange(ctx context.Context, topic *Topic, first, last int32) ([]PostHeader, error) {
var rc []PostHeader
err := amdb.Select(&rc, "SELECT * FROM posts WHERE topicid = ? AND num >= ? AND num <= ? ORDER BY num", topic.TopicId, first, last)
err := amdb.SelectContext(ctx, &rc, "SELECT * FROM posts WHERE topicid = ? AND num >= ? AND num <= ? ORDER BY num", topic.TopicId, first, last)
if err != nil {
return nil, err
}
+4 -3
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"errors"
"fmt"
"math"
@@ -32,9 +33,9 @@ func (d *PostLinkData) NeedsDBVerification() bool {
}
// VerifyNames verifies the post link data against the database.
func (d *PostLinkData) VerifyNames() error {
func (d *PostLinkData) VerifyNames(ctx context.Context) error {
if d.Community != "" {
comm, err := AmGetCommunityByAlias(d.Community)
comm, err := AmGetCommunityByAlias(ctx, d.Community)
if err != nil {
return err
}
@@ -43,7 +44,7 @@ func (d *PostLinkData) VerifyNames() error {
}
}
if d.Conference != "" {
conf, err := AmGetConferenceByAlias(d.Conference)
conf, err := AmGetConferenceByAlias(ctx, d.Conference)
if err != nil {
return err
}
+34 -27
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
_ "embed"
"slices"
"sync"
@@ -21,28 +22,28 @@ import (
// ServiceVTable is a serioes of functions called for services on specific events.
type ServiceVTable interface {
OnNewCommunity(*sqlx.Tx, *Community) error
OnDeleteCommunity(*sqlx.Tx, int32) error
OnUserJoinCommunity(*sqlx.Tx, *Community, *User) error
OnUserLeaveCommunity(*sqlx.Tx, *Community, *User) error
OnNewCommunity(context.Context, *sqlx.Tx, *Community) error
OnDeleteCommunity(context.Context, *sqlx.Tx, int32) error
OnUserJoinCommunity(context.Context, *sqlx.Tx, *Community, *User) error
OnUserLeaveCommunity(context.Context, *sqlx.Tx, *Community, *User) error
}
// emptyServiceVTable is a default ServiceVTable that does nothing.
type emptyServiceVTable struct{}
func (*emptyServiceVTable) OnNewCommunity(*sqlx.Tx, *Community) error {
func (*emptyServiceVTable) OnNewCommunity(context.Context, *sqlx.Tx, *Community) error {
return nil
}
func (*emptyServiceVTable) OnDeleteCommunity(*sqlx.Tx, int32) error {
func (*emptyServiceVTable) OnDeleteCommunity(context.Context, *sqlx.Tx, int32) error {
return nil
}
func (*emptyServiceVTable) OnUserJoinCommunity(*sqlx.Tx, *Community, *User) error {
func (*emptyServiceVTable) OnUserJoinCommunity(context.Context, *sqlx.Tx, *Community, *User) error {
return nil
}
func (*emptyServiceVTable) OnUserLeaveCommunity(*sqlx.Tx, *Community, *User) error {
func (*emptyServiceVTable) OnUserLeaveCommunity(context.Context, *sqlx.Tx, *Community, *User) error {
return nil
}
@@ -124,17 +125,18 @@ func init() {
/* AmGetCommunityServices returns all the community service definitions for a community.
* Parameters:
* ctx - Standard Go context value.
* cid - Community ID to get services for.
* Returns:
* Array of ServiceDef pointers for the community's services.
* Standard Go error status.
*/
func AmGetCommunityServices(cid int32) ([]*ServiceDef, error) {
func AmGetCommunityServices(ctx context.Context, cid int32) ([]*ServiceDef, error) {
servicesCacheMutex.Lock()
defer servicesCacheMutex.Unlock()
rc, ok := servicesCache.Get(cid)
if !ok {
rs, err := amdb.Query("SELECT ftr_code FROM commftrs WHERE commid = ?", cid)
rs, err := amdb.QueryContext(ctx, "SELECT ftr_code FROM commftrs WHERE commid = ?", cid)
if err != nil {
return nil, err
}
@@ -153,18 +155,19 @@ func AmGetCommunityServices(cid int32) ([]*ServiceDef, error) {
/* AmGetCommunityServices returns all the community service definitions for a community, using a transaction.
* Parameters:
* ctx - Standard Go context value.
* tx - Transaction to be used.
* cid - Community ID to get services for.
* Returns:
* Array of ServiceDef pointers for the community's services.
* Standard Go error status.
*/
func AmGetCommunityServicesTx(tx *sqlx.Tx, cid int32) ([]*ServiceDef, error) {
func AmGetCommunityServicesTx(ctx context.Context, tx *sqlx.Tx, cid int32) ([]*ServiceDef, error) {
servicesCacheMutex.Lock()
defer servicesCacheMutex.Unlock()
rc, ok := servicesCache.Get(cid)
if !ok {
rs, err := tx.Query("SELECT ftr_code FROM commftrs WHERE commid = ?", cid)
rs, err := tx.QueryContext(ctx, "SELECT ftr_code FROM commftrs WHERE commid = ?", cid)
if err != nil {
return nil, err
}
@@ -184,17 +187,18 @@ func AmGetCommunityServicesTx(tx *sqlx.Tx, cid int32) ([]*ServiceDef, error) {
/* AmEstablishCommunityServices establishes the service (feature) records for a new community,
* and allows the services to establish themselves.
* Parameters:
* ctx - Standard Go context value.
* tx - The transaction to use.
* c - The new community.
* Returns:
* Standard Go error status.
*/
func AmEstablishCommunityServices(tx *sqlx.Tx, c *Community) error {
func AmEstablishCommunityServices(ctx context.Context, tx *sqlx.Tx, c *Community) error {
dom := serviceRoot.byName["community"]
a := make([]*ServiceDef, 0, len(dom.Services))
for i, svc := range dom.Services {
if svc.Default {
_, err := tx.Exec("INSERT INTO commftrs (commid, ftr_code) VALUES (?, ?)", c.Id, svc.Index)
_, err := tx.ExecContext(ctx, "INSERT INTO commftrs (commid, ftr_code) VALUES (?, ?)", c.Id, svc.Index)
if err != nil {
return err
}
@@ -205,7 +209,7 @@ func AmEstablishCommunityServices(tx *sqlx.Tx, c *Community) error {
servicesCache.Add(c.Id, a)
servicesCacheMutex.Unlock()
for _, svc := range a {
err := svc.vtable.OnNewCommunity(tx, c)
err := svc.vtable.OnNewCommunity(ctx, tx, c)
if err != nil {
return err
}
@@ -216,23 +220,24 @@ func AmEstablishCommunityServices(tx *sqlx.Tx, c *Community) error {
/* AmDeleteCommunityServices cleans up all services associated with a community that has gone away,
* and then cleans up the service records.
* Parameters:
* ctx - Standard Go context value.
* tx - The transaction to use.
* cid - The ID of the departing community.
* Returns:
* Standard Go error status.
*/
func AmDeleteCommunityServices(tx *sqlx.Tx, cid int32) error {
arr, err := AmGetCommunityServices(cid)
func AmDeleteCommunityServices(ctx context.Context, tx *sqlx.Tx, cid int32) error {
arr, err := AmGetCommunityServices(ctx, cid)
if err == nil {
for _, svc := range arr {
err = svc.vtable.OnDeleteCommunity(tx, cid)
err = svc.vtable.OnDeleteCommunity(ctx, tx, cid)
if err != nil {
break
}
}
}
if err == nil {
_, err = tx.Exec("DELETE FROM commftrs WHERE commid = ?", cid)
_, err = tx.ExecContext(ctx, "DELETE FROM commftrs WHERE commid = ?", cid)
servicesCacheMutex.Lock()
servicesCache.Remove(cid)
servicesCacheMutex.Unlock()
@@ -242,17 +247,18 @@ func AmDeleteCommunityServices(tx *sqlx.Tx, cid int32) error {
/* AmOnUserJoinCommunityServices gives services a chance to update themselves when a user joins a community.
* Parameters:
* ctx - Standard Go context value.
* tx - The current database transaction.
* c - The community that is being joined.
* u - The user leaving that community.
* Returns:
* Standard Go error status.
*/
func AmOnUserJoinCommunityServices(tx *sqlx.Tx, c *Community, u *User) error {
arr, err := AmGetCommunityServicesTx(tx, c.Id)
func AmOnUserJoinCommunityServices(ctx context.Context, tx *sqlx.Tx, c *Community, u *User) error {
arr, err := AmGetCommunityServicesTx(ctx, tx, c.Id)
if err == nil {
for _, svc := range arr {
err = svc.vtable.OnUserJoinCommunity(tx, c, u)
err = svc.vtable.OnUserJoinCommunity(ctx, tx, c, u)
if err != nil {
break
}
@@ -263,17 +269,18 @@ func AmOnUserJoinCommunityServices(tx *sqlx.Tx, c *Community, u *User) error {
/* AmOnUserLeaveCommunityServices gives services a chance to update themselves when a user leaves a community.
* Parameters:
* ctx - Standard Go context value.
* tx - The current database transaction.
* c - The community that is being left.
* u - The user leaving that community.
* Returns:
* Standard Go error status.
*/
func AmOnUserLeaveCommunityServices(tx *sqlx.Tx, c *Community, u *User) error {
arr, err := AmGetCommunityServicesTx(tx, c.Id)
func AmOnUserLeaveCommunityServices(ctx context.Context, tx *sqlx.Tx, c *Community, u *User) error {
arr, err := AmGetCommunityServicesTx(ctx, tx, c.Id)
if err == nil {
for _, svc := range arr {
err = svc.vtable.OnUserLeaveCommunity(tx, c, u)
err = svc.vtable.OnUserLeaveCommunity(ctx, tx, c, u)
if err != nil {
break
}
@@ -282,8 +289,8 @@ func AmOnUserLeaveCommunityServices(tx *sqlx.Tx, c *Community, u *User) error {
return err
}
func AmTestService(c *Community, serviceId string) (bool, error) {
arr, err := AmGetCommunityServices(c.Id)
func AmTestService(ctx context.Context, c *Community, serviceId string) (bool, error) {
arr, err := AmGetCommunityServices(ctx, c.Id)
if err == nil {
for _, svc := range arr {
if svc.Id == serviceId {
+11 -6
View File
@@ -9,7 +9,11 @@
// The database package contains database management and storage logic.
package database
import "github.com/jmoiron/sqlx"
import (
"context"
"github.com/jmoiron/sqlx"
)
type Sidebox struct {
Uid int32 `db:"uid"`
@@ -19,12 +23,12 @@ type Sidebox struct {
}
// copySideboxes copies sideboxes from one user to another.
func copySideboxes(tx *sqlx.Tx, toUid int32, fromUid int32) error {
func copySideboxes(ctx context.Context, tx *sqlx.Tx, toUid int32, fromUid int32) error {
sbox := make([]Sidebox, 0, 3)
err := tx.Select(&sbox, "SELECT * from sideboxes WHERE uid = ?", fromUid)
err := tx.SelectContext(ctx, &sbox, "SELECT * from sideboxes WHERE uid = ?", fromUid)
if err == nil {
for _, sb := range sbox {
_, err := tx.Exec("INSERT INTO sideboxes (uid, boxid, sequence, param) VALUES (?, ?, ?, ?)", toUid, sb.Boxid, sb.Sequence, sb.Param)
_, err := tx.ExecContext(ctx, "INSERT INTO sideboxes (uid, boxid, sequence, param) VALUES (?, ?, ?, ?)", toUid, sb.Boxid, sb.Sequence, sb.Param)
if err != nil {
break
}
@@ -35,13 +39,14 @@ func copySideboxes(tx *sqlx.Tx, toUid int32, fromUid int32) error {
/* AmGetSideboxes returns all the configured sideboxes for a user.
* Parameters:
* ctx = Standard Go context value.
* uid = The ID of the user to retrieve sideboxes for.
* Returns:
* Array of Sidebox structures for the user, or nil
* Standard Go error status
*/
func AmGetSideboxes(uid int32) ([]*Sidebox, error) {
func AmGetSideboxes(ctx context.Context, uid int32) ([]*Sidebox, error) {
sboxes := make([]*Sidebox, 0, 3)
err := amdb.Select(&sboxes, "SELECT * FROM sideboxes WHERE uid = ? ORDER BY SEQUENCE", uid)
err := amdb.SelectContext(ctx, &sboxes, "SELECT * FROM sideboxes WHERE uid = ? ORDER BY SEQUENCE", uid)
return sboxes, err
}
+33 -26
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"errors"
"fmt"
"strings"
@@ -34,12 +35,12 @@ type Topic struct {
}
// GetPost returns a post in the topic by number.
func (t *Topic) GetPost(num int32) (*PostHeader, error) {
func (t *Topic) GetPost(ctx context.Context, num int32) (*PostHeader, error) {
if num > t.TopMessage {
return nil, fmt.Errorf("no post %d in topic %d", num, t.TopicId)
}
var dbdata []PostHeader
err := amdb.Select(&dbdata, "SELECT * FROM posts WHERE topicid = ? AND num = ?", t.TopicId, num)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM posts WHERE topicid = ? AND num = ?", t.TopicId, num)
if err == nil {
if len(dbdata) == 0 {
err = fmt.Errorf("no post %d in topic %d", num, t.TopicId)
@@ -53,8 +54,8 @@ func (t *Topic) GetPost(num int32) (*PostHeader, error) {
}
// GetLastRead returns the "last read" message for a user on a topic.
func (t *Topic) GetLastRead(u *User) (int32, error) {
rs, err := amdb.Query("SELECT last_message FROM topicsettings WHERE topicid = ? AND uid = ?", t.TopicId, u.Uid)
func (t *Topic) GetLastRead(ctx context.Context, u *User) (int32, error) {
rs, err := amdb.QueryContext(ctx, "SELECT last_message FROM topicsettings WHERE topicid = ? AND uid = ?", t.TopicId, u.Uid)
if err != nil {
return -1, err
}
@@ -66,12 +67,14 @@ func (t *Topic) GetLastRead(u *User) (int32, error) {
}
// SetLastRead sets the "last read" message for a user on a topic.
func (t *Topic) SetLastRead(u *User, postNum int32) error {
rs, err := amdb.Exec("UPDATE topicsettings SET last_message = ?, last_read = NOW() WHERE topicid = ? AND uid = ?", postNum, t.TopicId, u.Uid)
func (t *Topic) SetLastRead(ctx context.Context, u *User, postNum int32) error {
rs, err := amdb.ExecContext(ctx, "UPDATE topicsettings SET last_message = ?, last_read = NOW() WHERE topicid = ? AND uid = ?",
postNum, t.TopicId, u.Uid)
if err == nil {
nrow, _ := rs.RowsAffected()
if nrow == 0 {
_, err = amdb.Exec("INSERT INTO topicsettings (topicid, uid, last_message, last_read, last_post) VALUES (?, ?, ?, NOW(), NULL)", t.TopicId, u.Uid, postNum)
_, err = amdb.ExecContext(ctx, "INSERT INTO topicsettings (topicid, uid, last_message, last_read, last_post) VALUES (?, ?, ?, NOW(), NULL)",
t.TopicId, u.Uid, postNum)
}
}
return err
@@ -104,14 +107,15 @@ type TopicSummary struct {
/* AmGetTopic retrieves a topic by ID.
* Parameters:
* ctx - Standard Go context value.
* topicId - ID of the topic to retrieve.
* Returns:
* The topic pointer, or nil.
* Standard Go error status.
*/
func AmGetTopic(topicId int32) (*Topic, error) {
func AmGetTopic(ctx context.Context, topicId int32) (*Topic, error) {
var dbdata []Topic
err := amdb.Select(&dbdata, "SELECT * FROM topics WHERE topicid = ?", topicId)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM topics WHERE topicid = ?", topicId)
if err != nil {
return nil, err
}
@@ -126,15 +130,16 @@ func AmGetTopic(topicId int32) (*Topic, error) {
/* AmGetTopicTx retrieves a topic by ID, in a transaction.
* Parameters:
* ctx - Standard Go context value.
* tx - The transaction to use.
* topicId - ID of the topic to retrieve.
* Returns:
* The topic pointer, or nil.
* Standard Go error status.
*/
func AmGetTopicTx(tx *sqlx.Tx, topicId int32) (*Topic, error) {
func AmGetTopicTx(ctx context.Context, tx *sqlx.Tx, topicId int32) (*Topic, error) {
var dbdata []Topic
err := tx.Select(&dbdata, "SELECT * FROM topics WHERE topicid = ?", topicId)
err := tx.SelectContext(ctx, &dbdata, "SELECT * FROM topics WHERE topicid = ?", topicId)
if err != nil {
return nil, err
}
@@ -149,15 +154,16 @@ func AmGetTopicTx(tx *sqlx.Tx, topicId int32) (*Topic, error) {
/* AmGetTopicByNumber retrieves a topic by conference and sequence number.
* Parameters:
* ctx - Standard Go context value.
* conf - The conference to look in.
* topicNum - The topic number within that conference.
* Returns:
* Pointer to the Topic, or nil.
* Standard Go error status.
*/
func AmGetTopicByNumber(conf *Conference, topicNum int16) (*Topic, error) {
func AmGetTopicByNumber(ctx context.Context, conf *Conference, topicNum int16) (*Topic, error) {
var dbdata []Topic
err := amdb.Select(&dbdata, "SELECT * FROM topics WHERE confid = ? AND num = ?", conf.ConfId, topicNum)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM topics WHERE confid = ? AND num = ?", conf.ConfId, topicNum)
if err == nil {
if len(dbdata) == 0 {
err = fmt.Errorf("no topic numbered %d in conference %s (#%d)", topicNum, conf.Name, conf.ConfId)
@@ -189,6 +195,7 @@ const (
/* AmListTopics produces a list of topic summary information according to specific options.
* Parameters:
* ctx - Standard Go context value.
* confid - The ID of the conference to list topics in.
* uid - The UID of the user to consider the settings of.
* viewOption - One of the following constants:
@@ -210,7 +217,7 @@ const (
* List of TopicSummary pointers.
* Standard Go error status.
*/
func AmListTopics(confid int32, uid int32, viewOption int, sortOption int, ignoreSticky bool) ([]*TopicSummary, error) {
func AmListTopics(ctx context.Context, confid int32, uid int32, viewOption int, sortOption int, ignoreSticky bool) ([]*TopicSummary, error) {
// Decode the viewOption into a WHERE clause.
var whereClause string
switch viewOption {
@@ -296,7 +303,7 @@ func AmListTopics(confid int32, uid int32, viewOption int, sortOption int, ignor
fullStatement.WriteString(orderByClause)
// Execute and capture results
rs, err := amdb.Query(fullStatement.String(), uid, confid)
rs, err := amdb.QueryContext(ctx, fullStatement.String(), uid, confid)
if err != nil {
return nil, err
}
@@ -310,7 +317,7 @@ func AmListTopics(confid int32, uid int32, viewOption int, sortOption int, ignor
return rc, nil
}
func AmNewTopic(conf *Conference, user *User, title string, zeroPostPseud string, zeroPost string,
func AmNewTopic(ctx context.Context, conf *Conference, user *User, title string, zeroPostPseud string, zeroPost string,
zeroPostLines int32, ipaddr string) (*Topic, error) {
var ar *AuditRecord = nil
defer func() {
@@ -325,16 +332,16 @@ func AmNewTopic(conf *Conference, user *User, title string, zeroPostPseud string
}()
unlock := true
tx.Exec("LOCK TABLES confs WRITE, topics WRITE, topicsettings WRITE, posts WRITE, postdata WRITE;")
tx.ExecContext(ctx, "LOCK TABLES confs WRITE, topics WRITE, topicsettings WRITE, posts WRITE, postdata WRITE;")
defer func() {
if unlock {
tx.Exec("UNLOCK TABLES;")
tx.ExecContext(ctx, "UNLOCK TABLES;")
}
}()
// Insert the new topic into the database.
conf.Mutex.Lock()
rs, err := tx.Exec("INSERT INTO topics (confid, num, creator_uid, createdate, lastupdate, name) VALUES (?, ?, ?, NOW(), NOW(), ?)",
rs, err := tx.ExecContext(ctx, "INSERT INTO topics (confid, num, creator_uid, createdate, lastupdate, name) VALUES (?, ?, ?, NOW(), NOW(), ?)",
conf.ConfId, conf.TopTopic+1, user.Uid, title)
if err != nil {
conf.Mutex.Unlock()
@@ -347,14 +354,14 @@ func AmNewTopic(conf *Conference, user *User, title string, zeroPostPseud string
return nil, err
}
// Get the topic.
topic, err := AmGetTopicTx(tx, int32(xid))
topic, err := AmGetTopicTx(ctx, tx, int32(xid))
if err != nil {
conf.Mutex.Unlock()
return nil, err
}
// Update the conference to set the last update and top topic.
_, err = tx.Exec("UPDATE confs SET lastupdate = ?, top_topic = ? WHERE confid = ?", topic.CreateDate, conf.TopTopic+1, conf.ConfId)
_, err = tx.ExecContext(ctx, "UPDATE confs SET lastupdate = ?, top_topic = ? WHERE confid = ?", topic.CreateDate, conf.TopTopic+1, conf.ConfId)
if err != nil {
conf.Mutex.Unlock()
return nil, err
@@ -364,7 +371,7 @@ func AmNewTopic(conf *Conference, user *User, title string, zeroPostPseud string
conf.Mutex.Unlock()
// Add the "header record" for the first post.
rs, err = tx.Exec("INSERT INTO posts (topicid, num, linecount, creator_uid, posted, pseud) VALUES (?, 0, ?, ?, ?, ?)",
rs, err = tx.ExecContext(ctx, "INSERT INTO posts (topicid, num, linecount, creator_uid, posted, pseud) VALUES (?, 0, ?, ?, ?, ?)",
topic.TopicId, zeroPostLines, user.Uid, topic.CreateDate, zeroPostPseud)
if err != nil {
return nil, err
@@ -374,23 +381,23 @@ func AmNewTopic(conf *Conference, user *User, title string, zeroPostPseud string
return nil, err
}
// Add the post data.
_, err = tx.Exec("INSERT INTO postdata (postid, data) VALUES (?, ?)", int32(xid), zeroPost)
_, err = tx.ExecContext(ctx, "INSERT INTO postdata (postid, data) VALUES (?, ?)", int32(xid), zeroPost)
if err != nil {
return nil, err
}
// Add a new topic settings record for the user, too.
_, err = tx.Exec("INSERT INTO topicsettings (topicid, uid, last_post) VALUES (?, ?, ?)",
_, err = tx.ExecContext(ctx, "INSERT INTO topicsettings (topicid, uid, last_post) VALUES (?, ?, ?)",
topic.TopicId, user.Uid, topic.CreateDate)
if err != nil {
return nil, err
}
tx.Exec("UNLOCK TABLES;")
tx.ExecContext(ctx, "UNLOCK TABLES;")
unlock = false
// update the "last posted" date in the conference settings
_, err = conf.TouchPost(tx, user, topic.CreateDate)
_, err = conf.TouchPost(ctx, tx, user, topic.CreateDate)
if err != nil {
return nil, err
}
+90 -75
View File
@@ -10,6 +10,7 @@
package database
import (
"context"
"crypto/sha1"
"encoding/hex"
"errors"
@@ -53,11 +54,11 @@ func (p *UserPrefs) Clone() *UserPrefs {
}
// Save saves off the user preferences, replacing the prefs on the user if necessary.
func (p *UserPrefs) Save(u *User) error {
func (p *UserPrefs) Save(ctx context.Context, u *User) error {
if u != nil && u.Uid != p.Uid {
return errors.New("internal mismatch of IDs")
}
_, err := amdb.NamedExec("UPDATE userprefs SET localeid = :localeid, tzid = :tzid WHERE uid = :uid", p)
_, err := amdb.NamedExecContext(ctx, "UPDATE userprefs SET localeid = :localeid, tzid = :tzid WHERE uid = :uid", p)
if err == nil && u != nil {
u.prefs = p
}
@@ -181,27 +182,27 @@ func init() {
}
// ContactInfo returns the contact info structure for the user.
func (u *User) ContactInfo() (*ContactInfo, error) {
func (u *User) ContactInfo(ctx context.Context) (*ContactInfo, error) {
if u.ContactID < 0 {
return nil, nil
}
return AmGetContactInfo(u.ContactID)
return AmGetContactInfo(ctx, u.ContactID)
}
// ContactInfo returns the contact info structure for the user, quietly.
func (u *User) ContactInfoQ() *ContactInfo {
func (u *User) ContactInfoQ(ctx context.Context) *ContactInfo {
if u.ContactID < 0 {
return nil
}
ci, _ := AmGetContactInfo(u.ContactID)
ci, _ := AmGetContactInfo(ctx, u.ContactID)
return ci
}
// SetContactID sets the contact ID of a user.
func (u *User) SetContactID(cid int32) error {
func (u *User) SetContactID(ctx context.Context, cid int32) error {
u.Mutex.Lock()
defer u.Mutex.Unlock()
if _, err := amdb.Exec("UPDATE users SET contactid = ? WHERE uid = ?", cid, u.Uid); err != nil {
if _, err := amdb.ExecContext(ctx, "UPDATE users SET contactid = ? WHERE uid = ?", cid, u.Uid); err != nil {
return err
}
u.ContactID = cid
@@ -213,14 +214,14 @@ func (u *User) SetContactID(cid int32) error {
* Authentication token value
* Standard Go error status.
*/
func (u *User) NewAuthToken() (string, error) {
func (u *User) NewAuthToken(ctx context.Context) (string, error) {
if u.IsAnon {
return "", errors.New("cannot generate token for anonymous user")
}
u.Mutex.Lock()
defer u.Mutex.Unlock()
newToken := util.GenerateRandomAuthString()
if _, err := amdb.Exec("UPDATE users SET tokenauth = ? WHERE uid = ?", newToken, u.Uid); err != nil {
if _, err := amdb.ExecContext(ctx, "UPDATE users SET tokenauth = ? WHERE uid = ?", newToken, u.Uid); err != nil {
return "", err
}
u.Tokenauth = &newToken
@@ -230,12 +231,13 @@ func (u *User) NewAuthToken() (string, error) {
/* ConfirmEMailAddress checks the E-mail confirmation number and sets "verified" status if it's OK.
* Parameters:
* ctx - Standard Go context value.
* confnum - The entered confirmation number.
* remoteIP - The remote IP address for audit messages.
* Returns:
* Standard Go error status.
*/
func (u *User) ConfirmEMailAddress(confnum int32, remoteIP string) error {
func (u *User) ConfirmEMailAddress(ctx context.Context, confnum int32, remoteIP string) error {
var ar *AuditRecord = nil
defer func() {
AmStoreAudit(ar)
@@ -260,12 +262,12 @@ func (u *User) ConfirmEMailAddress(confnum int32, remoteIP string) error {
ar = AmNewAudit(AuditVerifyEmailFail, u.Uid, remoteIP, "Invalid confirmation number")
return errors.New("confirmation number is incorrect. Please try again")
}
_, err := tx.Exec("UPDATE users SET verify_email = 1, base_lvl = ? WHERE uid = ?",
_, err := tx.ExecContext(ctx, "UPDATE users SET verify_email = 1, base_lvl = ? WHERE uid = ?",
AmDefaultRole("Global.AfterVerify").Level(), u.Uid)
if err == nil {
u.VerifyEMail = true
u.BaseLevel = AmDefaultRole("Global.AfterVerify").Level()
err = AmAutoJoinCommunities(tx, u)
err = AmAutoJoinCommunities(ctx, tx, u)
if err == nil {
err = tx.Commit()
if err == nil {
@@ -278,11 +280,11 @@ func (u *User) ConfirmEMailAddress(confnum int32, remoteIP string) error {
}
// NewEmailConfirmationNumber creates a new confirmation number for a user and saves it off.
func (u *User) NewEmailConfirmationNumber() error {
func (u *User) NewEmailConfirmationNumber(ctx context.Context) error {
u.Mutex.Lock()
defer u.Mutex.Unlock()
newnum := util.GenerateRandomConfirmationNumber()
_, err := amdb.Exec("UPDATE users SET email_confnum = ? WHERE uid = ?", newnum, u.Uid)
_, err := amdb.ExecContext(ctx, "UPDATE users SET email_confnum = ? WHERE uid = ?", newnum, u.Uid)
if err != nil {
u.EmailConfNum = newnum
}
@@ -290,7 +292,7 @@ func (u *User) NewEmailConfirmationNumber() error {
}
// ChangePassword resets a user's password.
func (u *User) ChangePassword(password string, remoteIP string) error {
func (u *User) ChangePassword(ctx context.Context, password string, remoteIP string) error {
var ar *AuditRecord = nil
defer func() {
AmStoreAudit(ar)
@@ -299,7 +301,7 @@ func (u *User) ChangePassword(password string, remoteIP string) error {
u.Mutex.Lock()
defer u.Mutex.Unlock()
pval := hashPassword(password)
_, err := amdb.Exec("UPDATE users SET passhash = ? WHERE uid = ?", pval, u.Uid)
_, err := amdb.ExecContext(ctx, "UPDATE users SET passhash = ? WHERE uid = ?", pval, u.Uid)
if err == nil {
u.Passhash = pval
ar = AmNewAudit(AuditChangePassword, u.Uid, remoteIP, "via password change request")
@@ -308,11 +310,11 @@ func (u *User) ChangePassword(password string, remoteIP string) error {
}
// GetFlags retrieves the flags from the properties.
func (u *User) Flags() (*util.OptionSet, error) {
func (u *User) Flags(ctx context.Context) (*util.OptionSet, error) {
u.Mutex.Lock()
defer u.Mutex.Unlock()
if u.flags == nil {
s, err := AmGetUserProperty(u.Uid, UserPropFlags)
s, err := AmGetUserProperty(ctx, u.Uid, UserPropFlags)
if err != nil {
return nil, err
}
@@ -325,11 +327,11 @@ func (u *User) Flags() (*util.OptionSet, error) {
}
// SaveFlags writes the flags to the database and stores them.
func (u *User) SaveFlags(f *util.OptionSet) error {
func (u *User) SaveFlags(ctx context.Context, f *util.OptionSet) error {
s := f.AsString()
u.Mutex.Lock()
defer u.Mutex.Unlock()
err := AmSetUserProperty(u.Uid, UserPropFlags, &s)
err := AmSetUserProperty(ctx, u.Uid, UserPropFlags, &s)
if err == nil {
u.flags = f
}
@@ -337,8 +339,8 @@ func (u *User) SaveFlags(f *util.OptionSet) error {
}
// FlagValue returns the boolean value of one of the user flags.
func (u *User) FlagValue(ndx uint) bool {
f, err := u.Flags()
func (u *User) FlagValue(ctx context.Context, ndx uint) bool {
f, err := u.Flags(ctx)
if err != nil {
log.Errorf("flag retrieval error for user %d: %v", u.Uid, err)
return false
@@ -347,12 +349,12 @@ func (u *User) FlagValue(ndx uint) bool {
}
// Prefs returns the user's preferences record.
func (u *User) Prefs() (*UserPrefs, error) {
func (u *User) Prefs(ctx context.Context) (*UserPrefs, error) {
u.Mutex.Lock()
defer u.Mutex.Unlock()
if u.prefs == nil {
var dbdata []UserPrefs
err := amdb.Select(&dbdata, "SELECT * FROM userprefs WHERE uid = ?", u.Uid)
err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM userprefs WHERE uid = ?", u.Uid)
if err != nil {
return nil, err
}
@@ -366,13 +368,14 @@ func (u *User) Prefs() (*UserPrefs, error) {
/* SetProfileData sets the "profile" variables for this user.
* Parameters:
* ctx - Standard Go context value.
* reminder - Password reminder string.
* dob - Date of birth field.
* descr - Description string.
* Returns:
* Standard Go error status.
*/
func (u *User) SetProfileData(reminder string, dob *time.Time, descr *string) error {
func (u *User) SetProfileData(ctx context.Context, reminder string, dob *time.Time, descr *string) error {
u.Mutex.Lock()
defer u.Mutex.Unlock()
_, err := amdb.Exec("UPDATE users SET passreminder = ?, dob = ?, description = ? WHERE uid = ?", reminder, dob, descr, u.Uid)
@@ -386,19 +389,20 @@ func (u *User) SetProfileData(reminder string, dob *time.Time, descr *string) er
/* AmGetUser returns a reference to the specified user.
* Parameters:
* ctx - Standard Go context value.
* uid - The UID of the user.
* Returns:
* Pointer to User containing user data, or nil
* Standard Go error status
*/
func AmGetUser(uid int32) (*User, error) {
func AmGetUser(ctx context.Context, uid int32) (*User, error) {
var err error = nil
getUserMutex.Lock()
defer getUserMutex.Unlock()
rc, ok := userCache.Get(uid)
if !ok {
var dbdata []User
err = amdb.Select(&dbdata, "SELECT * from users WHERE uid = ?", uid)
err = amdb.SelectContext(ctx, &dbdata, "SELECT * from users WHERE uid = ?", uid)
if err != nil {
return nil, err
}
@@ -413,20 +417,21 @@ func AmGetUser(uid int32) (*User, error) {
/* AmGetUserTx returns a reference to the specified user inside a transaction.
* Parameters:
* ctxt - Standard Go context value.
* tx - The transaction we're in.
* uid - The UID of the user.
* Returns:
* Pointer to User containing user data, or nil
* Standard Go error status
*/
func AmGetUserTx(tx *sqlx.Tx, uid int32) (*User, error) {
func AmGetUserTx(ctx context.Context, tx *sqlx.Tx, uid int32) (*User, error) {
var err error = nil
getUserMutex.Lock()
defer getUserMutex.Unlock()
rc, ok := userCache.Get(uid)
if !ok {
var dbdata []User
err = tx.Select(&dbdata, "SELECT * from users WHERE uid = ?", uid)
err = tx.SelectContext(ctx, &dbdata, "SELECT * from users WHERE uid = ?", uid)
if err != nil {
return nil, err
}
@@ -441,19 +446,20 @@ func AmGetUserTx(tx *sqlx.Tx, uid int32) (*User, error) {
/* AmGetUserByName returns a reference to the specified user.
* Parameters:
* ctx - Standard Go context value.
* name - The username of the user.
* tx - If this is not nil, use this transaction.
* Returns:
* Pointer to User containing user data, or nil
* Standard Go error status
*/
func AmGetUserByName(name string, tx *sqlx.Tx) (*User, error) {
func AmGetUserByName(ctx context.Context, name string, tx *sqlx.Tx) (*User, error) {
var dbdata []User
var err error
if tx != nil {
err = tx.Select(&dbdata, "SELECT * FROM users WHERE username = ?", name)
err = tx.SelectContext(ctx, &dbdata, "SELECT * FROM users WHERE username = ?", name)
} else {
err = amdb.Select(&dbdata, "SELECT * FROM users WHERE username = ?", name)
err = amdb.SelectContext(ctx, &dbdata, "SELECT * FROM users WHERE username = ?", name)
}
if err != nil {
return nil, err
@@ -472,9 +478,9 @@ func AmGetUserByName(name string, tx *sqlx.Tx) (*User, error) {
}
// getAnonUserID retrieves the UID of the "anonymous" user from the database.
func getAnonUserID() (int32, error) {
func getAnonUserID(ctx context.Context) (int32, error) {
if anonUid < 0 {
rows, err := amdb.Query("SELECT uid FROM users WHERE is_anon = 1")
rows, err := amdb.QueryContext(ctx, "SELECT uid FROM users WHERE is_anon = 1")
if err == nil {
defer rows.Close()
if rows.Next() {
@@ -495,26 +501,29 @@ func getAnonUserID() (int32, error) {
/* AmIsUserAnon returns true if the specified user ID is the anonymous one.
* Parameters:
* ctx = Standard Go context value.
* uid = The user ID to test.
* Returns:
* true if the user is anonymous, false if not
* Standard Go error status
*/
func AmIsUserAnon(uid int32) (bool, error) {
auid, err := getAnonUserID()
func AmIsUserAnon(ctx context.Context, uid int32) (bool, error) {
auid, err := getAnonUserID(ctx)
return (uid == auid), err
}
/* AmGetAnonUser returns a reference to the anonymous user.
* Parameters:
* ctx = Standard Go context value.
* Returns:
* Pointer to User containing anonymous user data, or nil
* Standard Go error status
*/
func AmGetAnonUser() (*User, error) {
func AmGetAnonUser(ctx context.Context) (*User, error) {
var rc *User = nil
auid, err := getAnonUserID()
auid, err := getAnonUserID(ctx)
if err == nil {
rc, err = AmGetUser(auid)
rc, err = AmGetUser(ctx, auid)
}
return rc, err
}
@@ -531,16 +540,17 @@ func hashPassword(password string) string {
}
// touchUser updates the last access time for the user.
func touchUser(tx *sqlx.Tx, user *User) {
func touchUser(ctx context.Context, tx *sqlx.Tx, user *User) {
user.Mutex.Lock()
defer user.Mutex.Unlock()
moment := time.Now().UTC()
tx.Exec("UPDATE user SET lastaccess = ? WHERE uid = ?", moment, user.Uid)
tx.ExecContext(ctx, "UPDATE user SET lastaccess = ? WHERE uid = ?", moment, user.Uid)
user.LastAccess = &moment
}
/* AmAuthenticateUser authenticates a user by name and password.
* Parameters:
* ctx - Standard Go context parameter.
* name - The user name to try.
* password - The password to try.
* remote_ip - The remote IP address, for audit records.
@@ -548,8 +558,8 @@ func touchUser(tx *sqlx.Tx, user *User) {
* The User pointer if authenticated, or nil if not.
* Standard Go error status.
*/
func AmAuthenticateUser(name string, password string, remoteIP string) (*User, error) {
log.Debugf("AmAuthenicate() authenticating user %s...", name)
func AmAuthenticateUser(ctx context.Context, name string, password string, remoteIP string) (*User, error) {
log.Debugf("AmAuthenticateUser() authenticating user %s...", name)
var ar *AuditRecord = nil
defer func() {
AmStoreAudit(ar)
@@ -562,7 +572,7 @@ func AmAuthenticateUser(name string, password string, remoteIP string) (*User, e
}
}()
user, err := AmGetUserByName(name, tx)
user, err := AmGetUserByName(ctx, name, tx)
if err != nil {
log.Error("...user not found")
ar = AmNewAudit(AuditLoginFail, 0, remoteIP, fmt.Sprintf("Bad username: %s", name))
@@ -585,7 +595,7 @@ func AmAuthenticateUser(name string, password string, remoteIP string) (*User, e
return nil, errors.New("the password you have specified is incorrect; please try again")
}
log.Debug("...authenticated")
touchUser(tx, user)
touchUser(ctx, tx, user)
err = tx.Commit()
if err != nil {
return nil, err
@@ -621,13 +631,14 @@ func crackAuthString(authString string) (int32, string, error) {
/* AmAuthenticateUserByToken authenticates a user via the stored cookie authentication string.
* Parameters:
* ctx - Standard Go context value.
* authString - The stored cookie authentication string.
* remoteIP - The remote IP address wheter trhe user is logging in from.
* Returns:
* Pointer to the authenticated User, or nil.
* Standard Go error status.
*/
func AmAuthenticateUserByToken(authString string, remoteIP string) (*User, error) {
func AmAuthenticateUserByToken(ctx context.Context, authString string, remoteIP string) (*User, error) {
var ar *AuditRecord = nil
defer func() {
AmStoreAudit(ar)
@@ -645,7 +656,7 @@ func AmAuthenticateUserByToken(authString string, remoteIP string) (*User, error
return nil, fmt.Errorf("authString not valid, ignored: %v", err)
}
var user *User
user, err = AmGetUserTx(tx, uid)
user, err = AmGetUserTx(ctx, tx, uid)
if err != nil {
log.Error("...user not found")
ar = AmNewAudit(AuditLoginFail, 0, remoteIP, fmt.Sprintf("Bad uid: %d", uid))
@@ -668,7 +679,7 @@ func AmAuthenticateUserByToken(authString string, remoteIP string) (*User, error
return nil, errors.New("token mismatch")
}
log.Debug("...authenticated")
touchUser(tx, user)
touchUser(ctx, tx, user)
err = tx.Commit()
if err != nil {
return nil, err
@@ -680,6 +691,7 @@ func AmAuthenticateUserByToken(authString string, remoteIP string) (*User, error
/* AmCreateNewUser creates a new user record in the database.
* Parameters:
* ctx - Standard Go context value.
* username - New user name.
* password - New password.
* reminder - Password reminder string.
@@ -689,12 +701,12 @@ func AmAuthenticateUserByToken(authString string, remoteIP string) (*User, error
* Pointer to new user record.
* Standard Go error status.
*/
func AmCreateNewUser(username string, password string, reminder string, dob *time.Time, remoteIP string) (*User, error) {
func AmCreateNewUser(ctx context.Context, username string, password string, reminder string, dob *time.Time, remoteIP string) (*User, error) {
var ar *AuditRecord = nil
defer func() {
AmStoreAudit(ar)
}()
anon, _ := getAnonUserID()
anon, _ := getAnonUserID(ctx)
success := false
tx := amdb.MustBegin()
defer func() {
@@ -703,15 +715,15 @@ func AmCreateNewUser(username string, password string, reminder string, dob *tim
}
}()
unlock := true
tx.Exec("LOCK TABLES users WRITE, userprefs WRITE, propuser WRITE, commmember WRITE, sideboxes WRITE, confhotlist WRITE;")
tx.ExecContext(ctx, "LOCK TABLES users WRITE, userprefs WRITE, propuser WRITE, commmember WRITE, sideboxes WRITE, confhotlist WRITE;")
defer func() {
if unlock {
tx.Exec("UNLOCK TABLES;")
tx.ExecContext(ctx, "UNLOCK TABLES;")
}
}()
// Test if the user name is already taken.
rs, err := tx.Query("SELECT uid FROM users WHERE username = ?", username)
rs, err := tx.QueryContext(ctx, "SELECT uid FROM users WHERE username = ?", username)
if err != nil {
return nil, err
} else if rs.Next() {
@@ -720,7 +732,7 @@ func AmCreateNewUser(username string, password string, reminder string, dob *tim
}
// Insert the user record.
_, err2 := tx.Exec(`INSERT INTO users (username, passhash, verify_email, lockout, email_confnum,
_, err2 := tx.ExecContext(ctx, `INSERT INTO users (username, passhash, verify_email, lockout, email_confnum,
base_lvl, created, lastaccess, passreminder, description, dob) VALUES (?, ?, 0, 0, ?, ?, NOW(), NOW(), ?, '', ?)`,
username, hashPassword(password), util.GenerateRandomConfirmationNumber(), AmDefaultRole("Global.NewUser").Level(),
reminder, dob)
@@ -728,42 +740,42 @@ func AmCreateNewUser(username string, password string, reminder string, dob *tim
return nil, err2
}
// Read back the user, which also puts it in the cache.
user, err3 := AmGetUserByName(username, tx)
user, err3 := AmGetUserByName(ctx, username, tx)
if err3 != nil {
return nil, err3
}
log.Debugf("...created new user \"%s\" with UID %d", username, user.Uid)
// add user preferences
_, err = tx.Exec("INSERT INTO userprefs (uid) VALUES (?)", user.Uid)
_, err = tx.ExecContext(ctx, "INSERT INTO userprefs (uid) VALUES (?)", user.Uid)
if err != nil {
return nil, err
}
// add user properties
props := make([]UserProperties, 0)
err = tx.Select(&props, "SELECT * FROM propuser WHERE uid = ?", anon)
err = tx.SelectContext(ctx, &props, "SELECT * FROM propuser WHERE uid = ?", anon)
if err != nil {
return nil, err
}
for _, p := range props {
_, err := tx.Exec("INSERT INTO propuser (uid, ndx, data) VALUES (?, ?, ?)", user.Uid, p.Index, p.Data)
_, err := tx.ExecContext(ctx, "INSERT INTO propuser (uid, ndx, data) VALUES (?, ?, ?)", user.Uid, p.Index, p.Data)
if err != nil {
return nil, err
}
}
// add user sideboxes
err = copySideboxes(tx, user.Uid, anon)
err = copySideboxes(ctx, tx, user.Uid, anon)
if err != nil {
return nil, err
}
tx.Exec("UNLOCK TABLES;")
tx.ExecContext(ctx, "UNLOCK TABLES;")
unlock = false
// auto-join communities
err = AmAutoJoinCommunities(tx, user)
err = AmAutoJoinCommunities(ctx, tx, user)
if err != nil {
return nil, err
}
@@ -782,7 +794,7 @@ func AmCreateNewUser(username string, password string, reminder string, dob *tim
}
// internalGetProp is a helper used by the property functions.
func internalGetProp(uid int32, ndx int32) (*UserProperties, error) {
func internalGetProp(ctx context.Context, uid int32, ndx int32) (*UserProperties, error) {
var err error = nil
key := fmt.Sprintf("%d:%d", uid, ndx)
getUserPropMutex.Lock()
@@ -790,7 +802,7 @@ func internalGetProp(uid int32, ndx int32) (*UserProperties, error) {
rc, ok := userPropCache.Get(key)
if !ok {
var dbdata []UserProperties
err = amdb.Select(&dbdata, "SELECT * from propuser WHERE uid = ? AND ndx = ?", uid, ndx)
err = amdb.SelectContext(ctx, &dbdata, "SELECT * from propuser WHERE uid = ? AND ndx = ?", uid, ndx)
if err != nil {
return nil, err
}
@@ -808,14 +820,15 @@ func internalGetProp(uid int32, ndx int32) (*UserProperties, error) {
/* AmGetUserProperty retrieves the value of a user property.
* Parameters:
* ctx - Standard Go context value.
* uid - The UID of the user to get the property for.
* ndx - The index of the property to retrieve.
* Returns:
* Value of the property string.
* Standard Go error status.
*/
func AmGetUserProperty(uid int32, ndx int32) (*string, error) {
p, err := internalGetProp(uid, ndx)
func AmGetUserProperty(ctx context.Context, uid int32, ndx int32) (*string, error) {
p, err := internalGetProp(ctx, uid, ndx)
if err != nil {
return nil, err
}
@@ -824,27 +837,28 @@ func AmGetUserProperty(uid int32, ndx int32) (*string, error) {
/* AmSetUserProperty sets the value of a user property.
* Parameters:
* ctx - Standard Go context value.
* uid - The UID of the user to set the property for.
* ndx - The index of the property to set.
* val - The new value of the property.
* Returns:
* Standard Go error status.
*/
func AmSetUserProperty(uid int32, ndx int32, val *string) error {
p, err := internalGetProp(uid, ndx)
func AmSetUserProperty(ctx context.Context, uid int32, ndx int32, val *string) error {
p, err := internalGetProp(ctx, uid, ndx)
if err != nil {
return err
}
getUserPropMutex.Lock()
defer getUserPropMutex.Unlock()
if p != nil {
_, err = amdb.Exec("UPDATE propuser SET data = ? WHERE uid = ? AND ndx = ?", val, uid, ndx)
_, err = amdb.ExecContext(ctx, "UPDATE propuser SET data = ? WHERE uid = ? AND ndx = ?", val, uid, ndx)
if err == nil {
p.Data = val
}
} else {
prop := UserProperties{Uid: uid, Index: ndx, Data: val}
_, err := amdb.NamedExec("INSERT INTO propuser (uid, ndx, data) VALUES(:uid, :ndx, :data)", prop)
_, err := amdb.NamedExecContext(ctx, "INSERT INTO propuser (uid, ndx, data) VALUES(:uid, :ndx, :data)", prop)
if err == nil {
userPropCache.Add(fmt.Sprintf("%d:%d", uid, ndx), prop)
}
@@ -854,6 +868,7 @@ func AmSetUserProperty(uid int32, ndx int32, val *string) error {
/* AmSearchUsers searches for users matching certain criteria.
* Parameters:
* ctx - Standard Go context value.
* field - A value indicating which field to search:
* SearchUserFieldName - The user name.
* SearchUserFieldDescription - The user description.
@@ -871,7 +886,7 @@ func AmSetUserProperty(uid int32, ndx int32, val *string) error {
* The total number of users matching this query (could be greater than max)
* Standard Go error status.
*/
func AmSearchUsers(field int, oper int, term string, offset int, max int) ([]*User, int, error) {
func AmSearchUsers(ctx context.Context, field int, oper int, term string, offset int, max int) ([]*User, int, error) {
var queryPortion strings.Builder
switch field {
case SearchUserFieldName:
@@ -902,7 +917,7 @@ func AmSearchUsers(field int, oper int, term string, offset int, max int) ([]*Us
return nil, -1, errors.New("invalid operator selector")
}
q := queryPortion.String()
rs, err := amdb.Query("SELECT COUNT(*) FROM users u, contacts c WHERE u.contactid = c.contactid AND u.is_anon = 0 AND " + q)
rs, err := amdb.QueryContext(ctx, "SELECT COUNT(*) FROM users u, contacts c WHERE u.contactid = c.contactid AND u.is_anon = 0 AND "+q)
if err != nil {
return nil, -1, err
}
@@ -915,10 +930,10 @@ func AmSearchUsers(field int, oper int, term string, offset int, max int) ([]*Us
return make([]*User, 0), 0, nil
}
if offset > 0 {
rs, err = amdb.Query("SELECT u.uid FROM users u, contacts c WHERE u.contactid = c.contactid AND u.is_anon = 0 AND "+q+
rs, err = amdb.QueryContext(ctx, "SELECT u.uid FROM users u, contacts c WHERE u.contactid = c.contactid AND u.is_anon = 0 AND "+q+
" ORDER BY u.username LIMIT ? OFFSET ?", max, offset)
} else {
rs, err = amdb.Query("SELECT u.uid FROM users u, contacts c WHERE u.contactid = c.contactid AND u.is_anon = 0 AND "+q+
rs, err = amdb.QueryContext(ctx, "SELECT u.uid FROM users u, contacts c WHERE u.contactid = c.contactid AND u.is_anon = 0 AND "+q+
" ORDER BY u.username LIMIT ?", max)
}
if err != nil {
@@ -928,7 +943,7 @@ func AmSearchUsers(field int, oper int, term string, offset int, max int) ([]*Us
for rs.Next() {
var uid int32
rs.Scan(&uid)
u, err := AmGetUser(uid)
u, err := AmGetUser(ctx, uid)
if err == nil {
rc = append(rc, u)
}