Eric Bower
·
2025-12-26
topic.go
1package pipe
2
3import (
4 "fmt"
5 "strings"
6)
7
8// toTopic scopes a topic to user by prefixing name.
9func toTopic(userName, topic string) string {
10 if strings.HasPrefix(topic, userName+"/") {
11 return topic
12 }
13 return fmt.Sprintf("%s/%s", userName, topic)
14}
15
16func toPublicTopic(topic string) string {
17 if strings.HasPrefix(topic, "public/") {
18 return topic
19 }
20 return fmt.Sprintf("public/%s", topic)
21}
22
23// TopicResolveInput contains all inputs needed for topic resolution.
24type TopicResolveInput struct {
25 UserName string
26 Topic string
27 IsAdmin bool
28 IsPublic bool
29 AccessList []string
30 ExistingAccessList []string
31 HasExistingAccess bool
32 IsAccessCreator bool
33 HasUserAccess bool
34}
35
36// TopicResolveOutput contains the resolved topic name and any error.
37type TopicResolveOutput struct {
38 Name string
39 WithoutUser string
40 AccessDenied bool
41 GenerateNewTopic bool
42}
43
44// resolveTopic determines the final topic name based on user, flags, and access control.
45func resolveTopic(input TopicResolveInput) TopicResolveOutput {
46 var name string
47 var withoutUser string
48
49 if input.IsAdmin && strings.HasPrefix(input.Topic, "/") {
50 name = strings.TrimPrefix(input.Topic, "/")
51 return TopicResolveOutput{Name: name, WithoutUser: withoutUser}
52 }
53
54 name = toTopic(input.UserName, input.Topic)
55 if input.IsPublic {
56 name = toPublicTopic(input.Topic)
57 withoutUser = name
58 } else {
59 withoutUser = input.Topic
60 }
61
62 if input.HasExistingAccess && len(input.ExistingAccessList) > 0 && !input.IsAdmin {
63 if input.HasUserAccess || input.IsAccessCreator {
64 name = withoutUser
65 } else if !input.IsPublic {
66 name = toTopic(input.UserName, withoutUser)
67 } else {
68 return TopicResolveOutput{
69 Name: name,
70 WithoutUser: withoutUser,
71 AccessDenied: true,
72 GenerateNewTopic: true,
73 }
74 }
75 }
76
77 return TopicResolveOutput{Name: name, WithoutUser: withoutUser}
78}