Skip to content
Snippets Groups Projects
Commit e56a5d19 authored by Harry Hughes's avatar Harry Hughes
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 707 additions and 0 deletions
*.pyc
venv
x*
*.db
.DS_Store
logs*
Student Number: c22053853
Website Link:
Test user:
Email: test@test.com
Username: test
Password: test
\ No newline at end of file
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = '<dcb48b91e922460d1b73988d49fe5f98a6ea26c3c497dc2f>'
# suppress SQLAlchemy warning
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# DB Connection changed to mysql
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://c22053853:CardiffMySQL1!@csmysql.cs.cf.ac.uk:3306/c22053853_flask_db'
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
from blog import routes
from flask_admin import Admin
from blog.views import AdminView
from blog.models import User, Post
admin = Admin(app,name='Admin panel',template_mode='bootstrap3')
admin.add_view(AdminView(User, db.session))
admin.add_view(AdminView(Post, db.session))
from flask_wtf import FlaskForm
from flask_login import current_user
from wtforms import StringField, PasswordField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, EqualTo, ValidationError, Regexp, Length, Email
from blog.models import User
class RegistrationForm(FlaskForm):
email = StringField('Email',validators=[DataRequired(), Email()])
username = StringField('Username',validators=[DataRequired(), Length(min=2, max=11),Regexp('^[a-z]{4,11}$')])
password = PasswordField('Password',validators=[DataRequired()])
submit = SubmitField('Register')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user is not None:
raise ValidationError('Username already exist. Please choose a different one.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user is not None:
raise ValidationError('This email is already in use. Please use a different one.')
class LoginForm(FlaskForm):
email = StringField('Email',validators=[DataRequired()])
username = StringField('Username',validators=[DataRequired()])
password = PasswordField('Password',validators=[DataRequired()])
submit = SubmitField('Login')
class UpdateAccountForm(FlaskForm):
email = StringField('Email',validators=[DataRequired(), Email()])
username = StringField('Username',validators=[DataRequired(), Length(min=2, max=11)])
password = PasswordField('Password',validators=[DataRequired()])
submit = SubmitField('Update')
def validate_username(self, username):
if username.data != current_user.username:
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('That username is in use. Please try again')
def validate_email(self, email):
if email.data != current_user.email:
user = User.query.filter_by(email=email.data).first()
if user:
raise ValidationError('That email is in use. Please try again')
class PostForm(FlaskForm):
title = StringField('Title', validators=[DataRequired()])
content = TextAreaField('Content', validators=[DataRequired()])
submit = SubmitField('Post')
\ No newline at end of file
from datetime import datetime
from blog import db, login_manager
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
title = db.Column(db.Text, nullable=False)
content = db.Column(db.Text, nullable=False)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.date}', '{self.title}', '{self.content}')"
class User(UserMixin,db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(15), unique=True, nullable=False)
password=db.Column(db.String(128))
post = db.relationship('Post', backref='user', lazy=True)
is_admin=db.Column(db.Boolean,nullable=False,default=False)
email=db.Column(db.String(256), unique=True)
def __repr__(self):
return f"User('{self.username}')"
class Portfolio(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(255))
description = db.Column(db.Text)
date_completed = db.Column(db.Date)
client = db.Column(db.String(255))
technologies = db.Column(db.String(255))
link = db.Column(db.String(255))
#adapted from Grinberg(2014, 2018)
@property
def password(self):
raise AttributeError('Password is not readable.')
@password.setter
def password(self,password):
self.password=generate_password_hash(password)
def verify_password(self,password):
return check_password_hash(self.password,password)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
from flask import render_template, url_for, request, redirect, flash, Response, send_file, abort
from blog import app, db
from blog.models import User, Post, Portfolio
from blog.forms import RegistrationForm, LoginForm, UpdateAccountForm, PostForm
from flask_login import login_user, logout_user, current_user
@app.route("/")
@app.route("/home")
def home():
return render_template('home.html', title='Home')
@app.route("/portfolio")
def portfolio():
items = Portfolio.query.all()
return render_template('portfolio.html', items=items)
@app.route("/experience")
def experience():
return render_template('experience.html', title='Experience')
@app.route("/cv")
def cv():
return render_template('cv.html', title='cv')
@app.route('/download')
def download():
return send_file('static\pdf\cv.pdf', as_attachment=True)
@app.route("/blog")
def blog():
posts=Post.query.all()
return render_template('blog.html',posts=posts)
@app.route("/post", methods=['GET', 'POST'])
def post():
form = PostForm()
if form.validate_on_submit():
post = Post(title=form.title.data, content=form.content.data, author_id=current_user.id)
db.session.add(post)
db.session.commit()
flash('Success')
return redirect(url_for('blog'))
return render_template('post.html', title='New Post', form=form, legend='New Post')
@app.route("/post/update/<int:post_id>", methods=['GET', 'POST'])
def update_post(post_id):
post = Post.query.get_or_404(post_id)
if not post.author_id == current_user.id:
abort(403)
form = PostForm()
if form.validate_on_submit():
post.title = form.title.data
post.content = form.content.data
db.session.commit()
flash("Your post has been updated successfully!")
return redirect(url_for('post', post_id=post.id))
elif not request.method != 'GET':
form.title.data = post.title
form.content.data = post.content
return render_template('post.html', title='Update Post', form=form, legend='Update Post')
@app.route("/post/delete/<int:post_id>", methods=['GET', 'POST'])
def delete_post(post_id):
post = Post.query.get_or_404(post_id)
if not post.author_id == current_user.id:
abort(403)
db.session.delete(post)
db.session.commit()
flash("Your post has been deleted successfully",'success')
return redirect(url_for('home'))
@app.route("/account", methods=['GET', 'POST'])
def account():
form = UpdateAccountForm()
if form.validate_on_submit():
current_user.username = form.username.data
current_user.email = form.email.data
db.session.commit()
flash('Your account has been updated!')
return redirect(url_for('account'))
elif request.method == 'GET':
form.username.data = current_user.username
form.email.data = current_user.email
return render_template('account.html', title='Account', form=form)
@app.route("/register",methods=['GET','POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data, password=form.password.data)
db.session.add(user)
db.session.commit()
flash('Registration successful!')
return redirect(url_for('login'))
return render_template('register.html',title='Register',form=form)
@app.route("/registered")
def registered():
return render_template('registered.html', title='Thanks!')
@app.route("/login",methods=['GET','POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and (user.password, form.password.data):
login_user(user)
flash('You\'ve successfully logged in,'+' '+ current_user.username +'!')
return redirect(url_for('home'))
else:
flash('Invalid username or password.')
return render_template('login.html',title='Login', form=form)
@app.route("/logout")
def logout():
logout_user()
flash('You\'re now logged out. Thanks for your visit!')
return redirect(url_for('home'))
blog/static/img/portrait.jpg

607 KiB

File added
/*styling for the navigation bar*/
.nav-bar {
display: flex;
background-color: #000000;
justify-content: space-around;
width: 100%;
}
.nav-bar > li:hover {
background-color: rgb(170, 197, 14);
}
.nav-bar > li {
display: inline-flex;
padding: 25px;
}
.nav-bar > li > a {
color: white;
text-decoration: none;
font-size: medium;
}
/*formatting the site consistently*/
* {
padding: 0;
}
html {
font-size: 20px;
font-family: Arial, Helvetica, sans-serif;
color: black;
width: 100%;
}
body {
margin: 0 auto;
min-height: 100vh;
}
main {
padding:5vh;
}
/*formatting most of the text in the site*/
p, h1, h4, #portfolio {
text-indent: 10px;
padding: 10px;
}
h1 {
text-align: center;
}
/*formatting the buttons on the cv and blog pages*/
.button {
background-color: rgb(170, 197, 14);
border: none;
display: flex;
color: white;
margin-left: 20px;
margin-top: 50px;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display:inline-flex;
font-size: 16px;
}
.blogbutton {
background-color: rgb(170, 197, 14);
border: none;
float: left;
margin-left: 20px;
display: flex;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display:inline-flex;
font-size: 16px;
}
/*formatting the social media links on the home page*/
.social_media {
margin:20px;
text-align: center;
padding: 20px;
}
/*formatting the picture on the home page*/
.portrait_box {
display: flex;
float: left;
}
#portrait {
width: 250px;
margin: 20px;
border-radius: 50px;
}
/*formatting the posts on the blog*/
.post_title{
font-size: 28px;
}
.post_date {
font-size: 16px;
}
.post_content {
font-size: 22px;
}
.post {
text-align: center;
}
.account_username {
text-align: center;
}
.account_email {
padding-left: 20px;
}
#ptitle {
font-size: 28px;
}
#pcompleted {
font-size: 16px;
}
#pdescription {
font-size: 22px;
}
#psub {
text-align: center;
}
.postupdate {
float: right;
}
\ No newline at end of file
{% extends "layout.html" %}
{% block content %}
<div style="text-align:center">
<h2 class="account_username">{{ current_user.username }}</h2>
<p class="account_email">{{ current_user.email }}</p>
</div>
<div class="content-section">
<form method="POST" action="{{ url_for('account') }}">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.username.label(class="form-control-label") }}
{{ form.username(class="form-control") }}
{% if form.username.errors %}
<div class="alert alert-danger">
{% for error in form.username.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
<div class="form-group">
{{ form.email.label(class="form-control-label") }}
{{ form.email(class="form-control") }}
{% if form.email.errors %}
<div class="alert alert-danger">
{% for error in form.email.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
<div class="form-group">
{{ form.password.label(class="form-control-label") }}
{{ form.password(class="form-control") }}
{% if form.password.errors %}
<div class="alert alert-danger">
{% for error in form.password.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
</div>
{% endblock content %}
\ No newline at end of file
{% extends "admin/master.html" %}
{% block body %}
{% if current_user.is_admin %}
Welcome to the admin panel {{ current_user.username }}!
<a href="{{ url_for('home') }}" class="header">Are you finished?</a>
{% else %}
Hello, please login as an admin before accessing this panel &nbsp|<a href="{{ url_for('login') }}">Login&nbsp;</a>
{% endif %}
{% endblock %}
{% extends "layout.html" %}
{% block content %}
<h1> The Discussion Board </h1>
{% if current_user.is_authenticated %}
<a href="{{ url_for('post') }}" class="blogbutton">Create a Post!</a>
{% else %}
<h4> Not signed in? To contribute, either register or login!</h4>
{% endif %}
{% for post in posts %}
<div class="post">
<br>
<p class="post_title"> <b>{{ post.title }}</b></p>
<p class="post_username">by <i>{{ post.user.username }}</i></p>
<p class="post_date">{{post.date}}</p>
<p class="post_content">{{ post.content }}</p>
</div>
<div>
{% if post.author_id == current_user.id %}
<form action="{{url_for('update_post', post_id=post.id) }}"
method="GET">
<input type="submit" value="Edit">
</form>
<form action="{{ url_for('delete_post', post_id=post.id) }}"
method="POST">
<input type="submit" value="Delete">
</form>
{% endif %}
</div>
{% endfor %}
{% endblock content %}
{% extends "layout.html" %}
{% block content %}
<h1> My Curriculum Vitae </h1>
<h4> Press the button below to download my CV as a PDF. </h4>
<a class="button" href="/download">Download PDF</a>
{% endblock content %}
\ No newline at end of file
{% extends "layout.html" %}
{% block content %}
<h1>My General Experience and Competences</h1>
<p>In this section, I'll be covering different areas of competency or current/ future training -
the kind of languages I'm familiar with and topics researched etc.
</p>
<p>
Hopefully by now, I'm able to say that I'm familiar with <b>HTML</b>, <b>CSS</b>, <b>SQL</b> and <b>PHP</b> (through the GUI with which I manage
MySQL). As has been mentioned in previous sections, the MSc course I'm on is a conversion course, so the
very first languages and methdologies I ever seriously engaged with was HTML/CSS, and website creation is something
I really enjoy. As I've discovered creating this site, it can be far more complicated than that, however,
and the implementation of a <i>fullstack</i> microframework with Flask has been a new and interesting experience.
</p>
<p>
Of course, that's not all that I've learned so far. In particular, I've had plenty of experiene with both <b>Python</b>
and <b>JavaScript</b>, with further training in <b>Java</b> to come. Once I've had it marked, I'll link an example of my engagement
with both of these languages when solving 10 complex problems in both Python and JavaScript in the Portfolio page. Out of the languages
I've so far looked at, I've enjoyed Python the most.
</p>
{% endblock content %}
{% extends "layout.html" %}
{% block content %}
<header>
<h1>A Little Bit About Me</h1>
</header>
<body>
<div class="portrait_box">
<img id="portrait" src="static\img\portrait.jpg" alt="A Picture of Me"/>
</div>
<article>
<p> I'm Harry Hughes, an MSc Computing student at Cardiff University. Currently I'm coming towards
the end of my first semester, so I've created this website to provide an introduction to myself
and the skills that I'd have to offer upon graduating.
</p>
<p> I'm a very driven and open-minded person, with a super wide area of interests; my first
degree was in BA Philosophy from the University of Manchester, for example. When it comes to computing,
my particular interests are in the potential future of the field specifically regarding AI, and the
computer-agent interaction as a whole. While AI isn't a topic explicitly covered in my current degree,
the latter listed interest is through the Social Computing module, which I'm excitedly awaiting beginning.
</p>
<p> Of course, as I'm relatively new to formal computing, there won't yet be many projects listed on this website
(I'll be taking my incredibly rusty first attempts to my grave), but I'll keep this website updated with all
future projects I'll be partaking in. Furthermore, I'll be making use of the <a href="blog">blog</a> on the website, to host interesting
discussions about the field as and when such thoughts arise. I'm hoping it'll be something like a mini-Linkedin.
</p>
<p> Please, feel free to look around the website as you'd like. Anybody interested in contacting me can find me at the
links below, or navigate <a href="cv">here</a> and use my CV to fill in any blanks.
</p>
</article>
</body>
<footer>
<div class="social_media">
<a href="https://git.cardiff.ac.uk/c22053853">GitHub</a></img>
<a href="https://uk.linkedin.com/in/harryihughes">LinkedIn</a></img>
</div>
</footer>
{% endblock content %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
<title>Harry Hughes</title>
</head>
<body>
<nav>
<ul class="nav-bar">
<li><a href="{{ url_for('home') }}" class="header">Home</a>&nbsp</li>
<li><a href="{{ url_for('cv') }}" class="header">CV</a></li>
<li><a href="{{ url_for('experience') }}" class="header">Experience</a></li>
<li><a href="{{ url_for('portfolio') }}" class="header">Portfolio</a></li>
<li><a href="{{ url_for('blog') }}" class="header">Blog</a>&nbsp</li>
{% if current_user.is_admin %}
<li><a href="{{ url_for('admin.index') }}" class="header">Admin</a></li>
{% endif %}
{% if current_user.is_authenticated %}
<li><a href="{{ url_for('account') }}" class="header">Account</a></li>
<li><a href="{{ url_for('logout') }}" class="header">Logout</a></li>
{% else %}
<li><a href="{{ url_for('register') }}" class="header">Register</a></li>
<li><a href="{{ url_for('login') }}" class="header">Login</a></li>
{% endif %}
</ul>
</nav>
<div>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</div>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
{% extends "layout.html" %}
{% block content %}
<form method="POST" action="">
{{ form.csrf_token }}
<p>{{ form.email.label }} {{form.email}}</p>
<p>{{ form.username.label }} {{ form.username }}</p>
<p>{{ form.password.label }} {{ form.password }}</p>
<p><input type="submit" value="Login"></p>
</form>
{% endblock content %}
{% extends "layout.html" %}
{% block content %}
<head>
<h1>My Portfolio</h1>
<h4 id="psub"> <i>This is a collection of my previous work, and will be updated as and when.</i></h4>
</head>
<body>
<ul>
{% for item in items %}
<div class="portfolio">
<li>
<div style="text-align: center">
<h5 id="ptitle"> Title: {{ item.title }} </h5>
<p id="pcompleted"> Completed: {{ item.date_completed }} </p>
<p id="pdescription"> Description: {{ item.description }} </p>
<p id="ptechnologies"> Technologies: {{ item.technologies }} </p>
<p id="pclient"> Client: {{ item.client }} </p>
<a id="plink" href="{{item.link}}"> Link to project</a>
</div>
</li>
</div>
{% endfor %}
</ul>
</body>
{% endblock content %}
\ No newline at end of file
{% 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">{{ legend }}</legend>
<div class="form_group">
{{ form.title.label(class="form-control-label") }}
{% if form.title.errors %}
{{ form.title(class="form-control form-control-lg is-invalid") }}
<div class="invalid_feedback">
{% for error in form.title.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.title(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form_group">
{{ form.content.label(class="form-control-label") }}
{% if form.content.errors %}
{{ form.content(class="form-control form-control-lg is-invalid") }}
<div class="invalid_feedback">
{% for error in form.content.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.content(class="form-control form-control-lg") }}
{% endif %}
</div>
</fieldset>
<div class="form_group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
</div>
{% endblock content %}
<!-- REFERENCE
This code was adapted from a video by C. Shafer. 2018
Accessed: 25-01-2023
https://www.youtube.com/watch?v=u0oDDZrDz9U&list=PL-osiE80TeTs4UjLw5MM6OjgkjFeUxCYH&index=8
-->
\ No newline at end of file
{% extends "layout.html" %}
{% block content %}
<form method="POST" action="{{ url_for('register') }}">
{{ form.csrf_token }}
<p>{{ form.email.label }} {{ form.email }}</p>
<p>{{ form.username.label }} {{ form.username }}</p>
<p>{{ form.password.label }} {{ form.password }}</p>
<input type="submit" value="Register">
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</form>
{% endblock content %}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment