diff --git a/api/Makefile b/api/Makefile
index a469149..ff72694 100644
--- a/api/Makefile
+++ b/api/Makefile
@@ -1,7 +1,12 @@
-server: *.go routes/* util/*
+all: server
+
+server: *.go routes/* util/* global/* database/*
go build -o server .
test:
FRONTEND_URL=http://localhost:5173/ PASSWORD=test ./server
-.PHONY: test
+format:
+ gofmt -s -w .
+
+.PHONY: test format
diff --git a/api/database/database.go b/api/database/database.go
new file mode 100644
index 0000000..0388f24
--- /dev/null
+++ b/api/database/database.go
@@ -0,0 +1,55 @@
+package database
+
+import (
+ "database/sql"
+ "github.com/ngn13/website/api/global"
+)
+
+type Type struct {
+ Sql *sql.DB
+ Votes []global.Vote
+}
+
+func (t *Type) Setup() error {
+ t.Votes = []global.Vote{}
+
+ _, err := t.Sql.Exec(`
+ CREATE TABLE IF NOT EXISTS posts(
+ id TEXT NOT NULL UNIQUE,
+ title TEXT NOT NULL,
+ author TEXT NOT NULL,
+ date TEXT NOT NULL,
+ content TEXT NOT NULL,
+ public INTEGER NOT NULL,
+ vote INTEGER NOT NULL
+ );
+ `)
+
+ if err != nil {
+ return err
+ }
+
+ _, err = t.Sql.Exec(`
+ CREATE TABLE IF NOT EXISTS services(
+ name TEXT NOT NULL UNIQUE,
+ desc TEXT NOT NULL,
+ url TEXT NOT NULL
+ );
+ `)
+
+ return err
+}
+
+func (t *Type) Open(p string) error {
+ var err error
+
+ if t.Sql, err = sql.Open("sqlite3", p); err != nil {
+ return err
+ }
+
+ return t.Setup()
+}
+
+func (t *Type) Close() {
+ t.Sql.Close()
+}
diff --git a/api/global/global.go b/api/global/global.go
new file mode 100644
index 0000000..6542187
--- /dev/null
+++ b/api/global/global.go
@@ -0,0 +1,23 @@
+package global
+
+type Post struct {
+ ID string `json:"id"`
+ Title string `json:"title"`
+ Author string `json:"author"`
+ Date string `json:"date"`
+ Content string `json:"content"`
+ Public int `json:"public"`
+ Vote int `json:"vote"`
+}
+
+type Service struct {
+ Name string `json:"name"`
+ Desc string `json:"desc"`
+ Url string `json:"url"`
+}
+
+type Vote struct {
+ Post string
+ Client string
+ Status string
+}
diff --git a/api/main.go b/api/main.go
index 59cc9b4..545ef4d 100644
--- a/api/main.go
+++ b/api/main.go
@@ -1,42 +1,78 @@
package main
import (
- "database/sql"
"log"
+ "net/http"
"github.com/gofiber/fiber/v2"
+ "github.com/ngn13/website/api/database"
"github.com/ngn13/website/api/routes"
)
-func CorsMiddleware(c *fiber.Ctx) error {
- c.Set("Access-Control-Allow-Origin", "*")
- c.Set("Access-Control-Allow-Headers",
- "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
- c.Set("Access-Control-Allow-Methods", "PUT, DELETE, GET")
- return c.Next()
-}
-
func main() {
- app := fiber.New(fiber.Config{
- DisableStartupMessage: true,
- })
- app.Use(CorsMiddleware)
+ var (
+ app *fiber.App
+ db database.Type
+ err error
+ )
- db, err := sql.Open("sqlite3", "data.db")
- if err != nil {
- log.Fatal("Cannot connect to the database: "+err.Error())
- }
+ if err = db.Open("data.db"); err != nil {
+ log.Fatalf("Cannot access the database: %s", err.Error())
+ return
+ }
+ defer db.Close()
- log.Println("Creating tables")
- routes.BlogDb(db)
- routes.ServicesDb(db)
- routes.Setup(app, db)
+ app = fiber.New(fiber.Config{
+ DisableStartupMessage: true,
+ })
- log.Println("Starting web server at port 7001")
- err = app.Listen("0.0.0.0:7001")
- if err != nil {
- log.Printf("Error starting the webserver: %s", err.Error())
- }
+ app.Use("*", func(c *fiber.Ctx) error {
+ c.Set("Access-Control-Allow-Origin", "*")
+ c.Set("Access-Control-Allow-Headers",
+ "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
+ c.Set("Access-Control-Allow-Methods", "PUT, DELETE, GET")
+ c.Locals("database", &db)
+ return c.Next()
+ })
- defer db.Close()
+ // index route
+ app.Get("/", func(c *fiber.Ctx) error {
+ return c.Send([]byte("o/"))
+ })
+
+ // blog routes
+ blog_routes := app.Group("/blog")
+ blog_routes.Get("/feed.atom", routes.GetAtomFeed)
+ blog_routes.Get("/feed.rss", routes.GetRSSFeed)
+ blog_routes.Get("/feed.json", routes.GetJSONFeed)
+ blog_routes.Get("/sum", routes.SumPost)
+ blog_routes.Get("/get", routes.GetPost)
+ blog_routes.Get("/vote/set", routes.VoteSet)
+ blog_routes.Get("/vote/status", routes.VoteStat)
+
+ // service routes
+ service_routes := app.Group("services")
+ service_routes.Get("/all", routes.GetServices)
+
+ // admin routes
+ admin_routes := app.Group("admin")
+ admin_routes.Use("*", routes.AuthMiddleware)
+ admin_routes.Get("/login", routes.Login)
+ admin_routes.Get("/logout", routes.Logout)
+ admin_routes.Put("/service/add", routes.AddService)
+ admin_routes.Delete("/service/remove", routes.RemoveService)
+ admin_routes.Put("/blog/add", routes.AddPost)
+ admin_routes.Delete("/blog/remove", routes.RemovePost)
+
+ // 404 routes
+ app.All("*", func(c *fiber.Ctx) error {
+ return c.Status(http.StatusNotFound).JSON(fiber.Map{
+ "error": "Requested endpoint not found",
+ })
+ })
+
+ log.Println("Starting web server at port 7001")
+ if err = app.Listen("0.0.0.0:7001"); err != nil {
+ log.Printf("Error starting the webserver: %s", err.Error())
+ }
}
diff --git a/api/routes/admin.go b/api/routes/admin.go
index c1ac4ec..b628d52 100644
--- a/api/routes/admin.go
+++ b/api/routes/admin.go
@@ -1,6 +1,7 @@
package routes
import (
+ "log"
"net/http"
"os"
"strings"
@@ -8,132 +9,164 @@ import (
"github.com/gofiber/fiber/v2"
"github.com/mattn/go-sqlite3"
+ "github.com/ngn13/website/api/database"
+ "github.com/ngn13/website/api/global"
"github.com/ngn13/website/api/util"
)
-var Token string = util.CreateToken()
+var Token string = util.CreateToken()
func AuthMiddleware(c *fiber.Ctx) error {
- if c.Path() == "/admin/login" {
- return c.Next()
- }
+ if c.Path() == "/admin/login" {
+ return c.Next()
+ }
- if c.Get("Authorization") != Token {
- return util.ErrAuth(c)
- }
+ if c.Get("Authorization") != Token {
+ return util.ErrAuth(c)
+ }
- return c.Next()
+ return c.Next()
}
-func Login(c *fiber.Ctx) error{
- if c.Query("pass") != os.Getenv("PASSWORD") {
- return c.Status(http.StatusUnauthorized).JSON(fiber.Map{
- "error": "Authentication failed",
- })
- }
+func Login(c *fiber.Ctx) error {
+ if c.Query("pass") != os.Getenv("PASSWORD") {
+ return c.Status(http.StatusUnauthorized).JSON(fiber.Map{
+ "error": "Authentication failed",
+ })
+ }
- return c.Status(http.StatusOK).JSON(fiber.Map{
- "error": "",
- "token": Token,
- })
+ log.Printf("New login from %s", util.GetIP(c))
+
+ return c.Status(http.StatusOK).JSON(fiber.Map{
+ "error": "",
+ "token": Token,
+ })
}
-func Logout(c *fiber.Ctx) error{
- Token = util.CreateToken()
- return c.Status(http.StatusOK).JSON(fiber.Map{
- "error": "",
- })
+func Logout(c *fiber.Ctx) error {
+ Token = util.CreateToken()
+
+ log.Printf("Logout from %s", util.GetIP(c))
+
+ return c.Status(http.StatusOK).JSON(fiber.Map{
+ "error": "",
+ })
}
func RemoveService(c *fiber.Ctx) error {
- name := c.Query("name")
- if name == "" {
- util.ErrBadData(c)
- }
+ var (
+ db *database.Type
+ name string
+ )
- _, err := DB.Exec("DELETE FROM services WHERE name = ?", name)
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
-
- return util.NoError(c)
+ db = c.Locals("database").(*database.Type)
+ name = c.Query("name")
+
+ if name == "" {
+ util.ErrBadData(c)
+ }
+
+ _, err := db.Sql.Exec("DELETE FROM services WHERE name = ?", name)
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
+
+ return util.NoError(c)
}
func AddService(c *fiber.Ctx) error {
- var service Service
- if c.BodyParser(&service) != nil {
- return util.ErrBadJSON(c)
- }
+ var (
+ service global.Service
+ db *database.Type
+ )
- if service.Name == "" || service.Desc == "" || service.Url == "" {
- return util.ErrBadData(c)
- }
+ db = c.Locals("database").(*database.Type)
- rows, err := DB.Query("SELECT * FROM services WHERE name = ?", service.Name)
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
-
- if rows.Next() {
- rows.Close()
- return util.ErrExists(c)
- }
+ if c.BodyParser(&service) != nil {
+ return util.ErrBadJSON(c)
+ }
- rows.Close()
+ if service.Name == "" || service.Desc == "" || service.Url == "" {
+ return util.ErrBadData(c)
+ }
- _, err = DB.Exec(
- "INSERT INTO services(name, desc, url) values(?, ?, ?)",
- service.Name, service.Desc, service.Url,
- )
+ rows, err := db.Sql.Query("SELECT * FROM services WHERE name = ?", service.Name)
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
+ if rows.Next() {
+ rows.Close()
+ return util.ErrExists(c)
+ }
- return util.NoError(c)
+ rows.Close()
+
+ _, err = db.Sql.Exec(
+ "INSERT INTO services(name, desc, url) values(?, ?, ?)",
+ service.Name, service.Desc, service.Url,
+ )
+
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
+
+ return util.NoError(c)
}
-func RemovePost(c *fiber.Ctx) error{
- var id = c.Query("id")
- if id == "" {
- return util.ErrBadData(c)
- }
+func RemovePost(c *fiber.Ctx) error {
+ var (
+ db *database.Type
+ id string
+ )
- _, err := DB.Exec("DELETE FROM posts WHERE id = ?", id)
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
+ db = c.Locals("database").(*database.Type)
+ id = c.Query("id")
- return util.NoError(c)
+ if id == "" {
+ return util.ErrBadData(c)
+ }
+
+ _, err := db.Sql.Exec("DELETE FROM posts WHERE id = ?", id)
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
+
+ return util.NoError(c)
}
-func AddPost(c *fiber.Ctx) error{
- var post Post
- post.Public = 1
+func AddPost(c *fiber.Ctx) error {
+ var (
+ db *database.Type
+ post global.Post
+ )
- if c.BodyParser(&post) != nil {
- return util.ErrBadJSON(c)
- }
+ db = c.Locals("database").(*database.Type)
+ post.Public = 1
- if post.Title == "" || post.Author == "" || post.Content == "" {
- return util.ErrBadData(c)
- }
+ if c.BodyParser(&post) != nil {
+ return util.ErrBadJSON(c)
+ }
- post.Date = time.Now().Format("02/01/06")
- post.ID = TitleToID(post.Title)
+ if post.Title == "" || post.Author == "" || post.Content == "" {
+ return util.ErrBadData(c)
+ }
- _, err := DB.Exec(
- "INSERT INTO posts(id, title, author, date, content, public, vote) values(?, ?, ?, ?, ?, ?, ?)",
- post.ID, post.Title, post.Author, post.Date, post.Content, post.Public, post.Vote,
- )
+ post.Date = time.Now().Format("02/01/06")
+ post.ID = util.TitleToID(post.Title)
- if err != nil && strings.Contains(err.Error(), sqlite3.ErrConstraintUnique.Error()) {
- return util.ErrExists(c)
- }
+ _, err := db.Sql.Exec(
+ "INSERT INTO posts(id, title, author, date, content, public, vote) values(?, ?, ?, ?, ?, ?, ?)",
+ post.ID, post.Title, post.Author, post.Date, post.Content, post.Public, post.Vote,
+ )
- if util.ErrorCheck(err, c){
- return util.ErrExists(c)
- }
+ if err != nil && strings.Contains(err.Error(), sqlite3.ErrConstraintUnique.Error()) {
+ return util.ErrExists(c)
+ }
- return util.NoError(c)
+ if util.ErrorCheck(err, c) {
+ return util.ErrExists(c)
+ }
+
+ return util.NoError(c)
}
diff --git a/api/routes/blog.go b/api/routes/blog.go
index f7cc4c4..de214ed 100644
--- a/api/routes/blog.go
+++ b/api/routes/blog.go
@@ -2,274 +2,317 @@ package routes
import (
"database/sql"
- "log"
+ "fmt"
"net/http"
"net/url"
- "fmt"
"os"
- "strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gorilla/feeds"
+ "github.com/ngn13/website/api/database"
+ "github.com/ngn13/website/api/global"
"github.com/ngn13/website/api/util"
)
-func BlogDb(db *sql.DB) {
- _, err := db.Exec(`
- CREATE TABLE IF NOT EXISTS posts(
- id TEXT NOT NULL UNIQUE,
- title TEXT NOT NULL,
- author TEXT NOT NULL,
- date TEXT NOT NULL,
- content TEXT NOT NULL,
- public INTEGER NOT NULL,
- vote INTEGER NOT NULL
- );
- `)
- DB = db
- if err != nil {
- log.Fatal("Error creating table: "+err.Error())
- }
+func PostFromRow(post *global.Post, rows *sql.Rows) error {
+ err := rows.Scan(&post.ID, &post.Title, &post.Author, &post.Date, &post.Content, &post.Public, &post.Vote)
+ if err != nil {
+ return err
+ }
+
+ return nil
}
-func GetIP(c *fiber.Ctx) string {
- if c.Get("X-Real-IP") != "" {
- return strings.Clone(c.Get("X-Real-IP"))
- }
+func GetPostByID(db *database.Type, id string) (global.Post, string) {
+ var post global.Post = global.Post{}
+ post.Title = "NONE"
- return c.IP()
+ rows, err := db.Sql.Query("SELECT * FROM posts WHERE id = ?", id)
+
+ if err != nil {
+ return post, "Server error"
+ }
+
+ success := rows.Next()
+ if !success {
+ rows.Close()
+ return post, "Post not found"
+ }
+
+ err = PostFromRow(&post, rows)
+ if err != nil {
+ rows.Close()
+ return post, "Server error"
+ }
+ rows.Close()
+
+ if post.Title == "NONE" {
+ return post, "Post not found"
+ }
+
+ return post, ""
}
-func VoteStat(c *fiber.Ctx) error{
- var id = c.Query("id")
- if id == "" {
- return util.ErrBadData(c)
- }
+func VoteStat(c *fiber.Ctx) error {
+ var (
+ db *database.Type
+ id string
+ )
- for i := 0; i < len(votelist); i++ {
- if votelist[i].Client == GetIP(c) && votelist[i].Post == id {
- return c.JSON(fiber.Map {
- "error": "",
- "result": votelist[i].Status,
- })
- }
- }
+ db = c.Locals("database").(*database.Type)
+ id = c.Query("id")
- return c.Status(http.StatusNotFound).JSON(util.ErrorJSON("Client never voted"))
+ if id == "" {
+ return util.ErrBadData(c)
+ }
+
+ for i := 0; i < len(db.Votes); i++ {
+ if db.Votes[i].Client == util.GetIP(c) && db.Votes[i].Post == id {
+ return c.JSON(fiber.Map{
+ "error": "",
+ "result": db.Votes[i].Status,
+ })
+ }
+ }
+
+ return c.Status(http.StatusNotFound).JSON(util.ErrorJSON("Client never voted"))
}
-func VoteSet(c *fiber.Ctx) error{
- var id = c.Query("id")
- var to = c.Query("to")
- voted := false
+func VoteSet(c *fiber.Ctx) error {
+ var (
+ id string
+ to string
+ voted bool
+ db *database.Type
+ )
- if id == "" || (to != "upvote" && to != "downvote") {
- return util.ErrBadData(c)
- }
+ db = c.Locals("database").(*database.Type)
+ id = c.Query("id")
+ to = c.Query("to")
+ voted = false
- for i := 0; i < len(votelist); i++ {
- if votelist[i].Client == GetIP(c) && votelist[i].Post == id && votelist[i].Status == to {
- return c.Status(http.StatusForbidden).JSON(util.ErrorJSON("Client already voted"))
- }
+ if id == "" || (to != "upvote" && to != "downvote") {
+ return util.ErrBadData(c)
+ }
- if votelist[i].Client == GetIP(c) && votelist[i].Post == id && votelist[i].Status != to {
- voted = true
- }
- }
+ for i := 0; i < len(db.Votes); i++ {
+ if db.Votes[i].Client == util.GetIP(c) && db.Votes[i].Post == id && db.Votes[i].Status == to {
+ return c.Status(http.StatusForbidden).JSON(util.ErrorJSON("Client already voted"))
+ }
- post, msg := GetPostByID(id)
- if msg != ""{
- return c.Status(http.StatusNotFound).JSON(util.ErrorJSON(msg))
- }
+ if db.Votes[i].Client == util.GetIP(c) && db.Votes[i].Post == id && db.Votes[i].Status != to {
+ voted = true
+ }
+ }
- vote := post.Vote+1
+ post, msg := GetPostByID(db, id)
+ if msg != "" {
+ return c.Status(http.StatusNotFound).JSON(util.ErrorJSON(msg))
+ }
- if to == "downvote" {
- vote = post.Vote-1
- }
+ vote := post.Vote + 1
- if to == "downvote" && voted {
- vote = vote-1
- }
+ if to == "downvote" {
+ vote = post.Vote - 1
+ }
- if to == "upvote" && voted {
- vote = vote+1
- }
+ if to == "downvote" && voted {
+ vote = vote - 1
+ }
- _, err := DB.Exec("UPDATE posts SET vote = ? WHERE title = ?", vote, post.Title)
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
+ if to == "upvote" && voted {
+ vote = vote + 1
+ }
- for i := 0; i < len(votelist); i++ {
- if votelist[i].Client == GetIP(c) && votelist[i].Post == id && votelist[i].Status != to {
- votelist[i].Status = to
- return util.NoError(c)
- }
- }
+ _, err := db.Sql.Exec("UPDATE posts SET vote = ? WHERE title = ?", vote, post.Title)
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- var entry = Vote{}
- entry.Client = GetIP(c)
- entry.Status = to
- entry.Post = id
- votelist = append(votelist, entry)
- return util.NoError(c)
+ for i := 0; i < len(db.Votes); i++ {
+ if db.Votes[i].Client == util.GetIP(c) && db.Votes[i].Post == id && db.Votes[i].Status != to {
+ db.Votes[i].Status = to
+ return util.NoError(c)
+ }
+ }
+
+ var entry = global.Vote{}
+ entry.Client = util.GetIP(c)
+ entry.Status = to
+ entry.Post = id
+ db.Votes = append(db.Votes, entry)
+ return util.NoError(c)
}
-func GetPost(c *fiber.Ctx) error{
- var id = c.Query("id")
- if id == "" {
- return util.ErrBadData(c)
- }
+func GetPost(c *fiber.Ctx) error {
+ var (
+ id string
+ db *database.Type
+ )
- post, msg := GetPostByID(id)
- if msg != ""{
- return c.Status(http.StatusNotFound).JSON(util.ErrorJSON(msg))
- }
+ id = c.Query("id")
+ db = c.Locals("database").(*database.Type)
- return c.JSON(fiber.Map {
- "error": "",
- "result": post,
- })
+ if id == "" {
+ return util.ErrBadData(c)
+ }
+
+ post, msg := GetPostByID(db, id)
+ if msg != "" {
+ return c.Status(http.StatusNotFound).JSON(util.ErrorJSON(msg))
+ }
+
+ return c.JSON(fiber.Map{
+ "error": "",
+ "result": post,
+ })
}
+func SumPost(c *fiber.Ctx) error {
+ var (
+ posts []global.Post
+ post global.Post
+ db *database.Type
+ err error
+ )
+ db = c.Locals("database").(*database.Type)
-func SumPost(c *fiber.Ctx) error{
- var posts []Post = []Post{}
- rows, err := DB.Query("SELECT * FROM posts")
- if util.ErrorCheck(err, c) {
- return util.ErrServer(c)
- }
+ rows, err := db.Sql.Query("SELECT * FROM posts")
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- for rows.Next() {
- var post Post
- err := PostFromRow(&post, rows)
+ for rows.Next() {
+ err = PostFromRow(&post, rows)
- if util.ErrorCheck(err, c) {
- return util.ErrServer(c)
- }
-
- if post.Public == 0 {
- continue
- }
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- if len(post.Content) > 255{
- post.Content = post.Content[0:250]
- }
+ if post.Public == 0 {
+ continue
+ }
- posts = append(posts, post)
- }
- rows.Close()
+ if len(post.Content) > 255 {
+ post.Content = post.Content[0:250]
+ }
- return c.JSON(fiber.Map {
- "error": "",
- "result": posts,
- })
+ posts = append(posts, post)
+ }
+ rows.Close()
+
+ return c.JSON(fiber.Map{
+ "error": "",
+ "result": posts,
+ })
}
-func GetFeed() (*feeds.Feed, error){
- var posts []Post = []Post{}
- rows, err := DB.Query("SELECT * FROM posts")
- if err != nil {
- return nil, err
- }
+func GetFeed(db *database.Type) (*feeds.Feed, error) {
+ var (
+ posts []global.Post
+ post global.Post
+ err error
+ )
- for rows.Next() {
- var post Post
- err := PostFromRow(&post, rows)
+ rows, err := db.Sql.Query("SELECT * FROM posts")
+ if err != nil {
+ return nil, err
+ }
- if err != nil {
- return nil, err
- }
-
- if post.Public == 0 {
- continue
- }
+ for rows.Next() {
+ err := PostFromRow(&post, rows)
- posts = append(posts, post)
- }
- rows.Close()
+ if err != nil {
+ return nil, err
+ }
+ if post.Public == 0 {
+ continue
+ }
- blogurl, err := url.JoinPath(os.Getenv("FRONTEND_URL"), "/blog")
- if err != nil {
- return nil, fmt.Errorf("failed to create the blog URL: %s", err.Error())
- }
+ posts = append(posts, post)
+ }
+ rows.Close()
- feed := &feeds.Feed{
- Title: "[ngn.tf] | blog",
- Link: &feeds.Link{Href: blogurl},
- Description: "ngn's personal blog",
- Author: &feeds.Author{Name: "ngn", Email: "ngn@ngn.tf"},
- Created: time.Now(),
- }
+ blogurl, err := url.JoinPath(os.Getenv("FRONTEND_URL"), "/blog")
+ if err != nil {
+ return nil, fmt.Errorf("failed to create the blog URL: %s", err.Error())
+ }
- feed.Items = []*feeds.Item{}
- for _, p := range posts {
- purl, err := url.JoinPath(blogurl, p.ID)
- if err != nil {
- return nil, fmt.Errorf("failed to create URL for '%s': %s\n", p.ID, err.Error())
- }
+ feed := &feeds.Feed{
+ Title: "[ngn.tf] | blog",
+ Link: &feeds.Link{Href: blogurl},
+ Description: "ngn's personal blog",
+ Author: &feeds.Author{Name: "ngn", Email: "ngn@ngn.tf"},
+ Created: time.Now(),
+ }
- parsed, err := time.Parse("02/01/06", p.Date)
- if err != nil {
- return nil, fmt.Errorf("failed to parse time for '%s': %s\n", p.ID, err.Error())
- }
+ feed.Items = []*feeds.Item{}
+ for _, p := range posts {
+ purl, err := url.JoinPath(blogurl, p.ID)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create URL for '%s': %s\n", p.ID, err.Error())
+ }
- feed.Items = append(feed.Items, &feeds.Item{
- Id: p.ID,
- Title: p.Title,
- Link: &feeds.Link{Href: purl},
- Author: &feeds.Author{Name: p.Author},
- Created: parsed,
- })
- }
+ parsed, err := time.Parse("02/01/06", p.Date)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse time for '%s': %s\n", p.ID, err.Error())
+ }
- return feed, nil
+ feed.Items = append(feed.Items, &feeds.Item{
+ Id: p.ID,
+ Title: p.Title,
+ Link: &feeds.Link{Href: purl},
+ Author: &feeds.Author{Name: p.Author},
+ Created: parsed,
+ })
+ }
+
+ return feed, nil
}
func GetAtomFeed(c *fiber.Ctx) error {
- feed, err := GetFeed()
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
+ feed, err := GetFeed(c.Locals("database").(*database.Type))
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- atom, err := feed.ToAtom()
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
+ atom, err := feed.ToAtom()
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- c.Set("Content-Type", "application/atom+xml")
- return c.Send([]byte(atom))
+ c.Set("Content-Type", "application/atom+xml")
+ return c.Send([]byte(atom))
}
func GetRSSFeed(c *fiber.Ctx) error {
- feed, err := GetFeed()
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
+ feed, err := GetFeed(c.Locals("database").(*database.Type))
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- rss, err := feed.ToRss()
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
+ rss, err := feed.ToRss()
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- c.Set("Content-Type", "application/rss+xml")
- return c.Send([]byte(rss))
+ c.Set("Content-Type", "application/rss+xml")
+ return c.Send([]byte(rss))
}
func GetJSONFeed(c *fiber.Ctx) error {
- feed, err := GetFeed()
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
+ feed, err := GetFeed(c.Locals("database").(*database.Type))
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- json, err := feed.ToJSON()
- if util.ErrorCheck(err, c){
- return util.ErrServer(c)
- }
- c.Set("Content-Type", "application/feed+json")
- return c.Send([]byte(json))
+ json, err := feed.ToJSON()
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
+ c.Set("Content-Type", "application/feed+json")
+ return c.Send([]byte(json))
}
diff --git a/api/routes/global.go b/api/routes/global.go
deleted file mode 100644
index f33264e..0000000
--- a/api/routes/global.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package routes
-
-import (
- "database/sql"
- "strings"
-)
-
-// ############### BLOG ###############
-type Post struct {
- ID string `json:"id"`
- Title string `json:"title"`
- Author string `json:"author"`
- Date string `json:"date"`
- Content string `json:"content"`
- Public int `json:"public"`
- Vote int `json:"vote"`
-}
-
-var votelist = []Vote{}
-type Vote struct {
- Post string
- Client string
- Status string
-}
-
-func PostFromRow(post *Post, rows *sql.Rows) error{
- err := rows.Scan(&post.ID, &post.Title, &post.Author, &post.Date, &post.Content, &post.Public, &post.Vote)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func GetPostByID(id string) (Post, string) {
- var post Post = Post{}
- post.Title = "NONE"
-
- rows, err := DB.Query("SELECT * FROM posts WHERE id = ?", id)
-
- if err != nil{
- return post, "Server error"
- }
-
- success := rows.Next()
- if !success {
- rows.Close()
- return post, "Post not found"
- }
-
- err = PostFromRow(&post, rows)
- if err != nil {
- rows.Close()
- return post, "Server error"
- }
- rows.Close()
-
- if post.Title == "NONE" {
- return post, "Post not found"
- }
-
- return post, ""
-}
-
-func TitleToID(name string) string{
- return strings.ToLower(strings.ReplaceAll(name, " ", ""))
-}
-
-// ############### SERVICES ###############
-type Service struct {
- Name string `json:"name"`
- Desc string `json:"desc"`
- Url string `json:"url"`
-}
diff --git a/api/routes/routes.go b/api/routes/routes.go
deleted file mode 100644
index 9a2ee9b..0000000
--- a/api/routes/routes.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package routes
-
-import (
- "database/sql"
- "net/http"
-
- "github.com/gofiber/fiber/v2"
-)
-
-var DB *sql.DB
-
-func Setup(app *fiber.App, db *sql.DB){
- // database init
- DB = db
-
- // index route
- app.Get("/", func(c *fiber.Ctx) error {
- return c.Send([]byte("o/"))
- })
-
- // blog routes
- app.Get("/blog/feed.atom", GetAtomFeed)
- app.Get("/blog/feed.rss", GetRSSFeed)
- app.Get("/blog/feed.json", GetJSONFeed)
- app.Get("/blog/sum", SumPost)
- app.Get("/blog/get", GetPost)
- app.Get("/blog/vote/set", VoteSet)
- app.Get("/blog/vote/status", VoteStat)
-
- // service routes
- app.Get("/services/all", GetServices)
-
- // admin routes
- app.Use("/admin*", AuthMiddleware)
- app.Get("/admin/login", Login)
- app.Get("/admin/logout", Logout)
- app.Put("/admin/service/add", AddService)
- app.Delete("/admin/service/remove", RemoveService)
- app.Put("/admin/blog/add", AddPost)
- app.Delete("/admin/blog/remove", RemovePost)
-
- // 404 page
- app.All("*", func(c *fiber.Ctx) error {
- return c.Status(http.StatusNotFound).JSON(fiber.Map {
- "error": "Requested endpoint not found",
- })
- })
-}
diff --git a/api/routes/services.go b/api/routes/services.go
index eb5cc25..3ab7469 100644
--- a/api/routes/services.go
+++ b/api/routes/services.go
@@ -1,48 +1,41 @@
package routes
import (
- "database/sql"
"log"
"github.com/gofiber/fiber/v2"
+ "github.com/ngn13/website/api/database"
+ "github.com/ngn13/website/api/global"
"github.com/ngn13/website/api/util"
)
-func ServicesDb(db *sql.DB) {
- _, err := db.Exec(`
- CREATE TABLE IF NOT EXISTS services(
- name TEXT NOT NULL UNIQUE,
- desc TEXT NOT NULL,
- url TEXT NOT NULL
- );
- `)
-
- if err != nil {
- log.Fatal("Error creating table: "+err.Error())
- }
-}
-
func GetServices(c *fiber.Ctx) error {
- var services []Service = []Service{}
+ var (
+ services []global.Service = []global.Service{}
+ service global.Service
+ db *database.Type
+ err error
+ )
- rows, err := DB.Query("SELECT * FROM services")
- if util.ErrorCheck(err, c) {
- return util.ErrServer(c)
- }
+ db = c.Locals("database").(*database.Type)
- for rows.Next() {
- var service Service
- err := rows.Scan(&service.Name, &service.Desc, &service.Url)
- if err != nil {
- log.Println("Error scaning services row: "+err.Error())
- continue
- }
- services = append(services, service)
- }
- rows.Close()
+ rows, err := db.Sql.Query("SELECT * FROM services")
+ if util.ErrorCheck(err, c) {
+ return util.ErrServer(c)
+ }
- return c.JSON(fiber.Map {
- "error": "",
- "result": services,
- })
+ for rows.Next() {
+ if err = rows.Scan(&service.Name, &service.Desc, &service.Url); err != nil {
+ log.Println("Error scaning services row: " + err.Error())
+ continue
+ }
+ services = append(services, service)
+ }
+
+ rows.Close()
+
+ return c.JSON(fiber.Map{
+ "error": "",
+ "result": services,
+ })
}
diff --git a/api/util/utils.go b/api/util/utils.go
index 334f5e1..b4c30d8 100644
--- a/api/util/utils.go
+++ b/api/util/utils.go
@@ -4,57 +4,66 @@ import (
"log"
"math/rand"
"net/http"
+ "strings"
"github.com/gofiber/fiber/v2"
)
-var charlist []rune = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
+func TitleToID(name string) string {
+ return strings.ToLower(strings.ReplaceAll(name, " ", ""))
+}
func CreateToken() string {
- b := make([]rune, 20)
- for i := range b {
- b[i] = charlist[rand.Intn(len(charlist))]
- }
-
- return string(b)
+ s := make([]byte, 32)
+ for i := 0; i < 32; i++ {
+ s[i] = byte(65 + rand.Intn(25))
+ }
+ return string(s)
}
-func ErrorCheck(err error, c *fiber.Ctx) bool{
- if err != nil {
- log.Printf("Server error: '%s' on %s\n", err, c.Path())
- return true
- }
+func ErrorCheck(err error, c *fiber.Ctx) bool {
+ if err != nil {
+ log.Printf("Server error: '%s' on %s\n", err, c.Path())
+ return true
+ }
- return false
+ return false
}
-func ErrorJSON(error string) fiber.Map{
- return fiber.Map {
- "error": error,
- }
+func ErrorJSON(error string) fiber.Map {
+ return fiber.Map{
+ "error": error,
+ }
+}
+
+func GetIP(c *fiber.Ctx) string {
+ if c.Get("X-Real-IP") != "" {
+ return strings.Clone(c.Get("X-Real-IP"))
+ }
+
+ return c.IP()
}
func ErrServer(c *fiber.Ctx) error {
- return c.Status(http.StatusInternalServerError).JSON(ErrorJSON("Server error"))
+ return c.Status(http.StatusInternalServerError).JSON(ErrorJSON("Server error"))
}
func ErrExists(c *fiber.Ctx) error {
- return c.Status(http.StatusConflict).JSON(ErrorJSON("Entry already exists"))
+ return c.Status(http.StatusConflict).JSON(ErrorJSON("Entry already exists"))
}
func ErrBadData(c *fiber.Ctx) error {
- return c.Status(http.StatusBadRequest).JSON(ErrorJSON("Provided data is invalid"))
+ return c.Status(http.StatusBadRequest).JSON(ErrorJSON("Provided data is invalid"))
}
func ErrBadJSON(c *fiber.Ctx) error {
- return c.Status(http.StatusBadRequest).JSON(ErrorJSON("Bad JSON data"))
+ return c.Status(http.StatusBadRequest).JSON(ErrorJSON("Bad JSON data"))
}
func ErrAuth(c *fiber.Ctx) error {
- return c.Status(http.StatusUnauthorized).JSON(ErrorJSON("Authentication failed"))
+ return c.Status(http.StatusUnauthorized).JSON(ErrorJSON("Authentication failed"))
}
func NoError(c *fiber.Ctx) error {
- return c.Status(http.StatusOK).JSON(ErrorJSON(""))
+ return c.Status(http.StatusOK).JSON(ErrorJSON(""))
}
-
diff --git a/app/src/lib/header.svelte b/app/src/lib/header.svelte
index 0337a2e..c76bbf1 100644
--- a/app/src/lib/header.svelte
+++ b/app/src/lib/header.svelte
@@ -1,9 +1,12 @@
-
+
+
v4.8
+v4.9