Skip to content

Commit

Permalink
Blog interface
Browse files Browse the repository at this point in the history
  • Loading branch information
greyli committed Aug 26, 2018
1 parent 3bc3d52 commit d4db035
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 5 deletions.
88 changes: 84 additions & 4 deletions bluelog/blueprints/blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,29 @@
:copyright: © 2018 Grey Li <[email protected]>
:license: MIT, see LICENSE for more details.
"""
from flask import render_template, Blueprint
from flask import render_template, flash, redirect, url_for, request, current_app, Blueprint, abort, make_response

from bluelog.emails import send_new_comment_email, send_new_reply_email
from bluelog.extensions import db
from bluelog.forms import CommentForm, AdminCommentForm
from bluelog.models import Post, Category, Comment
from bluelog.utils import redirect_back

blog_bp = Blueprint('blog', __name__)


# skip it
class current_user:
is_authenticated = False


@blog_bp.route('/')
def index():
return render_template('blog/index.html')
page = request.args.get('page', 1, type=int)
per_page = current_app.config['BLUELOG_POST_PER_PAGE']
pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=per_page)
posts = pagination.items
return render_template('blog/index.html', pagination=pagination, posts=posts)


@blog_bp.route('/about')
Expand All @@ -22,9 +37,74 @@ def about():

@blog_bp.route('/category/<int:category_id>')
def show_category(category_id):
return render_template('blog/category.html')
category = Category.query.get_or_404(category_id)
page = request.args.get('page', 1, type=int)
per_page = current_app.config['BLUELOG_POST_PER_PAGE']
pagination = Post.query.with_parent(category).order_by(Post.timestamp.desc()).paginate(page, per_page)
posts = pagination.items
return render_template('blog/category.html', category=category, pagination=pagination, posts=posts)


@blog_bp.route('/post/<int:post_id>', methods=['GET', 'POST'])
def show_post(post_id):
return render_template('blog/post.html')
post = Post.query.get_or_404(post_id)
page = request.args.get('page', 1, type=int)
per_page = current_app.config['BLUELOG_COMMENT_PER_PAGE']
pagination = Comment.query.with_parent(post).filter_by(reviewed=True).order_by(Comment.timestamp.asc()).paginate(
page, per_page)
comments = pagination.items

if current_user.is_authenticated:
form = AdminCommentForm()
form.author.data = current_user.name
form.email.data = current_app.config['BLUELOG_EMAIL']
form.site.data = url_for('.index')
from_admin = True
reviewed = True
else:
form = CommentForm()
from_admin = False
reviewed = False

if form.validate_on_submit():
author = form.author.data
email = form.email.data
site = form.site.data
body = form.body.data
comment = Comment(
author=author, email=email, site=site, body=body,
from_admin=from_admin, post=post, reviewed=reviewed)
replied_id = request.args.get('reply')
if replied_id:
replied_comment = Comment.query.get_or_404(replied_id)
comment.replied = replied_comment
send_new_reply_email(replied_comment)
db.session.add(comment)
db.session.commit()
if current_user.is_authenticated: # send message based on authentication status
flash('Comment published.', 'success')
else:
flash('Thanks, your comment will be published after reviewed.', 'info')
send_new_comment_email(post) # send notification email to admin
return redirect(url_for('.show_post', post_id=post_id))
return render_template('blog/post.html', post=post, pagination=pagination, form=form, comments=comments)


@blog_bp.route('/reply/comment/<int:comment_id>')
def reply_comment(comment_id):
comment = Comment.query.get_or_404(comment_id)
if not comment.post.can_comment:
flash('Comment is disabled.', 'warning')
return redirect(url_for('.show_post', post_id=comment.post.id))
return redirect(
url_for('.show_post', post_id=comment.post_id, reply=comment_id, author=comment.author) + '#comment-form')


@blog_bp.route('/change-theme/<theme_name>')
def change_theme(theme_name):
if theme_name not in current_app.config['BLUELOG_THEMES'].keys():
abort(404)

response = make_response(redirect_back())
response.set_cookie('theme', theme_name, max_age=30 * 24 * 60 * 60)
return response
2 changes: 2 additions & 0 deletions bluelog/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class BaseConfig(object):
BLUELOG_POST_PER_PAGE = 10
BLUELOG_MANAGE_POST_PER_PAGE = 15
BLUELOG_COMMENT_PER_PAGE = 15
# ('theme name', 'display name')
BLUELOG_THEMES = {'perfect_blue': 'Perfect Blue', 'black_swan': 'Black Swan'}


class DevelopmentConfig(BaseConfig):
Expand Down
4 changes: 3 additions & 1 deletion bluelog/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{% block title %}{% endblock title %} - {{ admin.blog_title|default('Blog Title') }}</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/perfect_blue.min.css') }}" type="text/css">
<link rel="stylesheet"
href="{{ url_for('static', filename='css/%s.min.css' % request.cookies.get('theme', 'perfect_blue')) }}"
type="text/css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" type="text/css">
{% endblock head %}
</head>
Expand Down
13 changes: 13 additions & 0 deletions bluelog/templates/blog/_sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,16 @@
</div>
{% endif %}

<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenuButton"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Change Theme
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
{% for theme_name, display_name in config.BLUELOG_THEMES.items() %}
<a class="dropdown-item"
href="{{ url_for('blog.change_theme', theme_name=theme_name, next=request.full_path) }}">
{{ display_name }}</a>
{% endfor %}
</div>
</div>
2 changes: 2 additions & 0 deletions bluelog/templates/blog/category.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ <h1>Category: {{ category.name }}</h1>
</div>
<div class="row">
<div class="col-sm-8">
{% include "blog/_posts.html" %}
<div class="page-footer">{{ render_pagination(pagination) }}</div>
</div>
<div class="col-sm-4 sidebar">
{% include "blog/_sidebar.html" %}
Expand Down
4 changes: 4 additions & 0 deletions bluelog/templates/blog/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ <h4 class="text-muted">&nbsp;{{ admin.blog_sub_title|default('Blog Subtitle') }}
</div>
<div class="row">
<div class="col-sm-8">
{% include 'blog/_posts.html' %}
{% if posts %}
<div class="page-footer">{{ render_pager(pagination) }}</div>
{% endif %}
</div>
<div class="col-sm-4 sidebar">
{% include 'blog/_sidebar.html' %}
Expand Down
108 changes: 108 additions & 0 deletions bluelog/templates/blog/post.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
{% extends 'base.html' %}
{% from 'bootstrap/form.html' import render_form %}
{% from 'bootstrap/pagination.html' import render_pagination %}

{% block title %}{{ post.title }}{% endblock %}

{% block content %}
<div class="page-header">
<h1>{{ post.title }}
<span class="float-right">
</span>
</h1>
<small>
Category: <a
href="{{ url_for('.show_category', category_id=post.category.id) }}">{{ post.category.name }}</a><br>
Date: {{ moment(post.timestamp).format('LL') }}
</small>
</div>
<div class="row">
<div class="col-sm-8">
{{ post.body|safe }}
<hr>
<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target=".postLinkModal">Share
</button>
<div class="modal fade postLinkModal" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel"
aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Permalink</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<input type="text" class="form-control"
value="{{ url_for('.show_post', post_id=post.id, _external=True) }}" readonly>
</div>
</div>
</div>
</div>
</div>
<div class="comments" id="comments">
<h3>{{ comments|length }} Comments
<small>
<a href="{{ url_for('.show_post', post_id=post.id, page=pagination.pages or 1) }}#comments">
latest</a>
</small>
</h3>
{% if comments %}
<ul class="list-group">
{% for comment in comments %}
<li class="list-group-item list-group-item-action flex-column">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">
<a href="{% if comment.site %}{{ comment.site }}{% else %}#{% endif %}"
target="_blank">
{% if comment.from_admin %}
{{ admin.name }}
{% else %}
{{ comment.author }}
{% endif %}
</a>
{% if comment.from_admin %}
<span class="badge badge-primary">Author</span>{% endif %}
{% if comment.replied %}<span class="badge badge-light">Reply</span>{% endif %}
</h5>
<small data-toggle="tooltip" data-placement="top" data-delay="500"
data-timestamp="{{ comment.timestamp.strftime('%Y-%m-%dT%H:%M:%SZ') }}">
{{ moment(comment.timestamp).fromNow() }}
</small>
</div>
{% if comment.replied %}
<p class="alert alert-dark reply-body">{{ comment.replied.author }}:
<br>{{ comment.replied.body }}
</p>
{%- endif -%}
<p class="mb-1">{{ comment.body }}</p>
<div class="float-right">
<a class="btn btn-light btn-sm"
href="{{ url_for('.reply_comment', comment_id=comment.id) }}">Reply</a>
</div>
</li>
{% endfor %}
</ul>
{% else %}
<div class="tip"><h5>No comments.</h5></div>
{% endif %}
</div>
{% if comments %}
{{ render_pagination(pagination, fragment='#comments') }}
{% endif %}
{% if request.args.get('reply') %}
<div class="alert alert-dark">
Reply to <strong>{{ request.args.get('author') }}</strong>:
<a class="float-right" href="{{ url_for('.show_post', post_id=post.id) }}">Cancel</a>
</div>
{% endif %}
<div id="comment-form">
{{ render_form(form, action=request.full_path) }}
</div>
</div>
<div class="col-sm-4 sidebar">
{% include "blog/_sidebar.html" %}
</div>
</div>
{% endblock %}

0 comments on commit d4db035

Please sign in to comment.