Done for now
This commit is contained in:
17
.idea/dataSources.xml
generated
Normal file
17
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="db" uuid="84671ca6-a908-465f-865b-9dfeff8695f7">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/db.sqlite3</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
<libraries>
|
||||
<library>
|
||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.34.0/sqlite-jdbc-3.34.0.jar</url>
|
||||
</library>
|
||||
</libraries>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
17
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
17
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ourVersions">
|
||||
<value>
|
||||
<list size="2">
|
||||
<item index="0" class="java.lang.String" itemvalue="3.10" />
|
||||
<item index="1" class="java.lang.String" itemvalue="3.11" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
11
README.md
11
README.md
@@ -1,12 +1,15 @@
|
||||
# Portfolio Website
|
||||
|
||||
A quick portfolio website made to run on Heroku without any storage bucket.
|
||||
A quickly made portfolio website made to run on Heroku without any storage bucket.
|
||||
|
||||
Make sure the following environment variables are set:
|
||||
- `DATABASE_URL`
|
||||
- `PASSWORD`
|
||||
- `SECRET_KEY`
|
||||
|
||||
Tables can be created with:
|
||||
```python
|
||||
>>> from app import db, app
|
||||
>>> db.create_all(app=app)
|
||||
```shell
|
||||
$ python app.py
|
||||
```
|
||||
|
||||
## Missing features
|
||||
|
||||
57
app.py
57
app.py
@@ -1,6 +1,15 @@
|
||||
import os
|
||||
|
||||
from flask import Flask, render_template, jsonify, abort, send_file, request, redirect, flash
|
||||
from flask import (
|
||||
Flask,
|
||||
render_template,
|
||||
jsonify,
|
||||
abort,
|
||||
send_file,
|
||||
request,
|
||||
redirect,
|
||||
flash,
|
||||
)
|
||||
from sqlalchemy import func
|
||||
from base64 import standard_b64decode, standard_b64encode
|
||||
from io import BytesIO
|
||||
@@ -8,7 +17,7 @@ from io import BytesIO
|
||||
from model import db, Post, Category, ImageBase64
|
||||
|
||||
# Check for environment variable
|
||||
env_vars = ["DATABASE_URL", "PASSWORD", 'SECRET_KEY']
|
||||
env_vars = ["DATABASE_URL", "PASSWORD", "SECRET_KEY"]
|
||||
|
||||
for env_var in env_vars:
|
||||
if not os.getenv(env_var):
|
||||
@@ -16,10 +25,10 @@ for env_var in env_vars:
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL")
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
app.config['JSON_SORT_KEYS'] = False
|
||||
app.secret_key = os.getenv('SECRET_KEY')
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("DATABASE_URL")
|
||||
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
||||
app.config["JSON_SORT_KEYS"] = False
|
||||
app.secret_key = os.getenv("SECRET_KEY")
|
||||
|
||||
# Bind db to application
|
||||
db.init_app(app)
|
||||
@@ -28,14 +37,16 @@ db.init_app(app)
|
||||
@app.route("/")
|
||||
def index():
|
||||
posts = Post.get_posts()
|
||||
print(posts[0].title)
|
||||
# print(posts[0].title)
|
||||
|
||||
return render_template("main/index.html", posts=posts)
|
||||
|
||||
|
||||
@app.route('/<string:category_name>')
|
||||
@app.route("/<string: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:
|
||||
return abort(404)
|
||||
@@ -45,12 +56,12 @@ def category(category_name):
|
||||
return render_template("main/index.html", posts=posts)
|
||||
|
||||
|
||||
@app.route('/contact')
|
||||
@app.route("/contact")
|
||||
def contact():
|
||||
return render_template("main/contact.html")
|
||||
|
||||
|
||||
@app.route("/api/post/<int:post_id>", methods=["POST"])
|
||||
@app.route("/api/post/<int:post_id>")
|
||||
def get_post(post_id):
|
||||
post = Post.query.get(post_id)
|
||||
|
||||
@@ -60,7 +71,7 @@ def get_post(post_id):
|
||||
return jsonify({"success": False})
|
||||
|
||||
|
||||
@app.route('/images/<string:filename>')
|
||||
@app.route("/images/<string:filename>")
|
||||
def get_image(filename):
|
||||
image_b64 = ImageBase64.query.filter(ImageBase64.filename == filename).first()
|
||||
|
||||
@@ -69,36 +80,40 @@ def get_image(filename):
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
@app.route('/adm/uploadfile', methods=['POST', 'GET'])
|
||||
@app.route("/adm/uploadfile", methods=["POST", "GET"])
|
||||
def file_uploaded():
|
||||
if request.method == 'POST':
|
||||
if not request.form.get('password') == os.getenv('PASSWORD'):
|
||||
if request.method == "POST":
|
||||
if not request.form.get("password") == os.getenv("PASSWORD"):
|
||||
flash("Wrong Password")
|
||||
return redirect("/adm/uploadfile")
|
||||
|
||||
# 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")
|
||||
|
||||
files = request.files.getlist('files')
|
||||
files = request.files.getlist("files")
|
||||
|
||||
# if user does not select file, browser also
|
||||
# submit an empty part without filename
|
||||
for file in files:
|
||||
if file.filename == '':
|
||||
if file.filename == "":
|
||||
flash("No files")
|
||||
return redirect("/adm/uploadfile")
|
||||
data = standard_b64encode(file.read()).decode()
|
||||
database_object = ImageBase64(filename=file.filename, mimetype=file.mimetype, data=data)
|
||||
database_object = ImageBase64(
|
||||
filename=file.filename, mimetype=file.mimetype, data=data
|
||||
)
|
||||
db.session.add(database_object)
|
||||
|
||||
db.session.commit()
|
||||
return render_template("adm/uploadfile.html")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
app.app_context().push()
|
||||
db.create_all()
|
||||
|
||||
7594
static/css/bootstrap.css
vendored
7594
static/css/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
7
static/css/bootstrap.min.css
vendored
7
static/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Start of Custom CSS
|
||||
*/
|
||||
.nav-link, .navbar-brand {
|
||||
font-family: 'Amatic SC', cursive;
|
||||
font-size: 40px; }
|
||||
|
||||
.card-img-overlay {
|
||||
opacity: 0; }
|
||||
|
||||
.card:hover .card-img-overlay {
|
||||
opacity: 1; }
|
||||
|
||||
.card {
|
||||
margin: 10px; }
|
||||
.card .card-img-overlay {
|
||||
padding: 0; }
|
||||
.card .card-img-overlay .card-title-bg {
|
||||
height: 25%;
|
||||
opacity: 0.8; }
|
||||
.card .card-img-overlay .card-title-bg .card-text {
|
||||
opacity: 1; }
|
||||
|
||||
a .card, a .card:hover {
|
||||
color: inherit; }
|
||||
|
||||
.modal-body img {
|
||||
margin: 10px; }
|
||||
|
||||
.social-icon {
|
||||
margin: 10px; }
|
||||
|
||||
body {
|
||||
padding-top: 6.5rem; }
|
||||
|
||||
footer {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px; }
|
||||
|
||||
/*# sourceMappingURL=style.css.map */
|
||||
@@ -5,12 +5,9 @@ $('#detailModal').on('show.bs.modal', function (event) {
|
||||
" <span class=\"sr-only\">Loading...</span>\n" +
|
||||
"</div>");
|
||||
$('#details-description').html('');
|
||||
$.post(`/api/post/${post_id}`, data => {
|
||||
|
||||
$.get(`/api/post/${post_id}`, data => {
|
||||
let post = data.post;
|
||||
console.log(post);
|
||||
|
||||
// $('#details-title').text(post.title);
|
||||
$('#details-intro').html(post.intro);
|
||||
$('#details-description').html(post.description);
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Amatic+SC" rel="stylesheet">
|
||||
<!-- Bootstrap first, then custom style -->
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.css">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css"
|
||||
integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr"
|
||||
crossorigin="anonymous">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<nav class="navbar navbar-expand-md navbar-light bg-light fixed-top">
|
||||
<a class="navbar-brand font-weight-bold" href="{{ url_for("index") }}">Marlous</a>
|
||||
<a class="navbar-brand font-weight-bold" href="{{ url_for("index") }}">Marijn</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
{% set items = [("Nice Title", 'internal_title'),] %}
|
||||
{% set items = [("Category", ''),] %}
|
||||
{% for item in items %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if item[1] == request.path[1:] %}active{% endif %}"
|
||||
|
||||
Reference in New Issue
Block a user