Skip to content

Commit

Permalink
feat: Add new API notebook
Browse files Browse the repository at this point in the history
  • Loading branch information
jeff authored and jeff committed Jan 2, 2025
1 parent fbc25c6 commit ab1bf32
Show file tree
Hide file tree
Showing 6 changed files with 394 additions and 0 deletions.
4 changes: 4 additions & 0 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type NFContext struct {
SBIPort int

SpyFamilyData map[string]string
NoteData map[string]string
}

var nfContext = NFContext{}
Expand Down Expand Up @@ -57,6 +58,9 @@ func InitNfContext() {
"Henry": "Henderson",
"Martha": "Marriott",
}
nfContext.NoteData = map[string]string{
"User_Guide": "/<Title>/ Show the content of the note with title <Title>.\n",
}
}

func GetSelf() *NFContext {
Expand Down
102 changes: 102 additions & 0 deletions internal/sbi/api_notebook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package sbi

import (
"net/http"

"github.com/andy89923/nf-example/internal/logger"
"github.com/gin-gonic/gin"
)

func (s *Server) getNotebookRoute() []Route {
return []Route{
{
Name: "Show Note",
Method: http.MethodGet,
Pattern: "/:Title",
APIFunc: s.HTTPShowNote,
// Use
// curl -X GET http://127.0.0.163:8000/spyfamily/ -w "\n"
},
{
Name: "Create Note",
Method: http.MethodPut,
Pattern: "/:Title/:Content",
APIFunc: s.HTTPCreateNote,
// Use
// curl -X GET http://127.0.0.163:8000/spyfamily/Anya -w "\n"
// "Character: Anya Forger"
},
{
Name: "Update Note",
Method: http.MethodPost,
Pattern: "/:Title/:Content",
APIFunc: s.HTTPUpdateNote,
// Use
// curl -X GET http://127.0.0.163:8000/spyfamily/Anya -w "\n"
// "Character: Anya Forger"
},
{
Name: "Note Append with whitespace at front.",
Method: http.MethodPost,
Pattern: "/:Title/append/:Content_append",
APIFunc: s.HTTPNoteWhitespaceAppend,
// Use
// curl -X GET http://127.0.0.163:8000/spyfamily/Anya -w "\n"
// "Character: Anya Forger"
},
}
}

func (s *Server) HTTPShowNote(c *gin.Context) {
logger.SBILog.Infof("In HTTPShowNote")

targetName := c.Param("Title")
if targetName == "" {
c.String(http.StatusBadRequest, "No name provided")
return
}

s.Processor().FindNote(c, targetName)
}

func (s *Server) HTTPUpdateNote(c *gin.Context) {
logger.SBILog.Infof("In HTTPUpdateNote")

targetName := c.Param("Title")
if targetName == "" {
c.String(http.StatusBadRequest, "No name provided")
return
}

newContent := c.Param("Content")

s.Processor().UpdateNote(c, targetName, newContent)
}

func (s *Server) HTTPCreateNote(c *gin.Context) {
logger.SBILog.Infof("In HTTPCreateNote")

targetName := c.Param("Title")
if targetName == "" {
c.String(http.StatusBadRequest, "No name provided")
return
}

newContent := c.Param("Content")

s.Processor().CreateNote(c, targetName, newContent)
}

func (s *Server) HTTPNoteWhitespaceAppend(c *gin.Context) {
logger.SBILog.Infof("In HTTPNoteAppend")

targetName := c.Param("Title")
if targetName == "" {
c.String(http.StatusBadRequest, "No name provided")
return
}

newContent := c.Param("Content_append")

s.Processor().NoteWhitespaceAppend(c, targetName, newContent)
}
102 changes: 102 additions & 0 deletions internal/sbi/api_notebook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package sbi_test

import (
"net/http"
"net/http/httptest"
"testing"

"github.com/andy89923/nf-example/internal/sbi"
"github.com/andy89923/nf-example/pkg/factory"
"github.com/gin-gonic/gin"
"go.uber.org/mock/gomock"
)

func Test_getNotebookRoutes(t *testing.T) {
gin.SetMode(gin.TestMode)

mockCtrl := gomock.NewController(t)
nfApp := sbi.NewMocknfApp(mockCtrl)
nfApp.EXPECT().Config().Return(&factory.Config{
Configuration: &factory.Configuration{
Sbi: &factory.Sbi{
Port: 8000,
},
},
}).AnyTimes()
server := sbi.NewServer(nfApp, "")

t.Run("No name provided", func(t *testing.T) {
const EXPECTED_STATUS = http.StatusBadRequest
const EXPECTED_BODY = "No name provided"

httpRecorder := httptest.NewRecorder()
ginCtx, _ := gin.CreateTestContext(httpRecorder)

var err error
ginCtx.Request, err = http.NewRequest("GET", "/notebook/", nil)
if err != nil {
t.Errorf("Failed to create request: %s", err)
return
}

server.HTTPShowNote(ginCtx)

if httpRecorder.Code != EXPECTED_STATUS {
t.Errorf("Expected status code %d, got %d", EXPECTED_STATUS, httpRecorder.Code)
}

if httpRecorder.Body.String() != EXPECTED_BODY {
t.Errorf("Expected body %s, got %s", EXPECTED_BODY, httpRecorder.Body.String())
}
})

t.Run("No name provided", func(t *testing.T) {
const EXPECTED_STATUS = http.StatusBadRequest
const EXPECTED_BODY = "No name provided"

httpRecorder := httptest.NewRecorder()
ginCtx, _ := gin.CreateTestContext(httpRecorder)

var err error
ginCtx.Request, err = http.NewRequest("POST", "/notebook/", nil)
if err != nil {
t.Errorf("Failed to create request: %s", err)
return
}

server.HTTPUpdateNote(ginCtx)

if httpRecorder.Code != EXPECTED_STATUS {
t.Errorf("Expected status code %d, got %d", EXPECTED_STATUS, httpRecorder.Code)
}

if httpRecorder.Body.String() != EXPECTED_BODY {
t.Errorf("Expected body %s, got %s", EXPECTED_BODY, httpRecorder.Body.String())
}
})

t.Run("No name provided", func(t *testing.T) {
const EXPECTED_STATUS = http.StatusBadRequest
const EXPECTED_BODY = "No name provided"

httpRecorder := httptest.NewRecorder()
ginCtx, _ := gin.CreateTestContext(httpRecorder)

var err error
ginCtx.Request, err = http.NewRequest("POST", "/notebook//append/", nil)
if err != nil {
t.Errorf("Failed to create request: %s", err)
return
}

server.HTTPUpdateNote(ginCtx)

if httpRecorder.Code != EXPECTED_STATUS {
t.Errorf("Expected status code %d, got %d", EXPECTED_STATUS, httpRecorder.Code)
}

if httpRecorder.Body.String() != EXPECTED_BODY {
t.Errorf("Expected body %s, got %s", EXPECTED_BODY, httpRecorder.Body.String())
}
})
}
58 changes: 58 additions & 0 deletions internal/sbi/processor/notebook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package processor

import (
"fmt"
"net/http"
"strings"

"github.com/gin-gonic/gin"
)

func (p *Processor) FindNote(c *gin.Context, targetName string) {
if content, ok := p.Context().NoteData[targetName]; ok {
c.String(http.StatusOK, fmt.Sprintf("Title: %s\nContent:\n\t%s\n", targetName, content))
return
}
c.String(http.StatusNotFound, fmt.Sprintf("[%s] not found in Notebook\n", targetName))
}

func (p *Processor) UpdateNote(c *gin.Context, targetName string, newContent string) {
p.Context().NoteData[targetName] = newContent

if content, ok := p.Context().NoteData[targetName]; ok {
c.String(http.StatusOK, fmt.Sprintf("Title: %s\nContent:\n\t%s\n", targetName, content))
return
}
c.String(http.StatusNotFound, fmt.Sprintf("[%s] not found in Notebook\n", targetName))
}

func (p *Processor) CreateNote(c *gin.Context, targetName string, newContent string) {
if _, ok := p.Context().NoteData[targetName]; !ok {
p.Context().NoteData[targetName] = newContent

content := p.Context().NoteData[targetName]
c.String(http.StatusOK, fmt.Sprintf("Title: %s\nContent:\n\t%s\n", targetName, content))
return
} else if ok {
c.String(http.StatusForbidden, fmt.Sprintf(
"[%s] already exist. Please use POST to modify the content.\n",
targetName),
)
}
}

func (p *Processor) NoteWhitespaceAppend(c *gin.Context, targetName string, newContent string) {
if _, ok := p.Context().NoteData[targetName]; ok {
var sb strings.Builder
sb.WriteString(p.Context().NoteData[targetName])
sb.WriteString(" ")
sb.WriteString(newContent)

p.Context().NoteData[targetName] = sb.String()

content := p.Context().NoteData[targetName]
c.String(http.StatusOK, fmt.Sprintf("Title: %s\nContent:\n\t%s\n", targetName, content))
return
}
c.String(http.StatusNotFound, fmt.Sprintf("[%s] not found in Notebook\n", targetName))
}
Loading

0 comments on commit ab1bf32

Please sign in to comment.