Started working on V2 rework
|
@ -1,5 +0,0 @@
|
|||
dev
|
||||
.gitignore
|
||||
LICENSE
|
||||
README.md
|
||||
dist/main.db
|
12
.env.example
|
@ -9,15 +9,3 @@ DOMAIN_BASE=http://localhost:8080
|
|||
CACHE_MAP_LIMIT=15
|
||||
# Maximum API call requests to the API, this will ban the api for 5 minutes after requesting more than API_RATE_LIMIT in 5 minutes.
|
||||
API_BAN_LIMIT=300
|
||||
|
||||
# Optional database driver, you can just ignore and use sqlite
|
||||
# ! Warning: Sqlite not implemented yet
|
||||
DATABASE_DRIVER=mariadb
|
||||
|
||||
# Mysql database connetion details, fill these in if you chose mysql above.
|
||||
MYSQL_ROOT_PASSWORD=example-dev
|
||||
MYSQL_DATABASE=freepad
|
||||
MYSQL_USER=freepad
|
||||
MYSQL_PASSWORD=example-dev
|
||||
MYSQL_URL=mariadb
|
||||
MYSQL_PORT=3306
|
|
@ -2,7 +2,3 @@ dev/*
|
|||
!dev/.keep
|
||||
.env
|
||||
docker-compose.yaml
|
||||
# Ignore the database file
|
||||
dist/main.db
|
||||
dist/freepad
|
||||
dist/freepad
|
||||
|
|
15
Dockerfile
|
@ -1,15 +0,0 @@
|
|||
FROM alpine
|
||||
|
||||
LABEL version="1.5.1"
|
||||
|
||||
# Copy the distribution files
|
||||
COPY ./dist /app
|
||||
|
||||
# Make /app the work directory
|
||||
WORKDIR /app
|
||||
|
||||
# Expose the listening port
|
||||
EXPOSE 8080
|
||||
|
||||
# Run the program
|
||||
ENTRYPOINT ["./freepad"]
|
|
@ -8,7 +8,7 @@ Quickly create "pads" and share with others
|
|||
[![demo](https://img.shields.io/badge/Demo-Check%20out%20the%20functionality-orange)](https://pad.justkato.me/)
|
||||
![MariaDB](https://img.shields.io/badge/MariaDB-003545?style=for-the-badge&logo=mariadb&logoColor=white)
|
||||
|
||||
# **FreePad**
|
||||
# **FreePad V2**
|
||||
**FreePad** is a simple `Go` project to help you juggle temporary notes that you might wanna pass from one device to another, or from a person to another with memorable and easy to communicate online "Pads".
|
||||
|
||||
The project is absolutely free to use, you can extend the code and even contribute, I am more than happy to be corrected in my horrible beginner code.
|
||||
|
|
15
build.sh
|
@ -1,15 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
|
||||
echo "Removing old";
|
||||
rm dist/freepad;
|
||||
|
||||
# Remember current path
|
||||
MYDIR=`pwd`;
|
||||
# Go into src
|
||||
cd src;
|
||||
# Build
|
||||
echo "Building..."
|
||||
GIN_MODE=release CGO_ENABLED=0 GOOS=linux GIN_MODE=release go build -a -installsuffix cgo -o ../dist/freepad .
|
||||
# Go back!
|
||||
cd $MYDIR;
|
|
@ -1 +0,0 @@
|
|||
DROP TABLE IF EXISTS t_posts;
|
|
@ -1,12 +0,0 @@
|
|||
CREATE TABLE IF NOT EXISTS `t_posts` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(256) NOT NULL DEFAULT '' COLLATE 'latin1_swedish_ci',
|
||||
`content` MEDIUMTEXT NOT NULL COLLATE 'latin1_swedish_ci',
|
||||
`ts` DATETIME NOT NULL DEFAULT current_timestamp(),
|
||||
`ts_updated` DATETIME NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `name` (`name`) USING BTREE
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB
|
||||
;
|
|
@ -1 +0,0 @@
|
|||
DROP table t_posts;
|
|
@ -1,6 +0,0 @@
|
|||
CREATE TABLE IF NOT EXISTS "t_posts" (
|
||||
"id" INTEGER,
|
||||
"name" TEXT,
|
||||
"content" TEXT,
|
||||
PRIMARY KEY("id" AUTOINCREMENT)
|
||||
);
|
|
@ -1,38 +0,0 @@
|
|||
version: '3.4'
|
||||
services:
|
||||
|
||||
freepad:
|
||||
build: .
|
||||
networks:
|
||||
- backend
|
||||
environment:
|
||||
- DOMAIN_BASE=http://localhost:8888
|
||||
- MYSQL_URL=mariadb
|
||||
- MYSQL_ROOT_PASSWORD
|
||||
- MYSQL_DATABASE
|
||||
- MYSQL_USER
|
||||
- MYSQL_PASSWORD
|
||||
- MYSQL_PORT
|
||||
depends_on:
|
||||
- mariadb
|
||||
ports:
|
||||
- 8888:8080
|
||||
|
||||
mariadb:
|
||||
image: mariadb:10.2
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD
|
||||
- MYSQL_DATABASE
|
||||
- MYSQL_USER
|
||||
- MYSQL_PASSWORD
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ./dev/mariadb:/var/lib/mysql
|
||||
ports:
|
||||
- 3306:3306
|
||||
|
||||
networks:
|
||||
backend:
|
||||
driver: bridge
|
|
@ -0,0 +1,20 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, isDevelopment := os.LookupEnv("DEV_MODE")
|
||||
if isDevelopment {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
// Initialize the router
|
||||
router := gin.Default()
|
||||
|
||||
router.Run(":8080")
|
||||
|
||||
}
|
23
rundev.sh
|
@ -1,23 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "Removing old";
|
||||
rm dist/freepad;
|
||||
|
||||
source ../.env
|
||||
# Yeah, this is my solution
|
||||
export DOMAIN_BASE CACHE_MAP_LIMIT API_BAN_LIMIT DATABASE_DRIVER MYSQL_ROOT_PASSWORD MYSQL_DATABASE MYSQL_USER MYSQL_PASSWORD MYSQL_URL MYSQL_PORT IS_DEV
|
||||
|
||||
# Remember current path
|
||||
MYDIR=`pwd`;
|
||||
# Go into src
|
||||
cd src;
|
||||
# Build
|
||||
echo "Building..."
|
||||
|
||||
go build -o ../dist/freepad .
|
||||
# Go back!
|
||||
cd $MYDIR;
|
||||
|
||||
cd dist
|
||||
|
||||
./freepad && cd $MYDIR;
|
|
@ -1,122 +0,0 @@
|
|||
package post
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/JustKato/FreePad/helper"
|
||||
"github.com/JustKato/FreePad/models/database"
|
||||
)
|
||||
|
||||
var postList []*Post = []*Post{}
|
||||
|
||||
var postMap map[string]Post = make(map[string]Post)
|
||||
|
||||
func GetPostList() []*Post {
|
||||
return postList
|
||||
}
|
||||
|
||||
func Retrieve(name string) (*Post, error) {
|
||||
|
||||
if len(name) < 1 {
|
||||
return nil, errors.New("the name of the post must contain at least 1 character")
|
||||
}
|
||||
|
||||
if len(name) > 256 {
|
||||
return nil, errors.New("the name of the post must not exceed 256 characters")
|
||||
}
|
||||
|
||||
// Check if we have the post cached
|
||||
if val, ok := postMap[name]; ok {
|
||||
return &val, nil
|
||||
}
|
||||
|
||||
// Add the post to the database
|
||||
db, err := database.GetConn()
|
||||
if err != nil {
|
||||
println("Erorr", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
sql := `SELECT p.name, p.content FROM freepad.t_posts p WHERE p.name = ? LIMIT 1;`
|
||||
s, err := db.Prepare(sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := s.Query(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
anyLeft := rows.Next()
|
||||
if !anyLeft {
|
||||
return nil, errors.New("could not find the requested post")
|
||||
}
|
||||
|
||||
foundPost := Post{
|
||||
Name: "",
|
||||
Content: "",
|
||||
}
|
||||
|
||||
err = rows.Scan(&foundPost.Name, &foundPost.Content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &foundPost, nil
|
||||
}
|
||||
|
||||
func Create(name string, content string) (*Post, error) {
|
||||
|
||||
if len(name) < 1 {
|
||||
return nil, errors.New("the name of the post must contain at least 1 character")
|
||||
}
|
||||
|
||||
if len(name) > 256 {
|
||||
return nil, errors.New("the name of the post must not exceed 256 characters")
|
||||
}
|
||||
|
||||
if len(content) > 16777200 {
|
||||
return nil, errors.New("provided content is too long, please do not exceed ")
|
||||
}
|
||||
|
||||
// Initialize the post
|
||||
myPost := Post{
|
||||
Name: name,
|
||||
Content: content,
|
||||
}
|
||||
|
||||
// Check if we can cache this element
|
||||
if len(postMap) > helper.GetCacheMapLimit() {
|
||||
// Reset Cache
|
||||
postMap = make(map[string]Post)
|
||||
}
|
||||
|
||||
// Set the post by name
|
||||
postMap[name] = myPost
|
||||
|
||||
// Add the post to the database
|
||||
db, err := database.GetConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
sql := `REPLACE INTO freepad.t_posts (name, content) VALUES (?, ?)`
|
||||
s, err := db.Prepare(sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = s.Exec(myPost.Name, myPost.Content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return the post
|
||||
return &myPost, nil
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package post
|
||||
|
||||
type Post struct {
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/ulule/limiter/v3"
|
||||
"github.com/ulule/limiter/v3/drivers/store/memory"
|
||||
|
||||
mgin "github.com/ulule/limiter/v3/drivers/middleware/gin"
|
||||
)
|
||||
|
||||
func BindRateLimiter(router *gin.RouterGroup) {
|
||||
// Setup rate limitng
|
||||
rate := limiter.Rate{
|
||||
Period: 5 * time.Minute,
|
||||
Limit: 150,
|
||||
}
|
||||
|
||||
// Initialize the memory storage
|
||||
store := memory.NewStore()
|
||||
|
||||
// Generate the middleware
|
||||
middleware := mgin.NewMiddleware(limiter.New(store, rate))
|
||||
|
||||
// Use the middleware
|
||||
router.Use(middleware)
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func GetDomainBase() string {
|
||||
domainBase, domainExists := os.LookupEnv("DOMAIN_BASE")
|
||||
|
||||
if !domainExists {
|
||||
os.Setenv("DOMAIN_BASE", "http://localhost:8080")
|
||||
domainBase = "http://localhost:8080"
|
||||
}
|
||||
|
||||
return domainBase
|
||||
}
|
||||
|
||||
func GetCacheMapLimit() int {
|
||||
cacheMapLimit, domainExists := os.LookupEnv("CACHE_MAP_LIMIT")
|
||||
|
||||
if !domainExists {
|
||||
os.Setenv("CACHE_MAP_LIMIT", "25")
|
||||
cacheMapLimit = "25"
|
||||
}
|
||||
|
||||
rez, err := strconv.Atoi(cacheMapLimit)
|
||||
if err != nil {
|
||||
return 25
|
||||
}
|
||||
|
||||
return rez
|
||||
}
|
45
src/main.go
|
@ -1,45 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/JustKato/FreePad/models/database"
|
||||
"github.com/JustKato/FreePad/routes"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
_, isDevelopment := os.LookupEnv("IS_DEV")
|
||||
if isDevelopment {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
// Initialize the router
|
||||
router := gin.Default()
|
||||
|
||||
// Read HTML Templates
|
||||
router.LoadHTMLGlob("templates/**/*.html")
|
||||
|
||||
// Load in static path
|
||||
router.Static("/static", "static/")
|
||||
|
||||
// Add Routes
|
||||
routes.HomeRoutes(router)
|
||||
// Bind /api
|
||||
routes.ApiRoutes(router.Group("/api"))
|
||||
|
||||
// TODO: Sockets: https://gist.github.com/supanadit/f6de65fc5896e8bb0c4656e451387d0f
|
||||
|
||||
// Try and run migrations
|
||||
err := database.MigrateMysql()
|
||||
if err != nil {
|
||||
fmt.Println("Error")
|
||||
fmt.Println(err)
|
||||
fmt.Println("Error")
|
||||
}
|
||||
|
||||
router.Run(":8080")
|
||||
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
// Declare the default database driver
|
||||
const defaultDatabaseDriver string = "sqlite"
|
||||
|
||||
// Declare the valid database drivers
|
||||
var validDatabaseDrivers []string = []string{"sqlite", "mysql"}
|
||||
|
||||
// Get the database type to use
|
||||
func getDbType() string {
|
||||
// Grab the environment variable
|
||||
db, test := os.LookupEnv(`DATABASE_DRIVER`)
|
||||
|
||||
// Check if the test has failed
|
||||
if !test {
|
||||
return defaultDatabaseDriver
|
||||
}
|
||||
|
||||
for _, v := range validDatabaseDrivers {
|
||||
// Check if the provided database corresponds to this entry
|
||||
if v == db {
|
||||
// This is a valid database type
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
// No matches
|
||||
return defaultDatabaseDriver
|
||||
}
|
||||
|
||||
func GetConn() (*sql.DB, error) {
|
||||
|
||||
// TODO: Implement sqlite properly.
|
||||
return GetMysqlConn()
|
||||
|
||||
// Check what kind of database we are looking for
|
||||
// dbConnType := getDbType()
|
||||
|
||||
// if dbConnType == `mysql` {
|
||||
// return GetMysqlConn()
|
||||
// } else {
|
||||
// return GetLiteConn()
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
func GetSqliteDatabasePath() string {
|
||||
return "main.db"
|
||||
}
|
||||
|
||||
func GetLiteConn() (*sql.DB, error) {
|
||||
// Declare the database file name
|
||||
dbFile := GetSqliteDatabasePath()
|
||||
|
||||
db, err := sql.Open("sqlite3", dbFile)
|
||||
if err != nil {
|
||||
println("Error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func GetMysqlString() string {
|
||||
|
||||
user := os.Getenv("MYSQL_USER")
|
||||
password := os.Getenv("MYSQL_PASSWORD")
|
||||
dburl := os.Getenv("MYSQL_URL")
|
||||
dbname := os.Getenv("MYSQL_DATABASE")
|
||||
|
||||
return fmt.Sprintf("mysql://%s:%s@tcp(%s:3306)/%s", user, password, dburl, dbname)
|
||||
}
|
||||
|
||||
func GetMysqlConn() (*sql.DB, error) {
|
||||
|
||||
user := os.Getenv("MYSQL_USER")
|
||||
password := os.Getenv("MYSQL_PASSWORD")
|
||||
dburl := os.Getenv("MYSQL_URL")
|
||||
dbname := os.Getenv("MYSQL_DATABASE")
|
||||
|
||||
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s", user, password, dburl, dbname))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set options
|
||||
db.SetConnMaxLifetime(time.Minute * 5)
|
||||
db.SetMaxOpenConns(10)
|
||||
db.SetMaxIdleConns(10)
|
||||
|
||||
return db, nil
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
|
||||
_ "github.com/golang-migrate/migrate/v4/database/mysql"
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
)
|
||||
|
||||
func MigrateMysql() error {
|
||||
|
||||
m, err := migrate.New(
|
||||
"file://db/migrations/",
|
||||
GetMysqlString(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Migrate
|
||||
err = m.Up()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return m.Run()
|
||||
}
|
||||
|
||||
// Run migrations to ensure tables exist
|
||||
func MigrationUpdate() *migrate.Logger {
|
||||
// Get the path to the sqlite database
|
||||
databasePath := fmt.Sprintf("sqlite://%s", GetSqliteDatabasePath())
|
||||
|
||||
// Try and create a new migration
|
||||
m, err := migrate.New(
|
||||
"file://../db/migrations_sqlite",
|
||||
databasePath,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
// End the whole thing if migrations fail
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Run the update
|
||||
err = m.Up()
|
||||
m.Run()
|
||||
|
||||
m.Force(1)
|
||||
|
||||
return &m.Log
|
||||
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/JustKato/FreePad/controllers/post"
|
||||
"github.com/JustKato/FreePad/helper"
|
||||
"github.com/JustKato/FreePad/models/database"
|
||||
"github.com/JustKato/FreePad/types"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/skip2/go-qrcode"
|
||||
)
|
||||
|
||||
func ApiRoutes(route *gin.RouterGroup) {
|
||||
|
||||
// Bind the rate limiter
|
||||
helper.BindRateLimiter(route)
|
||||
|
||||
route.POST("/post", func(ctx *gin.Context) {
|
||||
// Get the name of the post
|
||||
postName := ctx.PostForm("name")
|
||||
// Get the content of the post
|
||||
postContent := ctx.PostForm("content")
|
||||
|
||||
// Try and run migrations
|
||||
err := database.MigrateMysql()
|
||||
if err != nil {
|
||||
fmt.Println("Error")
|
||||
fmt.Println(err)
|
||||
fmt.Println("Error")
|
||||
}
|
||||
|
||||
// Create my post
|
||||
myPost, err := post.Create(postName, postContent)
|
||||
if err != nil {
|
||||
fmt.Println("Error", err)
|
||||
ctx.JSON(400, types.FreeError{
|
||||
Error: err.Error(),
|
||||
Message: "There has been an error processing your request",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(200, gin.H{
|
||||
"message": "Post succesfully created",
|
||||
"post": myPost,
|
||||
"link": fmt.Sprintf("%s/%s", helper.GetDomainBase(), url.QueryEscape(myPost.Name)),
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
route.GET("/post", func(ctx *gin.Context) {
|
||||
// Get the name of the post
|
||||
postName := ctx.PostForm("name")
|
||||
|
||||
myPost, err := post.Retrieve(postName)
|
||||
if err != nil {
|
||||
fmt.Println("Error", err)
|
||||
ctx.JSON(400, types.FreeError{
|
||||
Error: err.Error(),
|
||||
Message: "There has been an error processing your request",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Return the post list
|
||||
ctx.JSON(200, myPost)
|
||||
})
|
||||
|
||||
route.GET("/posts", func(ctx *gin.Context) {
|
||||
// Return the post list
|
||||
ctx.JSON(200, post.GetPostList())
|
||||
})
|
||||
|
||||
// Add in health checks
|
||||
route.GET("/health", healthCheck)
|
||||
|
||||
route.POST("/qr", func(ctx *gin.Context) {
|
||||
|
||||
// Get the name of the post
|
||||
link := ctx.PostForm("link")
|
||||
|
||||
// store the png somewhere
|
||||
var png []byte
|
||||
|
||||
// Encode the link into a qr code
|
||||
png, err := qrcode.Encode(link, qrcode.High, 512)
|
||||
if err != nil {
|
||||
ctx.JSON(200, types.FreeError{
|
||||
Error: fmt.Sprint(err),
|
||||
Message: "Failed to convert qr Code",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Write the png to the response
|
||||
ctx.JSON(200, gin.H{
|
||||
"message": "Succesfully generated the QR",
|
||||
"qr": "data:image/jpeg;base64," + base64.StdEncoding.EncodeToString(png),
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func healthCheck(ctx *gin.Context) {
|
||||
ctx.JSON(200, gin.H{
|
||||
"message": "Healthy",
|
||||
})
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"github.com/JustKato/FreePad/controllers/post"
|
||||
"github.com/JustKato/FreePad/helper"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func HomeRoutes(router *gin.Engine) {
|
||||
|
||||
router.GET("/", func(c *gin.Context) {
|
||||
c.HTML(200, "index.html", gin.H{
|
||||
"title": "HomePage",
|
||||
"domain_base": helper.GetDomainBase(),
|
||||
})
|
||||
})
|
||||
|
||||
router.GET("/:post", func(c *gin.Context) {
|
||||
// Get the post we are looking for.
|
||||
postName := c.Param("post")
|
||||
|
||||
// Try and get this post's data
|
||||
postData, err := post.Retrieve(postName)
|
||||
if err != nil {
|
||||
postData = &post.Post{
|
||||
Name: postName,
|
||||
Content: "",
|
||||
}
|
||||
}
|
||||
|
||||
c.HTML(200, "page.html", gin.H{
|
||||
"title": postName,
|
||||
"post_content": postData.Content,
|
||||
"domain_base": helper.GetDomainBase(),
|
||||
})
|
||||
})
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package types
|
||||
|
||||
type FreeError struct {
|
||||
Error string `json:"error"`
|
||||
Message string `json:"message"`
|
||||
}
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 218 B After Width: | Height: | Size: 218 B |
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 186 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 780 B After Width: | Height: | Size: 780 B |
Before Width: | Height: | Size: 1021 B After Width: | Height: | Size: 1021 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |