Compare commits
59 Commits
a85e63a327
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
479044d4ea
|
|||
|
fd58f130a0
|
|||
|
4dcf065501
|
|||
|
75413b2c5e
|
|||
|
453f62cfae
|
|||
|
fde246ecb7
|
|||
|
46cc0237ce
|
|||
|
3506af77bf
|
|||
|
647e02d28e
|
|||
|
5bd5237bfa
|
|||
|
f829fb08d1
|
|||
|
d77439bafd
|
|||
|
3110d315e6
|
|||
|
507f6c932b
|
|||
|
58eda6d1ea
|
|||
|
e82adbe5e4
|
|||
|
01b3b7b429
|
|||
|
38f2f627a8
|
|||
|
feef4c7800
|
|||
|
1d04006335
|
|||
|
80e3d270c8
|
|||
|
58b3dfe28a
|
|||
|
758c87652c
|
|||
|
0bdaac368c
|
|||
|
31913d0b94
|
|||
|
fb9e3130e0
|
|||
|
2aaa448331
|
|||
|
fa8e4486f3
|
|||
|
20da46a8d7
|
|||
|
4a375149f6
|
|||
|
b02dfc0dac
|
|||
|
3e77074bec
|
|||
|
bf8594a546
|
|||
|
19110e74b4
|
|||
|
840d6e2ff5
|
|||
|
6ad1e9aa5c
|
|||
|
5d2aba9caa
|
|||
|
d5cae327f3
|
|||
|
02b69b8cdf
|
|||
|
8b1d66617f
|
|||
|
b26b0c01b0
|
|||
|
f8b9b5407b
|
|||
|
31a96558bf
|
|||
|
bba55bfc0e
|
|||
|
cfb643832b
|
|||
|
497c916d93
|
|||
|
8c07677a01
|
|||
|
677ac0241d
|
|||
|
d014848e71
|
|||
|
05d1952c84
|
|||
|
fae7507407
|
|||
|
f24dcae19f
|
|||
|
3761fc1b1e
|
|||
|
b704db1ba1
|
|||
|
b3d846c6f4
|
|||
|
f5f19f6dd4
|
|||
|
af171b3344
|
|||
|
3b9df825cd
|
|||
|
eb62c78624
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -126,7 +126,6 @@ dist
|
|||||||
|
|
||||||
# vuepress v2.x temp and cache directory
|
# vuepress v2.x temp and cache directory
|
||||||
.temp
|
.temp
|
||||||
.cache
|
|
||||||
|
|
||||||
# Docusaurus cache and generated files
|
# Docusaurus cache and generated files
|
||||||
.docusaurus
|
.docusaurus
|
||||||
@@ -155,7 +154,6 @@ dist
|
|||||||
|
|
||||||
# custom
|
# custom
|
||||||
|
|
||||||
# database
|
|
||||||
database/data.db
|
database/data.db
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -1,11 +1,8 @@
|
|||||||
# GiacPoints
|
# GiacPoints
|
||||||
|
|
||||||
A system for keeping track of house chores completed and attributing points to the activities.
|
A system for keeping track of house chores completed and attributing points to the activities.
|
||||||
|
# Installation
|
||||||
# Functionality
|
`Note: Linux only`
|
||||||
|
1. Clone this repo
|
||||||
Webpage - Login, add chores/activities (admin), tick of chores (user), log of completed chores (all)
|
2. rename `database/example.db` to `database/data.db`
|
||||||
|
3. Execute `main`
|
||||||
API layer - /loginUser, /getTasks, /completeTask, /getHistory?filter, /addTask
|
|
||||||
|
|
||||||
Backend - DB, user (name password userid role), activities (taskid name points), history (userid taskid time pointsGained)
|
|
||||||
BIN
database/example.db
Normal file
BIN
database/example.db
Normal file
Binary file not shown.
67
frontend/index.css
Normal file
67
frontend/index.css
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
.flex {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.loginSpacer {
|
||||||
|
height: 33%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
height: 85%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu {
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
padding: 5%;
|
||||||
|
}
|
||||||
|
#mainPage {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen {
|
||||||
|
width: 95%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#taskButton {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#historyContent {
|
||||||
|
height: 75%;
|
||||||
|
overflow: scroll;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stats {
|
||||||
|
height: 25%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tasks {
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 0;
|
||||||
|
background: white;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#taskCard {
|
||||||
|
margin-top: 45%;
|
||||||
|
}
|
||||||
70
frontend/index.html
Normal file
70
frontend/index.html
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>GiacPoints</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/picnic">
|
||||||
|
<link rel="stylesheet" href="/frontend/index.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="login">
|
||||||
|
<div class="flex three demo" style="height: 100%; width: 100%">
|
||||||
|
<div class="fourth two-fifth-1000"></div>
|
||||||
|
<div class="flex one demo half fifth-1000" style="height: 100%">
|
||||||
|
<div class="loginSpacer"></div>
|
||||||
|
<article class="card" style="padding: 5%">
|
||||||
|
<label for="name">Name</label> <br>
|
||||||
|
<input type="text" id="name"> <br>
|
||||||
|
<label for="password">Password</label> <br>
|
||||||
|
<input type="password" id="password"> <br>
|
||||||
|
<input type="submit" value="Login" style="width: 100%" onclick="login()" id="loginSubmit"> <br>
|
||||||
|
</article>
|
||||||
|
<div class="loginSpacer"></div>
|
||||||
|
</div>
|
||||||
|
<div class="fourth two-fifth-1000"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="mainPage" style="display: none;">
|
||||||
|
<div id="content">
|
||||||
|
<div id="tasks" class="screen flex two demo" style=""></div>
|
||||||
|
<div id="history" class="screen" style="display: none;">
|
||||||
|
<div id="stats">
|
||||||
|
<article class="card">
|
||||||
|
<header>
|
||||||
|
<h1>Stats</h1>
|
||||||
|
<pre id="statData"></pre>
|
||||||
|
</header>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<div id="historyContent"></div>
|
||||||
|
</div>
|
||||||
|
<div id="addTask" class="screen" style="display: none;">
|
||||||
|
<article class="card" id="taskCard">
|
||||||
|
<header>
|
||||||
|
<h1>New task</h1> <br>
|
||||||
|
<label for="newTaskName">Task name</label>
|
||||||
|
<input type="text" id="newTaskName"> <br>
|
||||||
|
<label for="newTaskPoints">Task points</label>
|
||||||
|
<input type="number" id="newTaskPoints" min="1" max="5"> <br>
|
||||||
|
<input onclick="newTask()" value="Create" type="submit"> <br>
|
||||||
|
</header>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="menu" class="flex three demo">
|
||||||
|
<div class="third" id="taskButton">
|
||||||
|
<span class="button" onclick="switchScreen('task')">Tasks</span>
|
||||||
|
</div>
|
||||||
|
<div class="third" id="historyButton">
|
||||||
|
<span class="button" onclick="switchScreen('history')">History</span>
|
||||||
|
</div>
|
||||||
|
<div class="third" id="addButton">
|
||||||
|
<span class="button tooltip-top" onclick="switchScreen('add')" >+ Task</span>
|
||||||
|
<!-- <span class="button tooltip-top" disabled data-tooltip="In construction">+ Task</span>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="/frontend/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
200
frontend/index.js
Normal file
200
frontend/index.js
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
function sleep(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function login() {
|
||||||
|
// tell the user the app is loading
|
||||||
|
document.getElementById("loginSubmit").value = "Loading";
|
||||||
|
// this.preventDefault();
|
||||||
|
// get login details
|
||||||
|
let name = document.getElementById("name").value;
|
||||||
|
let password = document.getElementById("password").value;
|
||||||
|
// request login
|
||||||
|
let response = await fetch("/login", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: name,
|
||||||
|
password: password
|
||||||
|
})
|
||||||
|
});
|
||||||
|
// if failed red button
|
||||||
|
// else switch screen
|
||||||
|
if (response.status !== 200) {
|
||||||
|
document.getElementById("loginSubmit").classList.add("error");
|
||||||
|
document.getElementById("loginSubmit").value = "Failed";
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// switch screen
|
||||||
|
document.getElementById("login").setAttribute("style", "display: none;");
|
||||||
|
document.getElementById("mainPage").setAttribute("style", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// store user data in session storage
|
||||||
|
let data = await response.json();
|
||||||
|
localStorage.setItem("uid", data.uid);
|
||||||
|
localStorage.setItem("name", data.name);
|
||||||
|
localStorage.setItem("role", data.role);
|
||||||
|
|
||||||
|
// if role is admin, keep auto styling
|
||||||
|
if (localStorage.getItem("role") !== "admin") {
|
||||||
|
document.getElementById("addButton").setAttribute("style", "display: none;");
|
||||||
|
document.getElementById("taskButton").classList.value = "half";
|
||||||
|
document.getElementById("historyButton").classList.value = "half";
|
||||||
|
document.getElementById("menu").classList.value = "flex two";
|
||||||
|
}
|
||||||
|
|
||||||
|
await populateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function populateScreen() {
|
||||||
|
// get task data
|
||||||
|
let taskPage = document.getElementById("tasks");
|
||||||
|
taskPage.innerHTML = "";
|
||||||
|
let response = await fetch("/getTasks");
|
||||||
|
let tasksRaw = await response.json();
|
||||||
|
let tasks = tasksRaw.tasks;
|
||||||
|
|
||||||
|
// get historical data
|
||||||
|
let historyPage = document.getElementById("historyContent");
|
||||||
|
historyPage.innerHTML = "";
|
||||||
|
response = await fetch("/getHistory");
|
||||||
|
let historyRaw = await response.json();
|
||||||
|
let history = historyRaw.history;
|
||||||
|
|
||||||
|
// get points data
|
||||||
|
let statsPage = document.getElementById("statData");
|
||||||
|
statsPage.innerText = "";
|
||||||
|
response = await fetch("/getUserPoints");
|
||||||
|
let statsRaw = await response.json();
|
||||||
|
let stats = statsRaw.userPoints;
|
||||||
|
|
||||||
|
// if it is a user make the tasks add points
|
||||||
|
// or if admin make it do nothing
|
||||||
|
if (localStorage.getItem("role") === "user") {
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < tasks.length; i++) {
|
||||||
|
taskPage.innerHTML += `
|
||||||
|
<div id="${tasks[i].tid}" class="half" style="height: fit-content">
|
||||||
|
<div class="button" onclick="completeTask(${tasks[i].tid})">
|
||||||
|
<p id="taskName">${tasks[i].name}</p>
|
||||||
|
<p id="${tasks[i].tid}-p">${tasks[i].points} points</p>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
taskPage.innerHTML +=`<sub>such empty</sub>`
|
||||||
|
}
|
||||||
|
} else if (localStorage.getItem("role") === "admin") {
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < tasks.length; i++) {
|
||||||
|
taskPage.innerHTML += `
|
||||||
|
<div id="${tasks[i].tid}" class="half" style="height: fit-content">
|
||||||
|
<div class="button" disabled data-tooltip="Admins can't get points">
|
||||||
|
<p id="taskName">${tasks[i].name}</p>
|
||||||
|
<p id="${tasks[i].tid}-p">${tasks[i].points} points</p>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
taskPage.innerHTML +=`<sub>such empty</sub>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (let i = (history.length -1); i >= 0; i-=1) {
|
||||||
|
historyPage.innerHTML += `
|
||||||
|
<div class="full">
|
||||||
|
<article class="card">
|
||||||
|
<header>
|
||||||
|
<p>User: ${history[i].user}</p>
|
||||||
|
<p>Task: ${history[i].task}</p>
|
||||||
|
<p>Time: ${history[i].time}</p>
|
||||||
|
<p>Points gained: ${history[i].pointsGained}</p>
|
||||||
|
</header>
|
||||||
|
</article>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
historyPage.innerHTML += `
|
||||||
|
<sub>Such empty</sub>`
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < stats.length; i++) {
|
||||||
|
// put user points in box
|
||||||
|
statsPage.innerText += `${stats[i].name}: ${stats[i].points} \n`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function completeTask(taskID) {
|
||||||
|
let points = document.getElementById(`${taskID}-p`).innerText.split(" ")[0];
|
||||||
|
let time = new Date().toISOString().split(".")[0];
|
||||||
|
let uid = localStorage.getItem("uid");
|
||||||
|
await fetch("/completeTask", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
uid: Number(uid),
|
||||||
|
tid: Number(taskID),
|
||||||
|
time: time,
|
||||||
|
pointsGained: Number(points)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function switchScreen(button) {
|
||||||
|
await populateScreen();
|
||||||
|
document.getElementById("tasks").setAttribute("style", "display: none;");
|
||||||
|
document.getElementById("history").setAttribute("style", "display: none;");
|
||||||
|
document.getElementById("addTask").setAttribute("style", "display: none;");
|
||||||
|
|
||||||
|
if (button === "task") {
|
||||||
|
document.getElementById("tasks").setAttribute("style", "");
|
||||||
|
} else if (button === "history") {
|
||||||
|
document.getElementById("history").setAttribute("style", "");
|
||||||
|
} else if (button === "add") {
|
||||||
|
document.getElementById("addTask").setAttribute("style", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function newTask() {
|
||||||
|
let points = document.getElementById(`newTaskPoints`);
|
||||||
|
let name = document.getElementById(`newTaskName`);
|
||||||
|
await fetch("/addTask", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
tid: 0,
|
||||||
|
name: name.value,
|
||||||
|
points: Number(points.value),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
points.value = "";
|
||||||
|
name.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fastLog() {
|
||||||
|
sleep(500);
|
||||||
|
if (localStorage.getItem("uid") != null && localStorage.getItem("name") != null && localStorage.getItem("role") != null) {
|
||||||
|
document.getElementById("login").setAttribute("style", "display: none;");
|
||||||
|
document.getElementById("mainPage").setAttribute("style", "");
|
||||||
|
if (localStorage.getItem("role") !== "admin") {
|
||||||
|
document.getElementById("addButton").setAttribute("style", "display: none;");
|
||||||
|
document.getElementById("taskButton").classList.value = "half";
|
||||||
|
document.getElementById("historyButton").classList.value = "half";
|
||||||
|
document.getElementById("menu").classList.value = "flex two";
|
||||||
|
}
|
||||||
|
|
||||||
|
await populateScreen();
|
||||||
|
} else {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fastLog();
|
||||||
6
go.mod
6
go.mod
@@ -2,7 +2,10 @@ module giacPoints
|
|||||||
|
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require github.com/gin-gonic/gin v1.9.1
|
require (
|
||||||
|
github.com/gin-gonic/gin v1.9.1
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.17
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
@@ -19,7 +22,6 @@ require (
|
|||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.17 // indirect
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
|
|||||||
134
main.go
134
main.go
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"flag"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -17,11 +18,12 @@ type loginInput struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type loginOutput struct {
|
type userData struct {
|
||||||
UID int `json:"uid"`
|
UID int `json:"uid"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
|
Points int `json:"points"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type task struct {
|
type task struct {
|
||||||
@@ -34,39 +36,57 @@ type taskArray struct {
|
|||||||
Tasks []task `json:"tasks"`
|
Tasks []task `json:"tasks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type historyData struct {
|
type newHistoryData struct {
|
||||||
UID int `json:"uid"`
|
UID int `json:"uid"`
|
||||||
TID int `json:"tid"`
|
TID int `json:"tid"`
|
||||||
Time string `json:"time"`
|
Time string `json:"time"`
|
||||||
PointsGained int `json:"pointsGained"`
|
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 {
|
type historyArray struct {
|
||||||
History []historyData `json:"history"`
|
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
|
// log the user into their account
|
||||||
func login(c *gin.Context) {
|
func login(c *gin.Context) {
|
||||||
// get the username and password from the request
|
// get the username and password from the request
|
||||||
var userData loginInput
|
var requestedUser loginInput
|
||||||
if err := c.BindJSON(&userData); err != nil {
|
if err := c.BindJSON(&requestedUser); err != nil {
|
||||||
c.IndentedJSON(http.StatusBadRequest, userData)
|
c.IndentedJSON(http.StatusBadRequest, requestedUser)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// check for user using given credentials
|
// check for user using given credentials
|
||||||
stmt, err := db.Prepare("SELECT * FROM users WHERE name=?")
|
stmt, err := db.Prepare("SELECT * FROM users WHERE name=?")
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
defer stmt.Close()
|
defer stmt.Close()
|
||||||
var user loginOutput
|
var user userData
|
||||||
err = stmt.QueryRow(userData.Name).Scan(&user.Name, &user.Password, &user.UID, &user.Role)
|
err = stmt.QueryRow(requestedUser.Name).Scan(&user.UID, &user.Name, &user.Password, &user.Role, &user.Points)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// search failed user not real
|
// search failed user not real
|
||||||
c.IndentedJSON(http.StatusNotFound, userData)
|
c.IndentedJSON(http.StatusNotFound, requestedUser)
|
||||||
|
panic(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if user.Password != userData.Password {
|
if user.Password != requestedUser.Password {
|
||||||
// user not real
|
// user not real
|
||||||
c.IndentedJSON(http.StatusNotFound, userData)
|
c.IndentedJSON(http.StatusNotFound, requestedUser)
|
||||||
|
panic(err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
// user is in
|
// user is in
|
||||||
@@ -98,7 +118,7 @@ func getTasks(c *gin.Context) {
|
|||||||
|
|
||||||
func completeTask(c *gin.Context) {
|
func completeTask(c *gin.Context) {
|
||||||
// get the task data from the request
|
// get the task data from the request
|
||||||
var completedTask historyData
|
var completedTask newHistoryData
|
||||||
if err := c.BindJSON(&completedTask); err != nil {
|
if err := c.BindJSON(&completedTask); err != nil {
|
||||||
c.IndentedJSON(http.StatusBadRequest, completedTask)
|
c.IndentedJSON(http.StatusBadRequest, completedTask)
|
||||||
return
|
return
|
||||||
@@ -114,17 +134,30 @@ func completeTask(c *gin.Context) {
|
|||||||
c.IndentedJSON(http.StatusNotModified, completedTask)
|
c.IndentedJSON(http.StatusNotModified, completedTask)
|
||||||
return
|
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)
|
c.IndentedJSON(http.StatusOK, completedTask)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHistory(c *gin.Context) {
|
func getHistory(c *gin.Context) {
|
||||||
// get the log of past points gained
|
// get the log of past points gained
|
||||||
var history []historyData
|
var history []newHistoryData
|
||||||
// get array of all historyData
|
// get array of all history Data
|
||||||
rows, err := db.Query("SELECT * FROM history")
|
rows, err := db.Query("SELECT * FROM history")
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var tempHistoryData historyData
|
var tempHistoryData newHistoryData
|
||||||
err = rows.Scan(&tempHistoryData.UID, &tempHistoryData.TID, &tempHistoryData.Time, &tempHistoryData.PointsGained)
|
err = rows.Scan(&tempHistoryData.UID, &tempHistoryData.TID, &tempHistoryData.Time, &tempHistoryData.PointsGained)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.IndentedJSON(http.StatusNotFound, history)
|
c.IndentedJSON(http.StatusNotFound, history)
|
||||||
@@ -133,8 +166,37 @@ func getHistory(c *gin.Context) {
|
|||||||
history = append(history, tempHistoryData)
|
history = append(history, tempHistoryData)
|
||||||
}
|
}
|
||||||
rows.Close()
|
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
|
var jsonHistory historyArray
|
||||||
jsonHistory.History = history
|
jsonHistory.History = historyRes
|
||||||
c.IndentedJSON(http.StatusOK, jsonHistory)
|
c.IndentedJSON(http.StatusOK, jsonHistory)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,15 +221,55 @@ func addTask(c *gin.Context) {
|
|||||||
c.IndentedJSON(http.StatusOK, newTask)
|
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() {
|
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()
|
router := gin.Default()
|
||||||
|
|
||||||
|
// api routes
|
||||||
router.POST("/login", login)
|
router.POST("/login", login)
|
||||||
router.POST("/completeTask", completeTask)
|
router.POST("/completeTask", completeTask)
|
||||||
router.POST("/addTask", addTask)
|
router.POST("/addTask", addTask)
|
||||||
router.GET("/getTasks", getTasks)
|
router.GET("/getTasks", getTasks)
|
||||||
router.GET("/getHistory", getHistory)
|
router.GET("/getHistory", getHistory)
|
||||||
|
router.GET("/getUserPoints", getUserPoints)
|
||||||
|
|
||||||
router.Run("localhost:8080")
|
// 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) {
|
func checkErr(err error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user