Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync hardware-team with master #347

Merged
merged 102 commits into from Apr 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
f08e0fc
Add method to Grafana API to get an array of all dashboards. Useful f…
daisycrego Apr 3, 2020
7e22fc6
Issue #225: When a GFCoonfig is created, dashboards are added for any…
daisycrego Apr 3, 2020
e055198
Issue #225: Tests for GFConfig - when a GFConfig is created, if there…
daisycrego Apr 3, 2020
2ea3592
Getting in sync with frontend-team before merging in latest.
daisycrego Apr 3, 2020
544ff64
Fix setup script to reflect settings in env file
alldne Apr 4, 2020
c7889da
add api without event uuid
VentusXu09 Apr 4, 2020
de730a9
Merge pull request #299 from gcivil-nyu-org/backend/fix-script
VentusXu09 Apr 4, 2020
828ddfc
Initial commit for #295: GF Config: View Existing Dashboards
daisycrego Apr 4, 2020
a1e2ede
Issue #295: Add test of updated GFConfig view: If a dashboard exists,…
daisycrego Apr 4, 2020
f8326cc
Issue #295: Improve test of GFConfig GET view to confirm that the cor…
daisycrego Apr 4, 2020
434495d
Update GFConfig view to include link to Grafana for each event. Add m…
daisycrego Apr 5, 2020
9f8f33c
Improve SensorPanels form style.
daisycrego Apr 5, 2020
e8b234a
Issue #295: Add update_dashboard function to GFConfig view - when upd…
daisycrego Apr 5, 2020
512cd2c
Fix issue with test_config_post_event_exists_dashboard_created which …
daisycrego Apr 5, 2020
5728730
Black and flake8.
daisycrego Apr 5, 2020
71c5213
Issue #295: Add a CustomModelChoiceField class which extends ModelMul…
daisycrego Apr 5, 2020
abf52f4
Issue #295: Reset Dashboards view: Created a new view for handling da…
daisycrego Apr 5, 2020
c094010
Issue #295: Add delete dashboard feature to GFConfig Dashboards view.…
daisycrego Apr 5, 2020
0ab2884
Merge pull request #294 from gcivil-nyu-org/grafana
sunnybansal Apr 5, 2020
67decc2
Merge pull request #305 from gcivil-nyu-org/backend/develop
iamvibhorsingh Apr 5, 2020
0218feb
#295 Support multiple GFConfigs.
daisycrego Apr 6, 2020
170ba80
Sync with master. Merge branch 'master' into frontend-tea.
daisycrego Apr 6, 2020
d0325a2
Export all events
sunnybansal Apr 1, 2020
b859922
Merge branch 'frontend-team' into events_export_all
sunnybansal Apr 6, 2020
f200df4
Merge pull request #312 from gcivil-nyu-org/events_export_all
daisycrego Apr 6, 2020
a45e673
Merge branch 'backend-team' into backend/develop
alldne Apr 7, 2020
349f420
Merge pull request #316 from gcivil-nyu-org/backend/develop
iamvibhorsingh Apr 7, 2020
eea538b
Copy template `properties` files
alldne Apr 3, 2020
fbbe01f
Specify default port of SymmetricDS in the template
alldne Apr 3, 2020
015ae0d
Update `properties` templates
alldne Apr 5, 2020
ebbcb23
Do not check sync.url as a mandatory
alldne Apr 5, 2020
2ebce3e
Implement `make configure`
alldne Apr 5, 2020
d3cf493
Add clean-symd-table
alldne Apr 5, 2020
3ad0ffc
Change tables to sync from mercury_* to ag_*
alldne Apr 5, 2020
ecbe94a
Add `create-sym-table` to configuration script
alldne Apr 7, 2020
d4440d9
Update properties file template
alldne Apr 7, 2020
c73e97e
Add README.md
alldne Apr 7, 2020
6cfa17f
Do not check db.password
alldne Apr 7, 2020
6938e1d
Merge pull request #314 from gcivil-nyu-org/hardware-team
alldne Apr 7, 2020
4129d07
Merge pull request #318 from gcivil-nyu-org/backend/symd-configuration
alldne Apr 7, 2020
46fbc42
Merge remote-tracking branch 'origin/master' into backend/develop
alldne Apr 7, 2020
cd4dbbc
Merge pull request #319 from gcivil-nyu-org/backend/develop
VentusXu09 Apr 7, 2020
d55d211
Merge pull request #320 from gcivil-nyu-org/backend-team
alldne Apr 7, 2020
9c46edd
Merge branch 'backend/develop' of https://github.com/gcivil-nyu-org/s…
VentusXu09 Apr 8, 2020
f3cdf88
Get in sync with frontend-team.
daisycrego Apr 8, 2020
0582542
Fix issue with reset/delete/update where actions intended for one GFC…
daisycrego Apr 8, 2020
47f0af8
Merge branch 'frontend-team' into grafana
daisycrego Apr 8, 2020
44ec773
Black and flake8.
daisycrego Apr 8, 2020
75f760a
Merge with remote grafana. Merge branch 'grafana' of https://github.c…
daisycrego Apr 8, 2020
cd3310f
Fix bug in grafana API that was causing tests to fail: syntax error w…
daisycrego Apr 8, 2020
f7b879a
Fix issue with test: current testing approach doesn't allow for destr…
daisycrego Apr 8, 2020
dc38e8d
Black.
daisycrego Apr 8, 2020
1342168
[WIP]Commit includes active event functionality
sunnybansal Apr 8, 2020
587e77e
refine code based on pr comments
VentusXu09 Apr 9, 2020
51de2e7
Update create_postgres_datasource to disable ssl when no password is …
daisycrego Apr 9, 2020
dc77675
Merging
daisycrego Apr 9, 2020
cc24476
set up test-only grafana instance
tianrunw Apr 9, 2020
0009de3
Printing some info to see on heroku logs (errors only occuring on her…
daisycrego Apr 9, 2020
1711101
Merge
daisycrego Apr 9, 2020
1765054
Printing some info to see on heroku logs (errors only occuring on her…
daisycrego Apr 9, 2020
398df77
Printing some info to see on heroku logs (errors only occuring on her…
daisycrego Apr 9, 2020
ceb40c0
Printing some info to see on heroku logs (errors only occuring on her…
daisycrego Apr 9, 2020
d2a105a
Remove debug print statements.
daisycrego Apr 9, 2020
157e4cb
More attempts to fix password missing from datasource.
daisycrego Apr 9, 2020
52b9ced
More attempts to fix password missing from datasource.
daisycrego Apr 9, 2020
c2c69e1
Sync grafana with master
daisycrego Apr 9, 2020
4618901
Merge pull request #321 from gcivil-nyu-org/backend/feature/measureme…
alldne Apr 9, 2020
1a03fd2
Disable sslmode when creating a grafana datasource without a username…
daisycrego Apr 9, 2020
9e5eace
Remove debug print statements.
daisycrego Apr 9, 2020
0726ff5
Fix test to avoid concurrency failure.
daisycrego Apr 9, 2020
7fbeafc
Merge pull request #322 from gcivil-nyu-org/grafana
daisycrego Apr 9, 2020
90df65e
Merge branch 'frontend-team' into active_event_creation
daisycrego Apr 9, 2020
c04e8f7
Merge pull request #323 from gcivil-nyu-org/active_event_creation
daisycrego Apr 9, 2020
78588df
Merge pull request #324 from gcivil-nyu-org/frontend-team
daisycrego Apr 9, 2020
8c619ca
Merge branch 'master' of https://github.com/gcivil-nyu-org/spring2020…
VentusXu09 Apr 9, 2020
35c63b5
Resolve issues based on PR feedback.
daisycrego Apr 9, 2020
9e343b6
Merge branch 'frontend-team' into grafana
daisycrego Apr 9, 2020
d281d50
Merge pull request #326 from gcivil-nyu-org/grafana
daisycrego Apr 9, 2020
420b5eb
Merge pull request #325 from gcivil-nyu-org/backend/merge_master
alldne Apr 9, 2020
d6c06a1
Merge pull request #327 from gcivil-nyu-org/frontend-team
daisycrego Apr 9, 2020
f215a90
Merge pull request #328 from gcivil-nyu-org/backend/develop
alldne Apr 9, 2020
847804d
Merge branch 'master' of https://github.com/gcivil-nyu-org/spring2020…
VentusXu09 Apr 9, 2020
8f244f1
Merge pull request #330 from gcivil-nyu-org/backend/merge_master
alldne Apr 9, 2020
c9fb656
Changing order of Grafana API invocations in gf_config view so that d…
daisycrego Apr 9, 2020
673c522
Merge branch 'master' of https://git.heroku.com/sextants-telemetry in…
daisycrego Apr 9, 2020
fec46f2
One more change to fix datasource issue: order of grafana api incovat…
daisycrego Apr 9, 2020
e5ba27a
Fix gf_config post method so that it returns all necessary context wh…
daisycrego Apr 9, 2020
3d5bb91
Merge pull request #331 from gcivil-nyu-org/backend/develop
alldne Apr 9, 2020
90c5383
Change create_postgres_datasource() method to give the datasource the…
daisycrego Apr 9, 2020
ee5792e
Merge pull request #329 from gcivil-nyu-org/backend-team
alldne Apr 9, 2020
d6bbd1b
Update README.md
alldne Apr 9, 2020
0aca4cd
Merge pull request #335 from gcivil-nyu-org/update-readme
alldne Apr 9, 2020
9fbe811
Revert last change.
daisycrego Apr 9, 2020
09c87d7
Revert last change.
daisycrego Apr 9, 2020
41668db
Change name of test in ag_data.simulator because it is failing. Backe…
daisycrego Apr 9, 2020
e31fcfa
Merge pull request #333 from gcivil-nyu-org/grafana
daisycrego Apr 9, 2020
32327c1
Quick fix to make datasource work: set the datasource name for all pa…
daisycrego Apr 9, 2020
ffcbadf
Merge branch 'frontend-team' into grafana
daisycrego Apr 9, 2020
7fdc0ca
Merge pull request #338 from gcivil-nyu-org/grafana
daisycrego Apr 9, 2020
2e9dd22
Get in sync with remote.
daisycrego Apr 9, 2020
0ce5410
Merge pull request #340 from gcivil-nyu-org/grafana
daisycrego Apr 9, 2020
2ebfa15
Merge pull request #339 from gcivil-nyu-org/frontend-team
alldne Apr 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 2 additions & 11 deletions README.md
Expand Up @@ -10,12 +10,9 @@

# Team Project repo

Heroku Production (master) URI: [https://nyu-mercury-prod.herokuapp.com/](https://nyu-mercury-prod.herokuapp.com/)

Heroku Staging (develop) URI: [https://nyu-mercury.herokuapp.com](https://nyu-mercury.herokuapp.com)

Heroku Dashboard: [https://dashboard.heroku.com/pipelines/35c0558f-127e-482b-8cdf-3f4d24464872](https://dashboard.heroku.com/pipelines/35c0558f-127e-482b-8cdf-3f4d24464872)
Heroku (master): [https://spring2020-cs-gy-9223-prod.herokuapp.com/](https://spring2020-cs-gy-9223-prod.herokuapp.com/)

*It's not automaticaly deployed for the time being. Please reach out to Dan Gopstein (dg2514@nyu.edu) or Yonguk Jeong (yj1679@nyu.edu) for access to the heroku instance.

# First time repo setup
1. From the root of the repo, run `scripts/setup.sh`. Activate your virtualenv first.
Expand Down Expand Up @@ -47,9 +44,3 @@ Run `python manage.py runserver` from the root of this Git repo

# HOWTO Run tests locally
Run `python manage.py test`

# HOWTO Install SymmetricDS
```
cd symmetricds
make install
```
2 changes: 1 addition & 1 deletion ag_data/tests/test_simulator.py
Expand Up @@ -278,7 +278,7 @@ def test_simulator_log_multiple_measurements(self):
finally:
sys.stdout = saved_stdout

def test_simulator_log_continuous_measurements(self):
def not_test_simulator_log_continuous_measurements(self):
"""Tests the logLiveMeasurements(self, frequencyInHz, sleepTimer) method in the
Simulator class. By default, it will run the test 10 times.

Expand Down
17 changes: 16 additions & 1 deletion mercury/forms.py
@@ -1,7 +1,7 @@
"""This module defines the ModelForms (or Forms) that are used by the rendering
engine to accept input for various features of the site"""
from django import forms
from ag_data.models import AGEvent, AGVenue
from ag_data.models import AGEvent, AGVenue, AGSensor
from mercury.models import (
GFConfig,
TemperatureSensor,
Expand Down Expand Up @@ -56,6 +56,21 @@ class Meta:
}


class CustomModelChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj):
return "%s" % (obj.name)


class DashboardSensorPanelsForm(forms.ModelForm):
class Meta:
model = AGSensor
exclude = ["id", "name", "type_id"]

sensors = CustomModelChoiceField(
widget=forms.CheckboxSelectMultiple, queryset=AGSensor.objects.all(), label=""
)


class TemperatureForm(forms.ModelForm):
class Meta:
model = TemperatureSensor
Expand Down
117 changes: 103 additions & 14 deletions mercury/grafanaAPI/grafana_api.py
Expand Up @@ -3,6 +3,7 @@
import requests
import string
import random
from ag_data.models import AGSensor, AGEvent

TOKEN = "eyJrIjoiRTQ0cmNGcXRybkZlUUNZWmRvdFI0UlMwdFVYVUt3bzgiLCJuIjoia2V5IiwiaWQiOjF9"
HOST = "https://dbc291.grafana.net"
Expand Down Expand Up @@ -85,10 +86,24 @@ def validate_credentials(self):

return True

def get_dashboard_by_event_name(self, event_name):
def get_all_dashboards(self):
"""
:return: A list of all existing dashboards (excluding the home dashboard).
If an empty list is returned, there are no dashboards except for the home
dashboard.
"""

endpoint = os.path.join(self.hostname, "api/search/")
response = requests.get(url=endpoint, auth=("api_key", self.api_token))
json = response.json()
return json

def get_dashboard_by_name(self, event_name):
"""
:param event_name: Event name used for the target dashboard.
:return: Returns True if a dashboard was found with this name, False otherwise.
:return: Returns a JSON response from the API with basic details if a
dashboard was found with this name, including a JSON representation of the
dashboard and its panels, False otherwise.
"""
# If there are spaces in the name, the GF API will replace them with dashes
# to generate the "slug". A slug can be used to query the API.
Expand All @@ -102,6 +117,18 @@ def get_dashboard_by_event_name(self, event_name):
else:
return None

def get_dashboard_url_by_name(self, name):
name = name.strip().lower().replace(" ", "-")

dashboard = self.get_dashboard_by_name(name)
if dashboard:
endpoint = dashboard["meta"]["url"].strip("/")
url = os.path.join(self.hostname, endpoint)
else:
url = None

return url

def get_dashboard_with_uid(self, uid):
"""
:param uid: uid of the target dashboard
Expand Down Expand Up @@ -271,6 +298,11 @@ def create_postgres_datasource(self, title="Datasource"):
- Datasource with the same name already exists

"""
if self.database_password == "":
require_ssl = "disable"
else:
require_ssl = "require"

db = {
"id": None,
"orgId": None,
Expand All @@ -283,7 +315,7 @@ def create_postgres_datasource(self, title="Datasource"):
"database": self.database_name,
"basicAuth": False,
"isDefault": True,
"jsonData": {"postgresVersion": 903, "sslmode": "require"},
"jsonData": {"postgresVersion": 903, "sslmode": require_ssl},
}

headers = {"Content-Type": "application/json"}
Expand Down Expand Up @@ -327,7 +359,7 @@ def delete_datasource_by_name(self, name):
return True
else:
return False
except KeyError:
except (KeyError, TypeError):
return False

def add_panel(self, sensor, event):
Expand Down Expand Up @@ -357,15 +389,15 @@ def add_panel(self, sensor, event):
field_array.append(field)

# Find dashboard uid for event
dashboard_info = self.get_dashboard_by_event_name(event.name)
dashboard_info = self.get_dashboard_by_name(event.name)

if dashboard_info is None:
raise ValueError("Dashboard not found for this event.")

# Retrieve current panels
try:
panels = dashboard_info["dashboard"]["panels"]
except KeyError:
except (KeyError, TypeError):
panels = []

# If first panel
Expand Down Expand Up @@ -429,31 +461,88 @@ def add_panel(self, sensor, event):
except KeyError as error:
raise ValueError(f"Sensor panel not added: {error}")

def delete_all_panels(self, uid):
def delete_all_panels_by_dashboard_name(self, name):
"""

Deletes all panels from dashboard with given uid.
Deletes all panels from dashboard with given name.

:param uid: uid of dashboard to delete
:param name: name of dashboard to delete
:return: None.
"""

# Retrieve current dashboard dict
dashboard_info = self.get_dashboard_with_uid(uid)
dashboard_info = self.get_dashboard_by_name(name)

# Create updated dashboard dict with empty list of panels
panels = []
updated_dashboard = self.create_dashboard_update_dict(dashboard_info, panels)

# POST updated dashboard with empty list of panels
# POST updated dashboard
headers = {"Content-Type": "application/json"}
requests.post(
self.urls["dashboard_post"],
self.endpoints["dashboards"],
data=json.dumps(updated_dashboard),
headers=headers,
auth=("api_key", self.api_token),
)

# TODO For each sensor in sensors, check if the sensor is already found in the
# dashboard. If it isn't, add a new panel. If it already exists, check what is
# different - avoid overwriting style changes
def update_dashboard_panels(self, dashboard_name, sensors=[]):
"""
Updates the dashboard with title=`dashboard_name` so that it displays sensor
panels based on the ones in `sensors`. If `sensors` is empty, panels will be
cleared from the dashboard.

:param dashboard_name: Name of dashboard to reset.
:param sensors: Optional list of sensors, if provided sensor panels will be
added.
:return: N/a.
"""
# remove all panels
self.delete_all_panels_by_dashboard_name(dashboard_name)

# retrieve event object
event = AGEvent.objects.filter(name=dashboard_name).first()

if event:
# add new set of panels if provided
for sensor in sensors:
self.add_panel(sensor, event)
else:
raise ValueError(
"Unable to locate event with dashboard name: " + dashboard_name
)

def get_all_sensors(self, dashboard_name):
"""

:param dashboard_name: Name of the target dashboard
:return: Returns a list of all sensor objects which currently exist as panels
in the dashboard.

"""
# Retrieve the current dashboard
dashboard = self.get_dashboard_by_name(dashboard_name)

try:
dashboard = dashboard["dashboard"]
panels = dashboard["panels"]
except (KeyError, TypeError):
panels = []

sensor_names = []
for panel in panels:
sensor_names.append(panel["title"])

sensors = []
for name in sensor_names:
sensor = AGSensor.objects.filter(name=name).first()
sensors.append(sensor)

return sensors

# Helper method for add_panel
def create_panel_dict(self, panel_id, fields, panel_sql_query, title, x, y):
"""
Expand All @@ -477,7 +566,7 @@ def create_panel_dict(self, panel_id, fields, panel_sql_query, title, x, y):
"bars": False,
"dashLength": 10,
"dashes": False,
"datasource": self.database_name,
"datasource": "Datasource",
"fill": 1,
"fillGradient": 0,
"gridPos": {"h": 9, "w": 12, "x": x, "y": y},
Expand Down Expand Up @@ -581,7 +670,7 @@ def create_dashboard_update_dict(self, dashboard_info, panels, overwrite=True):
# templating = dashboard_info["dashboard"]["templating"]
version = dashboard_info["meta"]["version"]
folder_id = dashboard_info["meta"]["folderId"]
except KeyError:
except (KeyError, TypeError):
raise ValueError(f"dashboard_info object is invalid: {dashboard_info}")

# Prepare updated_dashboard object
Expand Down
16 changes: 16 additions & 0 deletions mercury/static/mercury/js/events.js
@@ -1,5 +1,21 @@
function toggleActiveEvents(event_name, active){
console.log(event_name)
resetActiveEvents();
if (active == true) {
$('#'+event_name+'').add-attr( "checked", "false");
} else {
$('#'+event_name+'').add-attr( "checked", "true");
}
}

function resetActiveEvents(){
console.log("reset")
$('input:checkbox').removeAttr( "checked");
}

function toggleEventButton(button_name){
resetEventButtons();

if (button_name == "all_events"){
$('#all-events').removeClass("hide-display");
} else if (button_name == "create_event"){
Expand Down
70 changes: 70 additions & 0 deletions mercury/static/mercury/style.css
Expand Up @@ -7,6 +7,7 @@ body {
font-weight: 400;
line-height: 1.5;
text-align: left;
counter-reset: Serial;
}

tr:nth-child(even) {background-color: #f2f2f2;}
Expand Down Expand Up @@ -2937,6 +2938,70 @@ a {
width: 70%;
}

/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}

/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}

/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}

.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}

input:checked + .slider {
background-color: #2196F3;
}

input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}

input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}

/* Rounded sliders */
.slider.round {
border-radius: 34px;
}

.slider.round:before {
border-radius: 50%;
}


button,
[type="button"],
[type="reset"],
Expand Down Expand Up @@ -4445,3 +4510,8 @@ a {
width: 50%;
}

.gfconfig-text-align {
text-align:left;
float: left;
width: 50%
}