diff --git a/Database/Post.go b/Database/Post.go index 0c2544b..8b969c9 100644 --- a/Database/Post.go +++ b/Database/Post.go @@ -1,5 +1,7 @@ package Database +import "time" + func GetPostById(id string) (Post, error) { var ( post Post @@ -21,7 +23,24 @@ func GetPostsList(limit int, offset int) ([]Post, error) { ) e = DB.Model(&Post{}). - Order("created_at desc"). + Order("updated_at desc"). + Limit(limit). + Offset(offset). + Find(&posts). + Error + + return posts, e +} + +func GetPostsListBySubject(limit int, offset int, subject string) ([]Post, error) { + var ( + posts []Post + e error + ) + + e = DB.Model(&Post{}). + Where("subject = ?", subject). + Order("updated_at desc"). Limit(limit). Offset(offset). Find(&posts). @@ -30,6 +49,20 @@ func GetPostsList(limit int, offset int) ([]Post, error) { return posts, e } +func GetPostCountBySubject(subject string) (int64, error) { + var ( + count int64 + e error + ) + + e = DB.Model(&Post{}). + Where("subject = ?", subject). + Count(&count). + Error + + return count, e +} + func CreatePost(post Post) error { return DB.Model(&Post{}). Create(&post). @@ -39,3 +72,20 @@ func CreatePost(post Post) error { func UpdatePost(post Post) error { return DB.Save(&post).Error } + +func GetLastUpdatedAt() (time.Time, error) { + var ( + post Post + e error + ) + + e = DB.Model(&Post{}). + Select("updated_at"). + Order("updated_at desc"). + Limit(1). + Offset(0). + First(&post). + Error + + return post.UpdatedAt, e +} diff --git a/Helper/FileHelper.go b/Helper/FileHelper.go index 17fb14d..28cdf55 100644 --- a/Helper/FileHelper.go +++ b/Helper/FileHelper.go @@ -94,3 +94,25 @@ func GetFileContents(path string) (string, error) { // Convert []byte to string and print to screen return string(content), nil } + +func DeleteOldPostFile(title string) error { + var ( + filename, path string + e error + ) + + filename = strings.ReplaceAll(title, " ", "_") + ".gohtml" + + path = filepath.Join( + Variables.ProjectRoot, + "web/posts/", + filename, + ) + + e = os.Remove(path) + if e != nil { + return e + } + + return nil +} diff --git a/Helper/TemplateFormatter.go b/Helper/TemplateFormatter.go new file mode 100644 index 0000000..6aba76e --- /dev/null +++ b/Helper/TemplateFormatter.go @@ -0,0 +1,62 @@ +package Helper + +import ( + "strconv" + "strings" + "time" +) + +func MinusInt64(a, b int64) string { + return strconv.FormatInt(a-b, 10) +} + +func MinusInt(a, b int) string { + return strconv.Itoa(a - b) +} + +func Minus(a, b int) int { + return a - b +} + +func PlusInt64(a, b int64) string { + return strconv.FormatInt(a+b, 10) +} + +func PlusInt(a, b int) string { + return strconv.Itoa(a + b) +} + +func Iterate(count int) []int { + var i int + var Items []int + for i = 0; i < count; i++ { + Items = append(Items, i) + } + return Items +} + +func StrToLower(s string) string { + return strings.ToLower(s) +} + +func FormatTimestamp(t interface{}) string { + var ( + s string + tt time.Time + exists bool + ) + // Check if timestamp is string + s, exists = t.(string) + if exists { + return s + } + // Check if timestamp is time.Time + tt, exists = t.(time.Time) + if !exists || tt.IsZero() { + return "" + } + loc, _ := time.LoadLocation("Australia/Adelaide") + return tt. + In(loc). + Format("02/01/2006 03:04 PM") +} diff --git a/Helper/TimeHelper.go b/Helper/TimeHelper.go deleted file mode 100644 index bf1af4a..0000000 --- a/Helper/TimeHelper.go +++ /dev/null @@ -1,27 +0,0 @@ -package Helper - -import ( - "time" -) - -func FormatTimestamp(t interface{}) string { - var ( - s string - tt time.Time - exists bool - ) - // Check if timestamp is string - s, exists = t.(string) - if exists { - return s - } - // Check if timestamp is time.Time - tt, exists = t.(time.Time) - if !exists || tt.IsZero() { - return "" - } - loc, _ := time.LoadLocation("Australia/Adelaide") - return tt. - In(loc). - Format("02/01/2006 03:04 PM") -} diff --git a/Webserver/Admin.go b/Webserver/Admin.go index 4c516a8..97f9428 100644 --- a/Webserver/Admin.go +++ b/Webserver/Admin.go @@ -322,6 +322,10 @@ func AdminEditPost(w http.ResponseWriter, r *http.Request) { intro = r.FormValue("intro") body = r.FormValue("body") + if title != post.Title { + defer Helper.DeleteOldPostFile(post.Title) + } + bodyPath, e = Helper.WriteBody(title, body) if e != nil { log.Fatal(e) @@ -340,8 +344,6 @@ func AdminEditPost(w http.ResponseWriter, r *http.Request) { Helper.UploadFiles(fileUpload) - fmt.Println(post) - post.Title = title post.Subject = subject post.Intro = intro diff --git a/Webserver/Index.go b/Webserver/Index.go index 7600153..38f355a 100644 --- a/Webserver/Index.go +++ b/Webserver/Index.go @@ -1,7 +1,6 @@ package Webserver import ( - "log" "net/http" "PersonalWebsite/Database" @@ -13,10 +12,11 @@ func ViewIndex(w http.ResponseWriter, r *http.Request) { e error ) - v["SidebarLinks"], e = Database.GetAllSidebarLinks() + v["PageView"] = "index-intro.gohtml" + v["Posts"], e = Database.GetPostsList(5, 0) if e != nil { - // TODO: Handle - log.Fatal(e) + // TODO: Handle this + http.Error(w, "Error", http.StatusInternalServerError) } ServeTemplate(w, r, "html/index.gohtml", v) diff --git a/Webserver/Post.go b/Webserver/Post.go index fb2c301..91cbfbe 100644 --- a/Webserver/Post.go +++ b/Webserver/Post.go @@ -3,6 +3,7 @@ package Webserver import ( "log" "net/http" + "strconv" "PersonalWebsite/Database" @@ -11,6 +12,7 @@ import ( func ViewPost(w http.ResponseWriter, r *http.Request) { var ( + v = make(map[string]interface{}) urlParams map[string]string post Database.Post e error @@ -21,10 +23,79 @@ func ViewPost(w http.ResponseWriter, r *http.Request) { post, e = Database.GetPostById(urlParams["id"]) if e != nil { // TODO: Forward 404 - log.Println("Could not get user") + log.Println("Could not get post") http.Error(w, "Error", http.StatusInternalServerError) return } - log.Println(post) + v["Subject"] = post.Subject + v["PageView"] = "post.gohtml" + v["Post"] = post + + ServeTemplate(w, r, "html/index.gohtml", v) +} + +func ViewPostList(w http.ResponseWriter, r *http.Request, subject string) { + var ( + limit int = 2 + + v = make(map[string]interface{}) + posts []Database.Post + postsCount int64 + pageCount int + keys []string + page int + offset int + x, y int + ok bool + e error + ) + + keys, ok = r.URL.Query()["page"] + + if !ok || len(keys[0]) < 1 { + page = 0 + } else { + page, e = strconv.Atoi(keys[0]) + if e != nil { + // TODO: Handle this + http.Error(w, "Error", http.StatusInternalServerError) + return + } + } + + offset = limit * page + + posts, e = Database.GetPostsListBySubject(limit, offset, subject) + if e != nil { + // TODO: Handle this + http.Error(w, "Error", http.StatusInternalServerError) + return + } + + postsCount, e = Database.GetPostCountBySubject(subject) + if e != nil { + // TODO: Handle this + http.Error(w, "Error", http.StatusInternalServerError) + return + } + + x, y = int(postsCount), limit + pageCount = (x + y - 1) / y + + v["PageView"] = "post-list.gohtml" + v["Subject"] = subject + v["Posts"] = posts + v["Page"] = page + v["PageCount"] = pageCount + + ServeTemplate(w, r, "html/index.gohtml", v) +} + +func ViewPostListProgramming(w http.ResponseWriter, r *http.Request) { + ViewPostList(w, r, "Programming") +} + +func ViewPostListPentesting(w http.ResponseWriter, r *http.Request) { + ViewPostList(w, r, "Pentesting") } diff --git a/Webserver/ServeFile.go b/Webserver/ServeFile.go index f3b215b..9b81784 100644 --- a/Webserver/ServeFile.go +++ b/Webserver/ServeFile.go @@ -1,10 +1,11 @@ package Webserver import ( - "html/template" "net/http" "path" + "text/template" + "PersonalWebsite/Database" "PersonalWebsite/Helper" ) @@ -16,6 +17,10 @@ var ( partials = []string{ "html/header.gohtml", "html/sidebar.gohtml", + "html/index-intro.gohtml", + "html/index-post-list.gohtml", + "html/post-list.gohtml", + "html/post.gohtml", } ) @@ -26,7 +31,20 @@ func ServeTemplate(w http.ResponseWriter, r *http.Request, mainFile string, v ma e error ) - v["test"] = "Yeet" + if _, ok := v["Subject"]; !ok { + v["Subject"] = "" + } + + v["LastUpdatedAt"], e = Database.GetLastUpdatedAt() + if e != nil { + v["LastUpdatedAt"] = " - " + } + + v["SidebarLinks"], e = Database.GetAllSidebarLinks() + if e != nil { + // TODO: Handle + panic(e) + } files = []string{webRootJoin(mainFile)} for _, p := range partials { @@ -36,6 +54,13 @@ func ServeTemplate(w http.ResponseWriter, r *http.Request, mainFile string, v ma tpl, e = template.New(path.Base(files[0])).Funcs( template.FuncMap{ "FormatTimestamp": Helper.FormatTimestamp, + "MinusInt64": Helper.MinusInt64, + "MinusInt": Helper.MinusInt, + "Minus": Helper.MinusInt, + "PlusInt64": Helper.PlusInt64, + "PlusInt": Helper.PlusInt, + "Iterate": Helper.Iterate, + "StrToLower": Helper.StrToLower, }, ).ParseFiles(files...) if e != nil { diff --git a/Webserver/Webserver.go b/Webserver/Webserver.go index 5c4a7b0..5a36e7e 100644 --- a/Webserver/Webserver.go +++ b/Webserver/Webserver.go @@ -58,6 +58,8 @@ func Start() error { // Interface endpoints r.HandleFunc("/", ViewIndex) + r.HandleFunc("/programming", ViewPostListProgramming) + r.HandleFunc("/pentesting", ViewPostListPentesting) r.HandleFunc("/post/{id}", ViewPost) // Administration diff --git a/web/css/admin-new-post.css b/web/css/admin-new-post.css index b13b2d8..32bfcc3 100644 --- a/web/css/admin-new-post.css +++ b/web/css/admin-new-post.css @@ -2,10 +2,16 @@ input, label { display:block; } +label { + padding-top: 0.5em; +} + input, textarea { margin-top: 0.4em; margin-bottom: 1em; width: 100%; } - +input[type=submit] { + height: 2.5em; +} diff --git a/web/css/admin.css b/web/css/admin.css index affd199..92c0277 100644 --- a/web/css/admin.css +++ b/web/css/admin.css @@ -8,6 +8,7 @@ body { padding: 0; margin: 0; font-family: "Montserrat", sans-serif; + min-height: calc(100vh + 8em); } body * { @@ -28,6 +29,7 @@ header { width: 100%; background: #323232; height: 4em; + z-index: 9999; } header h3 { diff --git a/web/css/main.css b/web/css/main.css index 0279ed5..26f0c88 100644 --- a/web/css/main.css +++ b/web/css/main.css @@ -67,6 +67,7 @@ header h2:hover { padding-left: 15px; padding-right: 15px; padding-top: 10px; + margin-right: 20px; -webkit-transition: padding 1s linear, border 0.5s linear; -webkit-transition-timing-function: linear; transition: padding 0.3s linear, border 0.3s linear; @@ -154,9 +155,9 @@ header h2:hover { .main a:hover { color: #0091c9; - text-decoration: underline; } + .main img { max-width: 100%; } @@ -238,6 +239,7 @@ pre::-webkit-scrollbar-color { .post-title { padding: 10px; text-align: center; + font-size: 2em; } .post-icon { @@ -248,6 +250,14 @@ pre::-webkit-scrollbar-color { text-align: center; } +.index-recent-posts { + padding: 0; +} + +.index-recent-post-title-container { + padding-bottom: 1em; +} + .index-recent-posts li { list-style: none; @@ -255,23 +265,36 @@ pre::-webkit-scrollbar-color { -webkit-transition-timing-function: linear; transition: background 0.3s linear; transition-timing-function: linear; - padding: 10px; - margin-bottom: 10px; + padding: 1em; background: rgba(0, 0, 0, 0.65); + margin-bottom: 1.5em; } .index-recent-posts li:hover { background: rgba(0, 0, 0, 0.9); } +.index-recent-posts a:hover { + text-decoration: none; +} + +.index-post-intro * { + color: #ffffff; + margin: 0; +} + .index-recent-posts-title { font-size: 1.3em; + width: 80%; + display: inline; + margin: 0; } .datetimebox { - display: inline-block; + display: inline; float: right; font-size: 0.9em; + margin: 0; } @media all and (max-width : 950px) { diff --git a/web/html/admin/admin-new-post.gohtml b/web/html/admin/admin-new-post.gohtml index 6a07c5e..7139ec1 100644 --- a/web/html/admin/admin-new-post.gohtml +++ b/web/html/admin/admin-new-post.gohtml @@ -25,14 +25,14 @@