summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnson Bridges <bridges.anson@gmail.com>2024-11-05 15:38:54 -0500
committerAnson Bridges <bridges.anson@gmail.com>2024-11-05 15:38:54 -0500
commit1cbe6a267628509c24d32b458363ddb74cb82838 (patch)
treeb933d41e17ab6456c58ccff749098ae426136876
parent411b7f175fb81aed6a9b050ce0872b376afe0431 (diff)
MMXXIV PROGRESS
-rw-r--r--dashboard_website/__pycache__/datastructs.cpython-312.pycbin7576 -> 7899 bytes
-rw-r--r--dashboard_website/__pycache__/db.cpython-312.pycbin11011 -> 11486 bytes
-rw-r--r--dashboard_website/__pycache__/router.cpython-312.pycbin15831 -> 15791 bytes
-rw-r--r--dashboard_website/dashboard.py36
-rw-r--r--dashboard_website/datastructs.py12
-rw-r--r--dashboard_website/db.py23
-rw-r--r--dashboard_website/static/img/marker-icon-black-req.pngbin0 -> 6863 bytes
-rw-r--r--dashboard_website/static/img/marker-icon-blue-req.pngbin0 -> 8222 bytes
-rw-r--r--dashboard_website/static/img/marker-icon-green-req.pngbin0 -> 8170 bytes
-rw-r--r--dashboard_website/static/img/marker-icon-grey-req.pngbin0 -> 7573 bytes
-rw-r--r--dashboard_website/static/img/marker-icon-orange-req.pngbin0 -> 8191 bytes
-rw-r--r--dashboard_website/static/img/marker-icon-red-req.pngbin0 -> 8256 bytes
-rw-r--r--dashboard_website/static/img/marker-icon-yellow-req.pngbin0 -> 8194 bytes
-rw-r--r--dashboard_website/static/js/dashboard.js117
14 files changed, 157 insertions, 31 deletions
diff --git a/dashboard_website/__pycache__/datastructs.cpython-312.pyc b/dashboard_website/__pycache__/datastructs.cpython-312.pyc
index 1436e72..ff4cf5d 100644
--- a/dashboard_website/__pycache__/datastructs.cpython-312.pyc
+++ b/dashboard_website/__pycache__/datastructs.cpython-312.pyc
Binary files differ
diff --git a/dashboard_website/__pycache__/db.cpython-312.pyc b/dashboard_website/__pycache__/db.cpython-312.pyc
index 99f804e..2172d4d 100644
--- a/dashboard_website/__pycache__/db.cpython-312.pyc
+++ b/dashboard_website/__pycache__/db.cpython-312.pyc
Binary files differ
diff --git a/dashboard_website/__pycache__/router.cpython-312.pyc b/dashboard_website/__pycache__/router.cpython-312.pyc
index 7252768..2611148 100644
--- a/dashboard_website/__pycache__/router.cpython-312.pyc
+++ b/dashboard_website/__pycache__/router.cpython-312.pyc
Binary files differ
diff --git a/dashboard_website/dashboard.py b/dashboard_website/dashboard.py
index ba29799..8ec53e0 100644
--- a/dashboard_website/dashboard.py
+++ b/dashboard_website/dashboard.py
@@ -172,10 +172,33 @@ def visitTeam():
# ERROR CODES: 1 = missing fields, 2 = clue doesn't exist, 3 = already marked as visited
def visitGeneric():
content = request.get_json()
+ unvisit = False
+ print(content)
+ if "unvisit" in content:
+ unvisit = True
+
if not ('clue_name' in content):
return jsonify({'status' : "ERROR 1"})
- result = db.visitClue(content['clue_name'])
+ result = db.visitClue(content['clue_name'], unvisit)
+ if result != 0:
+ return jsonify({'status' : f"ERROR {result}"})
+ return jsonify({'status' : "OK"})
+
+@app.route("/requireClue", methods=['POST'])
+# Expected JSON
+# {"clue_name" : xxxx, str}
+# Returns JSON
+# {"status" : "OK"/"ERROR XX" }
+# ERROR CODES: 1 = missing fields, 2 = clue doesn't exist, 3 = already marked as visited
+def requireClue():
+ content = request.get_json()
+ print(content)
+
+ if not ('clue_name' in content):
+ return jsonify({'status' : "ERROR 1"})
+
+ result = db.toggleClueRequired(content['clue_name'])
if result != 0:
return jsonify({'status' : f"ERROR {result}"})
return jsonify({'status' : "OK"})
@@ -236,11 +259,14 @@ def getLatestInfo():
@app.route("/addClue", methods=['POST'])
def addClueWeb():
content = request.get_json()
-
+ print("adding clue:", content)
if not ('clue_name' in content and 'longitude' in content and 'latitude' in content and 'clue_info' in content):
- return jsonify({'status' : "ERROR 1"})
- #db.addClue()
- return jsonify({'status' : "OK",})
+ return jsonify({'status' : "ERROR: INVALID CLUE JSON FORMAT"})
+ res = db.addClue(content['clue_name'], content['clue_info'], content['latitude'], content['longitude'])
+ if res == 0:
+ return jsonify({'status' : "OK",})
+ elif res == -1:
+ return jsonify({'status' : "CLUE NAME ALREADY EXISTS"})
# main page
diff --git a/dashboard_website/datastructs.py b/dashboard_website/datastructs.py
index f150825..1b4b92b 100644
--- a/dashboard_website/datastructs.py
+++ b/dashboard_website/datastructs.py
@@ -48,31 +48,37 @@ class Point:
class Clue(Point):
- def __init__(self, lat, long, name, info, status, pool_index = 0, required=False):
+ def __init__(self, lat, long, name, info, status, assigned_team = 0, required=False):
self.longitude = long
self.latitude = lat
self.name = name
self.info = info
self.status = status # UNVISITED | VISITED | DISABLED | ASSIGNED
- self.pool_inbex = pool_index
+ self.assigned_team = assigned_team # 0 = to be assigned algorithmically
self.required = required
-
def visit(self):
self.status = "VISITED"
+ def unvisit(self):
+ self.status = "UNVISITED"
+
def toggle_enable(self):
if self.status == "UNVISITED" or self.status == "ASSIGNED":
self.status = "DISABLED"
elif self.status == "DISABLED":
self.status = "UNVISITED"
+ def toggle_required(self):
+ self.required = False if self.required else True
+
def toJSON(self):
json_dict = {'longitude' : self.longitude,
'latitude' : self.latitude,
'clue_name' : self.name.replace('"', "'"),
'clue_info' : self.info.replace('"', "'"),
'clue_status' : self.status,
+ 'assigned_team' : self.assigned_team,
'clue_required' : self.required}
return json_dict
diff --git a/dashboard_website/db.py b/dashboard_website/db.py
index 6991121..7bb5a18 100644
--- a/dashboard_website/db.py
+++ b/dashboard_website/db.py
@@ -141,9 +141,14 @@ def getCluesJSON(timestamp):
def addClue(clue_name, clue_info, longitude, latitude, status="UNVISITED"):
+ global clues_last_changed
+ for clue in clues:
+ if clue.name == clue_name:
+ return -1 # clue already exists
newClue = Clue(latitude, longitude, clue_name, clue_info, status)
clues.append(newClue)
clues_last_changed = time.time()
+ return 0
def deleteClue(clue_name):
@@ -155,11 +160,15 @@ def deleteClue(clue_name):
break
-def visitClue(clue_name):
+def visitClue(clue_name, unvisit=False):
global clues_last_changed
for clue in clues:
if clue.name == clue_name:
if clue.status == "VISITED":
+ if unvisit:
+ clue.unvisit()
+ clues_last_changed = time.time()
+ return 0
return 3 # already visited
clue.visit()
clues_last_changed = time.time()
@@ -178,6 +187,16 @@ def toggleEnableClue(clue_name):
return 0 # OK
return 2 # no clue
+def toggleClueRequired(clue_name):
+ global clues_last_changed
+ for clue in clues:
+ if clue.name == clue_name:
+ clue.toggle_required()
+ clues_last_changed = time.time()
+ updateRoutes()
+ return 0 # OK
+ return 2 # no clue
+
def visitClueTeam(team_name, clue_name):
global clues_last_changed
@@ -287,4 +306,4 @@ def save():
csvwriter.writerow([clue.name, clue.latitude, clue.longitude, clue.info, clue.status])
-load() \ No newline at end of file
+#load("all_clues.csv") \ No newline at end of file
diff --git a/dashboard_website/static/img/marker-icon-black-req.png b/dashboard_website/static/img/marker-icon-black-req.png
new file mode 100644
index 0000000..372b07d
--- /dev/null
+++ b/dashboard_website/static/img/marker-icon-black-req.png
Binary files differ
diff --git a/dashboard_website/static/img/marker-icon-blue-req.png b/dashboard_website/static/img/marker-icon-blue-req.png
new file mode 100644
index 0000000..4ee83f5
--- /dev/null
+++ b/dashboard_website/static/img/marker-icon-blue-req.png
Binary files differ
diff --git a/dashboard_website/static/img/marker-icon-green-req.png b/dashboard_website/static/img/marker-icon-green-req.png
new file mode 100644
index 0000000..173476d
--- /dev/null
+++ b/dashboard_website/static/img/marker-icon-green-req.png
Binary files differ
diff --git a/dashboard_website/static/img/marker-icon-grey-req.png b/dashboard_website/static/img/marker-icon-grey-req.png
new file mode 100644
index 0000000..7d6dde1
--- /dev/null
+++ b/dashboard_website/static/img/marker-icon-grey-req.png
Binary files differ
diff --git a/dashboard_website/static/img/marker-icon-orange-req.png b/dashboard_website/static/img/marker-icon-orange-req.png
new file mode 100644
index 0000000..55316ce
--- /dev/null
+++ b/dashboard_website/static/img/marker-icon-orange-req.png
Binary files differ
diff --git a/dashboard_website/static/img/marker-icon-red-req.png b/dashboard_website/static/img/marker-icon-red-req.png
new file mode 100644
index 0000000..4fba983
--- /dev/null
+++ b/dashboard_website/static/img/marker-icon-red-req.png
Binary files differ
diff --git a/dashboard_website/static/img/marker-icon-yellow-req.png b/dashboard_website/static/img/marker-icon-yellow-req.png
new file mode 100644
index 0000000..41e8d3f
--- /dev/null
+++ b/dashboard_website/static/img/marker-icon-yellow-req.png
Binary files differ
diff --git a/dashboard_website/static/js/dashboard.js b/dashboard_website/static/js/dashboard.js
index 3ff0de9..43c07f3 100644
--- a/dashboard_website/static/js/dashboard.js
+++ b/dashboard_website/static/js/dashboard.js
@@ -25,12 +25,27 @@ var baseIcon = L.Icon.extend({
var homeIcon = new baseIcon({iconUrl: 'static/img/marker-home.png'}),
activeBikeIcon = new baseIcon({iconUrl: 'static/img/marker-bike-active.png', className:"leaflet-bike-marker"}),
inactiveBikeIcon = new baseIcon({iconUrl: 'static/img/marker-bike-inactive.png'}),
- visitedIcon = new baseIcon({iconUrl: 'static/img/marker-icon-grey.png'}),
- unvisitedIcon = new baseIcon({iconUrl: 'static/img/marker-icon-blue.png'}), // generic, becomes colored when assigned to route
- orangeIcon = new baseIcon({iconUrl: 'static/img/marker-icon-orange.png'}),
- redIcon = new baseIcon({iconUrl: 'static/img/marker-icon-red.png'}),
- greenIcon = new baseIcon({iconUrl: 'static/img/marker-icon-green.png'}),
- yellowIcon = new baseIcon({iconUrl: 'static/img/marker-icon-yellow.png'});
+ visitedIcon = new baseIcon({iconUrl: 'static/img/marker-icon-green.png'}),
+ disabledIcon = new baseIcon({iconUrl: 'static/img/marker-icon-black.png'}),
+ unvisitedIcon = new baseIcon({iconUrl: 'static/img/marker-icon-grey.png'}), // generic, becomes colored when assigned to route
+ visitedIconReq = new baseIcon({iconUrl: 'static/img/marker-icon-green-req.png'}),
+ disabledIconReq = new baseIcon({iconUrl: 'static/img/marker-icon-black-req.png'}),
+ unvisitedIconReq = new baseIcon({iconUrl: 'static/img/marker-icon-grey-req.png'}); // generic, becomes colored when assigned to route
+var teamIcons = [ unvisitedIcon,
+ new baseIcon({iconUrl: 'static/img/marker-icon-orange.png'}),
+ new baseIcon({iconUrl: 'static/img/marker-icon-red.png'}),
+ new baseIcon({iconUrl: 'static/img/marker-icon-green.png'}),
+ new baseIcon({iconUrl: 'static/img/marker-icon-yellow.png'}) ];
+var teamIconsReq = [ disabledIconReq,
+ new baseIcon({iconUrl: 'static/img/marker-icon-orange-req.png'}),
+ new baseIcon({iconUrl: 'static/img/marker-icon-red-req.png'}),
+ new baseIcon({iconUrl: 'static/img/marker-icon-green-req.png'}),
+ new baseIcon({iconUrl: 'static/img/marker-icon-yellow-req.png'}) ];
+
+ team1IconReq = new baseIcon({iconUrl: 'static/img/marker-icon-orange.png'}),
+ team2IconReq = new baseIcon({iconUrl: 'static/img/marker-icon-red.png'}),
+ team3IconReq = new baseIcon({iconUrl: 'static/img/marker-icon-green.png'}),
+ team4Icon = new baseIcon({iconUrl: 'static/img/marker-icon-yellow.png'});
var bikeIcons = {'ACTIVE' : activeBikeIcon, 'INACTIVE' : inactiveBikeIcon}
function zoomToBike(team_name){
@@ -121,41 +136,83 @@ function drawClues(){
unvisited_clues_m.clearLayers();
visited_clues_m.clearLayers();
for (var i = 0; i < clues.length; i++) {
- var tempIcon = visitedIcon;
- if (clues[i]['clue_status'] == "UNVISITED") tempIcon = unvisitedIcon;
+ var tempIcon = teamIcons[clues[i]['assigned_team']];
+ if(clues[i]['clue_required']){
+ tempIcon = teamIconsReq[clues[i]['assigned_team']];
+ if (clues[i]['clue_status'] == "UNVISITED") tempIcon = unvisitedIconReq;
+ if (clues[i]['clue_status'] == "VISITED") tempIcon = visitedIconReq;
+ }
+ else{
+ if (clues[i]['clue_status'] == "UNVISITED") tempIcon = unvisitedIcon;
+ if (clues[i]['clue_status'] == "VISITED") tempIcon = visitedIcon;
+ }
+
var popupdiv = document.createElement('p');
var toggleVisitText = clues[i]['clue_status'] == "UNVISITED" ? "Visit" : "Unvisit";
var toggleDisableText = clues[i]['clue_status'] != "DISABLED" ? "Disable" : "Enable";
- popupdiv.innerHTML = "<span style='color:black'>" + clues[i]['clue_name'] + ": " + clues[i]['clue_info'] + "</span>";
- popupdiv.innerHTML += "<button id=\"visitbutton_"+clues[i]['clue_name']+"style='margin-left:2px' onclick=\"toggleVisitClue('"+clues[i]['clue_name']+"')\""+(clues[i]['clue_status'] == "DISABLED" ? "disabled" : "")+">"+toggleVisitText+"</button>";
- popupdiv.innerHTML += "<button id=\"enablebutton_"+clues[i]['clue_name']+"style='margin-left:2px' onclick=\"toggleEnableClue('"+clues[i]['clue_name']+"')\""+(clues[i]['clue_status'] == "VISITED" ? "disabled" : "")+">"+toggleDisableText+"</button>";
- var clueMarker = L.marker([clues[i]['latitude'], clueVisits[i]['longitude']], {icon: tempIcon}).bindPopup(popupdiv);
+ popupdiv.innerHTML = "<span style='color:black'>" + clues[i]['clue_name'] + ": </span><span style='color:grey'>" + clues[i]['clue_info'] + "</span><br/>";
+ popupdiv.innerHTML += "<button id=\"visitbutton_"+clues[i]['clue_name']+"\" style='margin-left:2px' onclick=\"toggle_visit_clue('"+clues[i]['clue_name']+"')\""+(clues[i]['clue_status'] == "DISABLED" ? "disabled" : "")+">"+toggleVisitText+"</button>";
+ popupdiv.innerHTML += "<button id=\"enablebutton_"+clues[i]['clue_name']+"\" style='margin-left:2px' onclick=\"toggle_enable_clue('"+clues[i]['clue_name']+"')\""+(clues[i]['clue_status'] == "VISITED" ? "disabled" : "")+">"+toggleDisableText+"</button>";
+ popupdiv.innerHTML += "<button id=\"requirebutton_"+clues[i]['clue_name']+"\" style='margin-left:2px' onclick=\"toggle_required_clue('"+clues[i]['clue_name']+"')\">"+(clues[i]['clue_required'] ? "Un-require" : "Require")+"</button></br>";
+ popupdiv.innerHTML += "<div style='color:grey'>Assigned team: <select style='color:grey' id='assignedteam_"+clues[i]['clue_name']+"'><option value='0'>None</option> <option value='1'>Team 1</option> <option value='2'>Team 2</option> <option value='3'>Team 3</option> <option value='4'>Team 4</option></select></span>";
+ var clueMarker = L.marker([clues[i]['longitude'], clues[i]['latitude']], {icon: tempIcon}).bindPopup(popupdiv);
clue_rels[clues[i]['clue_name']] = clueMarker;
if (clues[i]['clue_status'] == "UNVISITED") unvisited_clues_m.addLayer(clueMarker);
else visited_clues_m.addLayer(clueMarker);
+ popupdiv.querySelector("#assignedteam_"+clues[i]['clue_name']).selectedIndex = clues[i]['assigned_team'];
}
}
-function toggleVisitClue(clue_name){
+function toggle_visit_clue(clue_name){
if(!confirm("Are you sure you want to visit/unvisit this clue?")) return;
console.log("toggling visited status for "+clue_name);
- document.getElementById("visitbutton_"+clues[i]['clue_name']).disabled = true; // temporarily disable buttons until new server frame received
- document.getElementById("enablebutton_"+clues[i]['clue_name']).disabled = true;
+ var clue = get_clue_by_name(clue_name);
+ document.getElementById("visitbutton_"+clue['clue_name']).disabled = true; // temporarily disable buttons until new server frame received
+ document.getElementById("enablebutton_"+clue['clue_name']).disabled = true;
+ document.getElementById("requirebutton_"+clue['clue_name']).disabled = true;
fetch(host+'/visitClueGeneric', {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
- body: JSON.stringify({ "clue_name" : clue_name })})
+ body: JSON.stringify({ "clue_name" : clue_name, "unvisit": true})}) // unvisit (if appropriate)
.then((response) => response.json())
.then((json) => console.log(json));
}
-function toggleEnableClue(clue_name){
+function toggle_required_clue(clue_name){
+ if(!confirm("Are you sure you want to mark/unmark this clue?")) return;
+ console.log("toggling visited status for "+clue_name);
+ var clue = get_clue_by_name(clue_name);
+ document.getElementById("visitbutton_"+clue['clue_name']).disabled = true; // temporarily disable buttons until new server frame received
+ document.getElementById("enablebutton_"+clue['clue_name']).disabled = true;
+ document.getElementById("requirebutton_"+clue['clue_name']).disabled = true;
+ fetch(host+'/requireClue', {
+ method: "POST",
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ "clue_name" : clue_name, "unvisit": true})}) // unvisit (if appropriate)
+ .then((response) => response.json())
+ .then((json) => console.log(json));
+}
+
+function get_clue_by_name(clue_name){
+ for (var i = 0; i < clues.length; i++)
+ if(clues[i]['clue_name'] == clue_name)
+ return clues[i];
+ return NaN;
+}
+
+function toggle_enable_clue(clue_name){
+ if(!confirm("Are you sure you want to enable/disable this clue?")) return;
console.log("toggling enabled status for "+clue_name);
- document.getElementById("visitbutton_"+clues[i]['clue_name']).disabled = true; // temporarily disable buttons until new server frame received
- document.getElementById("enablebutton_"+clues[i]['clue_name']).disabled = true;
+ var clue = get_clue_by_name(clue_name);
+ document.getElementById("visitbutton_"+clue['clue_name']).disabled = true; // temporarily disable buttons until new server frame received
+ document.getElementById("enablebutton_"+clue['clue_name']).disabled = true;
+ document.getElementById("requirebutton_"+clue['clue_name']).disabled = true;
fetch(host+'/enableClue', {
method: "POST",
headers: {
@@ -168,6 +225,8 @@ function toggleEnableClue(clue_name){
}
function addClue(){
+ var clue_name = document.getElementById("new_clue_name").value;
+ var clue_info = document.getElementById("new_clue_info").value;
var long = parseFloat(document.getElementById("new_clue_longitude").value);
var lat = parseFloat(document.getElementById("new_clue_latitude").value);
if (isNaN(long) || isNaN(lat)){
@@ -175,12 +234,28 @@ function addClue(){
return;
}
if(confirm("Are you sure this is the right location?")){
- console.log("yes");
+ console.log("adding clue...");
+ fetch(host+'/addClue', {
+ method: "POST",
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ "clue_name" : clue_name, "clue_info" : clue_info, "latitude" : lat, "longitude" : long})})
+ .then((response) => response.json())
+ .then((json) => {
+ console.log(json);
+ if(json['status'] != "OK")
+ alert(json['status']);
+ else
+ alert("Clue added successfully.");
+ });
}
}
// run every x seconds to get latest info from server
function requestLatestInfo(){
+ console.log("requesting update");
function handleLatestInfo(json){
if(json['status'] != "OK") return;
latest_timestamp = json['timestamp'];
@@ -278,7 +353,7 @@ window.onload = function() {
}).addTo(previewmap);
//homemarker = L.marker([homebase['latitude'], homebase['longitude']], {icon: homeIcon}).addTo(map).bindPopup("Home is where the club is.");
- previewmarker = L.marker([0,0], {icon: greenIcon}).addTo(previewmap);
+ previewmarker = L.marker([0,0], {icon: visitedIcon}).addTo(previewmap);
map.addLayer(visited_clues_m);
map.addLayer(unvisited_clues_m);
map.addLayer(bikes_m);