Skip to content

Commit

Permalink
#81 forums to discuss and comment (#115)
Browse files Browse the repository at this point in the history
#81 forums with admin controlled categories
  • Loading branch information
ahhcash authored Nov 6, 2024
1 parent 4df2f58 commit 679f1ce
Show file tree
Hide file tree
Showing 26 changed files with 959 additions and 74 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,5 @@ GitHub.sublime-settings
!.vscode/extensions.json
.history
.env
ps_env
ps_env
.aider*
5 changes: 1 addition & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@ dist: focal
install:
- pip install -r src/requirements.txt

before_script:
- python src/manage.py migrate

script:
- python src/manage.py makemigrations --check --dry-run
- black . --check
- flake8 .
- PYTHONPATH=. coverage run --source='src/accounts,src/home,src/public_service_finder,src/services' src/manage.py test accounts home public_service_finder services
- PYTHONPATH=. coverage run --source='.' src/manage.py test accounts home public_service_finder services forum

after_success:
- coveralls
Expand Down
1 change: 1 addition & 0 deletions src/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@


# Elastic Beanstalk Files
.elasticbeanstalk/*
!.elasticbeanstalk/*.cfg.yml
Expand Down
15 changes: 0 additions & 15 deletions src/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,3 @@ class CustomUser(AbstractUser):

def __str__(self):
return f"{self.first_name} {self.last_name} ({self.username})"


# class ServiceSeeker(models.Model):
# user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
# username = models.CharField(max_length=150, unique=True)
# email = models.EmailField(unique=True)
# bookmarked_services = models.JSONField(
# default=list, blank=True, null=True
# ) # Allow null values
# location_preference = models.CharField(
# max_length=255, help_text="Preferred borough or location in NYC"
# )

# def __str__(self):
# return f"Seeker: {self.user.username}"
Empty file added src/forum/__init__.py
Empty file.
24 changes: 24 additions & 0 deletions src/forum/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Register your models here.

from django.contrib import admin
from .models import Category, Post, Comment


@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ("name", "created_at")
search_fields = ("name", "description")


@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ("title", "author", "category", "created_at", "is_closed")
list_filter = ("category", "is_closed", "created_at")
search_fields = ("title", "content", "author__username")


@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ("author", "post", "created_at")
list_filter = ("created_at",)
search_fields = ("content", "author__username", "post__title")
6 changes: 6 additions & 0 deletions src/forum/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class ForumConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "forum"
20 changes: 20 additions & 0 deletions src/forum/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django import forms
from .models import Post, Comment


class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ["title", "content"]
widgets = {
"content": forms.Textarea(attrs={"rows": 5}),
}


class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ["content"]
widgets = {
"content": forms.Textarea(attrs={"rows": 3}),
}
101 changes: 101 additions & 0 deletions src/forum/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Generated by Django 5.1.1 on 2024-11-04 00:44

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Category",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
("description", models.TextField(blank=True)),
("created_at", models.DateTimeField(auto_now_add=True)),
],
options={
"verbose_name_plural": "Categories",
},
),
migrations.CreateModel(
name="Post",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title", models.CharField(max_length=200)),
("content", models.TextField()),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("is_closed", models.BooleanField(default=False)),
(
"author",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
(
"category",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="forum.category"
),
),
],
),
migrations.CreateModel(
name="Comment",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("content", models.TextField()),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"author",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
(
"post",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="comments",
to="forum.post",
),
),
],
),
]
Empty file.
42 changes: 42 additions & 0 deletions src/forum/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from django.db import models

from accounts.models import CustomUser


# Create your models here.


class Category(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)

class Meta:
verbose_name_plural = "Categories"

def __str__(self):
return self.name


class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
author = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
is_closed = models.BooleanField(default=False)

def __str__(self):
return self.title


class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="comments")
author = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __str__(self):
return f"Comment by {self.author.username} on {self.post.title}"
83 changes: 83 additions & 0 deletions src/forum/templates/category_detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{% extends 'base.html' %}

{% block title %}{{ category.name }} - Forum{% endblock %}

{% block content %}
<!--TODO again, no MORE inline styles. this is TEMPORARY. we have filed a ticket -->
<div class="container mx-auto px-6 py-12" style="min-width:1000px; ">

<div class="mb-10 text-center mt-16">
<h1 class="text-4xl font-bold text-gray-800 mb-3">{{ category.name }}</h1>
<p class="text-gray-600 text-lg">{{ category.description }}</p>
</div>

<!-- Search and Create Post Section -->
<div class="mb-6 flex flex-col sm:flex-row justify-between items-start sm:items-center space-y-4 sm:space-y-0 w-full">
<!-- Search Form -->
<form method="get" class="w-full sm:w-3/4 lg:w-4/5 sm:mr-4"> <!-- Increased width -->
<div class="relative">
<input type="text"
name="search"
placeholder="Search posts..."
value="{{ search_query }}"
class="w-full px-4 py-3 pr-20 rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<!-- ... rest of the search input ... -->
</div>
</form>

<!-- Create Post Button -->
<a href="{% url 'forum:create_post' category.id %}"
class="bg-blue-500 text-white px-6 py-3 rounded-md hover:bg-blue-600 transition-colors duration-300 whitespace-nowrap">
Create New Post
</a>
</div>

<!-- Posts List -->
<div class="space-y-6 w-full"> <!-- Added w-full -->
{% for post in posts %}
<div class="bg-white rounded-lg shadow-md p-8 hover:shadow-lg transition-shadow duration-300" style="min-width: 100%;">
<div class="flex justify-between items-start gap-4"> <!-- Added gap-4 -->
<div class="flex-1"> <!-- Use flex-1 instead of flex-grow -->
<h2 class="text-xl font-semibold text-blue-700">
<a href="{% url 'forum:post_detail' post.id %}" class="hover:underline">
{{ post.title }}
</a>
</h2>
{% if post.author.user_type == "service_provider" %}
<span class="inline-block bg-purple-100 text-purple-800 text-xs px-2 py-1 rounded-full mt-2">
<i class="fas fa-building mr-1"></i> Service Provider
</span>
{% endif %}
</div>
{% if post.is_closed %}
<span class="bg-gray-200 text-gray-700 px-3 py-1 rounded-full text-sm whitespace-nowrap">
Closed
</span>
{% endif %}
</div>
<div class="mt-3 text-gray-600 line-clamp-2">{{ post.content|truncatewords:50 }}</div>
<div class="mt-4 flex justify-between items-center text-sm text-gray-500">
<span>Posted by {{ post.author.username }} on {{ post.created_at|date:"M d, Y" }}</span>
<span class="flex items-center">
<i class="fas fa-comment-alt mr-1"></i>
{{ post.comments.count }}
</span>
</div>
</div>
{% empty %}
<div class="text-center py-8 text-gray-500">
{% if search_query %}
No posts found matching your search.
{% else %}
No posts in this category yet.
{% endif %}
</div>
{% endfor %}
</div>

{% with page_obj=posts %}
{% include 'partials/_pagination.html' %}
{% endwith %}
</div>
{% endblock %}
33 changes: 33 additions & 0 deletions src/forum/templates/category_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{% extends 'base.html' %}

{% block title %}Forum Categories{% endblock %}

{% block content %}
<div class="container mx-auto px-6 py-12 max-w-7xl">
<div class="mb-10 text-center mt-16"> <!-- Added mt-16 for more top margin -->
<h1 class="text-4xl font-bold text-gray-800 mb-3">Discussion Forums</h1>
<p class="text-gray-600 text-lg">Choose a category to start or join discussions</p>
</div>

<div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{% for category in categories %}
<a href="{% url 'forum:category_detail' category.id %}"
class="block bg-white rounded-lg shadow-md hover:shadow-lg transition-all duration-300 hover:transform hover:-translate-y-1">
<div class="p-6">
<h2 class="text-xl font-semibold text-blue-700 mb-2 hover:text-blue-800">{{ category.name }}</h2>
<p class="text-gray-600 mb-4">{{ category.description }}</p>
<div class="flex justify-end items-center">
<span class="text-sm text-gray-500">
Created {{ category.created_at|date:"M d, Y" }}
</span>
</div>
</div>
</a>
{% empty %}
<div class="col-span-full text-center py-8 text-gray-500">
No categories available yet.
</div>
{% endfor %}
</div>
</div>
{% endblock %}
Loading

0 comments on commit 679f1ce

Please sign in to comment.