Skip to content

API - initial commit #2

Merged
merged 1 commit into from Mar 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 40 additions & 0 deletions API/DataObjects.py
@@ -0,0 +1,40 @@
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, Binary, Float
from sqlalchemy.orm import relationship, sessionmaker, deferred
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.ext.declarative import declarative_base

from datetime import datetime

Base = declarative_base()

class LocationData(Base):
"""
Location Data for HuskyTrack

Attributes:
uuid: The Location Data's universally unique identifier
uid: The user ID of the user this data belongs to
latitude: The latitude of the device when this measurement was taken
longitude: The longitude of the device when this measurement was taken
accuracy: The accuracy of the measurement as reported by the device
speed: The speed of the device when this measurement was taken
heading: The heading of the device when this measurement was taken
altitude: The altitude of the device when this measurement was taken
timestamp: The time at which this measurement was taken [ISO-8601 UTC]
"""

__tablename__ = 'location_data'

uuid = Column('uuid', String, primary_key=True)
uid = Column('uid', String, nullable=False)
latitude = Column('latitude', Float, nullable=False)
longitude = Column('longitude', Float, nullable=False)
accuracy = Column('accuracy', Float, nullable=False)
speed = Column('speed', Float, nullable=False)
heading = Column('heading', Float, nullable=False)
altitude = Column('altitude', Float, nullable=False)
timestamp = Column('timestamp', String, nullable=False)

def __repr__(self):
return self.uuid
Binary file added API/DataObjects.pyc
Binary file not shown.
Binary file added API/__pycache__/DataObjects.cpython-36.pyc
Binary file not shown.
146 changes: 146 additions & 0 deletions API/api.py
@@ -0,0 +1,146 @@
import configparser
import sys
import json
from datetime import datetime

from flask import Flask, request

from DataObjects import LocationData
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from collections import defaultdict

app = Flask(__name__)

ISO8601 = "%Y%m%dT%H%M%S"
ISO8601_O = "%Y-%m-%d %H:%M:%S"


def get_config():
"""
Get the configuration data for the application
"""
try:
config = configparser.SafeConfigParser()
config.read('config.ini')
return config
except Exception as e:
print("No configuration file found.", e)
sys.exit()

def get_session(config):
"""
Attempt to initialize the database session, quit if the
program cannot find the database.
"""
try:
# Collect Configuration
dao_type = config.get('database', 'type').lower()
username = config.get('database', 'username')
password = config.get('database', 'pass')
host = config.get('database', 'host')
port = config.get('database', 'port')
database = config.get('database', 'database')

# Build URL
if dao_type == 'sqlite':
url = dao_type + ":///" + host
else:
url = dao_type + "://" + username +\
":" + password + "@" + host + \
":" + port + "/" + database

# Create session
engine = create_engine(url)
Session = sessionmaker(bind=engine)
session = Session()
return session

except Exception as e:
print("Unable to configure database connection. Error:", e)
sys.exit()

@app.route('/api')
def api():
"""
Returns the version for compatibility/availability checks"
"""
return 'v0.1'

@app.route('/api/locationdata', methods=('GET', 'POST'))
def location_data():
"""
Request or post location data
"""
session = get_session(get_config())
if request.method == 'POST':
if request.is_json:
try:
raw_location_data = request.get_json()
location = raw_location_data["location"]
coords = location["coords"]
lat = coords["latitude"]
lng = coords["longitude"]
acc = coords["accuracy"]
spd = coords["speed"]
hed = coords["heading"]
alt = coords["altitude"]
tim = location["timestamp"]
uuid = location["uuid"]
uid = "1"
locationData = LocationData(uuid = uuid,
uid = uid,
latitude = lat,
longitude = lng,
accuracy = acc,
speed = spd,
heading = hed,
altitude = alt,
timestamp = tim)
session.add(locationData)
session.commit()
return "Success"
except Exception as e:
session.rollback()
return ("Fail", str(e))
else:
return "NOT JSON"
else:
try:
start = request.args.get('start')
end = request.args.get('end')

start = datetime.strptime(start, ISO8601)
end = datetime.strptime(end, ISO8601)

print(str([str(start), str(end)]))
query_results = session.query(LocationData).filter(LocationData.timestamp > start, LocationData.timestamp < end).all()

dataPoints = defaultdict(list)
for result in query_results:
dataPoints[result.uid].append(result)

result = []
for user in dataPoints:
print(user)
json_entry = json.loads('{}')
json_entry['user_id'] = user
json_entry['start_time'] = min(dataPoints[user], key=lambda x:x.timestamp).timestamp
json_entry['end_time'] = max(dataPoints[user], key=lambda x:x.timestamp).timestamp
json_entry['locations'] = []
for location in dataPoints[user]:
json_location = json.loads('{}')
json_location['latitude'] = location.latitude
json_location['longitude'] = location.longitude
json_location['timestamp'] = location.timestamp
json_entry['locations'].append(json_location)
result.append(json_entry)

return json.dumps(result)
except Exception as e:
print(e)
return json.dumps([[l.uuid, l.latitude, l.longitude, l.timestamp] for l in session.query(LocationData).all()])

if __name__ == '__main__':
app.run(debug=True)
7 changes: 7 additions & 0 deletions API/config.ini
@@ -0,0 +1,7 @@
[database]
type = sqlite
host = C:\Users\demel\Documents\GitHub\GPS-Tracking-of-On-Campus-Walking-Project\API\db\test.db
username = mason
pass = mason
port = 3306
database = mason
14 changes: 14 additions & 0 deletions API/db/init_sqlite.sql
@@ -0,0 +1,14 @@
BEGIN TRANSACTION;
DROP TABLE IF EXISTS `location_data`;
CREATE TABLE IF NOT EXISTS `location_data` (
`uuid` TEXT NOT NULL PRIMARY KEY UNIQUE,
`uid` TEXT NOT NULL,
`latitude` REAL NOT NULL,
`longitude` REAL NOT NULL,
`accuracy` REAL NOT NULL,
`speed` REAL NOT NULL,
`heading` REAL NOT NULL,
`altitude` REAL NOT NULL,
`timestamp` TEXT NOT NULL
);
COMMIT;
Binary file added API/db/test.db
Binary file not shown.
44 changes: 44 additions & 0 deletions API/post_test.py
@@ -0,0 +1,44 @@
import json
import urllib2
import uuid
import datetime

data = {
"location": {
"coords": {
"latitude": 1.5,
"longitude": 1.5,
"accuracy": 1.5,
"speed": 1.5,
"heading": 1.5,
"altitude": 1.5
},
"extras": {
"foo": "bar"
},
"activity": {
"type": "still",
"confidence": 100
},
"geofence": {
"identifier": "identifier",
"action": "ENTER"
},
"battery": {
"level": 1.5,
"is_charging": True
},
"timestamp": str(datetime.datetime.now().replace(microsecond=0).isoformat()),
"uuid": str(uuid.uuid4()),
"event": "EVENT",
"is_moving": 1.0,
"odometer": 1.0
}
}

req = urllib2.Request('http://127.0.0.1:5000/api/locationdata')
req.add_header('Content-Type', 'application/json')

response = urllib2.urlopen(req, json.dumps(data))

print(response.read())