Store role list in database and convert role mentions into a readable format
This commit is contained in:
@@ -22,6 +22,7 @@ type Database struct {
|
|||||||
Reaction *ReactionQuery
|
Reaction *ReactionQuery
|
||||||
Emoji *EmojiQuery
|
Emoji *EmojiQuery
|
||||||
Guild *GuildQuery
|
Guild *GuildQuery
|
||||||
|
Role *RoleQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(baseDB *dbutil.Database) *Database {
|
func New(baseDB *dbutil.Database) *Database {
|
||||||
@@ -59,6 +60,10 @@ func New(baseDB *dbutil.Database) *Database {
|
|||||||
db: db,
|
db: db,
|
||||||
log: db.Log.Sub("Guild"),
|
log: db.Log.Sub("Guild"),
|
||||||
}
|
}
|
||||||
|
db.Role = &RoleQuery{
|
||||||
|
db: db,
|
||||||
|
log: db.Log.Sub("Role"),
|
||||||
|
}
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
114
database/role.go
Normal file
114
database/role.go
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
log "maunium.net/go/maulogger/v2"
|
||||||
|
|
||||||
|
"maunium.net/go/mautrix/util/dbutil"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RoleQuery struct {
|
||||||
|
db *Database
|
||||||
|
log log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// language=postgresql
|
||||||
|
const (
|
||||||
|
roleSelect = "SELECT dc_guild_id, dcid, name, icon, mentionable, managed, hoist, color, position, permissions FROM role"
|
||||||
|
roleUpsert = `
|
||||||
|
INSERT INTO role (dc_guild_id, dcid, name, icon, mentionable, managed, hoist, color, position, permissions)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||||
|
ON CONFLICT (dc_guild_id, dcid) DO UPDATE
|
||||||
|
SET name=excluded.name, icon=excluded.icon, mentionable=excluded.mentionable, managed=excluded.managed,
|
||||||
|
hoist=excluded.hoist, color=excluded.color, position=excluded.position, permissions=excluded.permissions
|
||||||
|
`
|
||||||
|
roleDelete = "DELETE FROM role WHERE dc_guild_id=$1 AND dcid=$2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (rq *RoleQuery) New() *Role {
|
||||||
|
return &Role{
|
||||||
|
db: rq.db,
|
||||||
|
log: rq.log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rq *RoleQuery) GetByID(guildID, dcid string) *Role {
|
||||||
|
query := roleSelect + " WHERE dc_guild_id=$1 AND dcid=$2"
|
||||||
|
return rq.New().Scan(rq.db.QueryRow(query, guildID, dcid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rq *RoleQuery) DeleteByID(guildID, dcid string) {
|
||||||
|
_, err := rq.db.Exec("DELETE FROM role WHERE dc_guild_id=$1 AND dcid=$2", guildID, dcid)
|
||||||
|
if err != nil {
|
||||||
|
rq.log.Warnfln("Failed to delete %s/%s: %v", guildID, dcid, err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rq *RoleQuery) GetAll(guildID string) []*Role {
|
||||||
|
rows, err := rq.db.Query(roleSelect+" WHERE dc_guild_id=$1", guildID)
|
||||||
|
if err != nil {
|
||||||
|
rq.log.Errorfln("Failed to query roles of %s: %v", guildID, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var roles []*Role
|
||||||
|
for rows.Next() {
|
||||||
|
role := rq.New().Scan(rows)
|
||||||
|
if role != nil {
|
||||||
|
roles = append(roles, role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
|
||||||
|
type Role struct {
|
||||||
|
db *Database
|
||||||
|
log log.Logger
|
||||||
|
|
||||||
|
GuildID string
|
||||||
|
|
||||||
|
discordgo.Role
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Role) Scan(row dbutil.Scannable) *Role {
|
||||||
|
var icon sql.NullString
|
||||||
|
err := row.Scan(&r.GuildID, &r.ID, &r.Name, &icon, &r.Mentionable, &r.Managed, &r.Hoist, &r.Color, &r.Position, &r.Permissions)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
r.log.Errorln("Database scan failed:", err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r.Icon = icon.String
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Role) Upsert(txn dbutil.Execable) {
|
||||||
|
if txn == nil {
|
||||||
|
txn = r.db
|
||||||
|
}
|
||||||
|
_, err := txn.Exec(roleUpsert, r.GuildID, r.ID, r.Name, strPtr(r.Icon), r.Mentionable, r.Managed, r.Hoist, r.Color, r.Position, r.Permissions)
|
||||||
|
if err != nil {
|
||||||
|
r.log.Warnfln("Failed to insert %s/%s: %v", r.GuildID, r.ID, err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Role) Delete(txn dbutil.Execable) {
|
||||||
|
if txn == nil {
|
||||||
|
txn = r.db
|
||||||
|
}
|
||||||
|
_, err := txn.Exec(roleDelete, r.GuildID, r.Icon)
|
||||||
|
if err != nil {
|
||||||
|
r.log.Warnfln("Failed to delete %s/%s: %v", r.GuildID, r.ID, err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
-- v0 -> v5: Latest revision
|
-- v0 -> v7: Latest revision
|
||||||
|
|
||||||
CREATE TABLE guild (
|
CREATE TABLE guild (
|
||||||
dcid TEXT PRIMARY KEY,
|
dcid TEXT PRIMARY KEY,
|
||||||
@@ -74,7 +74,9 @@ CREATE TABLE "user" (
|
|||||||
discord_token TEXT,
|
discord_token TEXT,
|
||||||
management_room TEXT,
|
management_room TEXT,
|
||||||
space_room TEXT,
|
space_room TEXT,
|
||||||
dm_space_room TEXT
|
dm_space_room TEXT,
|
||||||
|
|
||||||
|
read_state_version INTEGER NOT NULL DEFAULT 0
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE user_portal (
|
CREATE TABLE user_portal (
|
||||||
@@ -126,3 +128,22 @@ CREATE TABLE emoji (
|
|||||||
discord_name TEXT,
|
discord_name TEXT,
|
||||||
matrix_url TEXT
|
matrix_url TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE role (
|
||||||
|
dc_guild_id TEXT,
|
||||||
|
dcid TEXT,
|
||||||
|
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
icon TEXT,
|
||||||
|
|
||||||
|
mentionable BOOLEAN NOT NULL,
|
||||||
|
managed BOOLEAN NOT NULL,
|
||||||
|
hoist BOOLEAN NOT NULL,
|
||||||
|
|
||||||
|
color INTEGER NOT NULL,
|
||||||
|
position INTEGER NOT NULL,
|
||||||
|
permissions BIGINT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (dc_guild_id, dcid),
|
||||||
|
CONSTRAINT role_guild_fkey FOREIGN KEY (dc_guild_id) REFERENCES guild (dcid) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|||||||
19
database/upgrades/07-store-role-info.sql
Normal file
19
database/upgrades/07-store-role-info.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
-- v7: Store role info
|
||||||
|
CREATE TABLE role (
|
||||||
|
dc_guild_id TEXT,
|
||||||
|
dcid TEXT,
|
||||||
|
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
icon TEXT,
|
||||||
|
|
||||||
|
mentionable BOOLEAN NOT NULL,
|
||||||
|
managed BOOLEAN NOT NULL,
|
||||||
|
hoist BOOLEAN NOT NULL,
|
||||||
|
|
||||||
|
color INTEGER NOT NULL,
|
||||||
|
position INTEGER NOT NULL,
|
||||||
|
permissions BIGINT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (dc_guild_id, dcid),
|
||||||
|
CONSTRAINT role_guild_fkey FOREIGN KEY (dc_guild_id) REFERENCES guild (dcid) ON DELETE CASCADE
|
||||||
|
);
|
||||||
@@ -263,7 +263,11 @@ func (r *discordTagHTMLRenderer) renderDiscordMention(w util.BufWriter, source [
|
|||||||
_, _ = fmt.Fprintf(w, `<a href="https://matrix.to/#/%s">%s</a>`, puppet.MXID, puppet.Name)
|
_, _ = fmt.Fprintf(w, `<a href="https://matrix.to/#/%s">%s</a>`, puppet.MXID, puppet.Name)
|
||||||
return
|
return
|
||||||
case *astDiscordRoleMention:
|
case *astDiscordRoleMention:
|
||||||
// TODO
|
role := r.portal.bridge.DB.Role.GetByID(r.portal.GuildID, strconv.FormatInt(node.id, 10))
|
||||||
|
if role != nil {
|
||||||
|
_, _ = fmt.Fprintf(w, `<font color="#%06x"><strong>@%s</strong></font>`, role.Color, role.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
case *astDiscordChannelMention:
|
case *astDiscordChannelMention:
|
||||||
portal := r.portal.bridge.GetExistingPortalByID(database.PortalKey{
|
portal := r.portal.bridge.GetExistingPortalByID(database.PortalKey{
|
||||||
ChannelID: strconv.FormatInt(node.id, 10),
|
ChannelID: strconv.FormatInt(node.id, 10),
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -11,7 +11,7 @@ require (
|
|||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/yuin/goldmark v1.4.12
|
github.com/yuin/goldmark v1.4.12
|
||||||
maunium.net/go/maulogger/v2 v2.3.2
|
maunium.net/go/maulogger/v2 v2.3.2
|
||||||
maunium.net/go/mautrix v0.11.1-0.20220705131441-28320db1cc9c
|
maunium.net/go/mautrix v0.11.1-0.20220708121944-cda2329dd1df
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -26,4 +26,4 @@ require (
|
|||||||
maunium.net/go/mauflag v1.0.0 // indirect
|
maunium.net/go/mauflag v1.0.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/bwmarrin/discordgo => gitlab.com/beeper/discordgo v0.23.3-0.20220708095310-09da7ef6f6de
|
replace github.com/bwmarrin/discordgo => gitlab.com/beeper/discordgo v0.23.3-0.20220708122002-c27922e0ba67
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -30,8 +30,8 @@ github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
|
|||||||
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
|
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
|
||||||
github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0=
|
github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0=
|
||||||
github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
gitlab.com/beeper/discordgo v0.23.3-0.20220708095310-09da7ef6f6de h1:XSKsxfGXfUf7KTyzM1NmzYkqetqiLivUULhXr7alZX4=
|
gitlab.com/beeper/discordgo v0.23.3-0.20220708122002-c27922e0ba67 h1:FSxw+90bXpsAJZfH5oz49LL33TAk4L/0U7eJW+He4ys=
|
||||||
gitlab.com/beeper/discordgo v0.23.3-0.20220708095310-09da7ef6f6de/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
gitlab.com/beeper/discordgo v0.23.3-0.20220708122002-c27922e0ba67/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
@@ -59,5 +59,5 @@ maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
|||||||
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
||||||
maunium.net/go/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0=
|
maunium.net/go/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0=
|
||||||
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||||
maunium.net/go/mautrix v0.11.1-0.20220705131441-28320db1cc9c h1:/vVqeoH1CLFEbBpmd6nczEmCxJ9dxImWX6MtkaJjd+8=
|
maunium.net/go/mautrix v0.11.1-0.20220708121944-cda2329dd1df h1:MvSfTply7Vn+02RukSqW02REGy2qYzDWm7tH+0i7Akc=
|
||||||
maunium.net/go/mautrix v0.11.1-0.20220705131441-28320db1cc9c/go.mod h1:Lj4pBam5P0zIvieIFHnGsuaj+xfFtI3y/sC8yGlyna8=
|
maunium.net/go/mautrix v0.11.1-0.20220708121944-cda2329dd1df/go.mod h1:Lj4pBam5P0zIvieIFHnGsuaj+xfFtI3y/sC8yGlyna8=
|
||||||
|
|||||||
74
user.go
74
user.go
@@ -459,6 +459,9 @@ func (user *User) Connect() error {
|
|||||||
user.Session.AddHandler(user.guildCreateHandler)
|
user.Session.AddHandler(user.guildCreateHandler)
|
||||||
user.Session.AddHandler(user.guildDeleteHandler)
|
user.Session.AddHandler(user.guildDeleteHandler)
|
||||||
user.Session.AddHandler(user.guildUpdateHandler)
|
user.Session.AddHandler(user.guildUpdateHandler)
|
||||||
|
user.Session.AddHandler(user.guildRoleCreateHandler)
|
||||||
|
user.Session.AddHandler(user.guildRoleUpdateHandler)
|
||||||
|
user.Session.AddHandler(user.guildRoleDeleteHandler)
|
||||||
|
|
||||||
user.Session.AddHandler(user.channelCreateHandler)
|
user.Session.AddHandler(user.channelCreateHandler)
|
||||||
user.Session.AddHandler(user.channelDeleteHandler)
|
user.Session.AddHandler(user.channelDeleteHandler)
|
||||||
@@ -586,6 +589,74 @@ func (user *User) addGuildToSpace(guild *Guild) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) discordRoleToDB(guildID string, role *discordgo.Role, dbRole *database.Role) (*database.Role, bool) {
|
||||||
|
var changed bool
|
||||||
|
if dbRole == nil {
|
||||||
|
dbRole = user.bridge.DB.Role.New()
|
||||||
|
dbRole.ID = role.ID
|
||||||
|
dbRole.GuildID = guildID
|
||||||
|
changed = true
|
||||||
|
} else {
|
||||||
|
changed = dbRole.Name != role.Name ||
|
||||||
|
dbRole.Icon != role.Icon ||
|
||||||
|
dbRole.Mentionable != role.Mentionable ||
|
||||||
|
dbRole.Managed != role.Managed ||
|
||||||
|
dbRole.Hoist != role.Hoist ||
|
||||||
|
dbRole.Color != role.Color ||
|
||||||
|
dbRole.Position != role.Position ||
|
||||||
|
dbRole.Permissions != role.Permissions
|
||||||
|
}
|
||||||
|
dbRole.Role = *role
|
||||||
|
return dbRole, changed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) handleGuildRoles(guildID string, newRoles []*discordgo.Role) {
|
||||||
|
existingRoles := user.bridge.DB.Role.GetAll(guildID)
|
||||||
|
existingRoleMap := make(map[string]*database.Role, len(existingRoles))
|
||||||
|
for _, role := range existingRoles {
|
||||||
|
existingRoleMap[role.ID] = role
|
||||||
|
}
|
||||||
|
txn, err := user.bridge.DB.Begin()
|
||||||
|
if err != nil {
|
||||||
|
user.log.Errorln("Failed to start transaction for guild role sync:", err)
|
||||||
|
panic(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, role := range newRoles {
|
||||||
|
dbRole, changed := user.discordRoleToDB(guildID, role, existingRoleMap[role.ID])
|
||||||
|
delete(existingRoleMap, role.ID)
|
||||||
|
if changed {
|
||||||
|
dbRole.Upsert(txn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, removeRole := range existingRoleMap {
|
||||||
|
removeRole.Delete(txn)
|
||||||
|
}
|
||||||
|
err = txn.Commit()
|
||||||
|
if err != nil {
|
||||||
|
user.log.Errorln("Failed to commit guild role sync:", err)
|
||||||
|
rollbackErr := txn.Rollback()
|
||||||
|
if rollbackErr != nil {
|
||||||
|
user.log.Errorln("Failed to rollback errored guild role sync:", rollbackErr)
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) guildRoleCreateHandler(_ *discordgo.Session, r *discordgo.GuildRoleCreate) {
|
||||||
|
dbRole, _ := user.discordRoleToDB(r.GuildID, r.Role, nil)
|
||||||
|
dbRole.Upsert(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) guildRoleUpdateHandler(_ *discordgo.Session, r *discordgo.GuildRoleUpdate) {
|
||||||
|
dbRole, _ := user.discordRoleToDB(r.GuildID, r.Role, nil)
|
||||||
|
dbRole.Upsert(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) guildRoleDeleteHandler(_ *discordgo.Session, r *discordgo.GuildRoleDelete) {
|
||||||
|
user.bridge.DB.Role.DeleteByID(r.GuildID, r.RoleID)
|
||||||
|
}
|
||||||
|
|
||||||
func (user *User) handleGuild(meta *discordgo.Guild, timestamp time.Time, isInSpace bool) {
|
func (user *User) handleGuild(meta *discordgo.Guild, timestamp time.Time, isInSpace bool) {
|
||||||
guild := user.bridge.GetGuildByID(meta.ID, true)
|
guild := user.bridge.GetGuildByID(meta.ID, true)
|
||||||
guild.UpdateInfo(user, meta)
|
guild.UpdateInfo(user, meta)
|
||||||
@@ -602,6 +673,9 @@ func (user *User) handleGuild(meta *discordgo.Guild, timestamp time.Time, isInSp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(meta.Roles) > 0 {
|
||||||
|
user.handleGuildRoles(meta.ID, meta.Roles)
|
||||||
|
}
|
||||||
if !isInSpace {
|
if !isInSpace {
|
||||||
isInSpace = user.addGuildToSpace(guild)
|
isInSpace = user.addGuildToSpace(guild)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user