From b74ea26cfc1ff5389ebdb0b7d1cf9eaad34d0e63 Mon Sep 17 00:00:00 2001
From: b4-sharp <Bradley2.Sharp@live.uwe.ac.uk>
Date: Mon, 13 Mar 2023 11:54:49 +0000
Subject: [PATCH] Fix merge

---
 store/forms.py                                |   2 +-
 store/models.py                               |  94 ++++-
 store/routes.py                               | 336 +++++++++++++++++-
 store/static/main.css                         |  18 +-
 store/static/oldmain.css                      |  69 ++++
 store/templates/base.html                     |  65 ++--
 store/templates/login.html                    |   5 -
 store/templates/userContent/ChangeEmail.html  |  28 ++
 .../templates/userContent/ChangePhNumber.html |  28 ++
 .../templates/userContent/ChangeUsername.html |  28 ++
 store/templates/userContent/account.html      |   9 +
 .../templates/userContent/accountDetails.html |  40 +++
 store/templates/userContent/admin.html        |   9 +
 store/templates/userContent/login.html        |  28 ++
 store/templates/userContent/register.html     |  38 ++
 .../templates/userContent/reset_password.html |  21 ++
 .../userContent/reset_password_confirm.html   |  26 ++
 .../userContent/reset_security1.html          |  21 ++
 store/templates/userContent/user.html         |   9 +
 store/templates/userContent/verify_code.html  |  21 ++
 .../userContent/verify_code_security1.html    |  21 ++
 .../verify_code_security1_confirm.html        |  26 ++
 store/utility.py                              |  50 ++-
 unit_tests.py                                 |  18 +-
 24 files changed, 965 insertions(+), 45 deletions(-)
 create mode 100644 store/static/oldmain.css
 delete mode 100644 store/templates/login.html
 create mode 100644 store/templates/userContent/ChangeEmail.html
 create mode 100644 store/templates/userContent/ChangePhNumber.html
 create mode 100644 store/templates/userContent/ChangeUsername.html
 create mode 100644 store/templates/userContent/account.html
 create mode 100644 store/templates/userContent/accountDetails.html
 create mode 100644 store/templates/userContent/admin.html
 create mode 100644 store/templates/userContent/login.html
 create mode 100644 store/templates/userContent/register.html
 create mode 100644 store/templates/userContent/reset_password.html
 create mode 100644 store/templates/userContent/reset_password_confirm.html
 create mode 100644 store/templates/userContent/reset_security1.html
 create mode 100644 store/templates/userContent/user.html
 create mode 100644 store/templates/userContent/verify_code.html
 create mode 100644 store/templates/userContent/verify_code_security1.html
 create mode 100644 store/templates/userContent/verify_code_security1_confirm.html

diff --git a/store/forms.py b/store/forms.py
index ecef864..712ad60 100644
--- a/store/forms.py
+++ b/store/forms.py
@@ -1,4 +1,4 @@
 import wtforms
 from flask_wtf import FlaskForm
 from wtforms import StringField # Basic example.
-from wtforms.validators import DataRequired # Basic example.
\ No newline at end of file
+from wtforms.validators import DataRequired # Basic example.
diff --git a/store/models.py b/store/models.py
index d291958..b88e0e3 100644
--- a/store/models.py
+++ b/store/models.py
@@ -1,5 +1,10 @@
 # https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/
+
+#from flask import current_app
 from store import db
+from flask_login import UserMixin
+from werkzeug.security import generate_password_hash, check_password_hash
+
 
 # Helper tables for many to many relationships, see https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/#many-to-many-relationships.
 items = db.Table('Items',
@@ -40,4 +45,91 @@ class ItemSet(db.Model):
         backref=db.backref('ItemSets', lazy=True))
     
     def __repr__(self):
-        return f"id: {self.id}, description: {self.description}, items: {self.items}"
\ No newline at end of file
+        return f"id: {self.id}, description: {self.description}, items: {self.items}"
+    
+# database for user register it will be added more cullomns in the future
+# that is a basic implementation to check if it works
+# Freddy implemented that
+#UserMixin is to inherit flask-login implementetion
+class User( db.Model, UserMixin):
+    user_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
+    username = db.Column(db.String(256), nullable=False, unique=True)
+    email = db.Column(db.String(256), nullable=False)
+    phone_number = db.Column(db.String(20), nullable=False)
+    password_hash = db.Column(db.String(256), nullable=False)
+    securityQ1 = db.Column(db.String(30), nullable=False)
+    userType = db.Column(db.String(20), default="standard")
+    
+
+    @classmethod
+    def create_user(cls, username: str, password: str,email: str , phone_number: str, securityQ1 : str ) :
+        password_hash = generate_password_hash(password)
+        user = cls(username=username, password_hash= password_hash, email=email, phone_number=phone_number, securityQ1 = securityQ1)
+        db.session.add(user)
+        db.session.commit()
+        return user
+    
+    @classmethod
+    def update_passwords(cls, user_id: int, password: str):
+        user = cls.query.get(user_id)
+        password_hash = generate_password_hash(password)
+        user.password_hash = password_hash
+        db.session.commit()
+
+    @classmethod
+    def update_security_q1(cls, user_id: int, securityQ1: str):
+        user = cls.query.get(user_id)
+        user.securityQ1 = securityQ1
+        db.session.commit()
+    
+    @classmethod
+    def update_username(cls, user_id: int, username: str):
+        user = cls.query.get(user_id)
+        user.username = username
+        db.session.commit()
+
+
+    @classmethod
+    def update_email(cls, user_id: int, email: str):
+        user = cls.query.get(user_id)
+        user.email = email
+        db.session.commit()
+
+    @classmethod
+    def update_Number(cls, user_id: int, phone_number: str):
+        user = cls.query.get(user_id)
+        user.email = phone_number
+        db.session.commit()
+
+    def is_active(self) -> bool:
+        return True 
+    
+
+    def get_userDetails(self):
+        lis = [self.username, self.email, self.phone_number]
+        return lis
+    
+
+    def get_id(self):
+        return str(self.user_id)
+    
+    def check_password(self, password: str) -> bool:
+        return check_password_hash(self.password_hash, password)
+    
+    def securityverification(self, securityQ1: str) -> bool:
+        if self.securityQ1 == securityQ1:
+            return True
+        else:
+            return False
+        
+    def checkIfUserExist(self, username: str) -> bool:
+        if self.username == username:
+            return True
+        else:
+            return False
+        
+
+    
+
+    def __repr__(self) -> str:
+        return f"User(user_id={self.user_id}, username='{self.username}')"
\ No newline at end of file
diff --git a/store/routes.py b/store/routes.py
index f68c1b4..5525a60 100644
--- a/store/routes.py
+++ b/store/routes.py
@@ -1,13 +1,53 @@
 from store import app, db
-from flask import render_template
+from flask import render_template, request, flash, redirect, url_for, Flask, session
 from store.utility import *
 
+# Official flask-login doc free liecense
+#https://flask-login.readthedocs.io/en/latest/
+from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
+
+#Official flask-mail docum
+#https://pythonhosted.org/Flask-Mail/
+from flask_mail import Mail, Message
+
+
+
+#Email configuration
+app.config['MAIL_SERVER']='smtp.gmail.com'
+app.config['MAIL_PORT'] = 465
+app.config['MAIL_USERNAME'] = 'antique.store7111@gmail.com'
+app.config['MAIL_PASSWORD'] = 'nbouhrtaurcefgvj'
+app.config['MAIL_USE_TLS'] = False
+app.config['MAIL_USE_SSL'] = True
+
+mail = Mail(app)
+
+
+#Create an instance of the LoginManager class and initialise 
+#it with your Flask application to begin using Flask-Login.
+login_manager = LoginManager()
+login_manager.init_app(app)
+login_manager.login_view = 'login'
+
+
+
+@login_manager.user_loader
+def load_user(user_id):
+    return User.query.get(int(user_id))
+
+def get_user_id():
+    if current_user.is_authenticated:
+        return current_user.user_id
+    else:
+        return None
+ 
 @app.route("/")
 @app.route("/index")
 def index():
     return render_template('index.html', title='Home') # If the title is unspecified then a default is used that is set in base.html
 
 @app.route("/basket")
+@login_required
 def basket():
     return render_template('basket.html', title='Basket')
 
@@ -19,6 +59,296 @@ def items():
 def itemSets():
     return render_template('itemSets.html', title='Item Sets')
 
-@app.route("/login")
+ 
+
+
+@app.route("/register", methods=['POST', 'GET'])
+def register():
+    if request.method == "POST":
+        error = None # errors      
+        username = request.form['username']
+        password = request.form['password']
+        securityQ1 = request.form['securityQ1']
+        email = request.form['email']
+        phone_number = request.form['phone_number']
+        #user_exists = User.query.filter_by(username=username).first()
+        if User.checkIfUserExist(User, username):
+            error = 'The username you chose is already taken.'
+            return render_template('userContent/register.html', title='Register', error=error)
+        else:
+            new_user = User.create_user(username=username, password=password, email = email, phone_number = phone_number,securityQ1 = securityQ1)
+            flash('Your account has been created! You are now able to log in.', 'success')
+            return redirect(url_for('index'))
+    return render_template('userContent/register.html', title='Register')   
+
+    
+@app.route("/login", methods=['POST', 'GET'])
 def login():
-    return render_template('login.html', title='Login')
\ No newline at end of file
+    if request.method == "POST":
+        username = request.form['username']
+        password = request.form['password']
+        securityQ1 = request.form['securityQ1']
+
+        user = User.query.filter_by(username=username).first()
+        if user and user.check_password(password):
+            if user.securityverification(securityQ1) == True:
+                login_user(user)
+                print(current_user.userType)
+                return redirect(url_for('index'))
+            else:
+                flash('Invalid security answer')
+        else:
+            flash('Login unsuccessful. Please check username and password.')
+    return render_template('userContent/login.html', title='Login')
+
+
+@app.route('/logout')
+@login_required
+def logout():
+    logout_user()
+    return redirect(url_for('index'))
+
+
+
+
+
+
+
+
+
+
+
+@app.route('/reset_password', methods=['GET', 'POST'])
+def reset_password():
+    if request.method == 'POST':
+        email = request.form['email']
+        print("the email was :", email)
+        user = User.query.filter_by(email=email).first()
+        if user:
+            verification_code =  getcode()
+            session['verification_code'] = verification_code
+            session['user_id'] = user.user_id
+            msg = Message('Password Reset Verification Code', sender='your-email@gmail.com', recipients=[email])
+            msg.body = f"Hello, Your password reset verification code is {verification_code}"
+            mail.send(msg)
+            flash('A verification code has been sent to your email')
+            return redirect(url_for('verify_code'))
+        else:
+            flash('Invalid email address')
+    return render_template('userContent/reset_password.html')
+
+@app.route('/verify_code', methods=['GET', 'POST'])
+def verify_code():
+    if 'user_id' not in session or 'verification_code' not in session:
+        return redirect(url_for('reset_password'))
+    if request.method == 'POST':
+        verification_code = request.form['verification_code']
+        if str(verification_code) == session['verification_code']:
+            session.pop('verification_code', None)
+            return redirect(url_for('reset_password_confirm'))
+        else:
+            flash('Invalid verification code')
+    return render_template('userContent/verify_code.html')
+ 
+
+
+
+@app.route('/reset_password_confirm', methods=['GET', 'POST'])
+def reset_password_confirm():
+    if 'user_id' not in session:
+        return redirect(url_for('reset_password'))
+    user_id = session['user_id']
+    if request.method == 'POST':
+        password = request.form['password']
+        confirm_password = request.form['confirm_password']
+        if password == confirm_password:
+            User.update_passwords(user_id, password)
+            session.pop('user_id', None)
+            flash('Your password has been successfully reset')
+            return redirect(url_for('login'))
+        else:
+            flash('Passwords do not match')
+    return render_template('userContent/reset_password_confirm.html')
+
+
+
+
+def getcode():
+    randomchar = [str(random.choice(string.ascii_letters)) + str(random.randint(10,99)) for _ in range(4)]
+    randomdString = ""
+    for i in range(0, 4):
+        randomdString += randomchar[i % 4]
+
+    return randomdString
+
+
+
+
+@app.route('/reset_security1', methods=['GET', 'POST'])
+def reset_security1():
+    if request.method == 'POST':
+        email = request.form['email']
+        print("the email was :", email)
+        user = User.query.filter_by(email=email).first()
+        if user:
+            verification_code =  getcode()
+            session['verification_code'] = verification_code
+            session['user_id'] = user.user_id
+            msg = Message('security answer, Reset Verification Code', sender='your-email@gmail.com', recipients=[email])
+            msg.body = f"Hello, Your security answer reset verification code is {verification_code}"
+            mail.send(msg)
+            flash('A verification code has been sent to your email')
+            return redirect(url_for('verify_code_security1'))
+        else:
+            flash('Invalid email address')
+    return render_template('userContent/reset_security1.html')
+
+@app.route('/verify_code_security1', methods=['GET', 'POST'])
+def verify_code_security1():
+    if 'user_id' not in session or 'verification_code' not in session:
+        return redirect(url_for('verify_code_security1'))
+    if request.method == 'POST':
+        verification_code = request.form['verification_code']
+        if str(verification_code) == session['verification_code']:
+            session.pop('verification_code', None)
+            return redirect(url_for('verify_code_security1_confirm'))
+        else:
+            flash('Invalid verification code')
+    return render_template('userContent/verify_code_security1.html')
+ 
+
+
+
+@app.route('/verify_code_security1_confirm', methods=['GET', 'POST'])
+def verify_code_security1_confirm():
+    if 'user_id' not in session:
+        return redirect(url_for('reset_security1'))
+    user_id = session['user_id']
+    if request.method == 'POST':
+        securityQ1 = request.form['securityQ1']
+        confirm_securityQ1 = request.form['confirm_securityQ1']
+        if securityQ1 == confirm_securityQ1:
+            User.update_security_q1(user_id, securityQ1)
+            session.pop('user_id', None)
+            flash('Your security question has been successfully reset')
+            return redirect(url_for('login'))
+        else:
+            flash('security question do not match')
+    return render_template('userContent/verify_code_security1_confirm.html')
+
+
+
+@app.route("/account")
+@login_required
+def account():
+    if current_user.userType == 'standard':
+        return redirect(url_for('standardUser'))
+    elif current_user.userType == 'admin':
+        return redirect(url_for('admin'))
+    else:
+        flash('Unauthorized access please contact us on antique.store7111@gmail.com')
+        return redirect(url_for('index')) 
+    
+
+
+    
+@app.route("/accountDetails")
+@login_required
+def accountDetails():
+    a = get_user_id()
+    user = User.query.filter_by(user_id = a).first()
+    return render_template('userContent/accountDetails.html', user=user)
+
+
+
+@app.route("/standardUser")
+@login_required
+def standardUser():
+    if current_user.userType != 'standard':
+        flash('Unauthorized access no admins allowed please create a standard account')
+        return redirect(url_for('home')) 
+    else:
+        return render_template('userContent/user.html') 
+
+
+
+
+@app.route("/admin")
+@login_required
+def admin():
+    if current_user.userType != 'admin':
+        flash('Unauthorized access')
+        return redirect(url_for('home')) 
+    else:
+        return render_template('userContent/admin.html') 
+    
+@app.route("/ChangeUsername/", methods=['GET', 'POST'])
+@login_required
+def ChangeUsername():
+
+    if request.method == 'POST':
+        user_id = current_user.user_id
+        password = request.form['password']
+        securityQ1 = request.form['securityQ1']
+        NewUsername = request.form['NewUsername']
+        user = User.query.get(user_id)
+        if user and user.check_password(password):
+        #if User.check_password(user_id, password):
+            if user.securityverification(securityQ1) == True:
+                User.update_username(user_id, NewUsername)
+                flash('username successfully changed.')
+            
+            else:
+                flash('Invalid security answer')
+        else:
+            flash('Wrong password.')
+    
+    return render_template('userContent/ChangeUsername.html') 
+    
+    
+
+@app.route("/ChangeEmail/", methods=['GET', 'POST'])
+@login_required
+def ChangeEmail():
+
+    if request.method == 'POST':
+        user_id = current_user.user_id
+        password = request.form['password']
+        securityQ1 = request.form['securityQ1']
+        NewEmail = request.form['NewEmail']
+        user = User.query.get(user_id)
+        if user and user.check_password(password):
+        #if User.check_password(user_id, password):
+            if user.securityverification(securityQ1) == True:
+                User.update_email(user_id, NewEmail)
+                flash('email successfully changed.')
+            
+            else:
+                flash('Invalid security answer')
+        else:
+            flash('Wrong password.')
+    
+    return render_template('userContent/ChangeEmail.html') 
+
+@app.route("/ChangePhNumber/", methods=['GET', 'POST'])
+@login_required
+def ChangePhNumber():
+
+    if request.method == 'POST':
+        user_id = current_user.user_id
+        password = request.form['password']
+        securityQ1 = request.form['securityQ1']
+        NewNumber = request.form['NewNumber']
+        user = User.query.get(user_id)
+        if user and user.check_password(password):
+        #if User.check_password(user_id, password):
+            if user.securityverification(securityQ1) == True:
+                User.update_Number(user_id, NewNumber)
+                flash('New Number successfully changed.')
+            
+            else:
+                flash('Invalid security answer')
+        else:
+            flash('Wrong password.')
+    
+    return render_template('userContent/ChangePhNumber.html') 
\ No newline at end of file
diff --git a/store/static/main.css b/store/static/main.css
index e2369d1..6782b0d 100644
--- a/store/static/main.css
+++ b/store/static/main.css
@@ -72,7 +72,7 @@ div{
     width:100%;
 }
 
-li a {
+.navbar li a {
     color:white;
     display: block;
     text-align: center;
@@ -80,7 +80,7 @@ li a {
     padding: 14px 16px;
 }
 
-ul {
+.navbar ul {
     list-style-type: none;
     margin: 0;
     padding: 0;
@@ -98,11 +98,11 @@ input[type=text] {
     font-size: 17px;
 }
 
-li {
+.navbar li {
     float:left;
 }
 
-li a:hover {
+.navbar li a:hover {
     background-color: white;
     color:black;
 }
@@ -114,4 +114,14 @@ li a:hover {
 
 h1{
     color: black;
+    font-size: 30px;
 }
+
+.error{
+    text-decoration: none;
+    color:red;
+    font-size: 30px;
+}
+
+
+
diff --git a/store/static/oldmain.css b/store/static/oldmain.css
new file mode 100644
index 0000000..5a6d56f
--- /dev/null
+++ b/store/static/oldmain.css
@@ -0,0 +1,69 @@
+body {
+    background-color: white;
+}
+
+footer {
+    background-color: black;
+    color: white;
+    position: fixed;
+    bottom:0;
+    left:0;
+    width:100%;
+}
+
+div{
+    position:fixed;
+    left:0;
+    width:100%;
+}
+
+.navbar li a {
+    color:white;
+    display: block;
+    text-align: center;
+    text-decoration: none;
+    padding: 14px 16px;
+}
+
+.navbar ul {
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+    overflow: hidden;
+    background-color: black;
+}
+
+
+input[type=text] {
+    float: left;
+    padding: 6px;
+    border: none;
+    margin-top: 8px;
+    margin-right: 16px;
+    font-size: 17px;
+}
+
+.navbar li {
+    float:left;
+}
+
+.navbar li a:hover {
+    background-color: white;
+    color:black;
+}
+
+*{
+    text-align: center;
+    font-family: sans-serif;
+}
+
+h1{
+    color: black;
+    font-size: 30px;
+}
+
+.error{
+    text-decoration: none;
+    color:red;
+    font-size: 30px;
+}
\ No newline at end of file
diff --git a/store/templates/base.html b/store/templates/base.html
index ad2955a..fd45e13 100644
--- a/store/templates/base.html
+++ b/store/templates/base.html
@@ -3,33 +3,58 @@
 <head>
   <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
   <title>{% block title %}{% endblock%}</title>
-  <link rel="stylesheet" type="text/css" href="../static/main.css">  <!-- Load the CSS. -->
+  <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='main.css') }}">  <!-- Load the CSS. -->
 </head>
 
 <body>
-    <header>
-    <h1>ANTIQUES ONLINE</h1>
+    <header class="header">
+      <a class="logo" href="{{ url_for('index')}}">ANTIQUES ONLINE</a>
     </header>
 
-  <div>
-    <ul>
-      <li><a href="{{ url_for('basket')}}">Basket</a></li>
-      <li><a href="{{ url_for('items')}}">Items</a></li>
-      <li><a href="{{ url_for('itemSets')}}">Item Sets</a></li>
-      <li><a href="{{ url_for('login')}}">Login</a></li>
+    <nav class="navbar">
+      <ul class="navbar-list">
+        <li><a href="{{ url_for('basket')}}">Basket</a></li>
+        <li><a href="{{ url_for('items')}}">Items</a></li>
+        <li><a href="{{ url_for('itemSets')}}">Item Sets</a></li>
+        
+        {% if current_user.is_authenticated %}
+          <li><a href="{{ url_for('account')}}">Account</a></li>
+          <li><a href="{{ url_for('logout')}}">Logout</a></li>
+          <li><a class="welcome">Welcome, {{ current_user.username }}!</a></li>  
+       {% else %}
+          <li><a href="{{ url_for('login')}}">Login</a></li>
+          <li><a href="{{ url_for('register')}}">Register</a></li>
+        {% endif %}
+        
+        <li class="search">
+          <form>
+            <button type="submit"><i class="fa fa-search"></i></button>
+            <input type="text" placeholder="Search...">
+          </form>
+        </li>
+      </ul>
+    </nav>
+    
+    <div class="container">
+      {% with messages = get_flashed_messages() %}
+        {% if messages %}
+          <ul class="flashes">
+            {% for message in messages %}
+              <li class="error">{{ message }}</li>
+            {% endfor %}
+          </ul>
+        {% endif %}
+      {% endwith %}
       
-      <input type="text" placeholder="Search...">
-    </ul>
-  </div>
-  
-  {% block content %}
-  
-  {% endblock %} <!-- Where HTML will go when extended. -->
-  
-  <footer>
-    <p>Contact Info: mail@mail.com
+      {% block content %}
+      
+      {% endblock %} <!-- Where HTML will go when extended. -->
+    </div>
+
+    <footer class="footer">
+      <p>Contact Info: mail@mail.com
         <br>
         Phone Number 0000 000 0000</p>
-  </footer>
+    </footer>
 </body>
 </html>
diff --git a/store/templates/login.html b/store/templates/login.html
deleted file mode 100644
index ecb8f69..0000000
--- a/store/templates/login.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{%extends 'base.html' %}
-
-{% block content %}
-    {% block title %} Login | Antiques Online {% endblock %}
-{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/ChangeEmail.html b/store/templates/userContent/ChangeEmail.html
new file mode 100644
index 0000000..db4e042
--- /dev/null
+++ b/store/templates/userContent/ChangeEmail.html
@@ -0,0 +1,28 @@
+
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} Reset code {% endblock %}
+
+    
+<form method="POST" action="{{ url_for('ChangeEmail') }}" style="float: center; text-align: center;">
+
+    <div class="container">
+      <h1>Change E-mail</h1>
+  
+      <label for="password"><b>Password verification</b></label>
+      <input type="password" placeholder="Enter Password" name="password" id="password" required>
+
+        
+      <label for="securityQ1"><b>what is your favourite colour, for verification porpuses/b></label>
+      <input type="securityQ1" placeholder="Enter a colour" name="securityQ1" id="securityQ1" required>
+
+        <label for="NewEmail"><b>New E-mail</b></label>
+      <input type="NewEmail" placeholder="Enter new E-mail" name="NewEmail" id="NewEmail" required>
+
+       <input class="button" type="submit" value="Change E-mail" > 
+
+     </div>
+ 
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/ChangePhNumber.html b/store/templates/userContent/ChangePhNumber.html
new file mode 100644
index 0000000..ec7cf88
--- /dev/null
+++ b/store/templates/userContent/ChangePhNumber.html
@@ -0,0 +1,28 @@
+
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} Reset code {% endblock %}
+
+    
+<form method="POST" action="{{ url_for('ChangePhNumber') }}" style="float: center; text-align: center;">
+
+    <div class="container">
+      <h1>Change Number</h1>
+  
+      <label for="password"><b>Password verification</b></label>
+      <input type="password" placeholder="Enter Password" name="password" id="password" required>
+
+        
+      <label for="securityQ1"><b>what is your favourite colour, for verification porpuses/b></label>
+      <input type="securityQ1" placeholder="Enter a colour" name="securityQ1" id="securityQ1" required>
+
+        <label for="NewNumber"><b> Enter New Number</b></label>
+      <input type="NewNumber" placeholder="Enter new Number" name="NewNumber" id="NewNumber" required>
+
+       <input class="button" type="submit" value="Change Number" > 
+
+     </div>
+ 
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/ChangeUsername.html b/store/templates/userContent/ChangeUsername.html
new file mode 100644
index 0000000..b2799c2
--- /dev/null
+++ b/store/templates/userContent/ChangeUsername.html
@@ -0,0 +1,28 @@
+
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} Reset code {% endblock %}
+
+    
+<form method="POST" action="{{ url_for('ChangeUsername') }}" style="float: center; text-align: center;">
+
+    <div class="container">
+      <h1>Change Username</h1>
+  
+      <label for="password"><b>Password verification</b></label>
+      <input type="password" placeholder="Enter Password" name="password" id="password" required>
+
+        
+      <label for="securityQ1"><b>what is your favourite colour, for verification porpuses/b></label>
+      <input type="securityQ1" placeholder="Enter a colour" name="securityQ1" id="securityQ1" required>
+
+        <label for="NewUsername"><b>New username</b></label>
+      <input type="NewUsername" placeholder="Enter new Username" name="NewUsername" id="NewUsername" required>
+
+       <input class="button" type="submit" value="Change username" > 
+
+     </div>
+ 
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/account.html b/store/templates/userContent/account.html
new file mode 100644
index 0000000..f341255
--- /dev/null
+++ b/store/templates/userContent/account.html
@@ -0,0 +1,9 @@
+{%extends 'base.html' %}
+
+{% block content %}
+    {% block title %} Account{% endblock %}
+    <h1>account Information</h1>
+    <ul>
+        <li><a href="{{ url_for('accountDetails', user_id=current_user.id)}}">View my Account details</a></li> 
+    </ul>
+{% endblock %}
diff --git a/store/templates/userContent/accountDetails.html b/store/templates/userContent/accountDetails.html
new file mode 100644
index 0000000..b0a4082
--- /dev/null
+++ b/store/templates/userContent/accountDetails.html
@@ -0,0 +1,40 @@
+{%extends 'base.html' %}
+
+{% block content %}
+
+
+<h1>Account Details</h1>
+<h1>Welcome, {{ user.username }}</h1>
+<table style="width:100%">
+    <tr>
+        <th>Your username is:</th>
+        <th>{{ user.username }}</th>
+        <th><a href="{{ url_for('ChangeUsername')}}">change your username</a></th>
+
+    </tr>
+    <tr>
+      <td>Your email address is:</td>
+      <td>{{ user.email }}</td>
+      <td><a href="{{ url_for('ChangeEmail')}}">Change email address</a></td>      
+    </tr>
+    <tr>  
+      <th>Your Phone Number is:</th>
+      <td>{{ user.phone_number }}</td>
+      <td><a href="{{ url_for('ChangePhNumber')}}">change phone number</a></td>
+    </tr>
+  </table>
+    
+{% endblock %}
+
+
+
+
+<!--
+  {% block title %} Account{% endblock %}
+  <h1>Account Details</h1>
+  <h1>Welcome, {{ user.username }}</h1>
+  <p>Your email address is: {{ user.email }}</p>
+  <p>Your Phone Number is: {{ user.phone_number }}</p>
+
+
+  -->
\ No newline at end of file
diff --git a/store/templates/userContent/admin.html b/store/templates/userContent/admin.html
new file mode 100644
index 0000000..7b4ed58
--- /dev/null
+++ b/store/templates/userContent/admin.html
@@ -0,0 +1,9 @@
+{%extends 'base.html' %}
+
+{% block content %}
+    {% block title %} Account{% endblock %}
+    <h1>Admin usertype account Information</h1>
+    <ul>
+        <li><a href="{{ url_for('accountDetails', user_id=current_user.id)}}">View my Account details</a></li> 
+    </ul>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/login.html b/store/templates/userContent/login.html
new file mode 100644
index 0000000..1513de5
--- /dev/null
+++ b/store/templates/userContent/login.html
@@ -0,0 +1,28 @@
+
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} login | Antiques Online {% endblock %}
+
+    
+<form method="POST" action="{{ url_for('login') }}" style="float: center; text-align: center;">
+
+    <div class="container">
+      <h1>Login</h1>
+  
+      <label for="username"><b>username</b></label>
+      <input type="username" placeholder="Enter username" name="username" id="username" required>
+  
+      <label for="password"><b>Password</b></label>
+      <input type="password" placeholder="Enter Password" name="password" id="password" required>
+      <label for="securityQ1"><b>what is your favourite colour</b></label>
+      <input type="securityQ1" placeholder="what is your favourite colour" name="securityQ1" id="securityQ1" required>
+
+      <a href="{{ url_for('reset_password')}}">Forgot my Password</a>
+      <a href="{{ url_for('reset_security1')}}">Forgot my favourite color</a>
+       <input class="button" type="submit" value="Login" > 
+
+     </div>
+ 
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/register.html b/store/templates/userContent/register.html
new file mode 100644
index 0000000..c813b3c
--- /dev/null
+++ b/store/templates/userContent/register.html
@@ -0,0 +1,38 @@
+
+
+  {%extends 'base.html' %}
+{% block content %}
+    {% block title %} Register | Antiques Online {% endblock %}
+
+    
+<form method="POST" action="{{ url_for('register') }}" style="float: center; text-align: center;">
+
+    <div class="container">
+      
+      <h1>Register</h1>
+     
+      {% if error %}
+        <p class=error><strong>Error:</strong> {{ error }}
+     {% endif %}
+  
+      <label for="username"><b>username</b></label>
+      <input type="username" placeholder="Enter username" name="username" id="username" required>
+
+      <label for="email"><b>E-mail</b></label>
+      <input type="email" placeholder="Enter E-mail" name="email" id="email" required>
+
+      <label for="phone_number"><b>Phone Number</b></label>
+      <input type="phone_number" placeholder="Enter Number" name="phone_number" id="phone_number" required>
+  
+      <label for="securityQ1"><b>what is your favourite colour</b></label>
+      <input type="securityQ1" placeholder="Enter a colour" name="securityQ1" id="securityQ1" required>
+
+      <label for="password"><b>Password</b></label>
+      <input type="password" placeholder="Enter Password" name="password" id="password" required>
+  
+       <input class="button" type="submit" value="Register" > 
+
+     </div>
+ 
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/reset_password.html b/store/templates/userContent/reset_password.html
new file mode 100644
index 0000000..74f003d
--- /dev/null
+++ b/store/templates/userContent/reset_password.html
@@ -0,0 +1,21 @@
+
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} Reset code {% endblock %}
+
+    
+<form method="POST" action="{{ url_for('reset_password') }}" style="float: center; text-align: center;">
+
+    <div class="container">
+      <h1>email verify</h1>
+  
+      <label for="email"><b>Enter your email</b></label>
+      <input type="email" placeholder="Enter your email" name="email" id="email" required>
+
+       <input class="button" type="submit" value="Reset Password" > 
+
+     </div>
+ 
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/reset_password_confirm.html b/store/templates/userContent/reset_password_confirm.html
new file mode 100644
index 0000000..72ece7e
--- /dev/null
+++ b/store/templates/userContent/reset_password_confirm.html
@@ -0,0 +1,26 @@
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} Verify reset Password {% endblock %}
+
+    
+    <form method="POST" action="{{ url_for('reset_password_confirm') }}" style="float: center; text-align: center;">
+
+      <div class="container">
+        
+        <h1>Reset Password</h1>
+      
+    
+        <label for="password"><b>Password</b></label>
+        <input type="password" placeholder="Enter Password" name="password" id="password" required>
+
+            
+        <label for="confirm_password"><b>confirm password</b></label>
+        <input type="confirm_password" placeholder="confirm password" name="confirm_password" id="confirm_password" required>
+
+         <input class="button" type="submit" value="confirm password" > 
+  
+       </div>
+   
+    </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/reset_security1.html b/store/templates/userContent/reset_security1.html
new file mode 100644
index 0000000..0e723fe
--- /dev/null
+++ b/store/templates/userContent/reset_security1.html
@@ -0,0 +1,21 @@
+
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} Reset code {% endblock %}
+
+    
+<form method="POST" action="{{ url_for('reset_security1') }}" style="float: center; text-align: center;">
+
+    <div class="container">
+      <h1>email verify</h1>
+  
+      <label for="email"><b>Enter your email</b></label>
+      <input type="email" placeholder="Enter your email" name="email" id="email" required>
+
+       <input class="button" type="submit" value="Reset security answer" > 
+
+     </div>
+ 
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/user.html b/store/templates/userContent/user.html
new file mode 100644
index 0000000..d0bdc29
--- /dev/null
+++ b/store/templates/userContent/user.html
@@ -0,0 +1,9 @@
+{%extends 'base.html' %}
+
+{% block content %}
+    {% block title %} Account{% endblock %}
+    <h1>Standard usertype account Information</h1>
+    <ul>
+        <li><a href="{{ url_for('accountDetails', user_id=current_user.id)}}">View my Account details</a></li> 
+    </ul>
+{% endblock %}
diff --git a/store/templates/userContent/verify_code.html b/store/templates/userContent/verify_code.html
new file mode 100644
index 0000000..8022e30
--- /dev/null
+++ b/store/templates/userContent/verify_code.html
@@ -0,0 +1,21 @@
+
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} Verify reset Password {% endblock %}
+
+    
+<form method="POST" action="{{ url_for('verify_code') }}" style="float: center; text-align: center;">
+
+    <div class="container">
+      <h1>Login</h1>
+  
+      <label for="verification_code"><b>Enter your code </b></label>
+      <input type="verification_code" placeholder="Enter your code " name="verification_code" id="verification_code" required>
+
+       <input class="button" type="submit" value="Reset Password" > 
+
+     </div>
+ 
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/verify_code_security1.html b/store/templates/userContent/verify_code_security1.html
new file mode 100644
index 0000000..094a2fc
--- /dev/null
+++ b/store/templates/userContent/verify_code_security1.html
@@ -0,0 +1,21 @@
+
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} Verify reset Password {% endblock %}
+
+    
+<form method="POST" action="{{ url_for('verify_code_security1') }}" style="float: center; text-align: center;">
+
+    <div class="container">
+      <h1>Reset security answer</h1>
+  
+      <label for="verification_code"><b>Enter your code </b></label>
+      <input type="verification_code" placeholder="Enter your code " name="verification_code" id="verification_code" required>
+
+       <input class="button" type="submit" value="Reset security answer" > 
+
+     </div>
+ 
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/verify_code_security1_confirm.html b/store/templates/userContent/verify_code_security1_confirm.html
new file mode 100644
index 0000000..dc526cd
--- /dev/null
+++ b/store/templates/userContent/verify_code_security1_confirm.html
@@ -0,0 +1,26 @@
+
+{%extends 'base.html' %}
+{% block content %}
+    {% block title %} Verify reset Password {% endblock %}
+
+    
+    <form method="POST" action="{{ url_for('verify_code_security1_confirm') }}" style="float: center; text-align: center;">
+
+      <div class="container">
+        
+        <h1>Reset security question</h1>
+      
+    
+        <label for="securityQ1"><b>what is your favourite colour</b></label>
+        <input type="securityQ1" placeholder="Enter a colour" name="securityQ1" id="securityQ1" required>
+
+            
+        <label for="confirm_securityQ1"><b>confirm answer</b></label>
+        <input type="confirm_securityQ1" placeholder="confirm answer" name="confirm_securityQ1" id="confirm_securityQ1" required>
+
+         <input class="button" type="submit" value="confirm password" > 
+  
+       </div>
+   
+    </form>
+{% endblock %}
\ No newline at end of file
diff --git a/store/utility.py b/store/utility.py
index 27029b6..6d97f9d 100644
--- a/store/utility.py
+++ b/store/utility.py
@@ -1,7 +1,11 @@
 # TODO: Search for similiarly named item to replace removed item from itemset.
+
 from store.models import *
 from sqlalchemy import select
-from store import db
+from store import *
+import random
+import string # for autegenarating letters
+
 # Difference between filter and filter_by: https://stackoverflow.com/a/31560897
 def get_unsold_items():
     return Item.query.filter_by(date_sold=None).all()
@@ -9,14 +13,28 @@ def get_unsold_items():
 def get_sold_items():
     return Item.query.filter(Item.date_sold.isnot(None)).all()
 
-def get_all_items():
-    return Item.query().all()
+def get_items():
+    return Item.query.all()
 
 def get_item_sets():
     return ItemSet.query.all()
 
-def add_similar_item_to_set(item):
-    pass
+from difflib import SequenceMatcher
+
+# Search the description of all items to find similar.
+# This is intended for use in replacing items in an items, 
+# and works best when description is close to the target.
+# As a result it does not return sold items.
+def get_similar_items(description):
+    to_search = get_items()
+    found = []
+    for descriptable in to_search:
+        # This relies on the fact both Item and Items sets have a description column.
+        if (SequenceMatcher(None, description.lower(), descriptable.description.lower()).ratio() > 0.4 # This ratio comparison needs to be fine tuned.
+        and descriptable.date_sold == None):
+            found.append(descriptable)
+
+    return found
 
 def remove_item(item):
     add_similar_item_to_set(item)
@@ -25,9 +43,19 @@ def remove_item(item):
     
 
 def remove_item_by_id(item_id):
-    add_similar_item_to_set()# TODO: Need to get Item object to pass to add similar item to set
+    add_similar_item_to_set() # TODO: Need to get Item object to pass to add similar item to set
     db.session.Item.query()
 
+# Search desciption for matching substring.
+# This is most useful for a user keyword search. 
+def get_by_keyword(substring):
+    to_search = get_items() + get_item_sets()
+    found = []
+    for descriptable in to_search:
+        if substring.lower() in descriptable.description.lower():
+            found.append(descriptable)
+    return found
+
 def get_itemsets_by_item_id(item_id):
     item_sets = get_item_sets()
     item_set_contained_id = []
@@ -37,6 +65,12 @@ def get_itemsets_by_item_id(item_id):
                 item_set_contained_id.append(item_set)
     return item_set_contained_id
 
+    # Alternate approach where items_sets are retrieved from queries, but are not in the desired format.
+    # item_sets = select(ItemSet).where(ItemSet.items.any(Item.id==item_id))
+    # flask_item_sets =  db.session.execute(item_sets).all()
+    # flask_item_set = flask_item_sets[0][0]
 
-    
-    
\ No newline at end of file
+def add_item(description, price, date_sold=None):
+    item = Item(description=description,price=price,date_sold=date_sold)
+    db.session.add(item)
+    db.session.commit()
\ No newline at end of file
diff --git a/unit_tests.py b/unit_tests.py
index 04d006c..35245b1 100644
--- a/unit_tests.py
+++ b/unit_tests.py
@@ -34,10 +34,22 @@ class TestUtility(unittest.TestCase):
         self.assertEqual(contains_itemset == True, True)
         self.assertEqual(contains_itemset2 == True, True)
 
-
-        
+    def test_get_by_keyword(self):
+        results = get_by_keyword("vase")
+        self.assertEqual(len(results) > 0, True)
     
+    def test_get_similar_items(self):
+        results = get_similar_items("Chinese Porcelaine Vases set")
+        is_search_too_wide = any("chinese" not in descriptable.description.lower() for descriptable in results)
+
+        self.assertEqual(len(results) > 0 and not is_search_too_wide, True)
+
+    def add_item_to_database(self):
+        item = ["Vase with golden trimming", 12]
+        add_item(item[0],item[1])
+        added_item = Item.query.filter_by(description = "Vase with golden trimming").all()
+        self.assertEqual(item[0], added_item.description)
 
 if __name__ == "__main__":
     with app.app_context():
-        unittest.main()
\ No newline at end of file
+        unittest.main()
-- 
GitLab