package handlers import ( "encoding/json" "net/http" "github.com/go-chi/chi/v5" "xorm.io/xorm" "github.com/forgeo/forgebucket/internal/api/middleware" "github.com/forgeo/forgebucket/internal/models" ) type LFSHandler struct{ db *xorm.Engine } func NewLFSHandler(db *xorm.Engine) *LFSHandler { return &LFSHandler{db: db} } func (h *LFSHandler) resolveRepo(w http.ResponseWriter, r *http.Request) (*models.Repository, bool) { ownerName := chi.URLParam(r, "owner") repoName := chi.URLParam(r, "repo") var owner models.User found, err := h.db.Where("username = ?", ownerName).Get(&owner) if err != nil { jsonError(w, "database error: "+err.Error(), http.StatusInternalServerError) return nil, false } if !found { jsonError(w, "repository not found", http.StatusNotFound) return nil, false } var repo models.Repository found, err = h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo) if err != nil { jsonError(w, "database error: "+err.Error(), http.StatusInternalServerError) return nil, false } if !found { jsonError(w, "repository not found", http.StatusNotFound) return nil, false } return &repo, true } func (h *LFSHandler) canManage(repo *models.Repository, callerID int64) bool { if callerID == repo.OwnerID { return true } var m models.RepoMember found, _ := h.db.Where("repo_id = ? AND user_id = ? AND permission = 'admin'", repo.ID, callerID).Get(&m) return found } func (h *LFSHandler) Get(w http.ResponseWriter, r *http.Request) { repo, ok := h.resolveRepo(w, r) if !ok { return } var s models.RepoLFSSettings h.db.Where("repo_id = ?", repo.ID).Get(&s) jsonOK(w, lfsResponse(repo.ID, &s)) } func (h *LFSHandler) Update(w http.ResponseWriter, r *http.Request) { repo, ok := h.resolveRepo(w, r) if !ok { return } callerID, _ := middleware.UserIDFromContext(r.Context()) if !h.canManage(repo, callerID) { jsonError(w, "forbidden", http.StatusForbidden) return } var body struct { Enabled *bool `json:"enabled"` LockingEnabled *bool `json:"lockingEnabled"` MaxFileSizeMB *int64 `json:"maxFileSizeMB"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { jsonError(w, "invalid request body", http.StatusBadRequest) return } var s models.RepoLFSSettings found, err := h.db.Where("repo_id = ?", repo.ID).Get(&s) if err != nil { jsonError(w, "database error: "+err.Error(), http.StatusInternalServerError) return } s.RepoID = repo.ID if body.Enabled != nil { s.Enabled = *body.Enabled } if body.LockingEnabled != nil { s.LockingEnabled = *body.LockingEnabled } if body.MaxFileSizeMB != nil { s.MaxFileSizeMB = *body.MaxFileSizeMB } if found { if _, err := h.db.ID(s.ID).Cols("enabled", "locking_enabled", "max_file_size_mb").Update(&s); err != nil { jsonError(w, "could not update LFS settings", http.StatusInternalServerError) return } } else { if _, err := h.db.Insert(&s); err != nil { jsonError(w, "could not save LFS settings", http.StatusInternalServerError) return } } jsonOK(w, lfsResponse(repo.ID, &s)) } type lfsSettingsResponse struct { Enabled bool `json:"enabled"` LockingEnabled bool `json:"lockingEnabled"` MaxFileSizeMB int64 `json:"maxFileSizeMB"` } func lfsResponse(_ int64, s *models.RepoLFSSettings) lfsSettingsResponse { return lfsSettingsResponse{ Enabled: s.Enabled, LockingEnabled: s.LockingEnabled, MaxFileSizeMB: s.MaxFileSizeMB, } }