Changeset 0.29.0 (#195)

This commit is contained in:
2026-03-17 16:28:47 +00:00
parent 128cbb8174
commit 5d637d3a90
129 changed files with 9418 additions and 3016 deletions

View File

@@ -12,7 +12,6 @@ import (
"github.com/gin-gonic/gin"
"git.gobha.me/xcaliber/chat-switchboard/database"
"git.gobha.me/xcaliber/chat-switchboard/extraction"
"git.gobha.me/xcaliber/chat-switchboard/models"
"git.gobha.me/xcaliber/chat-switchboard/storage"
@@ -162,10 +161,8 @@ func (h *FileHandler) Upload(c *gin.Context) {
return
}
// Update storage_key in PG
database.DB.ExecContext(c.Request.Context(),
database.Q(`UPDATE files SET storage_key = $1 WHERE id = $2`),
att.StorageKey, att.ID)
// Update storage_key
h.stores.Files.UpdateStorageKey(c.Request.Context(), att.ID, att.StorageKey)
// For images, mark extraction as not needed (complete immediately)
if strings.HasPrefix(contentType, "image/") {
@@ -463,14 +460,12 @@ func (h *FileHandler) CleanupChannelStorage(channelID string) {
// verifyChannelAccess checks that the requesting user owns the channel.
// Future RBAC (v0.20.0): replace with rbac.Can(userID, channelID, permission).
func (h *FileHandler) verifyChannelAccess(c *gin.Context, channelID, userID string) bool {
var ownerID string
err := database.DB.QueryRowContext(c.Request.Context(),
database.Q(`SELECT user_id FROM channels WHERE id = $1`), channelID).Scan(&ownerID)
owns, err := h.stores.Channels.UserOwns(c.Request.Context(), channelID, userID)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "channel not found"})
return false
}
if ownerID != userID {
if !owns {
// Check if user is admin (admins can access any channel)
role, _ := c.Get("role")
if role != "admin" {
@@ -516,16 +511,9 @@ func (h *FileHandler) UploadToProject(c *gin.Context) {
// Verify project access (user owns or is team member; admins bypass)
if c.GetString("role") != "admin" {
var exists bool
err := database.DB.QueryRowContext(c.Request.Context(), database.Q(`
SELECT EXISTS(
SELECT 1 FROM projects
WHERE id = $1 AND (owner_id = $2 OR team_id IN (
SELECT team_id FROM team_members WHERE user_id = $2 AND is_active = true
))
)
`), projectID, userID).Scan(&exists)
if err != nil || !exists {
teamIDs, _ := h.stores.Teams.GetUserTeamIDs(c.Request.Context(), userID)
ok, err := h.stores.Projects.UserCanAccess(c.Request.Context(), userID, projectID, teamIDs)
if err != nil || !ok {
c.JSON(http.StatusForbidden, gin.H{"error": "project not found or access denied"})
return
}
@@ -597,16 +585,9 @@ func (h *FileHandler) ListByProject(c *gin.Context) {
// Admins bypass project ownership/membership checks
if c.GetString("role") != "admin" {
var exists bool
err := database.DB.QueryRowContext(c.Request.Context(), database.Q(`
SELECT EXISTS(
SELECT 1 FROM projects
WHERE id = $1 AND (owner_id = $2 OR team_id IN (
SELECT team_id FROM team_members WHERE user_id = $2 AND is_active = true
))
)
`), projectID, userID).Scan(&exists)
if err != nil || !exists {
teamIDs, _ := h.stores.Teams.GetUserTeamIDs(c.Request.Context(), userID)
ok, err := h.stores.Projects.UserCanAccess(c.Request.Context(), userID, projectID, teamIDs)
if err != nil || !ok {
c.JSON(http.StatusForbidden, gin.H{"error": "project not found or access denied"})
return
}