mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 23:44:22 +00:00
Implement auth package tests
This commit is contained in:
@@ -3,9 +3,9 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"novamd/internal/auth"
|
"novamd/internal/auth"
|
||||||
|
"novamd/internal/context"
|
||||||
"novamd/internal/db"
|
"novamd/internal/db"
|
||||||
"novamd/internal/handlers"
|
"novamd/internal/handlers"
|
||||||
"novamd/internal/middleware"
|
|
||||||
"novamd/internal/storage"
|
"novamd/internal/storage"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
@@ -29,7 +29,7 @@ func SetupRoutes(r chi.Router, db db.Database, s storage.Manager, authMiddleware
|
|||||||
r.Group(func(r chi.Router) {
|
r.Group(func(r chi.Router) {
|
||||||
// Apply authentication middleware to all routes in this group
|
// Apply authentication middleware to all routes in this group
|
||||||
r.Use(authMiddleware.Authenticate)
|
r.Use(authMiddleware.Authenticate)
|
||||||
r.Use(middleware.WithUserContext)
|
r.Use(context.WithUserContextMiddleware)
|
||||||
|
|
||||||
// Auth routes
|
// Auth routes
|
||||||
r.Post("/auth/logout", handler.Logout(sessionService))
|
r.Post("/auth/logout", handler.Logout(sessionService))
|
||||||
@@ -67,7 +67,7 @@ func SetupRoutes(r chi.Router, db db.Database, s storage.Manager, authMiddleware
|
|||||||
|
|
||||||
// Single workspace routes
|
// Single workspace routes
|
||||||
r.Route("/{workspaceName}", func(r chi.Router) {
|
r.Route("/{workspaceName}", func(r chi.Router) {
|
||||||
r.Use(middleware.WithWorkspaceContext(db))
|
r.Use(context.WithWorkspaceContextMiddleware(db))
|
||||||
r.Use(authMiddleware.RequireWorkspaceAccess)
|
r.Use(authMiddleware.RequireWorkspaceAccess)
|
||||||
|
|
||||||
r.Get("/", handler.GetWorkspace())
|
r.Get("/", handler.GetWorkspace())
|
||||||
|
|||||||
@@ -1,25 +1,12 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"novamd/internal/httpcontext"
|
"novamd/internal/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type contextKey string
|
|
||||||
|
|
||||||
// UserContextKey is the key used to store user claims in the request context
|
|
||||||
const UserContextKey contextKey = "user"
|
|
||||||
|
|
||||||
// UserClaims represents the user information stored in the request context
|
|
||||||
type UserClaims struct {
|
|
||||||
UserID int
|
|
||||||
Role string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Middleware handles JWT authentication for protected routes
|
// Middleware handles JWT authentication for protected routes
|
||||||
type Middleware struct {
|
type Middleware struct {
|
||||||
jwtManager JWTManager
|
jwtManager JWTManager
|
||||||
@@ -70,14 +57,14 @@ func (m *Middleware) Authenticate(next http.Handler) http.Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add user claims to request context
|
// Create handler context with user information
|
||||||
ctx := context.WithValue(r.Context(), UserContextKey, UserClaims{
|
hctx := &context.HandlerContext{
|
||||||
UserID: claims.UserID,
|
UserID: claims.UserID,
|
||||||
Role: claims.Role,
|
UserRole: claims.Role,
|
||||||
})
|
}
|
||||||
|
|
||||||
// Call the next handler with the updated context
|
// Add context to request and continue
|
||||||
next.ServeHTTP(w, r.WithContext(ctx))
|
next.ServeHTTP(w, context.WithHandlerContext(r, hctx))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,13 +76,12 @@ func (m *Middleware) Authenticate(next http.Handler) http.Handler {
|
|||||||
func (m *Middleware) RequireRole(role string) func(http.Handler) http.Handler {
|
func (m *Middleware) RequireRole(role string) func(http.Handler) http.Handler {
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
claims, ok := r.Context().Value(UserContextKey).(UserClaims)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if claims.Role != role && claims.Role != "admin" {
|
if ctx.UserRole != role && ctx.UserRole != "admin" {
|
||||||
http.Error(w, "Insufficient permissions", http.StatusForbidden)
|
http.Error(w, "Insufficient permissions", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -112,8 +98,7 @@ func (m *Middleware) RequireRole(role string) func(http.Handler) http.Handler {
|
|||||||
// - http.Handler: the handler function
|
// - http.Handler: the handler function
|
||||||
func (m *Middleware) RequireWorkspaceAccess(next http.Handler) http.Handler {
|
func (m *Middleware) RequireWorkspaceAccess(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Get our handler context
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -133,17 +118,3 @@ func (m *Middleware) RequireWorkspaceAccess(next http.Handler) http.Handler {
|
|||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserFromContext retrieves user claims from the request context
|
|
||||||
// Parameters:
|
|
||||||
// - ctx: the request context
|
|
||||||
// Returns:
|
|
||||||
// - *UserClaims: the user claims
|
|
||||||
// - error: any error that occurred
|
|
||||||
func GetUserFromContext(ctx context.Context) (*UserClaims, error) {
|
|
||||||
claims, ok := ctx.Value(UserContextKey).(UserClaims)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("no user found in context")
|
|
||||||
}
|
|
||||||
return &claims, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
package auth_test
|
package auth_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"novamd/internal/auth"
|
"novamd/internal/auth"
|
||||||
"novamd/internal/httpcontext"
|
"novamd/internal/context"
|
||||||
"novamd/internal/models"
|
"novamd/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -97,7 +95,7 @@ func TestAuthenticateMiddleware(t *testing.T) {
|
|||||||
|
|
||||||
// Create test handler
|
// Create test handler
|
||||||
nextCalled := false
|
nextCalled := false
|
||||||
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
nextCalled = true
|
nextCalled = true
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
})
|
})
|
||||||
@@ -158,12 +156,15 @@ func TestRequireRole(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
// Create context with user claims
|
// Create handler context with user info
|
||||||
ctx := context.WithValue(context.Background(), auth.UserContextKey, auth.UserClaims{
|
hctx := &context.HandlerContext{
|
||||||
UserID: 1,
|
UserID: 1,
|
||||||
Role: tc.userRole,
|
UserRole: tc.userRole,
|
||||||
})
|
}
|
||||||
req := httptest.NewRequest("GET", "/test", nil).WithContext(ctx)
|
|
||||||
|
// Create request with handler context
|
||||||
|
req := httptest.NewRequest("GET", "/test", nil)
|
||||||
|
req = context.WithHandlerContext(req, hctx)
|
||||||
w := newMockResponseWriter()
|
w := newMockResponseWriter()
|
||||||
|
|
||||||
// Create test handler
|
// Create test handler
|
||||||
@@ -201,13 +202,13 @@ func TestRequireWorkspaceAccess(t *testing.T) {
|
|||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
setupContext func() *httpcontext.HandlerContext
|
setupContext func() *context.HandlerContext
|
||||||
wantStatusCode int
|
wantStatusCode int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "workspace owner access",
|
name: "workspace owner access",
|
||||||
setupContext: func() *httpcontext.HandlerContext {
|
setupContext: func() *context.HandlerContext {
|
||||||
return &httpcontext.HandlerContext{
|
return &context.HandlerContext{
|
||||||
UserID: 1,
|
UserID: 1,
|
||||||
UserRole: "editor",
|
UserRole: "editor",
|
||||||
Workspace: &models.Workspace{
|
Workspace: &models.Workspace{
|
||||||
@@ -220,8 +221,8 @@ func TestRequireWorkspaceAccess(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "admin access to other's workspace",
|
name: "admin access to other's workspace",
|
||||||
setupContext: func() *httpcontext.HandlerContext {
|
setupContext: func() *context.HandlerContext {
|
||||||
return &httpcontext.HandlerContext{
|
return &context.HandlerContext{
|
||||||
UserID: 2,
|
UserID: 2,
|
||||||
UserRole: "admin",
|
UserRole: "admin",
|
||||||
Workspace: &models.Workspace{
|
Workspace: &models.Workspace{
|
||||||
@@ -234,8 +235,8 @@ func TestRequireWorkspaceAccess(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "unauthorized access attempt",
|
name: "unauthorized access attempt",
|
||||||
setupContext: func() *httpcontext.HandlerContext {
|
setupContext: func() *context.HandlerContext {
|
||||||
return &httpcontext.HandlerContext{
|
return &context.HandlerContext{
|
||||||
UserID: 2,
|
UserID: 2,
|
||||||
UserRole: "editor",
|
UserRole: "editor",
|
||||||
Workspace: &models.Workspace{
|
Workspace: &models.Workspace{
|
||||||
@@ -248,8 +249,8 @@ func TestRequireWorkspaceAccess(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no workspace in context",
|
name: "no workspace in context",
|
||||||
setupContext: func() *httpcontext.HandlerContext {
|
setupContext: func() *context.HandlerContext {
|
||||||
return &httpcontext.HandlerContext{
|
return &context.HandlerContext{
|
||||||
UserID: 1,
|
UserID: 1,
|
||||||
UserRole: "editor",
|
UserRole: "editor",
|
||||||
Workspace: nil,
|
Workspace: nil,
|
||||||
@@ -262,8 +263,8 @@ func TestRequireWorkspaceAccess(t *testing.T) {
|
|||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
// Create request with context
|
// Create request with context
|
||||||
ctx := context.WithValue(context.Background(), httpcontext.HandlerContextKey, tc.setupContext())
|
req := httptest.NewRequest("GET", "/test", nil)
|
||||||
req := httptest.NewRequest("GET", "/test", nil).WithContext(ctx)
|
req = context.WithHandlerContext(req, tc.setupContext())
|
||||||
w := newMockResponseWriter()
|
w := newMockResponseWriter()
|
||||||
|
|
||||||
// Create test handler
|
// Create test handler
|
||||||
@@ -291,72 +292,3 @@ func TestRequireWorkspaceAccess(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetUserFromContext(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
setupCtx func() context.Context
|
|
||||||
wantUserID int
|
|
||||||
wantRole string
|
|
||||||
wantErr bool
|
|
||||||
errContains string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "valid user context",
|
|
||||||
setupCtx: func() context.Context {
|
|
||||||
return context.WithValue(context.Background(), auth.UserContextKey, auth.UserClaims{
|
|
||||||
UserID: 1,
|
|
||||||
Role: "admin",
|
|
||||||
})
|
|
||||||
},
|
|
||||||
wantUserID: 1,
|
|
||||||
wantRole: "admin",
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "missing user context",
|
|
||||||
setupCtx: func() context.Context {
|
|
||||||
return context.Background()
|
|
||||||
},
|
|
||||||
wantErr: true,
|
|
||||||
errContains: "no user found in context",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "invalid context value type",
|
|
||||||
setupCtx: func() context.Context {
|
|
||||||
return context.WithValue(context.Background(), auth.UserContextKey, "invalid")
|
|
||||||
},
|
|
||||||
wantErr: true,
|
|
||||||
errContains: "no user found in context",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
ctx := tc.setupCtx()
|
|
||||||
claims, err := auth.GetUserFromContext(ctx)
|
|
||||||
|
|
||||||
if tc.wantErr {
|
|
||||||
if err == nil {
|
|
||||||
t.Error("expected error, got nil")
|
|
||||||
} else if tc.errContains != "" && !strings.Contains(err.Error(), tc.errContains) {
|
|
||||||
t.Errorf("error = %v, want error containing %v", err, tc.errContains)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if claims.UserID != tc.wantUserID {
|
|
||||||
t.Errorf("UserID = %v, want %v", claims.UserID, tc.wantUserID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if claims.Role != tc.wantRole {
|
|
||||||
t.Errorf("Role = %v, want %v", claims.Role, tc.wantRole)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
62
server/internal/context/context.go
Normal file
62
server/internal/context/context.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Package context provides functions for managing request context
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"novamd/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type contextKey string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// HandlerContextKey is the key used to store handler context in the request context
|
||||||
|
HandlerContextKey contextKey = "handlerContext"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserClaims represents user information from authentication
|
||||||
|
type UserClaims struct {
|
||||||
|
UserID int
|
||||||
|
Role string
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerContext holds the request-specific data available to all handlers
|
||||||
|
type HandlerContext struct {
|
||||||
|
UserID int
|
||||||
|
UserRole string
|
||||||
|
Workspace *models.Workspace // Optional, only set for workspace routes
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRequestContext retrieves the handler context from the request
|
||||||
|
func GetRequestContext(w http.ResponseWriter, r *http.Request) (*HandlerContext, bool) {
|
||||||
|
ctx := r.Context().Value(HandlerContextKey)
|
||||||
|
if ctx == nil {
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return ctx.(*HandlerContext), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHandlerContext adds handler context to the request
|
||||||
|
func WithHandlerContext(r *http.Request, hctx *HandlerContext) *http.Request {
|
||||||
|
return r.WithContext(context.WithValue(r.Context(), HandlerContextKey, hctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserFromContext retrieves user claims from the context
|
||||||
|
func GetUserFromContext(ctx context.Context) (*UserClaims, error) {
|
||||||
|
val := ctx.Value(HandlerContextKey)
|
||||||
|
if val == nil {
|
||||||
|
return nil, fmt.Errorf("no user found in context")
|
||||||
|
}
|
||||||
|
|
||||||
|
hctx, ok := val.(*HandlerContext)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid context type")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &UserClaims{
|
||||||
|
UserID: hctx.UserID,
|
||||||
|
Role: hctx.UserRole,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -1,38 +1,37 @@
|
|||||||
package middleware
|
package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"novamd/internal/auth"
|
|
||||||
"novamd/internal/db"
|
"novamd/internal/db"
|
||||||
"novamd/internal/httpcontext"
|
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User ID and User Role context
|
// WithUserContextMiddleware extracts user information from JWT claims
|
||||||
func WithUserContext(next http.Handler) http.Handler {
|
// and adds it to the request context
|
||||||
|
func WithUserContextMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
claims, err := auth.GetUserFromContext(r.Context())
|
claims, err := GetUserFromContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hctx := &httpcontext.HandlerContext{
|
hctx := &HandlerContext{
|
||||||
UserID: claims.UserID,
|
UserID: claims.UserID,
|
||||||
UserRole: claims.Role,
|
UserRole: claims.Role,
|
||||||
}
|
}
|
||||||
|
|
||||||
r = httpcontext.WithHandlerContext(r, hctx)
|
r = WithHandlerContext(r, hctx)
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workspace context
|
// WithWorkspaceContextMiddleware adds workspace information to the request context
|
||||||
func WithWorkspaceContext(db db.Database) func(http.Handler) http.Handler {
|
func WithWorkspaceContextMiddleware(db db.Database) func(http.Handler) http.Handler {
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -46,7 +45,7 @@ func WithWorkspaceContext(db db.Database) func(http.Handler) http.Handler {
|
|||||||
|
|
||||||
// Update existing context with workspace
|
// Update existing context with workspace
|
||||||
ctx.Workspace = workspace
|
ctx.Workspace = workspace
|
||||||
r = httpcontext.WithHandlerContext(r, ctx)
|
r = WithHandlerContext(r, ctx)
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,8 @@ package handlers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"novamd/internal/context"
|
||||||
"novamd/internal/db"
|
"novamd/internal/db"
|
||||||
"novamd/internal/httpcontext"
|
|
||||||
"novamd/internal/models"
|
"novamd/internal/models"
|
||||||
"novamd/internal/storage"
|
"novamd/internal/storage"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -172,7 +172,7 @@ func (h *Handler) AdminUpdateUser() http.HandlerFunc {
|
|||||||
// AdminDeleteUser deletes a specific user
|
// AdminDeleteUser deletes a specific user
|
||||||
func (h *Handler) AdminDeleteUser() http.HandlerFunc {
|
func (h *Handler) AdminDeleteUser() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"novamd/internal/auth"
|
"novamd/internal/auth"
|
||||||
"novamd/internal/httpcontext"
|
"novamd/internal/context"
|
||||||
"novamd/internal/models"
|
"novamd/internal/models"
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
@@ -129,7 +129,7 @@ func (h *Handler) RefreshToken(authService *auth.SessionService) http.HandlerFun
|
|||||||
// GetCurrentUser returns the currently authenticated user
|
// GetCurrentUser returns the currently authenticated user
|
||||||
func (h *Handler) GetCurrentUser() http.HandlerFunc {
|
func (h *Handler) GetCurrentUser() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"novamd/internal/httpcontext"
|
"novamd/internal/context"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) ListFiles() http.HandlerFunc {
|
func (h *Handler) ListFiles() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ func (h *Handler) ListFiles() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) LookupFileByName() http.HandlerFunc {
|
func (h *Handler) LookupFileByName() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ func (h *Handler) LookupFileByName() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) GetFileContent() http.HandlerFunc {
|
func (h *Handler) GetFileContent() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ func (h *Handler) GetFileContent() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) SaveFile() http.HandlerFunc {
|
func (h *Handler) SaveFile() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ func (h *Handler) SaveFile() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) DeleteFile() http.HandlerFunc {
|
func (h *Handler) DeleteFile() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ func (h *Handler) DeleteFile() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) GetLastOpenedFile() http.HandlerFunc {
|
func (h *Handler) GetLastOpenedFile() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ func (h *Handler) GetLastOpenedFile() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) UpdateLastOpenedFile() http.HandlerFunc {
|
func (h *Handler) UpdateLastOpenedFile() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"novamd/internal/httpcontext"
|
"novamd/internal/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) StageCommitAndPush() http.HandlerFunc {
|
func (h *Handler) StageCommitAndPush() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ func (h *Handler) StageCommitAndPush() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) PullChanges() http.HandlerFunc {
|
func (h *Handler) PullChanges() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"novamd/internal/httpcontext"
|
"novamd/internal/context"
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
@@ -22,7 +22,7 @@ type DeleteAccountRequest struct {
|
|||||||
|
|
||||||
func (h *Handler) GetUser() http.HandlerFunc {
|
func (h *Handler) GetUser() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ func (h *Handler) GetUser() http.HandlerFunc {
|
|||||||
// UpdateProfile updates the current user's profile
|
// UpdateProfile updates the current user's profile
|
||||||
func (h *Handler) UpdateProfile() http.HandlerFunc {
|
func (h *Handler) UpdateProfile() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ func (h *Handler) UpdateProfile() http.HandlerFunc {
|
|||||||
// DeleteAccount handles user account deletion
|
// DeleteAccount handles user account deletion
|
||||||
func (h *Handler) DeleteAccount() http.HandlerFunc {
|
func (h *Handler) DeleteAccount() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"novamd/internal/httpcontext"
|
"novamd/internal/context"
|
||||||
"novamd/internal/models"
|
"novamd/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) ListWorkspaces() http.HandlerFunc {
|
func (h *Handler) ListWorkspaces() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ func (h *Handler) ListWorkspaces() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) CreateWorkspace() http.HandlerFunc {
|
func (h *Handler) CreateWorkspace() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ func (h *Handler) CreateWorkspace() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) GetWorkspace() http.HandlerFunc {
|
func (h *Handler) GetWorkspace() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ func gitSettingsChanged(new, old *models.Workspace) bool {
|
|||||||
|
|
||||||
func (h *Handler) UpdateWorkspace() http.HandlerFunc {
|
func (h *Handler) UpdateWorkspace() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ func (h *Handler) UpdateWorkspace() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) DeleteWorkspace() http.HandlerFunc {
|
func (h *Handler) DeleteWorkspace() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -197,7 +197,7 @@ func (h *Handler) DeleteWorkspace() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) GetLastWorkspaceName() http.HandlerFunc {
|
func (h *Handler) GetLastWorkspaceName() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -214,7 +214,7 @@ func (h *Handler) GetLastWorkspaceName() http.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) UpdateLastWorkspaceName() http.HandlerFunc {
|
func (h *Handler) UpdateLastWorkspaceName() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := context.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
package httpcontext
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"novamd/internal/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandlerContext holds the request-specific data available to all handlers
|
|
||||||
type HandlerContext struct {
|
|
||||||
UserID int
|
|
||||||
UserRole string
|
|
||||||
Workspace *models.Workspace
|
|
||||||
}
|
|
||||||
|
|
||||||
type contextKey string
|
|
||||||
|
|
||||||
const HandlerContextKey contextKey = "handlerContext"
|
|
||||||
|
|
||||||
func GetRequestContext(w http.ResponseWriter, r *http.Request) (*HandlerContext, bool) {
|
|
||||||
ctx := r.Context().Value(HandlerContextKey)
|
|
||||||
if ctx == nil {
|
|
||||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
return ctx.(*HandlerContext), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithHandlerContext(r *http.Request, hctx *HandlerContext) *http.Request {
|
|
||||||
return r.WithContext(context.WithValue(r.Context(), HandlerContextKey, hctx))
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user