|
- // NGnius 2020-01-30
-
- package main
-
- import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- )
-
- const (
- defaultCorsHeader = "*"
- defaultPassword = ""
- )
-
- var (
- corsHeader string
- password string
- reuseTokens bool
- )
-
- func boardHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Add("Content-Type", "application/json")
- w.Header().Add("Access-Control-Allow-Origin", corsHeader)
- if r.Method != "GET" {
- //w.WriteHeader(405)
- errorResponse(405, "Non-GET method not allowed at this endpoint", w, r)
- return
- }
- args := r.URL.Query()
- // check args pre-conditions
- if !checkArgExists(args, "board", w) {
- errorResponse(400, "Missing required 'board' URL parameter", w, r)
- return
- }
- board := args.Get("board")
- if !checkArgExists(args, "count", w) || !checkArgInt(args, "count", w, 0) {
- //w.WriteHeader(400)
- errorResponse(400, "Missing required 'count' integer URL parameter", w, r)
- return
- }
- count, _ := strconv.Atoi(args.Get("count"))
- if !checkArgExists(args, "start", w) || !checkArgInt(args, "start", w, 0) {
- //w.WriteHeader(400)
- errorResponse(400, "Missing required 'start' integer URL parameter", w, r)
- return
- }
- start, _ := strconv.Atoi(args.Get("start"))
- // execute query
- result := NewResult("", r.URL.String())
- b, err := boardByName(board)
- //b, ok := boards[board]
- if err != nil {
- fmt.Println(err)
- //w.WriteHeader(404)
- errorResponse(404, "Board could not be retrieved: "+err.Error(), w, r)
- return
- }
- bEntries, loadErr := b.SomeEntries(int64(start), int64(start+count))
- if loadErr != nil {
- fmt.Println(loadErr)
- //w.WriteHeader(404)
- errorResponse(404, "Board entries could not be retrieved: "+loadErr.Error(), w, r)
- return
- }
- for _, entry := range bEntries {
- item, entryErr := entry.JsonObject()
- if entryErr != nil {
- fmt.Println(entryErr)
- }
- result.Items = append(result.Items, &item)
- }
- result.Query = fmt.Sprintf("load board[name: %s] from %d to %d", board, start, count+start)
- result.Complete()
- data, err := json.Marshal(result)
- if err != nil {
- //w.WriteHeader(500)
- errorResponse(500, "Unable to convert result into JSON: "+err.Error(), w, r)
- return
- }
- w.Write(data)
- }
-
- func playerHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Add("Content-Type", "application/json")
- w.Header().Add("Access-Control-Allow-Origin", corsHeader)
- if r.Method != "GET" {
- //w.WriteHeader(405)
- errorResponse(405, "Non-GET method not allowed at this endpoint", w, r)
- return
- }
- args := r.URL.Query()
- // check args
- if !checkArgExists(args, "id", w) || !checkArgInt(args, "id", w, 1) {
- errorResponse(400, "Missing required 'id' integer URL parameter", w, r)
- return
- }
- id, _ := strconv.Atoi(args.Get("id"))
- entry_count := 0
- if checkArgExists(args, "entries", w) && checkArgInt(args, "entries", w, 0) {
- entry_count, _ = strconv.Atoi(args.Get("entries"))
- }
- // retrieve player
- result := NewResult("", r.URL.String())
- player := &Player{ID: int64(id)}
- loadErr := player.Load()
- if loadErr != nil {
- fmt.Println(loadErr)
- //w.WriteHeader(404)
- errorResponse(404, "Player could not be retrieved: "+loadErr.Error(), w, r)
- return
- }
- tempJsonObj, _ := player.JsonObject()
- pJsonObj := tempJsonObj.(PlayerJSON)
- if entry_count > 0 {
- entries, loadErr := player.SomeEntries(int64(entry_count))
- if loadErr == nil {
- for _, e := range entries {
- eJsonObj, entryErr := e.JsonObject()
- if entryErr != nil {
- fmt.Println(entryErr)
- }
- pJsonObj.Entries = append(pJsonObj.Entries, eJsonObj.(EntryJSON))
- }
- }
- }
- result.Items = []interface{}{pJsonObj}
- result.Query = fmt.Sprintf("load player[id: %d]", player.ID)
- result.Complete()
- data, err := json.Marshal(result)
- if err != nil {
- //w.WriteHeader(500)
- errorResponse(500, "Unable convert result to JSON: "+err.Error(), w, r)
- return
- }
- w.Write(data)
- }
-
- func newEntryHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Add("Content-Type", "application/json")
- w.Header().Add("Access-Control-Allow-Origin", corsHeader)
- if r.Method != "POST" {
- //w.WriteHeader(405)
- errorResponse(405, "Non-POST method not allowed at this endpoint", w, r)
- return
- }
- // check for API token
- tokenHeader := r.Header.Get("Authorization")
- tokenSplit := strings.Split(tokenHeader, " ")
- if tokenHeader == "" || len(tokenSplit) != 2 || tokenSplit[1] == "" {
- errorResponse(401, "Missing or invalid authorization header", w, r)
- return
- }
- key, keyErr := keyByToken(tokenSplit[1])
- if keyErr != nil || key.ID == 0 {
- errorResponse(401, "Invalid token", w, r)
- return
- }
- if !key.IsEnabled() {
- errorResponse(403, "Invalid token", w, r)
- return
- }
- data, readErr := ioutil.ReadAll(r.Body)
- if readErr != nil {
- fmt.Println(readErr)
- //w.WriteHeader(500)
- errorResponse(500, "Unable to read HTTP request body: "+readErr.Error(), w, r)
- return
- }
- newEntry, jsonErr := UnmarshalNewEntryJSON(data)
- if jsonErr != nil {
- //w.WriteHeader(400)
- errorResponse(400, "Unable to convert request to JSON: "+jsonErr.Error(), w, r)
- return
- }
- if password != "" && newEntry.Password != password {
- errorResponse(403, "Invalid password", w, r)
- return
- }
- if newEntry.PlayerID != key.Player && !key.IsMultiuser() {
- errorResponse(403, "Invalid authorization for player", w, r)
- return
- }
- sqlErr := newEntrySql(newEntry.Score, newEntry.PlayerID, newEntry.BoardID)
- if sqlErr != nil {
- fmt.Println(sqlErr)
- //w.WriteHeader(500)
- errorResponse(500, "Entry could not be created: "+sqlErr.Error(), w, r)
- return
- }
- //w.WriteHeader(204)
- errorResponse(200, "New entry created", w, r)
- }
-
- func newKeyHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Add("Content-Type", "application/json")
- w.Header().Add("Access-Control-Allow-Origin", corsHeader)
- if r.Method != "POST" {
- errorResponse(405, "Non-POST method not allowed at this endpoint", w, r)
- return
- }
- data, readErr := ioutil.ReadAll(r.Body)
- if readErr != nil {
- fmt.Println(readErr)
- errorResponse(500, "Unable to read HTTP request body: "+readErr.Error(), w, r)
- return
- }
- result := NewResult("", r.URL.String())
- newKey, jsonErr := UnmarshalNewKeyJSON(data)
- if jsonErr != nil {
- errorResponse(400, "Unable to convert request to JSON: "+jsonErr.Error(), w, r)
- return
- }
- var key *Key
- var sqlErr error
- if reuseTokens {
- key, sqlErr = keyByPlayer(newKey.PlayerID)
- }
- if (sqlErr != nil && reuseTokens) || !reuseTokens {
- key, sqlErr = newKeySql(newKey.PlayerID)
- }
- if sqlErr != nil {
- fmt.Println(sqlErr)
- errorResponse(500, "Key could not be created: "+sqlErr.Error(), w, r)
- return
- }
- jsonObj, _ := key.JsonObject()
- result.Items = []interface{}{jsonObj}
- result.Query = fmt.Sprintf("new key[player id: %d]", newKey.PlayerID)
- result.Complete()
- data, err := json.Marshal(result)
- if err != nil {
- errorResponse(500, "Unable convert result to JSON: "+err.Error(), w, r)
- return
- }
- w.Write(data)
- }
-
- func exampleHandler(w http.ResponseWriter, r *http.Request) {
- // useless function please ignore
- }
-
- // utility functions
-
- func checkArgExists(values url.Values, key string, w http.ResponseWriter) (ok bool) {
- ok = values.Get(key) != ""
- return
- }
-
- func checkArgInt(values url.Values, key string, w http.ResponseWriter, min int) (ok bool) {
- intVal, err := strconv.Atoi(values.Get(key))
- ok = err == nil && intVal >= min
- return
- }
-
- func errorResponse(statusCode int, reason string, w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(statusCode)
- query := "error"
- if statusCode == 200 {
- query = "success"
- }
- errorRes := NewResult(query, r.URL.String())
- errorRes.Items = append(errorRes.Items, ErrorJSON{Reason: reason, StatusCode: statusCode})
- errorRes.StatusCode = statusCode
- data, _ := json.Marshal(errorRes)
- w.Write(data)
- }
|