refactoring: use QueryRowContext instead of QueryContext when we only need one row
This commit is contained in:
+8
-18
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Amsterdam Web Communities System
|
* Amsterdam Web Communities System
|
||||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -11,6 +11,7 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -64,19 +65,13 @@ func loadCategories(ctx context.Context) error {
|
|||||||
categoryMutex.Lock()
|
categoryMutex.Lock()
|
||||||
defer categoryMutex.Unlock()
|
defer categoryMutex.Unlock()
|
||||||
if allCategories == nil {
|
if allCategories == nil {
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT COUNT(*) FROM refcategory")
|
row := amdb.QueryRowContext(ctx, "SELECT COUNT(*) FROM refcategory")
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return errors.New("internal error loading categories")
|
|
||||||
}
|
|
||||||
var ncats int32
|
var ncats int32
|
||||||
if err = rs.Scan(&ncats); err != nil {
|
if err := row.Scan(&ncats); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
allCategories = make([]Category, 0, ncats)
|
allCategories = make([]Category, 0, ncats)
|
||||||
if err = amdb.SelectContext(ctx, &allCategories, "SELECT * FROM refcategory ORDER BY parent, name"); err != nil {
|
if err := amdb.SelectContext(ctx, &allCategories, "SELECT * FROM refcategory ORDER BY parent, name"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for i, c := range allCategories {
|
for i, c := range allCategories {
|
||||||
@@ -234,20 +229,15 @@ func AmSearchCategories(ctx context.Context, oper int, term string, offset int,
|
|||||||
queryString.WriteString(" AND hide_search = 0")
|
queryString.WriteString(" AND hide_search = 0")
|
||||||
}
|
}
|
||||||
q := queryString.String()
|
q := queryString.String()
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT COUNT(*) FROM refcategory WHERE "+q)
|
row := amdb.QueryRowContext(ctx, "SELECT COUNT(*) FROM refcategory WHERE "+q)
|
||||||
if err != nil {
|
|
||||||
return nil, -1, err
|
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return nil, -1, errors.New("internal error getting category total")
|
|
||||||
}
|
|
||||||
var total int
|
var total int
|
||||||
if err = rs.Scan(&total); err != nil {
|
if err = row.Scan(&total); err != nil {
|
||||||
return nil, total, err
|
return nil, total, err
|
||||||
}
|
}
|
||||||
if total == 0 {
|
if total == 0 {
|
||||||
return make([]*Category, 0), 0, nil
|
return make([]*Category, 0), 0, nil
|
||||||
}
|
}
|
||||||
|
var rs *sql.Rows
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
rs, err = amdb.QueryContext(ctx, "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 {
|
} else {
|
||||||
|
|||||||
+76
-122
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Amsterdam Web Communities System
|
* Amsterdam Web Communities System
|
||||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -215,44 +215,35 @@ func (c *Community) Membership(ctx context.Context, u *User) (bool, bool, uint16
|
|||||||
// "no join required" - they are effectively a member, but don't cache that
|
// "no join required" - they are effectively a member, but don't cache that
|
||||||
return true, false, u.BaseLevel, nil
|
return true, false, u.BaseLevel, nil
|
||||||
}
|
}
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT locked, granted_lvl FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
|
row := amdb.QueryRowContext(ctx, "SELECT locked, granted_lvl FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
|
||||||
|
var locked bool
|
||||||
|
var level uint16
|
||||||
|
err := row.Scan(&locked, &level)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if rs.Next() {
|
memberCache.Add(key, &memberCacheData{isMember: true, locked: locked, level: level})
|
||||||
var locked bool
|
return true, locked, level, nil
|
||||||
var level uint16
|
}
|
||||||
if err = rs.Scan(&locked, &level); err == nil {
|
if err == sql.ErrNoRows {
|
||||||
memberCache.Add(key, &memberCacheData{isMember: true, locked: locked, level: level})
|
err = nil
|
||||||
return true, locked, level, nil
|
memberCache.Add(key, &memberCacheData{isMember: false, locked: false, level: uint16(0)})
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
memberCache.Add(key, &memberCacheData{isMember: false, locked: false, level: uint16(0)})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false, false, uint16(0), err
|
return false, false, uint16(0), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MemberCount returns the number of members in the community.
|
// MemberCount returns the number of members in the community.
|
||||||
func (c *Community) MemberCount(ctx context.Context, hidden bool) (int, error) {
|
func (c *Community) MemberCount(ctx context.Context, hidden bool) (int, error) {
|
||||||
var rs *sql.Rows
|
var row *sql.Row
|
||||||
var err error
|
|
||||||
if hidden {
|
if hidden {
|
||||||
rs, err = amdb.QueryContext(ctx, "SELECT COUNT(*) FROM commmember WHERE commid = ?", c.Id)
|
row = amdb.QueryRowContext(ctx, "SELECT COUNT(*) FROM commmember WHERE commid = ?", c.Id)
|
||||||
} else {
|
} else {
|
||||||
rs, err = amdb.QueryContext(ctx, "SELECT COUNT(*) FROM commmember WHERE commid = ? AND hidden = 0", c.Id)
|
row = amdb.QueryRowContext(ctx, "SELECT COUNT(*) FROM commmember WHERE commid = ? AND hidden = 0", c.Id)
|
||||||
}
|
}
|
||||||
if err != nil {
|
var rc int
|
||||||
|
if err := row.Scan(&rc); err == nil {
|
||||||
|
return rc, nil
|
||||||
|
} else {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
if rs.Next() {
|
|
||||||
var rc int
|
|
||||||
if err = rs.Scan(&rc); err == nil {
|
|
||||||
return rc, nil
|
|
||||||
} else {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, errors.New("internal error reading member count")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ListMembers lists or searches for community members matching certain criteria.
|
/* ListMembers lists or searches for community members matching certain criteria.
|
||||||
@@ -314,16 +305,12 @@ func (c *Community) ListMembers(ctx context.Context, field int, oper int, term s
|
|||||||
query.WriteString(" AND m.hidden = 0")
|
query.WriteString(" AND m.hidden = 0")
|
||||||
}
|
}
|
||||||
q := query.String()
|
q := query.String()
|
||||||
rs, err := amdb.QueryContext(ctx, `SELECT COUNT(*) FROM commmember m, users u, contacts c WHERE m.commid = ? AND m.uid = u.uid
|
row := amdb.QueryRowContext(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)
|
AND u.contactid = c.contactid`+q, c.Id)
|
||||||
if err != nil {
|
|
||||||
return nil, -1, err
|
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return nil, -1, errors.New("internal error getting member count")
|
|
||||||
}
|
|
||||||
var total int
|
var total int
|
||||||
if err = rs.Scan(&total); err == nil {
|
var err error
|
||||||
|
var rs *sql.Rows
|
||||||
|
if err = row.Scan(&total); err == nil {
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
rs, err = amdb.QueryContext(ctx, `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)
|
AND u.contactid = c.contactid`+q+" ORDER BY u.username LIMIT ? OFFSET ?", c.Id, max, offset)
|
||||||
@@ -381,35 +368,30 @@ func (c *Community) SetMembership(ctx context.Context, u *User, level uint16, lo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rs, err := tx.QueryContext(ctx, "SELECT granted_lvl, locked FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
|
row := tx.QueryRowContext(ctx, "SELECT granted_lvl, locked FROM commmember WHERE commid = ? AND uid = ?", c.Id, u.Uid)
|
||||||
|
var oldLevel uint16
|
||||||
|
var lockStatus bool
|
||||||
|
err := row.Scan(&oldLevel, &lockStatus)
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
if level != oldLevel || lockStatus != locked {
|
||||||
|
_, err = tx.ExecContext(ctx, "UPDATE commmember SET granted_lvl = ?, locked = ? WHERE commid = ? AND uid = ?",
|
||||||
|
level, locked, c.Id, u.Uid)
|
||||||
|
if err == nil {
|
||||||
|
stuffMembership(c.Id, u.Uid, true, locked, level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case sql.ErrNoRows:
|
||||||
|
_, err = tx.ExecContext(ctx, "INSERT INTO commmember (commid, uid, granted_lvl, locked) VALUES (?, ?, ?, ?)",
|
||||||
|
c.Id, u.Uid, level, locked)
|
||||||
|
if err == nil {
|
||||||
|
stuffMembership(c.Id, u.Uid, true, locked, level)
|
||||||
|
err = AmOnUserJoinCommunityServices(ctx, tx, c, u)
|
||||||
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if rs.Next() {
|
|
||||||
var oldLevel uint16
|
|
||||||
var lockStatus bool
|
|
||||||
if err = rs.Scan(&oldLevel, &lockStatus); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if level != oldLevel || lockStatus != locked {
|
|
||||||
_, 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
|
|
||||||
}
|
|
||||||
stuffMembership(c.Id, u.Uid, true, locked, level)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, 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)
|
|
||||||
if err = AmOnUserJoinCommunityServices(ctx, tx, c, u); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err := c.TouchUpdateTx(ctx, tx); err == nil {
|
if err := c.TouchUpdateTx(ctx, tx); err == nil {
|
||||||
ar := AmNewAudit(AuditCommunitySetMembership, personUID, ipaddr, fmt.Sprintf("cid=%d", c.Id),
|
ar := AmNewAudit(AuditCommunitySetMembership, personUID, ipaddr, fmt.Sprintf("cid=%d", c.Id),
|
||||||
@@ -518,11 +500,8 @@ func (c *Community) SetProfileData(ctx context.Context, name string, alias strin
|
|||||||
c.CreateLevel = create_lvl
|
c.CreateLevel = create_lvl
|
||||||
c.DeleteLevel = delete_lvl
|
c.DeleteLevel = delete_lvl
|
||||||
c.JoinLevel = join_lvl
|
c.JoinLevel = join_lvl
|
||||||
rs, err2 := amdb.QueryContext(ctx, "SELECT lastupdate FROM communities WHERE commid = ?", c.Id)
|
row := amdb.QueryRowContext(ctx, "SELECT lastupdate FROM communities WHERE commid = ?", c.Id)
|
||||||
if err2 == nil {
|
err2 := row.Scan(&(c.LastUpdate))
|
||||||
rs.Next()
|
|
||||||
err2 = rs.Scan(&c.LastUpdate)
|
|
||||||
}
|
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
log.Errorf("SetProfileData scan error: %v", err2)
|
log.Errorf("SetProfileData scan error: %v", err2)
|
||||||
}
|
}
|
||||||
@@ -547,13 +526,10 @@ func (c *Community) Touch(ctx context.Context) error {
|
|||||||
defer c.Mutex.Unlock()
|
defer c.Mutex.Unlock()
|
||||||
_, err := amdb.ExecContext(ctx, "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 {
|
if err == nil {
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT lastaccess FROM communities WHERE commid = ?", c.Id)
|
row := amdb.QueryRowContext(ctx, "SELECT lastaccess FROM communities WHERE commid = ?", c.Id)
|
||||||
if err == nil {
|
var na time.Time
|
||||||
rs.Next()
|
if err = row.Scan(&na); err == nil {
|
||||||
var na time.Time
|
c.LastAccess = &na
|
||||||
if err = rs.Scan(&na); err == nil {
|
|
||||||
c.LastAccess = &na
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -565,14 +541,11 @@ func (c *Community) TouchUpdateTx(ctx context.Context, tx *sqlx.Tx) error {
|
|||||||
defer c.Mutex.Unlock()
|
defer c.Mutex.Unlock()
|
||||||
_, err := tx.ExecContext(ctx, "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 {
|
if err == nil {
|
||||||
rs, err := tx.QueryContext(ctx, "SELECT lastaccess, lastupdate FROM communities WHERE commid = ?", c.Id)
|
row := tx.QueryRowContext(ctx, "SELECT lastaccess, lastupdate FROM communities WHERE commid = ?", c.Id)
|
||||||
if err != nil {
|
var na, nu time.Time
|
||||||
rs.Next()
|
if err = row.Scan(&na, &nu); err == nil {
|
||||||
var na, nu time.Time
|
c.LastAccess = &na
|
||||||
if err = rs.Scan(&na, &nu); err == nil {
|
c.LastUpdate = &nu
|
||||||
c.LastAccess = &na
|
|
||||||
c.LastUpdate = &nu
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -657,16 +630,11 @@ func AmGetCommunityTx(ctx context.Context, tx *sqlx.Tx, id int32) (*Community, e
|
|||||||
* Standard Go error status (nil if community not found)
|
* Standard Go error status (nil if community not found)
|
||||||
*/
|
*/
|
||||||
func AmGetCommunityByAlias(ctx context.Context, alias string) (*Community, error) {
|
func AmGetCommunityByAlias(ctx context.Context, alias string) (*Community, error) {
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT commid FROM communities WHERE alias = ?", alias)
|
row := amdb.QueryRowContext(ctx, "SELECT commid FROM communities WHERE alias = ?", alias)
|
||||||
|
var cid int32
|
||||||
|
err := row.Scan(&cid)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if rs.Next() {
|
return AmGetCommunity(ctx, cid)
|
||||||
var cid int32
|
|
||||||
if err = rs.Scan(&cid); err == nil {
|
|
||||||
return AmGetCommunity(ctx, cid)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -681,16 +649,11 @@ func AmGetCommunityByAlias(ctx context.Context, alias string) (*Community, error
|
|||||||
* Standard Go error status (nil if community not found)
|
* Standard Go error status (nil if community not found)
|
||||||
*/
|
*/
|
||||||
func AmGetCommunityByAliasTx(ctx context.Context, tx *sqlx.Tx, alias string) (*Community, error) {
|
func AmGetCommunityByAliasTx(ctx context.Context, tx *sqlx.Tx, alias string) (*Community, error) {
|
||||||
rs, err := tx.QueryContext(ctx, "SELECT commid FROM communities WHERE alias = ?", alias)
|
row := tx.QueryRowContext(ctx, "SELECT commid FROM communities WHERE alias = ?", alias)
|
||||||
|
var cid int32
|
||||||
|
err := row.Scan(&cid)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if rs.Next() {
|
return AmGetCommunityTx(ctx, tx, cid)
|
||||||
var cid int32
|
|
||||||
if err = rs.Scan(&cid); err == nil {
|
|
||||||
return AmGetCommunityTx(ctx, tx, cid)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -916,13 +879,14 @@ func AmCreateCommunity(ctx context.Context, name string, alias string, hostUid i
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// validate alias does not already exist
|
// validate alias does not already exist
|
||||||
rs, err := tx.QueryContext(ctx, "SELECT commid FROM communities WHERE alias = ?", alias)
|
row := tx.QueryRowContext(ctx, "SELECT commid FROM communities WHERE alias = ?", alias)
|
||||||
if err != nil {
|
err := row.Err()
|
||||||
|
if err != sql.ErrNoRows {
|
||||||
|
if err == nil {
|
||||||
|
err = errors.New("a community with that alias already exists")
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if rs.Next() {
|
|
||||||
return nil, errors.New("a community with that alias already exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
// establish the community record
|
// establish the community record
|
||||||
_, err = tx.ExecContext(ctx, `INSERT INTO communities (createdate, lastaccess, lastupdate, read_lvl, write_lvl,
|
_, err = tx.ExecContext(ctx, `INSERT INTO communities (createdate, lastaccess, lastupdate, read_lvl, write_lvl,
|
||||||
@@ -982,24 +946,19 @@ func AmCreateCommunity(ctx context.Context, name string, alias string, hostUid i
|
|||||||
* Standard Go error status.
|
* Standard Go error status.
|
||||||
*/
|
*/
|
||||||
func AmGetCommunitiesForCategory(ctx context.Context, 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
|
var err error
|
||||||
|
var row *sql.Row
|
||||||
if showAll {
|
if showAll {
|
||||||
rs, err = amdb.QueryContext(ctx, "SELECT COUNT(*) FROM communities WHERE catid = ?", catid)
|
row = amdb.QueryRowContext(ctx, "SELECT COUNT(*) FROM communities WHERE catid = ?", catid)
|
||||||
} else {
|
} else {
|
||||||
rs, err = amdb.QueryContext(ctx, "SELECT COUNT(*) FROM communities WHERE catid = ? AND hide_dir = 0", catid)
|
row = amdb.QueryRowContext(ctx, "SELECT COUNT(*) FROM communities WHERE catid = ? AND hide_dir = 0", catid)
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, -1, err
|
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return nil, -1, errors.New("internal error getting total match count")
|
|
||||||
}
|
}
|
||||||
var total int
|
var total int
|
||||||
err = rs.Scan(&total)
|
err = row.Scan(&total)
|
||||||
if err != nil || total == 0 {
|
if err != nil || total == 0 {
|
||||||
return make([]*Community, 0), 0, err // short-circuit return
|
return make([]*Community, 0), 0, err // short-circuit return
|
||||||
}
|
}
|
||||||
|
var rs *sql.Rows
|
||||||
if showAll {
|
if showAll {
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
rs, err = amdb.QueryContext(ctx, "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 ?",
|
||||||
@@ -1081,18 +1040,13 @@ func AmSearchCommunities(ctx context.Context, field int, oper int, term string,
|
|||||||
queryPortion.WriteString(" AND hide_search = 0")
|
queryPortion.WriteString(" AND hide_search = 0")
|
||||||
}
|
}
|
||||||
q := queryPortion.String()
|
q := queryPortion.String()
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT COUNT(*) FROM communities "+q)
|
row := amdb.QueryRowContext(ctx, "SELECT COUNT(*) FROM communities "+q)
|
||||||
if err != nil {
|
|
||||||
return nil, -1, err
|
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return nil, -1, errors.New("internal error getting count")
|
|
||||||
}
|
|
||||||
var total int
|
var total int
|
||||||
err = rs.Scan(&total)
|
err := row.Scan(&total)
|
||||||
if err != nil || total == 0 {
|
if err != nil || total == 0 {
|
||||||
return make([]*Community, 0), 0, err // short-circuit return
|
return make([]*Community, 0), 0, err // short-circuit return
|
||||||
}
|
}
|
||||||
|
var rs *sql.Rows
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
rs, err = amdb.QueryContext(ctx, "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 {
|
} else {
|
||||||
|
|||||||
+23
-30
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Amsterdam Web Communities System
|
* Amsterdam Web Communities System
|
||||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -11,6 +11,7 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -119,19 +120,16 @@ func (c *Conference) HostsQ(ctx context.Context) []*User {
|
|||||||
|
|
||||||
// Membership returns a membership flag and granted level for the user in this conference.
|
// Membership returns a membership flag and granted level for the user in this conference.
|
||||||
func (c *Conference) Membership(ctx context.Context, u *User) (bool, uint16, error) {
|
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)
|
row := amdb.QueryRowContext(ctx, "SELECT granted_lvl FROM confmember WHERE confid = ? AND uid = ?", c.ConfId, u.Uid)
|
||||||
if err != nil {
|
var level uint16
|
||||||
return false, 0, err
|
err := row.Scan(&level)
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
return true, level, nil
|
||||||
|
case sql.ErrNoRows:
|
||||||
|
return false, 0, nil
|
||||||
}
|
}
|
||||||
rc := false
|
return false, 0, err
|
||||||
if rs.Next() {
|
|
||||||
rc = true
|
|
||||||
var level uint16
|
|
||||||
if err = rs.Scan(&level); err == nil {
|
|
||||||
return rc, level, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rc, 0, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TestPermission is shorthand that tests if a user has a permission with respect to the conference.
|
/* TestPermission is shorthand that tests if a user has a permission with respect to the conference.
|
||||||
@@ -306,14 +304,11 @@ func AmGetConferenceByAlias(ctx context.Context, alias string) (*Conference, err
|
|||||||
if ok {
|
if ok {
|
||||||
confid = xconf.(int32)
|
confid = xconf.(int32)
|
||||||
} else {
|
} else {
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT confid FROM confalias WHERE alias = ?", alias)
|
row := amdb.QueryRowContext(ctx, "SELECT confid FROM confalias WHERE alias = ?", alias)
|
||||||
if err != nil {
|
err := row.Scan(&confid)
|
||||||
return nil, err
|
if err == sql.ErrNoRows {
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return nil, fmt.Errorf("alias not found: %s", alias)
|
return nil, fmt.Errorf("alias not found: %s", alias)
|
||||||
}
|
} else if err != nil {
|
||||||
if err = rs.Scan(&confid); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
conferenceAliasMap.Store(alias, confid)
|
conferenceAliasMap.Store(alias, confid)
|
||||||
@@ -331,19 +326,17 @@ func AmGetConferenceByAlias(ctx context.Context, alias string) (*Conference, err
|
|||||||
* Standard Go error status.
|
* Standard Go error status.
|
||||||
*/
|
*/
|
||||||
func AmGetConferenceByAliasInCommunity(ctx context.Context, cid int32, alias string) (*Conference, error) {
|
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
|
row := amdb.QueryRowContext(ctx, `SELECT c.confid FROM commtoconf c, confalias a WHERE c.confid = a.confid
|
||||||
AND c.commid = ? AND a.alias = ?`, cid, alias)
|
AND c.commid = ? AND a.alias = ?`, cid, alias)
|
||||||
if err != nil {
|
var confid int32
|
||||||
return nil, err
|
err := row.Scan(&confid)
|
||||||
}
|
switch err {
|
||||||
if !rs.Next() {
|
case nil:
|
||||||
|
AmGetConference(ctx, confid)
|
||||||
|
case sql.ErrNoRows:
|
||||||
return nil, errors.New("conference not found")
|
return nil, errors.New("conference not found")
|
||||||
}
|
}
|
||||||
var confid int32
|
return nil, err
|
||||||
if err = rs.Scan(&confid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return AmGetConference(ctx, confid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AmGetCommunityConferences returns all conferences for a given community.
|
/* AmGetCommunityConferences returns all conferences for a given community.
|
||||||
|
|||||||
+13
-24
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Amsterdam Web Communities System
|
* Amsterdam Web Communities System
|
||||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -11,7 +11,7 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -54,24 +54,16 @@ type ContactInfo struct {
|
|||||||
// lookupCommunityContact looks up the ID of a contact for a community.
|
// lookupCommunityContact looks up the ID of a contact for a community.
|
||||||
func lookupCommunityContact(ctx context.Context, id int32) (int32, error) {
|
func lookupCommunityContact(ctx context.Context, id int32) (int32, error) {
|
||||||
var rc int32 = -1
|
var rc int32 = -1
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT contactid FROM contacts WHERE owner_commid = ?", id)
|
row := amdb.QueryRowContext(ctx, "SELECT contactid FROM contacts WHERE owner_commid = ?", id)
|
||||||
if err == nil {
|
err := row.Scan(&rc)
|
||||||
if rs.Next() {
|
|
||||||
err = rs.Scan(&rc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rc, err
|
return rc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookupUserContact looks up the ID of a contact for a user.
|
// lookupUserContact looks up the ID of a contact for a user.
|
||||||
func lookupUserContact(ctx context.Context, uid int32) (int32, error) {
|
func lookupUserContact(ctx context.Context, uid int32) (int32, error) {
|
||||||
var rc int32 = -1
|
var rc int32 = -1
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT contactid FROM contacts WHERE owner_uid = ? AND owner_commid = -1", uid)
|
row := amdb.QueryRowContext(ctx, "SELECT contactid FROM contacts WHERE owner_uid = ? AND owner_commid = -1", uid)
|
||||||
if err == nil {
|
err := row.Scan(&rc)
|
||||||
if rs.Next() {
|
|
||||||
err = rs.Scan(&rc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rc, err
|
return rc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,12 +142,12 @@ func (ci *ContactInfo) Save(ctx context.Context) (bool, error) {
|
|||||||
}
|
}
|
||||||
if !emailChange {
|
if !emailChange {
|
||||||
// we don't THINK the E-mail address is changing, but we could be wrong...
|
// we don't THINK the E-mail address is changing, but we could be wrong...
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT contactid FROM contacts WHERE contactid = ? AND email = ?", ci.ContactId, ci.Email)
|
row := amdb.QueryRowContext(ctx, "SELECT contactid FROM contacts WHERE contactid = ? AND email = ?", ci.ContactId, ci.Email)
|
||||||
if err != nil {
|
err := row.Err()
|
||||||
return false, err
|
if err == sql.ErrNoRows {
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
emailChange = true
|
emailChange = true
|
||||||
|
} else if err != nil {
|
||||||
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Handle the database heavy lifting.
|
// Handle the database heavy lifting.
|
||||||
@@ -184,14 +176,11 @@ func (ci *ContactInfo) Save(ctx context.Context) (bool, error) {
|
|||||||
contactCache.Add(ci.ContactId, ci)
|
contactCache.Add(ci.ContactId, ci)
|
||||||
}
|
}
|
||||||
// Refresh the last update date.
|
// Refresh the last update date.
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT lastupdate FROM contacts WHERE contactid = ?", ci.ContactId)
|
row := amdb.QueryRowContext(ctx, "SELECT lastupdate FROM contacts WHERE contactid = ?", ci.ContactId)
|
||||||
|
err := row.Scan(&(ci.LastUpdate))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if !rs.Next() {
|
|
||||||
return false, errors.New("internal error rereading update timestamp")
|
|
||||||
}
|
|
||||||
err = rs.Scan(&ci.LastUpdate)
|
|
||||||
return emailChange, err
|
return emailChange, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-6
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Amsterdam Web Communities System
|
* Amsterdam Web Communities System
|
||||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -9,7 +9,10 @@
|
|||||||
// The database package contains database management and storage logic.
|
// The database package contains database management and storage logic.
|
||||||
package database
|
package database
|
||||||
|
|
||||||
import "context"
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
/* AmIsEmailAddressBanned returns true if the given E-mail address is on the "banned" list.
|
/* AmIsEmailAddressBanned returns true if the given E-mail address is on the "banned" list.
|
||||||
* Parameters:
|
* Parameters:
|
||||||
@@ -20,9 +23,12 @@ import "context"
|
|||||||
* Standard Go error status.
|
* Standard Go error status.
|
||||||
*/
|
*/
|
||||||
func AmIsEmailAddressBanned(ctx context.Context, address string) (bool, error) {
|
func AmIsEmailAddressBanned(ctx context.Context, address string) (bool, error) {
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT by_uid FROM emailban WHERE address = ?", address)
|
row := amdb.QueryRowContext(ctx, "SELECT by_uid FROM emailban WHERE address = ?", address)
|
||||||
if err != nil {
|
switch row.Err() {
|
||||||
return false, err
|
case nil:
|
||||||
|
return true, nil
|
||||||
|
case sql.ErrNoRows:
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
return rs.Next(), nil
|
return false, row.Err()
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-17
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Amsterdam Web Communities System
|
* Amsterdam Web Communities System
|
||||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -11,6 +11,7 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -115,23 +116,20 @@ func AmGlobals(ctx context.Context) (*Globals, error) {
|
|||||||
func AmGetGlobalProperty(ctx context.Context, index int32) (string, error) {
|
func AmGetGlobalProperty(ctx context.Context, index int32) (string, error) {
|
||||||
globalPropMutex.Lock()
|
globalPropMutex.Lock()
|
||||||
defer globalPropMutex.Unlock()
|
defer globalPropMutex.Unlock()
|
||||||
|
var err error = nil
|
||||||
rc, ok := globalProps[index]
|
rc, ok := globalProps[index]
|
||||||
if !ok {
|
if !ok {
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT data FROM propglobal WHERE ndx = ?", index)
|
row := amdb.QueryRowContext(ctx, "SELECT data FROM propglobal WHERE ndx = ?", index)
|
||||||
if err != nil {
|
err = row.Scan(&rc)
|
||||||
return "", err
|
switch err {
|
||||||
}
|
case nil:
|
||||||
if rs.Next() {
|
|
||||||
err = rs.Scan(&rc)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
globalProps[index] = rc
|
globalProps[index] = rc
|
||||||
return rc, nil
|
case sql.ErrNoRows:
|
||||||
|
rc = ""
|
||||||
|
err = nil
|
||||||
}
|
}
|
||||||
rc = ""
|
|
||||||
}
|
}
|
||||||
return rc, nil
|
return rc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AmSetGlobalProperty sets the value of a global property.
|
/* AmSetGlobalProperty sets the value of a global property.
|
||||||
@@ -147,11 +145,15 @@ func AmSetGlobalProperty(ctx context.Context, index int32, value string) error {
|
|||||||
defer globalPropMutex.Unlock()
|
defer globalPropMutex.Unlock()
|
||||||
_, updateMode := globalProps[index]
|
_, updateMode := globalProps[index]
|
||||||
if !updateMode {
|
if !updateMode {
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT data FROM propglobal WHERE ndx = ?", index)
|
row := amdb.QueryRowContext(ctx, "SELECT data FROM propglobal WHERE ndx = ?", index)
|
||||||
if err != nil {
|
switch row.Err() {
|
||||||
return err
|
case nil:
|
||||||
|
updateMode = true
|
||||||
|
case sql.ErrNoRows:
|
||||||
|
updateMode = false
|
||||||
|
default:
|
||||||
|
return row.Err()
|
||||||
}
|
}
|
||||||
updateMode = rs.Next()
|
|
||||||
}
|
}
|
||||||
var err error = nil
|
var err error = nil
|
||||||
if updateMode {
|
if updateMode {
|
||||||
|
|||||||
+9
-12
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Amsterdam Web Communities System
|
* Amsterdam Web Communities System
|
||||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -86,17 +86,12 @@ func AmLoadImage(ctx context.Context, id int32) (*ImageStore, error) {
|
|||||||
* Standard Go error status.
|
* Standard Go error status.
|
||||||
*/
|
*/
|
||||||
func AmStoreImage(ctx context.Context, typecode int16, owner int32, mimetype string, data []byte) (*ImageStore, error) {
|
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
|
|
||||||
}
|
|
||||||
var img *ImageStore
|
var img *ImageStore
|
||||||
if rs.Next() {
|
row := amdb.QueryRowContext(ctx, "SELECT imgid FROM imagestore WHERE typecode = ? AND ownerid = ?", typecode, owner)
|
||||||
var id int32
|
var id int32
|
||||||
err = rs.Scan(&id)
|
err := row.Scan(&id)
|
||||||
if err != nil {
|
switch err {
|
||||||
return nil, err
|
case nil:
|
||||||
}
|
|
||||||
img, err = AmLoadImage(ctx, id)
|
img, err = AmLoadImage(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -104,7 +99,7 @@ func AmStoreImage(ctx context.Context, typecode int16, owner int32, mimetype str
|
|||||||
img.MimeType = mimetype
|
img.MimeType = mimetype
|
||||||
img.Length = int32(len(data))
|
img.Length = int32(len(data))
|
||||||
img.Data = data
|
img.Data = data
|
||||||
} else {
|
case sql.ErrNoRows:
|
||||||
img = &ImageStore{
|
img = &ImageStore{
|
||||||
ImgId: -1,
|
ImgId: -1,
|
||||||
TypeCode: typecode,
|
TypeCode: typecode,
|
||||||
@@ -113,6 +108,8 @@ func AmStoreImage(ctx context.Context, typecode int16, owner int32, mimetype str
|
|||||||
Length: int32(len(data)),
|
Length: int32(len(data)),
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
err = img.Save(ctx)
|
err = img.Save(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+10
-13
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Amsterdam Web Communities System
|
* Amsterdam Web Communities System
|
||||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -11,6 +11,7 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
@@ -65,21 +66,17 @@ func AmTestIPBan(ctx context.Context, ip_address string) (string, error) {
|
|||||||
iv.SetBytes(addr)
|
iv.SetBytes(addr)
|
||||||
iv_lo := big.NewInt(0).And(iv, low64mask).Uint64()
|
iv_lo := big.NewInt(0).And(iv, low64mask).Uint64()
|
||||||
iv_hi := big.NewInt(0).Rsh(iv, 64).Uint64()
|
iv_hi := big.NewInt(0).Rsh(iv, 64).Uint64()
|
||||||
rows, err := amdb.QueryContext(ctx, `SELECT message FROM ipban WHERE (address_lo & mask_lo) = (? & mask_lo)
|
row := amdb.QueryRowContext(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 (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())
|
AND enable <> 0 ORDER BY mask_hi DESC, mask_lo DESC`, iv_lo, iv_hi, time.Now().UTC())
|
||||||
if err != nil {
|
err := row.Scan(&rc)
|
||||||
return "", err
|
switch err {
|
||||||
}
|
case nil:
|
||||||
defer rows.Close()
|
|
||||||
if rows.Next() {
|
|
||||||
err = rows.Scan(&rc)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
knownBans[ip_address] = rc
|
knownBans[ip_address] = rc
|
||||||
return rc, nil
|
return rc, nil
|
||||||
|
case sql.ErrNoRows:
|
||||||
|
knownGood[ip_address] = true
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
knownGood[ip_address] = true
|
return "", err
|
||||||
return "", nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-33
@@ -13,6 +13,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -63,15 +64,9 @@ func (p *PostHeader) IsScribbled() bool {
|
|||||||
|
|
||||||
// IsPublished returns true if the post has been published to the front page.
|
// IsPublished returns true if the post has been published to the front page.
|
||||||
func (p *PostHeader) IsPublished(ctx context.Context) (bool, error) {
|
func (p *PostHeader) IsPublished(ctx context.Context) (bool, error) {
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT COUNT(*) FROM postpublish WHERE postid = ?", p.PostId)
|
row := amdb.QueryRowContext(ctx, "SELECT COUNT(*) FROM postpublish WHERE postid = ?", p.PostId)
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return false, errors.New("internal failure in IsPublished")
|
|
||||||
}
|
|
||||||
ct := 0
|
ct := 0
|
||||||
err = rs.Scan(&ct)
|
err := row.Scan(&ct)
|
||||||
return ct > 0, err
|
return ct > 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,16 +81,16 @@ func (p *PostHeader) AttachmentInfo(ctx context.Context) (*PostAttachInfo, error
|
|||||||
if p.ScribbleDate != nil && p.ScribbleUid != nil {
|
if p.ScribbleDate != nil && p.ScribbleUid != nil {
|
||||||
return nil, errors.New("no attachment data for scribbled post")
|
return nil, errors.New("no attachment data for scribbled post")
|
||||||
}
|
}
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT filename, mimetype, datalen FROM postattach WHERE postid = ?", p.PostId)
|
row := amdb.QueryRowContext(ctx, "SELECT filename, mimetype, datalen FROM postattach WHERE postid = ?", p.PostId)
|
||||||
if err != nil {
|
var rc PostAttachInfo
|
||||||
return nil, err
|
err := row.Scan(&(rc.Filename), &(rc.MIMEType), &(rc.Length))
|
||||||
}
|
switch err {
|
||||||
if !rs.Next() {
|
case nil:
|
||||||
|
return &rc, nil
|
||||||
|
case sql.ErrNoRows:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var rc PostAttachInfo
|
return nil, err
|
||||||
err = rs.Scan(&(rc.Filename), &(rc.MIMEType), &(rc.Length))
|
|
||||||
return &rc, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AttachmentData returns attachment data for a post.
|
/* AttachmentData returns attachment data for a post.
|
||||||
@@ -109,18 +104,14 @@ func (p *PostHeader) AttachmentData(ctx context.Context) ([]byte, error) {
|
|||||||
if p.ScribbleDate != nil && p.ScribbleUid != nil {
|
if p.ScribbleDate != nil && p.ScribbleUid != nil {
|
||||||
return nil, errors.New("no attachment data for scribbled post")
|
return nil, errors.New("no attachment data for scribbled post")
|
||||||
}
|
}
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT datalen, stgmethod, data FROM postattach WHERE postid = ?", p.PostId)
|
row := amdb.QueryRowContext(ctx, "SELECT datalen, stgmethod, data FROM postattach WHERE postid = ?", p.PostId)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
var datalen int32
|
var datalen int32
|
||||||
var stgmethod int16
|
var stgmethod int16
|
||||||
var dbdata []byte
|
var dbdata []byte
|
||||||
err = rs.Scan(&datalen, &stgmethod, &dbdata)
|
err := row.Scan(&datalen, &stgmethod, &dbdata)
|
||||||
if err != nil {
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if stgmethod == stgMethodPlain {
|
if stgmethod == stgMethodPlain {
|
||||||
@@ -281,15 +272,9 @@ func (p *PostHeader) Scribble(ctx context.Context, u *User, ipaddr string) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reread the scribble date.
|
// Reread the scribble date.
|
||||||
rs, err := tx.QueryContext(ctx, "SELECT scribble_date FROM posts WHERE postid = ?", p.PostId)
|
row := tx.QueryRowContext(ctx, "SELECT scribble_date FROM posts WHERE postid = ?", p.PostId)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return errors.New("internal error while scribbling")
|
|
||||||
}
|
|
||||||
var newScribbleDate time.Time
|
var newScribbleDate time.Time
|
||||||
if err = rs.Scan(&newScribbleDate); err != nil {
|
if err = row.Scan(&newScribbleDate); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-14
@@ -56,14 +56,9 @@ func (t *Topic) GetPost(ctx context.Context, num int32) (*PostHeader, error) {
|
|||||||
|
|
||||||
// GetLastRead returns the "last read" message for a user on a topic.
|
// GetLastRead returns the "last read" message for a user on a topic.
|
||||||
func (t *Topic) GetLastRead(ctx context.Context, u *User) (int32, error) {
|
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)
|
row := amdb.QueryRowContext(ctx, "SELECT last_message FROM topicsettings WHERE topicid = ? AND uid = ?", t.TopicId, u.Uid)
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
var rc int32 = -1
|
var rc int32 = -1
|
||||||
if rs.Next() {
|
err := row.Scan(&rc)
|
||||||
err = rs.Scan(&rc)
|
|
||||||
}
|
|
||||||
return rc, err
|
return rc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,14 +78,9 @@ func (t *Topic) SetLastRead(ctx context.Context, u *User, postNum int32) error {
|
|||||||
|
|
||||||
// IsHidden tells us whether the user has the topic hidden.
|
// IsHidden tells us whether the user has the topic hidden.
|
||||||
func (t *Topic) IsHidden(ctx context.Context, u *User) (bool, error) {
|
func (t *Topic) IsHidden(ctx context.Context, u *User) (bool, error) {
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT hidden FROM topicsettings WHERE topicid = ? AND uid = ?", t.TopicId, u.Uid)
|
row := amdb.QueryRowContext(ctx, "SELECT hidden FROM topicsettings WHERE topicid = ? AND uid = ?", t.TopicId, u.Uid)
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
rc := false
|
rc := false
|
||||||
if rs.Next() {
|
err := row.Scan(&rc)
|
||||||
err = rs.Scan(&rc)
|
|
||||||
}
|
|
||||||
return rc, err
|
return rc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-26
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Amsterdam Web Communities System
|
* Amsterdam Web Communities System
|
||||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -12,6 +12,7 @@ package database
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"database/sql"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -465,18 +466,8 @@ func AmGetUserByName(ctx context.Context, name string, tx *sqlx.Tx) (*User, erro
|
|||||||
// getAnonUserID retrieves the UID of the "anonymous" user from the database.
|
// getAnonUserID retrieves the UID of the "anonymous" user from the database.
|
||||||
func getAnonUserID(ctx context.Context) (int32, error) {
|
func getAnonUserID(ctx context.Context) (int32, error) {
|
||||||
if anonUid < 0 {
|
if anonUid < 0 {
|
||||||
rows, err := amdb.QueryContext(ctx, "SELECT uid FROM users WHERE is_anon = 1")
|
row := amdb.QueryRowContext(ctx, "SELECT uid FROM users WHERE is_anon = 1")
|
||||||
if err == nil {
|
err := row.Scan(&anonUid)
|
||||||
defer rows.Close()
|
|
||||||
if rows.Next() {
|
|
||||||
err = rows.Scan(&anonUid)
|
|
||||||
if err == nil && rows.Next() {
|
|
||||||
err = fmt.Errorf("should be only one anonymous user in Amsterdam database")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("no anonymous user in Amsterdam database")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -706,12 +697,12 @@ func AmCreateNewUser(ctx context.Context, username string, password string, remi
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Test if the user name is already taken.
|
// Test if the user name is already taken.
|
||||||
rs, err := tx.QueryContext(ctx, "SELECT uid FROM users WHERE username = ?", username)
|
row := tx.QueryRowContext(ctx, "SELECT uid FROM users WHERE username = ?", username)
|
||||||
if err != nil {
|
if row.Err() == nil {
|
||||||
return nil, err
|
|
||||||
} else if rs.Next() {
|
|
||||||
log.Warnf("username \"%s\" already exists", username)
|
log.Warnf("username \"%s\" already exists", username)
|
||||||
return nil, errors.New("that user name already exists. Please try again")
|
return nil, errors.New("that user name already exists. Please try again")
|
||||||
|
} else if row.Err() != sql.ErrNoRows {
|
||||||
|
return nil, row.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the user record.
|
// Insert the user record.
|
||||||
@@ -730,7 +721,7 @@ func AmCreateNewUser(ctx context.Context, username string, password string, remi
|
|||||||
log.Debugf("...created new user \"%s\" with UID %d", username, user.Uid)
|
log.Debugf("...created new user \"%s\" with UID %d", username, user.Uid)
|
||||||
|
|
||||||
// add user preferences
|
// add user preferences
|
||||||
_, err = tx.ExecContext(ctx, "INSERT INTO userprefs (uid) VALUES (?)", user.Uid)
|
_, err := tx.ExecContext(ctx, "INSERT INTO userprefs (uid) VALUES (?)", user.Uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -895,20 +886,16 @@ func AmSearchUsers(ctx context.Context, field int, oper int, term string, offset
|
|||||||
return nil, -1, errors.New("invalid operator selector")
|
return nil, -1, errors.New("invalid operator selector")
|
||||||
}
|
}
|
||||||
q := queryPortion.String()
|
q := queryPortion.String()
|
||||||
rs, err := amdb.QueryContext(ctx, "SELECT COUNT(*) FROM users u, contacts c WHERE u.contactid = c.contactid AND u.is_anon = 0 AND "+q)
|
row := amdb.QueryRowContext(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
|
|
||||||
}
|
|
||||||
if !rs.Next() {
|
|
||||||
return nil, -1, errors.New("internal error getting count")
|
|
||||||
}
|
|
||||||
var total int
|
var total int
|
||||||
if err = rs.Scan(&total); err != nil {
|
err := row.Scan(&total)
|
||||||
|
if err != nil {
|
||||||
return nil, -1, err
|
return nil, -1, err
|
||||||
}
|
}
|
||||||
if total == 0 {
|
if total == 0 {
|
||||||
return make([]*User, 0), 0, nil
|
return make([]*User, 0), 0, nil
|
||||||
}
|
}
|
||||||
|
var rs *sql.Rows
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
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+
|
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)
|
" ORDER BY u.username LIMIT ? OFFSET ?", max, offset)
|
||||||
|
|||||||
Reference in New Issue
Block a user