Skip to content
Snippets Groups Projects
Commit cc17cdd6 authored by Aydin, Mehmet Can (PG/T - Comp Sci & Elec Eng)'s avatar Aydin, Mehmet Can (PG/T - Comp Sci & Elec Eng)
Browse files

Merge branch 'feat/frontend-design' into 'main'

Modified docker files, config files and frontend pages.

See merge request !28
parents c22d0999 bf8eed6f
No related branches found
No related tags found
1 merge request!28Modified docker files, config files and frontend pages.
Showing
with 286 additions and 107 deletions
......@@ -17,4 +17,4 @@ RUN pip3 install -r requirements.txt
COPY . /frontend
CMD [ "./wait-for-it.sh", "db:3306", "--timeout=0" ,"--","python3", "-m", "flask", "run", "--host=0.0.0.0", "-p 5003"]
\ No newline at end of file
CMD [ "./wait-for-it.sh", "user-db:3306", "--timeout=0" ,"--","python3", "run.py"]
\ No newline at end of file
# application/__init__.py
from flask import Flask
from os import environ
import os
from dotenv import load_dotenv
from flask_login import LoginManager
from flask_ckeditor import CKEditor
login_manager = LoginManager()
app = None
def create_app():
global app
if app is not None:
return app
app = Flask(__name__)
# Load environment variables
load_dotenv()
ckeditor = CKEditor(app)
ckeditor.FormatSource = False
app.config['SECRET_KEY'] = '3834j2724827'
environment_configuration = os.environ['CONFIGURATION_SETUP']
app.config.from_object(environment_configuration)
print(app.config)
login_manager.init_app(app)
......
# application/frontend/api/PostClient.py
import requests
from flask import session, request
from application import app
class PostClient:
post_service = app.config['POST_SERVICE']
def get_posts():
url = 'http://localhost:5002/api/posts'
url = 'http://' + PostClient.post_service + '/api/posts'
response = requests.request(method="GET", url=url)
if response.status_code == 404:
......@@ -16,7 +20,7 @@ class PostClient:
return response
def get_post(post_id):
url = 'http://localhost:5002/api/' + str(post_id)
url = 'http://' + PostClient.post_service + '/api/' + str(post_id)
response = requests.request(method="GET", url=url)
if response.status_code == 404:
......@@ -27,7 +31,7 @@ class PostClient:
return response
def get_comment(post_id, comment_id):
url = 'http://localhost:5002/api/' + str(post_id) + '/' + str(comment_id)
url = 'http://' + PostClient.post_service + '/api/' + str(post_id) + '/' + str(comment_id)
response = requests.request(method="GET", url=url)
if response.status_code == 404:
......@@ -42,7 +46,7 @@ class PostClient:
payload = {'title':form.title.data, 'category':form.category.data,
'content':form.content.data, 'user_api':session['user_api_key']}
url = 'http://localhost:5002/api/new-post'
url = 'http://' + PostClient.post_service + '/api/new-post'
response = requests.request(method="POST", url=url, data=payload)
if response:
......@@ -50,7 +54,7 @@ class PostClient:
def delete_post(post_id):
url = 'http://localhost:5002/api/' + str(post_id) + '/delete'
url = 'http://'+ PostClient.post_service + '/api/' + str(post_id) + '/delete'
response = requests.request(method="POST", url=url)
if response:
......@@ -60,7 +64,7 @@ class PostClient:
payload = {'content':form.content.data, 'user_api':session['user_api_key'],
'post_id':post_id}
url = 'http://localhost:5002/api/new-comment'
url = 'http://' + PostClient.post_service + '/api/new-comment'
response = requests.request(method="POST", url=url, data=payload)
if response:
......@@ -68,7 +72,7 @@ class PostClient:
def delete_comment(post_id,comment_id):
url = 'http://localhost:5002/api/' + str(post_id) + '/' + str(comment_id) + '/delete'
url = 'http://' + PostClient.post_service + '/api/' + str(post_id) + '/' + str(comment_id) + '/delete'
response = requests.request(method="POST", url=url)
if response:
......
# application/frontend/api/UserClient.py
import requests
from flask import session, request
from application import app
class UserClient:
user_service = app.config['USER_SERVICE']
@staticmethod
def get_user():
headers = {
'Authorization': 'Basic ' + session['user_api_key']
}
url = 'http://localhost:5001/api/user'
url = 'http://' + UserClient.user_service + '/api/user'
response = requests.request(method="GET", url=url, headers=headers)
if response.status_code == 401:
return False
......@@ -18,14 +21,14 @@ class UserClient:
@staticmethod
def does_exist(email):
url = 'http://localhost:5001/api/user/' + email + '/exists'
url = 'http://' + UserClient.user_service + '/' + email + '/exists'
response = requests.request("GET", url=url)
return response.status_code == 200
@staticmethod
def post_user_create(form):
user = False
payload = {
user = False
payload = {
'email': form.email.data,
'password': form.password.data,
'first_name': form.first_name.data,
......@@ -34,12 +37,12 @@ class UserClient:
'uni_number': form.uni_number.data,
'user_role': form.user_role.data
}
url = 'http://localhost:5001/api/user/create'
response = requests.request("POST", url=url, data=payload)
url = 'http://' + UserClient.user_service +'/api/user/create'
response = requests.request("POST", url=url, data=payload)
if response:
user = response.json()
return user
if response:
user = response.json()
return user
@staticmethod
def post_login(form):
......@@ -47,14 +50,14 @@ class UserClient:
payload = {'email': form.email.data,
'password': form.password.data}
url = 'http://localhost:5001/api/user/login'
url = 'http://'+ UserClient.user_service +'/api/user/login'
response = requests.request("POST", url=url, data=payload)
if response:
d = response.json()
print("This is response from user api: " + str(d))
if d['api_key'] is not None:
api_key = d['api_key']
api_key = d['api_key']
return api_key
return None
......@@ -65,7 +68,7 @@ class UserClient:
'Authorization': 'Basic ' + session['user_api_key']
}
url = 'http://localhost:5001/api/user/logout'
url = 'http://' + UserClient.user_service + '/api/user/logout'
response = requests.request("POST", url=url, headers=headers)
return response
\ No newline at end of file
......@@ -92,6 +92,7 @@ def get_posts():
categories = []
posts = PostClient.get_posts()
user = UserClient.get_user()
for post in posts:
categories.append(post['category'])
categories = sorted(set(categories))
......@@ -100,7 +101,7 @@ def get_posts():
return render_template('forum/index.html')
return render_template('forum/index.html',
posts=posts, categories=categories)
posts=posts, user=user, categories=categories)
@frontend_blueprint.route('/category/<category>', methods=['GET'])
def categories(category = None):
......@@ -109,6 +110,7 @@ def categories(category = None):
category_posts = []
posts = PostClient.get_posts()
user = UserClient.get_user()
for post in posts:
if post['category'] == category:
category_posts.append(post)
......@@ -117,13 +119,13 @@ def categories(category = None):
return redirect(url_for('frontend.get_posts'))
return render_template('forum/index.html',
posts=category_posts, category=category)
posts=category_posts, user=user, category=category)
@frontend_blueprint.route('/post/new', methods=['GET','POST'])
def create_post():
if len(session)<4:
return redirect(url_for('frontend.login_route'))
user = UserClient.get_user()
form = forms.CreatePostForm(request.form)
if request.method == "POST":
if form.validate_on_submit():
......@@ -139,7 +141,7 @@ def create_post():
'form': form,
'post': None
}
return render_template('forum/create_post.html', **content)
return render_template('forum/create_post.html',user=user, **content)
@frontend_blueprint.route('/post/<int:post_id>', methods=['GET','POST'])
......
.h7 {
font-size: 0.8rem;
}
.gedf-wrapper {
margin-top: 0.97rem;
}
@media (min-width: 992px) {
.gedf-main {
padding-left: 4rem;
padding-right: 4rem;
}
.gedf-card {
margin-bottom: 2.77rem;
}
}
/**Reset Bootstrap*/
.dropdown-toggle::after {
content: none;
}
\ No newline at end of file
<div>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul>
{% for category, message in messages %}
<li class="{{ category }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</div>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %} {% endblock %}</title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<link rel="stylesheet" href="../../static/index.css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
crossorigin="anonymous"></script>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
{% extends "base.html" %}
{% block content %}
{% include 'navbar.html' %}
{% include '_messages.html' %}
<div class="container-fluid gedf-wrapper">
<div class="row">
{% include 'sidebar.html' %}
{% block pageContent %} {% endblock %}
</div>
</div>
{% endblock %}
\ No newline at end of file
{# application/templates/forum/create_post.html #}
{% extends "base_col_1.html"%}
{% from 'macros.html' import displayField %}
{% block title %}Create Post{% endblock %}
{% block content %}
{% block pageContent %}
<div>
{% with messages = get_flashed_messages(with_categories=true) %}
......@@ -18,8 +20,8 @@
{% endwith %}
</div>
<h1>{{ page_title }} Post</h1>
<div class="col-md-6 gedf-main">
<div class="card gedf-card">
<form class="post__form" action="" method="POST">
{{ displayField(form.title, 'Enter post title') }}
......@@ -36,13 +38,17 @@
</select>
{{ displayField(form.content, 'Type content here') }}
<button class="btn btn--solid post-btn" aria-label="Create" type="submit">CREATE</button>
<a class="btn btn--cancel" href="{{ url_for('frontend.get_posts') }}">CANCEL</a>
<button class="btn btn-primary" aria-label="Create" type="submit">CREATE</button>
<a class="btn btn-danger" href="{{ url_for('frontend.get_posts') }}">CANCEL</a>
{{ form.csrf_token }}
</form>
</form>
</div>
</div>
{{ ckeditor.load(pkg_type="basic") }}
{{ ckeditor.config(name='content') }}
......
<div>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul>
{% for category, message in messages %}
<li class="{{ category }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</div>
<div>
<h1>
<a class="btn btn--link" href="{{ url_for('frontend.get_posts') }}">Home</a>
{% extends "base_col_1.html" %}
{% block title %} Home Page {% endblock %}
<a class="btn btn--link" href="{{ url_for('frontend.create_post') }}">New Post</a>
{% block pageContent%}
<a class="btn btn--link" href="{{ url_for('frontend.logout') }}">Logout</a>
<div>
</div>
<!-- Categories -->
<section class="index-categories">
<h1>
<div class="categories">
<ul class="category-menu">
{% for category in categories %}
<li class="tile__category">
<a class="btn btn--link" href="{{ url_for('frontend.categories', category=category) }}">{{category}}</a>
</li>
{% endfor %}
</ul>
</div>
</section>
<!-- END -->
<section>
<h1>
{{category}}
</section>
<!-- Posts -->
<article class="index-tiles row">
{% for post in posts %}
<div class="tile tile--wide">
<div class="col-md-6 gedf-main">
<div class="card gedf-card">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="posts-tab" data-toggle="tab" href="#posts" role="tab" aria-controls="posts" aria-selected="true">Start a discussion</a>
</li>
<li class="nav-item">
<a class="nav-link" id="images-tab" data-toggle="tab" role="tab" aria-controls="images" aria-selected="false" href="#images">Images</a>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="posts" role="tabpanel" aria-labelledby="posts-tab">
<div class="form-group">
<label class="sr-only" for="message">post</label>
<a class="btn btn--link" href="{{ url_for('frontend.create_post') }}">New Post</a>
</div>
</div>
<div class="tab-pane fade" id="images" role="tabpanel" aria-labelledby="images-tab">
<div class="form-group">
<div class="custom-file">
<input type="file" class="custom-file-input" id="customFile">
<label class="custom-file-label" for="customFile">Upload image</label>
</div>
</div>
<div class="py-4"></div>
</div>
</div>
<div class="tile__content">
</div>
</div>
{% for post in posts %}
<div class="card gedf-card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex justify-content-between align-items-center">
<div class="mr-2">
<img class="rounded-circle" width="45" src="https://picsum.photos/50/50" alt="">
</div>
<div class="ml-2">
<div class="h5 m-0">@{{ post['user_name']}}</div>
<div class="h7 text-muted">{{ post['user_name']}}</div>
</div>
</div>
<div>
<div class="dropdown">
<button class="btn btn-link dropdown-toggle" type="button" id="gedf-drop1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="gedf-drop1">
<div class="h6 dropdown-header">Configuration</div>
<a class="dropdown-item" href="#">Save</a>
<a class="dropdown-item" href="#">Hide</a>
<a class="dropdown-item" href="#">Report</a>
</div>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="text-muted h7 mb-2"> <i class="fa fa-clock-o"></i>{{ post['date_added']}}</div>
<a class="card-link" href="{{ url_for('frontend.display_post', post_id=post.id) }}">
<h5 class="card-title">{{ post['title'] }}</h5>
</a>
<p class="card-text">{{ post.content | safe }}</p>
</div>
<div class="card-footer">
<a href="#" class="card-link"><i class="fa fa-comment"></i> Comment</a>
</div>
</div>
{% endfor %}
</div>
<header class="tile__header">
<h2 class="tile__title"><a href="{{ url_for('frontend.display_post', post_id=post.id) }}">{{ post['title'] }}</a></h2>
<span class="tile__username">{{ post['user_name']}}</span>
<span class="tile__date">{{ post['date_added']}}</span>
</header>
<div class="tile__text">
<p>{{ post.content | safe }}</p>
</div>
{% endblock %}
</div>
</div>
{% endfor %}
</article>
<!-- END -->
\ No newline at end of file
<nav class="navbar navbar-light bg-white">
<div class="container-fluid">
<ul class="nav navbar-nav">
<li><a href="{{ url_for('frontend.get_posts') }}" class="navbar-brand">SurreySocial</a></li>
</ul>
<ul class="nav navbar-nav pull-right">
<li><a class="btn btn--link" href="{{ url_for('frontend.logout') }}">Logout</a></li>
</ul>
</div>
</nav>
<div class="col-md-3">
<div class="card">
<div class="card-body">
<div class="h5">{{user['result'].full_name}}</div>
<div class="h7 text-muted">{{user['result'].email}}</div>
<div class="h7">{{user['result'].user_role}} at University of Surrey
</div>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<div class="h6 text-muted">Categories</div>
<ul class="category-menu">
<p class="title__category">{{category}}</p>
{% for category in categories %}
<li class="tile__category">
<a class="btn btn--link" href="{{ url_for('frontend.categories', category=category) }}">{{category}}</a>
</li>
{% endfor %}
</ul>
</li>
</ul>
</div>
</div>
\ No newline at end of file
import os
from dotenv import load_dotenv
dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
if os.path.exists(dotenv_path):
load_dotenv(dotenv_path)
class Config:
SECRET_KEY = "3834j2724827"
class DevelopmentConfig(Config):
ENV = "development"
DEBUG = True
POST_SERVICE = "localhost:5002"
USER_SERVICE = "localhost:5001"
class ProductionConfig(Config):
ENV = "Production"
DEBUG = True
POST_SERVICE = "post-service:5002"
USER_SERVICE = "user-service:5001"
\ No newline at end of file
......@@ -5,7 +5,8 @@ services:
context: .
dockerfile: Dockerfile
ports:
- 5003:5003
- "5003:5003"
restart: always
volumes:
- .:/frontend
networks:
......
......@@ -23,6 +23,7 @@ Jinja2==3.1.2
MarkupSafe==2.1.2
marshmallow==3.19.0
passlib==1.7.4
password-strength==0.0.3.post2
protobuf==4.22.1
pycparser==2.21
python-dateutil==2.8.2
......
......@@ -16,4 +16,4 @@ RUN pip3 install -r requirements.txt
COPY . /post-service
CMD [ "./wait-for-it.sh", "db:3306", "--timeout=0" ,"--","python3", "-m", "flask", "run", "--host=0.0.0.0", "-p 5002"]
CMD [ "./wait-for-it.sh", "user-db:3306", "--timeout=0" ,"--","python3", "run.py"]
......@@ -2,21 +2,22 @@
import config
import os
from flask import Flask
from dotenv import load_dotenv
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
login_manager = LoginManager()
def create_app():
app = Flask(__name__)
# environment_configuration = os.environ['CONFIGURATION_SETUP']
# app.config.from_object(environment_configuration)
app.config.from_object(config.DevelopmentConfig)
# Load environment variables
load_dotenv()
environment_configuration = os.environ['CONFIGURATION_SETUP']
app.config.from_object(environment_configuration)
db.init_app(app)
# login_manager.init_app(app)
with app.app_context():
# Register blueprints
......
......@@ -16,12 +16,11 @@ class DevelopmentConfig(Config):
ENV = "development"
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///posts-service.db'
# SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://post-service:pass1234@host.docker.internal:3306/post_dev'
SQLALCHEMY_ECHO = True
class ProductionConfig(Config):
ENV = "production"
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://post-service:pass1234@db:3306/post'
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://post-service:pass1234@post-db:3306/post'
SQLALCHEMY_ECHO = False
......@@ -7,15 +7,15 @@ services:
context: .
dockerfile: Dockerfile
ports:
- 5002:5002
- "5002:5002"
volumes:
- .:/post-service
depends_on:
- db
- post-db
networks:
- service-network
db:
post-db:
image: mysql
restart: always
environment:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment