ultisuite-backend/internal/drivestore/store.go
R3D347HR4Y 621b0099d6
Some checks are pending
CI / Go tests (push) Waiting to run
CI / Integration tests (push) Waiting to run
CI / DB migrations (push) Waiting to run
feat(deploy): enhance Nginx configuration and API integration for UltiAI
- Updated .env.example to include new configuration options for the UltiAI branding and API endpoints.
- Enhanced Nginx configuration to support new API routes for the MCP and WebSocket connections.
- Introduced sub-filters for branding adjustments in Nginx responses.
- Added new JavaScript patch for API endpoint adjustments.
- Implemented tests for new API functionalities and improved error handling in the AI gateway.
2026-06-15 00:22:23 +02:00

374 lines
10 KiB
Go

package drivestore
import (
"context"
"errors"
"fmt"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
var ErrOrgFolderNotFound = errors.New("org folder not found")
var ErrMountNotFound = errors.New("mount not found")
type OrgFolder struct {
ID string `json:"id"`
OrgSlug string `json:"org_slug"`
NCFolderID int `json:"nc_folder_id"`
MountPoint string `json:"mount_point"`
QuotaBytes *int64 `json:"quota_bytes,omitempty"`
AutoProvisioned bool `json:"auto_provisioned"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type Mount struct {
ID string `json:"id"`
Scope string `json:"scope"`
OwnerUserID *string `json:"owner_user_id,omitempty"`
OrgSlug *string `json:"org_slug,omitempty"`
NCMountID *int `json:"nc_mount_id,omitempty"`
DisplayName string `json:"display_name"`
BackendType string `json:"backend_type"`
MountPoint string `json:"mount_point"`
Status string `json:"status"`
LastError string `json:"last_error,omitempty"`
ConfigEnc []byte `json:"-"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type Store struct {
db *pgxpool.Pool
}
func NewStore(db *pgxpool.Pool) *Store {
return &Store{db: db}
}
func (s *Store) ListOrgFolders(ctx context.Context) ([]OrgFolder, error) {
if s.db == nil {
return nil, fmt.Errorf("database not configured")
}
rows, err := s.db.Query(ctx, `
SELECT id, org_slug, nc_folder_id, mount_point, quota_bytes,
auto_provisioned, created_by, created_at, updated_at
FROM drive_org_folders
ORDER BY mount_point ASC
`)
if err != nil {
return nil, err
}
defer rows.Close()
var out []OrgFolder
for rows.Next() {
var item OrgFolder
if err := rows.Scan(
&item.ID, &item.OrgSlug, &item.NCFolderID, &item.MountPoint,
&item.QuotaBytes, &item.AutoProvisioned, &item.CreatedBy,
&item.CreatedAt, &item.UpdatedAt,
); err != nil {
return nil, err
}
out = append(out, item)
}
return out, rows.Err()
}
func (s *Store) GetOrgFolder(ctx context.Context, id string) (OrgFolder, error) {
if s.db == nil {
return OrgFolder{}, fmt.Errorf("database not configured")
}
var item OrgFolder
err := s.db.QueryRow(ctx, `
SELECT id, org_slug, nc_folder_id, mount_point, quota_bytes,
auto_provisioned, created_by, created_at, updated_at
FROM drive_org_folders WHERE id = $1
`, id).Scan(
&item.ID, &item.OrgSlug, &item.NCFolderID, &item.MountPoint,
&item.QuotaBytes, &item.AutoProvisioned, &item.CreatedBy,
&item.CreatedAt, &item.UpdatedAt,
)
if errors.Is(err, pgx.ErrNoRows) {
return OrgFolder{}, ErrOrgFolderNotFound
}
if err != nil {
return OrgFolder{}, err
}
return item, nil
}
func (s *Store) GetOrgFolderBySlug(ctx context.Context, orgSlug string) (OrgFolder, error) {
if s.db == nil {
return OrgFolder{}, fmt.Errorf("database not configured")
}
var item OrgFolder
err := s.db.QueryRow(ctx, `
SELECT id, org_slug, nc_folder_id, mount_point, quota_bytes,
auto_provisioned, created_by, created_at, updated_at
FROM drive_org_folders WHERE org_slug = $1
`, orgSlug).Scan(
&item.ID, &item.OrgSlug, &item.NCFolderID, &item.MountPoint,
&item.QuotaBytes, &item.AutoProvisioned, &item.CreatedBy,
&item.CreatedAt, &item.UpdatedAt,
)
if errors.Is(err, pgx.ErrNoRows) {
return OrgFolder{}, ErrOrgFolderNotFound
}
if err != nil {
return OrgFolder{}, err
}
return item, nil
}
type CreateOrgFolderParams struct {
OrgSlug string
NCFolderID int
MountPoint string
QuotaBytes *int64
AutoProvisioned bool
CreatedBy string
}
func (s *Store) CreateOrgFolder(ctx context.Context, p CreateOrgFolderParams) (OrgFolder, error) {
if s.db == nil {
return OrgFolder{}, fmt.Errorf("database not configured")
}
id := uuid.NewString()
var item OrgFolder
err := s.db.QueryRow(ctx, `
INSERT INTO drive_org_folders (
id, org_slug, nc_folder_id, mount_point, quota_bytes,
auto_provisioned, created_by
) VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, org_slug, nc_folder_id, mount_point, quota_bytes,
auto_provisioned, created_by, created_at, updated_at
`, id, p.OrgSlug, p.NCFolderID, p.MountPoint, p.QuotaBytes, p.AutoProvisioned, p.CreatedBy).Scan(
&item.ID, &item.OrgSlug, &item.NCFolderID, &item.MountPoint,
&item.QuotaBytes, &item.AutoProvisioned, &item.CreatedBy,
&item.CreatedAt, &item.UpdatedAt,
)
if err != nil {
return OrgFolder{}, err
}
return item, nil
}
func (s *Store) UpdateOrgFolder(ctx context.Context, id, mountPoint string, quotaBytes *int64) (OrgFolder, error) {
if s.db == nil {
return OrgFolder{}, fmt.Errorf("database not configured")
}
var item OrgFolder
err := s.db.QueryRow(ctx, `
UPDATE drive_org_folders
SET mount_point = $2, quota_bytes = $3, updated_at = NOW()
WHERE id = $1
RETURNING id, org_slug, nc_folder_id, mount_point, quota_bytes,
auto_provisioned, created_by, created_at, updated_at
`, id, mountPoint, quotaBytes).Scan(
&item.ID, &item.OrgSlug, &item.NCFolderID, &item.MountPoint,
&item.QuotaBytes, &item.AutoProvisioned, &item.CreatedBy,
&item.CreatedAt, &item.UpdatedAt,
)
if errors.Is(err, pgx.ErrNoRows) {
return OrgFolder{}, ErrOrgFolderNotFound
}
if err != nil {
return OrgFolder{}, err
}
return item, nil
}
func (s *Store) DeleteOrgFolder(ctx context.Context, id string) error {
if s.db == nil {
return fmt.Errorf("database not configured")
}
tag, err := s.db.Exec(ctx, `DELETE FROM drive_org_folders WHERE id = $1`, id)
if err != nil {
return err
}
if tag.RowsAffected() == 0 {
return ErrOrgFolderNotFound
}
return nil
}
func (s *Store) ListOrgMounts(ctx context.Context) ([]Mount, error) {
if s.db == nil {
return nil, fmt.Errorf("database not configured")
}
rows, err := s.db.Query(ctx, `
SELECT id, scope, owner_user_id, org_slug, nc_mount_id, display_name,
backend_type, mount_point, status, last_error, created_at, updated_at
FROM drive_mounts
WHERE scope = 'org'
ORDER BY display_name ASC
`)
if err != nil {
return nil, err
}
defer rows.Close()
return scanMounts(rows)
}
func (s *Store) ListMountsForUser(ctx context.Context, ownerUserID string, orgSlugs []string) ([]Mount, error) {
if s.db == nil {
return nil, fmt.Errorf("database not configured")
}
rows, err := s.db.Query(ctx, `
SELECT id, scope, owner_user_id, org_slug, nc_mount_id, display_name,
backend_type, mount_point, status, last_error, created_at, updated_at
FROM drive_mounts
WHERE (scope = 'user' AND owner_user_id = $1::uuid)
OR (
scope = 'org'
AND (cardinality($2::text[]) = 0 OR org_slug = ANY($2))
)
ORDER BY display_name ASC
`, ownerUserID, orgSlugs)
if err != nil {
return nil, err
}
defer rows.Close()
return scanMounts(rows)
}
func (s *Store) GetMount(ctx context.Context, id string) (Mount, error) {
if s.db == nil {
return Mount{}, fmt.Errorf("database not configured")
}
row := s.db.QueryRow(ctx, `
SELECT id, scope, owner_user_id, org_slug, nc_mount_id, display_name,
backend_type, mount_point, status, last_error, created_at, updated_at
FROM drive_mounts WHERE id = $1
`, id)
item, err := scanMount(row)
if errors.Is(err, pgx.ErrNoRows) {
return Mount{}, ErrMountNotFound
}
return item, err
}
type CreateMountParams struct {
Scope string
OwnerUserID *string
OrgSlug *string
NCMountID *int
DisplayName string
BackendType string
MountPoint string
Status string
ConfigEnc []byte
}
func (s *Store) CreateMount(ctx context.Context, p CreateMountParams) (Mount, error) {
if s.db == nil {
return Mount{}, fmt.Errorf("database not configured")
}
id := uuid.NewString()
status := p.Status
if status == "" {
status = "active"
}
row := s.db.QueryRow(ctx, `
INSERT INTO drive_mounts (
id, scope, owner_user_id, org_slug, nc_mount_id, display_name,
backend_type, mount_point, status, config_encrypted
) VALUES ($1, $2, $3::uuid, $4, $5, $6, $7, $8, $9, $10)
RETURNING id, scope, owner_user_id, org_slug, nc_mount_id, display_name,
backend_type, mount_point, status, last_error, created_at, updated_at
`, id, p.Scope, p.OwnerUserID, p.OrgSlug, p.NCMountID, p.DisplayName,
p.BackendType, p.MountPoint, status, p.ConfigEnc)
return scanMount(row)
}
func (s *Store) UpdateMountConfig(ctx context.Context, id string, configEnc []byte) error {
if s.db == nil {
return fmt.Errorf("database not configured")
}
tag, err := s.db.Exec(ctx, `
UPDATE drive_mounts SET config_encrypted = $2, updated_at = NOW() WHERE id = $1
`, id, configEnc)
if err != nil {
return err
}
if tag.RowsAffected() == 0 {
return ErrMountNotFound
}
return nil
}
func (s *Store) GetMountConfig(ctx context.Context, id string) ([]byte, error) {
if s.db == nil {
return nil, fmt.Errorf("database not configured")
}
var config []byte
err := s.db.QueryRow(ctx, `SELECT config_encrypted FROM drive_mounts WHERE id = $1`, id).Scan(&config)
if errors.Is(err, pgx.ErrNoRows) {
return nil, ErrMountNotFound
}
return config, err
}
func (s *Store) UpdateMountStatus(ctx context.Context, id, status, lastError string, ncMountID *int) error {
if s.db == nil {
return fmt.Errorf("database not configured")
}
tag, err := s.db.Exec(ctx, `
UPDATE drive_mounts
SET status = $2, last_error = $3, nc_mount_id = COALESCE($4, nc_mount_id), updated_at = NOW()
WHERE id = $1
`, id, status, lastError, ncMountID)
if err != nil {
return err
}
if tag.RowsAffected() == 0 {
return ErrMountNotFound
}
return nil
}
func (s *Store) DeleteMount(ctx context.Context, id string) error {
if s.db == nil {
return fmt.Errorf("database not configured")
}
tag, err := s.db.Exec(ctx, `DELETE FROM drive_mounts WHERE id = $1`, id)
if err != nil {
return err
}
if tag.RowsAffected() == 0 {
return ErrMountNotFound
}
return nil
}
type scannable interface {
Scan(dest ...any) error
}
func scanMount(row scannable) (Mount, error) {
var item Mount
err := row.Scan(
&item.ID, &item.Scope, &item.OwnerUserID, &item.OrgSlug, &item.NCMountID,
&item.DisplayName, &item.BackendType, &item.MountPoint, &item.Status,
&item.LastError, &item.CreatedAt, &item.UpdatedAt,
)
return item, err
}
func scanMounts(rows pgx.Rows) ([]Mount, error) {
var out []Mount
for rows.Next() {
item, err := scanMount(rows)
if err != nil {
return nil, err
}
out = append(out, item)
}
return out, rows.Err()
}