~m15o/riku

2e6d702583fc5e23e17e81390343557403d2d497 — m15o 2 years ago 398aa57
Update footer
20 files changed, 115 insertions(+), 129 deletions(-)

M assets/static_stylesheet.go
M assets/style.css
M bin/riku
D mailer/mailer.go
R model/{request.go => response.go}
R storage/{request.go => response.go}
M storage/sql.go
M storage/sql/schema_version_1.sql
M web/handler/feed_show.go
M web/handler/handler.go
M web/handler/html.go
M web/handler/html/index.html
M web/handler/html/manual.html
M web/handler/html/response.html
M web/handler/html/responses.html
M web/handler/response_list.go
M web/handler/response_move_archive.go
M web/handler/response_move_inbox.go
R web/handler/{request_remove.go => response_remove.go}
R web/handler/{request_submit.go => response_submit.go}
M assets/static_stylesheet.go => assets/static_stylesheet.go +5 -0
@@ 266,5 266,10 @@ dd {
.response {
	display: flex;
	justify-content: space-between;
}

footer {
	border-top: 2px solid palevioletred;
	margin-top: 1em;
}`,
}

M assets/style.css => assets/style.css +5 -0
@@ 261,4 261,9 @@ dd {
.response {
	display: flex;
	justify-content: space-between;
}

footer {
	border-top: 2px solid palevioletred;
	margin-top: 1em;
}
\ No newline at end of file

M bin/riku => bin/riku +0 -0
D mailer/mailer.go => mailer/mailer.go +0 -29
@@ 1,29 0,0 @@
package mailer

import (
	"riku/model"
)

func Notify(email string, r model.Request) error {
	return nil
	//from := "m15o@posteo.net"
	//
	//user := "8481258e-e868-4569-ae04-a0a745cc185c"
	//password := "8481258e-e868-4569-ae04-a0a745cc185c"
	//
	//to := []string{
	//	email,
	//}
	//
	//addr := "smtp.postmarkapp.com:2525"
	//host := "smtp.postmarkapp.com"
	//
	//msg := []byte("From: m15o@posteo.net\r\n" +
	//	"To: " + "email" + "\r\n" +
	//	"Subject: " + "[" + r.Tag + "]" + " New request\r\n\r\n" +
	//	r.Data + "\r\n")
	//
	//auth := smtp.PlainAuth("", user, password, host)
	//
	//return smtp.SendMail(addr, auth, from, to, msg)
}

R model/request.go => model/response.go +3 -3
@@ 6,16 6,16 @@ import (
	"time"
)

type Request struct {
type Response struct {
	Id        int64
	CreatedAt time.Time
	Closed    bool
	Archived  bool
	Label     string
	Data      string
	Referer   string
}

func (r Request) Form() map[string][]string {
func (r Response) Form() map[string][]string {
	var rv map[string][]string
	if err := json.Unmarshal([]byte(r.Data), &rv); err != nil {
		fmt.Println(err)

R storage/request.go => storage/response.go +24 -24
@@ 18,12 18,12 @@ func (s *Storage) Save(userId int64, referer, label, data string) error {
	return err
}

func populateRequest(rows *sql.Rows) (model.Request, error) {
	var rv model.Request
func populateResponse(rows *sql.Rows) (model.Response, error) {
	var rv model.Response
	err := rows.Scan(
		&rv.Id,
		&rv.CreatedAt,
		&rv.Closed,
		&rv.Archived,
		&rv.Label,
		&rv.Data,
		&rv.Referer,


@@ 31,7 31,7 @@ func populateRequest(rows *sql.Rows) (model.Request, error) {
	return rv, err
}

func (s *Storage) Responses(userId int64, label string, closed bool) ([]model.Request, error) {
func (s *Storage) Responses(userId int64, label string, archived bool) ([]model.Response, error) {
	if label == "" {
		label = "%"
	}


@@ 39,7 39,7 @@ func (s *Storage) Responses(userId int64, label string, closed bool) ([]model.Re
        SELECT
            id,
            created_at,
            closed,
            archived,
		    label,
            data,
            referer


@@ 47,18 47,18 @@ func (s *Storage) Responses(userId int64, label string, closed bool) ([]model.Re
        WHERE
            user_id=$1
            AND label LIKE $2
            AND closed=$3
            AND archived=$3
        ORDER BY created_at DESC
    `, userId, label, closed)
    `, userId, label, archived)

	if err != nil {
		return nil, err
	}

	var requests []model.Request
	var requests []model.Response

	for rows.Next() {
		r, err := populateRequest(rows)
		r, err := populateResponse(rows)

		if err != nil {
			return requests, err


@@ 70,14 70,14 @@ func (s *Storage) Responses(userId int64, label string, closed bool) ([]model.Re
	return requests, nil
}

func (s *Storage) ResponseById(userId, requestId int64) (model.Request, error) {
	var rv model.Request
func (s *Storage) ResponseById(userId, requestId int64) (model.Response, error) {
	var rv model.Response

	rows, err := s.db.Query(`
        SELECT
            id,
            created_at,
            closed,
            archived,
		    label,
            data,
		   referer


@@ 92,7 92,7 @@ func (s *Storage) ResponseById(userId, requestId int64) (model.Request, error) {
	}

	for rows.Next() {
		rv, err = populateRequest(rows)
		rv, err = populateResponse(rows)

		if err != nil {
			return rv, err


@@ 102,12 102,12 @@ func (s *Storage) ResponseById(userId, requestId int64) (model.Request, error) {
	return rv, nil
}

func (s *Storage) AllResponses(userId int64) ([]model.Request, error) {
func (s *Storage) AllResponses(userId int64) ([]model.Response, error) {
	rows, err := s.db.Query(`
        SELECT
            id,
            created_at,
            closed,
            archived,
		    label,
            data,
            referer


@@ 121,10 121,10 @@ func (s *Storage) AllResponses(userId int64) ([]model.Request, error) {
		return nil, err
	}

	var requests []model.Request
	var requests []model.Response

	for rows.Next() {
		r, err := populateRequest(rows)
		r, err := populateResponse(rows)

		if err != nil {
			return requests, err


@@ 136,10 136,10 @@ func (s *Storage) AllResponses(userId int64) ([]model.Request, error) {
	return requests, nil
}

func (s *Storage) Close(requestId, userId int64) error {
func (s *Storage) MoveToArchive(requestId, userId int64) error {
	query := `
        UPDATE requests
        SET closed=true
        SET archived=true
        WHERE id=$1 AND user_id=$2
    `



@@ 148,10 148,10 @@ func (s *Storage) Close(requestId, userId int64) error {
	return err
}

func (s *Storage) Open(requestId, userId int64) error {
func (s *Storage) MoveToInbox(requestId, userId int64) error {
	query := `
        UPDATE requests
        SET closed=false
        SET archived=false
        WHERE id=$1 AND user_id=$2
    `



@@ 171,13 171,13 @@ func (s *Storage) Remove(requestId, userId int64) error {
	return err
}

func (s *Storage) Labels(userId int64, closed bool) ([]string, error) {
func (s *Storage) Labels(userId int64, archived bool) ([]string, error) {
	rows, err := s.db.Query(`
        SELECT
            DISTINCT label
        FROM requests
        WHERE user_id=$1 AND closed=$2
    `, userId, closed)
        WHERE user_id=$1 AND archived=$2
    `, userId, archived)

	if err != nil {
		return nil, err

M storage/sql.go => storage/sql.go +1 -1
@@ 16,7 16,7 @@ create table users (
create table requests (
    id integer not null,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    closed bool not null default false,
    archived bool not null default false,
    user_id integer not null references users(id),
    label varchar(50) not null default '',
    data text not null default '',

M storage/sql/schema_version_1.sql => storage/sql/schema_version_1.sql +1 -1
@@ 11,7 11,7 @@ create table users (
create table requests (
    id integer not null,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    closed bool not null default false,
    archived bool not null default false,
    user_id integer not null references users(id),
    label varchar(50) not null default '',
    data text not null default '',

M web/handler/feed_show.go => web/handler/feed_show.go +1 -1
@@ 60,7 60,7 @@ func Time(t time.Time) TimeStr {
	return TimeStr(t.Format("2006-01-02T15:04:05-07:00"))
}

func createAtomEntryFromResponse(response model.Request) *Entry {
func createAtomEntryFromResponse(response model.Response) *Entry {
	title := fmt.Sprintf("Response %d", response.Id)
	if response.Label != "" {
		title = fmt.Sprintf("[%s] %s", response.Label, title)

M web/handler/handler.go => web/handler/handler.go +25 -7
@@ 16,8 16,8 @@ type handler struct {
	session *session.Manager
}

func list(closed, label string) string {
	return fmt.Sprintf("/?label=%s&closed=%s", label, closed)
func list(archived, label string) string {
	return fmt.Sprintf("/?label=%s&archived=%s", label, archived)
}

func serverError(w http.ResponseWriter, err error) {


@@ 25,6 25,10 @@ func serverError(w http.ResponseWriter, err error) {
	http.Error(w, fmt.Sprintf("server error: %s", err), http.StatusInternalServerError)
}

func forbidden(w http.ResponseWriter) {
	http.Error(w, "Forbidden", http.StatusForbidden)
}

func (h *handler) handleSessionMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		user, _ := h.session.GetUser(r)


@@ 39,6 43,17 @@ func (h *handler) handleSessionMiddleware(next http.Handler) http.Handler {
	})
}

func (h *handler) protect(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		user := request.GetUserContextKey(r)
		if user.Name == "" {
			forbidden(w)
			return
		}
		fn(w, r)
	}
}

func New(store *storage.Storage, s *session.Manager) http.Handler {
	router := mux.NewRouter()



@@ 51,20 66,23 @@ func New(store *storage.Storage, s *session.Manager) http.Handler {

	router.Use(h.handleSessionMiddleware)

	// Unprotected routes
	router.HandleFunc("/style.css", h.showStylesheet).Methods(http.MethodGet)
	router.HandleFunc("/login", h.showLoginView).Methods(http.MethodGet)
	router.HandleFunc("/login", h.checkLogin).Methods(http.MethodPost)
	router.HandleFunc("/register", h.showRegisterView).Methods(http.MethodGet)
	router.HandleFunc("/register", h.register).Methods(http.MethodPost)
	router.HandleFunc("/submit", h.submitRequest).Methods(http.MethodPost)
	router.HandleFunc("/close", h.moveResponseToArchive).Methods(http.MethodGet)
	router.HandleFunc("/open", h.moveResponseToInbox).Methods(http.MethodGet)
	router.HandleFunc("/", h.responseList).Methods(http.MethodGet)
	router.HandleFunc("/delete", h.removeRequest).Methods(http.MethodGet)
	router.HandleFunc("/delete", h.removeResponse).Methods(http.MethodGet)
	router.HandleFunc("/logout", h.logout).Methods(http.MethodGet)
	router.HandleFunc("/thank-you", h.showThankYouView).Methods(http.MethodGet)
	router.HandleFunc("/manual", h.showManualView).Methods(http.MethodGet)
	router.HandleFunc("/response", h.showResponseView).Methods(http.MethodGet)

	// Protected routes
	router.HandleFunc("/submit", h.protect(h.submitResponse)).Methods(http.MethodPost)
	router.HandleFunc("/move-to-archive", h.protect(h.moveResponseToArchive)).Methods(http.MethodGet)
	router.HandleFunc("/move-to-inbox", h.protect(h.moveResponseToInbox)).Methods(http.MethodGet)
	router.HandleFunc("/response", h.protect(h.showResponseView)).Methods(http.MethodGet)
	router.HandleFunc("/feed.atom", h.showFeedView).Methods(http.MethodGet)

	return router

M web/handler/html.go => web/handler/html.go +19 -20
@@ 8,7 8,7 @@ var TplMap = map[string]string{
{{ define "content" }}
<h1>Collect responses from HTML forms</h1>

<p>Riku lets you collect responses from forms on your site. Forms to:</p>
<p>Riku is a free and open-source software that lets you collect responses from forms on your site. Forms to:</p>

<ul>
    <li>Send you a comment</li>


@@ 30,13 30,12 @@ var TplMap = map[string]string{

<p>
    <a href="/register">Register</a><br>
    <a href="/manual">Read the manual</a>
    <a href="">Source code</a>
</p>
<!--<form action="https://riku.miso.town/submit?user_id=1&label=riku" method="post">-->
<!--    <label for="email">Email:</label>-->
<!--    <input type="email" name="email" id="email" required>-->
<!--    <input type="submit" value="submit">-->
<!--</form>-->

<p>Questions? Send me an email at m15o at posteo dot net</p>

<p><a href="/manual">Want to learn more? Read the manual!</a></p>
{{ end }}`,
	"login": `{{ define "title" }}Login{{ end }}



@@ 73,17 72,17 @@ var TplMap = map[string]string{

  &lt;div class=&quot;field&quot;&gt;
    &lt;label for=&quot;name&quot;&gt;Name&lt;/label&gt;
    &lt;input type=&quot;text&quot; name=&quot;name&quot; required&gt;
    &lt;input type=&quot;text&quot; name=&quot;name&quot; id="name" required&gt;
  &lt;/div&gt;

  &lt;div class=&quot;field&quot;&gt;
    &lt;label for=&quot;email&quot;&gt;Email (optional)&lt;/label&gt;
    &lt;input type=&quot;email&quot; name=&quot;email&quot;&gt;
    &lt;input type=&quot;email&quot; name=&quot;email&quot; id="email"&gt;
  &lt;/div&gt;

  &lt;div class=&quot;field&quot;&gt;
    &lt;label for=&quot;message&quot;&gt;Message&lt;/label&gt;
    &lt;textarea name=&quot;message&quot; style=&quot;height: 200px;&quot; required&gt;&lt;/textarea&gt;
    &lt;textarea name=&quot;message&quot; style=&quot;height: 200px;&quot; id="message" required&gt;&lt;/textarea&gt;
  &lt;/div&gt;

  &lt;input type=&quot;submit&quot; value=&quot;Submit&quot;&gt;


@@ 156,11 155,11 @@ var TplMap = map[string]string{
`,
	"response": `{{ define "content" }}
<nav class="tabs">
    <a href="/?closed=false" {{ if not .response.Closed }}class="selected"{{ end }}>inbox</a> <a href="/?closed=true" {{ if .response.Closed }}class="selected"{{ end }}>archive</a>
    <a href="/" {{ if not .response.Archived }}class="selected"{{ end }}>inbox</a> <a href="/?archived=true" {{ if .response.Archived }}class="selected"{{ end }}>archive</a>
</nav>

<nav class="breadcrumb">
    <a href="/?closed={{ .response.Closed }}">{{ if .response.Closed }}archive{{ else }}inbox{{ end }}</a> › Response #{{ .response.Id }}
    <a href="/?archived={{ .response.Archived }}">{{ if .response.Archived }}archive{{ else }}inbox{{ end }}</a> › Response #{{ .response.Id }}
</nav>

<h1>Response #{{ .response.Id }}</h1>


@@ 182,13 181,13 @@ var TplMap = map[string]string{
</table>

<div class="actions">
    {{ if .response.Closed }}
        <form action="/open" method="get" class="action">
    {{ if .response.Archived }}
        <form action="/move-to-inbox" method="get" class="action">
            <input type="hidden" name="id" value="{{ .response.Id }}">
            <input type="submit" value="move to inbox">
        </form>
    {{ else }}
        <form action="/close" method="get" class="action">
        <form action="/move-to-archive" method="get" class="action">
            <input type="hidden" name="id" value="{{ .response.Id }}">
            <input type="submit" value="move to archive">
        </form>


@@ 196,7 195,7 @@ var TplMap = map[string]string{

    <form action="/delete" method="get" class="action">
        <input type="hidden" name="id" value="{{ .response.Id }}">
        <input type="hidden" name="closed" value="{{ .response.Closed }}">
        <input type="hidden" name="archived" value="{{ .response.Archived }}">
        <input type="submit" value="delete">
    </form>
</div>


@@ 218,10 217,10 @@ var TplMap = map[string]string{
	"responses": `{{ define "content" }}

<nav class="tabs">
    <a href="?closed=false" {{ if not .closed }}class="selected"{{ end }}>inbox</a> <a href="?closed=true" {{ if .closed }}class="selected"{{ end }}>archive</a>
    <a href="/" {{ if not .archived }}class="selected"{{ end }}>inbox</a> <a href="/?archived=true" {{ if .archived }}class="selected"{{ end }}>archive</a>
</nav>

{{ if not .closed }}
{{ if not .archived }}
<h1>Inbox</h1>
<div class="info"><p>POST to https://riku.miso.town/submit?user_id={{ .logged.Id }}</p></div>
{{ else }}


@@ 232,7 231,7 @@ var TplMap = map[string]string{

{{ if gt (len .labels) 1 }}
<p>
    <a href="/?closed={{ .closed }}">all</a>{{ range .labels }} {{ if eq . $.label }}{{ . }}{{ else }}<a href="?label={{ . }}&closed={{ $.closed }}">{{ . }}</a>{{ end }}{{ end }}
    <a href="/?archived={{ .archived }}">all</a>{{ range .labels }} {{ if eq . $.label }}{{ . }}{{ else }}<a href="?label={{ . }}&archived={{ $.archived }}">{{ . }}</a>{{ end }}{{ end }}
</p>
{{ end }}



@@ 245,7 244,7 @@ var TplMap = map[string]string{
            <div class="response">
                <a href="/response?id={{ .Id }}">Response #{{ .Id }}</a>
                {{ if .Label }}
                <a href="?label={{ .Label }}&closed={{ $.closed }}">{{ .Label }}</a>
                <a href="?label={{ .Label }}&archived={{ $.archived }}">{{ .Label }}</a>
                {{ end }}
            </div>
        </td>

M web/handler/html/index.html => web/handler/html/index.html +6 -7
@@ 3,7 3,7 @@
{{ define "content" }}
<h1>Collect responses from HTML forms</h1>

<p>Riku lets you collect responses from forms on your site. Forms to:</p>
<p>Riku is a free and open-source software that lets you collect responses from forms on your site. Forms to:</p>

<ul>
    <li>Send you a comment</li>


@@ 25,11 25,10 @@

<p>
    <a href="/register">Register</a><br>
    <a href="/manual">Read the manual</a>
    <a href="">Source code</a>
</p>
<!--<form action="https://riku.miso.town/submit?user_id=1&label=riku" method="post">-->
<!--    <label for="email">Email:</label>-->
<!--    <input type="email" name="email" id="email" required>-->
<!--    <input type="submit" value="submit">-->
<!--</form>-->

<p>Questions? Send me an email at m15o at posteo dot net</p>

<p><a href="/manual">Want to learn more? Read the manual!</a></p>
{{ end }}
\ No newline at end of file

M web/handler/html/manual.html => web/handler/html/manual.html +3 -3
@@ 13,17 13,17 @@

  &lt;div class=&quot;field&quot;&gt;
    &lt;label for=&quot;name&quot;&gt;Name&lt;/label&gt;
    &lt;input type=&quot;text&quot; name=&quot;name&quot; required&gt;
    &lt;input type=&quot;text&quot; name=&quot;name&quot; id="name" required&gt;
  &lt;/div&gt;

  &lt;div class=&quot;field&quot;&gt;
    &lt;label for=&quot;email&quot;&gt;Email (optional)&lt;/label&gt;
    &lt;input type=&quot;email&quot; name=&quot;email&quot;&gt;
    &lt;input type=&quot;email&quot; name=&quot;email&quot; id="email"&gt;
  &lt;/div&gt;

  &lt;div class=&quot;field&quot;&gt;
    &lt;label for=&quot;message&quot;&gt;Message&lt;/label&gt;
    &lt;textarea name=&quot;message&quot; style=&quot;height: 200px;&quot; required&gt;&lt;/textarea&gt;
    &lt;textarea name=&quot;message&quot; style=&quot;height: 200px;&quot; id="message" required&gt;&lt;/textarea&gt;
  &lt;/div&gt;

  &lt;input type=&quot;submit&quot; value=&quot;Submit&quot;&gt;

M web/handler/html/response.html => web/handler/html/response.html +6 -6
@@ 1,10 1,10 @@
{{ define "content" }}
<nav class="tabs">
    <a href="/?closed=false" {{ if not .response.Closed }}class="selected"{{ end }}>inbox</a> <a href="/?closed=true" {{ if .response.Closed }}class="selected"{{ end }}>archive</a>
    <a href="/" {{ if not .response.Archived }}class="selected"{{ end }}>inbox</a> <a href="/?archived=true" {{ if .response.Archived }}class="selected"{{ end }}>archive</a>
</nav>

<nav class="breadcrumb">
    <a href="/?closed={{ .response.Closed }}">{{ if .response.Closed }}archive{{ else }}inbox{{ end }}</a> › Response #{{ .response.Id }}
    <a href="/?archived={{ .response.Archived }}">{{ if .response.Archived }}archive{{ else }}inbox{{ end }}</a> › Response #{{ .response.Id }}
</nav>

<h1>Response #{{ .response.Id }}</h1>


@@ 26,13 26,13 @@
</table>

<div class="actions">
    {{ if .response.Closed }}
        <form action="/open" method="get" class="action">
    {{ if .response.Archived }}
        <form action="/move-to-inbox" method="get" class="action">
            <input type="hidden" name="id" value="{{ .response.Id }}">
            <input type="submit" value="move to inbox">
        </form>
    {{ else }}
        <form action="/close" method="get" class="action">
        <form action="/move-to-archive" method="get" class="action">
            <input type="hidden" name="id" value="{{ .response.Id }}">
            <input type="submit" value="move to archive">
        </form>


@@ 40,7 40,7 @@

    <form action="/delete" method="get" class="action">
        <input type="hidden" name="id" value="{{ .response.Id }}">
        <input type="hidden" name="closed" value="{{ .response.Closed }}">
        <input type="hidden" name="archived" value="{{ .response.Archived }}">
        <input type="submit" value="delete">
    </form>
</div>

M web/handler/html/responses.html => web/handler/html/responses.html +4 -4
@@ 1,10 1,10 @@
{{ define "content" }}

<nav class="tabs">
    <a href="?closed=false" {{ if not .closed }}class="selected"{{ end }}>inbox</a> <a href="?closed=true" {{ if .closed }}class="selected"{{ end }}>archive</a>
    <a href="/" {{ if not .archived }}class="selected"{{ end }}>inbox</a> <a href="/?archived=true" {{ if .archived }}class="selected"{{ end }}>archive</a>
</nav>

{{ if not .closed }}
{{ if not .archived }}
<h1>Inbox</h1>
<div class="info"><p>POST to https://riku.miso.town/submit?user_id={{ .logged.Id }}</p></div>
{{ else }}


@@ 15,7 15,7 @@

{{ if gt (len .labels) 1 }}
<p>
    <a href="/?closed={{ .closed }}">all</a>{{ range .labels }} {{ if eq . $.label }}{{ . }}{{ else }}<a href="?label={{ . }}&closed={{ $.closed }}">{{ . }}</a>{{ end }}{{ end }}
    <a href="/?archived={{ .archived }}">all</a>{{ range .labels }} {{ if eq . $.label }}{{ . }}{{ else }}<a href="?label={{ . }}&archived={{ $.archived }}">{{ . }}</a>{{ end }}{{ end }}
</p>
{{ end }}



@@ 28,7 28,7 @@
            <div class="response">
                <a href="/response?id={{ .Id }}">Response #{{ .Id }}</a>
                {{ if .Label }}
                <a href="?label={{ .Label }}&closed={{ $.closed }}">{{ .Label }}</a>
                <a href="?label={{ .Label }}&archived={{ $.archived }}">{{ .Label }}</a>
                {{ end }}
            </div>
        </td>

M web/handler/response_list.go => web/handler/response_list.go +4 -4
@@ 16,14 16,14 @@ func (h *handler) responseList(w http.ResponseWriter, r *http.Request) {
	}

	label := r.URL.Query().Get("label")
	closed := r.URL.Query().Get("closed") == "true"
	archived := r.URL.Query().Get("archived") == "true"

	requests, err := h.store.Responses(user.Id, label, closed)
	requests, err := h.store.Responses(user.Id, label, archived)
	if err != nil {
		fmt.Println(err)
	}

	labels, err := h.store.Labels(user.Id, closed)
	labels, err := h.store.Labels(user.Id, archived)
	if err != nil {
		fmt.Println(err)
	}


@@ 32,6 32,6 @@ func (h *handler) responseList(w http.ResponseWriter, r *http.Request) {
	v.Set("requests", requests)
	v.Set("labels", labels)
	v.Set("label", label)
	v.Set("closed", closed)
	v.Set("archived", archived)
	v.Render()
}

M web/handler/response_move_archive.go => web/handler/response_move_archive.go +2 -4
@@ 11,9 11,7 @@ func (h *handler) moveResponseToArchive(w http.ResponseWriter, r *http.Request) 

	id, _ := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64)

	h.store.Close(id, user.Id)
	h.store.MoveToArchive(id, user.Id)

	//status, label := r.URL.Query().Get("status"), r.URL.Query().Get("label")

	http.Redirect(w, r, "/?closed=false", http.StatusFound)
	http.Redirect(w, r, "/", http.StatusFound)
}

M web/handler/response_move_inbox.go => web/handler/response_move_inbox.go +2 -4
@@ 11,9 11,7 @@ func (h *handler) moveResponseToInbox(w http.ResponseWriter, r *http.Request) {

	id, _ := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64)

	h.store.Open(id, user.Id)
	h.store.MoveToInbox(id, user.Id)

	//closed, label := r.URL.Query().Get("closed"), r.URL.Query().Get("label")

	http.Redirect(w, r, "/?closed=true", http.StatusFound)
	http.Redirect(w, r, "/?archived=true", http.StatusFound)
}

R web/handler/request_remove.go => web/handler/response_remove.go +3 -3
@@ 6,14 6,14 @@ import (
	"strconv"
)

func (h *handler) removeRequest(w http.ResponseWriter, r *http.Request) {
func (h *handler) removeResponse(w http.ResponseWriter, r *http.Request) {
	user := request.GetUserContextKey(r)

	id, _ := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64)

	h.store.Remove(id, user.Id)

	closed, label := r.URL.Query().Get("closed"), r.URL.Query().Get("label")
	archived, label := r.URL.Query().Get("archived"), r.URL.Query().Get("label")

	http.Redirect(w, r, list(closed, label), http.StatusFound)
	http.Redirect(w, r, list(archived, label), http.StatusFound)
}

R web/handler/request_submit.go => web/handler/response_submit.go +1 -8
@@ 7,7 7,7 @@ import (
	"strconv"
)

func (h *handler) submitRequest(w http.ResponseWriter, r *http.Request) {
func (h *handler) submitResponse(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	userId, _ := strconv.ParseInt(r.URL.Query().Get("user_id"), 10, 64)


@@ 33,13 33,6 @@ func (h *handler) submitRequest(w http.ResponseWriter, r *http.Request) {
		return
	}

	//user, _ := h.store.UserById(userId)

	//err = mailer.Notify(user.Email, model.Request{
	//	Tag:  tag,
	//	Data: data,
	//})

	if err != nil {
		fmt.Println(err)
		return