From adc7b9b71a27372717c441049dfbc64211ba9ff6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20Wikle=20DUBARD?= <loic97429@gmail.com>
Date: Sat, 23 Nov 2019 15:52:36 +0100
Subject: [PATCH] login+register page done

---
 __pycache__/forms.cpython-37.pyc | Bin 0 -> 1133 bytes
 app.py                           |  62 +++++++++++++++++++++++--
 forms.py                         |  26 +++++++++++
 requirements.txt                 |   4 +-
 templates/layout.html            |  21 ++++++---
 templates/login.html             |  56 +++++++++++++++++++++++
 templates/register.html          |  75 +++++++++++++++++++++++++++++++
 7 files changed, 234 insertions(+), 10 deletions(-)
 create mode 100644 __pycache__/forms.cpython-37.pyc
 create mode 100644 forms.py
 create mode 100644 templates/login.html
 create mode 100644 templates/register.html

diff --git a/__pycache__/forms.cpython-37.pyc b/__pycache__/forms.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e5766b1011bb1053214f523730cde9a5988bf640
GIT binary patch
literal 1133
zcmZuwOLNmO5SILYrG)Y-aOu^DHW!Wz)9H(W>6A{=UNplPH&Rj$mYvEDg<Qk6zk(A#
z312z&FK}X4c3K#aN1J^~yZXM(Zm$;*Sc~|_`)?*8Khan%3zQw$)dvuqaGDcI8KtNj
zxgkwvN{d<2X0~*gqy1*?N{@NcXTA(rAVU^X@|tjq+g}N{1znmf0^8v(*sivF+#8YD
zzkw<wrj37?r`5;9QpwnA!cncVVtSZ~oHxCbw5qO3#alBR&Cg|4w??#Embpj^ZNb54
zKdsZDxSVH7@Wwe3#k9U?>;su*dE*{j&eQy~9AnAVazWXFU0r|>gi%hIAxut%wIssk
z1~<8NZA=YrUmMJUh@&I!l5{>#`0ymio>H9?fbHp=ko!y8WksULgC%8aJcMUQO@An+
zSyijF&dLIx&AhWps3Mi(#(-9C9)gIC#*|qBBK-^)1)tJ9<7r*0O8F3OycINy{$5#3
zG9@=xp2nMXur1tCHZ3;KX2<cp#!C_`kt9u!B(mi59Q7zk5SlikU?PY@T$HDa%)7qY
znzleN6^@BoM}ecn`s22KvZ|_VJnK}NtnWlU#Z(l(UJO)O)`R_WJeQ)VtHH_e-P?n`
z)6rm@XYw3)-x`<c_+l%a%?1-drrMr;Q6U_~b}FptQHwr?-G|SBZ{5)Gzlgn^;~hBg
zFR_|FLsRN<v!f4fq|*YT0ugc>ek1MxVQ%9emD5Z!rE!R<>chqAJ_zOwg%t8!sD%Sr
zn{SHaxThXq7+F-0P~4%4)Tt*Z?m%?FWS;7-(cq~KOu5Ca)t;g6IS9P7Lg*0-#KEK5
ze;ltde}ey|<f@)193|$0hB&r8=%UDu(nZ(1;PxNGbxXc}s%BUNtSkJlrN(>N4$~`&
OeIZeiv0-eO{oZf8jt2e!

literal 0
HcmV?d00001

diff --git a/app.py b/app.py
index 29a2ca2..08d3510 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 0000000..2dd6a69
--- /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 dd195e9..895e049 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 163f2c3..7178d53 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 0000000..c6db788
--- /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 0000000..564ed6d
--- /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
-- 
GitLab