repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

pico / pkg / apps / pipe
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}