package main import ( "database/sql" "flag" "github.com/gin-gonic/gin" _ "github.com/mattn/go-sqlite3" "net/http" ) // define global db var db, _ = sql.Open("sqlite3", "./database/data.db") // types representing json queries type loginInput struct { Name string `json:"name"` Password string `json:"password"` } type userData struct { UID int `json:"uid"` Name string `json:"name"` Password string `json:"password"` Role string `json:"role"` Points int `json:"points"` } type task struct { TID int `json:"tid"` Name string `json:"name"` Points int `json:"points"` } type taskArray struct { Tasks []task `json:"tasks"` } type newHistoryData struct { UID int `json:"uid"` TID int `json:"tid"` Time string `json:"time"` PointsGained int `json:"pointsGained"` } type historyData struct { User string `json:"user"` Task string `json:"task"` Time string `json:"time"` PointsGained int `json:"pointsGained"` } type historyArray struct { History []historyData `json:"history"` } type userPointsData struct { Name string `json:"name"` Points int `json:"points"` } type userPointsArray struct { UserPoints []userPointsData `json:"userPoints"` } // log the user into their account func login(c *gin.Context) { // get the username and password from the request var requestedUser loginInput if err := c.BindJSON(&requestedUser); err != nil { c.IndentedJSON(http.StatusBadRequest, requestedUser) return } // check for user using given credentials stmt, err := db.Prepare("SELECT * FROM users WHERE name=?") checkErr(err) defer stmt.Close() var user userData err = stmt.QueryRow(requestedUser.Name).Scan(&user.UID, &user.Name, &user.Password, &user.Role, &user.Points) if err != nil { // search failed user not real c.IndentedJSON(http.StatusNotFound, requestedUser) panic(err) return } if user.Password != requestedUser.Password { // user not real c.IndentedJSON(http.StatusNotFound, requestedUser) panic(err) return } else { // user is in c.IndentedJSON(http.StatusOK, user) } } func getTasks(c *gin.Context) { // return a list of all the tasks var tasks []task // get array of all tasks rows, err := db.Query("SELECT * FROM activities") checkErr(err) for rows.Next() { var tempTask task err = rows.Scan(&tempTask.TID, &tempTask.Name, &tempTask.Points) if err != nil { c.IndentedJSON(http.StatusNotFound, tasks) return } tasks = append(tasks, tempTask) } rows.Close() var jsonTasks taskArray jsonTasks.Tasks = tasks c.IndentedJSON(http.StatusOK, jsonTasks) } func completeTask(c *gin.Context) { // get the task data from the request var completedTask newHistoryData if err := c.BindJSON(&completedTask); err != nil { c.IndentedJSON(http.StatusBadRequest, completedTask) return } // insert data to history table stmt, err := db.Prepare("INSERT INTO history (uid, taskid, time, pointsGained) VALUES (?, ?, ?, ?)") if err != nil { c.IndentedJSON(http.StatusNotModified, completedTask) return } _, err = stmt.Exec(completedTask.UID, completedTask.TID, completedTask.Time, completedTask.PointsGained) if err != nil { c.IndentedJSON(http.StatusNotModified, completedTask) return } // add points to user table stmt, err = db.Prepare("UPDATE users SET points = points + ? WHERE uid=?") if err != nil { c.IndentedJSON(http.StatusNotModified, completedTask) return } _, err = stmt.Exec(completedTask.PointsGained, completedTask.UID) if err != nil { c.IndentedJSON(http.StatusNotModified, completedTask) return } c.IndentedJSON(http.StatusOK, completedTask) } func getHistory(c *gin.Context) { // get the log of past points gained var history []newHistoryData // get array of all history Data rows, err := db.Query("SELECT * FROM history") checkErr(err) for rows.Next() { var tempHistoryData newHistoryData err = rows.Scan(&tempHistoryData.UID, &tempHistoryData.TID, &tempHistoryData.Time, &tempHistoryData.PointsGained) if err != nil { c.IndentedJSON(http.StatusNotFound, history) return } history = append(history, tempHistoryData) } rows.Close() var historyRes []historyData // make the data human-readable for i := 0; i < len(history); i++ { var tempHistory historyData // get the username var tempUser userData stmt, err := db.Prepare("SELECT * FROM users WHERE uid=?") checkErr(err) err = stmt.QueryRow(history[i].UID).Scan(&tempUser.UID, &tempUser.Name, &tempUser.Password, &tempUser.Role, &tempUser.Points) checkErr(err) tempHistory.User = tempUser.Name stmt.Close() // get the task name and points var tempTask task stmt, err = db.Prepare("SELECT * FROM activities WHERE taskId=?") checkErr(err) err = stmt.QueryRow(history[i].TID).Scan(&tempTask.TID, &tempTask.Name, &tempTask.Points) checkErr(err) tempHistory.Task = tempTask.Name tempHistory.PointsGained = tempTask.Points stmt.Close() tempHistory.Time = history[i].Time historyRes = append(historyRes, tempHistory) } var jsonHistory historyArray jsonHistory.History = historyRes c.IndentedJSON(http.StatusOK, jsonHistory) } func addTask(c *gin.Context) { // get the data of the new task var newTask task if err := c.BindJSON(&newTask); err != nil { c.IndentedJSON(http.StatusBadRequest, newTask) return } // insert new task into the task table stmt, err := db.Prepare("INSERT INTO activities (name, points) VALUES (?,?)") if err != nil { c.IndentedJSON(http.StatusNotModified, newTask) return } _, err = stmt.Exec(newTask.Name, newTask.Points) if err != nil { c.IndentedJSON(http.StatusNotModified, newTask) return } c.IndentedJSON(http.StatusOK, newTask) } func getUserPoints(c *gin.Context) { // get the names of all users var allUsers []userPointsData rows, err := db.Query("SELECT name, points FROM users WHERE role='user'") checkErr(err) // put them in an array of users for rows.Next() { var tempUser userPointsData err = rows.Scan(&tempUser.Name, &tempUser.Points) if err != nil { c.IndentedJSON(http.StatusNotFound, allUsers) return } allUsers = append(allUsers, tempUser) } rows.Close() // return to the requester var jsonUserPoints userPointsArray jsonUserPoints.UserPoints = allUsers c.IndentedJSON(http.StatusOK, jsonUserPoints) } func main() { var port string flag.StringVar(&port, "port", "localhost:8080", "define the port you want the program to use to serve") flag.Parse() //release mode //gin.SetMode(gin.ReleaseMode) router := gin.Default() // api routes router.POST("/login", login) router.POST("/completeTask", completeTask) router.POST("/addTask", addTask) router.GET("/getTasks", getTasks) router.GET("/getHistory", getHistory) router.GET("/getUserPoints", getUserPoints) // page routes router.LoadHTMLGlob("frontend/*") router.GET("/", func(c *gin.Context) { c.HTML(http.StatusOK, "index.html", gin.H{}) }) router.Static("/frontend", "./frontend") router.Run(port) } func checkErr(err error) { if err != nil { panic(err) } }