183 lines
4.5 KiB
Go
183 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"inou/lib"
|
|
)
|
|
|
|
type AccessRecord struct {
|
|
Accessor string `json:"accessor"`
|
|
Target string `json:"target"`
|
|
Name string `json:"name,omitempty"`
|
|
Relation int `json:"relation"`
|
|
IsCareReceiver bool `json:"is_care_receiver"`
|
|
CanEdit bool `json:"can_edit"`
|
|
CreatedAt int64 `json:"created_at,omitempty"`
|
|
AccessedAt int64 `json:"accessed_at,omitempty"`
|
|
}
|
|
|
|
type AccessRequest struct {
|
|
Accessor string `json:"accessor"`
|
|
Target string `json:"target"`
|
|
Relation int `json:"relation"`
|
|
IsCareReceiver bool `json:"is_care_receiver"`
|
|
CanEdit bool `json:"can_edit"`
|
|
Delete bool `json:"delete"`
|
|
Touch bool `json:"touch"`
|
|
}
|
|
|
|
func handleAccess(w http.ResponseWriter, r *http.Request) {
|
|
if !isLocalhost(r) {
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
if r.Method == "GET" {
|
|
handleAccessGet(w, r)
|
|
return
|
|
}
|
|
if r.Method == "POST" {
|
|
handleAccessPost(w, r)
|
|
return
|
|
}
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
|
|
func handleAccessGet(w http.ResponseWriter, r *http.Request) {
|
|
accessorHex := r.URL.Query().Get("accessor")
|
|
targetHex := r.URL.Query().Get("target")
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
// Single record lookup
|
|
if accessorHex != "" && targetHex != "" {
|
|
access, err := lib.AccessGet(accessorHex, targetHex)
|
|
if err != nil || access.Status != 1 {
|
|
json.NewEncoder(w).Encode(map[string]interface{}{"found": false})
|
|
return
|
|
}
|
|
|
|
json.NewEncoder(w).Encode(AccessRecord{
|
|
Accessor: accessorHex,
|
|
Target: targetHex,
|
|
Relation: access.Relation,
|
|
IsCareReceiver: access.IsCareReceiver,
|
|
CanEdit: access.CanEdit,
|
|
CreatedAt: access.CreatedAt,
|
|
AccessedAt: access.AccessedAt,
|
|
})
|
|
return
|
|
}
|
|
|
|
// List all with access to target (includes names from dossiers join)
|
|
if targetHex != "" {
|
|
records, err := lib.AccessListByTargetWithNames(targetHex)
|
|
if err != nil {
|
|
json.NewEncoder(w).Encode([]interface{}{})
|
|
return
|
|
}
|
|
|
|
var result []AccessRecord
|
|
for _, rec := range records {
|
|
result = append(result, AccessRecord{
|
|
Accessor: rec["accessor_id"].(string),
|
|
Target: targetHex,
|
|
Name: rec["name"].(string),
|
|
Relation: rec["relation"].(int),
|
|
IsCareReceiver: rec["is_care_receiver"].(bool),
|
|
CanEdit: rec["can_edit"].(bool),
|
|
})
|
|
}
|
|
json.NewEncoder(w).Encode(result)
|
|
return
|
|
}
|
|
|
|
http.Error(w, "target required", http.StatusBadRequest)
|
|
}
|
|
|
|
func handleAccessPost(w http.ResponseWriter, r *http.Request) {
|
|
var req AccessRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if req.Accessor == "" || req.Target == "" {
|
|
http.Error(w, "accessor and target required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
accessorID := req.Accessor
|
|
targetID := req.Target
|
|
now := time.Now().Unix()
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
if req.Delete {
|
|
err := lib.AccessRemove(accessorID, targetID)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
json.NewEncoder(w).Encode(map[string]interface{}{"deleted": true})
|
|
return
|
|
}
|
|
|
|
if req.Touch {
|
|
err := lib.AccessUpdateTimestamp(accessorID, targetID)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
json.NewEncoder(w).Encode(map[string]interface{}{"touched": true})
|
|
return
|
|
}
|
|
|
|
// Upsert: try to get existing, then update or create
|
|
access := &lib.DossierAccess{
|
|
AccessorDossierID: accessorID,
|
|
TargetDossierID: targetID,
|
|
Relation: req.Relation,
|
|
IsCareReceiver: req.IsCareReceiver,
|
|
CanEdit: req.CanEdit,
|
|
Status: 1,
|
|
CreatedAt: now,
|
|
AccessedAt: now,
|
|
}
|
|
|
|
// Check if exists to preserve created_at
|
|
existing, _ := lib.AccessGet(accessorID, targetID)
|
|
if existing != nil {
|
|
access.CreatedAt = existing.CreatedAt
|
|
}
|
|
|
|
if err := lib.AccessWrite(access); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
json.NewEncoder(w).Encode(AccessRecord{
|
|
Accessor: req.Accessor,
|
|
Target: req.Target,
|
|
Relation: req.Relation,
|
|
IsCareReceiver: req.IsCareReceiver,
|
|
CanEdit: req.CanEdit,
|
|
})
|
|
}
|
|
|
|
func isLocalhost(r *http.Request) bool {
|
|
ip := r.RemoteAddr
|
|
return strings.HasPrefix(ip, "127.0.0.1") || strings.HasPrefix(ip, "[::1]")
|
|
}
|
|
|
|
func boolToInt(b bool) int {
|
|
if b {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|