Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
AlDu2407 authored Mar 17, 2024
2 parents fe40c13 + 9efb940 commit 8cdef66
Show file tree
Hide file tree
Showing 11 changed files with 292 additions and 123 deletions.
2 changes: 1 addition & 1 deletion admin-app/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func postPostHandler(database database.Database) func(*gin.Context) {
err := decoder.Decode(&add_post_request)

if err != nil {
log.Warn().Msgf("could not get post from DB: %v", err)
log.Warn().Msgf("invalid post request: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "invalid request body",
"msg": err.Error(),
Expand Down
30 changes: 26 additions & 4 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package app
import (
"bytes"
"net/http"
"strconv"
"time"

"github.com/gin-gonic/gin"
Expand All @@ -21,11 +22,14 @@ func SetupRoutes(app_settings common.AppSettings, database database.Database) *g
r.MaxMultipartMemory = 1

// All cache-able endpoints
cache := makeCache(4, time.Minute*10)
cache := MakeCache(4, time.Minute*10, &TimeValidator{})
addCachableHandler(r, "GET", "/", homeHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/contact", contactHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/post/:id", postHandler, &cache, app_settings, database)

// Add the pagination route as a cacheable endpoint
addCachableHandler(r, "GET", "/page/:num", homeHandler, &cache, app_settings, database)

// DO not cache as it needs to handlenew form values
r.POST("/contact-send", makeContactFormHandler())

Expand All @@ -39,14 +43,20 @@ func addCachableHandler(e *gin.Engine, method string, endpoint string, generator
// if the endpoint is cached
cached_endpoint, err := (*cache).Get(c.Request.RequestURI)
if err == nil {
c.Data(http.StatusOK, "text/html; charset=utf-8", cached_endpoint.contents)
c.Data(http.StatusOK, "text/html; charset=utf-8", cached_endpoint.Contents)
return
}

// Before handler call (retrieve from cache)
html_buffer, err := generator(c, app_settings, db)
if err != nil {
log.Error().Msgf("could not generate html: %v", err)
// TODO : Need a proper error page
c.JSON(http.StatusInternalServerError, gin.H{
"error": "could not render HTML",
"msg": err.Error(),
})
return
}

// After handler (add to cache)
Expand Down Expand Up @@ -75,7 +85,19 @@ func addCachableHandler(e *gin.Engine, method string, endpoint string, generator
// / This function will act as the handler for
// / the home page
func homeHandler(c *gin.Context, settings common.AppSettings, db database.Database) ([]byte, error) {
posts, err := db.GetPosts()
pageNum := 0 // Default to page 0
if pageNumQuery := c.Param("num"); pageNumQuery != "" {
num, err := strconv.Atoi(pageNumQuery)
if err == nil && num > 0 {
pageNum = num
} else {
log.Error().Msgf("Invalid page number: %s", pageNumQuery)
}
}
limit := 10 // or whatever limit you want
offset := max((pageNum-1)*limit, 0)

posts, err := db.GetPosts(limit, offset)
if err != nil {
return nil, err
}
Expand All @@ -86,7 +108,7 @@ func homeHandler(c *gin.Context, settings common.AppSettings, db database.Databa

err = index_view.Render(c, html_buffer)
if err != nil {
log.Error().Msgf("could not render index: %v", err)
log.Error().Msgf("Could not render index: %v", err)
return []byte{}, err
}

Expand Down
18 changes: 9 additions & 9 deletions app/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
const MAX_CACHE_SIZE_MB = 10

type EndpointCache struct {
name string
contents []byte
validUntil time.Time
Name string
Contents []byte
ValidUntil time.Time
}

func emptyEndpointCache() EndpointCache {
Expand All @@ -36,7 +36,7 @@ type TimeValidator struct{}

func (validator *TimeValidator) IsValid(cache *EndpointCache) bool {
// We only return the cache if it's still valid
return cache.validUntil.After(time.Now())
return cache.ValidUntil.After(time.Now())
}

type TimedCache struct {
Expand All @@ -54,9 +54,9 @@ func (cache *TimedCache) Store(name string, buffer []byte) error {
}

var cache_entry interface{} = EndpointCache{
name: name,
contents: buffer,
validUntil: time.Now().Add(cache.cacheTimeout),
Name: name,
Contents: buffer,
ValidUntil: time.Now().Add(cache.cacheTimeout),
}
cache.cacheMap.Set(name, &cache_entry)
cache.estimatedSize.Add(uint64(len(buffer)))
Expand Down Expand Up @@ -85,11 +85,11 @@ func (cache *TimedCache) Size() uint64 {
return cache.estimatedSize.Load()
}

func makeCache(n_shards int, expiry_duration time.Duration) Cache {
func MakeCache(n_shards int, expiry_duration time.Duration, validator CacheValidator) Cache {
return &TimedCache{
cacheMap: shardedmap.NewShardMap(n_shards),
cacheTimeout: expiry_duration,
estimatedSize: atomic.Uint64{},
validator: &TimeValidator{},
validator: validator,
}
}
68 changes: 0 additions & 68 deletions cmd/urchin/index_test.go

This file was deleted.

13 changes: 9 additions & 4 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

type Database interface {
GetPosts() ([]common.Post, error)
GetPosts(int, int) ([]common.Post, error)
GetPost(post_id int) (common.Post, error)
AddPost(title string, excerpt string, content string) (int, error)
ChangePost(id int, title string, excerpt string, content string) error
Expand All @@ -28,8 +28,9 @@ type SqlDatabase struct {

// / This function gets all the posts from the current
// / database connection.
func (db SqlDatabase) GetPosts() (all_posts []common.Post, err error) {
rows, err := db.Connection.Query("SELECT title, excerpt, id FROM posts;")
func (db SqlDatabase) GetPosts(limit int, offset int) (all_posts []common.Post, err error) {
query := "SELECT title, excerpt, id FROM posts LIMIT ? OFFSET ?;"
rows, err := db.Connection.Query(query, limit, offset)
if err != nil {
return make([]common.Post, 0), err
}
Expand Down Expand Up @@ -174,13 +175,17 @@ func (db SqlDatabase) AddImage(uuid string, name string, alt string) (err error)
}

func MakeSqlConnection(user string, password string, address string, port int, database string) (SqlDatabase, error) {
/// Checking the DB connection

/// TODO : let user specify the DB
connection_str := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", user, password, address, port, database)
db, err := sql.Open("mysql", connection_str)
if err != nil {
return SqlDatabase{}, err
}

if err := db.Ping(); err != nil {
return SqlDatabase{}, err
}
// See "Important settings" section.
db.SetConnMaxLifetime(time.Second * 5)
db.SetMaxOpenConns(10)
Expand Down
68 changes: 68 additions & 0 deletions tests/admin_app_tests/endpoint_tests/endpoint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package endpoint_tests

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

admin_app "github.com/matheusgomes28/urchin/admin-app"
"github.com/matheusgomes28/urchin/common"
"github.com/matheusgomes28/urchin/tests/mocks"
"github.com/stretchr/testify/assert"
)

type postRequest struct {
Title string `json:"title"`
Excerpt string `json:"excerpt"`
Content string `json:"content"`
}

type postResponse struct {
Id int `json:"id"`
}

var app_settings = common.AppSettings{
DatabaseAddress: "localhost",
DatabasePort: 3006,
DatabaseUser: "root",
DatabasePassword: "root",
DatabaseName: "urchin",
WebserverPort: 8080,
}

func TestIndexPing(t *testing.T) {

database_mock := mocks.DatabaseMock{}
r := admin_app.SetupRoutes(app_settings, database_mock)
w := httptest.NewRecorder()

request := postRequest{
Title: "",
Excerpt: "",
Content: "",
}
request_body, err := json.Marshal(request)
assert.Nil(t, err)

req, _ := http.NewRequest("POST", "/posts", bytes.NewReader(request_body))
req.Header.Add("content-type", "application/json")
r.ServeHTTP(w, req)

assert.Equal(t, 200, w.Code)

var response postResponse
err = json.Unmarshal(w.Body.Bytes(), &response)
assert.Nil(t, err)

assert.Equal(t, response.Id, 0)
}

// TODO : Test request without excerpt

// TODO : Test request without content

// TODO : Test request without title

// TODO : Test request that fails to be added to database
Loading

0 comments on commit 8cdef66

Please sign in to comment.