Przeglądaj źródła

Add support for unbridging guilds

Tulir Asokan 2 lat temu
rodzic
commit
9d84faa954
4 zmienionych plików z 78 dodań i 46 usunięć
  1. 4 0
      database/portal.go
  2. 30 0
      guildportal.go
  3. 23 9
      portal.go
  4. 21 37
      user.go

+ 4 - 0
database/portal.go

@@ -56,6 +56,10 @@ func (pq *PortalQuery) GetAll() []*Portal {
 	return pq.getAll(portalSelect)
 }
 
+func (pq *PortalQuery) GetAllInGuild(guildID string) []*Portal {
+	return pq.getAll(portalSelect+" WHERE dc_guild_id=$1", guildID)
+}
+
 func (pq *PortalQuery) GetByID(key PortalKey) *Portal {
 	return pq.get(portalSelect+" WHERE dcid=$1 AND (receiver=$2 OR receiver='')", key.ChannelID, key.Receiver)
 }

+ 30 - 0
guildportal.go

@@ -17,6 +17,7 @@
 package main
 
 import (
+	"errors"
 	"fmt"
 	"sync"
 
@@ -285,3 +286,32 @@ func (guild *Guild) UpdateAvatar(iconID string) bool {
 	}
 	return true
 }
+
+func (guild *Guild) cleanup() {
+	if guild.MXID == "" {
+		return
+	}
+	intent := guild.bridge.Bot
+	if guild.bridge.SpecVersions.UnstableFeatures["com.beeper.room_yeeting"] {
+		err := intent.BeeperDeleteRoom(guild.MXID)
+		if err == nil || errors.Is(err, mautrix.MNotFound) {
+			return
+		}
+		guild.log.Warnfln("Failed to delete %s using hungryserv yeet endpoint, falling back to normal behavior: %v", guild.MXID, err)
+	}
+	guild.bridge.cleanupRoom(intent, guild.MXID, false, guild.log)
+}
+
+func (guild *Guild) RemoveMXID() {
+	guild.bridge.guildsLock.Lock()
+	defer guild.bridge.guildsLock.Unlock()
+	if guild.MXID == "" {
+		return
+	}
+	delete(guild.bridge.guildsByMXID, guild.MXID)
+	guild.MXID = ""
+	guild.AvatarSet = false
+	guild.NameSet = false
+	guild.AutoBridgeChannels = false
+	guild.Update()
+}

+ 23 - 9
portal.go

@@ -177,6 +177,10 @@ func (br *DiscordBridge) GetAllPortals() []*Portal {
 	return br.dbPortalsToPortals(br.DB.Portal.GetAll())
 }
 
+func (br *DiscordBridge) GetAllPortalsInGuild(guildID string) []*Portal {
+	return br.dbPortalsToPortals(br.DB.Portal.GetAllInGuild(guildID))
+}
+
 func (br *DiscordBridge) GetAllIPortals() (iportals []bridge.Portal) {
 	portals := br.GetAllPortals()
 	iportals = make([]bridge.Portal, len(portals))
@@ -1291,6 +1295,12 @@ func (portal *Portal) RemoveMXID() {
 	}
 	delete(portal.bridge.portalsByMXID, portal.MXID)
 	portal.MXID = ""
+	portal.AvatarSet = false
+	portal.NameSet = false
+	portal.TopicSet = false
+	portal.Encrypted = false
+	portal.InSpace = ""
+	portal.FirstEventID = ""
 	portal.Update()
 	portal.bridge.DB.Message.DeleteAll(portal.Key)
 }
@@ -1316,9 +1326,13 @@ func (portal *Portal) cleanup(puppetsOnly bool) {
 		return
 	}
 
-	members, err := intent.JoinedMembers(portal.MXID)
+	portal.bridge.cleanupRoom(intent, portal.MXID, puppetsOnly, portal.log)
+}
+
+func (br *DiscordBridge) cleanupRoom(intent *appservice.IntentAPI, mxid id.RoomID, puppetsOnly bool, log log.Logger) {
+	members, err := intent.JoinedMembers(mxid)
 	if err != nil {
-		portal.log.Errorln("Failed to get portal members for cleanup:", err)
+		log.Errorln("Failed to get portal members for cleanup:", err)
 		return
 	}
 
@@ -1327,23 +1341,23 @@ func (portal *Portal) cleanup(puppetsOnly bool) {
 			continue
 		}
 
-		puppet := portal.bridge.GetPuppetByMXID(member)
+		puppet := br.GetPuppetByMXID(member)
 		if puppet != nil {
-			_, err = puppet.DefaultIntent().LeaveRoom(portal.MXID)
+			_, err = puppet.DefaultIntent().LeaveRoom(mxid)
 			if err != nil {
-				portal.log.Errorln("Error leaving as puppet while cleaning up portal:", err)
+				log.Errorln("Error leaving as puppet while cleaning up portal:", err)
 			}
 		} else if !puppetsOnly {
-			_, err = intent.KickUser(portal.MXID, &mautrix.ReqKickUser{UserID: member, Reason: "Deleting portal"})
+			_, err = intent.KickUser(mxid, &mautrix.ReqKickUser{UserID: member, Reason: "Deleting portal"})
 			if err != nil {
-				portal.log.Errorln("Error kicking user while cleaning up portal:", err)
+				log.Errorln("Error kicking user while cleaning up portal:", err)
 			}
 		}
 	}
 
-	_, err = intent.LeaveRoom(portal.MXID)
+	_, err = intent.LeaveRoom(mxid)
 	if err != nil {
-		portal.log.Errorln("Error leaving with main intent while cleaning up portal:", err)
+		log.Errorln("Error leaving with main intent while cleaning up portal:", err)
 	}
 }
 

+ 21 - 37
user.go

@@ -1033,41 +1033,25 @@ func (user *User) bridgeGuild(guildID string, everything bool) error {
 }
 
 func (user *User) unbridgeGuild(guildID string) error {
-	//user.guildsLock.Lock()
-	//defer user.guildsLock.Unlock()
-	//
-	//guild, exists := user.guilds[guildID]
-	//if !exists {
-	//	return fmt.Errorf("guildID not found")
-	//}
-	//
-	//if !guild.Bridge {
-	//	return fmt.Errorf("guild not bridged")
-	//}
-	//
-	//// First update the guild so we don't have any other go routines recreating
-	//// channels we're about to destroy.
-	//guild.Bridge = false
-	//guild.Upsert()
-	//
-	//// Now run through the channels in the guild and remove any portals we
-	//// have for them.
-	//channels, err := user.Session.GuildChannels(guildID)
-	//if err != nil {
-	//	return err
-	//}
-	//
-	//for _, channel := range channels {
-	//	if channelIsBridgeable(channel) {
-	//		key := database.PortalKey{
-	//			ChannelID: channel.ID,
-	//			Receiver:  user.DiscordID,
-	//		}
-	//
-	//		portal := user.bridge.GetPortalByID(key)
-	//		portal.leave(user)
-	//	}
-	//}
-
-	return errors.New("unbridging is not currently supported")
+	if user.PermissionLevel < bridgeconfig.PermissionLevelAdmin {
+		return errors.New("only bridge admins can unbridge guilds")
+	}
+	guild := user.bridge.GetGuildByID(guildID, false)
+	if guild == nil {
+		return errors.New("guild not found")
+	}
+	guild.roomCreateLock.Lock()
+	defer guild.roomCreateLock.Unlock()
+	if !guild.AutoBridgeChannels && guild.MXID == "" {
+		return errors.New("that guild is not bridged")
+	}
+	guild.AutoBridgeChannels = false
+	guild.Update()
+	for _, portal := range user.bridge.GetAllPortalsInGuild(guild.ID) {
+		portal.cleanup(false)
+		portal.RemoveMXID()
+	}
+	guild.cleanup()
+	guild.RemoveMXID()
+	return nil
 }