Skip to content

Commit 8ff44f1

Browse files
committed
Initial working commit
0 parents  commit 8ff44f1

File tree

7 files changed

+230
-0
lines changed

7 files changed

+230
-0
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# A full stack example for data2410
2+
3+
## Running each container with docker
4+
This example uses the `skynet` network, created with `$ docker network create skynet`. If you want to use your own network, replace `skynet` with the name of your own network.
5+
6+
7+
Standing in the source repo, start the database like this:
8+
```
9+
$ docker run -it --rm -d --name mysql1 --network skynet -e MYSQL_ROOT_PASSWORD=my-secret-pw -v $(pwd)/sql:/docker-entrypoint-initdb.d mysql
10+
```
11+
Notice the `-d` - this will make the container run in the background. If you have docker for mac or docker for windows installed, you should be able to see a container named `mysql1` running.
12+
13+
The backend, which hosts both the API and the frontend can now be started like this:
14+
```
15+
$ docker run -it --rm --name pyback --network skynet -p 5000:5000 -v $(pwd)/python_backend/server.py:/var/fullstack/server.py -v $(pwd)/frontend/:/var/fullstack/frontend/ -t python_backend python /var/fullstack/server.py
16+
```
17+
18+
## Running with docker compose
19+
TODO

frontend/fullstack.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
console.log("Fullstack frontend loaded");
3+
4+
var images = [
5+
"https://static.wikia.nocookie.net/mlp/images/b/b2/Pinkie_Pie_ID_S4E11.png",
6+
"https://media.karousell.com/media/photos/products/2017/02/02/lego_batman_lobster_figure_1486041715_4eed985e.jpg",
7+
"https://static.dw.com/image/18463014_303.jpg",
8+
"https://static.wikia.nocookie.net/mlp/images/b/b2/Pinkie_Pie_ID_S4E11.png"
9+
]
10+
11+
var users = []
12+
13+
function load_copter(){
14+
var copter_img = "https://www.puppentoys.com/WebRoot/ce_es/Shops/940395445/5320/45C4/8DBF/84BC/3270/C0A8/8010/C606/A5935-2.jpg"
15+
var nocopter_img = "http://www.skyblue-pink.com/wp-content/uploads/2013/08/sadbatman.jpg"
16+
row = this.parentElement.parentElement;
17+
copter = Boolean(users[row.id - 1][2]);
18+
console.log(`Loading copter for ${row.id}. Has ponycopter? ${users[row.id - 1][2]}`);
19+
var h_img = row.querySelector(".card-image");
20+
h_img.src = copter ? copter_img : nocopter_img;
21+
}
22+
23+
function render_users(data){
24+
console.log(`Rendering ${data}`)
25+
var h_list = document.getElementById("user_list");
26+
var h_row1 = document.getElementById("first_row");
27+
console.log(`My DOM list: ${h_list}`)
28+
for (i in data){
29+
users[i] = data[i];
30+
[id, n, copter] = data[i];
31+
32+
var cloned_row = h_row1.cloneNode(true);
33+
cloned_row.id = id;
34+
35+
var h_title = cloned_row.querySelector(".card-title");
36+
h_title.innerHTML = id.toString() + ". Name: " + n;
37+
38+
var h_img = cloned_row.querySelector(".card-image");
39+
h_img.src = images[id - 1];
40+
41+
var h_btn = cloned_row.querySelector(".btn");
42+
h_btn.onclick = load_copter;
43+
console.log(`Added onclick: ${h_btn.onclick}`)
44+
45+
console.log(`ID: ${id}, Name: ${n}, Copter? ${Boolean(copter)}`);
46+
h_list.appendChild(cloned_row);
47+
48+
}
49+
h_row1.remove();
50+
}
51+
52+
fetch("./api/users")
53+
.then(response => response.json())
54+
.then(data => render_users(data));
55+
56+
console.log("Fetch in progress");

frontend/index.html

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Fullstack example</title>
5+
6+
<!-- From https://mdbootstrap.com/docs/standard/getting-started/installation/-->
7+
<!-- Font Awesome -->
8+
<link
9+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
10+
rel="stylesheet"
11+
/>
12+
<!-- Google Fonts -->
13+
<link
14+
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
15+
rel="stylesheet"
16+
/>
17+
<!-- MDB -->
18+
<link
19+
href="https://cdnjs.cloudflare.com/ajax/libs/mdb-ui-kit/3.3.0/mdb.min.css"
20+
rel="stylesheet"
21+
/>
22+
23+
<!-- MDB -->
24+
<script
25+
type="text/javascript"
26+
src="https://cdnjs.cloudflare.com/ajax/libs/mdb-ui-kit/3.3.0/mdb.min.js"
27+
></script>
28+
29+
<script src="fullstack.js"></script>
30+
31+
32+
</head>
33+
<body>
34+
35+
36+
<!-- <h1>Fullstack example</h1>
37+
Inspect the API directly as well!-->
38+
39+
<main class="my-5">
40+
<div class="container" id="user_list">
41+
42+
<section class="text-center text-md-start">
43+
<h4 class="mb-5">
44+
A fullstack example
45+
</h4>
46+
47+
<div class="row" id="first_row">
48+
<div class="col-md-4 mb-4">
49+
<div class="bg-image hover-overlay shadow-1-strong rounded ripple" data-mdb-ripple-color="light">
50+
<img src="https://mdbootstrap.com/img/new/standard/nature/184.jpg"
51+
class="img-fluid card-image"
52+
style="width: 300px;height: 150px; object-fit: cover;" />
53+
<a href="#!">
54+
<div class="mask" style="background-color: rgba(251, 251, 251, 0.15);"></div>
55+
</a>
56+
</div>
57+
</div>
58+
<div class="col-md-8 mb-4">
59+
<h5 class="card-title">Very long post title</h5>
60+
<p>
61+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatibus ratione
62+
necessitatibus itaque error alias repellendus nemo reiciendis aperiam quisquam minus
63+
ipsam reprehenderit commodi ducimus, in dicta aliquam eveniet dignissimos magni.
64+
</p>
65+
<button type="button" class="btn btn-primary" onclick="load_copter(this)">Load Ponycopter</button>
66+
</div>
67+
</div>
68+
</section>
69+
</div>
70+
</main>
71+
-->
72+
</body>
73+
</html>

python_backend/Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM python:3
2+
COPY requirements.txt ./
3+
RUN pip install --no-cache-dir -r requirements.txt

python_backend/requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mysql-connector-python
2+
Flask
3+
requests

python_backend/server.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import sys
2+
import flask
3+
import mysql.connector
4+
5+
mysql_user = 'anonymous'
6+
mysql_pwd = 'PiWaC!23CyZzkAYYpi&2S'
7+
mysql_host = 'mysql1'
8+
mysql_db = 'all_the_things'
9+
10+
mydb = mysql.connector.connect(user = mysql_user, password = mysql_pwd,
11+
host = mysql_host,
12+
database = mysql_db)
13+
14+
15+
mycursor = mydb.cursor()
16+
mycursor.execute("SELECT * FROM lonely_heroes")
17+
myresult = mycursor.fetchall()
18+
19+
print("Hello python! This is {}".format(sys.argv[0]))
20+
print("Listing lonely heroes:")
21+
for i, name, copter in myresult:
22+
print("ID: {}, Name: {}, Ponycopter: {}".format(i, name, bool(copter)))
23+
24+
#mydb.close()
25+
26+
# The API
27+
app = flask.Flask(__name__, static_folder="/var/fullstack/frontend", static_url_path="")
28+
29+
@app.route('/', defaults={'path': 'index.html'})
30+
@app.route('/<path>')
31+
def serve_page(path):
32+
print("Request received for {}".format(path))
33+
return flask.send_from_directory('/var/fullstack/frontend', path)
34+
35+
@app.route('/api/users/', methods=['GET'])
36+
def get_users():
37+
print("Requested users")
38+
mycursor = mydb.cursor()
39+
mycursor.execute("SELECT * FROM lonely_heroes")
40+
myresult = mycursor.fetchall()
41+
return flask.jsonify(myresult)
42+
43+
if __name__ == '__main__':
44+
# Note that flask by default listens to localhost / 127.0.0.1
45+
# that's not going to work with docker port forwarding - localhost addresses
46+
# are not allowed to escape the local network so they can't be forwarded out of
47+
# a docker network.
48+
app.run(host="0.0.0.0") #debug=True)
49+
mydb.close()

sql/my_database.sql

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
CREATE DATABASE all_the_things;
2+
USE all_the_things;
3+
4+
CREATE TABLE lonely_heroes (
5+
id INT unsigned NOT NULL AUTO_INCREMENT,
6+
name VARCHAR(150) NOT NULL,
7+
has_ponycopter BOOLEAN NOT NULL default FALSE,
8+
PRIMARY KEY (id)
9+
);
10+
11+
# Not needed but nice for debug output
12+
DESCRIBE lonely_heroes;
13+
14+
INSERT INTO lonely_heroes (name, has_ponycopter) VALUES
15+
('Superman', TRUE),
16+
('Batman', FALSE),
17+
('Chuck', TRUE),
18+
('Pinky Pie', TRUE);
19+
20+
21+
22+
# Not needed but nice for debug output
23+
SELECT * FROM lonely_heroes;
24+
25+
# A user with read-only access to a single table
26+
CREATE USER 'anonymous' IDENTIFIED BY 'PiWaC!23CyZzkAYYpi&2S';
27+
GRANT SELECT ON lonely_heroes TO 'anonymous';

0 commit comments

Comments
 (0)