Made is more presentable, added a README and a simple cleanup.
This commit is contained in:
2021-03-23 10:51:17 +01:00
parent e4abd2e3cf
commit cb6c84069e
11 changed files with 78 additions and 81 deletions

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"python.pythonPath": "/Users/marijn/.local/share/virtualenvs/mvl-flask-HZyO5HXA/bin/python"
}

View File

@@ -9,7 +9,7 @@ verify_ssl = true
flask = "*" flask = "*"
flask-sqlalchemy = "*" flask-sqlalchemy = "*"
gunicorn = "*" gunicorn = "*"
psycopg2-binary = "*" psycopg2 = "*"
[requires] [requires]
python_version = "3.7" python_version = "3.9"

102
Pipfile.lock generated
View File

@@ -1,11 +1,11 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "c2d61bd8088f47c3f29ed6dbe2aa8a396284e7587021c1bc00d6ae8685e517dc" "sha256": "2d1f5f4e8498d9eed144ea06b0fe5ccce9e748352cf2001b01cf94d60161a496"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
"python_version": "3.7" "python_version": "3.9"
}, },
"sources": [ "sources": [
{ {
@@ -21,23 +21,24 @@
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==7.1.2" "version": "==7.1.2"
}, },
"flask": { "flask": {
"hashes": [ "hashes": [
"sha256:ad7c6d841e64296b962296c2c2dabc6543752985727af86a975072dea984b6f3", "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060",
"sha256:e7d32475d1de5facaa55e3958bc4ec66d3762076b074296aa50ef8fdc5b9df61" "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.0.3" "version": "==1.1.2"
}, },
"flask-sqlalchemy": { "flask-sqlalchemy": {
"hashes": [ "hashes": [
"sha256:0c9609b0d72871c540a7945ea559c8fdf5455192d2db67219509aed680a3d45a", "sha256:2bda44b43e7cacb15d4e05ff3cc1f8bc97936cc464623424102bfc2c35e95912",
"sha256:8631bbea987bc3eb0f72b1f691d47bd37ceb795e73b59ab48586d76d75a7c605" "sha256:f12c3d4cc5cc7fdcc148b9527ea05671718c3ea45d50c7e732cceb33f574b390"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.4.0" "version": "==2.5.1"
}, },
"greenlet": { "greenlet": {
"hashes": [ "hashes": [
@@ -85,30 +86,23 @@
"sha256:f8450d5ef759dbe59f84f2c9f77491bb3d3c44bc1a573746daf086e70b14c243", "sha256:f8450d5ef759dbe59f84f2c9f77491bb3d3c44bc1a573746daf086e70b14c243",
"sha256:f97d83049715fd9dec7911860ecf0e17b48d8725de01e45de07d8ac0bd5bc378" "sha256:f97d83049715fd9dec7911860ecf0e17b48d8725de01e45de07d8ac0bd5bc378"
], ],
"markers": "python_version >= '3'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==1.0.0" "version": "==1.0.0"
}, },
"gunicorn": { "gunicorn": {
"hashes": [ "hashes": [
"sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626",
"sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c"
], ],
"index": "pypi", "index": "pypi",
"version": "==19.9.0" "version": "==20.0.4"
},
"importlib-metadata": {
"hashes": [
"sha256:742add720a20d0467df2f444ae41704000f50e1234f46174b51f9c6031a1bd71",
"sha256:b74159469b464a99cb8cc3e21973e4d96e05d3024d337313fedb618a6e86e6f4"
],
"markers": "python_version < '3.8'",
"version": "==3.7.3"
}, },
"itsdangerous": { "itsdangerous": {
"hashes": [ "hashes": [
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.0" "version": "==1.1.0"
}, },
"jinja2": { "jinja2": {
@@ -116,7 +110,7 @@
"sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
"sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6" "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
], ],
"index": "pypi", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.11.3" "version": "==2.11.3"
}, },
"markupsafe": { "markupsafe": {
@@ -174,41 +168,29 @@
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be", "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be",
"sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621" "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.1" "version": "==1.1.1"
}, },
"psycopg2-binary": { "psycopg2": {
"hashes": [ "hashes": [
"sha256:080c72714784989474f97be9ab0ddf7b2ad2984527e77f2909fcd04d4df53809", "sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301",
"sha256:110457be80b63ff4915febb06faa7be002b93a76e5ba19bf3f27636a2ef58598", "sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725",
"sha256:171352a03b22fc099f15103959b52ee77d9a27e028895d7e5fde127aa8e3bac5", "sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821",
"sha256:19d013e7b0817087517a4b3cab39c084d78898369e5c46258aab7be4f233d6a1", "sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3",
"sha256:249b6b21ae4eb0f7b8423b330aa80fab5f821b9ffc3f7561a5e2fd6bb142cf5d", "sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051",
"sha256:2ac0731d2d84b05c7bb39e85b7e123c3a0acd4cda631d8d542802c88deb9e87e", "sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5",
"sha256:2b6d561193f0dc3f50acfb22dd52ea8c8dfbc64bcafe3938b5f209cc17cb6f00", "sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84",
"sha256:2bd23e242e954214944481124755cbefe7c2cf563b1a54cd8d196d502f2578bf", "sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a",
"sha256:3e1239242ca60b3725e65ab2f13765fc199b03af9eaf1b5572f0e97bdcee5b43", "sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e",
"sha256:3eb70bb697abbe86b1d2b1316370c02ba320bfd1e9e35cf3b9566a855ea8e4e5", "sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad",
"sha256:51a2fc7e94b98bd1bb5d4570936f24fc2b0541b63eccadf8fdea266db8ad2f70", "sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5",
"sha256:52f1bdafdc764b7447e393ed39bb263eccb12bfda25a4ac06d82e3a9056251f6", "sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7",
"sha256:5b3581319a3951f1e866f4f6c5e42023db0fae0284273b82e97dfd32c51985cd", "sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3",
"sha256:63c1b66e3b2a3a336288e4bcec499e0dc310cd1dceaed1c46fa7419764c68877", "sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d",
"sha256:8123a99f24ecee469e5c1339427bcdb2a33920a18bb5c0d58b7c13f3b0298ba3", "sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543"
"sha256:85e699fcabe7f817c0f0a412d4e7c6627e00c412b418da7666ff353f38e30f67",
"sha256:8dbff4557bbef963697583366400822387cccf794ccb001f1f2307ed21854c68",
"sha256:908d21d08d6b81f1b7e056bbf40b2f77f8c499ab29e64ec5113052819ef1c89b",
"sha256:af39d0237b17d0a5a5f638e9dffb34013ce2b1d41441fd30283e42b22d16858a",
"sha256:af51bb9f055a3f4af0187149a8f60c9d516cf7d5565b3dac53358796a8fb2a5b",
"sha256:b2ecac57eb49e461e86c092761e6b8e1fd9654dbaaddf71a076dcc869f7014e2",
"sha256:cd37cc170678a4609becb26b53a2bc1edea65177be70c48dd7b39a1149cabd6e",
"sha256:d17e3054b17e1a6cb8c1140f76310f6ede811e75b7a9d461922d2c72973f583e",
"sha256:d305313c5a9695f40c46294d4315ed3a07c7d2b55e48a9010dad7db7a66c8b7f",
"sha256:dd0ef0eb1f7dd18a3f4187226e226a7284bda6af5671937a221766e6ef1ee88f",
"sha256:e1adff53b56db9905db48a972fb89370ad5736e0450b96f91bcf99cadd96cfd7",
"sha256:f0d43828003c82dbc9269de87aa449e9896077a71954fbbb10a614c017e65737",
"sha256:f78e8b487de4d92640105c1389e5b90be3496b1d75c90a666edd8737cc2dbab7"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.8.3" "version": "==2.8.6"
}, },
"sqlalchemy": { "sqlalchemy": {
"hashes": [ "hashes": [
@@ -247,30 +229,16 @@
"sha256:facacaea95e0822f7bbeaa6909b30b2836b14cff8790209d52a0c866e240b673", "sha256:facacaea95e0822f7bbeaa6909b30b2836b14cff8790209d52a0c866e240b673",
"sha256:ff76d7dbf33f62e30e5a1d1b095d46afcdc49e42cbe33ce12014110147466700" "sha256:ff76d7dbf33f62e30e5a1d1b095d46afcdc49e42cbe33ce12014110147466700"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.4.2" "version": "==1.4.2"
}, },
"typing-extensions": {
"hashes": [
"sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918",
"sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c",
"sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"
],
"markers": "python_version < '3.8'",
"version": "==3.7.4.3"
},
"werkzeug": { "werkzeug": {
"hashes": [ "hashes": [
"sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43", "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43",
"sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c" "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==1.0.1" "version": "==1.0.1"
},
"zipp": {
"hashes": [
"sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76",
"sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"
],
"version": "==3.4.1"
} }
}, },
"develop": {} "develop": {}

18
README.md Normal file
View File

@@ -0,0 +1,18 @@
# Portfolio Website
A quick portfolio website made to run on Heroku without any storage bucket.
Tables can be created with:
```python
>>> from app import db
>>> db.create_all()
```
## Missing features
- Migrations
- Multiple categories
- An admin interface to add things (other then pictures) to the portfolio.
- A login-system
- A JQuery-free website

10
app.py
View File

@@ -9,6 +9,7 @@ from model import db, Post, Category, ImageBase64
# Check for environment variable # Check for environment variable
env_vars = ["DATABASE_URL", "PASSWORD", 'SECRET_KEY'] env_vars = ["DATABASE_URL", "PASSWORD", 'SECRET_KEY']
for env_var in env_vars: for env_var in env_vars:
if not os.getenv(env_var): if not os.getenv(env_var):
raise RuntimeError(f"{env_var} is not set") raise RuntimeError(f"{env_var} is not set")
@@ -28,12 +29,14 @@ db.init_app(app)
def index(): def index():
posts = Post.get_posts() posts = Post.get_posts()
print(posts[0].title) print(posts[0].title)
return render_template("main/index.html", posts=posts) return render_template("main/index.html", posts=posts)
@app.route('/<string:category_name>') @app.route('/<string:category_name>')
def category(category_name): def category(category_name):
category_item = Category.query.filter(func.lower(Category.name) == category_name.replace('_', ' ')).first() category_item = Category.query.filter(func.lower(Category.name) == category_name.replace('_', ' ')).first()
if not category_item: if not category_item:
return abort(404) return abort(404)
@@ -50,6 +53,7 @@ def contact():
@app.route("/api/post/<int:post_id>", methods=["POST"]) @app.route("/api/post/<int:post_id>", methods=["POST"])
def get_post(post_id): def get_post(post_id):
post = Post.query.get(post_id) post = Post.query.get(post_id)
if post: if post:
return jsonify({"success": True, "post": post.serialize}) return jsonify({"success": True, "post": post.serialize})
else: else:
@@ -59,9 +63,12 @@ def get_post(post_id):
@app.route('/images/<string:filename>') @app.route('/images/<string:filename>')
def get_image(filename): def get_image(filename):
image_b64 = ImageBase64.query.filter(ImageBase64.filename == filename).first() image_b64 = ImageBase64.query.filter(ImageBase64.filename == filename).first()
if not image_b64: if not image_b64:
return abort(404) return abort(404)
image = standard_b64decode(image_b64.data) image = standard_b64decode(image_b64.data)
return send_file(BytesIO(image), mimetype=image_b64.mimetype, attachment_filename=filename) return send_file(BytesIO(image), mimetype=image_b64.mimetype, attachment_filename=filename)
@@ -71,10 +78,13 @@ def file_uploaded():
if not request.form.get('password') == os.getenv('PASSWORD'): if not request.form.get('password') == os.getenv('PASSWORD'):
flash("Wrong Password") flash("Wrong Password")
return redirect("/adm/uploadfile") return redirect("/adm/uploadfile")
# check if the post request has the file part # check if the post request has the file part
if 'files' not in request.files: if 'files' not in request.files:
return redirect("/adm/uploadfile") return redirect("/adm/uploadfile")
files = request.files.getlist('files') files = request.files.getlist('files')
# if user does not select file, browser also # if user does not select file, browser also
# submit an empty part without filename # submit an empty part without filename
for file in files: for file in files:

View File

@@ -53,6 +53,6 @@ class ImageBase64(db.Model):
class Category(db.Model): class Category(db.Model):
__tablename__ = "category" __tablename__ = "categories"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False) name = db.Column(db.String(80), nullable=False)

View File

@@ -1,6 +1,6 @@
{% extends 'adm/layout.html' %} {% extends 'adm/layout.html' %}
{% block title %} {% block title %}
Upload File - mvl Upload File
{% endblock %} {% endblock %}
{% block main %} {% block main %}
{% if get_flashed_messages() %} {% if get_flashed_messages() %}
@@ -13,7 +13,7 @@
<form class="" method=post enctype=multipart/form-data> <form class="" method=post enctype=multipart/form-data>
<div class="form-group"> <div class="form-group">
<label for=password>Password</label> <label for=password>Password</label>
<input class="form-control" id=password type=password name=password> <input class="form-control" id="password" type="password" name="password">
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="custom-file"> <div class="custom-file">

View File

@@ -5,15 +5,13 @@
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-12 col-md-6 align-content-center"> <div class="col-12 col-md-6 align-content-center">
<h1 class="text-center">Hoi!</h1> <h1 class="text-center">Hoi!</h1>
<p>Na het behalen van mijn diploma 'Product Design' van de Hogeschool van Amsterdam in februari 2018 ben <p></p>
ik gaan werken bij een grafisch ontwerpbureau in Haarlem.
Daarnaast ben ik steeds meer bezig met eigen opdrachten, zoals te zien is in dit portfolio.</p>
<div class="text-center "> <div class="text-center ">
<a href="https://www.linkedin.com/in/marlousvanleeuwen/"><i <a href="#"><i
class="social-icon fab fa-linkedin-in fa-3x fa-fw text-dark"></i></a> class="social-icon fab fa-linkedin-in fa-3x fa-fw text-dark"></i></a>
<a href="mailto:marlousvleeuwen@live.nl"><i <a href="#"><i
class="social-icon far fa-envelope fa-3x fa-fw text-dark"></i></a> class="social-icon far fa-envelope fa-3x fa-fw text-dark"></i></a>
<a href="https://www.instagram.com/marlousvleeuwen/"><i <a href="#"><i
class="social-icon fab fa-instagram fa-3x fa-fw text-dark"></i></a> class="social-icon fab fa-instagram fa-3x fa-fw text-dark"></i></a>
</div> </div>
</div> </div>

View File

@@ -1,3 +1,3 @@
<footer class="small text-center text-muted"> <footer class="small text-center text-muted">
&copy; 2019 Marlous van Leeuwen &amp; Marijn Jansen &copy; Marijn Doeve
</footer> </footer>

View File

@@ -1,6 +1,6 @@
{% extends "main/layout.html" %} {% extends "main/layout.html" %}
{% block title %}Marlous van Leeuwen{% endblock %} {% block title %}{% endblock %}
{% block main %} {% block main %}
<main class="container"> <main class="container">

View File

@@ -8,7 +8,7 @@
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav"> <ul class="navbar-nav">
{% set items = [("Product Design", 'product_design'), ("Grafisch Vormgeven", "grafisch_vormgeven"), ("Fotografie", "fotografie")] %} {% set items = [("Nice Title", 'internal_title'),] %}
{% for item in items %} {% for item in items %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if item[1] == request.path[1:] %}active{% endif %}" <a class="nav-link {% if item[1] == request.path[1:] %}active{% endif %}"