Skip to content

Commit

Permalink
Begining support for flexible cards in Urchin
Browse files Browse the repository at this point in the history
  • Loading branch information
matheusgomes28 committed Dec 18, 2024
1 parent d915e1c commit da40c88
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 2 deletions.
9 changes: 9 additions & 0 deletions admin-app/admin_requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ type AddImageRequest struct {
Alt string `json:"alt"`
}

// TODO : Does this still need to be here?
// TODO : Are we handling images apart from file adds?
type DeleteImageBinding struct {
Name string `uri:"name" binding:"required"`
}

type AddCardRequest struct {
Title string `json:"title"`
Image string `json:"image"`
Schema string `json:"schema"`
Content string `json:"content"`
}
4 changes: 4 additions & 0 deletions admin-app/admin_responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ type PostIdResponse struct {
Id int `json:"id"`
}

type CardIdResponse struct {
Id string `json:"id"`
}

type GetPostResponse struct {
Id int `json:"id"`
Title string `json:"title"`
Expand Down
2 changes: 1 addition & 1 deletion admin-app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func SetupRoutes(app_settings common.AppSettings, database database.Database) *g
r.MaxMultipartMemory = 1

r.GET("/posts/:id", getPostHandler(database))
r.POST("/posts", postPostHandler(database))
r.POST("/posts", postCardHandler(database))
r.PUT("/posts", putPostHandler(database))
r.DELETE("/posts/:id", deletePostHandler(database))

Expand Down
55 changes: 55 additions & 0 deletions admin-app/card.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package admin_app

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

"github.com/gin-gonic/gin"
"github.com/matheusgomes28/urchin/common"
"github.com/matheusgomes28/urchin/database"
"github.com/rs/zerolog/log"
)

func postCardHandler(database database.Database) func(*gin.Context) {
return func(c *gin.Context) {
var add_card_request AddCardRequest
if c.Request.Body == nil {
c.JSON(http.StatusBadRequest, common.MsgErrorRes("no request body provided"))
return
}
decoder := json.NewDecoder(c.Request.Body)
err := decoder.Decode(&add_card_request)

if err != nil {
log.Warn().Msgf("invalid post request: %v", err)
c.JSON(http.StatusBadRequest, common.ErrorRes("invalid request body", err))
return
}

// TODO : Sanity checks that everything inside the
// TODO : request makes sense. I.e. content is json,
// TODO : i.e json content matches the schema, etc.
// err = checkRequiredData(add_card_request)
// if err != nil {
// log.Error().Msgf("failed to add post required data is missing: %v", err)
// c.JSON(http.StatusBadRequest, common.ErrorRes("missing required data", err))
// return
// }

id, err := database.AddCard(
add_card_request.Title,
add_card_request.Image,
add_card_request.Schema,
add_card_request.Content,
)
if err != nil {
log.Error().Msgf("failed to add card: %v", err)
c.JSON(http.StatusBadRequest, common.ErrorRes("could not add post", err))
return
}

c.JSON(http.StatusOK, CardIdResponse{
id,
})
}
}
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func SetupRoutes(app_settings common.AppSettings, database database.Database) *g
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", "/product", productHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/about", aboutHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/services", servicesHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/post/:id", postHandler, &cache, app_settings, database)
Expand Down
12 changes: 12 additions & 0 deletions app/product.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app

import (
"github.com/gin-gonic/gin"
"github.com/matheusgomes28/urchin/common"
"github.com/matheusgomes28/urchin/database"
"github.com/matheusgomes28/urchin/views"
)

func productHandler(c *gin.Context, app_settings common.AppSettings, db database.Database) ([]byte, error) {
return renderHtml(c, views.MakeProductPage(app_settings.AppNavbar.Links))
}
9 changes: 9 additions & 0 deletions common/card.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package common

type Card struct {
Id string `json:"id"`
Title string `json:"title"`
Image string `json:"image"`
Schema string `json:"schema"`
Content string `json:"content"`
}
24 changes: 24 additions & 0 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"time"

"github.com/google/uuid"
"github.com/matheusgomes28/urchin/common"
"github.com/rs/zerolog/log"
)
Expand All @@ -18,6 +19,7 @@ type Database interface {
DeletePost(id int) (int, error)
AddPage(title string, content string, link string) (int, error)
GetPage(link string) (common.Page, error)
AddCard(title string, image string, schema string, content string) (string, error)
}

type SqlDatabase struct {
Expand Down Expand Up @@ -179,6 +181,28 @@ func (db SqlDatabase) GetPage(link string) (common.Page, error) {
return page, nil
}

// / This function adds the card metadata to the cards table.
// / Returns the uuid as a string if successful, otherwise error
// / won't be null
func (db SqlDatabase) AddCard(title string, image string, schema string, content string) (string, error) {

// TODO : Generate a uuid
uuid := uuid.New().String()

_, err := db.Connection.Exec("INSERT INTO cards(uuid, image_location, json_data, json_schema) VALUES(?, ?, ?, ?)", uuid, image, content, schema)
if err != nil {
return "", err
}

return common.Card{
Id: uuid,
Title: title,
Image: image,
Schema: schema,
Content: content,
}, nil
}

func MakeSqlConnection(user string, password string, address string, port int, database string) (SqlDatabase, error) {

/// TODO : let user specify the DB
Expand Down
2 changes: 1 addition & 1 deletion docker/.air.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ tmp_dir = "tmp"
follow_symlink = false
include_dir = []
include_ext = ["go", "tpl", "tmpl", "templ", "html"]
include_file = []
include_file = ["urchin_config.toml", "docker/urchin_config.toml"]
kill_delay = "0s"
log = "build-errors.log"
poll = false
Expand Down
2 changes: 2 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ services:
mariadb:
image: mariadb:11.2.3-jammy
container_name: mariadb
ports:
- "3336:3306"
env_file:
- ../.dev.env
healthcheck:
Expand Down
1 change: 1 addition & 0 deletions docker/urchin_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ links = [
{ name = "About", href = "/about", title = "About page" },
{ name = "Services", href = "/services", title = "Services page" },
{ name = "Images", href = "/images", title = "Images page" },
{ name = "Products", href = "/Products", title = "Product cards page" },
{ name = "Contact", href = "/contact", title = "Contacts page" },
]
14 changes: 14 additions & 0 deletions migrations/20241218210123_add_cards_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- +goose Up
-- +goose StatementBegin
CREATE TABLE cards (
uuid VARCHAR(36) DEFAULT(UUID()) PRIMARY KEY,
image_location TEXT NOT NULL,
json_data TEXT NOT NULL,
json_schema TEXT NOT NULL
);
-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
DROP TABLE cards;
-- +goose StatementEnd
1 change: 1 addition & 0 deletions urchin_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ links = [
{ name = "Services", href = "/services", title = "Services page" },
{ name = "Images", href = "/images", title = "Images page" },
{ name = "Contact", href = "/contact", title = "Contacts page" },
{ name = "Products", href = "/Products", title = "Product cards page"},
]
62 changes: 62 additions & 0 deletions views/product.templ
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package views

import "github.com/matheusgomes28/urchin/common"

templ makeCard(title string, slogan string) {
<a href="#" class="relative block rounded-tr-3xl border border-gray-100">
<span
class="absolute -right-px -top-px rounded-bl-3xl rounded-tr-3xl bg-gray-700 px-6 py-4 font-medium uppercase tracking-widest text-white"
>
{slogan}
</span>

<!-- TODO : Take the image as param -->
<img
src="https://images.unsplash.com/photo-1485955900006-10f4d324d411?q=80&w=2672&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt=""
class="h-80 w-full rounded-tr-3xl object-cover"
/>

<div class="p-4 text-center">
<strong class="text-xl font-medium text-gray-900 dark:text-gray-100"> {title} </strong>

<p class="mt-2 text-pretty text-gray-700 dark:text-gray-100">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet officia rem vel voluptatum in
eum vitae aliquid at sed dignissimos.
</p>

<span
class="mt-4 block rounded-md border border-indigo-900 bg-indigo-900 px-5 py-3 text-sm font-medium uppercase tracking-widest text-white transition-colors dark:text-gray-100 hover:bg-white hover:text-indigo-900"
>
Learn More
</span>
</div>
</a>
}

templ makeCardGrid() {
<div class="grid grid-cols-3 gap-4 content-center justify-center items-center">
<div class="max-w-sm">
@makeCard("Card One", "Save 10%")
</div>
<div class="max-w-sm">
@makeCard("Card One", "Save 10%")
</div>
<div class="max-w-sm">
@makeCard("Card One", "Save 10%")
</div>
<div class="max-w-sm">
@makeCard("Card One", "Save 10%")
</div>
<div class="max-w-sm">
@makeCard("Card One", "Save 10%")
</div>
</div>
}

templ MakeProductPage(links []common.Link) {
@MakeLayout("Product Page", links, makeCardGrid())

// TODO : for each product coming from the database
// TODO : we're going to create a card for it
}

0 comments on commit da40c88

Please sign in to comment.