inou/lib/stubs.go

384 lines
9.4 KiB
Go

package lib
// =============================================================================
// LEGACY STUBS — temporary bridges while callers are migrated to dbcore.go
//
// Each stub logs its call so we can find and replace callers.
// Delete this file when all callers use the new core.
// =============================================================================
import (
"fmt"
"log"
"os"
"path/filepath"
)
// --- Legacy types ---
type EntryFilter struct {
DossierID string
Type string
Value string
SearchKey string
SearchKey2 string
FromDate int64
ToDate int64
Limit int
}
type AccessFilter struct {
AccessorID string
TargetID string
Status *int
}
type DossierQueryRow struct {
Dossier
Category int `db:"category"`
EntryCount int `db:"entry_count"`
}
type DossierAccess struct {
Access
}
// --- Entry convenience wrappers (all delegate to core with RBAC) ---
func EntryGet(ctx *AccessContext, id string) (*Entry, error) {
accessorID := ""
if ctx != nil {
accessorID = ctx.AccessorID
}
return entryGetByID(accessorID, id)
}
func EntryQuery(ctx *AccessContext, dossierID string, category int, typ, parent string) ([]*Entry, error) {
accessorID := ""
if ctx != nil {
accessorID = ctx.AccessorID
}
f := &Filter{Category: category}
if typ != "" {
f.Type = typ
}
if parent != "" && parent != "*" {
f.ParentID = parent
}
return EntryRead(accessorID, dossierID, f)
}
func EntryList(accessorID string, parent string, category int, f *EntryFilter) ([]*Entry, error) {
dossierID := ""
filter := &Filter{Category: category, ParentID: parent}
if f != nil {
dossierID = f.DossierID
filter.Type = f.Type
filter.SearchKey = f.SearchKey
filter.SearchKey2 = f.SearchKey2
filter.FromDate = f.FromDate
filter.ToDate = f.ToDate
filter.Limit = f.Limit
}
return EntryRead(accessorID, dossierID, filter)
}
func EntryQueryOld(dossierID string, category int, typ string) ([]*Entry, error) {
return EntryRead("", dossierID, &Filter{Category: category, Type: typ})
}
func EntryCount(ctx *AccessContext, dossierID string, category int, typ string) (int, error) {
entries, err := EntryQuery(ctx, dossierID, category, typ, "*")
if err != nil {
return 0, err
}
return len(entries), nil
}
func EntryChildren(dossierID, parentID string) ([]*Entry, error) {
return EntryRead("", dossierID, &Filter{Category: -1, ParentID: parentID})
}
func EntryChildrenByType(dossierID, parentID string, typ string) ([]*Entry, error) {
return EntryRead("", dossierID, &Filter{Category: -1, ParentID: parentID, Type: typ})
}
func EntryTypes(dossierID string, category int) ([]string, error) {
entries, err := EntryRead("", dossierID, &Filter{Category: category})
if err != nil {
return nil, err
}
seen := map[string]bool{}
var types []string
for _, e := range entries {
if !seen[e.Type] {
seen[e.Type] = true
types = append(types, e.Type)
}
}
return types, nil
}
// --- Dossier stubs ---
func DossierGetBySessionToken(token string) *Dossier {
log.Printf("[STUB] DossierGetBySessionToken")
return nil
}
func DossierQuery(accessorID string) ([]*DossierQueryRow, error) {
// Get all accessible dossier profiles via RBAC
dossierEntries, err := EntryRead(accessorID, "", &Filter{Category: 0})
if err != nil {
return nil, err
}
var rows []*DossierQueryRow
for _, de := range dossierEntries {
d := *DossierFromEntry(de)
// Count entries by category for this dossier
allEntries, err := EntryRead(accessorID, de.DossierID, &Filter{Category: -1})
if err != nil {
continue
}
catCounts := map[int]int{}
for _, e := range allEntries {
if e.Category > 0 {
catCounts[e.Category]++
}
}
if len(catCounts) == 0 {
// Still include dossier even with no entries
rows = append(rows, &DossierQueryRow{Dossier: d})
} else {
for cat, count := range catCounts {
rows = append(rows, &DossierQueryRow{Dossier: d, Category: cat, EntryCount: count})
}
}
}
return rows, nil
}
// --- Access stubs ---
func AccessGet(accessorID, targetID string) (*Access, error) {
var grants []Access
if err := dbQuery(
"SELECT AccessID, DossierID, GranteeID, EntryID, Ops, Relation, CreatedAt FROM access WHERE GranteeID = ? AND DossierID = ?",
[]any{accessorID, targetID},
&grants,
); err != nil {
return nil, err
}
// Prefer dossier-level grant (EntryID == dossierID)
for _, g := range grants {
if g.EntryID == targetID {
return &g, nil
}
}
if len(grants) > 0 {
return &grants[0], nil
}
return nil, nil
}
func AccessRemove(accessorID, targetID string) error {
log.Printf("[STUB] AccessRemove(accessor=%s, target=%s)", accessorID, targetID)
return nil
}
func AccessList(f *AccessFilter) ([]*Access, error) {
if f == nil {
return nil, nil
}
var grants []*Access
if f.AccessorID != "" {
return grants, dbQuery(
"SELECT AccessID, DossierID, GranteeID, EntryID, Relation, Ops, CreatedAt FROM access WHERE GranteeID = ?",
[]any{f.AccessorID},
&grants,
)
}
if f.TargetID != "" {
return grants, dbQuery(
"SELECT AccessID, DossierID, GranteeID, EntryID, Relation, Ops, CreatedAt FROM access WHERE DossierID = ?",
[]any{f.TargetID},
&grants,
)
}
return nil, nil
}
func AccessListByAccessor(granteeID string) ([]*Access, error) {
log.Printf("[STUB] AccessListByAccessor(grantee=%s)", granteeID)
return nil, nil
}
func AccessListByTargetWithNames(targetID string) ([]map[string]interface{}, error) {
log.Printf("[STUB] AccessListByTargetWithNames(target=%s)", targetID)
return nil, nil
}
func AccessUpdateTimestamp(granteeID, dossierID string) error {
log.Printf("[STUB] AccessUpdateTimestamp(grantee=%s, dossier=%s)", granteeID, dossierID)
return nil
}
func AccessGrantRole(dossierID, granteeID, role string) error {
log.Printf("[STUB] AccessGrantRole(dossier=%s, grantee=%s, role=%s)", dossierID, granteeID, role)
return nil
}
// --- Audit stubs ---
func auditWrite(a *AuditEntry) {
if a.AuditID == "" {
a.AuditID = NewID()
}
if a.Timestamp == 0 {
a.Timestamp = nowUnix()
}
db.Exec(`INSERT INTO audit (AuditID, Actor1ID, Actor2ID, TargetID, Action, Details, RelationID, Timestamp)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
a.AuditID, a.Actor1ID, a.Actor2ID, a.TargetID,
PackStr(a.Action), PackStr(a.Details),
a.RelationID, a.Timestamp,
)
}
func AuditAdd(a *AuditEntry) error {
auditWrite(a)
return nil
}
func AuditLog(actor1ID string, action string, targetID string, details string) {
auditWrite(&AuditEntry{Actor1ID: actor1ID, Action: action, TargetID: targetID, Details: details})
}
func AuditLogFull(actor1ID, actor2ID, targetID string, action, details string, relationID int) {
auditWrite(&AuditEntry{Actor1ID: actor1ID, Actor2ID: actor2ID, TargetID: targetID, Action: action, Details: details, RelationID: relationID})
}
// --- Object I/O (RBAC enforced, Pack/Unpack for encryption) ---
func ObjectWrite(ctx *AccessContext, dossierID, entryID string, data []byte) error {
accessorID := ""
if ctx != nil {
accessorID = ctx.AccessorID
}
if !CheckAccess(accessorID, dossierID, entryID, PermWrite) {
return fmt.Errorf("access denied")
}
path := ObjectPath(dossierID, entryID)
if err := os.MkdirAll(path[:len(path)-len(entryID)-1], 0750); err != nil {
return err
}
return os.WriteFile(path, Pack(data), 0640)
}
func ObjectRead(ctx *AccessContext, dossierID, entryID string) ([]byte, error) {
accessorID := ""
if ctx != nil {
accessorID = ctx.AccessorID
}
if !CheckAccess(accessorID, dossierID, entryID, PermRead) {
return nil, fmt.Errorf("access denied")
}
packed, err := os.ReadFile(ObjectPath(dossierID, entryID))
if err != nil {
return nil, err
}
return Unpack(packed), nil
}
func ObjectRemoveByDossier(ctx *AccessContext, dossierID string) error {
accessorID := ""
if ctx != nil {
accessorID = ctx.AccessorID
}
if !CheckAccess(accessorID, dossierID, "", PermDelete) {
return fmt.Errorf("access denied")
}
return os.RemoveAll(filepath.Join(ObjectDir, dossierID))
}
// --- Lab stubs ---
func LabEntryListForIndex() ([]*Entry, error) {
log.Printf("[STUB] LabEntryListForIndex")
return nil, nil
}
func EntryCategoryCounts(ctx *AccessContext, dossierID string) (map[string]int, error) {
accessorID := ""
if ctx != nil {
accessorID = ctx.AccessorID
}
entries, err := EntryRead(accessorID, dossierID, &Filter{Category: -1})
if err != nil {
return nil, err
}
counts := map[string]int{}
for _, e := range entries {
if e.Category > 0 {
counts[CategoryName(e.Category)]++
}
}
return counts, nil
}
func EntryQueryByDate(dossierID string, from, to int64) ([]*Entry, error) {
return EntryRead("", dossierID, &Filter{Category: -1, FromDate: from, ToDate: to})
}
// --- Audit types and stubs ---
type AuditFilter struct {
ActorID string
TargetID string
Action string
FromDate int64
ToDate int64
Limit int
}
func AuditList(f *AuditFilter) ([]*AuditEntry, error) {
if f == nil {
return nil, nil
}
q := "SELECT AuditID, Actor1ID, Actor2ID, TargetID, Action, Details, RelationID, Timestamp FROM audit WHERE 1=1"
var args []any
if f.TargetID != "" {
q += " AND TargetID = ?"
args = append(args, f.TargetID)
}
if f.ActorID != "" {
q += " AND Actor1ID = ?"
args = append(args, f.ActorID)
}
if f.FromDate > 0 {
q += " AND Timestamp >= ?"
args = append(args, f.FromDate)
}
if f.ToDate > 0 {
q += " AND Timestamp < ?"
args = append(args, f.ToDate)
}
q += " ORDER BY Timestamp DESC"
if f.Limit > 0 {
q += fmt.Sprintf(" LIMIT %d", f.Limit)
}
var entries []*AuditEntry
err := dbQuery(q, args, &entries)
return entries, err
}
// --- Misc ---