Compare commits
10 Commits
cfd708f158
...
6dd0631537
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dd0631537 | ||
|
|
db45fd2d6f | ||
|
|
ea028a7642 | ||
|
|
ceb0a40771 | ||
|
|
3a940e8789 | ||
|
|
fd8de82a89 | ||
|
|
c84243354e | ||
|
|
1de7ad09ec | ||
|
|
1d688a4123 | ||
|
|
08abb25ce8 |
@ -2,6 +2,8 @@
|
||||
{% load static %}
|
||||
{% load helpers %}
|
||||
|
||||
{% block head_title %}{{ object }} | {% endblock head_title %}
|
||||
|
||||
{% block content %}
|
||||
<article class="account">
|
||||
<header>
|
||||
|
||||
@ -28,8 +28,8 @@ class AccountDetailView(LoginRequiredMixin, DetailView):
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['posts'] = Post.objects.filter(author=self.object).order_by('-created_at')
|
||||
context['comments'] = Comment.objects.filter(author=self.object).order_by('-created_at')
|
||||
context['posts'] = Post.objects.filter(author=self.object).order_by('-updated_at')[:10]
|
||||
context['comments'] = Comment.objects.filter(author=self.object).order_by('-updated_at')[:10]
|
||||
|
||||
return context
|
||||
|
||||
|
||||
20
src/core/migrations/0009_alter_post_recipients.py
Normal file
20
src/core/migrations/0009_alter_post_recipients.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Generated by Django 4.0.6 on 2022-07-26 13:45
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('core', '0008_alter_post_options'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='post',
|
||||
name='recipients',
|
||||
field=models.ManyToManyField(blank=True, help_text='will be notified when creating or commenting on a post', related_name='subscriptions', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
17
src/core/migrations/0010_alter_post_options.py
Normal file
17
src/core/migrations/0010_alter_post_options.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Generated by Django 4.0.6 on 2022-07-26 13:47
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0009_alter_post_recipients'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='post',
|
||||
options={'ordering': ['-created_at']},
|
||||
),
|
||||
]
|
||||
@ -130,7 +130,8 @@ class Post(models.Model):
|
||||
recipients = models.ManyToManyField(
|
||||
User,
|
||||
blank=True,
|
||||
related_name='subscriptions'
|
||||
related_name='subscriptions',
|
||||
help_text='will be notified when creating or commenting on a post'
|
||||
)
|
||||
tags = GenericRelation(Tag)
|
||||
|
||||
@ -149,4 +150,4 @@ class Post(models.Model):
|
||||
return self.title
|
||||
|
||||
class Meta:
|
||||
ordering = ['-updated_at', '-created_at']
|
||||
ordering = ['-created_at']
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{% block content %}
|
||||
<article>
|
||||
<h1>Update comment</h1>
|
||||
<form method="POST" action="{% url 'core:comment-update' comment.pk %}">
|
||||
<form method="POST" action="{% url 'core:comment-update' comment.pk %}" class="comments__form">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<p>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block head_title %}Delete Post | {% endblock head_title %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Delete Post</h1>
|
||||
<form method="POST" action="{% url 'core:post-delete' post.topic.pk post.pk %}">
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block head_title %}New Post | {% endblock head_title %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<menu>
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
{% load static %}
|
||||
{% load helpers %}
|
||||
|
||||
{% block head_title %}{{ post.title }} | {% endblock head_title %}
|
||||
|
||||
{% block head %}
|
||||
<script type="module" src="{% static 'scripts/comments.js' %}" defer></script>
|
||||
{% endblock head %}
|
||||
@ -49,6 +51,20 @@
|
||||
<form action="{% url 'core:comment-create' %}" method="POST">
|
||||
{% csrf_token %}
|
||||
{{ comment_create_form.as_p }}
|
||||
<p>
|
||||
{% for recipient in post.recipients.all %}
|
||||
{% if post.recipients.all|length > 2 %}
|
||||
{% if not forloop.last %}{{ recipient }},{% else %}and {{ recipient }}{% endif %}
|
||||
{% elif post.recipients.all|length is 2 %}
|
||||
{% if forloop.last %}and {{ recipient }} {% else %} {{ recipient }}{% endif %}
|
||||
{% else %}
|
||||
{{ recipient }}
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
No one
|
||||
{% endfor %}
|
||||
will be notified when you post your comment.
|
||||
</p>
|
||||
<input class="action-button" type="submit" value="Post comment">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block head_title %}Edit Post | {% endblock head_title %}
|
||||
|
||||
{% block content %}
|
||||
<article class="post">
|
||||
<h1>Update Post</h1>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block head_title %}Delete Topic | {% endblock head_title %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Delete Topic</h1>
|
||||
<form method="POST" action="{% url 'core:topic-delete' topic.pk %}">
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block head_title %}New Topic | {% endblock head_title %}
|
||||
|
||||
{% block content %}
|
||||
<h1>+ New Topic</h1>
|
||||
<form method="POST" action="{% url 'core:topic-create' %}">
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block head_title %}{{ topic.name }} | {% endblock head_title %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<menu>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block head_title %}Edit Topic | {% endblock head_title %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Update Topic</h1>
|
||||
<form method="POST" action="{% url 'core:topic-update' topic.pk %}">
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block head_title %}Topics | {% endblock head_title %}
|
||||
|
||||
{% block content %}
|
||||
<article>
|
||||
<header>
|
||||
|
||||
@ -13,6 +13,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from accounts.models import User
|
||||
from .models import Topic, Post, Comment
|
||||
from .forms import PostForm, PostCreateForm, CommentCreateForm
|
||||
|
||||
@ -80,6 +81,17 @@ class TopicDetailView(LoginRequiredMixin, DetailView):
|
||||
model = Topic
|
||||
pk_url_kwarg = 'topic_pk'
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = Topic.objects.all().prefetch_related(
|
||||
models.Prefetch(
|
||||
'post_set',
|
||||
queryset=Post.objects.filter(
|
||||
topic=self.kwargs['topic_pk']
|
||||
).order_by('-created_at').prefetch_related('comments')
|
||||
)
|
||||
)
|
||||
return queryset
|
||||
|
||||
|
||||
class TopicUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||
model = Topic
|
||||
@ -127,6 +139,15 @@ class PostDetailView(LoginRequiredMixin, DetailView):
|
||||
model = Post
|
||||
pk_url_kwarg = 'post_pk'
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = Post.objects.all().prefetch_related(
|
||||
models.Prefetch(
|
||||
'recipients',
|
||||
queryset=User.objects.exclude(pk=self.request.user.pk)
|
||||
)
|
||||
)
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
object_content_type = ContentType.objects.get_for_model(self.object).pk
|
||||
|
||||
@ -33,6 +33,7 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sites',
|
||||
|
||||
# 3rd party
|
||||
'debug_toolbar',
|
||||
'django_filters',
|
||||
'compressor',
|
||||
'anymail',
|
||||
@ -44,6 +45,7 @@ INSTALLED_APPS = [
|
||||
|
||||
# Middlewares
|
||||
MIDDLEWARE = [
|
||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
@ -130,34 +132,18 @@ USE_TZ = True
|
||||
# Logging
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse',
|
||||
},
|
||||
'require_debug_true': {
|
||||
'()': 'django.utils.log.RequireDebugTrue',
|
||||
},
|
||||
},
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '{name} {levelname} {asctime} {module} {process:d} {thread:d} {message}',
|
||||
'style': '{',
|
||||
},
|
||||
},
|
||||
'disable_existing_loggers': True,
|
||||
'handlers': {
|
||||
'file': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.FileHandler',
|
||||
'filters': ['require_debug_false'],
|
||||
'filename': LOGGING_FILE_LOCATION,
|
||||
'formatter': 'verbose',
|
||||
'filename': '/home/nathanchapman/debug.log',
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django.file': {
|
||||
'django': {
|
||||
'handlers': ['file'],
|
||||
'level': 'INFO',
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
},
|
||||
|
||||
@ -11,5 +11,6 @@ urlpatterns = [
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns += [path('__debug__/', include('debug_toolbar.urls'))]
|
||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
@ -24,6 +24,7 @@ body {
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
a {
|
||||
color: inherit;
|
||||
@ -41,6 +42,7 @@ h5 {
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
@ -78,6 +80,13 @@ iframe {
|
||||
aspect-ratio: 16/9;
|
||||
}
|
||||
|
||||
object {
|
||||
width: 100%;
|
||||
aspect-ratio: 4/3;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid var(--table-border);
|
||||
}
|
||||
|
||||
|
||||
/* Lists
|
||||
========================================================================== */
|
||||
@ -137,7 +146,7 @@ textarea {
|
||||
box-sizing: border-box;
|
||||
font: inherit;
|
||||
font-family: 'PT Mono', monospace;
|
||||
font-size: 2rem;
|
||||
font-size: 2.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
width: 100%;
|
||||
resize: vertical;
|
||||
@ -160,8 +169,11 @@ input[type=submit],
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
input[type=submit]:hover,
|
||||
.action-button:hover {
|
||||
background-color: var(--color-highlight);
|
||||
color: var(--color-blue);
|
||||
}
|
||||
|
||||
|
||||
@ -174,6 +186,10 @@ main {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
article {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
|
||||
/* ==========================================================================
|
||||
Header
|
||||
@ -219,6 +235,10 @@ main {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.messages {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* Breadcrumbs
|
||||
========================================================================== */
|
||||
@ -260,19 +280,32 @@ main {
|
||||
justify-content: space-between;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.post__header {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.post__content {
|
||||
font-family: 'STIX Two Text';
|
||||
font-size: 2rem;
|
||||
font-family: 'STIX Two Text', serif;
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 4rem;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.post__content {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.post__content h1,
|
||||
.post__content h2,
|
||||
.post__content h3,
|
||||
.post__content h4,
|
||||
.post__content h5 {
|
||||
font-family: 'STIX Two Text';
|
||||
font-family: 'STIX Two Text', serif;
|
||||
text-transform: unset;
|
||||
margin: 2em 0 1em;
|
||||
}
|
||||
@ -293,10 +326,14 @@ main {
|
||||
font-size: 1.125em;
|
||||
}
|
||||
|
||||
.post__content p {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.post__content blockquote {
|
||||
font-size: 0.875em;
|
||||
max-width: 80%;
|
||||
margin: 0 auto 1rem;
|
||||
padding: 0.25rem 1rem 0 2rem;
|
||||
margin: 0 0 1rem;
|
||||
border-left: 0.25rem solid black;
|
||||
}
|
||||
|
||||
|
||||
@ -305,29 +342,42 @@ main {
|
||||
Comments
|
||||
========================================================================== */
|
||||
.comment {
|
||||
margin: 2rem 0;
|
||||
margin: 2em 0;
|
||||
background-color: var(--color-lightgrey);
|
||||
padding: 1rem;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.comment__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
line-height: 1.3;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.comment__header {
|
||||
flex-direction: column;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.comment__content {
|
||||
font-family: 'STIX Two Text';
|
||||
font-size: 2rem;
|
||||
font-family: 'STIX Two Text', serif;
|
||||
font-size: 2.5rem;
|
||||
/*max-width: 64ch;*/
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.comment__content {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.comment__content h1,
|
||||
.comment__content h2,
|
||||
.comment__content h3,
|
||||
.comment__content h4,
|
||||
.comment__content h5 {
|
||||
font-family: 'STIX Two Text';
|
||||
font-family: 'STIX Two Text', serif;
|
||||
text-transform: unset;
|
||||
margin: 2em 0 1em;
|
||||
}
|
||||
@ -348,22 +398,29 @@ main {
|
||||
font-size: 1.125em;
|
||||
}
|
||||
|
||||
.comment__content blockquote {
|
||||
font-size: 1.75rem;
|
||||
max-width: 80%;
|
||||
margin: 0 auto 1rem;
|
||||
}
|
||||
|
||||
.comment p {
|
||||
margin-bottom: 1em;
|
||||
line-height: 1.75;
|
||||
}
|
||||
.comment ul {
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.comment__content blockquote {
|
||||
padding: 0.25rem 1rem 0 2rem;
|
||||
margin: 0 0 1rem;
|
||||
border-left: 0.25rem solid black;
|
||||
}
|
||||
|
||||
|
||||
.comments__form textarea {
|
||||
font-family: 'PT Mono';
|
||||
font-size: 2rem;
|
||||
font-size: 2.5rem;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.comments__form textarea {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,10 +11,10 @@
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,700;0,900;1,400;1,700;1,900&family=PT+Mono&family=STIX+Two+Text:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,700;0,900;1,400;1,700;1,900&family=PT+Mono&family=STIX+Two+Text:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
|
||||
|
||||
{% compress css %}
|
||||
<link rel="stylesheet" type="text/css" href="{% static "styles/main.css" %}">
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'styles/main.css' %}">
|
||||
{% endcompress %}
|
||||
|
||||
<script type="module" defer src="{% static 'scripts/timezone.js' %}"></script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user