package handlers
import (
"errors"
"html/template"
"log"
"net/http"
"net/url"
"time"
"code.revolvingcow.com/revolvingcow/loop/account"
"code.revolvingcow.com/revolvingcow/loop/environment"
"code.revolvingcow.com/revolvingcow/loop/markdown"
"code.revolvingcow.com/revolvingcow/loop/security"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
)
var (
templateWorkspace = template.Must(template.ParseFiles(
"html/loop.html",
"html/workspace.html",
))
store = sessions.NewCookieStore([]byte(environment.Salt()))
)
// WorkspaceModel passes information to the template engine providing context to the web page.
type WorkspaceModel struct {
Username string
Directories []string
Title string
Content string
}
// ContentHandler is the default handler used for user content.
func ContentHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Serving template for the content handler")
session, _ := store.Get(r, "session-account")
account, err := validateCredentials(session)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
directories, _ := account.Content()
model := WorkspaceModel{
Username: account.Username,
Directories: directories,
}
if err := templateWorkspace.Execute(w, model); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
// ContentCreateHandler creates new content in the user context.
func ContentCreateHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Creating new document")
session, _ := store.Get(r, "session-account")
account, err := validateCredentials(session)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
vars := mux.Vars(r)
title := vars["title"]
if title != "" {
title, err = url.QueryUnescape(title)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
account.Add(title, "document.md", []byte{})
} else {
http.Redirect(w, r, account.Username, http.StatusSeeOther)
}
http.Redirect(w, r, "/"+account.Username+"/edit/"+url.QueryEscape(title), http.StatusSeeOther)
}
// ContentReadHandler reads a document in the user context.
func ContentReadHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Reading document")
session, _ := store.Get(r, "session-account")
account, err := validateCredentials(session)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
vars := mux.Vars(r)
title := vars["title"]
if title == "" {
http.Error(w, "No title given", http.StatusInternalServerError)
return
}
title, err = url.QueryUnescape(title)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
contents, err := account.Read(title)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
directories, _ := account.Content()
model := WorkspaceModel{
Username: account.Username,
Directories: directories,
Title: title,
Content: contents,
}
if err := templateWorkspace.Execute(w, model); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
// ContentPreviewHandler displays a Markdown document in HTML format.
func ContentPreviewHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Previewing document")
session, _ := store.Get(r, "session-account")
account, err := validateCredentials(session)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
vars := mux.Vars(r)
title := vars["title"]
title, err = url.QueryUnescape(title)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
contents := r.FormValue("contents")
if contents == "" {
contents, _ = account.Read(title)
}
md := template.HTML(string(markdown.MarkdownToHtml([]byte(contents))))
model := PageBlog{
Title: title,
Published: time.Now().Format("2006-01-02 15:04"),
Body: md,
}
if err := templateArticle.Execute(w, model); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
// ContentUpdateHandler updates content in the user context.
func ContentUpdateHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Updating document")
session, _ := store.Get(r, "session-account")
account, err := validateCredentials(session)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
vars := mux.Vars(r)
title := vars["title"]
if title == "" {
http.Error(w, "No title given", http.StatusInternalServerError)
return
}
title, err = url.QueryUnescape(title)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
contents := r.FormValue("contents")
if contents == "" {
http.Error(w, "No content given", http.StatusInternalServerError)
return
}
account.Add(title, "document.md", []byte(contents))
}
// ContentUploadHandler allows for multiple document uploads in the user context.
func ContentUploadHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Uploading attachment")
}
// ContentDeleteHandler deletes content in the user context.
func ContentDeleteHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Deleting document")
session, _ := store.Get(r, "session-account")
account, err := validateCredentials(session)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
vars := mux.Vars(r)
title := vars["title"]
if title == "" {
http.Error(w, "No title given", http.StatusInternalServerError)
return
}
title, err = url.QueryUnescape(title)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
account.Remove(title)
http.Redirect(w, r, "/"+account.Username, http.StatusSeeOther)
}
// validateCredentials attempts to validate session information.
func validateCredentials(session *sessions.Session) (account.Account, error) {
user := session.Values["username"]
pass := session.Values["passphrase"]
if user == nil || pass == nil {
return account.Account{}, errors.New("No session state")
}
account := account.Account{
Username: user.(string),
Passphrase: security.GeneratePassphrase(user.(string), pass.(string)),
}
valid, err := account.Validate()
if err != nil || !valid {
return account, errors.New("Invalid credentials")
}
return account, nil
}