Skip to content

Commit

Permalink
Merge pull request #347 from compscidr/jason/settings
Browse files Browse the repository at this point in the history
Configurable blog settings
  • Loading branch information
compscidr authored Oct 29, 2024
2 parents 6bbd572 + 3fe1698 commit 378a64c
Show file tree
Hide file tree
Showing 24 changed files with 1,321 additions and 639 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
coverage.txt
articles.json
profiles.json

Expand Down
206 changes: 155 additions & 51 deletions admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,22 @@ var UploadsFolder = "uploads/"

// Admin handles admin requests
type Admin struct {
db *gorm.DB
db **gorm.DB // needs a double pointer to be able to update the db
auth auth.IAuth
b blog.Blog
b *blog.Blog
version string
}

// New constructs an Admin API
func New(db *gorm.DB, auth auth.IAuth, b blog.Blog, version string) Admin {
api := Admin{db, auth, b, version}
func New(db *gorm.DB, auth auth.IAuth, b *blog.Blog, version string) Admin {
api := Admin{&db, auth, b, version}
return api
}

func (a *Admin) UpdateDb(db *gorm.DB) {
a.db = &db
}

// ////JSON API///////
func safeSlug(slug string) string {
slug = strings.ReplaceAll(slug, " ", "-")
Expand All @@ -42,7 +46,7 @@ func safeSlug(slug string) string {
}

// CreatePost adds a post if the user has permission
func (a Admin) CreatePost(c *gin.Context) {
func (a *Admin) CreatePost(c *gin.Context) {
contentType := c.Request.Header.Get("content-type")
if contentType != "application/json" {
c.JSON(http.StatusUnsupportedMediaType, "Expecting application/json")
Expand Down Expand Up @@ -71,15 +75,15 @@ func (a Admin) CreatePost(c *gin.Context) {
//todo: make tags work - need to get the relations working
requestPost.Slug = safeSlug(requestPost.Title)
log.Print("CREATING POST: ", requestPost)
a.db.Create(&requestPost)
(*a.db).Create(&requestPost)

log.Println("POST CREATED: ", requestPost)
c.JSON(http.StatusCreated, requestPost)
}

// UploadFile is the endpoint for storing files on the server
// https://github.com/gin-gonic/examples/blob/master/upload-file/single/main.go
func (a Admin) UploadFile(c *gin.Context) {
func (a *Admin) UploadFile(c *gin.Context) {
log.Println("Upload file API hit")

if !a.auth.IsAdmin(c) {
Expand Down Expand Up @@ -109,7 +113,7 @@ func (a Admin) UploadFile(c *gin.Context) {

// UpdatePost modifies an existing post
// Requires the ID of the post, title and content to not be empty
func (a Admin) UpdatePost(c *gin.Context) {
func (a *Admin) UpdatePost(c *gin.Context) {
contentType := c.Request.Header.Get("content-type")
if contentType != "application/json" {
c.JSON(http.StatusUnsupportedMediaType, "Expecting application/json")
Expand Down Expand Up @@ -138,15 +142,15 @@ func (a Admin) UpdatePost(c *gin.Context) {
requestPost.Slug = safeSlug(requestPost.Slug)

var existingPost blog.Post
err := a.db.Where("id = ?", requestPost.ID).First(&existingPost).Error
err := (*a.db).Where("id = ?", requestPost.ID).First(&existingPost).Error

if err != nil {
c.JSON(http.StatusBadRequest, "Existing post with ID "+fmt.Sprint(requestPost.ID)+" not found")
return
}

//clear old associations
a.db.Model(&existingPost).Association("Tags").Clear()
(*a.db).Model(&existingPost).Association("Tags").Clear()

log.Println("UPDATING DRAFT AS: ", requestPost.Draft)

Expand All @@ -156,19 +160,19 @@ func (a Admin) UpdatePost(c *gin.Context) {
existingPost.Tags = requestPost.Tags
existingPost.CreatedAt = requestPost.CreatedAt
existingPost.Draft = requestPost.Draft
a.db.Model(&existingPost).Where("id = ?", requestPost.ID).Updates(&existingPost)
(*a.db).Model(&existingPost).Where("id = ?", requestPost.ID).Updates(&existingPost)

//https://stackoverflow.com/questions/56653423/gorm-doesnt-update-boolean-field-to-false
if !requestPost.Draft {
a.db.Model(&existingPost).Select("draft").Update("draft", false)
(*a.db).Model(&existingPost).Select("draft").Update("draft", false)
}

log.Println("POST UPDATED: ", existingPost)
c.JSON(http.StatusAccepted, existingPost)
}

// DeletePost deletes a post from the database
func (a Admin) DeletePost(c *gin.Context) {
func (a *Admin) DeletePost(c *gin.Context) {
contentType := c.Request.Header.Get("content-type")
if contentType != "application/json" {
c.JSON(http.StatusUnsupportedMediaType, "Expecting application/json")
Expand All @@ -187,84 +191,182 @@ func (a Admin) DeletePost(c *gin.Context) {
return
}

a.db.Where("id = ?", requestPost.ID).Delete(&blog.Post{})
(*a.db).Where("id = ?", requestPost.ID).Delete(&blog.Post{})

c.JSON(http.StatusOK, "")
}

func (a Admin) PublishPost(c *gin.Context) {
func (a *Admin) PublishPost(c *gin.Context) {
id := c.Param("id")
log.Println("Publishing post: ", id)

var post blog.Post
a.db.Where("id = ?", id).First(&post)
a.db.Model(&post).Select("draft").Update("draft", false)
(*a.db).Where("id = ?", id).First(&post)
(*a.db).Model(&post).Select("draft").Update("draft", false)
c.JSON(http.StatusAccepted, post)
}

func (a Admin) DraftPost(c *gin.Context) {
func (a *Admin) DraftPost(c *gin.Context) {
id := c.Param("id")
log.Println("Drafting post: ", id)
var post blog.Post
a.db.Where("id = ?", id).First(&post)
a.db.Model(&post).Select("draft").Update("draft", true)
(*a.db).Where("id = ?", id).First(&post)
(*a.db).Model(&post).Select("draft").Update("draft", true)
c.JSON(http.StatusAccepted, post)
}

func (a *Admin) AddSetting(c *gin.Context) {
contentType := c.Request.Header.Get("content-type")
if contentType != "application/json" {
c.JSON(http.StatusUnsupportedMediaType, "Expecting application/json")
return
}

if !a.auth.IsAdmin(c) {
log.Println("IS ADMIN RETURNED FALSE")
c.JSON(http.StatusUnauthorized, "Not Authorized")
return
}

var requestSetting blog.Setting
err := c.BindJSON(&requestSetting)
if err != nil {
log.Println("MALFORMED REQ: " + err.Error())
c.JSON(http.StatusBadRequest, "Malformed request")
return
}

if requestSetting.Key == "" {
c.JSON(http.StatusBadRequest, "Missing Key Name for Setting")
return
}

log.Print("CREATING SETTING: ", requestSetting)
(*a.db).Create(&requestSetting)

log.Println("SETTING CREATED: ", requestSetting)
c.JSON(http.StatusCreated, requestSetting)
}

func (a *Admin) UpdateSettings(c *gin.Context) {
contentType := c.Request.Header.Get("content-type")
if contentType != "application/json" {
c.JSON(http.StatusUnsupportedMediaType, "Expecting application/json")
return
}

if !a.auth.IsAdmin(c) {
log.Println("IS ADMIN RETURNED FALSE")
c.JSON(http.StatusUnauthorized, "Not Authorized")
return
}

var requestSettings []blog.Setting
err := c.BindJSON(&requestSettings)
if err != nil {
log.Println("MALFORMED REQ: " + err.Error())
c.JSON(http.StatusBadRequest, "Malformed request")
return
}

for _, setting := range requestSettings {
if setting.Key == "" {
c.JSON(http.StatusBadRequest, "Missing Key Name for Setting")
return
}
(*a.db).Save(&setting)
}
c.JSON(http.StatusAccepted, requestSettings)
}

func (a *Admin) GetSetting(c *gin.Context) {
if !a.auth.IsAdmin(c) {
log.Println("IS ADMIN RETURNED FALSE")
c.JSON(http.StatusUnauthorized, "Not Authorized")
return
}

key := c.Param("key")
log.Println("Getting setting: ", key)

err := (*a.db).Where("key = ?", key).First(&blog.Setting{}).Error
if err != nil {
c.JSON(http.StatusNotFound, "Setting not found")
} else {
c.JSON(http.StatusOK, blog.Setting{})
}
}

func (a *Admin) GetSettings(c *gin.Context) {
if !a.auth.IsAdmin(c) {
log.Println("IS ADMIN RETURNED FALSE")
c.JSON(http.StatusUnauthorized, "Not Authorized")
return
}

settingsMap := a.b.GetSettings()
c.JSON(http.StatusOK, settingsMap)
}

//////HTML API///////

// Admin is the admin dashboard of the website
func (a Admin) Admin(c *gin.Context) {
func (a *Admin) Admin(c *gin.Context) {
c.HTML(http.StatusOK, "admin.html", gin.H{
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"admin_page": true,
"settings": a.b.GetSettings(),
})
}

func (a Admin) AdminDashboard(c *gin.Context) {
func (a *Admin) AdminDashboard(c *gin.Context) {
c.HTML(http.StatusOK, "admin_dashboard.html", gin.H{
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"admin_page": true,
"settings": a.b.GetSettings(),
})
}

func (a Admin) AdminPosts(c *gin.Context) {
func (a *Admin) AdminPosts(c *gin.Context) {
c.HTML(http.StatusOK, "admin_all_posts.html", gin.H{
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"admin_page": true,
"settings": a.b.GetSettings(),
})
}

func (a Admin) AdminNewPost(c *gin.Context) {
func (a *Admin) AdminNewPost(c *gin.Context) {
c.HTML(http.StatusOK, "admin_new_post.html", gin.H{
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"admin_page": true,
"settings": a.b.GetSettings(),
})
}

func (a Admin) AdminSettings(c *gin.Context) {
func (a *Admin) AdminSettings(c *gin.Context) {
c.HTML(http.StatusOK, "admin_settings.html", gin.H{
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"posts": a.b.GetPosts(true),
"logged_in": a.auth.IsLoggedIn(c),
"is_admin": a.auth.IsAdmin(c),
"version": a.version,
"admin_page": true,
"settings": a.b.GetSettings(),
})
}

func (a Admin) Post(c *gin.Context) {
func (a *Admin) Post(c *gin.Context) {
if !a.auth.IsAdmin(c) {
log.Println("IS ADMIN RETURNED FALSE")
c.JSON(http.StatusUnauthorized, "Not Authorized")
Expand All @@ -278,15 +380,17 @@ func (a Admin) Post(c *gin.Context) {
"description": err.Error(),
"version": a.b.Version,
"title": "Post Not Found",
"admin_page": true,
"admin_page": true,
"settings": a.b.GetSettings(),
})
} else {
c.HTML(http.StatusOK, "post-admin.html", gin.H{
"logged_in": a.auth.IsAdmin(c),
"is_admin": a.auth.IsLoggedIn(c),
"post": post,
"version": a.b.Version,
"logged_in": a.auth.IsAdmin(c),
"is_admin": a.auth.IsLoggedIn(c),
"post": post,
"version": a.b.Version,
"admin_page": true,
"settings": a.b.GetSettings(),
})
}
}
2 changes: 1 addition & 1 deletion admin/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestCreatePost(t *testing.T) {
a := &Auth{}
sch := scholar.New("profiles.json", "articles.json")
b := blog.New(db, a, "test", sch)
ad := admin.New(db, a, b, "test")
ad := admin.New(db, a, &b, "test")

router := gin.Default()
store := cookie.NewStore([]byte("changelater"))
Expand Down
Loading

0 comments on commit 378a64c

Please sign in to comment.