feat: refactor channel mapping with structured parameters and shared channel integration

- Add ChannelMappingRequest and ChannelMappingDeleteRequest structs with validation
- Update BridgeManager interface to accept structured parameters instead of individual strings
- Implement proper user ID and team ID propagation to shared channels
- Add shared channel creation/deletion integration with Mattermost API
- Update command handlers to provide user and team context
- Enhance logging with comprehensive parameter tracking

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Felipe M 2025-08-01 19:10:40 +02:00
parent a5eb80817c
commit 1f45197aa8
No known key found for this signature in database
GPG key ID: 52E5D65FCF99808A
5 changed files with 223 additions and 51 deletions

View file

@ -1,5 +1,7 @@
package model
import "fmt"
type BridgeID string
type UserState int
@ -11,6 +13,60 @@ const (
UserStateOffline
)
// ChannelMappingRequest contains information needed to create a channel mapping
type ChannelMappingRequest struct {
ChannelID string // Mattermost channel ID
BridgeName string // Name of the bridge (e.g., "xmpp")
BridgeRoomID string // Remote room/channel ID (e.g., JID for XMPP)
UserID string // ID of user who triggered the mapping creation
TeamID string // Team ID where the channel belongs
}
// Validate checks if all required fields are present and valid
func (r ChannelMappingRequest) Validate() error {
if r.ChannelID == "" {
return fmt.Errorf("channelID cannot be empty")
}
if r.BridgeName == "" {
return fmt.Errorf("bridgeName cannot be empty")
}
if r.BridgeRoomID == "" {
return fmt.Errorf("bridgeRoomID cannot be empty")
}
if r.UserID == "" {
return fmt.Errorf("userID cannot be empty")
}
if r.TeamID == "" {
return fmt.Errorf("teamID cannot be empty")
}
return nil
}
// ChannelMappingDeleteRequest contains information needed to delete a channel mapping
type ChannelMappingDeleteRequest struct {
ChannelID string // Mattermost channel ID
BridgeName string // Name of the bridge (e.g., "xmpp")
UserID string // ID of user who triggered the mapping deletion
TeamID string // Team ID where the channel belongs
}
// Validate checks if all required fields are present and valid
func (r ChannelMappingDeleteRequest) Validate() error {
if r.ChannelID == "" {
return fmt.Errorf("channelID cannot be empty")
}
if r.BridgeName == "" {
return fmt.Errorf("bridgeName cannot be empty")
}
if r.UserID == "" {
return fmt.Errorf("userID cannot be empty")
}
if r.TeamID == "" {
return fmt.Errorf("teamID cannot be empty")
}
return nil
}
type BridgeManager interface {
// RegisterBridge registers a bridge with the given name. Returns an error if the name is empty,
// the bridge is nil, or a bridge with the same name is already registered.
@ -52,10 +108,10 @@ type BridgeManager interface {
OnPluginConfigurationChange(config any) error
// OnChannelMappingCreated is called when a channel mapping is created.
OnChannelMappingCreated(channelID, bridgeName, bridgeRoomID string) error
OnChannelMappingCreated(req ChannelMappingRequest) error
// OnChannelMappingDeleted is called when a channel mapping is deleted.
OnChannelMappingDeleted(channelID, bridgeName string) error
OnChannelMappingDeleted(req ChannelMappingDeleteRequest) error
}
type Bridge interface {

40
server/model/strings.go Normal file
View file

@ -0,0 +1,40 @@
package model
import "strings"
// sanitizeShareName creates a valid ShareName matching the regex: ^[a-z0-9]+([a-z\-\_0-9]+|(__)?)[a-z0-9]*$
func SanitizeShareName(name string) string {
// Convert to lowercase and replace spaces with hyphens
shareName := strings.ToLower(name)
shareName = strings.ReplaceAll(shareName, " ", "-")
// Remove any characters that aren't lowercase letters, numbers, hyphens, or underscores
var validShareName strings.Builder
for _, r := range shareName {
if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' || r == '_' {
validShareName.WriteRune(r)
}
}
result := validShareName.String()
if result == "" {
return "matrixbridge" // fallback if no valid characters
}
// Ensure it starts with alphanumeric
for len(result) > 0 && (result[0] == '-' || result[0] == '_') {
result = result[1:]
}
// Ensure it ends with alphanumeric
for len(result) > 0 && (result[len(result)-1] == '-' || result[len(result)-1] == '_') {
result = result[:len(result)-1]
}
// Final fallback check
if result == "" {
return "matrixbridge"
}
return result
}