Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
stechuhr-server
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pandemic_Response
stechuhr-server
Commits
716996da
Commit
716996da
authored
4 years ago
by
David Huss
Browse files
Options
Downloads
Patches
Plain Diff
Integrate config, split get/post
parent
e4697c8e
No related branches found
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
README.md
+7
-2
7 additions, 2 deletions
README.md
stechuhr_server/server.py
+112
-59
112 additions, 59 deletions
stechuhr_server/server.py
test.sh
+1
-1
1 addition, 1 deletion
test.sh
with
120 additions
and
62 deletions
README.md
+
7
−
2
View file @
716996da
#! /bin/bash
## Run dev-server
To make a development server run on localhost:
```
python3
export FLASK_APP=stechuhr_server/server.py
$HOME/.poetry/bin/poetry run flask run
export FLASK_ENV=development
poetry run flask run
```
This diff is collapsed.
Click to expand it.
stechuhr_server/server.py
+
112
−
59
View file @
716996da
...
...
@@ -14,17 +14,35 @@ from .config import initialize_config
APPLICATION_NAME
=
"
stechuhr-server
"
DEFAULT_CONFIG
=
"""
[server]
address =
"
127.0.0.1
"
port = 80
timeout = 5
[application]
ignore_get_requests = false
[database]
# sqlite db path, use
"
:memory:
"
for RAM db
path =
"
visitors.db
"
# minimum and maximum lengths
min_id_length = 6
max_id_length = 24
min_entrance_length = 1
max_entrance_length = 128
min_place_length = 1
max_place_length = 128
[log]
level =
"
INFO
"
format =
"
[%(asctime)s] %(levelname)s in %(module)s: %(message)s
"
"""
# Initialize the configuration (create a default one if needed)
config
=
initialize_config
(
APPLICATION_NAME
,
DEFAULT_CONFIG
)
dictConfig
({
'
version
'
:
1
,
'
formatters
'
:
{
'
default
'
:
{
'
format
'
:
'
[%(asctime)s] %(levelname)s in %(module)s: %(message)s
'
,
'
format
'
:
config
[
"
log
"
][
"
format
"
]
,
}},
'
handlers
'
:
{
'
wsgi
'
:
{
'
class
'
:
'
logging.StreamHandler
'
,
...
...
@@ -32,50 +50,85 @@ dictConfig({
'
formatter
'
:
'
default
'
}},
'
root
'
:
{
'
level
'
:
'
INFO
'
,
'
level
'
:
config
[
"
log
"
][
"
level
"
]
,
'
handlers
'
:
[
'
wsgi
'
]
}
})
app
=
Flask
(
APPLICATION_NAME
)
conn
=
sqlite3
.
connect
(
'
test.db
'
)
conn
=
sqlite3
.
connect
(
config
[
"
database
"
][
"
path
"
]
)
cursor
=
conn
.
cursor
()
sqlite_create_table_query
=
'''
CREATE TABLE visitors (
time timestamp PRIMARY KEY,
movement_id TEXT PRIMARY KEY,
time timestamp NOT NULL,
place TEXT NOT NULL,
entrance TEXT NOT NULL,
direction TEXT NOT NULL,
id TEXT NOT NULL);
'''
# Try to construct the new table. If it exists already, do nothing
try
:
app
.
logger
.
info
(
'
Constructing table for visitors
'
)
cursor
.
execute
(
sqlite_create_table_query
)
except
sqlite3
.
OperationalError
:
app
.
logger
.
info
(
'
Constructed table for visitors
'
)
except
sqlite3
.
OperationalError
as
e
:
app
.
logger
.
warning
(
e
)
pass
conn
.
close
()
def
register_movement
(
data
:
dict
,
conn
,
cursor
):
"""
Construct and store a new movment in the database
"""
data
[
"
time
"
]
=
dt
.
datetime
.
now
()
data
=
construct_movement_id
(
data
)
sqlite_insert_with_param
=
"""
INSERT INTO
'
visitors
'
(
'
id
'
,
'
pla
ce
'
,
'
direction
'
,
'
time
'
)
VALUES (?, ?, ?, ?);
"""
data_tuple
=
(
data
[
"
id
"
],
data
[
"
pla
ce
"
],
data
[
"
direction
"
],
data
[
"
time
"
])
(
'
movement_id
'
,
'
id
'
,
'
place
'
,
'
entran
ce
'
,
'
direction
'
,
'
time
'
)
VALUES (?, ?, ?,
?, ?,
?);
"""
data_tuple
=
(
data
[
"
movement_id
"
],
data
[
"
id
"
],
data
[
"
place
"
],
data
[
"
entran
ce
"
],
data
[
"
direction
"
],
data
[
"
time
"
])
cursor
.
execute
(
sqlite_insert_with_param
,
data_tuple
)
conn
.
commit
()
def
construct_movement_id
(
data
:
dict
)
->
dict
:
"""
Generate and set the
"
movement_id
"
for a given data dict
"""
if
not
"
time
"
in
data
.
keys
():
raise
ValueError
(
"
No
\"
time
\"
key set yet. run construct_movement_id only after setting time
"
)
time
=
data
[
"
time
"
].
isoformat
()
movement_id
=
"
{}--{}-{}/{}/{}
"
.
format
(
time
,
data
[
"
id
"
],
data
[
"
place
"
],
data
[
"
entrance
"
],
data
[
"
direction
"
])
data
[
"
movement_id
"
]
=
movement_id
return
data
def
get_records
(
conn
,
cursor
):
sqlite_select_query
=
"""
SELECT place, direction, time, id from visitors where time = ?
"""
"""
Get all existing movement records
"""
sqlite_select_query
=
"""
SELECT place, entrance, direction, time, id from visitors where movement_id = ?
"""
try
:
cursor
.
execute
(
sqlite_select_query
,
(
1
,))
records
=
cursor
.
fetchall
()
visitors
=
[{
"
place
"
:
r
[
0
],
"
direction
"
:
r
[
1
],
"
time
"
:
r
[
2
],
"
id
"
:
r
[
3
]}
for
r
in
records
]
visitors
=
[{
"
place
"
:
r
[
0
],
"
entrance
"
:
r
[
1
],
"
direction
"
:
r
[
2
],
"
time
"
:
r
[
3
],
"
id
"
:
r
[
4
]}
for
r
in
records
]
except
sqlite3
.
OperationalError
as
e
:
# If there is no table or no records, just return an empty list
app
.
logger
.
info
(
'
Couldn
\'
t retrieve visitor records: {}
'
.
format
(
e
))
visitors
=
[]
return
visitors
def
is_valid_data
(
data
:
dict
)
->
bool
:
"""
Check if the body data of the request is valid
"""
expected_keys
=
[
"
place
"
,
"
direction
"
,
"
id
"
]
expected_keys
=
[
"
place
"
,
"
entrance
"
,
"
direction
"
,
"
id
"
]
expected_directions
=
[
"
in
"
,
"
out
"
]
max_entrance_length
=
128
max_place_length
=
128
max_id_length
=
128
has_all_keys
=
all
([
k
in
data
.
keys
()
for
k
in
expected_keys
])
...
...
@@ -92,7 +145,12 @@ def is_valid_data(data: dict) -> bool:
# Basic length check for place
if
len
(
data
[
"
place
"
])
>=
max_place_length
:
app
.
logger
.
info
(
'
400, JSON
"
place
"
-key was too long: was {} should be <= {}
'
.
format
(
len
(
data
[
"
place
"
]),
max_place_length
))
app
.
logger
.
info
(
'
400, JSON
"
place
"
-key was too long: was {} should be <= {}
'
.
format
(
len
(
data
[
"
place
"
]),
max_entrance_length
))
return
False
# Basic length check for entrance
if
len
(
data
[
"
entrance
"
])
>=
max_entrance_length
:
app
.
logger
.
info
(
'
400, JSON
"
entrance
"
-key was too long: was {} should be <= {}
'
.
format
(
len
(
data
[
"
entrance
"
]),
max_entrance_length
))
return
False
# Basic length check for ID
...
...
@@ -104,11 +162,9 @@ def is_valid_data(data: dict) -> bool:
return
True
@app.route
(
'
/
'
,
methods
=
[
'
GET
'
,
'
POST
'
])
def
root
():
conn
=
sqlite3
.
connect
(
'
test.db
'
)
cursor
=
conn
.
cursor
()
if
request
.
method
==
'
POST
'
:
# This gets run for each request
@app.route
(
'
/
'
,
methods
=
[
'
POST
'
])
def
post
():
if
not
request
.
data
:
# Missing data body, reject
app
.
logger
.
info
(
'
400, Missing data body
'
)
...
...
@@ -120,7 +176,9 @@ def root():
# Get JSON
data
=
request
.
json
if
is_valid_data
(
data
):
# Everything went ok
# Valid data, open a db connection
conn
=
sqlite3
.
connect
(
config
[
"
database
"
][
"
path
"
])
cursor
=
conn
.
cursor
()
register_movement
(
data
,
conn
,
cursor
)
conn
.
close
()
app
.
logger
.
info
(
'
200, OK
'
)
...
...
@@ -129,24 +187,19 @@ def root():
# Malformed data, reject
app
.
logger
.
info
(
'
400, Malformed JSON-Body
'
)
return
""
,
400
# This gets run for each request
@app.route
(
'
/
'
,
methods
=
[
'
GET
'
])
def
get
():
if
config
[
"
application
"
][
"
ignore_get_requests
"
]:
app
.
logger
.
info
(
'
501, Get Request Ignored
'
)
return
""
,
501
else
:
# Get Request, not implemented
conn
=
sqlite3
.
connect
(
config
[
"
database
"
][
"
path
"
])
cursor
=
conn
.
cursor
()
visitors
=
get_records
(
conn
,
cursor
)
visitors
=
"
\n
"
.
join
([
str
(
v
)
for
v
in
visitors
])
conn
.
close
()
app
.
logger
.
info
(
'
200, Get visitors: {}
'
.
format
(
visitors
))
# app.logger.info('501, Get Request not implemented')
return
visitors
,
200
\ No newline at end of file
def
main
():
# Initialize the configuration (create a default one if needed)
config
=
initialize_config
(
APPLICATION_NAME
,
DEFAULT_CONFIG
)
if
(
__name__
==
'
__main__
'
):
main
()
\ No newline at end of file
This diff is collapsed.
Click to expand it.
test.sh
+
1
−
1
View file @
716996da
#! /bin/bash
curl
--header
"Content-Type: application/json"
--request
POST
--data
'{"place":"Haupteingang", "direction":"in","id":"543GFDHGfddf455"}'
http://localhost:5000/
curl
--header
"Content-Type: application/json"
--request
POST
--data
'{"place":"
lerchenfeld", "entrance":"
Haupteingang", "direction":"in",
"id":"543GFDHGfddf455"}'
http://localhost:5000/
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment