🎉🚀 May the concensus be with us!
This commit is contained in:
commit
48328e7db2
33 changed files with 4051 additions and 0 deletions
137
http/main.go
Normal file
137
http/main.go
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.c-base.org/baccenfutter/govote/store"
|
||||
"code.c-base.org/baccenfutter/govote/utils"
|
||||
"code.c-base.org/baccenfutter/govote/voting"
|
||||
"code.c-base.org/baccenfutter/govote/voting/quorum"
|
||||
"code.c-base.org/baccenfutter/govote/voting/threshold"
|
||||
"code.c-base.org/baccenfutter/govote/voting/vote"
|
||||
"github.com/google/uuid"
|
||||
"github.com/labstack/echo"
|
||||
"github.com/labstack/echo/middleware"
|
||||
)
|
||||
|
||||
func Serve(bindAddr string) error {
|
||||
e := echo.New()
|
||||
e.Pre(middleware.RemoveTrailingSlash())
|
||||
// e.Use(middleware.Recover())
|
||||
|
||||
NewTemplateRenderer(e, "tmpl/*.html")
|
||||
|
||||
e.Static("/static", "static")
|
||||
e.GET("/", handleIndex)
|
||||
e.GET("/v", handleVotingForm)
|
||||
e.POST("/v", handleNewVoting)
|
||||
e.GET("/v/:id", handleShowVoting)
|
||||
e.POST("/v/:id", handleVote)
|
||||
|
||||
return e.Start(bindAddr)
|
||||
}
|
||||
|
||||
func handleIndex(ctx echo.Context) error {
|
||||
// return ctx.Redirect(http.StatusTemporaryRedirect, "/v")
|
||||
return ctx.String(200, ctx.Request().Header.Get("X-Remote-User"))
|
||||
}
|
||||
|
||||
func handleNewVoting(ctx echo.Context) error {
|
||||
id :=utils.GenerateRandomString(11)
|
||||
var (
|
||||
formReferendum = ctx.FormValue("referendum")
|
||||
formDeadline = ctx.FormValue("deadline")
|
||||
formQuorum = ctx.FormValue("quorum")
|
||||
formThreshold = ctx.FormValue("threshold")
|
||||
formElectors = ctx.FormValue("electors")
|
||||
formAnonymous = ctx.FormValue("anonymous")
|
||||
)
|
||||
|
||||
var (
|
||||
err error
|
||||
r string
|
||||
d time.Time
|
||||
q quorum.Quorum
|
||||
t threshold.Threshold
|
||||
e = []string{}
|
||||
a bool
|
||||
)
|
||||
|
||||
r = formReferendum
|
||||
deadlineNum := fmt.Sprintf("%s", formDeadline[:len(formDeadline)-1])
|
||||
deadlineUnit := fmt.Sprintf("%s", formDeadline[len(formDeadline)-1:])
|
||||
deadlineInt, err := strconv.Atoi(deadlineNum)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch deadlineUnit {
|
||||
case "m", "":
|
||||
d = time.Now().UTC().Add(time.Duration(deadlineInt)*time.Minute).Round(time.Second)
|
||||
case "h":
|
||||
d = time.Now().UTC().Add(time.Duration(deadlineInt)*time.Hour).Round(time.Second)
|
||||
case "d":
|
||||
d = time.Now().UTC().Add(time.Duration(deadlineInt)*time.Hour*24).Round(time.Second)
|
||||
default:
|
||||
panic("this code should never be reached")
|
||||
}
|
||||
|
||||
if q, err = quorum.FromString(formQuorum); err != nil {
|
||||
return err
|
||||
}
|
||||
if t, err = threshold.FromString(formThreshold); err != nil {
|
||||
return err
|
||||
}
|
||||
e = strings.Split(formElectors, " ")
|
||||
if formAnonymous == "on" {
|
||||
a = true
|
||||
}
|
||||
|
||||
store.NewVoting(id, r, d, q, t, e, a)
|
||||
return ctx.Redirect(http.StatusFound, fmt.Sprintf("/v/%s", id))
|
||||
}
|
||||
|
||||
func handleVotingForm(ctx echo.Context) error {
|
||||
return ctx.Render(http.StatusOK, "voting_form", nil)
|
||||
}
|
||||
|
||||
func handleVote(ctx echo.Context) error {
|
||||
var (
|
||||
id = uuid.New().String()
|
||||
vid = ctx.Param("id")
|
||||
elector = ctx.Request().Header.Get("X-Remote-User")
|
||||
choice = ctx.FormValue("vote")
|
||||
v *voting.Voting
|
||||
c vote.Choice
|
||||
err error
|
||||
)
|
||||
v, err = store.GetVoting(vid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if time.Now().UTC().After(v.Deadline()) {
|
||||
return ctx.Redirect(http.StatusFound, fmt.Sprintf("/v/%s", vid))
|
||||
}
|
||||
if c, err = vote.ChoiceFromString(choice); err != nil {
|
||||
return err
|
||||
}
|
||||
store.PlaceVote(id, vid, elector, c)
|
||||
return ctx.Render(http.StatusFound, "thanks", map[string]interface{}{
|
||||
"Id": id,
|
||||
"Vid": vid,
|
||||
})
|
||||
}
|
||||
|
||||
func handleShowVoting(ctx echo.Context) error {
|
||||
v, err := store.GetVoting(ctx.Param("id"))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
return ctx.Render(http.StatusOK, "voting", map[string]interface{}{
|
||||
"Voting": v,
|
||||
})
|
||||
}
|
||||
31
http/template_renderer.go
Normal file
31
http/template_renderer.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"io"
|
||||
"text/template"
|
||||
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
type Template struct {
|
||||
Templates *template.Template
|
||||
}
|
||||
|
||||
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
|
||||
return t.Templates.ExecuteTemplate(w, name, data)
|
||||
}
|
||||
|
||||
func NewTemplateRenderer(e *echo.Echo, paths ...string) {
|
||||
tmpl := &template.Template{}
|
||||
for i := range paths {
|
||||
template.Must(tmpl.ParseGlob(paths[i]))
|
||||
}
|
||||
t := newTemplate(tmpl)
|
||||
e.Renderer = t
|
||||
}
|
||||
|
||||
func newTemplate(templates *template.Template) echo.Renderer {
|
||||
return &Template{
|
||||
Templates: templates,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue