From 8a62c9e306ec0cb64b536f659370d1f0e833b97e Mon Sep 17 00:00:00 2001 From: LordMathis Date: Sun, 8 Dec 2024 17:47:44 +0100 Subject: [PATCH] Regenerate docs --- server/documentation.md | 602 ++++++++++++++++++++++++++++------------ 1 file changed, 432 insertions(+), 170 deletions(-) diff --git a/server/documentation.md b/server/documentation.md index 76e9edb..a738170 100644 --- a/server/documentation.md +++ b/server/documentation.md @@ -5,9 +5,9 @@ Generated documentation for all packages in the NovaMD project. ## Table of Contents - [cmd/server](#cmd-server) +- [docs](#docs) - [internal/app](#internal-app) - [internal/auth](#internal-auth) -- [internal/config](#internal-config) - [internal/context](#internal-context) - [internal/db](#internal-db) - [internal/git](#internal-git) @@ -23,6 +23,31 @@ Package main provides the entry point for the application. It loads the configuration, initializes the server, and starts the server. ``` +## docs + +```go +package docs // import "novamd/docs" + +Package docs Code generated by swaggo/swag. DO NOT EDIT + +VARIABLES + +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "", + BasePath: "/api/v1", + Schemes: []string{}, + Title: "NovaMD API", + Description: "This is the API for NovaMD markdown note taking app.", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + SwaggerInfo holds exported Swagger Info so clients can modify it + +``` + ## internal/app ```go @@ -31,124 +56,6 @@ package app // import "novamd/internal/app" Package app provides application-level functionality for initializing and running the server -FUNCTIONS - -func SetupRoutes(r chi.Router, db db.Database, s storage.Manager, authMiddleware *auth.Middleware, sessionService *auth.SessionService) - SetupRoutes configures the API routes - - -TYPES - -type Server struct { - // Has unexported fields. -} - Server represents the HTTP server and its dependencies - -func NewServer(cfg *config.Config) (*Server, error) - NewServer initializes a new server instance with all dependencies - -func (s *Server) Close() error - Close handles graceful shutdown of server dependencies - -func (s *Server) Start() error - Start configures and starts the HTTP server - -``` - -## internal/auth - -```go -package auth // import "novamd/internal/auth" - -Package auth provides JWT token generation and validation - -TYPES - -type Claims struct { - jwt.RegisteredClaims // Embedded standard JWT claims - UserID int `json:"uid"` // User identifier - Role string `json:"role"` // User role (admin, editor, viewer) - Type TokenType `json:"type"` // Token type (access or refresh) -} - Claims represents the custom claims we store in JWT tokens - -type JWTConfig struct { - SigningKey string // Secret key used to sign tokens - AccessTokenExpiry time.Duration // How long access tokens are valid - RefreshTokenExpiry time.Duration // How long refresh tokens are valid -} - JWTConfig holds the configuration for the JWT service - -type JWTManager interface { - GenerateAccessToken(userID int, role string) (string, error) - GenerateRefreshToken(userID int, role string) (string, error) - ValidateToken(tokenString string) (*Claims, error) - RefreshAccessToken(refreshToken string) (string, error) -} - JWTManager defines the interface for managing JWT tokens - -func NewJWTService(config JWTConfig) (JWTManager, error) - NewJWTService creates a new JWT service with the provided configuration - Returns an error if the signing key is missing - -type Middleware struct { - // Has unexported fields. -} - Middleware handles JWT authentication for protected routes - -func NewMiddleware(jwtManager JWTManager) *Middleware - NewMiddleware creates a new authentication middleware - -func (m *Middleware) Authenticate(next http.Handler) http.Handler - Authenticate middleware validates JWT tokens and sets user information in - context - -func (m *Middleware) RequireRole(role string) func(http.Handler) http.Handler - RequireRole returns a middleware that ensures the user has the required role - -func (m *Middleware) RequireWorkspaceAccess(next http.Handler) http.Handler - RequireWorkspaceAccess returns a middleware that ensures the user has access - to the workspace - -type SessionService struct { - // Has unexported fields. -} - SessionService manages user sessions in the database - -func NewSessionService(db db.SessionStore, jwtManager JWTManager) *SessionService - NewSessionService creates a new session service with the given database and - JWT manager - -func (s *SessionService) CleanExpiredSessions() error - CleanExpiredSessions removes all expired sessions from the database - -func (s *SessionService) CreateSession(userID int, role string) (*models.Session, string, error) - CreateSession creates a new user session for a user with the given userID - and role - -func (s *SessionService) InvalidateSession(sessionID string) error - InvalidateSession removes a session with the given sessionID from the - database - -func (s *SessionService) RefreshSession(refreshToken string) (string, error) - RefreshSession creates a new access token using a refreshToken - -type TokenType string - TokenType represents the type of JWT token (access or refresh) - -const ( - AccessToken TokenType = "access" // AccessToken - Short-lived token for API access - RefreshToken TokenType = "refresh" // RefreshToken - Long-lived token for obtaining new access tokens -) -``` - -## internal/config - -```go -package config // import "novamd/internal/config" - -Package config provides the configuration for the application - TYPES type Config struct { @@ -156,7 +63,8 @@ type Config struct { WorkDir string StaticPath string Port string - AppURL string + RootURL string + Domain string CORSOrigins []string AdminEmail string AdminPassword string @@ -171,12 +79,132 @@ type Config struct { func DefaultConfig() *Config DefaultConfig returns a new Config instance with default values -func Load() (*Config, error) - Load creates a new Config instance with values from environment variables +func LoadConfig() (*Config, error) + LoadConfig creates a new Config instance with values from environment + variables -func (c *Config) Validate() error - Validate checks if the configuration is valid +type Options struct { + Config *Config + Database db.Database + Storage storage.Manager + JWTManager auth.JWTManager + SessionManager auth.SessionManager + CookieService auth.CookieManager +} + Options holds all dependencies and configuration for the server +func DefaultOptions(cfg *Config) (*Options, error) + DefaultOptions creates server options with default configuration + +type Server struct { + // Has unexported fields. +} + Server represents the HTTP server and its dependencies + +func NewServer(options *Options) *Server + NewServer creates a new server instance with the given options + +func (s *Server) Close() error + Close handles graceful shutdown of server dependencies + +func (s *Server) Router() chi.Router + Router returns the chi router for testing + +func (s *Server) Start() error + Start configures and starts the HTTP server + +``` + +## internal/auth + +```go +package auth // import "novamd/internal/auth" + +Package auth provides JWT token generation and validation + +Package auth provides JWT token generation and validation + +FUNCTIONS + +func NewSessionService(db db.SessionStore, jwtManager JWTManager) *sessionManager + NewSessionService creates a new session service with the given database and + JWT manager revive:disable:unexported-return + + +TYPES + +type Claims struct { + jwt.RegisteredClaims // Embedded standard JWT claims + UserID int `json:"uid"` // User identifier + Role string `json:"role"` // User role (admin, editor, viewer) + Type TokenType `json:"type"` // Token type (access or refresh) +} + Claims represents the custom claims we store in JWT tokens + +type CookieManager interface { + GenerateAccessTokenCookie(token string) *http.Cookie + GenerateRefreshTokenCookie(token string) *http.Cookie + GenerateCSRFCookie(token string) *http.Cookie + InvalidateCookie(cookieType string) *http.Cookie +} + CookieManager interface defines methods for generating cookies + +func NewCookieService(isDevelopment bool, domain string) CookieManager + NewCookieService creates a new cookie service + +type JWTConfig struct { + SigningKey string // Secret key used to sign tokens + AccessTokenExpiry time.Duration // How long access tokens are valid + RefreshTokenExpiry time.Duration // How long refresh tokens are valid +} + JWTConfig holds the configuration for the JWT service + +type JWTManager interface { + GenerateAccessToken(userID int, role string, sessionID string) (string, error) + GenerateRefreshToken(userID int, role string, sessionID string) (string, error) + ValidateToken(tokenString string) (*Claims, error) +} + JWTManager defines the interface for managing JWT tokens + +func NewJWTService(config JWTConfig) (JWTManager, error) + NewJWTService creates a new JWT service with the provided configuration + Returns an error if the signing key is missing + +type Middleware struct { + // Has unexported fields. +} + Middleware handles JWT authentication for protected routes + +func NewMiddleware(jwtManager JWTManager, sessionManager SessionManager, cookieManager CookieManager) *Middleware + NewMiddleware creates a new authentication middleware + +func (m *Middleware) Authenticate(next http.Handler) http.Handler + Authenticate middleware validates JWT tokens and sets user information in + context + +func (m *Middleware) RequireRole(role string) func(http.Handler) http.Handler + RequireRole returns a middleware that ensures the user has the required role + +func (m *Middleware) RequireWorkspaceAccess(next http.Handler) http.Handler + RequireWorkspaceAccess returns a middleware that ensures the user has access + to the workspace + +type SessionManager interface { + CreateSession(userID int, role string) (*models.Session, string, error) + RefreshSession(refreshToken string) (string, error) + ValidateSession(sessionID string) (*models.Session, error) + InvalidateSession(token string) error + CleanExpiredSessions() error +} + SessionManager is an interface for managing user sessions + +type TokenType string + TokenType represents the type of JWT token (access or refresh) + +const ( + AccessToken TokenType = "access" // AccessToken - Short-lived token for API access + RefreshToken TokenType = "refresh" // RefreshToken - Long-lived token for obtaining new access tokens +) ``` ## internal/context @@ -271,6 +299,7 @@ type Migration struct { type SessionStore interface { CreateSession(session *models.Session) error GetSessionByRefreshToken(refreshToken string) (*models.Session, error) + GetSessionByID(sessionID string) (*models.Session, error) DeleteSession(sessionID string) error CleanExpiredSessions() error } @@ -350,7 +379,7 @@ TYPES type Client interface { Clone() error Pull() error - Commit(message string) error + Commit(message string) (CommitHash, error) Push() error EnsureRepo() error } @@ -359,6 +388,12 @@ type Client interface { func New(url, username, token, workDir, commitName, commitEmail string) Client New creates a new git Client instance +type CommitHash plumbing.Hash + CommitHash represents a Git commit hash + +func (h CommitHash) String() string + String returns the string representation of the CommitHash + type Config struct { URL string Username string @@ -380,6 +415,16 @@ Package handlers contains the request handlers for the api routes. TYPES +type CommitRequest struct { + Message string `json:"message" example:"Initial commit"` +} + CommitRequest represents a request to commit changes + +type CommitResponse struct { + CommitHash string `json:"commitHash" example:"a1b2c3d4"` +} + CommitResponse represents a response to a commit request + type CreateUserRequest struct { Email string `json:"email"` DisplayName string `json:"displayName"` @@ -393,6 +438,17 @@ type DeleteAccountRequest struct { } DeleteAccountRequest represents a user account deletion request +type DeleteWorkspaceResponse struct { + NextWorkspaceName string `json:"nextWorkspaceName"` +} + DeleteWorkspaceResponse contains the name of the next workspace after + deleting the current one + +type ErrorResponse struct { + Message string `json:"message"` +} + ErrorResponse is a generic error response + type Handler struct { DB db.Database Storage storage.Manager @@ -403,92 +459,286 @@ func NewHandler(db db.Database, s storage.Manager) *Handler NewHandler creates a new handler with the given dependencies func (h *Handler) AdminCreateUser() http.HandlerFunc - AdminCreateUser creates a new user + AdminCreateUser godoc @Summary Create a new user @Description Create a + new user as an admin @Tags Admin @Security CookieAuth @ID adminCreateUser + @Accept json @Produce json @Param user body CreateUserRequest true + "User details" @Success 200 {object} models.User @Failure 400 {object} + ErrorResponse "Invalid request body" @Failure 400 {object} ErrorResponse + "Email, password, and role are required" @Failure 400 {object} ErrorResponse + "Password must be at least 8 characters" @Failure 409 {object} ErrorResponse + "Email already exists" @Failure 500 {object} ErrorResponse "Failed to + hash password" @Failure 500 {object} ErrorResponse "Failed to create user" + @Failure 500 {object} ErrorResponse "Failed to initialize user workspace" + @Router /admin/users [post] func (h *Handler) AdminDeleteUser() http.HandlerFunc - AdminDeleteUser deletes a specific user + AdminDeleteUser godoc @Summary Delete a specific user @Description + Delete a specific user as an admin @Tags Admin @Security CookieAuth @ID + adminDeleteUser @Param userId path int true "User ID" @Success 204 "No + Content" @Failure 400 {object} ErrorResponse "Invalid user ID" @Failure + 400 {object} ErrorResponse "Cannot delete your own account" @Failure 403 + {object} ErrorResponse "Cannot delete other admin users" @Failure 404 + {object} ErrorResponse "User not found" @Failure 500 {object} ErrorResponse + "Failed to delete user" @Router /admin/users/{userId} [delete] func (h *Handler) AdminGetSystemStats() http.HandlerFunc - AdminGetSystemStats returns system-wide statistics for admins + AdminGetSystemStats godoc @Summary Get system statistics @Description Get + system-wide statistics as an admin @Tags Admin @Security CookieAuth @ID + adminGetSystemStats @Produce json @Success 200 {object} SystemStats @Failure + 500 {object} ErrorResponse "Failed to get user stats" @Failure 500 {object} + ErrorResponse "Failed to get file stats" @Router /admin/stats [get] func (h *Handler) AdminGetUser() http.HandlerFunc - AdminGetUser gets a specific user by ID + AdminGetUser godoc @Summary Get a specific user @Description Get a specific + user as an admin @Tags Admin @Security CookieAuth @ID adminGetUser @Produce + json @Param userId path int true "User ID" @Success 200 {object} models.User + @Failure 400 {object} ErrorResponse "Invalid user ID" @Failure 404 {object} + ErrorResponse "User not found" @Router /admin/users/{userId} [get] func (h *Handler) AdminListUsers() http.HandlerFunc - AdminListUsers returns a list of all users + AdminListUsers godoc @Summary List all users @Description Returns the list + of all users @Tags Admin @Security CookieAuth @ID adminListUsers @Produce + json @Success 200 {array} models.User @Failure 500 {object} ErrorResponse + "Failed to list users" @Router /admin/users [get] func (h *Handler) AdminListWorkspaces() http.HandlerFunc - AdminListWorkspaces returns a list of all workspaces and their stats + AdminListWorkspaces godoc @Summary List all workspaces @Description List + all workspaces and their stats as an admin @Tags Admin @Security CookieAuth + @ID adminListWorkspaces @Produce json @Success 200 {array} WorkspaceStats + @Failure 500 {object} ErrorResponse "Failed to list workspaces" @Failure + 500 {object} ErrorResponse "Failed to get user" @Failure 500 {object} + ErrorResponse "Failed to get file stats" @Router /admin/workspaces [get] func (h *Handler) AdminUpdateUser() http.HandlerFunc - AdminUpdateUser updates a specific user + AdminUpdateUser godoc @Summary Update a specific user @Description + Update a specific user as an admin @Tags Admin @Security CookieAuth @ID + adminUpdateUser @Accept json @Produce json @Param userId path int true + "User ID" @Param user body UpdateUserRequest true "User details" @Success + 200 {object} models.User @Failure 400 {object} ErrorResponse "Invalid user + ID" @Failure 400 {object} ErrorResponse "Invalid request body" @Failure 404 + {object} ErrorResponse "User not found" @Failure 500 {object} ErrorResponse + "Failed to hash password" @Failure 500 {object} ErrorResponse "Failed to + update user" @Router /admin/users/{userId} [put] func (h *Handler) CreateWorkspace() http.HandlerFunc - CreateWorkspace creates a new workspace + CreateWorkspace godoc @Summary Create workspace @Description Creates a new + workspace @Tags workspaces @ID createWorkspace @Security CookieAuth @Accept + json @Produce json @Param body body models.Workspace true "Workspace" + @Success 200 {object} models.Workspace @Failure 400 {object} ErrorResponse + "Invalid request body" @Failure 400 {object} ErrorResponse "Invalid + workspace" @Failure 500 {object} ErrorResponse "Failed to create workspace" + @Failure 500 {object} ErrorResponse "Failed to initialize workspace + directory" @Failure 500 {object} ErrorResponse "Failed to setup git repo" + @Router /workspaces [post] func (h *Handler) DeleteAccount() http.HandlerFunc - DeleteAccount handles user account deletion + DeleteAccount godoc @Summary Delete account @Description Deletes the user's + account and all associated data @Tags users @ID deleteAccount @Security + CookieAuth @Accept json @Produce json @Param body body DeleteAccountRequest + true "Account deletion request" @Success 204 "No Content - Account deleted + successfully" @Failure 400 {object} ErrorResponse "Invalid request body" + @Failure 401 {object} ErrorResponse "Password is incorrect" @Failure 403 + {object} ErrorResponse "Cannot delete the last admin account" @Failure 404 + {object} ErrorResponse "User not found" @Failure 500 {object} ErrorResponse + "Failed to verify admin status" @Failure 500 {object} ErrorResponse "Failed + to delete account" @Router /profile [delete] func (h *Handler) DeleteFile() http.HandlerFunc - DeleteFile deletes a file + DeleteFile godoc @Summary Delete file @Description Deletes a file in + the user's workspace @Tags files @ID deleteFile @Security CookieAuth + @Param workspace_name path string true "Workspace name" @Param + file_path path string true "File path" @Success 204 "No Content + - File deleted successfully" @Failure 400 {object} ErrorResponse + "Invalid file path" @Failure 404 {object} ErrorResponse "File not + found" @Failure 500 {object} ErrorResponse "Failed to delete file" + @Failure 500 {object} ErrorResponse "Failed to write response" @Router + /workspaces/{workspace_name}/files/{file_path} [delete] func (h *Handler) DeleteWorkspace() http.HandlerFunc - DeleteWorkspace deletes the current workspace + DeleteWorkspace godoc @Summary Delete workspace @Description Deletes + the current workspace @Tags workspaces @ID deleteWorkspace @Security + CookieAuth @Produce json @Param workspace_name path string true "Workspace + name" @Success 200 {object} DeleteWorkspaceResponse @Failure 400 {object} + ErrorResponse "Cannot delete the last workspace" @Failure 500 {object} + ErrorResponse "Failed to get workspaces" @Failure 500 {object} ErrorResponse + "Failed to start transaction" @Failure 500 {object} ErrorResponse "Failed + to update last workspace" @Failure 500 {object} ErrorResponse "Failed to + delete workspace" @Failure 500 {object} ErrorResponse "Failed to rollback + transaction" @Failure 500 {object} ErrorResponse "Failed to commit + transaction" @Router /workspaces/{workspace_name} [delete] func (h *Handler) GetCurrentUser() http.HandlerFunc - GetCurrentUser returns the currently authenticated user + GetCurrentUser godoc @Summary Get current user @Description Returns + the current authenticated user @Tags auth @ID getCurrentUser @Security + CookieAuth @Produce json @Success 200 {object} models.User @Failure 404 + {object} ErrorResponse "User not found" @Router /auth/me [get] func (h *Handler) GetFileContent() http.HandlerFunc - GetFileContent returns the content of a file + GetFileContent godoc @Summary Get file content @Description Returns the + content of a file in the user's workspace @Tags files @ID getFileContent + @Security CookieAuth @Produce plain @Param workspace_name path string + true "Workspace name" @Param file_path path string true "File path" + @Success 200 {string} string "Raw file content" @Failure 400 {object} + ErrorResponse "Invalid file path" @Failure 404 {object} ErrorResponse + "File not found" @Failure 500 {object} ErrorResponse "Failed to read file" + @Failure 500 {object} ErrorResponse "Failed to write response" @Router + /workspaces/{workspace_name}/files/{file_path} [get] func (h *Handler) GetLastOpenedFile() http.HandlerFunc - GetLastOpenedFile returns the last opened file in the workspace + GetLastOpenedFile godoc @Summary Get last opened file @Description + Returns the path of the last opened file in the user's workspace @Tags + files @ID getLastOpenedFile @Security CookieAuth @Produce json @Param + workspace_name path string true "Workspace name" @Success 200 {object} + LastOpenedFileResponse @Failure 400 {object} ErrorResponse "Invalid file + path" @Failure 500 {object} ErrorResponse "Failed to get last opened file" + @Router /workspaces/{workspace_name}/files/last [get] func (h *Handler) GetLastWorkspaceName() http.HandlerFunc - GetLastWorkspaceName returns the name of the last opened workspace + GetLastWorkspaceName godoc @Summary Get last workspace name @Description + Returns the name of the last opened workspace @Tags workspaces @ID + getLastWorkspaceName @Security CookieAuth @Produce json @Success 200 + {object} LastWorkspaceNameResponse @Failure 500 {object} ErrorResponse + "Failed to get last workspace" @Router /workspaces/last [get] func (h *Handler) GetWorkspace() http.HandlerFunc - GetWorkspace returns the current workspace + GetWorkspace godoc @Summary Get workspace @Description Returns the current + workspace @Tags workspaces @ID getWorkspace @Security CookieAuth @Produce + json @Param workspace_name path string true "Workspace name" @Success 200 + {object} models.Workspace @Failure 500 {object} ErrorResponse "Internal + server error" @Router /workspaces/{workspace_name} [get] func (h *Handler) ListFiles() http.HandlerFunc - ListFiles returns a list of all files in the workspace + ListFiles godoc @Summary List files @Description Lists all files in the + user's workspace @Tags files @ID listFiles @Security CookieAuth @Produce + json @Param workspace_name path string true "Workspace name" @Success 200 + {array} storage.FileNode @Failure 500 {object} ErrorResponse "Failed to list + files" @Router /workspaces/{workspace_name}/files [get] func (h *Handler) ListWorkspaces() http.HandlerFunc - ListWorkspaces returns a list of all workspaces for the current user + ListWorkspaces godoc @Summary List workspaces @Description Lists all + workspaces for the current user @Tags workspaces @ID listWorkspaces + @Security CookieAuth @Produce json @Success 200 {array} models.Workspace + @Failure 500 {object} ErrorResponse "Failed to list workspaces" @Router + /workspaces [get] -func (h *Handler) Login(authService *auth.SessionService) http.HandlerFunc - Login handles user authentication and returns JWT tokens +func (h *Handler) Login(authManager auth.SessionManager, cookieService auth.CookieManager) http.HandlerFunc + Login godoc @Summary Login @Description Logs in a user and returns a + session with access and refresh tokens @Tags auth @Accept json @Produce + json @Param body body LoginRequest true "Login request" @Success 200 + {object} LoginResponse @Header 200 {string} X-CSRF-Token "CSRF token for + future requests" @Failure 400 {object} ErrorResponse "Invalid request + body" @Failure 400 {object} ErrorResponse "Email and password are required" + @Failure 401 {object} ErrorResponse "Invalid credentials" @Failure 500 + {object} ErrorResponse "Failed to create session" @Failure 500 {object} + ErrorResponse "Failed to generate CSRF token" @Router /auth/login [post] -func (h *Handler) Logout(authService *auth.SessionService) http.HandlerFunc - Logout invalidates the user's session +func (h *Handler) Logout(authManager auth.SessionManager, cookieService auth.CookieManager) http.HandlerFunc + Logout godoc @Summary Logout @Description Log out invalidates the user's + session @Tags auth @ID logout @Success 204 "No Content" @Failure 400 + {object} ErrorResponse "Session ID required" @Failure 500 {object} + ErrorResponse "Failed to logout" @Router /auth/logout [post] func (h *Handler) LookupFileByName() http.HandlerFunc - LookupFileByName returns the paths of files with the given name + LookupFileByName godoc @Summary Lookup file by name @Description Returns the + paths of files with the given name in the user's workspace @Tags files @ID + lookupFileByName @Security CookieAuth @Produce json @Param workspace_name + path string true "Workspace name" @Param filename query string true + "File name" @Success 200 {object} LookupResponse @Failure 400 {object} + ErrorResponse "Filename is required" @Failure 404 {object} ErrorResponse + "File not found" @Router /workspaces/{workspace_name}/files/lookup [get] func (h *Handler) PullChanges() http.HandlerFunc - PullChanges pulls changes from the remote repository + PullChanges godoc @Summary Pull changes from remote @Description Pulls + changes from the remote repository @Tags git @ID pullChanges @Security + CookieAuth @Produce json @Param workspace_name path string true "Workspace + name" @Success 200 {object} PullResponse @Failure 500 {object} ErrorResponse + "Failed to pull changes" @Router /workspaces/{workspace_name}/git/pull + [post] -func (h *Handler) RefreshToken(authService *auth.SessionService) http.HandlerFunc - RefreshToken generates a new access token using a refresh token +func (h *Handler) RefreshToken(authManager auth.SessionManager, cookieService auth.CookieManager) http.HandlerFunc + RefreshToken godoc @Summary Refresh token @Description Refreshes the access + token using the refresh token @Tags auth @ID refreshToken @Accept json + @Produce json @Success 200 @Header 200 {string} X-CSRF-Token "New CSRF + token" @Failure 400 {object} ErrorResponse "Refresh token required" @Failure + 401 {object} ErrorResponse "Invalid refresh token" @Failure 500 {object} + ErrorResponse "Failed to generate CSRF token" @Router /auth/refresh [post] func (h *Handler) SaveFile() http.HandlerFunc - SaveFile saves the content of a file + SaveFile godoc @Summary Save file @Description Saves the content of a file + in the user's workspace @Tags files @ID saveFile @Security CookieAuth + @Accept plain @Produce json @Param workspace_name path string true + "Workspace name" @Param file_path path string true "File path" @Success + 200 {object} SaveFileResponse @Failure 400 {object} ErrorResponse "Failed + to read request body" @Failure 400 {object} ErrorResponse "Invalid file + path" @Failure 500 {object} ErrorResponse "Failed to save file" @Router + /workspaces/{workspace_name}/files/{file_path} [post] func (h *Handler) StageCommitAndPush() http.HandlerFunc - StageCommitAndPush stages, commits, and pushes changes to the remote - repository + StageCommitAndPush godoc @Summary Stage, commit, and push changes + @Description Stages, commits, and pushes changes to the remote repository + @Tags git @ID stageCommitAndPush @Security CookieAuth @Produce json + @Param workspace_name path string true "Workspace name" @Param body body + CommitRequest true "Commit request" @Success 200 {object} CommitResponse + @Failure 400 {object} ErrorResponse "Invalid request body" @Failure + 400 {object} ErrorResponse "Commit message is required" @Failure 500 + {object} ErrorResponse "Failed to stage, commit, and push changes" @Router + /workspaces/{workspace_name}/git/commit [post] func (h *Handler) UpdateLastOpenedFile() http.HandlerFunc - UpdateLastOpenedFile updates the last opened file in the workspace + UpdateLastOpenedFile godoc @Summary Update last opened file @Description + Updates the last opened file in the user's workspace @Tags files @ID + updateLastOpenedFile @Security CookieAuth @Accept json @Produce json + @Param workspace_name path string true "Workspace name" @Param body + body UpdateLastOpenedFileRequest true "Update last opened file request" + @Success 204 "No Content - Last opened file updated successfully" @Failure + 400 {object} ErrorResponse "Invalid request body" @Failure 400 {object} + ErrorResponse "Invalid file path" @Failure 404 {object} ErrorResponse "File + not found" @Failure 500 {object} ErrorResponse "Failed to update file" + @Router /workspaces/{workspace_name}/files/last [put] func (h *Handler) UpdateLastWorkspaceName() http.HandlerFunc - UpdateLastWorkspaceName updates the name of the last opened workspace + UpdateLastWorkspaceName godoc @Summary Update last workspace name + @Description Updates the name of the last opened workspace @Tags workspaces + @ID updateLastWorkspaceName @Security CookieAuth @Accept json @Produce json + @Success 204 "No Content - Last workspace updated successfully" @Failure + 400 {object} ErrorResponse "Invalid request body" @Failure 500 {object} + ErrorResponse "Failed to update last workspace" @Router /workspaces/last + [put] func (h *Handler) UpdateProfile() http.HandlerFunc - UpdateProfile updates the current user's profile + UpdateProfile godoc @Summary Update profile @Description Updates the + user's profile @Tags users @ID updateProfile @Security CookieAuth @Accept + json @Produce json @Param body body UpdateProfileRequest true "Profile + update request" @Success 200 {object} models.User @Failure 400 {object} + ErrorResponse "Invalid request body" @Failure 400 {object} ErrorResponse + "Current password is required to change password" @Failure 400 {object} + ErrorResponse "New password must be at least 8 characters long" @Failure + 400 {object} ErrorResponse "Current password is required to change email" + @Failure 401 {object} ErrorResponse "Current password is incorrect" + @Failure 404 {object} ErrorResponse "User not found" @Failure 409 {object} + ErrorResponse "Email already in use" @Failure 500 {object} ErrorResponse + "Failed to process new password" @Failure 500 {object} ErrorResponse "Failed + to update profile" @Router /profile [put] func (h *Handler) UpdateWorkspace() http.HandlerFunc - UpdateWorkspace updates the current workspace + UpdateWorkspace godoc @Summary Update workspace @Description Updates + the current workspace @Tags workspaces @ID updateWorkspace @Security + CookieAuth @Accept json @Produce json @Param workspace_name path string + true "Workspace name" @Param body body models.Workspace true "Workspace" + @Success 200 {object} models.Workspace @Failure 400 {object} ErrorResponse + "Invalid request body" @Failure 500 {object} ErrorResponse "Failed to update + workspace" @Failure 500 {object} ErrorResponse "Failed to setup git repo" + @Router /workspaces/{workspace_name} [put] + +type LastOpenedFileResponse struct { + LastOpenedFilePath string `json:"lastOpenedFilePath"` +} + LastOpenedFileResponse represents a response to a last opened file request + +type LastWorkspaceNameResponse struct { + LastWorkspaceName string `json:"lastWorkspaceName"` +} + LastWorkspaceNameResponse contains the name of the last opened workspace type LoginRequest struct { Email string `json:"email"` @@ -497,22 +747,28 @@ type LoginRequest struct { LoginRequest represents a user login request type LoginResponse struct { - AccessToken string `json:"accessToken"` - RefreshToken string `json:"refreshToken"` - User *models.User `json:"user"` - Session *models.Session `json:"session"` + User *models.User `json:"user"` + SessionID string `json:"sessionId,omitempty"` + ExpiresAt time.Time `json:"expiresAt,omitempty"` } LoginResponse represents a user login response -type RefreshRequest struct { - RefreshToken string `json:"refreshToken"` +type LookupResponse struct { + Paths []string `json:"paths"` } - RefreshRequest represents a refresh token request + LookupResponse represents a response to a file lookup request -type RefreshResponse struct { - AccessToken string `json:"accessToken"` +type PullResponse struct { + Message string `json:"message" example:"Pulled changes from remote"` } - RefreshResponse represents a refresh token response + PullResponse represents a response to a pull http request + +type SaveFileResponse struct { + FilePath string `json:"filePath"` + Size int64 `json:"size"` + UpdatedAt time.Time `json:"updatedAt"` +} + SaveFileResponse represents a response to a save file request type StaticHandler struct { // Has unexported fields. @@ -532,6 +788,12 @@ type SystemStats struct { } SystemStats holds system-wide statistics +type UpdateLastOpenedFileRequest struct { + FilePath string `json:"filePath"` +} + UpdateLastOpenedFileRequest represents a request to update the last opened + file + type UpdateProfileRequest struct { DisplayName string `json:"displayName"` Email string `json:"email"` @@ -733,7 +995,7 @@ func (e *PathValidationError) Error() string type RepositoryManager interface { SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToken, commitName, commitEmail string) error DisableGitRepo(userID, workspaceID int) - StageCommitAndPush(userID, workspaceID int, message string) error + StageCommitAndPush(userID, workspaceID int, message string) (git.CommitHash, error) Pull(userID, workspaceID int) error } RepositoryManager defines the interface for managing Git repositories. @@ -809,7 +1071,7 @@ func (s *Service) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToke The repository is cloned from the given gitURL using the given gitUser and gitToken. -func (s *Service) StageCommitAndPush(userID, workspaceID int, message string) error +func (s *Service) StageCommitAndPush(userID, workspaceID int, message string) (git.CommitHash, error) StageCommitAndPush stages, commit with the message, and pushes the changes to the Git repository. The git repository belongs to the given userID and is associated with the given workspaceID.