Multiple fixes and added article get endpoint for authors
This commit is contained in:
4
.env
4
.env
@@ -2,8 +2,8 @@ SERVER_PORT=8080
|
|||||||
|
|
||||||
# the global address of your webserver (protocol://domain[:port]). make sure this DOES NOT has a trailing slash
|
# the global address of your webserver (protocol://domain[:port]). make sure this DOES NOT has a trailing slash
|
||||||
ADDRESS=http://localhost:8080
|
ADDRESS=http://localhost:8080
|
||||||
# the path you serve on. must be at least a slash
|
# the path you serve on
|
||||||
Path=/
|
SUBPATH=
|
||||||
|
|
||||||
DATABASE_FILE=database.sqlite3
|
DATABASE_FILE=database.sqlite3
|
||||||
FRONTEND_DIR=./frontend/
|
FRONTEND_DIR=./frontend/
|
||||||
|
|||||||
@@ -12,21 +12,75 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Article(w http.ResponseWriter, r *http.Request) {
|
func Article(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodGet:
|
|
||||||
assetsGet(w, r)
|
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
assetsPost(w, r)
|
articlePost(w, r)
|
||||||
case http.MethodDelete:
|
case http.MethodDelete:
|
||||||
assetsDelete(w, r)
|
articleDelete(w, r)
|
||||||
|
case http.MethodPatch:
|
||||||
|
articlePatch(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type getResponse struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Summary string `json:"summary"`
|
||||||
|
Authors []int `json:"authors"`
|
||||||
|
Image string `json:"image"`
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
Link string `json:"link"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func articleGet(w http.ResponseWriter, r *http.Request) {
|
||||||
|
authorId, ok := authorizedSession(r)
|
||||||
|
if !ok {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rawId := r.URL.Query().Get("id")
|
||||||
|
|
||||||
|
if rawId == "" {
|
||||||
|
ApiError{Message: "no id was given", Code: http.StatusBadRequest}.Send(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, err := strconv.Atoi(rawId)
|
||||||
|
if err != nil {
|
||||||
|
ApiError{"invalid 'id' parameter", http.StatusUnprocessableEntity}.Send(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !database.Exists(database.GetDB().Table("article_author"), "author_id=?", authorId) {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var article database.Article
|
||||||
|
if database.GetDB().Table("article").First(&article, id).RowsAffected == 0 {
|
||||||
|
ApiError{Message: "no such id", Code: http.StatusNotFound}.Send(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := getResponse{
|
||||||
|
Title: article.Title,
|
||||||
|
Summary: article.Summary,
|
||||||
|
Image: article.Image,
|
||||||
|
Link: article.Link,
|
||||||
|
Content: base64.StdEncoding.EncodeToString([]byte(article.Markdown)),
|
||||||
|
}
|
||||||
|
database.GetDB().Table("article_author").Select("author_id").Where("article_id", article.Id).Find(&resp.Authors)
|
||||||
|
database.GetDB().Table("article_tag").Select("tag").Where("article_id", article.Id).Find(&resp.Tags)
|
||||||
|
|
||||||
|
json.NewEncoder(w).Encode(resp)
|
||||||
|
}
|
||||||
|
|
||||||
type uploadPayload struct {
|
type uploadPayload struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Summary string `json:"summary"`
|
Summary string `json:"summary"`
|
||||||
@@ -102,7 +156,7 @@ func articlePost(w http.ResponseWriter, r *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
articleSummary.Tags = []string{}
|
articleSummary.Tags = []string{}
|
||||||
}
|
}
|
||||||
articleSummary.Link = path.Join(config.Path, "article", url.PathEscape(articleSummary.Link))
|
articleSummary.Link = path.Join("/", config.SubPath, "article", url.PathEscape(articleSummary.Link))
|
||||||
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
json.NewEncoder(w).Encode(articleSummary)
|
json.NewEncoder(w).Encode(articleSummary)
|
||||||
@@ -216,7 +270,7 @@ func articlePatch(w http.ResponseWriter, r *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
articleSummary.Tags = []string{}
|
articleSummary.Tags = []string{}
|
||||||
}
|
}
|
||||||
articleSummary.Link = path.Join(config.Path, "article", url.PathEscape(articleSummary.Link))
|
articleSummary.Link = path.Join("/", config.SubPath, "article", url.PathEscape(articleSummary.Link))
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(articleSummary)
|
json.NewEncoder(w).Encode(articleSummary)
|
||||||
|
|||||||
@@ -10,6 +10,71 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestArticleGet(t *testing.T) {
|
||||||
|
if err := initTestDatabase("upload_get_test.sqlite3"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
database.GetDB().Table("article").Create([]map[string]interface{}{
|
||||||
|
{
|
||||||
|
"title": "Get test",
|
||||||
|
"summary": "",
|
||||||
|
"created": time.Now().Unix(),
|
||||||
|
"link": "get-test",
|
||||||
|
"markdown": "Testing ._.",
|
||||||
|
"html": "<p>Testing ._.<p>",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
database.GetDB().Table("author").Create([]map[string]interface{}{
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"password": "",
|
||||||
|
"information": "admin",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
database.GetDB().Table("article_author").Create([]map[string]interface{}{
|
||||||
|
{
|
||||||
|
"article_id": 1,
|
||||||
|
"author_id": 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(articleGet))
|
||||||
|
checkTestInformation(t, server.URL, []testInformation{
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Cookie: map[string]string{
|
||||||
|
"session_id": initSession(),
|
||||||
|
},
|
||||||
|
ResultBody: map[string]interface{}{
|
||||||
|
"message": "no id was given",
|
||||||
|
},
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Query: map[string]interface{}{
|
||||||
|
"id": 1,
|
||||||
|
},
|
||||||
|
Cookie: map[string]string{
|
||||||
|
"session_id": initSession(),
|
||||||
|
},
|
||||||
|
ResultBody: getResponse{
|
||||||
|
Title: "Get test",
|
||||||
|
Authors: []int{1},
|
||||||
|
Tags: []string{},
|
||||||
|
Link: "get-test",
|
||||||
|
Content: base64.StdEncoding.EncodeToString([]byte("Testing ._.")),
|
||||||
|
},
|
||||||
|
Code: http.StatusOK,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestArticlePost(t *testing.T) {
|
func TestArticlePost(t *testing.T) {
|
||||||
if err := initTestDatabase("upload_post_test.sqlite3"); err != nil {
|
if err := initTestDatabase("upload_post_test.sqlite3"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func assetsGet(w http.ResponseWriter, r *http.Request) {
|
|||||||
request.Find(&assets)
|
request.Find(&assets)
|
||||||
|
|
||||||
for _, asset := range assets {
|
for _, asset := range assets {
|
||||||
asset.Link = path.Join(config.Path, "assets", asset.Link)
|
asset.Link = path.Join("/", config.SubPath, "assets", asset.Link)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
@@ -101,7 +101,7 @@ func assetsPost(w http.ResponseWriter, r *http.Request) {
|
|||||||
json.NewEncoder(w).Encode(schema.Asset{
|
json.NewEncoder(w).Encode(schema.Asset{
|
||||||
Id: tmpDatabaseSchema.Id,
|
Id: tmpDatabaseSchema.Id,
|
||||||
Name: tmpDatabaseSchema.Name,
|
Name: tmpDatabaseSchema.Name,
|
||||||
Link: path.Join(config.Path, "assets", tmpDatabaseSchema.Link),
|
Link: path.Join("/", config.SubPath, "assets", tmpDatabaseSchema.Link),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func Recent(w http.ResponseWriter, r *http.Request) {
|
|||||||
database.GetDB().Table("author").Where("id IN (?)", database.GetDB().Table("article_author").Select("author_id").Where("article_id = ?", summary.Id)).Find(&summary.Authors)
|
database.GetDB().Table("author").Where("id IN (?)", database.GetDB().Table("article_author").Select("author_id").Where("article_id = ?", summary.Id)).Find(&summary.Authors)
|
||||||
summary.Tags = []string{}
|
summary.Tags = []string{}
|
||||||
database.GetDB().Table("article_tag").Select("tag").Where("article_id = ?", summary.Id).Find(&summary.Tags)
|
database.GetDB().Table("article_tag").Select("tag").Where("article_id = ?", summary.Id).Find(&summary.Tags)
|
||||||
summary.Link = path.Join(config.Path, "article", summary.Link)
|
summary.Link = path.Join("/", config.SubPath, "article", summary.Link)
|
||||||
articleSummaries[i] = summary
|
articleSummaries[i] = summary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func Search(w http.ResponseWriter, r *http.Request) {
|
|||||||
database.GetDB().Table("author").Where("id IN (?)", database.GetDB().Table("article_author").Select("author_id").Where("article_id = ?", summary.Id)).Find(&summary.Authors)
|
database.GetDB().Table("author").Where("id IN (?)", database.GetDB().Table("article_author").Select("author_id").Where("article_id = ?", summary.Id)).Find(&summary.Authors)
|
||||||
summary.Tags = []string{}
|
summary.Tags = []string{}
|
||||||
database.GetDB().Table("article_tag").Select("tag").Where("article_id = ?", summary.Id).Find(&summary.Tags)
|
database.GetDB().Table("article_tag").Select("tag").Where("article_id = ?", summary.Id).Find(&summary.Tags)
|
||||||
summary.Link = path.Join(config.Path, "article", summary.Link)
|
summary.Link = path.Join("/", config.SubPath, "article", summary.Link)
|
||||||
articleSummaries[i] = summary
|
articleSummaries[i] = summary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ func Tags(w http.ResponseWriter, r *http.Request) {
|
|||||||
request := database.GetDB().Table("article_tag")
|
request := database.GetDB().Table("article_tag")
|
||||||
|
|
||||||
if query.Has("name") {
|
if query.Has("name") {
|
||||||
request.Where("name LIKE ?", "%"+query.Get("name")+"%")
|
request.Where("tag LIKE ?", "%"+query.Get("name")+"%")
|
||||||
}
|
}
|
||||||
if query.Has("limit") {
|
if query.Has("limit") {
|
||||||
limit, err := strconv.Atoi(query.Get("limit"))
|
limit, err := strconv.Atoi(query.Get("limit"))
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ var (
|
|||||||
ServerPort string
|
ServerPort string
|
||||||
|
|
||||||
Address string
|
Address string
|
||||||
Path string
|
SubPath string
|
||||||
|
|
||||||
DatabaseFile string
|
DatabaseFile string
|
||||||
FrontendDir string
|
FrontendDir string
|
||||||
@@ -21,7 +21,7 @@ func init() {
|
|||||||
ServerPort = os.Getenv("SERVER_PORT")
|
ServerPort = os.Getenv("SERVER_PORT")
|
||||||
|
|
||||||
Address = os.Getenv("ADDRESS")
|
Address = os.Getenv("ADDRESS")
|
||||||
Path = os.Getenv("Path")
|
SubPath = os.Getenv("SUBPATH")
|
||||||
|
|
||||||
DatabaseFile = os.Getenv("DATABASE_FILE")
|
DatabaseFile = os.Getenv("DATABASE_FILE")
|
||||||
FrontendDir = os.Getenv("FRONTEND_DIR")
|
FrontendDir = os.Getenv("FRONTEND_DIR")
|
||||||
|
|||||||
7
main.go
7
main.go
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,8 +18,8 @@ func main() {
|
|||||||
r.StrictSlash(true)
|
r.StrictSlash(true)
|
||||||
|
|
||||||
var subrouter *mux.Router
|
var subrouter *mux.Router
|
||||||
if config.Path != "/" {
|
if config.SubPath != "" {
|
||||||
subrouter = r.PathPrefix(config.Path).Subrouter()
|
subrouter = r.PathPrefix(config.SubPath).Subrouter()
|
||||||
} else {
|
} else {
|
||||||
subrouter = r
|
subrouter = r
|
||||||
}
|
}
|
||||||
@@ -69,7 +70,7 @@ func setupFrontend(r *mux.Router) {
|
|||||||
r.Path("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
r.Path("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
landingpage.Execute(w, struct {
|
landingpage.Execute(w, struct {
|
||||||
BasePath string
|
BasePath string
|
||||||
}{BasePath: config.Address + config.Path})
|
}{BasePath: config.Address + path.Join("/", config.SubPath)})
|
||||||
})
|
})
|
||||||
|
|
||||||
r.NotFoundHandler = http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
r.NotFoundHandler = http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"TheAdversary/database"
|
"TheAdversary/database"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
@@ -40,7 +41,7 @@ func Article(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
ta := tmplArticle{
|
ta := tmplArticle{
|
||||||
Title: article.Title,
|
Title: article.Title,
|
||||||
BasePath: config.Address + config.Path,
|
BasePath: config.Address + path.Join("/", config.SubPath),
|
||||||
Summary: article.Summary,
|
Summary: article.Summary,
|
||||||
Image: article.Image,
|
Image: article.Image,
|
||||||
Authors: authors,
|
Authors: authors,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ServePath(w http.ResponseWriter, r *http.Request) {
|
func ServePath(w http.ResponseWriter, r *http.Request) {
|
||||||
path := filepath.Join(config.FrontendDir, strings.TrimPrefix(r.URL.Path, config.Path))
|
path := filepath.Join(config.FrontendDir, strings.TrimPrefix(r.URL.Path, config.SubPath))
|
||||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
Error404(w, r)
|
Error404(w, r)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user