diff --git a/.env b/.env index 4bcb8a9..e15f0fe 100644 --- a/.env +++ b/.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 ADDRESS=http://localhost:8080 -# the path you serve on. must be at least a slash -Path=/ +# the path you serve on +SUBPATH= DATABASE_FILE=database.sqlite3 FRONTEND_DIR=./frontend/ diff --git a/api/article.go b/api/article.go index 415cc36..571b57e 100644 --- a/api/article.go +++ b/api/article.go @@ -12,21 +12,75 @@ import ( "net/http" "net/url" "path" + "strconv" "strings" "time" ) func Article(w http.ResponseWriter, r *http.Request) { switch r.Method { - case http.MethodGet: - assetsGet(w, r) case http.MethodPost: - assetsPost(w, r) + articlePost(w, r) 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 { Title string `json:"title"` Summary string `json:"summary"` @@ -102,7 +156,7 @@ func articlePost(w http.ResponseWriter, r *http.Request) { } else { 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) json.NewEncoder(w).Encode(articleSummary) @@ -216,7 +270,7 @@ func articlePatch(w http.ResponseWriter, r *http.Request) { } else { 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) json.NewEncoder(w).Encode(articleSummary) diff --git a/api/article_test.go b/api/article_test.go index 5d18627..b81050b 100644 --- a/api/article_test.go +++ b/api/article_test.go @@ -10,6 +10,71 @@ import ( "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": "

Testing ._.

", + }, + }) + 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) { if err := initTestDatabase("upload_post_test.sqlite3"); err != nil { t.Fatal(err) diff --git a/api/assets.go b/api/assets.go index 394551f..b9c901e 100644 --- a/api/assets.go +++ b/api/assets.go @@ -58,7 +58,7 @@ func assetsGet(w http.ResponseWriter, r *http.Request) { request.Find(&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) @@ -101,7 +101,7 @@ func assetsPost(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(schema.Asset{ Id: tmpDatabaseSchema.Id, Name: tmpDatabaseSchema.Name, - Link: path.Join(config.Path, "assets", tmpDatabaseSchema.Link), + Link: path.Join("/", config.SubPath, "assets", tmpDatabaseSchema.Link), }) } } diff --git a/api/recent.go b/api/recent.go index 5a7a063..4ab71c2 100644 --- a/api/recent.go +++ b/api/recent.go @@ -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) summary.Tags = []string{} 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 } diff --git a/api/search.go b/api/search.go index ba65135..5f96e7c 100644 --- a/api/search.go +++ b/api/search.go @@ -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) summary.Tags = []string{} 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 } diff --git a/api/tags.go b/api/tags.go index 24fc3e8..87a1991 100644 --- a/api/tags.go +++ b/api/tags.go @@ -12,7 +12,7 @@ func Tags(w http.ResponseWriter, r *http.Request) { request := database.GetDB().Table("article_tag") if query.Has("name") { - request.Where("name LIKE ?", "%"+query.Get("name")+"%") + request.Where("tag LIKE ?", "%"+query.Get("name")+"%") } if query.Has("limit") { limit, err := strconv.Atoi(query.Get("limit")) diff --git a/config/config.go b/config/config.go index a178a0d..de4e197 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,7 @@ var ( ServerPort string Address string - Path string + SubPath string DatabaseFile string FrontendDir string @@ -21,7 +21,7 @@ func init() { ServerPort = os.Getenv("SERVER_PORT") Address = os.Getenv("ADDRESS") - Path = os.Getenv("Path") + SubPath = os.Getenv("SUBPATH") DatabaseFile = os.Getenv("DATABASE_FILE") FrontendDir = os.Getenv("FRONTEND_DIR") diff --git a/main.go b/main.go index be54004..a12cca0 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "github.com/gorilla/mux" "html/template" "net/http" + "path" "path/filepath" ) @@ -17,8 +18,8 @@ func main() { r.StrictSlash(true) var subrouter *mux.Router - if config.Path != "/" { - subrouter = r.PathPrefix(config.Path).Subrouter() + if config.SubPath != "" { + subrouter = r.PathPrefix(config.SubPath).Subrouter() } else { subrouter = r } @@ -69,7 +70,7 @@ func setupFrontend(r *mux.Router) { r.Path("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { landingpage.Execute(w, struct { 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) { diff --git a/server/article.go b/server/article.go index 12754a1..2e21051 100644 --- a/server/article.go +++ b/server/article.go @@ -5,6 +5,7 @@ import ( "TheAdversary/database" "github.com/gorilla/mux" "net/http" + "path" "path/filepath" "text/template" "time" @@ -40,7 +41,7 @@ func Article(w http.ResponseWriter, r *http.Request) { ta := tmplArticle{ Title: article.Title, - BasePath: config.Address + config.Path, + BasePath: config.Address + path.Join("/", config.SubPath), Summary: article.Summary, Image: article.Image, Authors: authors, diff --git a/server/path.go b/server/path.go index 9b70807..3e24878 100644 --- a/server/path.go +++ b/server/path.go @@ -9,7 +9,7 @@ import ( ) 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) { Error404(w, r) } else {