work on updated client API

This commit is contained in:
Neale Pickett 2019-02-23 00:43:04 +00:00
parent 651c8fdfa4
commit ad9dab3d8f
3 changed files with 63 additions and 41 deletions

View File

@ -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),
) )

View File

@ -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);
}
}

View File

@ -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>