Feature: Save posts + Better error handling

This commit is contained in:
Wire 2020-07-15 03:03:03 +02:00
parent 62003cb39d
commit cda0b18c10
12 changed files with 144 additions and 17 deletions

View File

@ -11,4 +11,4 @@ migrate = Migrate(app, db)
login = LoginManager(app)
login.login_view = 'login'
from app import routes, models
from app import routes, models, errors

16
app/errors.py Normal file
View File

@ -0,0 +1,16 @@
from flask import render_template
from app import app, db
@app.errorhandler(404)
def not_found_error(error):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_error(error):
db.session.rollback()
return render_template('500.html'), 500
@app.errorhandler(405)
def internal_error(error):
db.session.rollback()
return render_template('405.html'), 405

View File

@ -39,8 +39,9 @@ class User(UserMixin, db.Model):
def following_list(self):
return self.followed.all()
def followed_posts(self):
return "Soon.."
def saved_posts(self):
return Post.query.filter_by(user_id=self.id)
followed = db.relationship(
'User', secondary=followers,
@ -70,7 +71,9 @@ class twitterPost():
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
timestamp = db.Column(db.String(100))
url = db.Column(db.String(100), unique=True)
username = db.Column(db.String(24))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):

View File

@ -3,7 +3,7 @@ from flask import render_template, flash, redirect, url_for, request
from app.forms import LoginForm, RegistrationForm, EmptyForm, SearchForm
from requests_futures.sessions import FuturesSession
from concurrent.futures import as_completed
from app.models import User, twitterPost
from app.models import User, twitterPost, Post
from werkzeug.urls import url_parse
from bs4 import BeautifulSoup
from flask import Markup
@ -80,10 +80,38 @@ def register():
@app.route('/savePost/<url>', methods=['POST'])
@login_required
def savePost(url):
print("SAVEPOST")
print("Saved {}.".format(url.replace('~', '/')))
savedUrl = url.replace('~', '/')
r = requests.get(savedUrl)
html = BeautifulSoup(str(r.content), "lxml")
post = html.body.find_all('div', attrs={'class':'tweet-content'})
newPost = Post()
newPost.url = savedUrl
newPost.body = html.body.find_all('div', attrs={'class':'main-tweet'})[0].find_all('div', attrs={'class':'tweet-content'})[0].text
newPost.username = html.body.find('a','username').text.replace("@","")
newPost.timestamp = html.body.find_all('p', attrs={'class':'tweet-published'})[0].text
newPost.user_id = current_user.id
try:
db.session.add(newPost)
db.session.commit()
except:
flash("Post could not be saved. Either it was already saved or there was an error.")
return redirect(url_for('index'))
@app.route('/saved')
@login_required
def saved():
savedPosts = current_user.saved_posts().all()
return render_template('saved.html', title='Saved', savedPosts=savedPosts)
@app.route('/deleteSaved/<id>', methods=['POST'])
@login_required
def deleteSaved(id):
savedPost = Post.query.filter_by(id=id).first()
db.session.delete(savedPost)
db.session.commit()
return redirect(url_for('saved'))
@app.route('/follow/<username>', methods=['POST'])
@login_required
def follow(username):
@ -109,7 +137,6 @@ def follow(username):
else:
return redirect(url_for('index'))
@app.route('/unfollow/<username>', methods=['POST'])
@login_required
def unfollow(username):
@ -177,9 +204,9 @@ def search():
@app.route('/notfound')
def notfound():
return render_template('404.html')
@app.route('/error/<errno>')
def error(errno):
return render_template('{}.html'.format(str(errno)))
@app.route('/user/<username>')
@login_required
@ -194,7 +221,7 @@ def user(username):
db.session.commit()
elif not isTwitter and user is None:
return redirect(url_for('notfound'))
return redirect( url_for('error', errno="404"))
posts = []
posts.extend(getPosts(username))

BIN
app/static/img/405.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
app/static/img/500.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

10
app/templates/405.html Normal file
View File

@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block content %}
<div style="margin-top: 2em;" class="ui one column centered grid">
<img class="ui medium circular image" src="{{ url_for('static',filename='img/405.png') }}">
</div>
<div style="margin: 1.5em;" class="ui one column centered grid">
<h2 class="ui header">You are not allowed to do this!</h2>
</div>
{% endblock %}

10
app/templates/500.html Normal file
View File

@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block content %}
<div style="margin-top: 2em;" class="ui one column centered grid">
<img class="ui medium circular image" src="{{ url_for('static',filename='img/500.png') }}">
</div>
<div style="margin: 1.5em;" class="ui one column centered grid">
<h2 class="ui header">Something went wrong... But it's not your fault!</h2>
</div>
{% endblock %}

View File

@ -0,0 +1,35 @@
<div class="column"> <!--Start tweet-->
<div class="ui centered card">
<div class="content">
<div class="extra content">
<div class="left floated author">
<img class="ui avatar image" src="{{ url_for('static',filename='img/avatars/')}}{{range(1, 12) | random}}.png">
</div>
</div>
<div class="header" id="author"><a href="user/{{post.username}}">@{{ post.username }}</a></div>
<div class="meta">
<span class="category" id="time"><i class="clock icon"></i> {{post.timestamp.replace("\xc2\xb7", "")}} </span>
</div>
<div class="description">
<p>{{post.body}}</p>
</div>
<div class="extra center aligned content">
<p>
<form class="ui form" action="{{ url_for('deleteSaved', id=post.id) }}" method="post">
<a href="{{ post.url }}"><button type="button" class="ui blue left aligned icon button">
<i class="share icon"></i>
</button></a>
<button type="submit" class="ui red right aligned icon button">
<i class="trash icon"></i>
</button>
</form>
</p>
</div>
</div>
<!--newPost.url = savedUrl
newPost.body = html.body.find_all('div', attrs={'class':'main-tweet'})[0].find_all('div', attrs={'class':'tweet-content'})[0].text
newPost.username = html.body.find('a','username').text.replace("@","")
newPost.timestamp = html.body.find_all('p', attrs={'class':'tweet-published'})[0].text
newPost.user_id = current_user.id-->
</div>
</div> <!--End tweet-->

View File

@ -21,7 +21,7 @@
{% else %}
<a href="{{ url_for('search') }}" class="item">Search</a>
<a href="{{ url_for('following') }}" class="item">Following</a>
<a href="#" class="item">Saved</a>
<a href="{{ url_for('saved') }}" class="item">Saved</a>
<a href="{{ url_for('logout') }}" class="item">Logout</a>
{% endif %}
</div>

27
app/templates/saved.html Normal file
View File

@ -0,0 +1,27 @@
{% extends "base.html" %}
{% block content %}
<div style="padding: 1.3em;" class="ui one column centered grid">
<h2 class="ui blue header">
Your saved posts
</h2>
</div>
<hr>
<div class="ui one column grid" id="card-container">
{% if not savedPosts %}
<div style="margin-top: 2em;" class="ui one column centered grid">
<div style="margin: 1.5em;" class="ui row">
<img class="ui medium circular image" src="{{ url_for('static',filename='img/empty.png') }}">
</div>
<div style="margin: 1.5em;" class="ui row">
<h2 class="ui header">No saved posts yet.</h2>
</div>
</div>
{% else %}
{% for post in savedPosts %}
{% include '_post_saved.html' %}
{% endfor %}
{% endif %}
</div>
{% endblock %}

View File

@ -1,4 +1,3 @@
aiohttp==3.6.2
alembic==1.4.2
async-timeout==3.0.1
attrs==19.3.0
@ -19,7 +18,6 @@ Flask-WTF==0.14.3
future==0.18.2
gevent==20.6.2
greenlet==0.4.16
grequests==0.6.0
idna==2.10
itsdangerous==1.1.0
Jinja2==2.11.2
@ -29,6 +27,7 @@ Mako==1.1.3
MarkupSafe==1.1.1
multidict==4.7.6
numpy==1.19.0
PyMySQL==0.9.3
python-dateutil==2.8.1
python-dotenv==0.14.0
python-editor==1.0.4