diff --git a/__pycache__/forms.cpython-37.pyc b/__pycache__/forms.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5766b1011bb1053214f523730cde9a5988bf640 Binary files /dev/null and b/__pycache__/forms.cpython-37.pyc differ diff --git a/app.py b/app.py index 29a2ca29ebe60b8bbec2c6bba1fdda2fab7ac139..08d351005ee06cc0303dd4ca68779bc4c09b836d 100755 --- a/app.py +++ b/app.py @@ -1,17 +1,38 @@ #!/usr/bin/python3 -from flask import Flask, render_template, url_for +from flask import Flask, render_template, url_for, flash, redirect +from flask_sqlalchemy import SQLAlchemy import requests +from forms import RegistrationForm, LoginForm import asyncio from bs4 import BeautifulSoup as bs4 app_name = "Climbing Coach" app = Flask(app_name) +app.config['SECRET_KEY'] = '6009555f5e50514b882adf5c6a42ea7b' +app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///site.db" +db = SQLAlchemy(app) + + +class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(20), unique=True, nullable=False) + email = db.Column(db.String(120), unique=True, nullable=False) + image_file = db.Column(db.String(20), nullable=False, default='default.jpg') + password = db.Column(db.String(60), nullable=False) + posts = db.relationship('Post', backref='author', lazy=True) + + def __repr__(self): + return f"User('{self.username}', '{self.email}', '{self.image_file}')" def get_news(): - r = requests.get("https://www.8a.nu/rss/Main.aspx?CountryCode=GLOBAL").content + """ Parse le flux rss de 8a.nu """ + r = requests.get( + "https://www.8a.nu/rss/Main.aspx?CountryCode=GLOBAL").content soup = bs4(r, "html.parser") - news = [{"title": e.title.text, "description": e.description.text, "date_posted": e.pubdate.text} for e in soup.find_all("item")] + news = [{"title": e.title.text, "description": e.description.text, + "date_posted": e.pubdate.text.replace(" 00:00:00 GMT", "") + } for e in soup.find_all("item")] # print(news) return news @@ -28,6 +49,41 @@ def about(): return render_template("about.html", title=app_name + " - About") +@app.route("/register", methods=['GET', 'POST']) +def register(): + form = RegistrationForm() + if form.validate_on_submit(): + flash(f"Account created for { form.email.data } !", "success") + return redirect(url_for('home')) + return render_template('register.html', + title=app_name + " - Register", form=form) + + +@app.route("/login", methods=['GET', 'POST']) +def login(): + form = LoginForm() + + if form.validate_on_submit(): + if form.email.data == "test@test.com" and form.password.data == "test": + # TODO: replace fake test login with database login + flash(f"You have been logged in !", "success") + return redirect(url_for('home')) + else: + flash(f"Login Unsuccessful. Please check username and password", "danger") + return render_template('login.html', + title=app_name + " - Login", form=form) + + +@app.route("/planning") +def planning(): + return "TODO" + + +@app.route("/meteo") +def meteo(): + return "TODO" + + if __name__ == '__main__': # get_news() app.run(debug=True) diff --git a/forms.py b/forms.py new file mode 100644 index 0000000000000000000000000000000000000000..2dd6a691b0cd83a77971a4c8b7908bfcab31112f --- /dev/null +++ b/forms.py @@ -0,0 +1,26 @@ +from flask_wtf import FlaskForm + +from wtforms import StringField, PasswordField, SubmitField, BooleanField + +from wtforms.validators import DataRequired, Length, Email, EqualTo + + +class RegistrationForm(FlaskForm): + username = StringField('Username', + validators=[DataRequired(), Length(min=2, max=20)]) + email = StringField('Email', + validators=[DataRequired(), Email()]) + password = PasswordField('Password', validators=[DataRequired()]) + confirm_password = PasswordField( + 'Confirm Password', + validators=[DataRequired(), EqualTo('password')] + ) + submit = SubmitField('Sign Up') + + +class LoginForm(FlaskForm): + email = StringField('Email', + validators=[DataRequired(), Email()]) + password = PasswordField('Password', validators=[DataRequired()]) + remember = BooleanField('Remember') + submit = SubmitField('Log In') diff --git a/requirements.txt b/requirements.txt index dd195e99f4f09af9d9494eaac133dd41fc78ed6c..895e049eba110d940daf28a7b62ba5f91b54ffbf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,6 @@ flask requests fpdf asyncio -beautifulsoup4 \ No newline at end of file +beautifulsoup4 +flask-wtf +flask-sqlalchemy \ No newline at end of file diff --git a/templates/layout.html b/templates/layout.html index 163f2c3b94993ca922dc5dc14addee22246d35dc..7178d5391b8e490c3d4ab6bbcb5ba3be2297029f 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -22,15 +22,15 @@ </button> <div class="collapse navbar-collapse" id="navbarToggle"> <div class="navbar-nav mr-auto"> - <a class="nav-item nav-link" href="/">Home</a> - <a class="nav-item nav-link" href="/planning">Planning</a> - <a class="nav-item nav-link" href="/meteo">Check the Weather</a> - <a class="nav-item nav-link" href="/about">About</a> + <a class="nav-item nav-link" href="{{ url_for('home') }}">Home</a> + <a class="nav-item nav-link" href="{{ url_for('planning') }}">Planning</a> + <a class="nav-item nav-link" href="{{ url_for('meteo') }}">Check the Weather</a> + <a class="nav-item nav-link" href="{{ url_for('about') }}">About</a> </div> <!-- Navbar Right Side --> <div class="navbar-nav"> - <a class="nav-item nav-link" href="/login">Login</a> - <a class="nav-item nav-link" href="/register">Register</a> + <a class="nav-item nav-link" href="{{ url_for('login') }}">Login</a> + <a class="nav-item nav-link" href="{{ url_for('register') }}">Register</a> </div> </div> </div> @@ -40,6 +40,15 @@ <main role="main" class="container"> <div class="row"> <div class="col-md-8"> + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + <div class="alert alert-{{ category }}"> + {{ message }} + </div> + {% endfor %} + {% endif %} + {% endwith %} {% block content %}{% endblock %} </div> <div class="col-md-8"> diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000000000000000000000000000000000000..c6db788cf76ac6844108407a8e23cba0a0d07012 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,56 @@ +{% extends "layout.html" %} +{% block content %} + <div class="content-section"> + <form method="POST" action=""> + {{ form.hidden_tag() }} + <fieldset class="form-group"> + <legend class="border-bottom mb-4">Join Today</legend> + + <div class="form-group"> + {{ form.email.label(class="form-control-label") }} + + {% if form.email.errors %} + {{ form.email(class="form-control form-control-lg is-invalid") }} + <div class="invalid-feedback"> + {% for error in form.email.errors %} + <span>{{ error }} </span> + {% endfor %} + </div> + {% endif %} + + {{ form.email(class="form-control form-control-lg") }} + </div> + <div class="form-group"> + {{ form.password.label(class="form-control-label") }} + + {% if form.password.errors %} + {{ form.password(class="form-control form-control-lg is-invalid") }} + <div class="invalid-feedback"> + {% for error in form.password.errors %} + <span>{{ error }} </span> + {% endfor %} + </div> + {% endif %} + + {{ form.password(class="form-control form-control-lg") }} + </div> + + <div class="form-check"> + {{ form.remember(class="form-check-input") }} + {{ form.remember.label(class="form-check-label") }} + </div> + </fieldset> + <div class="form-group"> + {{ form.submit(class="btn btn-outline-info ") }} + </div> + <small class="text-muted ml-2"> + <a href="#">Forgot Password ?</a> + </small> + </form> + </div> + <div class="border-top pt-3"> + <small class="text-muted"> + Need an account ? <a class="ml-2" href="{{ url_for('register') }}">Sign Up Now</a> + </small> + </div> +{% endblock content %} \ No newline at end of file diff --git a/templates/register.html b/templates/register.html new file mode 100644 index 0000000000000000000000000000000000000000..564ed6d4f9a43c9f6e27dcb14b0bfc3fee4db389 --- /dev/null +++ b/templates/register.html @@ -0,0 +1,75 @@ +{% extends "layout.html" %} +{% block content %} + <div class="content-section"> + <form method="POST" action=""> + {{ form.hidden_tag() }} + <fieldset class="form-group"> + <legend class="border-bottom mb-4">Join Today</legend> + <div class="form-group"> + {{ form.username.label(class="form-control-label") }} + + {% if form.username.errors %} + {{ form.username(class="form-control form-control-lg is-invalid") }} + <div class="invalid-feedback"> + {% for error in form.username.errors %} + <span>{{ error }} </span> + {% endfor %} + </div> + {% endif %} + + {{ form.username(class="form-control form-control-lg") }} + </div> + <div class="form-group"> + {{ form.email.label(class="form-control-label") }} + + {% if form.email.errors %} + {{ form.email(class="form-control form-control-lg is-invalid") }} + <div class="invalid-feedback"> + {% for error in form.email.errors %} + <span>{{ error }} </span> + {% endfor %} + </div> + {% endif %} + + {{ form.email(class="form-control form-control-lg") }} + </div> + <div class="form-group"> + {{ form.password.label(class="form-control-label") }} + + {% if form.password.errors %} + {{ form.password(class="form-control form-control-lg is-invalid") }} + <div class="invalid-feedback"> + {% for error in form.password.errors %} + <span>{{ error }} </span> + {% endfor %} + </div> + {% endif %} + + {{ form.password(class="form-control form-control-lg") }} + </div> + <div class="form-group"> + {{ form.confirm_password.label(class="form-control-label") }} + + {% if form.confirm_password.errors %} + {{ form.confirm_password(class="form-control form-control-lg is-invalid") }} + <div class="invalid-feedback"> + {% for error in form.confirm_password.errors %} + <span>{{ error }} </span> + {% endfor %} + </div> + {% endif %} + + {{ form.confirm_password(class="form-control form-control-lg") }} + </div> + </fieldset> + <div class="form-group"> + {{ form.submit(class="btn btn-outline-info ") }} + </div> + </form> + </div> + <div class="border-top pt-3"> + <small class="text-muted"> + Already have an account ? <a class="ml-2" href="{{ url_for('login') }}">Log In</a> + </small> + </div> +{% endblock content %} \ No newline at end of file