sum7/warehost
sum7
/
warehost
Archived
1
0
Fork 0

[TASK] [web] add blog

add blog post + bugfix

add blog on webserver
This commit is contained in:
Martin Geno 2017-02-26 17:02:05 +01:00
parent 4a08e44182
commit 14ff889bba
No known key found for this signature in database
GPG Key ID: F0D39A37E925E941
9 changed files with 385 additions and 24 deletions

View File

@ -5,4 +5,4 @@ webroot: ../../web_webroot/
database: "host=localhost user=warehost dbname=warehost password=hallo sslmode=disable" database: "host=localhost user=warehost dbname=warehost password=hallo sslmode=disable"
log: log:
path: test.log path: test.log
databasedebug: false databasedebug: true

View File

@ -5,11 +5,9 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
"strings"
"text/template" "text/template"
// "github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday"
liblog "dev.sum7.eu/sum7/warehost/lib/log" liblog "dev.sum7.eu/sum7/warehost/lib/log"
web "dev.sum7.eu/sum7/warehost/modul/web" web "dev.sum7.eu/sum7/warehost/modul/web"
) )
@ -63,6 +61,7 @@ func handlerfiles(w http.ResponseWriter, r *http.Request) {
func handlerfunc(w http.ResponseWriter, r *http.Request) { func handlerfunc(w http.ResponseWriter, r *http.Request) {
url := web.FixPath(r.URL.Path[1:]) url := web.FixPath(r.URL.Path[1:])
urlParts := strings.Split(url, "/")
logger := liblog.NewModulLog(r.Host).GetLog(r, url) logger := liblog.NewModulLog(r.Host).GetLog(r, url)
website, err := getWebsite(r.Host) website, err := getWebsite(r.Host)
if err != nil { if err != nil {
@ -82,6 +81,12 @@ func handlerfunc(w http.ResponseWriter, r *http.Request) {
if item.Path == "" && urlObj == nil { if item.Path == "" && urlObj == nil {
urlObj = item urlObj = item
} }
if item.Path == strings.Join(urlParts[0:len(urlParts)-1], "/") && (urlObj == nil || urlObj.Path == "") {
urlObj = item
}
if len(urlParts) > 2 && item.Path == strings.Join(urlParts[0:len(urlParts)-3], "/") && (urlObj == nil || urlObj.Path == "") {
urlObj = item
}
if item.Path == url { if item.Path == url {
urlObj = item urlObj = item
} }
@ -93,12 +98,29 @@ func handlerfunc(w http.ResponseWriter, r *http.Request) {
WebsiteID: website.ID, WebsiteID: website.ID,
URLID: urlObj.ID, URLID: urlObj.ID,
} }
dbconnection.Where(page).FirstOrInit(&page) blog := web.Blog{
if page.ID > 0 { WebsiteID: website.ID,
unsafe := blackfriday.MarkdownCommon([]byte(page.Content)) URLID: urlObj.ID,
//page.Content = string(bluemonday.UGCPolicy().SanitizeBytes(unsafe)) }
page.Content = string(unsafe) blogpost := web.BlogPost{}
if !dbconnection.Where(page).First(&page).RecordNotFound() {
page.URL = urlObj page.URL = urlObj
} else {
if !dbconnection.Where(blog).Preload("Posts").First(&blog).RecordNotFound() {
blogpost.BlogID = blog.ID
if urlObj.Path != blogpost.Title && ((blog.PostURL == 0 && len(urlParts) > 1) || (blog.PostURL == 1 && len(urlParts) > 2)) {
db := dbconnection.Where(blogpost).Where("LOWER(title) = LOWER(?)", urlParts[len(urlParts)-1])
if blog.PostURL == 1 {
db = db.Where("to_char(createat,'YYYY-MM') = ?", strings.Join(urlParts[len(urlParts)-3:len(urlParts)-1], "-"))
}
db.First(&blogpost)
blogpost.Blog = &blog
}
for _, post := range blog.Posts {
post.Blog = &blog
}
blog.URL = urlObj
}
} }
i := TemplateInfo{ i := TemplateInfo{
@ -107,6 +129,8 @@ func handlerfunc(w http.ResponseWriter, r *http.Request) {
URL: url, URL: url,
Menu: menus, Menu: menus,
Page: &page, Page: &page,
Blog: &blog,
BlogPost: &blogpost,
} }
t, err := template.ParseGlob(fmt.Sprintf("%s/%d/%s/%s", config.Webroot, website.ID, "tmpl", "*.tmpl")) t, err := template.ParseGlob(fmt.Sprintf("%s/%d/%s/%s", config.Webroot, website.ID, "tmpl", "*.tmpl"))
logger.Info("done") logger.Info("done")

View File

@ -8,5 +8,7 @@ type TemplateInfo struct {
URL string URL string
Website *modul.Website Website *modul.Website
Page *modul.Page Page *modul.Page
Blog *modul.Blog
BlogPost *modul.BlogPost
Menu []*modul.Menu Menu []*modul.Menu
} }

View File

@ -7,7 +7,7 @@ log:
path: test.log path: test.log
webroot: ./webroot/build webroot: ./webroot/build
database: "host=localhost user=warehost dbname=warehost password=hallo sslmode=disable" database: "host=localhost user=warehost dbname=warehost password=hallo sslmode=disable"
databasedebug: false databasedebug: true
modules: modules:
web: web:
enabled: true enabled: true

View File

@ -43,6 +43,14 @@ func BindAPI(db *gorm.DB, router *goji.Mux, prefix string) {
router.HandleFunc(pat.Post(prefix+"/website/:websiteid/page"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(pageAdd)))) router.HandleFunc(pat.Post(prefix+"/website/:websiteid/page"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(pageAdd))))
router.HandleFunc(pat.Patch(prefix+"/website/:websiteid/page/:pageid"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(pageEdit)))) router.HandleFunc(pat.Patch(prefix+"/website/:websiteid/page/:pageid"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(pageEdit))))
router.HandleFunc(pat.Delete(prefix+"/website/:websiteid/page/:pageid"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(pageDelete)))) router.HandleFunc(pat.Delete(prefix+"/website/:websiteid/page/:pageid"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(pageDelete))))
router.HandleFunc(pat.Get(prefix+"/website/:websiteid/blog"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(blogList))))
router.HandleFunc(pat.Post(prefix+"/website/:websiteid/blog"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(blogAdd))))
router.HandleFunc(pat.Patch(prefix+"/website/:websiteid/blog/:blogid"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(blogEdit))))
router.HandleFunc(pat.Delete(prefix+"/website/:websiteid/blog/:blogid"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(blogDelete))))
router.HandleFunc(pat.Get(prefix+"/website/:websiteid/blog/:blogid"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(blogShow))))
router.HandleFunc(pat.Post(prefix+"/website/:websiteid/blog/:blogid/post"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(blogpostAdd))))
router.HandleFunc(pat.Patch(prefix+"/website/:websiteid/blog/:blogid/post/:blogpostid"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(blogpostEdit))))
router.HandleFunc(pat.Delete(prefix+"/website/:websiteid/blog/:blogid/post/:blogpostid"), libapi.SessionHandler(libsystem.LoginHandler(InvolveWebsiteHandler(blogpostDelete))))
} }
// Involve to get Website where loggend in user has privilegs // Involve to get Website where loggend in user has privilegs

143
modul/web/apiblog.go Normal file
View File

@ -0,0 +1,143 @@
package web
import (
"net/http"
"strconv"
"goji.io/pat"
libapi "dev.sum7.eu/sum7/warehost/lib/api"
)
func getBlog(w http.ResponseWriter, r *http.Request) (blog Blog, returnerr *libapi.ErrorResult) {
ctx := r.Context()
id, err := strconv.ParseInt(pat.Param(r, "blogid"), 10, 64)
if err != nil {
returnerr = &libapi.ErrorResult{Message: "Internal Request Error"}
w.WriteHeader(http.StatusBadRequest)
return
}
blog = Blog{}
dbconnection.Where(map[string]interface{}{"id": id, "website": ctx.Value("websiteid").(int64)}).Preload("URL").Preload("Posts").Find(&blog)
if blog.ID <= 0 {
returnerr = &libapi.ErrorResult{Fields: []string{"blog"}, Message: "not found"}
w.WriteHeader(http.StatusNotFound)
}
return
}
// blogList give all blogs of a website
func blogList(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger := log.GetLog(r, "bloglist")
var blogges []*Blog
dbconnection.Where("website = ?", ctx.Value("websiteid").(int64)).Preload("URL").Find(&blogges)
logger.Info("done")
libapi.JSONWrite(w, r, blogges, nil)
}
func blogShow(w http.ResponseWriter, r *http.Request) {
logger := log.GetLog(r, "blogshow")
blog, returnerr := getBlog(w, r)
if returnerr != nil {
logger.Info("not found")
libapi.JSONWrite(w, r, false, returnerr)
return
}
logger = logger.WithField("bID", blog.ID)
logger.Info("done")
libapi.JSONWrite(w, r, blog, nil)
}
// BlogAdd to add a new blog
func blogAdd(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger := log.GetLog(r, "blogadd")
var blog Blog
returnerr := libapi.JSONDecoder(w, r, logger, &blog)
if returnerr != nil {
libapi.JSONWrite(w, r, false, returnerr)
return
}
blog.WebsiteID = ctx.Value("websiteid").(int64)
blog.URL = &URL{
WebsiteID: ctx.Value("websiteid").(int64),
Path: FixPath(blog.URL.Path),
}
if err := dbconnection.Create(&blog).Error; err != nil {
logger.Error("database: during create blog: ", err)
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Message: "Internal Database Error"})
return
}
logger.Info("done")
libapi.JSONWrite(w, r, true, nil)
}
// BlogEdit to edit blog
func blogEdit(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger := log.GetLog(r, "blogedit")
var blog Blog
blogid, err := strconv.ParseInt(pat.Param(r, "blogid"), 10, 64)
if err != nil {
logger.Warn("invalid blogid, no integer")
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Fields: []string{"blogid"}, Message: "Not a valid blogid"})
return
}
logger = logger.WithField("id", blogid)
returnerr := libapi.JSONDecoder(w, r, logger, &blog)
if returnerr != nil {
libapi.JSONWrite(w, r, false, returnerr)
return
}
blog.ID = blogid
blog.WebsiteID = ctx.Value("websiteid").(int64)
blog.URL.WebsiteID = blog.WebsiteID
blog.URL.Path = FixPath(blog.URL.Path)
tx := dbconnection.Begin()
if err := tx.Save(blog.URL).Error; err != nil {
logger.Error("database: during save website url: ", err)
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Message: "Internal Database Error"})
return
}
blog.URLID = blog.URL.ID
blog.URL = nil
if err := tx.Save(blog).Error; err != nil {
logger.Error("database: during save website blog: ", err)
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Message: "Internal Database Error"})
return
}
tx.Commit()
logger.Info("done")
libapi.JSONWrite(w, r, true, nil)
}
// BlogDelete to delete blog
func blogDelete(w http.ResponseWriter, r *http.Request) {
logger := log.GetLog(r, "blogdelete")
blogid, err := strconv.ParseInt(pat.Param(r, "blogid"), 10, 64)
if err != nil {
logger.Warn("invalid blogid, no integer")
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Fields: []string{"blogid"}, Message: "Not a valid blogid"})
return
}
logger = logger.WithField("id", blogid)
blog := &Blog{}
dbconnection.Where("id = ?", blogid).Preload("URL").First(blog)
if err := dbconnection.Unscoped().Delete(blog.URL).Error; err != nil {
logger.Error("database: during delete website blog: ", err)
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Message: "Internal Database Error"})
return
}
logger.Info("done")
libapi.JSONWrite(w, r, true, nil)
}

114
modul/web/apiblogpost.go Normal file
View File

@ -0,0 +1,114 @@
package web
import (
"net/http"
"strconv"
"goji.io/pat"
libapi "dev.sum7.eu/sum7/warehost/lib/api"
)
// to add a new blog post
func blogpostAdd(w http.ResponseWriter, r *http.Request) {
logger := log.GetLog(r, "blogpostadd")
blog, returnerr := getBlog(w, r)
if returnerr != nil {
logger.Info("not found")
libapi.JSONWrite(w, r, false, returnerr)
return
}
logger = logger.WithField("bID", blog.ID)
var blogpost BlogPost
returnerr = libapi.JSONDecoder(w, r, logger, &blogpost)
if returnerr != nil {
libapi.JSONWrite(w, r, false, returnerr)
return
}
blogpost.BlogID = blog.ID
if blogpost.Preview != nil {
blogpost.PreviewID = &blogpost.Preview.ID
blogpost.Preview = nil
}
if err := dbconnection.Create(&blogpost).Error; err != nil {
logger.Error("database: during create blog: ", err)
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Message: "Internal Database Error"})
return
}
logger.Info("done")
libapi.JSONWrite(w, r, true, nil)
}
// to edit a blog post
func blogpostEdit(w http.ResponseWriter, r *http.Request) {
logger := log.GetLog(r, "blogpostedit")
blog, returnerr := getBlog(w, r)
if returnerr != nil {
logger.Info("not found")
libapi.JSONWrite(w, r, false, returnerr)
return
}
logger = logger.WithField("bID", blog.ID)
blogpostid, err := strconv.ParseInt(pat.Param(r, "blogpostid"), 10, 64)
if err != nil {
logger.Warn("invalid blogpostid, no integer")
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Fields: []string{"blogid"}, Message: "Not a valid blogpostid"})
return
}
logger = logger.WithField("pID", blogpostid)
var blogpost BlogPost
returnerr = libapi.JSONDecoder(w, r, logger, &blogpost)
if returnerr != nil {
libapi.JSONWrite(w, r, false, returnerr)
return
}
blogpost.BlogID = blog.ID
blogpost.ID = blogpostid
if blogpost.Preview != nil {
blogpost.PreviewID = &blogpost.Preview.ID
blogpost.Preview = nil
}
if err := dbconnection.Save(&blogpost).Error; err != nil {
logger.Error("database: during save website blogpost: ", err)
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Message: "Internal Database Error"})
return
}
logger.Info("done")
libapi.JSONWrite(w, r, true, nil)
}
// to delete a blog post
func blogpostDelete(w http.ResponseWriter, r *http.Request) {
logger := log.GetLog(r, "blogpostdelete")
blog, returnerr := getBlog(w, r)
if returnerr != nil {
logger.Info("not found")
libapi.JSONWrite(w, r, false, returnerr)
return
}
logger = logger.WithField("bID", blog.ID)
blogpostid, err := strconv.ParseInt(pat.Param(r, "blogpostid"), 10, 64)
if err != nil {
logger.Warn("invalid blogpostid, no integer")
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Fields: []string{"blogid"}, Message: "Not a valid blogpostid"})
return
}
logger = logger.WithField("pID", blogpostid)
blogpost := &BlogPost{}
dbconnection.Where("blog = ? and id = ?", blog.ID, blogpostid).First(blogpost)
if err := dbconnection.Unscoped().Delete(blogpost).Error; err != nil {
logger.Error("database: during delete website blogpost: ", err)
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Message: "Internal Database Error"})
return
}
logger.Info("done")
libapi.JSONWrite(w, r, true, nil)
}

View File

@ -1,6 +1,10 @@
package web package web
import ( import (
"strconv"
"strings"
"time"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
system "dev.sum7.eu/sum7/warehost/system" system "dev.sum7.eu/sum7/warehost/system"
@ -39,8 +43,8 @@ func (Manager) TableName() string { return "web_manager" }
// Media struct // Media struct
type Media struct { type Media struct {
ID int64 `gorm:"primary_key"` ID int64 `gorm:"primary_key"`
WebsiteID int64 `sql:"type:bigint REFERENCES web_website(id) ON UPDATE CASCADE ON DELETE CASCADE;column:website;primary_key" json:"-"` WebsiteID int64 `sql:"type:bigint REFERENCES web_website(id) ON UPDATE CASCADE ON DELETE CASCADE;column:website;unique_index:media_website_path" json:"-"`
Path string `gorm:"type:varchar(255);column:path" json:"path"` Path string `gorm:"type:varchar(255);column:path;unique_index:media_website_path" json:"path"`
} }
// TableName of struct // TableName of struct
@ -84,6 +88,72 @@ type Page struct {
// TableName of struct // TableName of struct
func (Page) TableName() string { return "web_page" } func (Page) TableName() string { return "web_page" }
// PostURLType of URL Schema on a blog
type PostURLType int
const (
// PostURLDate http(s)://DOMAIN/url/year/month/day/posttitle
PostURLDate = 0
// PostURLTitle http(s)://DOMAIN/url/posttitle
PostURLTitle = 1
)
// Blog struct
type Blog struct {
ID int64 `gorm:"primary_key"`
WebsiteID int64 `sql:"type:bigint REFERENCES web_website(id) ON UPDATE CASCADE ON DELETE CASCADE;column:website" json:"-"`
URLID int64 `sql:"type:bigint unique REFERENCES web_url(id) ON UPDATE CASCADE ON DELETE CASCADE;column:url" json:"-"`
URL *URL `gorm:"foreignkey:URL" json:"url"`
PostURL PostURLType `sql:"type:int;column:posturl" json:"posturl"`
PreviewEnable bool `gorm:"column:preview_enable" json:"preview_enable"`
AuthorEnable bool `gorm:"column:author_enable" json:"author_enable"`
CreateAtEnable bool `gorm:"column:createat_enable" json:"createat_enable"`
TimerangeEnable bool `gorm:"column:timerange_enable" json:"timerange_enable"`
Title string `gorm:"type:varchar(255);column:title" json:"title"`
Content string `gorm:"type:text;column:content" json:"content"`
Posts []*BlogPost `gorm:"foreignkey:Blog" json:"posts"`
}
// TableName of struct
func (Blog) TableName() string { return "web_blog" }
// BlogPost struct
type BlogPost struct {
ID int64 `gorm:"primary_key"`
BlogID int64 `sql:"type:bigint REFERENCES web_blog(id) ON UPDATE CASCADE ON DELETE CASCADE;column:blog" json:"-"`
Blog *Blog `json:"blog"`
CreateAt time.Time `sql:"default:current_timestamp" gorm:"column:createat" json:"createat"`
Author string `gorm:"type:varchar(255);column:author" json:"author"`
Title string `gorm:"type:varchar(255);column:title" json:"title"`
Location string `gorm:"type:varchar(255);column:location" json:"location"`
Start time.Time `gorm:"column:start" json:"start"`
End time.Time `gorm:"column:end" json:"end"`
Link string `gorm:"type:varchar(255);column:link" json:"link"`
PreviewID *int64 `sql:"type:bigint REFERENCES web_media(id) ON UPDATE CASCADE ON DELETE SET NULL;column:preview" json:"-"`
Preview *Media `gorm:"foreignkey:Media" json:"preview"`
Summary string `gorm:"type:text;column:summary" json:"summary"`
Content string `gorm:"type:text;column:content" json:"content"`
}
func (bg *BlogPost) GetURL() string {
var parts []string
if blog := bg.Blog; blog != nil {
parts = append(parts, blog.URL.Path)
if blog.PostURL == 1 {
month := strconv.Itoa(int(bg.CreateAt.Month()))
if len(month) == 1 {
month = "0" + month
}
parts = append(parts, strconv.Itoa(bg.CreateAt.Year()), month)
}
}
parts = append(parts, bg.Title)
return "/" + FixPath(strings.Join(parts, "/"))
}
// TableName of struct
func (BlogPost) TableName() string { return "web_blogpost" }
// BuildMenuTree format a array of Menu to a Tree of Menu (with Children) // BuildMenuTree format a array of Menu to a Tree of Menu (with Children)
func BuildMenuTree(items []*Menu) []*Menu { func BuildMenuTree(items []*Menu) []*Menu {
menumap := make(map[int64]*Menu) menumap := make(map[int64]*Menu)
@ -111,5 +181,5 @@ func BuildMenuTree(items []*Menu) []*Menu {
// SyncModels to verify the database schema // SyncModels to verify the database schema
func SyncModels(dbconnection *gorm.DB) { func SyncModels(dbconnection *gorm.DB) {
dbconnection.AutoMigrate(&Website{}, &Domain{}, &Manager{}, &URL{}, &Media{}, &Menu{}, &Page{}) dbconnection.AutoMigrate(&Website{}, &Domain{}, &Manager{}, &URL{}, &Media{}, &Menu{}, &Page{}, &Blog{}, &BlogPost{})
} }

View File

@ -246,7 +246,7 @@ func loginAdd(w http.ResponseWriter, r *http.Request) {
Active: true, Active: true,
} }
if err := dbconnection.Create(loginObj).Error; err != nil { if err := dbconnection.Create(&loginObj).Error; err != nil {
logger.Warn("error create login") logger.Warn("error create login")
libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Message: "Username exists already"}) libapi.JSONWrite(w, r, false, &libapi.ErrorResult{Message: "Username exists already"})
return return