Add endpoint to get status as json
This commit is contained in:
parent
087e5a2f4c
commit
003373834f
15 changed files with 221 additions and 101 deletions
2
Makefile
Normal file
2
Makefile
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
build:
|
||||
CGO_ENABLED=0 GOOS=linux go build -o bin/statuscafe main.go
|
||||
|
|
@ -22,7 +22,6 @@ var TplCommonMap = map[string]string{
|
|||
{{ template "content" . }}
|
||||
</main>
|
||||
<footer>
|
||||
This is the footer
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -64,21 +64,26 @@ func New(cfg *config.Config, sess *session.Session, data *storage.Storage) (http
|
|||
}
|
||||
h.initTpl()
|
||||
|
||||
// Index
|
||||
router.HandleFunc("/", h.showIndexView).Methods(http.MethodGet)
|
||||
router.HandleFunc("/login", h.showLoginView).Methods(http.MethodGet)
|
||||
router.HandleFunc("/check-login", h.checkLogin).Methods(http.MethodPost)
|
||||
router.HandleFunc("/register", h.handleRegister)
|
||||
router.HandleFunc("/logout", h.logout).Methods(http.MethodGet)
|
||||
|
||||
//router.HandleFunc("/statuses/new", h.showNewStatusView).Methods(http.MethodGet)
|
||||
router.HandleFunc("/status-new", h.showNewStatusView).Methods(http.MethodGet)
|
||||
router.HandleFunc("/status-save", h.saveStatus).Methods(http.MethodPost)
|
||||
router.HandleFunc("/statuses/{id}/edit", h.showEditStatusView).Methods(http.MethodGet)
|
||||
router.HandleFunc("/statuses/{id}/update", h.updateStatus).Methods(http.MethodPost)
|
||||
//router.HandleFunc("/statuses/{id}/remove", h.handleRemoveStatus)
|
||||
//router.HandleFunc("/status-remove", h.handleRemoveStatus)
|
||||
|
||||
router.PathPrefix("/").Handler(http.FileServer(http.Dir(cfg.AssetsDir)))
|
||||
router.HandleFunc("/users/{user}", h.showUserView).Methods(http.MethodGet)
|
||||
router.HandleFunc("/users/{user}/status.json", h.showUserStatusView).Methods(http.MethodGet)
|
||||
router.PathPrefix("/assets/").Handler(
|
||||
http.StripPrefix("/assets/",
|
||||
http.FileServer(
|
||||
http.Dir(cfg.AssetsDir),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
return router, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,21 +11,50 @@ Are you sure you you want to delete the following status?
|
|||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
{{ end }}`,
|
||||
"create_status": `{{ define "content" }}
|
||||
<h1>New status</h1>
|
||||
{{ if .form.Error }}
|
||||
<p>{{ .form.Error }}</p>
|
||||
{{ end }}
|
||||
{{ if .flash }}
|
||||
<p>{{ .flash }}</p>
|
||||
{{ end }}
|
||||
<form action="/statuses/save" method="post">
|
||||
<div class="field">
|
||||
<input type="text" name="content" placeholder="What's new?" required autofocus />
|
||||
</div>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
{{ end }}`,
|
||||
"create_status": `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>status cafe</title>
|
||||
<meta name="description" content="your friends' updates">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>New status</h1>
|
||||
{{ if .form.Error }}
|
||||
<p>{{ .form.Error }}</p>
|
||||
{{ end }}
|
||||
{{ if .flash }}
|
||||
<p>{{ .flash }}</p>
|
||||
{{ end }}
|
||||
<form action="/status-save?silent=1" method="post" name="update-status">
|
||||
<div class="field">
|
||||
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus></textarea>
|
||||
</div>
|
||||
<br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
</main>
|
||||
</div>
|
||||
<script>
|
||||
document.forms["update-status"].onsubmit = function (event) {
|
||||
event.preventDefault();
|
||||
fetch("/status-save?silent=1", {
|
||||
method: "POST",
|
||||
body: new FormData(document.forms["update-status"])
|
||||
})
|
||||
.then(response => response.ok)
|
||||
.then(submitted => {
|
||||
if (submitted) {
|
||||
window.close()
|
||||
window.location = "/"
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>`,
|
||||
"edit_status": `{{ define "content" }}
|
||||
<h1>Edit status</h1>
|
||||
{{ if .form.Error }}
|
||||
|
|
@ -55,17 +84,18 @@ Are you sure you you want to delete the following status?
|
|||
{{ end }}
|
||||
<form action="/status-save" method="post">
|
||||
<div class="field">
|
||||
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus></textarea>
|
||||
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box; height: 100px;" autofocus></textarea>
|
||||
</div>
|
||||
<br>
|
||||
<input type="submit" value="Submit">
|
||||
<p>Drag to your bookmarks to update from anywhere: <a href="javascript:void(open('https://status.cafe/status-new','status.cafe','resizable,scrollbars,width=360,height=200'))">Set status</a></p>
|
||||
</form>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Status stream</h2>
|
||||
{{ range .statuses }}
|
||||
<article class="status">
|
||||
<div class="username"><a href="/{{ .User }}">{{ .User }}</a>, {{ .TimeAgo }}</div>
|
||||
<div class="username"><a href="/users/{{ .User }}">{{ .User }}</a>, {{ .TimeAgo }}</div>
|
||||
<p>{{ .Content }}</p>
|
||||
</article>
|
||||
{{ end }}
|
||||
|
|
@ -111,5 +141,16 @@ Are you sure you you want to delete the following status?
|
|||
<br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
{{ end }}`,
|
||||
"user": `{{ define "content" }}
|
||||
<section>
|
||||
<h2>{{ .user }}</h2>
|
||||
{{ range .statuses }}
|
||||
<article class="status">
|
||||
<div class="username">{{ .TimeAgo }}</div>
|
||||
<p>{{ .Content }}</p>
|
||||
</article>
|
||||
{{ end }}
|
||||
</section>
|
||||
{{ end }}`,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
{{ template "content" . }}
|
||||
</main>
|
||||
<footer>
|
||||
This is the footer
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,44 @@
|
|||
{{ define "content" }}
|
||||
<h1>New status</h1>
|
||||
{{ if .form.Error }}
|
||||
<p>{{ .form.Error }}</p>
|
||||
{{ end }}
|
||||
{{ if .flash }}
|
||||
<p>{{ .flash }}</p>
|
||||
{{ end }}
|
||||
<form action="/statuses/save" method="post">
|
||||
<div class="field">
|
||||
<input type="text" name="content" placeholder="What's new?" required autofocus />
|
||||
</div>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
{{ end }}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>status cafe</title>
|
||||
<meta name="description" content="your friends' updates">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>New status</h1>
|
||||
{{ if .form.Error }}
|
||||
<p>{{ .form.Error }}</p>
|
||||
{{ end }}
|
||||
{{ if .flash }}
|
||||
<p>{{ .flash }}</p>
|
||||
{{ end }}
|
||||
<form action="/status-save?silent=1" method="post" name="update-status">
|
||||
<div class="field">
|
||||
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus></textarea>
|
||||
</div>
|
||||
<br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
</main>
|
||||
</div>
|
||||
<script>
|
||||
document.forms["update-status"].onsubmit = function (event) {
|
||||
event.preventDefault();
|
||||
fetch("/status-save?silent=1", {
|
||||
method: "POST",
|
||||
body: new FormData(document.forms["update-status"])
|
||||
})
|
||||
.then(response => response.ok)
|
||||
.then(submitted => {
|
||||
if (submitted) {
|
||||
window.close()
|
||||
window.location = "/"
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -10,17 +10,18 @@
|
|||
{{ end }}
|
||||
<form action="/status-save" method="post">
|
||||
<div class="field">
|
||||
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box;" autofocus></textarea>
|
||||
<textarea name="content" placeholder="What's new?" required style="width: 100%; box-sizing: border-box; height: 100px;" autofocus></textarea>
|
||||
</div>
|
||||
<br>
|
||||
<input type="submit" value="Submit">
|
||||
<p>Drag to your bookmarks to update from anywhere: <a href="javascript:void(open('https://status.cafe/status-new','status.cafe','resizable,scrollbars,width=360,height=200'))">Set status</a></p>
|
||||
</form>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Status stream</h2>
|
||||
{{ range .statuses }}
|
||||
<article class="status">
|
||||
<div class="username"><a href="/{{ .User }}">{{ .User }}</a>, {{ .TimeAgo }}</div>
|
||||
<div class="username"><a href="/users/{{ .User }}">{{ .User }}</a>, {{ .TimeAgo }}</div>
|
||||
<p>{{ .Content }}</p>
|
||||
</article>
|
||||
{{ end }}
|
||||
|
|
|
|||
11
web/handler/html/user.html
Normal file
11
web/handler/html/user.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{{ define "content" }}
|
||||
<section>
|
||||
<h2>{{ .user }}</h2>
|
||||
{{ range .statuses }}
|
||||
<article class="status">
|
||||
<div class="username">{{ .TimeAgo }}</div>
|
||||
<p>{{ .Content }}</p>
|
||||
</article>
|
||||
{{ end }}
|
||||
</section>
|
||||
{{ end }}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
|
@ -11,11 +10,6 @@ type Update struct {
|
|||
}
|
||||
|
||||
func (h *Handler) showIndexView(w http.ResponseWriter, r *http.Request) {
|
||||
user, err := h.getUser(r)
|
||||
if err != nil {
|
||||
unauthorized(w)
|
||||
return
|
||||
}
|
||||
statuses, err := h.storage.LatestStatuses()
|
||||
if err != nil {
|
||||
serverError(w, err)
|
||||
|
|
@ -31,7 +25,6 @@ func (h *Handler) showIndexView(w http.ResponseWriter, r *http.Request) {
|
|||
flash = flashes[0].(string)
|
||||
}
|
||||
session.Save(r, w)
|
||||
fmt.Println(user)
|
||||
h.renderLayout(w, "index", map[string]interface{}{
|
||||
"statuses": statuses,
|
||||
"flash": flash,
|
||||
|
|
|
|||
|
|
@ -112,6 +112,6 @@ func (h *Handler) register(w http.ResponseWriter, r *http.Request) {
|
|||
serverError(w, err)
|
||||
return
|
||||
}
|
||||
h.renderLayout(w, "index", nil, user.Name)
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,10 @@ package handler
|
|||
import "net/http"
|
||||
|
||||
func (h *Handler) showNewStatusView(w http.ResponseWriter, r *http.Request) {
|
||||
user, err := h.getUser(r)
|
||||
_, err := h.getUser(r)
|
||||
if err != nil {
|
||||
unauthorized(w)
|
||||
return
|
||||
}
|
||||
session, err := h.sess.Store.Get(r, "ichi")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
flash := ""
|
||||
if flashes := session.Flashes(); len(flashes) > 0 {
|
||||
flash = flashes[0].(string)
|
||||
}
|
||||
session.Save(r, w)
|
||||
h.renderLayout(w, "create_status", map[string]interface{}{
|
||||
"flash": flash,
|
||||
}, user)
|
||||
h.view("create_status").Execute(w, nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,9 @@ func RouteInt64Param(r *http.Request, param string) int64 {
|
|||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
if value < 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,16 +28,18 @@ func (h *Handler) saveStatus(w http.ResponseWriter, r *http.Request) {
|
|||
serverError(w, err)
|
||||
return
|
||||
}
|
||||
session, err := h.sess.Store.Get(r, "ichi")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
if r.URL.Query().Get("silent") != "1" {
|
||||
session, err := h.sess.Store.Get(r, "ichi")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
session.AddFlash("Status updated!")
|
||||
err = session.Save(r, w)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
session.AddFlash("Status updated!")
|
||||
err = session.Save(r, w)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
|
|
|
|||
52
web/handler/user_view.go
Normal file
52
web/handler/user_view.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gorilla/mux"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (h *Handler) showUserView(w http.ResponseWriter, r *http.Request) {
|
||||
user := mux.Vars(r)["user"]
|
||||
if !h.storage.UserExists(user) {
|
||||
notFound(w)
|
||||
return
|
||||
}
|
||||
statuses, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 20, 0)
|
||||
if err != nil {
|
||||
serverError(w, err)
|
||||
return
|
||||
}
|
||||
h.renderLayout(w, "user", map[string]interface{}{
|
||||
"user": user,
|
||||
"statuses": statuses,
|
||||
}, "")
|
||||
}
|
||||
|
||||
type statusjson struct {
|
||||
Author string `json:"author"`
|
||||
Content string `json:"content"`
|
||||
TimeAgo string `json:"time_ago"`
|
||||
}
|
||||
|
||||
func (h *Handler) showUserStatusView(w http.ResponseWriter, r *http.Request) {
|
||||
user := mux.Vars(r)["user"]
|
||||
if !h.storage.UserExists(user) {
|
||||
notFound(w)
|
||||
return
|
||||
}
|
||||
statuses, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 1, 0)
|
||||
if err != nil {
|
||||
serverError(w, err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var res statusjson
|
||||
if len(statuses) > 0 {
|
||||
res.Author = statuses[0].User
|
||||
res.Content = statuses[0].Content
|
||||
res.TimeAgo = statuses[0].TimeAgo()
|
||||
}
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
||||
50
web/web.go
50
web/web.go
|
|
@ -10,15 +10,15 @@ import (
|
|||
"status/web/session"
|
||||
)
|
||||
|
||||
func httpToHTTPSHandler() *http.ServeMux {
|
||||
handleRedirect := func(w http.ResponseWriter, r *http.Request) {
|
||||
newURI := "https://" + r.Host + r.URL.String()
|
||||
http.Redirect(w, r, newURI, http.StatusFound)
|
||||
}
|
||||
mux := &http.ServeMux{}
|
||||
mux.HandleFunc("/", handleRedirect)
|
||||
return mux
|
||||
}
|
||||
//func httpToHTTPSHandler() *http.ServeMux {
|
||||
// handleRedirect := func(w http.ResponseWriter, r *http.Request) {
|
||||
// newURI := "https://" + r.Host + r.URL.String()
|
||||
// http.Redirect(w, r, newURI, http.StatusFound)
|
||||
// }
|
||||
// mux := &http.ServeMux{}
|
||||
// mux.HandleFunc("/", handleRedirect)
|
||||
// return mux
|
||||
//}
|
||||
|
||||
func Serve(data *storage.Storage, cfg *config.Config) error {
|
||||
var err error
|
||||
|
|
@ -27,21 +27,21 @@ func Serve(data *storage.Storage, cfg *config.Config) error {
|
|||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
switch cfg.Env {
|
||||
case "PROD":
|
||||
go func() {
|
||||
fmt.Printf("Starting HTTP server on :443\n")
|
||||
err := http.ListenAndServeTLS(":443", cfg.CertFile, cfg.KeyFile, s)
|
||||
if err != nil {
|
||||
log.Fatalf("httpsSrv.ListendAndServeTLS() failed with %s", err)
|
||||
}
|
||||
}()
|
||||
fmt.Printf("Starting HTTP to HTTPS server on :80\n")
|
||||
err = http.ListenAndServe(":80", httpToHTTPSHandler())
|
||||
break
|
||||
default:
|
||||
fmt.Printf("Starting HTTP server on port 8000\n")
|
||||
err = http.ListenAndServe(":8000", s)
|
||||
}
|
||||
//switch cfg.Env {
|
||||
//case "PROD":
|
||||
// go func() {
|
||||
// fmt.Printf("Starting HTTP server on :443\n")
|
||||
// err := http.ListenAndServeTLS(":443", cfg.CertFile, cfg.KeyFile, s)
|
||||
// if err != nil {
|
||||
// log.Fatalf("httpsSrv.ListendAndServeTLS() failed with %s", err)
|
||||
// }
|
||||
// }()
|
||||
// fmt.Printf("Starting HTTP to HTTPS server on :80\n")
|
||||
// err = http.ListenAndServe(":80", httpToHTTPSHandler())
|
||||
// break
|
||||
//default:
|
||||
fmt.Printf("Starting HTTP server on port 8000\n")
|
||||
err = http.ListenAndServe(":8000", s)
|
||||
//}
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue