diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/StaffProfileDemo.iml b/.idea/StaffProfileDemo.iml new file mode 100644 index 0000000..7eb1baf --- /dev/null +++ b/.idea/StaffProfileDemo.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..92f079a --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f6104af --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..41b3889 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Test/__init__.py b/Test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Test/app_test.py b/Test/app_test.py new file mode 100644 index 0000000..8a37741 --- /dev/null +++ b/Test/app_test.py @@ -0,0 +1,44 @@ +import unittest +from app import app + + +class BasicTestsSetup(unittest.TestCase): + + def setUp(self): + app.config['TESTING'] = True + app.config['WTF_CSRF_ENABLED'] = False + app.config['DEBUG'] = False + self.app = app.test_client() + self.assertEqual(app.debug, False) + + # executed after each test + def tearDown(self): + pass + + +class TestCaseExamples(unittest.TestCase): + + def test_home_status(self): + tester = app.test_client(self) + response = tester.get('/', content_type='html/text') + self.assertEqual(response.status_code, 200) # (test if the page renders and response is correct ) + + def test_home_content(self): + tester = app.test_client(self) + response = tester.get('/', content_type='html/text') + self.assertTrue(b'\n\n\n \n Demo\n' in response.data) # passed the test + + def test_dashboard(self): + tester = app.test_client(self) + response = tester.get('/dashboard', content_type='html/text') + self.assertTrue(b'\n\n \n \n \n' in response.data) # passed the test + + def test_report_id(self): + tester = app.test_client(self) + response = tester.get('/issue/1', content_type='html/text') + self.assertTrue(b'

Issue Details

' in response.data) # passed the test + + + +if __name__ == '__main__': + unittest.main() diff --git a/Test/test_issue.py b/Test/test_issue.py new file mode 100644 index 0000000..b09edc0 --- /dev/null +++ b/Test/test_issue.py @@ -0,0 +1,32 @@ +import unittest +from issue import Issue + + +class TestIssue(unittest.TestCase): + def setUp(self): + self.__issue = Issue() + + def test_issue_has_title(self): + self.__issue.set_title("problem with the bin") + title = self.__issue.get_title() + self.assertEqual(title, "problem with the bin") + + def test_issue_has_type(self): + self.__issue.set_issue_type("bins") + type = self.__issue.get_issue_type() + self.assertEqual(type, "bins") + + def test_issue_has_description(self): + self.__issue.set_description("there is a bin left outside 2 days before collection day") + description = self.__issue.get_description() + self.assertEqual(description, "there is a bin left outside 2 days before collection day") + + def test_issue_has_postcode(self): + self.__issue.set_postcode("CV24EP") + postcode = self.__issue.get_postcode() + self.assertEqual(postcode, "CV24EP") + + def test_issue_has_time(self): + self.__issue.set_time("03/04/2021 21:14") + the_time = self.__issue.get_time() + self.assertEqual(the_time, "03/04/2021 21:14") diff --git a/Test/test_manager.py b/Test/test_manager.py new file mode 100644 index 0000000..cc3596f --- /dev/null +++ b/Test/test_manager.py @@ -0,0 +1,24 @@ +# Currently there is no class manager. In Composite pattern +# the manager is part of "staff". Perhaps, this could grow into a +# separate class on its own + + +# import unittest +# from manager import Manager +# +# +# class TestManager(unittest.TestCase): +# +# def setUp(self): +# print("setup") +# self.__manager = Manager() +# self.__email = "" +# +# +# def tearDown(self): +# print("teardown") +# del self.__manager +# +# +# if __name__ == '__main__': +# unittest.main() diff --git a/Test/test_messageboard.py b/Test/test_messageboard.py new file mode 100644 index 0000000..8d2eda5 --- /dev/null +++ b/Test/test_messageboard.py @@ -0,0 +1,14 @@ +import unittest +from messageboard import MessageController +import datetime + + +class TestMessageController(unittest.TestCase): + def setUp(self): + self.__message_controller = MessageController() + + # MessageController displays message correctly + def test_issue_has_title(self): + message = self.__message_controller.display_message("this is a test message") + now = datetime.datetime.now() + self.assertEqual(message, now.strftime("%Y-%m-%d %H:%M:%S") + " " + "this is a test message") diff --git a/Test/test_staff.py b/Test/test_staff.py new file mode 100644 index 0000000..d3d35bc --- /dev/null +++ b/Test/test_staff.py @@ -0,0 +1,39 @@ +import unittest +from staff import Staff + + +class TestStaff(unittest.TestCase): + + # standard built in method "setUp" for testing + def setUp(self): + self.__user = Staff() + self.__user.set_role("staff") + self.__user.set_email("staff@mail.com") + self.__user.add_manager("manager@mail.com") + + # test if role is correct + def test_get_role(self): + test_result = self.__user.get_role() + self.assertEqual(test_result, "staff") + + # test if email is correct + def test_get_email(self): + test_result = self.__user.get_email() + self.assertEqual(test_result, "staff@mail.com") + + # test that it doesn't have "managers" composite pattern + def test_phone_is_null(self): + # use built in hasattr() to check if attribute + # get_phone exist + test_result = hasattr(self.__user, "get_phone") + self.assertIs(test_result, False) + + # test that it doesn't have "managers" composite pattern + def test_manager_exists(self): + test_result = self.__user.get_managers_email() + self.assertEqual(test_result, ["manager@mail.com"]) + + def test_manager_add(self): + self.__user.add_manager("manager2@mail.com") + test_result = self.__user.get_managers_email() + self.assertEqual(test_result, ["manager@mail.com","manager2@mail.com"]) \ No newline at end of file diff --git a/Test/test_user.py b/Test/test_user.py new file mode 100644 index 0000000..c6f543c --- /dev/null +++ b/Test/test_user.py @@ -0,0 +1,35 @@ +import unittest +from user import User + + +class TestUser(unittest.TestCase): + + # standard built in method "setUp" for testing + def setUp(self): + self.__user = User() + self.__user.set_role("user") + self.__user.set_email("test@mail.com") + self.__user.set_phone("07427730650") + + # test if role is correct + def test_get_role(self): + test_result = self.__user.get_role() + self.assertEqual(test_result, "user") + + # test if email is correct + def test_get_email(self): + test_result = self.__user.get_email() + self.assertEqual(test_result, "test@mail.com") + + # test if phone exists and is correct + def test_phone_exists(self): + test_result = self.__user.get_phone() + self.assertIsNotNone(test_result) + self.assertEqual(test_result, "07427730650") + + # test that it doesn't have "managers" composite pattern + def test_has_not_manager(self): + # use built in hasattr() to check if attribute + # get_managers exist + test_result = hasattr(self.__user, "get_managers") + self.assertIs(test_result, False) \ No newline at end of file diff --git a/Test/test_user_profile.py b/Test/test_user_profile.py new file mode 100644 index 0000000..3fd1092 --- /dev/null +++ b/Test/test_user_profile.py @@ -0,0 +1,36 @@ +import unittest +from user_profile import Profile + + +class TestProfile(unittest.TestCase): + + def setUp(self): + self.__user = Profile() + + # we test if attributes exist + def test_has_get_email(self): + # use built in hasattr() to check if attribute + # get_managers exist + test_result = hasattr(self.__user, "get_email") + self.assertIs(test_result, True) + + # we test if attributes exist + def test_has_set_email(self): + # use built in hasattr() to check if attribute + # get_managers exist + test_result = hasattr(self.__user, "set_email") + self.assertIs(test_result, True) + + # we test if attributes exist + def test_has_get_role(self): + # use built in hasattr() to check if attribute + # get_managers exist + test_result = hasattr(self.__user, "get_role") + self.assertIs(test_result, True) + + # we test if attributes exist + def test_has_get_role(self): + # use built in hasattr() to check if attribute + # get_managers exist + test_result = hasattr(self.__user, "set_role") + self.assertIs(test_result, True) \ No newline at end of file diff --git a/Test/test_userfactory.py b/Test/test_userfactory.py new file mode 100644 index 0000000..9cc0904 --- /dev/null +++ b/Test/test_userfactory.py @@ -0,0 +1,17 @@ +import unittest +from userfactory import UserFactory + + +class TestUserFactory(unittest.TestCase): + def setUp(self): + self.__factory = UserFactory() + + def test_factory_creates_staff(self): + staff = self.__factory.factory("staff") + role = staff.get_role() + self.assertEqual(role, "staff") + + def test_factory_creates_user(self): + staff = self.__factory.factory("user") + role = staff.get_role() + self.assertEqual(role, "user") \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..4d57ce1 --- /dev/null +++ b/app.py @@ -0,0 +1,203 @@ +""" This is the app""" +from flask import Flask, render_template, request, make_response +from flaskext.mysql import MySQL +from pip._vendor import requests +from werkzeug.utils import redirect + +from userfactory import UserFactory +from staff import Staff +from flask_mail import Mail, Message +from datetime import date +import json + +mysql = MySQL() + +# initializing a variable of Flask +app = Flask(__name__, template_folder="templates") + +# MySQL configurations +app.config['MYSQL_DATABASE_USER'] = 'root' +app.config['MYSQL_DATABASE_PASSWORD'] = '' +app.config['MYSQL_DATABASE_DB'] = 'data_staff' +app.config['MYSQL_DATABASE_HOST'] = 'localhost' + +# email set-up +app.config['MAIL_SERVER'] = 'smtp.gmail.com' +app.config['MAIL_PORT'] = 465 +app.config['MAIL_USERNAME'] = 'contact.forkswap@gmail.com' +app.config['MAIL_PASSWORD'] = 'hashedpassword' +app.config['MAIL_USE_TLS'] = False +app.config['MAIL_USE_SSL'] = True + +mysql.init_app(app) +mail = Mail(app) +mail.init_app(app) + +the_list = [] # a list of StaffProject objects + + +@app.route('/') +def landing_page(): + return render_template('index.html') + + +@app.route('/sign-in', methods=['GET', 'POST']) +def sign_in(): + if request.method == 'GET': + return render_template('signin.html') + else: + con = mysql.connect() # set up database connection + cur = con.cursor() + email = request.form['email'] + password = request.form['password'] + + cur.execute('SELECT * FROM users WHERE email=%s AND password=%s', [email, password]) + print("retrieve the data from the database") + rows = cur.fetchall() + con.commit() + + # Group of Four: FACTORY pattern + the_user = UserFactory().factory(rows[0][3]) + + if len(rows) != 0: # necessary check for db non indexed / null values + if the_user.get_role() == "staff": # factory pattern continued + resp = redirect("/dashboard") + resp.set_cookie('loggedInToken', "staff") # instead of staff on main we would have a session token + return resp + elif the_user.get_role() == "user": # factory pattern continued + resp = make_response(render_template('index.html')) + resp.set_cookie('loggedInToken', "user") # instead of user on main we would have a session token + return resp + +@app.route('/dashboard') +def dashboard(): + loggedInToken = request.cookies.get('loggedInToken') + if loggedInToken == "staff": + con = mysql.connect() # set up database connection + cur = con.cursor() + cur.execute('SELECT * FROM issues') + rows = cur.fetchall() + con.commit() + print(rows) + return render_template('dashboard.html', rows=rows) + else: + return render_template('signin.html') + +@app.route('/report-issue') +def report_issue(): + loggedInToken = request.cookies.get('loggedInToken') + if loggedInToken == "user": + return render_template('report.html') + else: + return render_template('signin.html') + + +@app.route('/issue', methods=['POST']) +def issue(): + if request.method == 'POST': + con = mysql.connect() # set up database connection + cur = con.cursor() + title = request.form['title'] + query = request.form['query'] + description = request.form['description'] + postcode = request.form['postcode'] + today = date.today() + + cur.execute('INSERT INTO issues (title, type_of_issue, description, postcode, time, userId)' + 'VALUES( %s, %s, %s, %s, %s, %s)', + (title, query, description, postcode, today, 1)) + con.commit() + con.close() + return render_template('index.html') + +@app.route('/issue/', methods=['GET', 'POST']) +def issue_detailed(id): + if request.method == 'GET': + con = mysql.connect() # set up database connection + cur = con.cursor() + cur.execute('SELECT * FROM issues WHERE id=%s', [id]) + rows = cur.fetchall() + con.commit() + title = rows[0][1] + query = rows[0][2] + description = rows[0][3] + postcode = rows[0][4] + date_var = rows[0][5] + userid = rows[0][6] + solved = rows[0][7] + + # API implementation + location = requests.get('https://geocode.search.hereapi.com/v1/geocode?apikey=9Ps1jjtBfqi8UrDg3V1tpKnAqbdLUI6KqhY3NU062K4&q='+postcode) + location = json.loads(location.text)["items"][0]["title"] + cur.execute('SELECT * FROM users WHERE id=%s', rows[0][6]) + rows = cur.fetchall() + cur.execute('SELECT * FROM messages WHERE issue_id=%s', id) + rows2 = cur.fetchall() + message = '' + if rows2: + message = rows2[0][2] + + staff = Staff() + + # GoF composite pattern ----------------------- + cur.execute('SELECT * FROM managers') + rows3 = cur.fetchall() + manager = Staff() + manager.set_email(rows3[0][1]) + staff.add_manager(manager) + manager_info = staff.get_managers_email() + con.close() + return render_template("report_details.html", title=title, query=query, description=description, location=location, date=date_var, phone=rows[0][4], id=id, solved=solved, userid = userid, messages = message, manager_info = rows3[0][1]) + else: + con = mysql.connect() + cur = con.cursor() + cur.execute('UPDATE issues SET solved=1 WHERE id=%s', (id)) + con.commit() + con.close() + return redirect("/dashboard") + + +@app.route('/delete/', methods=['POST']) +def delete(id): + if request.method == 'POST': + try: + con = mysql.connect() + cur = con.cursor() + cur.execute('DELETE FROM Issues WHERE id=%s', id) + con.commit() + finally: + con.close() + return redirect("/dashboard") + +@app.route('/email//', methods=['POST']) +def email(id, issue): + if request.method == 'POST': + con = mysql.connect() + cur = con.cursor() + emailText = request.form['emailText'] + cur.execute('SELECT * FROM users WHERE id=%s', id) + rows = cur.fetchall() + con.commit() + receiver = rows[0][1] + + # Group of Four: MEDIATOR PATTERN + staff = Staff() + message = staff.send_message(emailText) + + # Add message to db + cur.execute('INSERT INTO messages (issue_id, message)' + 'VALUES( %s, %s)', + (issue, message)) + con.commit() + # email + msg = Message("Update on Council Matter", + sender="contact.forkswap@gmail.com", + recipients=[receiver]) + msg.body = emailText; + mail.send(msg) + con.close() + return redirect("/dashboard") + + +if __name__ == "__main__": + app.run() diff --git a/issue.py b/issue.py new file mode 100644 index 0000000..2f1e672 --- /dev/null +++ b/issue.py @@ -0,0 +1,41 @@ +""" This is the entity, Issue""" + + +class Issue: + + def __init__(self): # a method to create objects + self.__title = "" # private attribute + self.__typeOfIssue = "" # private attribute + self.__description = "" # private attribute + self.__postcode = "" # private attribute + self.__time = "" # private attribute + + def get_title(self): # get method + return self.__title + + def set_title(self, title): # set method + self.__title = title + + def get_issue_type(self): # get method + return self.__typeOfIssue + + def set_issue_type(self, issue): # set method + self.__typeOfIssue = issue + + def get_description(self): # get method + return self.__description + + def set_description(self, description): # set method + self.__description = description + + def get_postcode(self): # get method + return self.__postcode + + def set_postcode(self, postcode): # set method + self.__postcode = postcode + + def get_time(self): # get method + return self.__time + + def set_time(self, time): # set method + self.__time = time diff --git a/messageboard.py b/messageboard.py new file mode 100644 index 0000000..5a4dbad --- /dev/null +++ b/messageboard.py @@ -0,0 +1,12 @@ +""" This is an entity, MessageBoard""" +import datetime + + +# Group of Four: Mediator Pattern +class MessageController(object): # a static class + + @staticmethod + def display_message(text_to_display): # a static method + now = datetime.datetime.now() + displayable_message = now.strftime("%Y-%m-%d %H:%M:%S") + " " + text_to_display + return displayable_message diff --git a/staff.py b/staff.py new file mode 100644 index 0000000..dbcf5ca --- /dev/null +++ b/staff.py @@ -0,0 +1,46 @@ +""" This is the entity, Staff""" +from messageboard import MessageController +from user_profile import Profile + + +class Staff(Profile): + + def __init__(self): # a method to create objects + self.__email = "" + self.__role = "staff" + self.__managers = [] # Group of Four composite pattern + + # Group of Four Composite Pattern + def add_manager(self, manager): + self.__managers.append(manager) + # self.__managers.append(manager) + + def remove_manager(self, manager): + self.__managers.remove(manager) + + def get_managers(self): + return self.__managers + + def get_managers_email(self): + emails = [] + for member in self.__managers: + emails.append(member) + return emails + # ---------------------------------------------------- + + def get_email(self): # get method + return self.__email + + def set_email(self, mail): # set method + self.__email = mail + + def get_role(self): + return self.__role + + def set_role(self, role): + self.__role = role + + # Group of Four: Mediator pattern applied to displayable messages + def send_message(self, message): + text = MessageController.display_message(message) + return text diff --git a/static/images/bin.png b/static/images/bin.png new file mode 100644 index 0000000..6126546 Binary files /dev/null and b/static/images/bin.png differ diff --git a/static/javascript/dashboard.js b/static/javascript/dashboard.js new file mode 100644 index 0000000..89b51e4 --- /dev/null +++ b/static/javascript/dashboard.js @@ -0,0 +1,53 @@ +/* globals Chart:false, feather:false */ + +(function () { + 'use strict' + + feather.replace() + + // Graphs + var ctx = document.getElementById('myChart') + // eslint-disable-next-line no-unused-vars + var myChart = new Chart(ctx, { + type: 'line', + data: { + labels: [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday' + ], + datasets: [{ + data: [ + 1, + 2, + 0, + 0, + 3, + 0, + 5 + ], + lineTension: 0, + backgroundColor: 'transparent', + borderColor: '#007bff', + borderWidth: 4, + pointBackgroundColor: '#007bff' + }] + }, + options: { + scales: { + yAxes: [{ + ticks: { + beginAtZero: false + } + }] + }, + legend: { + display: false + } + } + }) +})() diff --git a/static/styles/dashboard.css b/static/styles/dashboard.css new file mode 100644 index 0000000..8b0fa72 --- /dev/null +++ b/static/styles/dashboard.css @@ -0,0 +1,100 @@ +body { + font-size: .875rem; +} + +.feather { + width: 16px; + height: 16px; + vertical-align: text-bottom; +} + +/* + * Sidebar + */ + +.sidebar { + position: fixed; + top: 0; + /* rtl:raw: + right: 0; + */ + bottom: 0; + /* rtl:remove */ + left: 0; + z-index: 100; /* Behind the navbar */ + padding: 48px 0 0; /* Height of navbar */ + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); +} + +@media (max-width: 767.98px) { + .sidebar { + top: 5rem; + } +} + +.sidebar-sticky { + position: relative; + top: 0; + height: calc(100vh - 48px); + padding-top: .5rem; + overflow-x: hidden; + overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ +} + +.sidebar .nav-link { + font-weight: 500; + color: #333; +} + +.sidebar .nav-link .feather { + margin-right: 4px; + color: #727272; +} + +.sidebar .nav-link.active { + color: #007bff; +} + +.sidebar .nav-link:hover .feather, +.sidebar .nav-link.active .feather { + color: inherit; +} + +.sidebar-heading { + font-size: .75rem; + text-transform: uppercase; +} + +/* + * Navbar + */ + +.navbar-brand { + padding-top: .75rem; + padding-bottom: .75rem; + font-size: 1rem; + background-color: rgba(0, 0, 0, .25); + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); +} + +.navbar .navbar-toggler { + top: .25rem; + right: 1rem; +} + +.navbar .form-control { + padding: .75rem 1rem; + border-width: 0; + border-radius: 0; +} + +.form-control-dark { + color: #fff; + background-color: rgba(255, 255, 255, .1); + border-color: rgba(255, 255, 255, .1); +} + +.form-control-dark:focus { + border-color: transparent; + box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); +} diff --git a/static/styles/signin.css b/static/styles/signin.css new file mode 100644 index 0000000..4732d1f --- /dev/null +++ b/static/styles/signin.css @@ -0,0 +1,39 @@ +html, +body { + height: 100%; +} + +body { + display: flex; + align-items: center; + padding-top: 40px; + padding-bottom: 40px; + background-color: #f5f5f5; +} + +.form-signin { + width: 100%; + max-width: 330px; + padding: 15px; + margin: auto; +} + +.form-signin .checkbox { + font-weight: 400; +} + +.form-signin .form-floating:focus-within { + z-index: 2; +} + +.form-signin input[type="email"] { + margin-bottom: -1px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.form-signin input[type="password"] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} diff --git a/templates/dashboard.html b/templates/dashboard.html new file mode 100644 index 0000000..ac6e70f --- /dev/null +++ b/templates/dashboard.html @@ -0,0 +1,209 @@ + + + + + + + + + Demo + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

Dashboard

+
+
+ + +
+ +
+
+ + + +

Latest Reports

+
+ + + + + + + + + + + + {% for row in rows %} + {% if row[7] == 1 %} + + + + + + + + {% else %} + + + + + + + + {% endif %} + + + {% endfor %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#TypeLocationTimeAction
{{row[0]}} {{row[2]}} {{row[4]}}{{row[5]}} + See report +
{{row[0]}} {{row[2]}} {{row[4]}}{{row[5]}} + See report +
+
+
+
+
+ + + + + + + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..d125fa0 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,113 @@ + + + + + Demo + + + + + + + +
+
+
+
+
+
Waste and recycling
+

Find Bin Collection Day

+

Order bins

+

Request Garden Services

+
+
+ +
+
+
+
+
Planning and Building
+

Apply for Permission

+

Building Control

+

Search for Applications

+
+
+
Your Council
+

Jobs

+

Local Plan

+

Strategies and Plans

+

Your Councillor

+

Pay the Council

+ +
+
+ +

+
+
+
+ +
+
+

Green Energy

+

For Everyone

+
+

+ +

+ We have been providing our citizens with affordable and reliable green energy solutions since our first day. + With the new "Go Green" scheme, everyone can now get green energy. +

+ + +
+ +
+ + +
+ + \ No newline at end of file diff --git a/templates/report.html b/templates/report.html new file mode 100644 index 0000000..0494077 --- /dev/null +++ b/templates/report.html @@ -0,0 +1,102 @@ + + + + + Demo + + + + + + + +
+

Report a council related issue

+

+
+
+
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ + \ No newline at end of file diff --git a/templates/report_details.html b/templates/report_details.html new file mode 100644 index 0000000..f13f65f --- /dev/null +++ b/templates/report_details.html @@ -0,0 +1,126 @@ + + + + + Demo + + + + + + + +
+

Issue Details

+

+
+
+

{{title}}

+ {{query}} +
+
Description:
+

{{description}}

+
+
Location:
+

{{location}}

+
+
Time
+

{{date}}

+ +
+ {% if solved == 1 %} +
+
+ +
+
+ {% else %} +
+
+ +
+
+
+
+ +
+
+

Past Messages

+

{{messages}}

+ +
+

For any enquiries please contact {{manager_info}}

+

+
+ + + {% endif %} + +
+ + +
+ + \ No newline at end of file diff --git a/templates/signin.html b/templates/signin.html new file mode 100644 index 0000000..8213ce7 --- /dev/null +++ b/templates/signin.html @@ -0,0 +1,65 @@ + + + + + + + + + Demo + + + + + + + + + + + + + + +
+
+

Local Council

+

Please sign in

+ +
+ + +
+
+ + +
+ +
+ +
+ +

© 2017–2021

+
+
+ + + + + diff --git a/user.py b/user.py new file mode 100644 index 0000000..985fa7b --- /dev/null +++ b/user.py @@ -0,0 +1,30 @@ +""" This is the entity, Staff""" +from user_profile import Profile + + +class User (Profile): + + def __init__(self): # a method to create objects + self.__email = "" + self.__role = "user" + self.__phone = "" + + def get_email(self): # get method + return self.__email + + def set_email(self, mail): # set method + self.__email = mail + + # part of GoF: Factory + def get_phone(self): + return self.__phone + + def set_phone(self, phone): + self.__phone = phone + # ----------------------- + + def get_role(self): # get method + return self.__role + + def set_role(self, role): # set method + self.__role = role diff --git a/user_profile.py b/user_profile.py new file mode 100644 index 0000000..789f6a4 --- /dev/null +++ b/user_profile.py @@ -0,0 +1,21 @@ +""" This is the interface, Profile""" + + +class Profile: + + def __init__(self): # a method to create objects + self._email = "" + self._role = "" + + def get_email(self): # get method + pass + + def set_email(self, email): # set method + pass + + def get_role(self): # get method + pass + + def set_role(self, role): # set method + pass + diff --git a/userfactory.py b/userfactory.py new file mode 100644 index 0000000..e6f9108 --- /dev/null +++ b/userfactory.py @@ -0,0 +1,20 @@ +""" ProfileFacotry""" +from user import User +from staff import Staff + + +class UserFactory: + # FACTORY class + # Group of Four: FACTORY METHOD + + @staticmethod + def factory(role): + if role is not None: + if role.lower() == "staff": + return Staff() + elif role.lower() == "user": + return User() + else: + return None + +