instance.go (5532B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package bundb 19 20 import ( 21 "context" 22 23 "github.com/superseriousbusiness/gotosocial/internal/config" 24 "github.com/superseriousbusiness/gotosocial/internal/db" 25 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 26 "github.com/uptrace/bun" 27 ) 28 29 type instanceDB struct { 30 conn *DBConn 31 } 32 33 func (i *instanceDB) CountInstanceUsers(ctx context.Context, domain string) (int, db.Error) { 34 q := i.conn. 35 NewSelect(). 36 TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")). 37 Column("account.id"). 38 Where("? != ?", bun.Ident("account.username"), domain). 39 Where("? IS NULL", bun.Ident("account.suspended_at")) 40 41 if domain == config.GetHost() || domain == config.GetAccountDomain() { 42 // if the domain is *this* domain, just count where the domain field is null 43 q = q.WhereGroup(" AND ", whereEmptyOrNull("account.domain")) 44 } else { 45 q = q.Where("? = ?", bun.Ident("account.domain"), domain) 46 } 47 48 count, err := q.Count(ctx) 49 if err != nil { 50 return 0, i.conn.ProcessError(err) 51 } 52 return count, nil 53 } 54 55 func (i *instanceDB) CountInstanceStatuses(ctx context.Context, domain string) (int, db.Error) { 56 q := i.conn. 57 NewSelect(). 58 TableExpr("? AS ?", bun.Ident("statuses"), bun.Ident("status")) 59 60 if domain == config.GetHost() || domain == config.GetAccountDomain() { 61 // if the domain is *this* domain, just count where local is true 62 q = q.Where("? = ?", bun.Ident("status.local"), true) 63 } else { 64 // join on the domain of the account 65 q = q. 66 Join("JOIN ? AS ? ON ? = ?", bun.Ident("accounts"), bun.Ident("account"), bun.Ident("account.id"), bun.Ident("status.account_id")). 67 Where("? = ?", bun.Ident("account.domain"), domain) 68 } 69 70 count, err := q.Count(ctx) 71 if err != nil { 72 return 0, i.conn.ProcessError(err) 73 } 74 return count, nil 75 } 76 77 func (i *instanceDB) CountInstanceDomains(ctx context.Context, domain string) (int, db.Error) { 78 q := i.conn. 79 NewSelect(). 80 TableExpr("? AS ?", bun.Ident("instances"), bun.Ident("instance")) 81 82 if domain == config.GetHost() { 83 // if the domain is *this* domain, just count other instances it knows about 84 // exclude domains that are blocked 85 q = q. 86 Where("? != ?", bun.Ident("instance.domain"), domain). 87 Where("? IS NULL", bun.Ident("instance.suspended_at")) 88 } else { 89 // TODO: implement federated domain counting properly for remote domains 90 return 0, nil 91 } 92 93 count, err := q.Count(ctx) 94 if err != nil { 95 return 0, i.conn.ProcessError(err) 96 } 97 return count, nil 98 } 99 100 func (i *instanceDB) GetInstance(ctx context.Context, domain string) (*gtsmodel.Instance, db.Error) { 101 instance := >smodel.Instance{} 102 103 if err := i.conn. 104 NewSelect(). 105 Model(instance). 106 Where("? = ?", bun.Ident("instance.domain"), domain). 107 Scan(ctx); err != nil { 108 return nil, i.conn.ProcessError(err) 109 } 110 111 return instance, nil 112 } 113 114 func (i *instanceDB) GetInstancePeers(ctx context.Context, includeSuspended bool) ([]*gtsmodel.Instance, db.Error) { 115 instances := []*gtsmodel.Instance{} 116 117 q := i.conn. 118 NewSelect(). 119 Model(&instances). 120 Where("? != ?", bun.Ident("instance.domain"), config.GetHost()) 121 122 if !includeSuspended { 123 q = q.Where("? IS NULL", bun.Ident("instance.suspended_at")) 124 } 125 126 if err := q.Scan(ctx); err != nil { 127 return nil, i.conn.ProcessError(err) 128 } 129 130 return instances, nil 131 } 132 133 func (i *instanceDB) GetInstanceAccounts(ctx context.Context, domain string, maxID string, limit int) ([]*gtsmodel.Account, db.Error) { 134 accounts := []*gtsmodel.Account{} 135 136 q := i.conn.NewSelect(). 137 Model(&accounts). 138 Where("? = ?", bun.Ident("account.domain"), domain). 139 Order("account.id DESC") 140 141 if maxID != "" { 142 q = q.Where("? < ?", bun.Ident("account.id"), maxID) 143 } 144 145 if limit > 0 { 146 q = q.Limit(limit) 147 } 148 149 if err := q.Scan(ctx); err != nil { 150 return nil, i.conn.ProcessError(err) 151 } 152 153 if len(accounts) == 0 { 154 return nil, db.ErrNoEntries 155 } 156 157 return accounts, nil 158 } 159 160 func (i *instanceDB) GetInstanceModeratorAddresses(ctx context.Context) ([]string, db.Error) { 161 addresses := []string{} 162 163 // Select email addresses of approved, confirmed, 164 // and enabled moderators or admins. 165 166 q := i.conn. 167 NewSelect(). 168 TableExpr("? AS ?", bun.Ident("users"), bun.Ident("user")). 169 Column("user.email"). 170 Where("? = ?", bun.Ident("user.approved"), true). 171 Where("? IS NOT NULL", bun.Ident("user.confirmed_at")). 172 Where("? = ?", bun.Ident("user.disabled"), false). 173 WhereGroup(" AND ", func(q *bun.SelectQuery) *bun.SelectQuery { 174 return q. 175 Where("? = ?", bun.Ident("user.moderator"), true). 176 WhereOr("? = ?", bun.Ident("user.admin"), true) 177 }). 178 OrderExpr("? ASC", bun.Ident("user.email")) 179 180 if err := q.Scan(ctx, &addresses); err != nil { 181 return nil, i.conn.ProcessError(err) 182 } 183 184 if len(addresses) == 0 { 185 return nil, db.ErrNoEntries 186 } 187 188 return addresses, nil 189 }