This commit is contained in:
Lennart J. Kurzweg (Nx2)
2026-03-23 22:06:12 +01:00
parent d55fff9f4a
commit b5a3a63dde
6 changed files with 80 additions and 112 deletions

View File

@@ -32,6 +32,7 @@ type publicInfo struct {
// access control, privacy redaction, and aggregate (virtual) calendars.
type DBBackend struct {
pool *pgxpool.Pool // Connection pool to PostgreSQL
prefix string // Public URL base path prefix
redactionText string // Text used to hide confidential event details (e.g. "[REDACED]")
defaultClass string // Class assumed if non is set ("PUBLIC", "PRIVATE", "CONFIDENTIAL")
aggregates map[string]*config.Aggregate // In-memory map of path -> virtual calendar definitions
@@ -51,6 +52,7 @@ func NewDBBackend(ctx context.Context, cfg *config.Config) (*DBBackend, error) {
b := &DBBackend{
pool: pool,
prefix: cfg.Server.BasePath(),
redactionText: cfg.Server.Redaction,
defaultClass: cfg.Server.DefaultClass,
aggregates: make(map[string]*config.Aggregate),
@@ -163,6 +165,8 @@ func (b *DBBackend) syncConfig(ctx context.Context, cfg *config.Config) error {
b.userAggs = make(map[string][]string)
b.publicAccess = make(map[string]publicInfo)
prefix := cfg.Server.BasePath()
// --- Phase 1: User Sync ---
for _, u := range cfg.Users {
configUserNames[u.Name] = true
@@ -185,7 +189,7 @@ func (b *DBBackend) syncConfig(ctx context.Context, cfg *config.Config) error {
// --- Phase 2: Calendar & Access Sync ---
for _, c := range cfg.Calendars {
path := fmt.Sprintf("/%s/calendars/%s/", c.Owner, c.ID)
path := prefix + fmt.Sprintf("/%s/calendars/%s/", c.Owner, c.ID)
configCalendarPaths[path] = true
var ownerID int
@@ -243,7 +247,7 @@ func (b *DBBackend) syncConfig(ctx context.Context, cfg *config.Config) error {
// Check for public access (ICS)
for _, a := range c.Access {
if a.ICS != "" {
pubPath := fmt.Sprintf("/public/%s/%s.ics", c.Owner, c.ID)
pubPath := prefix + fmt.Sprintf("/public/%s/%s.ics", c.Owner, c.ID)
b.publicAccess[pubPath] = publicInfo{
InternalPath: path,
Mode: a.ICS,
@@ -255,7 +259,7 @@ func (b *DBBackend) syncConfig(ctx context.Context, cfg *config.Config) error {
// --- Phase 3: Aggregate Setup ---
// Aggregates are virtual, so we only track them in memory for routing.
for _, agg := range cfg.Aggregates {
p_ := fmt.Sprintf("/%s/calendars/%s/", agg.Owner, agg.ID)
p_ := prefix + fmt.Sprintf("/%s/calendars/%s/", agg.Owner, agg.ID)
if configCalendarPaths[p_] {
return fmt.Errorf("aggregate %s collides with real calendar path", p_)
}
@@ -267,7 +271,7 @@ func (b *DBBackend) syncConfig(ctx context.Context, cfg *config.Config) error {
aggAccess[agg.Owner] = true
for _, a := range agg.Access {
if a.ICS != "" {
pubPath := fmt.Sprintf("/public/%s/%s.ics", agg.Owner, agg.ID)
pubPath := prefix + fmt.Sprintf("/public/%s/%s.ics", agg.Owner, agg.ID)
b.publicAccess[pubPath] = publicInfo{
InternalPath: p_,
Mode: a.ICS,
@@ -548,7 +552,7 @@ func (b *DBBackend) CalendarHomeSetPath(ctx context.Context) (string, error) {
if err != nil {
return "", err
}
return fmt.Sprintf("/%s/calendars/", username), nil
return b.prefix + fmt.Sprintf("/%s/calendars/", username), nil
}
// ListCalendars returns all calendars (real and virtual) the user has access to.
@@ -699,7 +703,7 @@ func (b *DBBackend) listAggregateObjects(ctx context.Context, aggPath string, ag
var res []caldav.CalendarObject
for _, sourceID := range agg.Sources {
sourcePath := fmt.Sprintf("/%s/calendars/%s/", agg.Owner, sourceID)
sourcePath := b.prefix + fmt.Sprintf("/%s/calendars/%s/", agg.Owner, sourceID)
var calID int
var ownerName string
@@ -763,7 +767,7 @@ func (b *DBBackend) GetCalendarObject(ctx context.Context, p string, req *caldav
sourceID := parts[0]
realFileName := parts[1]
sourcePath := fmt.Sprintf("/%s/calendars/%s/", agg.Owner, sourceID)
sourcePath := b.prefix + fmt.Sprintf("/%s/calendars/%s/", agg.Owner, sourceID)
var calID int
var ownerName string
err := b.pool.QueryRow(ctx, "SELECT c.id, u.name FROM calendars c JOIN users u ON c.owner_id = u.id WHERE c.path = $1", sourcePath).Scan(&calID, &ownerName)