End of rework
This commit is contained in:
parent
6beb1bb246
commit
2415834c72
9 changed files with 168 additions and 181 deletions
22
app/forms.py
22
app/forms.py
|
@ -1,7 +1,8 @@
|
|||
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()])
|
||||
|
@ -9,6 +10,15 @@ class LoginForm(FlaskForm):
|
|||
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()])
|
||||
|
@ -26,3 +36,13 @@ class RegistrationForm(FlaskForm):
|
|||
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")
|
||||
|
|
|
@ -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))
|
||||
|
|
112
app/routes.py
112
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():
|
||||
|
@ -14,9 +13,6 @@ def login():
|
|||
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)
|
||||
next_page = request.args.get("next")
|
||||
if not next_page or url_parse(next_page).netloc != "":
|
||||
|
@ -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,26 +89,30 @@ 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)
|
||||
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", twlogin = TwitterAPI.query.filter_by(user=current_user).first(), trlogin = TrelloAPI.query.filter_by(user=current_user).first(), trloginfail = trloginfail)
|
||||
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 = current_user.twitter_api.first()
|
||||
trapi = current_user.trello_api.first()
|
||||
tweets = list()
|
||||
timeline = list()
|
||||
boards = list()
|
||||
columns = list()
|
||||
|
||||
if twapi:
|
||||
twapi = twapi.api_login()
|
||||
|
||||
twapi = tw.api_login(session)
|
||||
if request.args.get("twrm"):
|
||||
database.twrm(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:
|
||||
|
@ -120,46 +122,48 @@ def dashboard():
|
|||
except:
|
||||
formerror = True
|
||||
else:
|
||||
database.twadd(twapi.me().id, tweet, slots, str(request.form["keywords"].split(",")))
|
||||
formerror = False
|
||||
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()
|
||||
|
||||
tweets = list()
|
||||
idtake = list()
|
||||
for t in database.twlist(twapi.me().id):
|
||||
tw = twapi.get_status(t["id"])
|
||||
for t in Tweets.query.filter_by(user = current_user):
|
||||
statu = twapi.get_status(t.statu_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)
|
||||
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})
|
||||
|
||||
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:
|
||||
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 tr.is_login(session):
|
||||
trapi = trello.TrelloClient(api_key = trello_credentials.api_key, token = database.trtoken(twapi.me().id))
|
||||
boards = list()
|
||||
|
||||
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")
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
<h3>Current automatized tweets</h3>
|
||||
<hr />
|
||||
{% if current_user.twitter_api.first() %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -33,10 +34,14 @@
|
|||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<h4>Twitter API not connected</h4>
|
||||
{% endif %}
|
||||
<hr />
|
||||
|
||||
<h3>Add an automatized tweet</h3>
|
||||
<hr />
|
||||
{% if current_user.twitter_api.first() %}
|
||||
<form action = "https://cyberplanificateur.flifloo.fr/dashboard" method = "POST">
|
||||
<section>
|
||||
<div class="row">
|
||||
|
@ -54,12 +59,16 @@
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<input type="submit" value="Connect" class="button primary">
|
||||
<input type="submit" value="Select" class="button primary">
|
||||
</form>
|
||||
{% else %}
|
||||
<h4>Twitter API not connected</h4>
|
||||
{% endif %}
|
||||
<hr />
|
||||
|
||||
<h3>Trello board</h3>
|
||||
<hr />
|
||||
{% if current_user.trello_api.first() %}
|
||||
<section>
|
||||
<div class="row">
|
||||
<div class="col-6 col-12-medium">
|
||||
|
@ -67,7 +76,7 @@
|
|||
<form action="https://cyberplanificateur.flifloo.fr/dashboard" method="POST">
|
||||
{% for b in boards %}
|
||||
<div class="col-4 col-12-small">
|
||||
<input type="radio" id="{{ b['id'] }}" name="board" value="{{ b['id'] }}">
|
||||
<input type="radio" id="{{ b['id'] }}" name="board" value="{{ b['id'] }}" {% if b['select'] %} checked="checked" {% endif %}>
|
||||
<label for="{{ b['id'] }}">{{ b['text'] }}</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
@ -76,18 +85,25 @@
|
|||
</div>
|
||||
<div class="col-6 col-12-medium">
|
||||
<h4>Choose a column</h4>
|
||||
{% if columns %}
|
||||
<form action="https://cyberplanificateur.flifloo.fr/dashboard" method="POST">
|
||||
{% for c in columns %}
|
||||
<div class="col-4 col-12-small">
|
||||
<input type="radio" id="{{ c['id'] }}" name="column" value="{{ c['id'] }}">
|
||||
<input type="radio" id="{{ c['id'] }}" name="column" value="{{ c['id'] }}" {% if c['select'] %} checked="checked" {% endif %}>
|
||||
<label for="{{ c['id'] }}">{{ c['text'] }}</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<input type="submit" value="Select" class="button primary">
|
||||
</form>
|
||||
{% else %}
|
||||
<p>No board set yet</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% else %}
|
||||
<h4>Trello API not connected</h4>
|
||||
{% endif %}
|
||||
<hr />
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -14,10 +14,16 @@
|
|||
<p>
|
||||
{{ form.username.label }}<br>
|
||||
{{ form.username(size=32) }}
|
||||
{% for error in form.username.errors %}
|
||||
<span style="color: red;">[{{ error }}]</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
<p>
|
||||
{{ form.password.label }}<br>
|
||||
{{ form.password(size=32) }}
|
||||
{% for error in form.password.errors %}
|
||||
<span style="color: red;">[{{ error }}]</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
<p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
|
||||
<p>{{ form.submit() }}</p>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
<h3>Connexions</h3>
|
||||
<p>Twitter :
|
||||
{% if twlogin %}
|
||||
{% if current_user.twitter_api.first() %}
|
||||
<font color="green">Connected</font></p>
|
||||
<a href="{{ url_for('twlogout') }}" class="button">Disconnect</a>
|
||||
{% else %}
|
||||
|
@ -20,15 +20,22 @@
|
|||
<a href="{{ url_for('twlogin') }}" class="button primary">Connect</a>
|
||||
{% endif %}
|
||||
<p>Trello :
|
||||
{% if trlogin %}
|
||||
{% if current_user.trello_api.first() %}
|
||||
<font color="green">Connected</font></p>
|
||||
<a href="{{ url_for('trlogout') }}" class="button">Disconnect</a>
|
||||
{% else %}
|
||||
<font color="red">Disconnected</font></p>
|
||||
<p><a href="{{ url_for('trlogin') }}">Click here</a> and give the token bellow</p>
|
||||
<form action = "https://cyberplanificateur.flifloo.fr/settings" method = "POST">
|
||||
<input type="text" name="trtoken" placeholder="Trello token" />
|
||||
<input type="submit" value="Connect" class="button primary">
|
||||
<form action = "" method = "POST" novalidate>
|
||||
{{ form.hidden_tag() }}
|
||||
<p>
|
||||
{{ form.token.label }}
|
||||
{{ form.token(size=64) }}
|
||||
{% for error in form.token.errors %}
|
||||
<span style="color: red;">[{{ error }}]</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
<p>{{ form.submit() }}</p>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
|
|
68
database.py
68
database.py
|
@ -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")
|
5
tr.py
5
tr.py
|
@ -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)
|
18
tw.py
18
tw.py
|
@ -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()
|
Reference in a new issue