Commit 8230e835 authored by Evert Prants's avatar Evert Prants

Boards, Replies and Votes

parent 22ca7de9
# Episodes.Community - Community-Driven TV Show Episode Link Sharing Site
# Copyright (C) 2017 Evert "Diamond" Prants <evert@lunasqu.ee>, Taizo "Tsa6" Simpson <taizo@tsa6.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from django import forms
from LandingPage.models import DiscussionBoard, DiscussionReply
class BoardForm(forms.ModelForm):
body = forms.CharField(widget=forms.Textarea)
class Meta():
model = DiscussionBoard
fields = ('title','body',)
help_texts = {
'title': 'Name of the board',
'body': 'Enter your message here'
}
class ReplyForm(forms.ModelForm):
class Meta():
model = DiscussionReply
fields = ('body',)
help_texts = {
'body': 'Enter your message here'
}
{% extends "base.html" %}
{% block title %}
{{board.title}} - {{show.name}} Discussions - Episodes.Community
{% endblock %}
{% block content %}
<div class="container mb-5 mt-5">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/show/{{show.abbr}}">{{show.name}}</a></li>
<li class="breadcrumb-item"><a href="/show/{{show.abbr}}/discuss">Discussions</a></li>
<li class="breadcrumb-item active" aria-current="page">{{board.title}}</li>
</ol>
</nav>
<div class="row">
<h1 class="col">{{board.title}}</h1>
<div class="col-2">
<div class="d-flex flex-row-reverse mt-2">
{% if board.locked %}
<p>This board is locked</p>
{% else %}
{% if user.is_authenticated %}
<a href="/show/{{show.abbr}}/discuss/board/reply/{{board.pk}}" class="btn btn-primary"><i class="fa fa-fw fa-pencil"></i>&nbsp;Reply</a>
{% else %}
<p><a href="/login">Log in</a> to reply</p>
{% endif %}
{% endif %}
</div>
</div>
</div>
<p class="timestamp text-muted font-weight-light">Created {{board.timestamp}} by {{board.user.display_name}}</p>
{% for reply in replies %}
<div class="reply border-bottom mb-4" id="reply-{{forloop.counter}}">
<div class="row">
<div class="avatar">
<img src="https://icynet.eu/api/avatar/{{reply.user.icy_id}}" class="m-auto d-block">
<p class="text-center font-weight-bold">{{reply.user.display_name}}</p>
</div>
<div class="col border-left d-flex flex-column">
<p class="timestamp text-muted font-weight-light">Submitted {{board.timestamp}}</p>
<div class="user-content mb-auto">
{{reply.body}}
</div>
<div class="actions d-flex flex-row-reverse">
<div class="vote-btns">
<form method="POST" class="d-inline" action="/show/{{show.abbr}}/discuss/vote/{{reply.id}}/1">
{% csrf_token %}
<button href="#" class="btn btn-link text-success">
<i class="fa fa-fw fa-thumbs-up"></i>&nbsp;{{reply.positives}}
</button>
</form>
<form method="POST" class="d-inline" action="/show/{{show.abbr}}/discuss/vote/{{reply.id}}/0">
{% csrf_token %}
<button href="#" class="btn btn-link text-danger">
<i class="fa fa-fw fa-thumbs-down"></i>&nbsp;{{reply.negatives}}
</button>
</form>
</div>
<!--<a href="#" class="btn btn-secondary mr-1">Quote</a>-->
</div>
</div>
</div>
</div>
{% empty %}
<h3>Nobody has replied to this board!</h3>
{% endfor %}
{% if replies.has_other_pages %}
<nav aria-label="Boards navigation">
<ul class="pagination">
{% if replies.has_previous %}
<li class="page-item">
<a href="?page={{ replies.previous_page_number }}" class="page-link">Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">Previous</a>
</li>
{% endif %}
{% for i in replies.paginator.page_range %}
{% if replies.number == i %}
<li class="page-item active">
<span class="page-link">{{ i }} <span class="sr-only">(current)</span></span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% if replies.has_next %}
<li class="page-item">
<a href="?page={{ replies.next_page_number }}" class="page-link">Next</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">Next</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% if user.is_authenticated and not board.locked %}
<h2>Quick Reply</h2>
<div class="reply-box">
<form class="form-horizontal" role="form" action="/show/{{show.abbr}}/discuss/board/reply/{{board.pk}}" method="post">
{% include "form.html" %}
<div class="form-group">
<button type="submit" class="btn btn-primary">Reply</button>
</div>
</form>
</div>
{% endif %}
</div>
{% endblock %}
{% extends "base.html" %}
{% block title %}
Reply - {{show.name}} Discussions - Episodes.Community
{% endblock %}
{% block content %}
<section class="container mt-5 mb-5">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/show/{{show.abbr}}">{{show.name}}</a></li>
<li class="breadcrumb-item"><a href="/show/{{show.abbr}}/discuss">Discussions</a></li>
<li class="breadcrumb-item"><a href="/show/{{show.abbr}}/discuss/board/{{board.pk}}-{{board.title|slugify}}">{{board.title}}</a></li>
<li class="breadcrumb-item active" aria-current="page">Reply</li>
</ol>
</nav>
<h1>New Reply</h1>
{% if error %}
<div class="alert alert-danger">{{error}}</div>
{% endif %}
<form class="form-horizontal" role="form" action="" method="post">
{% include "form.html" %}
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</section>
{% endblock %}
......@@ -4,12 +4,19 @@
{% endblock %}
{% block content %}
<div class="container mb-5 mt-5">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/show/{{show.abbr}}">{{show.name}}</a></li>
<li class="breadcrumb-item active" aria-current="page">Discussions</li>
</ol>
</nav>
<h1>{{show.name}} Discussion Boards</h1>
<p>Discuss {{show.name}} with your fellow community members!</p>
<div class="d-flex flex-row-reverse mb-4">
{% if user.is_authenticated %}
<a href="/show/{{show.abbr}}/discuss/board/new" class="btn btn-primary"><i class="fa fa-fw fa-pencil"></i>&nbsp;Create New Board</a>
{% else %}
<a href="/login">Log in</a> to create boards
<p><a href="/login">Log in</a> to create boards</p>
{% endif %}
</div>
<div class="bg-light rounded p-2 row">
......@@ -29,7 +36,17 @@
</span>
</div>
<div class="col-2">
{% if board.num_replies > 0 %}
<div class="reply mt-2">
<div class="user">
<small class="text-muted font-weight-light">by </small>
{{board.latest_reply.user.display_name}}
</div>
<small class="timestamp text-muted font-weight-light">{{board.latest_reply.timestamp}}</small>
</div>
{% else %}
<span class="text-muted font-weight-light">No replies</span>
{% endif %}
</div>
</div>
</div>
......@@ -56,11 +73,11 @@
</li>
{% else %}
<li class="page-item">
<span class="page-link" href="?page={{ i }}">{{ i }}</span>
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% if users.has_next %}
{% if boards.has_next %}
<li class="page-item">
<a href="?page={{ boards.next_page_number }}" class="page-link">Next</a>
</li>
......
{% extends "base.html" %}
{% block title %}
Create a Board - {{show.name}} Discussions - Episodes.Community
{% endblock %}
{% block content %}
<section class="container mt-5 mb-5">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/show/{{show.abbr}}">{{show.name}}</a></li>
<li class="breadcrumb-item"><a href="/show/{{show.abbr}}/discuss">Discussions</a></li>
<li class="breadcrumb-item active" aria-current="page">New Board</li>
</ol>
</nav>
<h1>Create a Board</h1>
{% if error %}
<div class="alert alert-danger">{{error}}</div>
{% endif %}
<form class="form-horizontal" role="form" action="" method="post">
{% include "form.html" %}
<div class="form-group">
<button type="submit" class="btn btn-primary">Create</button>
</div>
</form>
</section>
{% endblock %}
......@@ -20,5 +20,9 @@ from . import views
urlpatterns = [
url(r'^$', views.Boards.as_view()),
url(r'^vote/(?P<replyid>\d+)/(?P<positive>[0-1])/?$', views.BoardVoteSubmit.as_view()),
url(r'^board/new$', views.BoardForm),
url(r'^board/reply/(?P<bid>\d{1,4})/?$', views.BoardReplyForm),
url(r'^board/(?P<bid>\d{1,4})(-[\w-]+)?/?$', views.Board.as_view()),
]
This diff is collapsed.
......@@ -173,3 +173,4 @@ AUTH_B64 = base64.b64encode(bytearray('%s:%s'%(AUTH_CLIENT_ID,oauth_options.get(
AUTH_REDIRECT_URL = oauth_options.get('redirect_url')
DISCUSSIONS_PER_PAGE = 26
DISCUSSIONS_REPLIES_PER_PAGE = 10
......@@ -36,7 +36,7 @@ from django.conf.urls.static import static
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^show/(?P<abbr>\w{1,16})/discuss', include('Discussions.urls')),
url(r'^show/(?P<abbr>\w{1,16})/discuss/', include('Discussions.urls')),
url(r'^show/(?P<abbr>\w{1,16})/', include('Show.urls')),
url(r'^', include('LandingPage.urls'))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
......@@ -92,6 +92,7 @@ class Show(TimestampedModel):
permissions = (
('can_create_show_ban', 'Can ban an user from submitting to this show'),
('can_moderate_show', 'Can add episodes, seasons and unrestricted submissions'),
('can_moderate_board', 'Can delete and edit boards and replies of this show'),
)
def __str__(self):
......@@ -387,10 +388,6 @@ class DiscussionBoard(TimestampedModel):
max_length=100,
help_text='The title of the discussion'
)
body = models.TextField(
help_text='The body of the post',
verbose_name='Body'
)
views = models.IntegerField(
help_text='The amount of times this board has been viewed',
default=0
......@@ -399,6 +396,14 @@ class DiscussionBoard(TimestampedModel):
help_text='Whether or not this board is pinned',
default=False
)
locked = models.BooleanField(
help_text='Whether or not this board is locked for further replies',
default=False
)
def latest_reply(self):
return self.replies.latest('timestamp')
def __str__(self):
return '[%s] "%s" by %s'%(self.show.abbr, self.title, self.user)
......@@ -420,6 +425,10 @@ class DiscussionReply(TimestampedModel):
help_text='The body of the response',
verbose_name='Body'
)
deleted = models.BooleanField(
help_text='Whether or not the content has been deleted by a moderator',
default=False
)
def __str__(self):
return '[%s] %s\'s response to "%s"'%(self.board.show.abbr,self.user, self.board.title)
......@@ -430,11 +439,11 @@ class DiscussionVote(TimestampedModel):
related_name='discussion_votes',
help_text='The user which cast this vote'
)
board = models.ForeignKey(
DiscussionBoard,
reply = models.ForeignKey(
DiscussionReply,
on_delete=models.CASCADE,
related_name='votes',
help_text='The board this vote was cast on'
help_text='The reply this vote was cast on'
)
positive = models.BooleanField(
help_text='If true, the vote is an upvote. Otherwise, it is a downvote. Neutral votes are not recorded'
......
......@@ -187,6 +187,30 @@ footer .logo .part1 {
text-shadow: 2px 2px 1px #0059a0;
margin-right: 5px;
}
.avatar {
-webkit-box-flex: 0;
-ms-flex: 0 0 180px;
flex: 0 0 180px;
max-width: 180px;
}
.avatar img {
max-width: 150px;
max-height: 150px;
}
.mini_avatar {
-webkit-box-flex: 0;
-ms-flex: 0 0 50px;
flex: 0 0 45px;
max-width: 45px;
}
.mini_avatar img {
max-width: 45px;
max-height: 45px;
}
.user-content {
word-wrap: break-word;
word-break: break-all;
}
@media all and (max-width: 800px) {
.logo {
font-size: 5vw !important;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment