| @@ -1,4 +1,5 @@ | |||
| # Default ignored files | |||
| /workspace.xml | |||
| # Datasource local storage ignored files | |||
| /dataSources.local.xml | |||
| /dataSources.local.xml | |||
| /dataSources/ | |||
| @@ -7,5 +7,19 @@ | |||
| <jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver> | |||
| <jdbc-url>jdbc:mysql://localhost:3306</jdbc-url> | |||
| </data-source> | |||
| <data-source source="LOCAL" name="calender" uuid="17a463e8-6100-487f-bdd0-6ebd223d5bf6"> | |||
| <driver-ref>sqlite.xerial</driver-ref> | |||
| <synchronize>true</synchronize> | |||
| <jdbc-driver>org.sqlite.JDBC</jdbc-driver> | |||
| <jdbc-url>jdbc:sqlite:C:\Users\jbuer\PycharmProjects\dankventskalender3.0\instance\calender.sqlite</jdbc-url> | |||
| <libraries> | |||
| <library> | |||
| <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.25.1/license.txt</url> | |||
| </library> | |||
| <library> | |||
| <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.25.1/sqlite-jdbc-3.25.1.jar</url> | |||
| </library> | |||
| </libraries> | |||
| </data-source> | |||
| </component> | |||
| </project> | |||
| @@ -11,15 +11,17 @@ from calender.db import get_db | |||
| bp = Blueprint('calender', __name__) | |||
| ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} | |||
| #Todo admin interface for managing submit, comments, submission date | |||
| @bp.route('/') | |||
| def index(): | |||
| db = get_db() | |||
| posts = db.execute( | |||
| 'SELECT p.id, title, body, created, author_id, username' | |||
| 'SELECT p.id, title, body, created, author_id, username, nickname, file' | |||
| ' FROM post p JOIN user u ON p.author_id = u.id' | |||
| ' ORDER BY created DESC' | |||
| ).fetchall() | |||
| # noinspection PyUnresolvedReferences | |||
| return render_template('calender/index.html', posts=posts) | |||
| @@ -28,7 +30,19 @@ def index(): | |||
| def create(): | |||
| if request.method == 'POST': | |||
| title = request.form['title'] | |||
| nickname = request.form['nickname'] | |||
| body = request.form['body'] | |||
| # check if the post request has the file part | |||
| if 'file' not in request.files: | |||
| flash('No file part') | |||
| return redirect(request.url) | |||
| file = request.files['file'] | |||
| # if user does not select file, browser also | |||
| # submit an empty part without filename | |||
| if file.filename == '': | |||
| flash('No selected file') | |||
| return redirect(request.url) | |||
| error = None | |||
| if not title: | |||
| @@ -37,28 +51,18 @@ def create(): | |||
| if error is not None: | |||
| flash(error) | |||
| else: | |||
| db = get_db() | |||
| db.execute( | |||
| 'INSERT INTO post (title, body, author_id)' | |||
| ' VALUES (?, ?, ?)', | |||
| (title, body, g.user['id']) | |||
| ) | |||
| db.commit() | |||
| # check if the post request has the file part | |||
| if 'file' not in request.files: | |||
| flash('No file part') | |||
| return redirect(request.url) | |||
| file = request.files['file'] | |||
| # if user does not select file, browser also | |||
| # submit an empty part without filename | |||
| if file.filename == '': | |||
| flash('No selected file') | |||
| return redirect(request.url) | |||
| if file and allowed_file(file.filename): | |||
| filename = secure_filename(file.filename) | |||
| file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename)) | |||
| return redirect(url_for('calender.uploaded_file', | |||
| filename=filename)) | |||
| db = get_db() | |||
| db.execute( | |||
| 'INSERT INTO post (title, body, author_id, nickname, file)' | |||
| ' VALUES (?, ?, ?, ?, ?)', | |||
| (title, body, g.user['id'], nickname, url_for('calender.uploaded_file', | |||
| filename=filename)) | |||
| ) | |||
| db.commit() | |||
| # return redirect(url_for('calender.uploaded_file',filename=filename)) | |||
| return redirect(url_for('calender.index')) | |||
| return render_template('calender/create.html') | |||
| @@ -66,7 +70,7 @@ def create(): | |||
| def get_post(id, check_author=True): | |||
| post = get_db().execute( | |||
| 'SELECT p.id, title, body, created, author_id, username' | |||
| 'SELECT p.id, title, body, created, author_id, username, nickname, file' | |||
| ' FROM post p JOIN user u ON p.author_id = u.id' | |||
| ' WHERE p.id = ?', | |||
| (id,) | |||
| @@ -22,6 +22,7 @@ def close_db(e=None): | |||
| if db is not None: | |||
| db.close() | |||
| def init_db(): | |||
| db = get_db() | |||
| @@ -36,6 +37,7 @@ def init_db_command(): | |||
| init_db() | |||
| click.echo('Initialized the database.') | |||
| def init_app(app): | |||
| app.teardown_appcontext(close_db) | |||
| app.cli.add_command(init_db_command) | |||
| @@ -12,6 +12,8 @@ CREATE TABLE post ( | |||
| author_id INTEGER NOT NULL, | |||
| created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||
| title TEXT NOT NULL, | |||
| nickname TEXT NOT NULL, | |||
| body TEXT NOT NULL, | |||
| file TEXT NOT NULL, | |||
| FOREIGN KEY (author_id) REFERENCES user (id) | |||
| ); | |||
| ); | |||
| @@ -1,82 +1,80 @@ | |||
| body, h1, h2, h3, h4, h5 { | |||
| font-family: "Raleway", sans-serif; | |||
| color: black; | |||
| margin-bottom: 20px; | |||
| } | |||
| .w3-content .w3-container-display img{ | |||
| max-width: 100%; | |||
| .w3-content .w3-container-display img { | |||
| max-width: 100%; | |||
| } | |||
| .w3-content { | |||
| max-width: 800px; | |||
| max-width: 800px; | |||
| } | |||
| footer{ | |||
| padding-left: 2px; | |||
| position: fixed; | |||
| left: 0; | |||
| bottom: 0; | |||
| video { | |||
| width: 100%; | |||
| max-width: 500px; | |||
| height: auto; | |||
| } | |||
| video { | |||
| width:100%; | |||
| max-width:500px; | |||
| height:auto; | |||
| } | |||
| iframe{ | |||
| width:100%; | |||
| max-width:500px; | |||
| } | |||
| img { | |||
| width: 100%; | |||
| iframe { | |||
| width: 100%; | |||
| max-width: 500px; | |||
| } | |||
| textarea{ | |||
| resize: none; | |||
| img { | |||
| width: 100%; | |||
| } | |||
| .container { | |||
| max-width: 500px; | |||
| margin: 0 auto; | |||
| } | |||
| .bgimg-1{ | |||
| } | |||
| .bgimg-1 { | |||
| background-attachment: fixed; | |||
| background-position: center; | |||
| background-repeat: no-repeat; | |||
| background-size: cover; | |||
| background-image: url("horsehead.jpg"); | |||
| background-image: url("horsehead.jpg"); | |||
| min-height: 100%; | |||
| } | |||
| .button_flash { | |||
| background-color: #004A7F; | |||
| -webkit-border-radius: 10px; | |||
| border-radius: 10px; | |||
| border: none; | |||
| color: #FFFFFF; | |||
| cursor: pointer; | |||
| display: inline-block; | |||
| font-family: Arial; | |||
| font-size: 20px; | |||
| padding: 5px 10px; | |||
| text-align: center; | |||
| text-decoration: none; | |||
| background-color: #004A7F; | |||
| -webkit-border-radius: 10px; | |||
| border-radius: 10px; | |||
| border: none; | |||
| color: #FFFFFF; | |||
| cursor: pointer; | |||
| display: inline-block; | |||
| font-family: Arial; | |||
| font-size: 20px; | |||
| padding: 5px 10px; | |||
| text-align: center; | |||
| text-decoration: none; | |||
| } | |||
| .button_flash { | |||
| -webkit-animation: glowing_red 1500ms infinite; | |||
| -moz-animation: glowing_red 1500ms infinite; | |||
| -o-animation: glowing_red 1500ms infinite; | |||
| animation: glowing_red 1500ms infinite; | |||
| -webkit-animation: glowing_red 1500ms infinite; | |||
| -moz-animation: glowing_red 1500ms infinite; | |||
| -o-animation: glowing_red 1500ms infinite; | |||
| animation: glowing_red 1500ms infinite; | |||
| } | |||
| .button_flash_animation { | |||
| -webkit-animation: glowing_green 2000ms infinite; | |||
| -moz-animation: glowing_green 2000ms infinite; | |||
| -o-animation: glowing_green 2000ms infinite; | |||
| animation: glowing_green 2000ms infinite; | |||
| -webkit-animation: glowing_green 2000ms infinite; | |||
| -moz-animation: glowing_green 2000ms infinite; | |||
| -o-animation: glowing_green 2000ms infinite; | |||
| animation: glowing_green 2000ms infinite; | |||
| } | |||
| .rotated-image { | |||
| animation: spin_img 1s infinite linear | |||
| animation: spin_img 1s infinite linear | |||
| } | |||
| .dropbtn { | |||
| padding: 16px; | |||
| font-size: 16px; | |||
| @@ -99,7 +97,7 @@ textarea{ | |||
| background-color: #f9f9f9; | |||
| min-width: 160px; | |||
| overflow: auto; | |||
| box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); | |||
| box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); | |||
| z-index: 1; | |||
| } | |||
| @@ -110,101 +108,140 @@ textarea{ | |||
| display: block; | |||
| } | |||
| .dropdown a:hover {background-color: #f1f1f1} | |||
| .show {display:block;} | |||
| .dropdown a:hover { | |||
| background-color: #f1f1f1 | |||
| } | |||
| .show { | |||
| display: block; | |||
| } | |||
| @-webkit-keyframes glowing_red { | |||
| 0% { background-color: #B20000; -webkit-box-shadow: 0 0 3px #B20000; } | |||
| 50% { background-color: #FF0000; -webkit-box-shadow: 0 0 40px #FF0000; } | |||
| 100% { background-color: #B20000; -webkit-box-shadow: 0 0 3px #B20000; } | |||
| 0% { | |||
| background-color: #B20000; | |||
| -webkit-box-shadow: 0 0 3px #B20000; | |||
| } | |||
| 50% { | |||
| background-color: #FF0000; | |||
| -webkit-box-shadow: 0 0 40px #FF0000; | |||
| } | |||
| 100% { | |||
| background-color: #B20000; | |||
| -webkit-box-shadow: 0 0 3px #B20000; | |||
| } | |||
| } | |||
| @-moz-keyframes glowing_red { | |||
| 0% { background-color: #B20000; -moz-box-shadow: 0 0 3px #B20000; } | |||
| 50% { background-color: #FF0000; -moz-box-shadow: 0 0 40px #FF0000; } | |||
| 100% { background-color: #B20000; -moz-box-shadow: 0 0 3px #B20000; } | |||
| 0% { | |||
| background-color: #B20000; | |||
| -moz-box-shadow: 0 0 3px #B20000; | |||
| } | |||
| 50% { | |||
| background-color: #FF0000; | |||
| -moz-box-shadow: 0 0 40px #FF0000; | |||
| } | |||
| 100% { | |||
| background-color: #B20000; | |||
| -moz-box-shadow: 0 0 3px #B20000; | |||
| } | |||
| } | |||
| @-o-keyframes glowing_red { | |||
| 0% { background-color: #B20000; box-shadow: 0 0 3px #B20000; } | |||
| 50% { background-color: #FF0000; box-shadow: 0 0 40px #FF0000; } | |||
| 100% { background-color: #B20000; box-shadow: 0 0 3px #B20000; } | |||
| 0% { | |||
| background-color: #B20000; | |||
| box-shadow: 0 0 3px #B20000; | |||
| } | |||
| 50% { | |||
| background-color: #FF0000; | |||
| box-shadow: 0 0 40px #FF0000; | |||
| } | |||
| 100% { | |||
| background-color: #B20000; | |||
| box-shadow: 0 0 3px #B20000; | |||
| } | |||
| } | |||
| @keyframes glowing_red { | |||
| 0% { background-color: #B20000; box-shadow: 0 0 3px #B20000; } | |||
| 50% { background-color: #FF0000; box-shadow: 0 0 40px #FF0000; } | |||
| 100% { background-color: #B20000; box-shadow: 0 0 3px #B20000; } | |||
| 0% { | |||
| background-color: #B20000; | |||
| box-shadow: 0 0 3px #B20000; | |||
| } | |||
| 50% { | |||
| background-color: #FF0000; | |||
| box-shadow: 0 0 40px #FF0000; | |||
| } | |||
| 100% { | |||
| background-color: #B20000; | |||
| box-shadow: 0 0 3px #B20000; | |||
| } | |||
| } | |||
| @-webkit-keyframes glowing_green { | |||
| 0% { background-color: #3fff00; -webkit-box-shadow: 0 0 3px #3fff00; } | |||
| 50% { background-color: #0ad100; -webkit-box-shadow: 0 0 40px #0ad100; } | |||
| 100% { background-color: #3fff00; -webkit-box-shadow: 0 0 3px #3fff00; } | |||
| 0% { | |||
| background-color: #3fff00; | |||
| -webkit-box-shadow: 0 0 3px #3fff00; | |||
| } | |||
| 50% { | |||
| background-color: #0ad100; | |||
| -webkit-box-shadow: 0 0 40px #0ad100; | |||
| } | |||
| 100% { | |||
| background-color: #3fff00; | |||
| -webkit-box-shadow: 0 0 3px #3fff00; | |||
| } | |||
| } | |||
| @-moz-keyframes glowing_green { | |||
| 0% { background-color: #3fff00; -moz-box-shadow: 0 0 3px #3fff00; } | |||
| 50% { background-color: #0ad100; -moz-box-shadow: 0 0 40px #0ad100; } | |||
| 100% { background-color: #3fff00; -moz-box-shadow: 0 0 3px #3fff00; } | |||
| 0% { | |||
| background-color: #3fff00; | |||
| -moz-box-shadow: 0 0 3px #3fff00; | |||
| } | |||
| 50% { | |||
| background-color: #0ad100; | |||
| -moz-box-shadow: 0 0 40px #0ad100; | |||
| } | |||
| 100% { | |||
| background-color: #3fff00; | |||
| -moz-box-shadow: 0 0 3px #3fff00; | |||
| } | |||
| } | |||
| @-o-keyframes glowing_green { | |||
| 0% { background-color: #3fff00; box-shadow: 0 0 3px #3fff00; } | |||
| 50% { background-color: #0ad100; box-shadow: 0 0 40px #0ad100; } | |||
| 100% { background-color: #3fff00; box-shadow: 0 0 3px #3fff00; } | |||
| 0% { | |||
| background-color: #3fff00; | |||
| box-shadow: 0 0 3px #3fff00; | |||
| } | |||
| 50% { | |||
| background-color: #0ad100; | |||
| box-shadow: 0 0 40px #0ad100; | |||
| } | |||
| 100% { | |||
| background-color: #3fff00; | |||
| box-shadow: 0 0 3px #3fff00; | |||
| } | |||
| } | |||
| @keyframes glowing_green { | |||
| 0% { background-color: #3fff00; box-shadow: 0 0 3px #3fff00; } | |||
| 50% { background-color: #0ad100; box-shadow: 0 0 40px #0ad100; } | |||
| 100% { background-color: #3fff00; box-shadow: 0 0 3px #3fff00; } | |||
| 0% { | |||
| background-color: #3fff00; | |||
| box-shadow: 0 0 3px #3fff00; | |||
| } | |||
| 50% { | |||
| background-color: #0ad100; | |||
| box-shadow: 0 0 40px #0ad100; | |||
| } | |||
| 100% { | |||
| background-color: #3fff00; | |||
| box-shadow: 0 0 3px #3fff00; | |||
| } | |||
| } | |||
| @keyframes spin_img { | |||
| 0% { | |||
| transform: rotate(0deg); | |||
| } | |||
| 100% { | |||
| transform: rotate(-360deg); | |||
| } | |||
| 0% { | |||
| transform: rotate(0deg); | |||
| } | |||
| 100% { | |||
| transform: rotate(-360deg); | |||
| } | |||
| } | |||
| .button3 { | |||
| color: black; | |||
| } | |||
| .button3:hover { | |||
| background-color: #f44336; | |||
| color: white; | |||
| } | |||
| .button span { | |||
| cursor: pointer; | |||
| display: inline-block; | |||
| position: relative; | |||
| transition: 0.5s; | |||
| } | |||
| .button span:after { | |||
| content: '\00bb'; | |||
| position: absolute; | |||
| opacity: 0; | |||
| top: 0; | |||
| right: -20px; | |||
| transition: 0.5s; | |||
| } | |||
| .button:hover span { | |||
| padding-right: 25px; | |||
| } | |||
| .button:hover span:after { | |||
| opacity: 1; | |||
| right: 0; | |||
| } | |||
| @@ -1,26 +0,0 @@ | |||
| html { font-family: sans-serif; background: #eee; padding: 1rem; } | |||
| body { max-width: 960px; margin: 0 auto; background: white; } | |||
| h1 { font-family: serif; color: #377ba8; margin: 1rem 0; } | |||
| a { color: #377ba8; } | |||
| hr { border: none; border-top: 1px solid lightgray; } | |||
| nav { background: lightgray; display: flex; align-items: center; padding: 0 0.5rem; } | |||
| nav h1 { flex: auto; margin: 0; } | |||
| nav h1 a { text-decoration: none; padding: 0.25rem 0.5rem; } | |||
| nav ul { display: flex; list-style: none; margin: 0; padding: 0; } | |||
| nav ul li a, nav ul li span, header .action { display: block; padding: 0.5rem; } | |||
| .content { padding: 0 1rem 1rem; } | |||
| .content > header { border-bottom: 1px solid lightgray; display: flex; align-items: flex-end; } | |||
| .content > header h1 { flex: auto; margin: 1rem 0 0.25rem 0; } | |||
| .flash { margin: 1em 0; padding: 1em; background: #cae6f6; border: 1px solid #377ba8; } | |||
| .post > header { display: flex; align-items: flex-end; font-size: 0.85em; } | |||
| .post > header > div:first-of-type { flex: auto; } | |||
| .post > header h1 { font-size: 1.5em; margin-bottom: 0; } | |||
| .post .about { color: slategray; font-style: italic; } | |||
| .post .body { white-space: pre-line; } | |||
| .content:last-child { margin-bottom: 0; } | |||
| .content form { margin: 1em 0; display: flex; flex-direction: column; } | |||
| .content label { font-weight: bold; margin-bottom: 0.5em; } | |||
| .content input, .content textarea { margin-bottom: 1em; } | |||
| .content textarea { min-height: 12em; resize: vertical; } | |||
| input.danger { color: #cc2f2e; } | |||
| input[type=submit] { align-self: start; min-width: 10em; } | |||
| @@ -59,4 +59,5 @@ | |||
| </section> | |||
| {% block content %} | |||
| {% endblock %} | |||
| </body> | |||
| </body> | |||
| <footer class="w3-highway-red">Special thanks to <strong>Langspielplatte</strong> for hosting this webspace! <strong><3</strong> </footer> | |||
| @@ -8,11 +8,14 @@ | |||
| <form method=post enctype=multipart/form-data> | |||
| <label for="title">Title</label> | |||
| <input name="title" id="title" value="{{ request.form['title'] }}" required> | |||
| <label for="nickname">Nickname</label> | |||
| <input name="nickname" id="nickname" value="{{ request.form['nickname'] }}" required> | |||
| <label for="body">Body</label> | |||
| <textarea name="body" id="body">{{ request.form['body'] }}</textarea> | |||
| <label for="file">Body</label> | |||
| <div> | |||
| <p>Choose a mp4, webm, gif , png or jpg file.(max 25MB)</p> | |||
| <input type="file" placeholder="meme" name="file" required> | |||
| <input type="file" placeholder="meme" name="file" id="file" required> | |||
| </div> | |||
| <input type="submit" value=Upload> | |||
| </form> | |||
| @@ -1,7 +1,8 @@ | |||
| {% extends 'base.html' %} | |||
| {% block header %} | |||
| {% block header %} | |||
| <div class="container w3-center"> | |||
| <h1>{% block title %}Welcome to the Dankventskalender 2020!{% endblock %}</h1> | |||
| <div> | |||
| @@ -14,25 +15,31 @@ | |||
| {% endif %} | |||
| </div> | |||
| </div> | |||
| {% endblock %} | |||
| {% block content %} | |||
| {% for post in posts %} | |||
| <article class="post"> | |||
| <header> | |||
| <div> | |||
| <h1>{{ post['title'] }}</h1> | |||
| <div class="about">by {{ post['username'] }} on {{ post['created'].strftime('%Y-%m-%d') }}</div> | |||
| </div> | |||
| {% if g.user['id'] == post['author_id'] %} | |||
| <a class="action" href="{{ url_for('calender.update', id=post['id']) }}">Edit</a> | |||
| <div class="container w3-center"> | |||
| {% for post in posts %} | |||
| <div class="item"> | |||
| <article class="post"> | |||
| <header> | |||
| <div> | |||
| <h1>{{ post['title'] }}</h1> | |||
| <h2>{{ post['nickname'] }}</h2> | |||
| <div class="about">by {{ post['username'] }} | |||
| on {{ post['created'].strftime('%Y-%m-%d') }}</div> | |||
| </div> | |||
| {% if g.user['id'] == post['author_id'] %} | |||
| <a class="action" href="{{ url_for('calender.update', id=post['id']) }}">Edit</a> | |||
| {% endif %} | |||
| </header> | |||
| <img class="file" src="{{ post['file'] }}"> | |||
| <p class="body">{{ post['body'] }}</p> | |||
| </article> | |||
| {% if not loop.last %} | |||
| <hr> | |||
| {% endif %} | |||
| </header> | |||
| <p class="body">{{ post['body'] }}</p> | |||
| </article> | |||
| {% if not loop.last %} | |||
| <hr> | |||
| {% endif %} | |||
| {% endfor %} | |||
| {% endblock %} | |||
| </div> | |||
| {% endfor %} | |||
| </div> | |||
| {% endblock %} | |||
| @@ -7,6 +7,6 @@ setup( | |||
| include_package_data=True, | |||
| zip_safe=False, | |||
| install_requires=[ | |||
| 'flask', | |||
| 'flask', 'click' | |||
| ], | |||
| ) | |||