Skip to content

Commit

Permalink
Merge pull request #2479 from aliraza556/feature/implement-snippet-ma…
Browse files Browse the repository at this point in the history
…nagement

feat: implement snippet management endpoints and db functions
  • Loading branch information
humansinstitute authored Jan 22, 2025
2 parents 327e548 + ab7fa3d commit c026b25
Show file tree
Hide file tree
Showing 8 changed files with 1,159 additions and 1 deletion.
5 changes: 5 additions & 0 deletions db/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,9 @@ type Database interface {
CreateWorkspaceDraftTicket(ticket *Tickets) (Tickets, error)
UpdateWorkspaceDraftTicket(ticket *Tickets) (Tickets, error)
DeleteWorkspaceDraftTicket(workspaceUuid string, uuid string) error
CreateSnippet(snippet *TextSnippet) (*TextSnippet, error)
GetSnippetsByWorkspace(workspaceUUID string) ([]TextSnippet, error)
GetSnippetByID(id uint) (*TextSnippet, error)
UpdateSnippet(snippet *TextSnippet) (*TextSnippet, error)
DeleteSnippet(id uint) error
}
83 changes: 83 additions & 0 deletions db/snippets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package db

import (
"errors"
"fmt"
"time"

"gorm.io/gorm"
)

func (db database) CreateSnippet(snippet *TextSnippet) (*TextSnippet, error) {
if snippet.WorkspaceUUID == "" {
return nil, errors.New("workspace UUID is required")
}

if snippet.Title == "" {
return nil, errors.New("title is required")
}

if snippet.Snippet == "" {
return nil, errors.New("snippet content is required")
}

now := time.Now()
snippet.DateCreated = now
snippet.LastEdited = now

if err := db.db.Create(snippet).Error; err != nil {
return nil, fmt.Errorf("failed to create snippet: %w", err)
}

return snippet, nil
}

func (db database) GetSnippetsByWorkspace(workspaceUUID string) ([]TextSnippet, error) {
var snippets []TextSnippet

if err := db.db.Where("workspace_uuid = ?", workspaceUUID).Find(&snippets).Error; err != nil {
return nil, fmt.Errorf("failed to fetch snippets: %w", err)
}

return snippets, nil
}

func (db database) GetSnippetByID(id uint) (*TextSnippet, error) {
var snippet TextSnippet

if err := db.db.First(&snippet, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("record not found")
}
return nil, fmt.Errorf("failed to fetch snippet: %w", err)
}

return &snippet, nil
}

func (db database) UpdateSnippet(snippet *TextSnippet) (*TextSnippet, error) {
if snippet.ID == 0 {
return nil, errors.New("snippet ID is required")
}

snippet.LastEdited = time.Now()

if err := db.db.Model(&TextSnippet{}).Where("id = ?", snippet.ID).Updates(snippet).Error; err != nil {
return nil, fmt.Errorf("failed to update snippet: %w", err)
}

return db.GetSnippetByID(snippet.ID)
}

func (db database) DeleteSnippet(id uint) error {
result := db.db.Delete(&TextSnippet{}, id)
if result.Error != nil {
return fmt.Errorf("failed to delete snippet: %w", result.Error)
}

if result.RowsAffected == 0 {
return errors.New("snippet not found")
}

return nil
}
3 changes: 3 additions & 0 deletions db/test_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func InitTestDB() {
db.AutoMigrate(&Bounty{})
db.AutoMigrate(&Notification{})
db.AutoMigrate(&BountyTiming{})
db.AutoMigrate(&TextSnippet{})

people := TestDB.GetAllPeople()
for _, p := range people {
Expand Down Expand Up @@ -113,6 +114,8 @@ func CleanTestData() {
TestDB.db.Exec("DELETE FROM chats")

TestDB.db.Exec("DELETE FROM notifications")

TestDB.db.Exec("DELETE FROM text_snippets")
}

func DeleteAllChatMessages() {
Expand Down
216 changes: 216 additions & 0 deletions handlers/snippet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package handlers

import (
"encoding/json"
"fmt"
"net/http"

"github.com/go-chi/chi"
"github.com/stakwork/sphinx-tribes/auth"
"github.com/stakwork/sphinx-tribes/db"
"github.com/stakwork/sphinx-tribes/logger"
"github.com/stakwork/sphinx-tribes/utils"
)

type snippetHandler struct {
httpClient HttpClient
db db.Database
}

func NewSnippetHandler(httpClient HttpClient, db db.Database) *snippetHandler {
return &snippetHandler{
httpClient: httpClient,
db: db,
}
}

type SnippetRequest struct {
Title string `json:"title"`
Snippet string `json:"snippet"`
}

func (sh *snippetHandler) CreateSnippet(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
pubKeyFromAuth, _ := ctx.Value(auth.ContextKey).(string)

if pubKeyFromAuth == "" {
logger.Log.Info("[snippet] no pubkey from auth")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{"error": "Unauthorized"})
return
}

workspaceUUID := r.URL.Query().Get("workspace_uuid")
if workspaceUUID == "" {
http.Error(w, "workspace_uuid is required", http.StatusBadRequest)
return
}

var req SnippetRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}

if req.Title == "" || req.Snippet == "" {
http.Error(w, "Title and snippet are required", http.StatusBadRequest)
return
}

snippet := &db.TextSnippet{
WorkspaceUUID: workspaceUUID,
Title: req.Title,
Snippet: req.Snippet,
}

createdSnippet, err := sh.db.CreateSnippet(snippet)
if err != nil {
logger.Log.Error(fmt.Sprintf("Failed to create snippet: %v", err))
http.Error(w, "Failed to create snippet", http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(createdSnippet)
}

func (sh *snippetHandler) GetSnippetsByWorkspace(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
pubKeyFromAuth, _ := ctx.Value(auth.ContextKey).(string)

if pubKeyFromAuth == "" {
logger.Log.Info("[snippet] no pubkey from auth")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{"error": "Unauthorized"})
return
}

workspaceUUID := chi.URLParam(r, "workspace_uuid")
if workspaceUUID == "" {
http.Error(w, "workspace_uuid is required", http.StatusBadRequest)
return
}

snippets, err := sh.db.GetSnippetsByWorkspace(workspaceUUID)
if err != nil {
logger.Log.Error(fmt.Sprintf("Failed to fetch snippets: %v", err))
http.Error(w, "Failed to fetch snippets", http.StatusInternalServerError)
return
}

json.NewEncoder(w).Encode(snippets)
}

func (sh *snippetHandler) GetSnippetByID(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
pubKeyFromAuth, _ := ctx.Value(auth.ContextKey).(string)

if pubKeyFromAuth == "" {
logger.Log.Info("[snippet] no pubkey from auth")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{"error": "Unauthorized"})
return
}

idStr := chi.URLParam(r, "id")
id, err := utils.ConvertStringToUint(idStr)
if err != nil {
http.Error(w, "Invalid snippet ID", http.StatusBadRequest)
return
}

snippet, err := sh.db.GetSnippetByID(id)
if err != nil {
if err.Error() == "record not found" {
http.Error(w, "Snippet not found", http.StatusNotFound)
return
}
logger.Log.Error(fmt.Sprintf("Failed to fetch snippet: %v", err))
http.Error(w, "Failed to fetch snippet", http.StatusInternalServerError)
return
}

json.NewEncoder(w).Encode(snippet)
}

func (sh *snippetHandler) UpdateSnippet(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
pubKeyFromAuth, _ := ctx.Value(auth.ContextKey).(string)

if pubKeyFromAuth == "" {
logger.Log.Info("[snippet] no pubkey from auth")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{"error": "Unauthorized"})
return
}

idStr := chi.URLParam(r, "id")
id, err := utils.ConvertStringToUint(idStr)
if err != nil {
http.Error(w, "Invalid snippet ID", http.StatusBadRequest)
return
}

var req SnippetRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}

if req.Title == "" || req.Snippet == "" {
http.Error(w, "Title and snippet are required", http.StatusBadRequest)
return
}

snippet := &db.TextSnippet{
ID: id,
Title: req.Title,
Snippet: req.Snippet,
}

updatedSnippet, err := sh.db.UpdateSnippet(snippet)
if err != nil {
if err.Error() == "record not found" {
http.Error(w, "Snippet not found", http.StatusNotFound)
return
}
logger.Log.Error(fmt.Sprintf("Failed to update snippet: %v", err))
http.Error(w, "Failed to update snippet", http.StatusInternalServerError)
return
}

json.NewEncoder(w).Encode(updatedSnippet)
}

func (sh *snippetHandler) DeleteSnippet(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
pubKeyFromAuth, _ := ctx.Value(auth.ContextKey).(string)

if pubKeyFromAuth == "" {
logger.Log.Info("[snippet] no pubkey from auth")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{"error": "Unauthorized"})
return
}

idStr := chi.URLParam(r, "id")
id, err := utils.ConvertStringToUint(idStr)
if err != nil {
http.Error(w, "Invalid snippet ID", http.StatusBadRequest)
return
}

err = sh.db.DeleteSnippet(id)
if err != nil {
if err.Error() == "snippet not found" {
http.Error(w, "Snippet not found", http.StatusNotFound)
return
}
logger.Log.Error(fmt.Sprintf("Failed to delete snippet: %v", err))
http.Error(w, "Failed to delete snippet", http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"message": "Snippet deleted successfully"})
}
Loading

0 comments on commit c026b25

Please sign in to comment.