mirror of https://github.com/dirtbags/moth.git
work on updated client API
This commit is contained in:
parent
651c8fdfa4
commit
ad9dab3d8f
|
@ -12,39 +12,26 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// https://github.com/omniti-labs/jsend
|
||||||
type JSend struct {
|
type JSend struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Data JSendData `json:"data"`
|
Data struct {
|
||||||
|
Short string `json:"short"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
} `json:"data"`
|
||||||
}
|
}
|
||||||
type JSendData struct {
|
|
||||||
Short string `json:"short"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Status int
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Success = iota
|
JSendSuccess = "success"
|
||||||
Fail
|
JSendFail = "fail"
|
||||||
Error
|
JSendError = "error"
|
||||||
)
|
)
|
||||||
|
|
||||||
func respond(w http.ResponseWriter, req *http.Request, status Status, short string, format string, a ...interface{}) {
|
func respond(w http.ResponseWriter, req *http.Request, status string, short string, format string, a ...interface{}) {
|
||||||
resp := JSend{
|
resp := JSend{}
|
||||||
Status: "success",
|
resp.Status = status
|
||||||
Data: JSendData{
|
resp.Data.Short = short
|
||||||
Short: short,
|
resp.Data.Description = fmt.Sprintf(format, a...)
|
||||||
Description: fmt.Sprintf(format, a...),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
switch status {
|
|
||||||
case Success:
|
|
||||||
resp.Status = "success"
|
|
||||||
case Fail:
|
|
||||||
resp.Status = "fail"
|
|
||||||
default:
|
|
||||||
resp.Status = "error"
|
|
||||||
}
|
|
||||||
|
|
||||||
respBytes, err := json.Marshal(resp)
|
respBytes, err := json.Marshal(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -82,7 +69,7 @@ func (ctx *Instance) registerHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
if (teamid == "") || (teamname == "") {
|
if (teamid == "") || (teamname == "") {
|
||||||
respond(
|
respond(
|
||||||
w, req, Fail,
|
w, req, JSendFail,
|
||||||
"Invalid Entry",
|
"Invalid Entry",
|
||||||
"Either `id` or `name` was missing from this request.",
|
"Either `id` or `name` was missing from this request.",
|
||||||
)
|
)
|
||||||
|
@ -92,7 +79,7 @@ func (ctx *Instance) registerHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
teamids, err := os.Open(ctx.StatePath("teamids.txt"))
|
teamids, err := os.Open(ctx.StatePath("teamids.txt"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respond(
|
respond(
|
||||||
w, req, Fail,
|
w, req, JSendFail,
|
||||||
"Cannot read valid team IDs",
|
"Cannot read valid team IDs",
|
||||||
"An error was encountered trying to read valid teams IDs: %v", err,
|
"An error was encountered trying to read valid teams IDs: %v", err,
|
||||||
)
|
)
|
||||||
|
@ -101,7 +88,7 @@ func (ctx *Instance) registerHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
defer teamids.Close()
|
defer teamids.Close()
|
||||||
if !hasLine(teamids, teamid) {
|
if !hasLine(teamids, teamid) {
|
||||||
respond(
|
respond(
|
||||||
w, req, Fail,
|
w, req, JSendFail,
|
||||||
"Invalid Team ID",
|
"Invalid Team ID",
|
||||||
"I don't have a record of that team ID. Maybe you used capital letters accidentally?",
|
"I don't have a record of that team ID. Maybe you used capital letters accidentally?",
|
||||||
)
|
)
|
||||||
|
@ -109,10 +96,17 @@ func (ctx *Instance) registerHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.OpenFile(ctx.StatePath("teams", teamid), os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
|
f, err := os.OpenFile(ctx.StatePath("teams", teamid), os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if os.IsExist(err) {
|
||||||
|
respond(
|
||||||
|
w, req, JSendFail,
|
||||||
|
"Already registered",
|
||||||
|
"This team ID has already been registered.",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
respond(
|
respond(
|
||||||
w, req, Fail,
|
w, req, JSendFail,
|
||||||
"Registration failed",
|
"Registration failed",
|
||||||
"Unable to register. Perhaps a teammate has already registered?",
|
"Unable to register. Perhaps a teammate has already registered?",
|
||||||
)
|
)
|
||||||
|
@ -121,7 +115,7 @@ func (ctx *Instance) registerHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
fmt.Fprintln(f, teamname)
|
fmt.Fprintln(f, teamname)
|
||||||
respond(
|
respond(
|
||||||
w, req, Success,
|
w, req, JSendSuccess,
|
||||||
"Team registered",
|
"Team registered",
|
||||||
"Okay, your team has been named and you may begin using your team ID!",
|
"Okay, your team has been named and you may begin using your team ID!",
|
||||||
)
|
)
|
||||||
|
@ -136,7 +130,7 @@ func (ctx *Instance) answerHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
points, err := strconv.Atoi(pointstr)
|
points, err := strconv.Atoi(pointstr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respond(
|
respond(
|
||||||
w, req, Fail,
|
w, req, JSendFail,
|
||||||
"Cannot parse point value",
|
"Cannot parse point value",
|
||||||
"This doesn't look like an integer: %s", pointstr,
|
"This doesn't look like an integer: %s", pointstr,
|
||||||
)
|
)
|
||||||
|
@ -146,7 +140,7 @@ func (ctx *Instance) answerHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
haystack, err := ctx.OpenCategoryFile(category, "answers.txt")
|
haystack, err := ctx.OpenCategoryFile(category, "answers.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respond(
|
respond(
|
||||||
w, req, Fail,
|
w, req, JSendFail,
|
||||||
"Cannot list answers",
|
"Cannot list answers",
|
||||||
"Unable to read the list of answers for this category.",
|
"Unable to read the list of answers for this category.",
|
||||||
)
|
)
|
||||||
|
@ -158,7 +152,7 @@ func (ctx *Instance) answerHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
needle := fmt.Sprintf("%d %s", points, answer)
|
needle := fmt.Sprintf("%d %s", points, answer)
|
||||||
if !hasLine(haystack, needle) {
|
if !hasLine(haystack, needle) {
|
||||||
respond(
|
respond(
|
||||||
w, req, Fail,
|
w, req, JSendFail,
|
||||||
"Wrong answer",
|
"Wrong answer",
|
||||||
"That is not the correct answer for %s %d.", category, points,
|
"That is not the correct answer for %s %d.", category, points,
|
||||||
)
|
)
|
||||||
|
@ -167,14 +161,14 @@ func (ctx *Instance) answerHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
if err := ctx.AwardPoints(teamid, category, points); err != nil {
|
if err := ctx.AwardPoints(teamid, category, points); err != nil {
|
||||||
respond(
|
respond(
|
||||||
w, req, Error,
|
w, req, JSendError,
|
||||||
"Cannot award points",
|
"Cannot award points",
|
||||||
"The answer is correct, but there was an error awarding points: %v", err.Error(),
|
"The answer is correct, but there was an error awarding points: %v", err.Error(),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
respond(
|
respond(
|
||||||
w, req, Success,
|
w, req, JSendSuccess,
|
||||||
"Points awarded",
|
"Points awarded",
|
||||||
fmt.Sprintf("%d points for %s!", points, teamid),
|
fmt.Sprintf("%d points for %s!", points, teamid),
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,7 +12,7 @@ h1 {
|
||||||
background: #5e576b;
|
background: #5e576b;
|
||||||
color: #9e98a8;
|
color: #9e98a8;
|
||||||
}
|
}
|
||||||
.Fail, .Error {
|
.Fail, .Error, #messages {
|
||||||
background: #3a3119;
|
background: #3a3119;
|
||||||
color: #ffcc98;
|
color: #ffcc98;
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,10 @@ iframe#body {
|
||||||
img {
|
img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
#messages {
|
||||||
|
min-height: 3em;
|
||||||
|
border: solid black 2px;
|
||||||
|
}
|
||||||
#scoreboard {
|
#scoreboard {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -87,3 +91,25 @@ img {
|
||||||
.kvpair {
|
.kvpair {
|
||||||
border: solid black 2px;
|
border: solid black 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
display: inline-block;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
display: block;
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
margin: 1px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 5px solid #fff;
|
||||||
|
border-color: #fff transparent #fff transparent;
|
||||||
|
animation: rotate 1.2s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes rotate {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Sign In</title>
|
<title>MOTH</title>
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<link rel="stylesheet" href="basic.css">
|
<link rel="stylesheet" href="basic.css">
|
||||||
<script src="moth.js"></script>
|
<script src="moth.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1 id="title">Sign In</h1>
|
<h1 id="title">MOTH</h1>
|
||||||
<section>
|
<section>
|
||||||
|
<div id="messages"></div>
|
||||||
|
|
||||||
<div id="login">
|
<div id="login">
|
||||||
Team name: <input name="name">
|
Team name: <input name="name">
|
||||||
Team ID: <input name="id"> <br>
|
Team ID: <input name="id"> <br>
|
||||||
|
|
Loading…
Reference in New Issue