Added forums

This commit is contained in:
Zakary Timson 2018-01-11 00:58:07 -05:00
parent cf20df8d33
commit 912a5dcb25
8 changed files with 223 additions and 96 deletions

View File

@ -48,6 +48,7 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django_forms_bootstrap',
'expert_witnesses', 'expert_witnesses',
'forum.apps.ForumConfig', 'forum.apps.ForumConfig',
'main.apps.MainConfig', 'main.apps.MainConfig',
@ -94,12 +95,14 @@ WSGI_APPLICATION = 'OACPL.wsgi.application'
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.postgresql',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'NAME': 'postgres',
'USER': 'postgres',
'HOST': 'db',
'PORT': 5432,
} }
} }
# Password validation # Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

View File

@ -31,8 +31,7 @@ urlpatterns = [
url(r'^contact/', main.views.contact, name='contact'), url(r'^contact/', main.views.contact, name='contact'),
url(r'^experts/(?P<id>\d+)', expert_witnesses.views.viewer, name='expert'), url(r'^experts/(?P<id>\d+)', expert_witnesses.views.viewer, name='expert'),
url(r'^experts/', expert_witnesses.views.browser, name='experts'), url(r'^experts/', expert_witnesses.views.browser, name='experts'),
url(r'^forum/post/(?P<post>\d*)', forum.views.post, name='post'), url(r'^forum/post/(?P<post>\d*)', forum.views.viewPost, name='post'),
url(r'^forum/comment', forum.views.comment, name='comment'),
url(r'^forum/(?P<thread>\d*)?', forum.views.view, name='forum'), url(r'^forum/(?P<thread>\d*)?', forum.views.view, name='forum'),
url(r'^login/', main.views.login, name='login'), url(r'^login/', main.views.login, name='login'),
url(r'^logout/', main.views.logout, name='logout'), url(r'^logout/', main.views.logout, name='logout'),

View File

@ -8,15 +8,15 @@ admin.site.register(Thread)
@admin.register(Post) @admin.register(Post)
class PostAdmin(admin.ModelAdmin): class PostAdmin(admin.ModelAdmin):
list_display = ['title', 'topic', 'creator', 'created'] list_display = ['title', 'resolved', 'topic', 'creator', 'created']
search_fields = ['title', 'topic', 'creator', 'created'] search_fields = ['title', 'resolved', 'topic', 'creator', 'created']
def get_form(self, request, obj=None, **kwargs): def get_form(self, request, obj=None, **kwargs):
if obj: if obj:
self.fields = ['creator', 'created', 'topic', 'title', 'question'] self.fields = ['creator', 'created', 'resolved', 'title', 'topic', 'question']
self.readonly_fields = ['creator', 'created'] self.readonly_fields = ['creator', 'created']
else: else:
self.fields = ['topic', 'title', 'question'] self.fields = ['title', 'topic', 'question']
self.readonly_fields = [] self.readonly_fields = []
return super(PostAdmin, self).get_form(request, obj, **kwargs) return super(PostAdmin, self).get_form(request, obj, **kwargs)

29
forum/forms.py Normal file
View File

@ -0,0 +1,29 @@
from django import forms
from tinymce import TinyMCE
from .models import Comment, Post, Thread
class CommentForm(forms.ModelForm):
reply = forms.CharField(widget=TinyMCE(mce_attrs={'height': 200}))
class Meta:
model = Comment
fields = ['reply']
class CreatePostForm(forms.ModelForm):
question = forms.CharField(widget=TinyMCE(mce_attrs={'height': 200}))
class Meta:
model = Post
fields = ['title', 'topic', 'question']
class EditPostForm(forms.ModelForm):
question = forms.CharField(widget=TinyMCE(mce_attrs={'height': 200}))
class Meta:
model = Post
fields = ['question']

View File

@ -6,45 +6,126 @@
<div class="container py-3"> <div class="container py-3">
<div class="col-12 bg-white p-3"> <div class="col-12 bg-white p-3">
<div class="col-12"> <div class="col-12">
{% if post.creator == user and not post.resolved or perms.forum.change_post and not post.resolved %}
<div class="btn-group float-right">
<button class="btn" data-toggle="modal" data-target="#editModal"><i class="fa fa-pencil"></i></button>
{% if post.creator == user or perms.forum.delete_post %}
<button class="btn" data-toggle="modal" data-target="#deleteModal"><i class="fa fa-trash"></i></button>
{% endif %}
<button class="btn btn-danger" data-toggle="modal" data-target="#closeModal">Close</button>
</div>
{% endif %}
<h2 class="mb-0">{{ post.title }}</h2> <h2 class="mb-0">{{ post.title }}</h2>
<small class="text-muted">Asked By: {{ post.creator }}</small> <span class="text-muted">
{% if post.resolved %}<span class="badge badge-sm badge-danger">Closed</span> {% endif %}
Asked By: {{ post.creator }}, {{ post.created | date }}
</span>
<hr>
</div> </div>
<div class="col-12 mt-3"> <div class="col-12 my-3">
{{ post }} {{ post.question | safe }}
</div> </div>
{% for comment in comments %} {% if comments %}
<div class="col-12 bg-white p-3 mt-3 rounded" style="border: 1px solid rgba(0, 0, 0, 0.2"> <div class="col-12 mt-5">
<div class="col-12"> <h4>Answers</h4>
<small class="text-muted">Answered By: {{ comment.creator }}</small> <ul class="list-group w-100">
<div class="w-100"> {% for comment in comments %}
{% autoescape off %} <li class="list-group-item">
{{ comment }} <span class="text-muted">{{ comment.creator }}, {{ comment.created | date }}</span>
{% endautoescape %} {% autoescape off %}
</div> {{ comment }}
</div> {% endautoescape %}
</li>
{% endfor %}
</ul>
</div> </div>
{% endfor %} {% endif %}
</div> </div>
<div class="col-12 bg-white mt-3 py-3" style="position: relative"> {% if not post.resolved and perms.forum.add_comment %}
<div> <div class="col-12 bg-white mt-3 py-3" style="overflow: auto">
<h5>Comment</h5> <div class="col-12">
<form method="post" action="{% url 'comment' %}"> <h5>Comment</h5>
{% csrf_token %} <form method="post">
<input name="post" type="hidden" value="{{ post.id }}"> <div>
<textarea class="form-control" name="comment" value="{{ comment }}" {% csrf_token %}
{% if not request.user.is_authenticated or not perms.form.add_comment %}disabled{% endif %}></textarea> <input type="hidden" name="request" value="comment">
<button class="btn btn-primary float-right">Create</button> {{ form.reply }}
</form> <button class="btn btn-primary float-right mt-3">Create</button>
{% if not request.user.is_authenticated %} </div>
<span style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)">You must <a </form>
href="{% url 'login' %}">login</a> to comment</span> </div>
{% endif %}
{% if request.user.is_authenticatednot and perms.form.add_comment %}
<span style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)">You do not have permission to comment</span>
{% endif %}
</div> </div>
{% endif %}
</div>
</div>
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editModal" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Edit</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="editForm" method="post">
{% csrf_token %}
<input type="hidden" name="request" value="edit">
{{ editForm.question }}
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary" form="editForm">Save changes</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModal" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Delete Post</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Are you sure you would like to delete this post? It cannot be undone.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<form method="post">
{% csrf_token %}
<input type="hidden" name="request" value="delete">
<button class="btn"><i class="fa fa-trash"></i></button>
</form>
</div>
</div>
</div>
</div>
<div class="modal fade" id="closeModal" tabindex="-1" role="dialog" aria-labelledby="closeModal" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Close Post</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Are you sure you would like to close this issue? No one will be able to respond anylonger.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<form method="post">
{% csrf_token %}
<input type="hidden" name="request" value="resolve">
<button class="btn btn-danger" data-toggle="modal" data-target="#closeModal">Close</button>
</form>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,14 +1,23 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load bootstrap_tags %}
{% block head %} {% block head %}
<script> <script>
$(function () { $(function () {
{% if form.errors %}
$('#create-post-modal').modal(show = true);
{% endif %}
$('#my-posts').popover({ $('#my-posts').popover({
title: 'My Posts', title: 'My Posts',
placement: 'bottom', placement: 'bottom',
html: true, html: true,
content: '<ul class="list-group">{% if myPosts.count == 0 %}None{% endif %}{% for post in myPosts %}<a href="{% url 'post' post.id %}" class="list-group-item list-group-item-action">{{ post.title }}</a>{% endfor %}</ul>' content: '<ul class="list-group">{% if myPosts.count == 0 %}None{% endif %}{% for post in myPosts %}<a href="{% url 'post' post.id %}" class="list-group-item list-group-item-action">{{ post.title }}</a>{% endfor %}</ul>'
}); });
$('#createPostButton').click(function () {
$('#createPost').submit();
});
}); });
</script> </script>
{% endblock %} {% endblock %}
@ -42,17 +51,22 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
<div class="row"> {% if posts %}
<div class="col-12"> <div class="row">
<h3 class="text-white d-inline">Posts</h3> <div class="col-12">
<ul class="list-group"> <h3 class="text-white d-inline">{% if thread %}"{{ thread }}" {% endif %}Posts</h3>
{% for post in posts %} <ul class="list-group">
<a href="{% url 'post' post.id %}" {% for post in posts %}
class="list-group-item list-group-item-action">{{ post.title }}</a> <a href="{% url 'post' post.id %}" class="list-group-item list-group-item-action">
{% endfor %} {% if post.resolved %}<span class="badge badge-danger">Closed</span> {% endif %}
</ul> {{ post.title }}
<span class="float-right text-muted">{{ post.creator }}, {{ post.created | date }}</span>
</a>
{% endfor %}
</ul>
</div>
</div> </div>
</div> {% endif %}
</div> </div>
</div> </div>
@ -66,29 +80,13 @@
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="col-12"> <form id="createPost" method="post">
<form> {% csrf_token %}
<div class="form-group"> {{ form | as_bootstrap }}
<label for="title">Title</label> </form>
<input class="form-control" name="title">
</div>
<div class="form-group">
<label for="thread">Topic</label>
<select class="form-control" name="thread">
{% for thread in threads %}
<option value="{{ thread.id }}">{{ thread.topic }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="title">Body</label>
<textarea class="form-control" name="body"></textarea>
</div>
</form>
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-primary">Create</button> <button id="createPostButton" type="button" class="btn btn-primary">Create</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div> </div>
</div> </div>

View File

@ -1,40 +1,56 @@
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from .forms import CommentForm, CreatePostForm, EditPostForm
from .models import Thread, Post, Comment from .models import Thread, Post, Comment
def view(request, thread=None): def view(request, thread=None):
myPosts = None if request.method == 'POST':
form = CreatePostForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.creator = request.user
instance.save()
return redirect('post', post=instance.id)
else:
form = CreatePostForm()
my_posts = None
if request.user.is_authenticated(): if request.user.is_authenticated():
myPosts = Post.objects.filter(creator=request.user) my_posts = Post.objects.filter(creator=request.user, resolved=False)
if not thread: if not thread:
threads = Thread.objects.all() threads = Thread.objects.all()
posts = Post.objects.order_by('created')[:10] thread_name = None
posts = Post.objects.filter(resolved=False).order_by('-created')[:10]
else: else:
threads = None threads = None
posts = Post.objects.filter(topic=thread) thread_name = Thread.objects.get(id=thread).topic
return render(request, 'view.html', {'threads': threads, 'posts': posts, 'myPosts': myPosts}) posts = Post.objects.filter(topic=thread).order_by('-created')
return render(request, 'view.html', {'threads': threads, 'posts': posts, 'myPosts': my_posts, 'thread': thread_name, 'form': form})
def post(request, post): def viewPost(request, post):
this_post = Post.objects.get(id=post) this_post = Post.objects.get(id=post)
comments = Comment.objects.filter(post=post)
return render(request, 'post.html', {'post': this_post, 'comments': comments})
if request.method == 'POST':
if request.POST.get('request') == 'comment':
form = CommentForm(request.POST)
Comment.objects.create(post_id=post,
reply=form.data.get('reply'),
creator=request.user)
elif request.POST.get('request') == 'edit':
form = EditPostForm(request.POST, instance=this_post)
form.save()
elif request.POST.get('request') == 'resolve':
if this_post.creator == request.user or request.user.has_perm('forum.change_post'):
this_post.resolved = True
this_post.save()
elif request.POST.get('request') == 'delete':
if this_post.creator == request.user or request.user.has_perm('forum.delete_post'):
this_post.delete()
return redirect('forum')
def create(request): form = CommentForm()
pass edit_form = EditPostForm(instance=this_post)
comments = Comment.objects.filter(post=this_post)
return render(request, 'post.html', {'post': this_post, 'comments': comments, 'form': form, 'editForm': edit_form})
def comment(request):
success = False
post = Post.objects.get(id=request.POST.get('post'))
comments = Comment.objects.filter(post=post)
try:
success = Comment.objects.create(post=post,
reply=request.POST.get('comment'),
creator=request.user)
success.save()
finally:
return redirect('forum', post.id)

View File

@ -1,5 +1,6 @@
bootstrap-admin==0.3.7.1 bootstrap-admin==0.3.7.1
Django==1.11.5 Django==1.11.5
django-forms-bootstrap==3.1.0
django-tinymce4-lite==1.7.0
Pillow==4.2.1 Pillow==4.2.1
requests==2.11.1 requests==2.11.1
django-tinymce4-lite==1.7.0