diff --git a/app/__init__.py b/app/__init__.py index fd1e205..ada3337 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -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 diff --git a/app/errors.py b/app/errors.py new file mode 100644 index 0000000..7db1d62 --- /dev/null +++ b/app/errors.py @@ -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 \ No newline at end of file diff --git a/app/models.py b/app/models.py index 62d99b4..be3bb81 100644 --- a/app/models.py +++ b/app/models.py @@ -39,9 +39,10 @@ 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, primaryjoin=(followers.c.follower_id == id), @@ -70,8 +71,10 @@ 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): - return ''.format(self.body) + return ''.format(self.body) \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index b80fd6a..8116ed8 100644 --- a/app/routes.py +++ b/app/routes.py @@ -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/', 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/', 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/', methods=['POST']) @login_required def follow(username): @@ -109,7 +137,6 @@ def follow(username): else: return redirect(url_for('index')) - @app.route('/unfollow/', 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/') +def error(errno): + return render_template('{}.html'.format(str(errno))) @app.route('/user/') @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)) diff --git a/app/static/img/405.png b/app/static/img/405.png new file mode 100644 index 0000000..9f38ff7 Binary files /dev/null and b/app/static/img/405.png differ diff --git a/app/static/img/500.png b/app/static/img/500.png new file mode 100644 index 0000000..1f21355 Binary files /dev/null and b/app/static/img/500.png differ diff --git a/app/templates/405.html b/app/templates/405.html new file mode 100644 index 0000000..e2f7ce0 --- /dev/null +++ b/app/templates/405.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+
+

You are not allowed to do this!

+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/500.html b/app/templates/500.html new file mode 100644 index 0000000..d435cad --- /dev/null +++ b/app/templates/500.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+
+

Something went wrong... But it's not your fault!

+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/_post_saved.html b/app/templates/_post_saved.html new file mode 100644 index 0000000..b86d920 --- /dev/null +++ b/app/templates/_post_saved.html @@ -0,0 +1,35 @@ +
+
+
+
+
+ +
+
+ +
+ {{post.timestamp.replace("\xc2\xb7", "")}} +
+
+

{{post.body}}

+
+
+

+

+ + +
+

+
+
+ +
+
\ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index 7d3d11f..d31ba27 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -21,7 +21,7 @@ {% else %} Search Following - Saved + Saved Logout {% endif %} diff --git a/app/templates/saved.html b/app/templates/saved.html new file mode 100644 index 0000000..8783c36 --- /dev/null +++ b/app/templates/saved.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block content %} +
+

+ Your saved posts +

+
+
+
+ {% if not savedPosts %} +
+
+ +
+ +
+

No saved posts yet.

+
+
+ {% else %} + {% for post in savedPosts %} + {% include '_post_saved.html' %} + {% endfor %} + {% endif %} +
+{% endblock %} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 31d3b12..f5c9d1f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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