diff --git a/app/forms.py b/app/forms.py index 4afddfd..84cb7f8 100644 --- a/app/forms.py +++ b/app/forms.py @@ -1,28 +1,48 @@ from flask_wtf import FlaskForm -from wtforms import StringField, PasswordField, BooleanField, SubmitField +from wtforms import StringField, PasswordField, BooleanField, SubmitField, RadioField, IntegerField from wtforms.validators import ValidationError, DataRequired, Email, EqualTo from app.models import User +import trello, trello_credentials class LoginForm(FlaskForm): - username = StringField("Username", validators=[DataRequired()]) - password = PasswordField("Password", validators=[DataRequired()]) + username = StringField("Username", validators = [DataRequired()]) + password = PasswordField("Password", validators = [DataRequired()]) remember_me = BooleanField("Remember Me") submit = SubmitField("Sign In") + def validate_username(self, username): + if not User.query.filter_by(username = username.data).first(): + raise ValidationError("Invalid username.") + + def validate_password(self, password): + user = User.query.filter_by(username = self.username.data).first() + if user and not user.check_password(password.data): + raise ValidationError("Invalid password.") + class RegistrationForm(FlaskForm): - username = StringField("Username", validators=[DataRequired()]) - email = StringField("Email", validators=[DataRequired(), Email()]) - password = PasswordField("Password", validators=[DataRequired()]) + username = StringField("Username", validators = [DataRequired()]) + email = StringField("Email", validators = [DataRequired(), Email()]) + password = PasswordField("Password", validators = [DataRequired()]) password2 = PasswordField( - "Repeat Password", validators=[DataRequired(), EqualTo("password")]) + "Repeat Password", validators = [DataRequired(), EqualTo("password")]) submit = SubmitField("Register") def validate_username(self, username): - user = User.query.filter_by(username=username.data).first() + user = User.query.filter_by(username = username.data).first() if user is not None: raise ValidationError("Please use a different username.") def validate_email(self, email): - user = User.query.filter_by(email=email.data).first() + user = User.query.filter_by(email = email.data).first() if user is not None: raise ValidationError("Please use a different email address.") + +class TrelloAPIForm(FlaskForm): + token = StringField("Token", validators = [DataRequired()]) + submit = SubmitField("Connect") + + def validate_token(self, token): + try: + trello.TrelloClient(api_key = trello_credentials.api_key, token = token.data).list_boards() + except: + raise ValidationError("Invalid Trello Token") diff --git a/app/models.py b/app/models.py index 24dbecb..42ce835 100644 --- a/app/models.py +++ b/app/models.py @@ -2,6 +2,7 @@ from app import db from werkzeug.security import generate_password_hash, check_password_hash from flask_login import UserMixin from app import login +import tweepy, twitter_credentials, trello, trello_credentials class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True, unique=True) @@ -9,7 +10,9 @@ class User(UserMixin, db.Model): email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) twitter_api = db.relationship("TwitterAPI", backref="user", lazy="dynamic") - trello_api = db.relationship('TrelloAPI', backref="user", lazy="dynamic") + tweets = db.relationship("Tweets", backref="user", lazy="dynamic") + trello_api = db.relationship("TrelloAPI", backref="user", lazy="dynamic") + boards = db.relationship("Boards", backref="user", lazy="dynamic") def set_password(self, password): self.password_hash = generate_password_hash(password) @@ -26,11 +29,33 @@ class TwitterAPI(db.Model): access_token = db.Column(db.String(50), unique=True) access_token_secret = db.Column(db.String(45), unique=True) + def api_login(self): + auth = tweepy.OAuthHandler(twitter_credentials.consumer_key, twitter_credentials.consumer_secret_key) + auth.set_access_token(self.access_token, self.access_token_secret) + return tweepy.API(auth) + +class Tweets(db.Model): + id = db.Column(db.Integer, primary_key=True, unique=True) + user_id = db.Column(db.Integer, db.ForeignKey("user.id")) + statu_id = db.Column(db.Integer, unique=True) + slots = db.Column(db.Integer) + slots_max = db.Column(db.Integer) + keywords = db.Column(db.String(256)) + class TrelloAPI(db.Model): id = db.Column(db.Integer, primary_key=True, unique=True) user_id = db.Column(db.Integer, db.ForeignKey("user.id"), unique=True) token = db.Column(db.String(64), unique=True) + def api_login(self): + return trello.TrelloClient(api_key = trello_credentials.api_key, token = self.token) + +class Boards(db.Model): + id = db.Column(db.Integer, primary_key=True, unique=True) + user_id = db.Column(db.Integer, db.ForeignKey("user.id"), unique=True) + board_id = db.Column(db.String(24)) + column_id = db.Column(db.String(24)) + @login.user_loader def load_user(id): return User.query.get(int(id)) diff --git a/app/routes.py b/app/routes.py index 6e60a29..5a5bf77 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,11 +1,10 @@ from app import app, db -from flask import Flask, request, redirect, session, render_template, flash, url_for +from flask import Flask, request, redirect, session, render_template, url_for from flask_login import current_user, login_user, logout_user, login_required -from app.forms import LoginForm, RegistrationForm -from app.models import User, TwitterAPI, TrelloAPI +from app.forms import LoginForm, RegistrationForm, TrelloAPIForm +from app.models import User, TwitterAPI, Tweets, TrelloAPI, Boards from werkzeug.urls import url_parse -import twitter_credentials, tweepy, tw -import trello_credentials, trello, tr +import tweepy, trello, twitter_credentials, trello_credentials @app.route("/login", methods=["GET", "POST"]) def login(): @@ -13,16 +12,13 @@ def login(): return redirect(url_for("home")) form = LoginForm() if form.validate_on_submit(): - user = User.query.filter_by(username=form.username.data).first() - if user is None or not user.check_password(form.password.data): - flash("Invalid username or password") - return redirect(url_for("login")) - login_user(user, remember=form.remember_me.data) + user = User.query.filter_by(username = form.username.data).first() + login_user(user, remember = form.remember_me.data) next_page = request.args.get("next") if not next_page or url_parse(next_page).netloc != "": next_page = url_for("home") return redirect(next_page) - return render_template("login.html", form=form) + return render_template("login.html", form = form) @app.route("/register", methods=["GET", "POST"]) def register(): @@ -30,11 +26,10 @@ def register(): return redirect(url_for("index")) form = RegistrationForm() if form.validate_on_submit(): - user = User(username=form.username.data, email=form.email.data) - user.set_password(form.password.data) - db.session.add(user) + u = User(username=form.username.data, email=form.email.data) + u.set_password(form.password.data) + db.session.add(u) db.session.commit() - flash("Congratulations, you are now a registered user!") return redirect(url_for("login")) return render_template("register.html", form=form) @@ -46,6 +41,8 @@ def logout(): @app.route("/twlogin") @login_required def twlogin(): + if current_user.twitter_api.first(): + return "Already an api connected." auth = tweepy.OAuthHandler(twitter_credentials.consumer_key, twitter_credentials.consumer_secret_key, "https://cyberplanificateur.flifloo.fr/twlogin") if request.args.get("oauth_token") and request.args.get("oauth_verifier"): auth.request_token = {"oauth_token" : request.args.get("oauth_token"), "oauth_token_secret" : request.args.get("oauth_verifier")} @@ -54,8 +51,7 @@ def twlogin(): except: return "Error ! Failed to get access token" else: - twapi = TwitterAPI(access_token = auth.access_token, access_token_secret = auth.access_token_secret, user = current_user) - db.session.add(twapi) + db.session.add(TwitterAPI(access_token = auth.access_token, access_token_secret = auth.access_token_secret, user = current_user)) db.session.commit() elif not TwitterAPI.query.filter_by(user=current_user).first(): return redirect(auth.get_authorization_url()) @@ -73,6 +69,8 @@ def twlogout(): @app.route("/trlogin") @login_required def trlogin(): + if current_user.twitter_api.first(): + return "Already an api connected." return redirect(f"https://trello.com/1/authorize?expiration=never&name=Cyberplanificateur&scope=read,write&response_type=token&key={trello_credentials.api_key}&return_url=https://cyberplanificateur.flifloo.fr/settings") @app.route("/trlogout") @@ -91,75 +89,81 @@ def home(): @app.route("/settings", methods = ["POST", "GET"]) @login_required def settings(): - trloginfail = False - if "trtoken" in request.form: - try: - trello.TrelloClient(api_key = trello_credentials.api_key, token = request.form["trtoken"]).list_boards() - except: - trloginfail = True - else: - trapi = TrelloAPI(token = request.form["trtoken"], user = current_user) - db.session.add(trapi) - db.session.commit() - return render_template("settings.html", twlogin = TwitterAPI.query.filter_by(user=current_user).first(), trlogin = TrelloAPI.query.filter_by(user=current_user).first(), trloginfail = trloginfail) + form = TrelloAPIForm() + if form.validate_on_submit(): + if current_user.trello_api.first(): + return "Already an api connected." + db.session.add(TrelloAPI(token = form.token.data, user = current_user)) + db.session.commit() + return render_template("settings.html", form = form) @app.route("/dashboard", methods = ["POST", "GET"]) +@login_required def dashboard(): - if not tw.is_login(session): - return redirect("/") - - twapi = tw.api_login(session) - if request.args.get("twrm"): - database.twrm(request.args.get("twrm")) - if request.args.get("delet"): - twapi.destroy_status(request.args.get["twrm"]) - elif "tweet" in request.form and "slots" in request.form and "keywords" in request.form: - try: - slots = int(request.form["slots"]) - tweet = int(request.form["tweet"]) - except: - formerror = True - else: - database.twadd(twapi.me().id, tweet, slots, str(request.form["keywords"].split(","))) - formerror = False - + twapi = current_user.twitter_api.first() + trapi = current_user.trello_api.first() tweets = list() - idtake = list() - for t in database.twlist(twapi.me().id): - tw = twapi.get_status(t["id"]) - keywords = "|" - for te in eval(t["keywords"]): - keywords += f" {te} |" - tweets.append({"text": tw.text, "id": tw.id, "slots": f"{t['slots']}/{t['maxslots']}", "keywords": keywords}) - idtake.append(tw.id) - timeline = list() - for t in twapi.user_timeline(): - if not t.in_reply_to_status_id and not t.retweeted and t.id not in idtake: - timeline.append({"text": t.text, "id": t.id}) + boards = list() + columns = list() - if tr.is_login(session): - trapi = trello.TrelloClient(api_key = trello_credentials.api_key, token = database.trtoken(twapi.me().id)) - boards = list() + if twapi: + twapi = twapi.api_login() + + if request.args.get("twrm"): + db.session.delete(Tweets.query.filter_by(user = current_user, statu_id = request.args.get("twrm")).first()) + db.session.commit() + if request.args.get("delet"): + twapi.destroy_status(request.args.get["twrm"]) + elif "tweet" in request.form and "slots" in request.form and "keywords" in request.form: + try: + slots = int(request.form["slots"]) + tweet = int(request.form["tweet"]) + except: + formerror = True + else: + db.session.add(Tweets(user = current_user, statu_id = tweet, slots = 0, slots_max = slots, keywords = str(request.form["keywords"].split(",")))) + db.session.commit() + elif "board" in request.form: + db.session.add(Boards(user = current_user, board_id = request.form["board"])) + db.session.commit() + elif "column" in request.form: + current_user.boards.first().column_id = request.form["column"] + db.session.commit() + + for t in Tweets.query.filter_by(user = current_user): + statu = twapi.get_status(t.statu_id) + keywords = "|" + for text in eval(t.keywords): + keywords += f" {text} |" + tweets.append({"text": statu.text, "id": t.statu_id, "slots": f"{t.slots}/{t.slots_max}", "keywords": keywords}) + + for t in twapi.user_timeline(): + if not t.in_reply_to_status_id and not t.retweeted and not Tweets.query.filter_by(user = current_user, statu_id = t.id).first(): + timeline.append({"text": t.text, "id": t.id}) + + + if trapi: + trapi = trapi.api_login() for b in trapi.list_boards(): - boards.append(b.name) + select = False + if b.id == current_user.boards.first().board_id: + select = True + boards.append({"text": b.name, "id": b.id, "select": select}) + if current_user.boards.first() and current_user.boards.first().board_id: + for c in trapi.get_board(current_user.boards.first().board_id).list_lists(): + select = False + if c.id == current_user.boards.first().column_id: + select = True + columns.append({"text": c.name, "id": c.id, "select": select}) - return render_template("dashboard.html", login = True, tweets = tweets, timeline = timeline, boards = boards, columns = None) + return render_template("dashboard.html", timeline = timeline, tweets = tweets, boards = boards, columns = columns) @app.route("/twtoken") def twtoken(): return f"{session['access_token']} -- {session['access_secret_token']}" -@app.route("/twpost") -def twpost(): - if tw.is_login(session): - api = twapi_login(session) - api.update_status("bloup") - return "Send !" - else: - return "Not login !" - @app.route("/test") def test(): return render_template("elements.html") diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html index b602dea..48b7935 100644 --- a/app/templates/dashboard.html +++ b/app/templates/dashboard.html @@ -12,6 +12,7 @@

Current automatized tweets


+ {% if current_user.twitter_api.first() %} @@ -33,10 +34,14 @@ {% endfor %}
+ {% else %} +

Twitter API not connected

+ {% endif %}

Add an automatized tweet


+ {% if current_user.twitter_api.first() %}
@@ -54,12 +59,16 @@
- +
+ {% else %} +

Twitter API not connected

+ {% endif %}

Trello board


+ {% if current_user.trello_api.first() %}
@@ -67,7 +76,7 @@
{% for b in boards %}
- +
{% endfor %} @@ -76,18 +85,25 @@

Choose a column

+ {% if columns %} {% for c in columns %}
- +
{% endfor %} + {% else %} +

No board set yet

+ {% endif %}
+ {% else %} +

Trello API not connected

+ {% endif %}
diff --git a/app/templates/login.html b/app/templates/login.html index 1dfec0b..33f5160 100644 --- a/app/templates/login.html +++ b/app/templates/login.html @@ -14,10 +14,16 @@

{{ form.username.label }}
{{ form.username(size=32) }} + {% for error in form.username.errors %} + [{{ error }}] + {% endfor %}

{{ form.password.label }}
{{ form.password(size=32) }} + {% for error in form.password.errors %} + [{{ error }}] + {% endfor %}

{{ form.remember_me() }} {{ form.remember_me.label }}

{{ form.submit() }}

diff --git a/app/templates/settings.html b/app/templates/settings.html index 0f19606..bbb41ed 100644 --- a/app/templates/settings.html +++ b/app/templates/settings.html @@ -12,7 +12,7 @@

Connexions

Twitter : - {% if twlogin %} + {% if current_user.twitter_api.first() %} Connected

Disconnect {% else %} @@ -20,15 +20,22 @@ Connect {% endif %}

Trello : - {% if trlogin %} + {% if current_user.trello_api.first() %} Connected

Disconnect {% else %} Disconnected

Click here and give the token bellow

-
- - + + {{ form.hidden_tag() }} +

+ {{ form.token.label }} + {{ form.token(size=64) }} + {% for error in form.token.errors %} + [{{ error }}] + {% endfor %} +

+

{{ form.submit() }}

{% endif %} diff --git a/database.py b/database.py deleted file mode 100644 index 3bbd5dd..0000000 --- a/database.py +++ /dev/null @@ -1,68 +0,0 @@ -import sqlite3 - -def tradd(id, token): - with sqlite3.connect('database.db') as db: - sucess = True - dbc = db.cursor() - for u in dbc.execute("SELECT * FROM trello WHERE id=?", (id,)): - sucess = False - if sucess: - dbc.execute("INSERT INTO trello (id, token) VALUES (?, ?)", (id, token,)) - dbc.close() - db.commit() - return sucess - -def trrm(id): - with sqlite3.connect('database.db') as db: - dbc = db.cursor() - dbc.execute("DELETE FROM trello WHERE id=?", (id,)) - dbc.close() - db.commit() - -def trtoken(id): - with sqlite3.connect('database.db') as db: - token = False - dbc = db.cursor() - for u in dbc.execute("SELECT * FROM trello WHERE id=?;", (id,)): - token = u - dbc.close() - return token - -def twadd(user, id, maxslots, keywords): - with sqlite3.connect('database.db') as db: - dbc = db.cursor() - dbc.execute("INSERT INTO tweets (user, id, slots, maxslots, keywords) VALUES (?, ?, ?, ?, ?)", (user, id, 0, maxslots, keywords,)) - dbc.close() - db.commit() - -def twrm(id): - with sqlite3.connect('database.db') as db: - dbc = db.cursor() - dbc.execute("DELETE FROM tweets WHERE id=?", (id,)) - dbc.close() - db.commit() - -def twlist(user): - with sqlite3.connect('database.db') as db: - dbc = db.cursor() - tweets = list() - for u in dbc.execute("SELECT * FROM tweets WHERE user=?", (user,)): - tweets.append({"id": u[1], "slots": u[2], "maxslots": u[3], "keywords": u[4]}) - dbc.close() - db.commit() - return tweets - - -with sqlite3.connect('database.db') as db: - Table = False - dbc = db.cursor() - log = False - iid = None - for t in dbc.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='trello';"): - Table = True - if not Table: - dbc.execute('''CREATE TABLE trello (id int, token text)''') - dbc.execute('''CREATE TABLE tweets (user int, id int, slots int, maxslots int, keywords text)''') - dbc.close() - db.commit() - #register("flifloo", "flifloo@gmail.com", "owo") diff --git a/tr.py b/tr.py deleted file mode 100644 index e0cd1fb..0000000 --- a/tr.py +++ /dev/null @@ -1,5 +0,0 @@ -import trello -import tw - -def is_trlogin(session): - return is_twkeys(session) and database.trtoken(tw.api_login(session).me().id) diff --git a/tw.py b/tw.py deleted file mode 100644 index 59cebe1..0000000 --- a/tw.py +++ /dev/null @@ -1,18 +0,0 @@ -import tweepy, twitter_credentials - -def api_login(session): - auth = tweepy.OAuthHandler(twitter_credentials.consumer_key, twitter_credentials.consumer_secret_key) - auth.set_access_token(session["access_token"], session["access_secret_token"]) - return tweepy.API(auth) - -def is_keys(session): - try: - session["access_token"] - session["access_secret_token"] - except: - return False - else: - return True - -def is_login(session): - return is_keys(session) and api_login(session).verify_credentials()