Skip to content

Commit 37ac2e5

Browse files
authored
Add files via upload
1 parent 69a06ec commit 37ac2e5

File tree

8 files changed

+272
-0
lines changed

8 files changed

+272
-0
lines changed

day68/main.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
from flask import Flask, render_template, request, url_for, redirect, flash, send_from_directory
2+
from werkzeug.security import generate_password_hash, check_password_hash
3+
from flask_sqlalchemy import SQLAlchemy
4+
from flask_login import UserMixin, login_user, LoginManager, login_required, current_user, logout_user
5+
6+
app = Flask(__name__)
7+
8+
app.config['SECRET_KEY'] = 'any-secret-key-you-choose'
9+
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
10+
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
11+
db = SQLAlchemy(app)
12+
13+
# Initiate the LoginManager class
14+
login_manager = LoginManager()
15+
login_manager.init_app(app)
16+
17+
18+
@login_manager.user_loader
19+
def load_user(user_id):
20+
return User.query.get(int(user_id))
21+
22+
23+
# Create DB
24+
class User(UserMixin, db.Model):
25+
id = db.Column(db.Integer, primary_key=True)
26+
email = db.Column(db.String(100), unique=True)
27+
password = db.Column(db.String(100))
28+
name = db.Column(db.String(1000))
29+
# db.create_all()
30+
31+
32+
@app.route('/')
33+
def home():
34+
return render_template("index.html", logged_in=current_user.is_authenticated)
35+
36+
37+
# Register user & hash password
38+
@app.route('/register', methods=["GET", "POST"])
39+
def register():
40+
if request.method == "POST":
41+
# Check if email is already in use
42+
if User.query.filter_by(email=request.form.get('email')).first():
43+
flash("You've already signed up with that email, log in instead!")
44+
return redirect(url_for('login'))
45+
# Generated hash
46+
hash_and_salted_password = generate_password_hash(
47+
request.form.get('password'),
48+
method='pbkdf2:sha256',
49+
salt_length=8
50+
)
51+
new_user = User(
52+
email=request.form.get('email'),
53+
name=request.form.get('name'),
54+
password=hash_and_salted_password,
55+
)
56+
db.session.add(new_user)
57+
db.session.commit()
58+
login_user(new_user)
59+
return redirect(url_for("secrets"))
60+
return render_template("register.html", logged_in=current_user.is_authenticated)
61+
62+
63+
# Authenticate user
64+
@app.route('/login', methods=["GET", "POST"])
65+
def login():
66+
if request.method == "POST":
67+
email = request.form.get('email')
68+
password = request.form.get('password')
69+
user = User.query.filter_by(email=email).first()
70+
# Notify user if credentials are incorrect
71+
if not user:
72+
flash("That email does not exist, please try again.")
73+
return redirect(url_for('login'))
74+
elif not check_password_hash(user.password, password):
75+
flash('Password incorrect, please try again.')
76+
return redirect(url_for('login'))
77+
else:
78+
login_user(user)
79+
return redirect(url_for('secrets'))
80+
return render_template("login.html", logged_in=current_user.is_authenticated)
81+
82+
83+
@app.route('/secrets')
84+
@login_required
85+
def secrets():
86+
print(current_user.name)
87+
return render_template("secrets.html", name=current_user.name, logged_in=True)
88+
89+
90+
@app.route('/logout')
91+
def logout():
92+
logout_user()
93+
return redirect(url_for('home'))
94+
95+
96+
@app.route('/download')
97+
@login_required
98+
def download():
99+
return send_from_directory(directory='static/files', path="cheat_sheet.pdf")
100+
101+
102+
if __name__ == "__main__":
103+
app.run(debug=True)

day68/static/css/styles.css

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
@import url(https://fonts.googleapis.com/css?family=Open+Sans);
2+
.btn { display: inline-block; *display: inline; *zoom: 1; padding: 4px 10px 4px; margin-bottom: 0; font-size: 13px; line-height: 18px; color: #333333; text-align: center;text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); vertical-align: middle; background-color: #f5f5f5; background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(top, #ffffff, #e6e6e6); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr=#ffffff, endColorstr=#e6e6e6, GradientType=0); border-color: #e6e6e6 #e6e6e6 #e6e6e6; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); border: 1px solid #e6e6e6; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); cursor: pointer; *margin-left: .3em; }
3+
.btn:hover, .btn:active, .btn.active, .btn.disabled, .btn[disabled] { background-color: #e6e6e6; }
4+
.btn-large { padding: 9px 14px; font-size: 15px; line-height: normal; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; }
5+
.btn:hover { color: #333333; text-decoration: none; background-color: #e6e6e6; background-position: 0 -15px; -webkit-transition: background-position 0.1s linear; -moz-transition: background-position 0.1s linear; -ms-transition: background-position 0.1s linear; -o-transition: background-position 0.1s linear; transition: background-position 0.1s linear; }
6+
.btn-primary, .btn-primary:hover { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); color: #ffffff; }
7+
.btn-primary.active { color: rgba(255, 255, 255, 0.75); }
8+
.btn-primary { background-color: #4a77d4; background-image: -moz-linear-gradient(top, #6eb6de, #4a77d4); background-image: -ms-linear-gradient(top, #6eb6de, #4a77d4); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#6eb6de), to(#4a77d4)); background-image: -webkit-linear-gradient(top, #6eb6de, #4a77d4); background-image: -o-linear-gradient(top, #6eb6de, #4a77d4); background-image: linear-gradient(top, #6eb6de, #4a77d4); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr=#6eb6de, endColorstr=#4a77d4, GradientType=0); border: 1px solid #3762bc; text-shadow: 1px 1px 1px rgba(0,0,0,0.4); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.5); }
9+
.btn-primary:hover, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, .btn-primary[disabled] { filter: none; background-color: #4a77d4; }
10+
.btn-block { width: 100%; display:block; margin-bottom:20px; }
11+
12+
* { -webkit-box-sizing:border-box; -moz-box-sizing:border-box; -ms-box-sizing:border-box; -o-box-sizing:border-box; box-sizing:border-box; }
13+
14+
html { width: 100%; height:100%; overflow:hidden; }
15+
16+
body {
17+
width: 100%;
18+
height:100%;
19+
font-family: 'Open Sans', sans-serif;
20+
background: #092756;
21+
background: -moz-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%),-moz-linear-gradient(top, rgba(57,173,219,.25) 0%, rgba(42,60,87,.4) 100%), -moz-linear-gradient(-45deg, #670d10 0%, #092756 100%);
22+
background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), -webkit-linear-gradient(top, rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -webkit-linear-gradient(-45deg, #670d10 0%,#092756 100%);
23+
background: -o-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), -o-linear-gradient(top, rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -o-linear-gradient(-45deg, #670d10 0%,#092756 100%);
24+
background: -ms-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), -ms-linear-gradient(top, rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -ms-linear-gradient(-45deg, #670d10 0%,#092756 100%);
25+
background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), linear-gradient(to bottom, rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), linear-gradient(135deg, #670d10 0%,#092756 100%);
26+
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3E1D6D', endColorstr='#092756',GradientType=1 );
27+
}
28+
29+
a {
30+
text-decoration: none;
31+
text-align: center;
32+
}
33+
p {
34+
color: #ee6f57;
35+
text-align: center;
36+
}
37+
38+
.box {
39+
position: absolute;
40+
top: 50%;
41+
left: 50%;
42+
margin: -150px 0 0 -150px;
43+
width:300px;
44+
height:300px;
45+
}
46+
.box h1 { color: #fff; text-shadow: 0 0 10px rgba(0,0,0,0.3); letter-spacing:1px; text-align:center; }
47+
.container {
48+
margin-top: 10rem;
49+
text-align: center;
50+
}
51+
.container h1 { color: #fff; text-shadow: 0 0 10px rgba(0,0,0,0.3); letter-spacing:1px; text-align:center; }
52+
input {
53+
width: 100%;
54+
margin-bottom: 10px;
55+
background: rgba(0,0,0,0.3);
56+
border: none;
57+
outline: none;
58+
padding: 10px;
59+
font-size: 13px;
60+
color: #fff;
61+
text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
62+
border: 1px solid rgba(0,0,0,0.3);
63+
border-radius: 4px;
64+
box-shadow: inset 0 -5px 45px rgba(100,100,100,0.2), 0 1px 1px rgba(255,255,255,0.2);
65+
-webkit-transition: box-shadow .5s ease;
66+
-moz-transition: box-shadow .5s ease;
67+
-o-transition: box-shadow .5s ease;
68+
-ms-transition: box-shadow .5s ease;
69+
transition: box-shadow .5s ease;
70+
}
71+
input:focus { box-shadow: inset 0 -5px 45px rgba(100,100,100,0.4), 0 1px 1px rgba(255,255,255,0.2); }

day68/static/files/cheat_sheet.pdf

63.5 KB
Binary file not shown.

day68/templates/base.html

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1">
8+
<title>Flask Authentication</title>
9+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
10+
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css')}}">
11+
</head>
12+
13+
<body>
14+
15+
<nav class="navbar navbar-expand-lg navbar-light bg-light">
16+
<a class="navbar-brand" href="/">Flask Authentication</a>
17+
<div class="collapse navbar-collapse">
18+
<ul class="navbar-nav ml-auto">
19+
<li class="nav-item">
20+
<a class="nav-link" href="{{ url_for('home') }}">Home</a>
21+
</li>
22+
{% if not logged_in: %}
23+
<li class="nav-item">
24+
<a class="nav-link" href="{{ url_for('login') }}">Login</a>
25+
</li>
26+
<li class="nav-item">
27+
<a class="nav-link" href="{{ url_for('register') }}">Register</a>
28+
</li>
29+
{% endif %}
30+
<li class="nav-item">
31+
<a class="nav-link" href="{{ url_for('logout') }}">Log Out</a>
32+
</li>
33+
</ul>
34+
</div>
35+
</nav>
36+
{% block content %}
37+
{% endblock %}
38+
</body>
39+
40+
</html>

day68/templates/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% extends "base.html" %}
2+
{% block content %}
3+
4+
<div class="box">
5+
<h1>Flask Authentication</h1>
6+
7+
<a href="{{ url_for('login') }}" class="btn btn-primary btn-block btn-large">Login</a>
8+
<a href="{{ url_for('register') }}" class="btn btn-secondary btn-block btn-large">Register</a>
9+
10+
</div>
11+
12+
{% endblock %}

day68/templates/login.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{% extends "base.html" %}
2+
{% block content %}
3+
4+
<div class="box">
5+
<h1>Login</h1>
6+
{% with messages = get_flashed_messages() %}
7+
{% if messages %}
8+
{% for message in messages %}
9+
<p>{{ message }}</p>
10+
{% endfor %}
11+
{% endif %}
12+
{% endwith %}
13+
<form method="post">
14+
<input type="text" name="email" placeholder="Email" required="required"/>
15+
<input type="password" name="password" placeholder="Password" required="required"/>
16+
<button type="submit" class="btn btn-primary btn-block btn-large">Let me in.</button>
17+
</form>
18+
</div>
19+
20+
{% endblock %}

day68/templates/register.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{% extends "base.html" %}
2+
{% block content %}
3+
4+
<div class="box">
5+
<h1>Register</h1>
6+
<form action="{{ url_for('register') }}" method="post">
7+
<input type="text" name="name" placeholder="Name" required="required" />
8+
<input type="email" name="email" placeholder="Email" required="required" />
9+
<input type="password" name="password" placeholder="Password" required="required" />
10+
<button type="submit" class="btn btn-primary btn-block btn-large">Sign me up.</button>
11+
</form>
12+
</div>
13+
14+
{% endblock %}

day68/templates/secrets.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% extends "base.html" %}
2+
{% block content %}
3+
4+
<div class="container">
5+
{% if name: %}
6+
<h1 class="title">Welcome, {{ name }}!</h1>
7+
<a href="{{ url_for('download', filename='cheat_sheet.pdf') }}">Download Your File</a>
8+
{% else: %}
9+
<h1 class="title">Please register or login to view this page.</h1>
10+
{% endif %}
11+
</div>
12+
{% endblock %}

0 commit comments

Comments
 (0)