Initial Commit
This commit is contained in:
80
app.go
Normal file
80
app.go
Normal file
@@ -0,0 +1,80 @@
|
||||
// app.go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// App : holds the router and db configuration
|
||||
type App struct {
|
||||
Router *mux.Router
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
// Initialize : Initialize the app
|
||||
func (a *App) Initialize(user, password, dbname string) {
|
||||
connectionString :=
|
||||
fmt.Sprintf("%s:%s@/%s?parseTime=true", user, password, dbname)
|
||||
|
||||
var err error
|
||||
a.DB, err = sql.Open("mysql", connectionString)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
a.Router = mux.NewRouter()
|
||||
a.initializeRoutes()
|
||||
}
|
||||
|
||||
func respondWithError(w http.ResponseWriter, code int, message string) {
|
||||
respondWithJSON(w, code, map[string]string{"error": message})
|
||||
}
|
||||
|
||||
func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
|
||||
response, _ := json.Marshal(payload)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
w.Write(response)
|
||||
}
|
||||
|
||||
// Run : Run the app
|
||||
func (a *App) Run(addr string) {
|
||||
log.Fatal(http.ListenAndServe(":8000", a.Router))
|
||||
}
|
||||
|
||||
// initializeRoutes : initialize all routes
|
||||
func (a *App) initializeRoutes() {
|
||||
|
||||
a.Router.HandleFunc("/api/v1/configs", a.getConfigs).Methods("GET")
|
||||
a.Router.HandleFunc("/api/v1/config", a.createConfig).Methods("POST")
|
||||
a.Router.HandleFunc("/api/v1/config/{id:[0-9]+}", a.getConfig).Methods("GET")
|
||||
a.Router.HandleFunc("/api/v1/config/{id:[0-9]+}", a.updateConfig).Methods("PUT")
|
||||
a.Router.HandleFunc("/api/v1/config/{id:[0-9]+}", a.deleteConfig).Methods("DELETE")
|
||||
|
||||
a.Router.HandleFunc("/api/v1/dataTypes", a.getDataTypes).Methods("GET")
|
||||
a.Router.HandleFunc("/api/v1/dataType", a.createDataType).Methods("POST")
|
||||
a.Router.HandleFunc("/api/v1/dataType/{id:[0-9]+}", a.getDataType).Methods("GET")
|
||||
a.Router.HandleFunc("/api/v1/dataType/{id:[0-9]+}", a.updateDataType).Methods("PUT")
|
||||
a.Router.HandleFunc("/api/v1/dataType/{id:[0-9]+}", a.deleteDataType).Methods("DELETE")
|
||||
|
||||
//Serve public files
|
||||
var dir string
|
||||
flag.StringVar(&dir, "dir", "./public", "the directory to serve files from. Defaults to the current dir")
|
||||
flag.Parse()
|
||||
a.Router.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir(dir))))
|
||||
|
||||
// Serve Root HTML Page
|
||||
a.Router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "./html/index.html")
|
||||
})
|
||||
}
|
||||
110
handler_config.go
Normal file
110
handler_config.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func (a *App) getConfig(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid config ID")
|
||||
return
|
||||
}
|
||||
|
||||
c := Config{ID: id}
|
||||
if err := c.getConfig(a.DB); err != nil {
|
||||
switch err {
|
||||
case sql.ErrNoRows:
|
||||
respondWithError(w, http.StatusNotFound, "Config not found")
|
||||
default:
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusOK, c)
|
||||
}
|
||||
|
||||
func (a *App) getConfigs(w http.ResponseWriter, r *http.Request) {
|
||||
count, _ := strconv.Atoi(r.FormValue("count"))
|
||||
start, _ := strconv.Atoi(r.FormValue("start"))
|
||||
|
||||
if count > 10 || count < 1 {
|
||||
count = 10
|
||||
}
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
|
||||
configs, err := getConfigs(a.DB, start, count)
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusOK, configs)
|
||||
}
|
||||
|
||||
func (a *App) createConfig(w http.ResponseWriter, r *http.Request) {
|
||||
var c Config
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
if err := decoder.Decode(&c); err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid request payload")
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
if err := c.createConfig(a.DB); err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusCreated, c)
|
||||
}
|
||||
|
||||
func (a *App) updateConfig(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid config ID")
|
||||
return
|
||||
}
|
||||
|
||||
var c Config
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
if err := decoder.Decode(&c); err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid request payload")
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
c.ID = id
|
||||
|
||||
if err := c.updateConfig(a.DB); err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusOK, c)
|
||||
}
|
||||
|
||||
func (a *App) deleteConfig(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid Config ID")
|
||||
return
|
||||
}
|
||||
|
||||
c := Config{ID: id}
|
||||
if err := c.deleteConfig(a.DB); err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusOK, map[string]string{"result": "success"})
|
||||
}
|
||||
110
handler_datatype.go
Normal file
110
handler_datatype.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func (a *App) getDataType(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid config ID")
|
||||
return
|
||||
}
|
||||
|
||||
c := DataType{ID: id}
|
||||
if err := c.getDataType(a.DB); err != nil {
|
||||
switch err {
|
||||
case sql.ErrNoRows:
|
||||
respondWithError(w, http.StatusNotFound, "DataType not found")
|
||||
default:
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusOK, c)
|
||||
}
|
||||
|
||||
func (a *App) getDataTypes(w http.ResponseWriter, r *http.Request) {
|
||||
count, _ := strconv.Atoi(r.FormValue("count"))
|
||||
start, _ := strconv.Atoi(r.FormValue("start"))
|
||||
|
||||
if count > 10 || count < 1 {
|
||||
count = 10
|
||||
}
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
|
||||
configs, err := getDataTypes(a.DB, start, count)
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusOK, configs)
|
||||
}
|
||||
|
||||
func (a *App) createDataType(w http.ResponseWriter, r *http.Request) {
|
||||
var c DataType
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
if err := decoder.Decode(&c); err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid request payload")
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
if err := c.createDataType(a.DB); err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusCreated, c)
|
||||
}
|
||||
|
||||
func (a *App) updateDataType(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid config ID")
|
||||
return
|
||||
}
|
||||
|
||||
var c DataType
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
if err := decoder.Decode(&c); err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid request payload")
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
c.ID = id
|
||||
|
||||
if err := c.updateDataType(a.DB); err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusOK, c)
|
||||
}
|
||||
|
||||
func (a *App) deleteDataType(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusBadRequest, "Invalid DataType ID")
|
||||
return
|
||||
}
|
||||
|
||||
c := DataType{ID: id}
|
||||
if err := c.deleteDataType(a.DB); err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondWithJSON(w, http.StatusOK, map[string]string{"result": "success"})
|
||||
}
|
||||
14
html/index.html
Normal file
14
html/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment-with-locales.min.js"></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Lumberjack</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="text/javascript" src="/public/transformed.js"></script></body>
|
||||
</html>
|
||||
14
main.go
Normal file
14
main.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
func main() {
|
||||
|
||||
a := App{}
|
||||
a.Initialize(
|
||||
os.Getenv("APP_DB_USERNAME"),
|
||||
os.Getenv("APP_DB_PASSWORD"),
|
||||
os.Getenv("APP_DB_NAME"))
|
||||
|
||||
a.Run(":8080")
|
||||
}
|
||||
78
model_config.go
Normal file
78
model_config.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config : holds information about a specific Config
|
||||
type Config struct {
|
||||
ID int `json:"id"`
|
||||
Parameter string `json:"parameter"`
|
||||
Val string `json:"val"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// Configs : a list of Config items
|
||||
type Configs []Config
|
||||
|
||||
// getConfig : used during GET command
|
||||
func (c *Config) getConfig(db *sql.DB) error {
|
||||
return db.QueryRow("SELECT parameter, val, createdAt, updatedAt FROM configs WHERE id=?", c.ID).Scan(&c.Parameter, &c.Val, &c.CreatedAt, &c.UpdatedAt)
|
||||
}
|
||||
|
||||
// updateConfig : used during PUT command
|
||||
func (c *Config) updateConfig(db *sql.DB) error {
|
||||
updStmt, updErr := db.Prepare("UPDATE configs SET parameter=?, val=?, updatedAt=? WHERE id=?")
|
||||
if updErr != nil {
|
||||
panic(updErr.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
defer updStmt.Close() // Close the statement when we leave main() / the program terminates
|
||||
|
||||
_, err := updStmt.Exec(c.Parameter, c.Val, time.Now(), c.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// deleteConfig : used during DELETE command
|
||||
func (c *Config) deleteConfig(db *sql.DB) error {
|
||||
_, err := db.Exec("DELETE FROM configs WHERE id=?", c.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// createConfig : used during PUSH command
|
||||
func (c *Config) createConfig(db *sql.DB) error {
|
||||
stmtIns, insErr := db.Prepare("INSERT INTO configs (parameter, val, createdAt, updatedAt) VALUES (?, ?, ?, ?);")
|
||||
if insErr != nil {
|
||||
panic(insErr.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
defer stmtIns.Close() // Close the statement when we leave main() / the program terminates
|
||||
|
||||
_, err := stmtIns.Exec(c.Parameter, c.Val, time.Now(), time.Now())
|
||||
return err
|
||||
}
|
||||
|
||||
// getConfigs : used during GET command for all
|
||||
func getConfigs(db *sql.DB, start, count int) (Configs, error) {
|
||||
rows, err := db.Query(
|
||||
"SELECT id, parameter, val, createdAt, updatedAt FROM configs LIMIT ? OFFSET ?",
|
||||
count, start)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
configs := Configs{}
|
||||
|
||||
for rows.Next() {
|
||||
var c Config
|
||||
if err := rows.Scan(&c.ID, &c.Parameter, &c.CreatedAt, &c.UpdatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configs = append(configs, c)
|
||||
}
|
||||
|
||||
return configs, nil
|
||||
}
|
||||
78
model_datatype.go
Normal file
78
model_datatype.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DataType : holds information about a specific DataType
|
||||
type DataType struct {
|
||||
ID int `json:"id"`
|
||||
DataType string `json:"dataType"`
|
||||
PlcType string `json:"plcType"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// DataTypes : a list of DataType items
|
||||
type DataTypes []DataType
|
||||
|
||||
// getDataType : used during GET command
|
||||
func (c *DataType) getDataType(db *sql.DB) error {
|
||||
return db.QueryRow("SELECT dataType, plcType, createdAt, updatedAt FROM dataTypes WHERE id=?", c.ID).Scan(&c.DataType, &c.PlcType, &c.CreatedAt, &c.UpdatedAt)
|
||||
}
|
||||
|
||||
// updateDataType : used during PUT command
|
||||
func (c *DataType) updateDataType(db *sql.DB) error {
|
||||
updStmt, updErr := db.Prepare("UPDATE dataTypes SET dataType=?, plcType=?, updatedAt=? WHERE id=?")
|
||||
if updErr != nil {
|
||||
panic(updErr.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
defer updStmt.Close() // Close the statement when we leave main() / the program terminates
|
||||
|
||||
_, err := updStmt.Exec(c.DataType, c.PlcType, time.Now(), c.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// deleteDataType : used during DELETE command
|
||||
func (c *DataType) deleteDataType(db *sql.DB) error {
|
||||
_, err := db.Exec("DELETE FROM dataTypes WHERE id=?", c.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// createDataType : used during PUSH command
|
||||
func (c *DataType) createDataType(db *sql.DB) error {
|
||||
stmtIns, insErr := db.Prepare("INSERT INTO dataTypes (dataType, plcType, createdAt, updatedAt) VALUES (?, ?, ?, ?);")
|
||||
if insErr != nil {
|
||||
panic(insErr.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
defer stmtIns.Close() // Close the statement when we leave main() / the program terminates
|
||||
|
||||
_, err := stmtIns.Exec(c.DataType, c.PlcType, time.Now(), time.Now())
|
||||
return err
|
||||
}
|
||||
|
||||
// getDataTypes : used during GET command for all
|
||||
func getDataTypes(db *sql.DB, start, count int) (DataTypes, error) {
|
||||
rows, err := db.Query(
|
||||
"SELECT id, dataType, plcType, createdAt, updatedAt FROM dataTypes LIMIT ? OFFSET ?",
|
||||
count, start)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
dataTypes := DataTypes{}
|
||||
|
||||
for rows.Next() {
|
||||
var c DataType
|
||||
if err := rows.Scan(&c.ID, &c.DataType, &c.CreatedAt, &c.UpdatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dataTypes = append(dataTypes, c)
|
||||
}
|
||||
|
||||
return dataTypes, nil
|
||||
}
|
||||
15
model_device.go
Normal file
15
model_device.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
// Device : holds information about a specific Device
|
||||
type Device struct {
|
||||
ID int `json:"id"`
|
||||
DeviceType DeviceType `json:"deviceType"`
|
||||
Address string `json:"address"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// Devices : a list of Device items
|
||||
type Devices []Device
|
||||
14
model_devicetype.go
Normal file
14
model_devicetype.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
// DeviceType : holds information about a specific DeviceType
|
||||
type DeviceType struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// DeviceTypes : a list of DeviceType items
|
||||
type DeviceTypes []DeviceType
|
||||
16
model_file.go
Normal file
16
model_file.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
// File : holds information about a specific File
|
||||
type File struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Location string `json:"location"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// Files : a list of File items
|
||||
type Files []File
|
||||
25
model_tag.go
Normal file
25
model_tag.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
// Tag : holds information about a specific Tag
|
||||
type Tag struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
TagClass TagClass `json:"tagClass"`
|
||||
Tag string `json:"tag"`
|
||||
Device Device `json:"device"`
|
||||
Description string `json:"description"`
|
||||
DataType DataType `json:"dataType"`
|
||||
ChangeThreshold float32 `json:"changeThreshold"`
|
||||
GuaranteeSec int `json:"guaranteeSec"`
|
||||
MapFunction string `json:"mapFunction"`
|
||||
Units string `json:"units"`
|
||||
MinExpected float32 `json:"minExpected"`
|
||||
MaxExpected float32 `json:"maxExpected"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// Tags : a list of Tag items
|
||||
type Tags []Tag
|
||||
15
model_tagclass.go
Normal file
15
model_tagclass.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
// TagClass : holds information about a specific TagClass
|
||||
type TagClass struct {
|
||||
ID int `json:"id"`
|
||||
ClassType string `json:"classType"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// TagClasses : a list of TagClass items
|
||||
type TagClasses []TagClass
|
||||
0
public/transformed.js
Normal file
0
public/transformed.js
Normal file
41
test_test.go
Normal file
41
test_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var a App
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
a = App{}
|
||||
a.Initialize(
|
||||
os.Getenv("TEST_DB_USERNAME"),
|
||||
os.Getenv("TEST_DB_PASSWORD"),
|
||||
os.Getenv("TEST_DB_NAME"))
|
||||
|
||||
ensureConfigTableExists()
|
||||
ensureDataTypeTableExists()
|
||||
|
||||
code := m.Run()
|
||||
|
||||
clearConfigTable()
|
||||
clearDataTypeTable()
|
||||
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func executeRequest(req *http.Request) *httptest.ResponseRecorder {
|
||||
rr := httptest.NewRecorder()
|
||||
a.Router.ServeHTTP(rr, req)
|
||||
|
||||
return rr
|
||||
}
|
||||
|
||||
func checkResponseCode(t *testing.T, expected, actual int) {
|
||||
if expected != actual {
|
||||
t.Errorf("Expected response code %d. Got %d\n", expected, actual)
|
||||
}
|
||||
}
|
||||
156
testconfig_test.go
Normal file
156
testconfig_test.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const configTableCreationQuery = `CREATE TABLE IF NOT EXISTS configs (
|
||||
id int(10) unsigned AUTO_INCREMENT,
|
||||
parameter varchar(255),
|
||||
val varchar(255),
|
||||
createdAt datetime,
|
||||
updatedAt datetime,
|
||||
UNIQUE KEY parameter (parameter),
|
||||
PRIMARY KEY (id)
|
||||
)`
|
||||
|
||||
func ensureConfigTableExists() {
|
||||
if _, err := a.DB.Exec(configTableCreationQuery); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func clearConfigTable() {
|
||||
a.DB.Exec("DELETE FROM configs")
|
||||
a.DB.Exec("ALTER TABLE configs AUTO_INCREMENT = 1")
|
||||
}
|
||||
|
||||
func TestEmptyConfigTable(t *testing.T) {
|
||||
clearConfigTable()
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/configs", nil)
|
||||
response := executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
if body := response.Body.String(); body != "[]" {
|
||||
t.Errorf("Expected an empty array. Got %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNonExistentConfig(t *testing.T) {
|
||||
clearConfigTable()
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/config/11", nil)
|
||||
response := executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusNotFound, response.Code)
|
||||
|
||||
var m map[string]string
|
||||
json.Unmarshal(response.Body.Bytes(), &m)
|
||||
if m["error"] != "Config not found" {
|
||||
t.Errorf("Expected the 'error' key of the response to be set to 'Config not found'. Got '%s'", m["error"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateConfig(t *testing.T) {
|
||||
clearConfigTable()
|
||||
|
||||
payload := []byte(`{"parameter":"save_all","val":"true"}`)
|
||||
|
||||
req, _ := http.NewRequest("POST", "/api/v1/config", bytes.NewBuffer(payload))
|
||||
response := executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusCreated, response.Code)
|
||||
|
||||
var m map[string]interface{}
|
||||
json.Unmarshal(response.Body.Bytes(), &m)
|
||||
|
||||
if m["parameter"] != "save_all" {
|
||||
t.Errorf("Expected config parameter to be 'save_all'. Got '%v'", m["parameter"])
|
||||
}
|
||||
|
||||
if m["val"] != "true" {
|
||||
t.Errorf("Expected config val to be 'true'. Got '%v'", m["val"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfig(t *testing.T) {
|
||||
clearConfigTable()
|
||||
addConfigs(1)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/config/1", nil)
|
||||
response := executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
func addConfigs(count int) {
|
||||
if count < 1 {
|
||||
count = 1
|
||||
}
|
||||
insStmt, insErr := a.DB.Prepare("INSERT INTO configs(parameter, val, createdAt, updatedAt) VALUES(?, ?, ?, ?)")
|
||||
if insErr != nil {
|
||||
panic(insErr.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
defer insStmt.Close() // Close the statement when we leave main() / the program terminates
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
insStmt.Exec("testparam"+strconv.Itoa(i), (i+1.0)*10, time.Now(), time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateConfig(t *testing.T) {
|
||||
clearConfigTable()
|
||||
addConfigs(1)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/config/1", nil)
|
||||
response := executeRequest(req)
|
||||
var originalConfig map[string]interface{}
|
||||
json.Unmarshal(response.Body.Bytes(), &originalConfig)
|
||||
|
||||
payload := []byte(`{"parameter":"test param","val":"11.22"}`)
|
||||
|
||||
req, _ = http.NewRequest("PUT", "/api/v1/config/1", bytes.NewBuffer(payload))
|
||||
response = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
var m map[string]interface{}
|
||||
json.Unmarshal(response.Body.Bytes(), &m)
|
||||
|
||||
if m["id"] != originalConfig["id"] {
|
||||
t.Errorf("Expected the id to remain the same (%v). Got %v", originalConfig["id"], m["id"])
|
||||
}
|
||||
|
||||
if m["parameter"] == originalConfig["parameter"] {
|
||||
t.Errorf("Expected the parameter to change from '%v' to '%v'. Got '%v'", originalConfig["parameter"], m["parameter"], m["parameter"])
|
||||
}
|
||||
|
||||
if m["val"] == originalConfig["val"] {
|
||||
t.Errorf("Expected the val to change from '%v' to '%v'. Got '%v'", originalConfig["val"], m["val"], m["val"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteConfig(t *testing.T) {
|
||||
clearConfigTable()
|
||||
addConfigs(1)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/config/1", nil)
|
||||
response := executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
req, _ = http.NewRequest("DELETE", "/api/v1/config/1", nil)
|
||||
response = executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
req, _ = http.NewRequest("GET", "/api/v1/config/1", nil)
|
||||
response = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusNotFound, response.Code)
|
||||
}
|
||||
156
testdatatype_test.go
Normal file
156
testdatatype_test.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const dataTypeTableCreationQuery = `CREATE TABLE IF NOT EXISTS dataTypes (
|
||||
id int(10) unsigned AUTO_INCREMENT,
|
||||
dataType varchar(255),
|
||||
plcType varchar(255),
|
||||
createdAt datetime,
|
||||
updatedAt datetime,
|
||||
UNIQUE KEY dataType (dataType),
|
||||
PRIMARY KEY (id)
|
||||
)`
|
||||
|
||||
func ensureDataTypeTableExists() {
|
||||
if _, err := a.DB.Exec(dataTypeTableCreationQuery); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func clearDataTypeTable() {
|
||||
a.DB.Exec("DELETE FROM dataTypes")
|
||||
a.DB.Exec("ALTER TABLE dataTypes AUTO_INCREMENT = 1")
|
||||
}
|
||||
|
||||
func TestEmptyDataTypeTable(t *testing.T) {
|
||||
clearDataTypeTable()
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/dataTypes", nil)
|
||||
response := executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
if body := response.Body.String(); body != "[]" {
|
||||
t.Errorf("Expected an empty array. Got %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNonExistentDataType(t *testing.T) {
|
||||
clearDataTypeTable()
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/dataType/11", nil)
|
||||
response := executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusNotFound, response.Code)
|
||||
|
||||
var m map[string]string
|
||||
json.Unmarshal(response.Body.Bytes(), &m)
|
||||
if m["error"] != "DataType not found" {
|
||||
t.Errorf("Expected the 'error' key of the response to be set to 'DataType not found'. Got '%s'", m["error"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateDataType(t *testing.T) {
|
||||
clearDataTypeTable()
|
||||
|
||||
payload := []byte(`{"dataType":"Floating Point","plcType":"REAL"}`)
|
||||
|
||||
req, _ := http.NewRequest("POST", "/api/v1/dataType", bytes.NewBuffer(payload))
|
||||
response := executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusCreated, response.Code)
|
||||
|
||||
var m map[string]interface{}
|
||||
json.Unmarshal(response.Body.Bytes(), &m)
|
||||
|
||||
if m["dataType"] != "Floating Point" {
|
||||
t.Errorf("Expected dataType dataType to be 'Floating Point'. Got '%v'", m["dataType"])
|
||||
}
|
||||
|
||||
if m["plcType"] != "REAL" {
|
||||
t.Errorf("Expected dataType plcType to be 'REAL'. Got '%v'", m["plcType"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDataType(t *testing.T) {
|
||||
clearDataTypeTable()
|
||||
addDataTypes(1)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/dataType/1", nil)
|
||||
response := executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
func addDataTypes(count int) {
|
||||
if count < 1 {
|
||||
count = 1
|
||||
}
|
||||
insStmt, insErr := a.DB.Prepare("INSERT INTO dataTypes(dataType, plcType, createdAt, updatedAt) VALUES(?, ?, ?, ?)")
|
||||
if insErr != nil {
|
||||
panic(insErr.Error()) // proper error handling instead of panic in your app
|
||||
}
|
||||
defer insStmt.Close() // Close the statement when we leave main() / the program terminates
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
insStmt.Exec("TESTTYPE"+strconv.Itoa(i), "TESTPLCTYPE"+strconv.Itoa(i), time.Now(), time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateDataType(t *testing.T) {
|
||||
clearDataTypeTable()
|
||||
addDataTypes(1)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/dataType/1", nil)
|
||||
response := executeRequest(req)
|
||||
var originalDataType map[string]interface{}
|
||||
json.Unmarshal(response.Body.Bytes(), &originalDataType)
|
||||
|
||||
payload := []byte(`{"dataType":"Floating Point","plcType":"REAL"}`)
|
||||
|
||||
req, _ = http.NewRequest("PUT", "/api/v1/dataType/1", bytes.NewBuffer(payload))
|
||||
response = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
var m map[string]interface{}
|
||||
json.Unmarshal(response.Body.Bytes(), &m)
|
||||
|
||||
if m["id"] != originalDataType["id"] {
|
||||
t.Errorf("Expected the id to remain the same (%v). Got %v", originalDataType["id"], m["id"])
|
||||
}
|
||||
|
||||
if m["dataType"] == originalDataType["dataType"] {
|
||||
t.Errorf("Expected the dataType to change from '%v' to '%v'. Got '%v'", originalDataType["dataType"], m["dataType"], m["dataType"])
|
||||
}
|
||||
|
||||
if m["plcType"] == originalDataType["plcType"] {
|
||||
t.Errorf("Expected the plcType to change from '%v' to '%v'. Got '%v'", originalDataType["plcType"], m["plcType"], m["plcType"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteDataType(t *testing.T) {
|
||||
clearDataTypeTable()
|
||||
addDataTypes(1)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/api/v1/dataType/1", nil)
|
||||
response := executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
req, _ = http.NewRequest("DELETE", "/api/v1/dataType/1", nil)
|
||||
response = executeRequest(req)
|
||||
|
||||
checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
req, _ = http.NewRequest("GET", "/api/v1/dataType/1", nil)
|
||||
response = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusNotFound, response.Code)
|
||||
}
|
||||
Reference in New Issue
Block a user