blog

Remove some bugs pertaining to previous commit

- Remove a redundant piece of the comments section - Fix a bug in the CommentForm where it required a slug of the Post. It now requires the ID of the Post. - Fix a bug in views.post where it would not accept comments to comments, including some other bugs in that system. - Remove the Python comment generator, since the DTL version supports recursion properly, takes the context into account ánd is a lot cleaner to work with.

Author
Maarten Vangeneugden
Date
April 3, 2022, 2:15 p.m.
Hash
c20135034fa1e7ba77d5b15c18b947742c03f1aa
Parent
05280c1b832e2534eef2b40eac3a07e0653ff4b9
Modified files
forms.py
migrations/0012_auto_20220403_1326.py
models.py
templates/blog/comment.djhtml
templates/blog/post.djhtml
views.py

forms.py

1 addition and 1 deletion.

View changes Hide changes
1
1
from django.forms import ModelForm
2
2
from . import models
3
3
4
4
class CommentForm(ModelForm):
5
5
    class Meta:
6
6
        model = models.Comment
7
7
        fields = ['name',
8
8
                  'reaction_to',
9
-
                  'text',
+
9
                  'text',
10
10
                  ]
11
11

migrations/0012_auto_20220403_1326.py

33 additions and 0 deletions.

View changes Hide changes
+
1
+
2
from django.db import migrations, models
+
3
+
4
+
5
class Migration(migrations.Migration):
+
6
+
7
    dependencies = [
+
8
        ('blog', '0011_auto_20220220_1906'),
+
9
    ]
+
10
+
11
    operations = [
+
12
        migrations.AddField(
+
13
            model_name='comment',
+
14
            name='from_myself',
+
15
            field=models.BooleanField(default=False),
+
16
        ),
+
17
        migrations.AddField(
+
18
            model_name='post',
+
19
            name='title_fr_be',
+
20
            field=models.CharField(blank=True, max_length=64),
+
21
        ),
+
22
        migrations.AddField(
+
23
            model_name='post',
+
24
            name='title_nl_be',
+
25
            field=models.CharField(blank=True, max_length=64),
+
26
        ),
+
27
        migrations.AddField(
+
28
            model_name='post',
+
29
            name='visible',
+
30
            field=models.BooleanField(default=True, help_text="Whether this post is shown in the index. If False, it's             only accessible by direct link."),
+
31
        ),
+
32
    ]
+
33

models.py

15 additions and 9 deletions.

View changes Hide changes
1
1
from django.utils import translation
2
2
from django.template.defaultfilters import slugify
3
3
from django.db import models
4
4
from django.conf import settings  # Necessary to get the link to the media root folder
5
5
import datetime
6
6
import os
7
7
import subprocess
8
8
9
9
from django.shortcuts import render as render_shortcut
10
10
11
11
""" New version:
12
12
- For each post, there's no longer a mandatory Dutch and English
13
13
  version. Instead, only the title needs to be in multiple languages.
14
14
- There's a new table for the links to the articles themselves. These include a
15
15
  language code and a foreign key to the post they belong to.
16
16
- If an article is available in the active language, but not tagged for the same
17
17
  dialect, then it should just show up without any warnings.
18
18
- If an article is not available in the active language, only the title should
19
19
  show up, but where the short intro text would normally be, there should be an
20
20
  explanation that it's only available in other languages, and provide links to
21
21
  those versions.
22
22
"""
23
23
24
24
# Look, you think this function is worthless, it's not. It's required to make
25
25
# migrations with manage.py, so here it stays, being empty and hollow like the
26
26
# piece of shit it is.
27
27
def post_title_directory():
28
28
    pass
29
29
        
30
30
31
31
class Post(models.Model):
32
32
    """ Represents a blog post."""
33
33
    published = models.DateTimeField(auto_now_add=True)
34
34
    visible = models.BooleanField(default=True, 
35
35
            help_text="Whether this post is shown in the index. If False, it's \
36
36
            only accessible by direct link.")
37
37
    title_en = models.CharField(max_length=64, unique=True, blank=False)
38
-
    title_nl = models.CharField(max_length=64, unique=True, blank=False)
39
-
    title_fr = models.CharField(max_length=64, unique=True, blank=True)
40
-
    title_de = models.CharField(max_length=64, unique=True, blank=True)
41
-
    title_es = models.CharField(max_length=64, unique=True, blank=True)
42
-
    title_eo = models.CharField(max_length=64, unique=True, blank=True)
43
-
    title_af = models.CharField(max_length=64, unique=True, blank=True)
44
-
    title_nl_be=models.CharField(max_length=64, unique=True, blank=True)
45
-
    title_fr_be=models.CharField(max_length=64, unique=True, blank=True)
46
-
+
38
    # collisions. But at this moment, there are still some posts that don't have
+
39
    # a title in all these languages (and "" collides with ""), so until that's
+
40
    # fixed, they're set to False.
+
41
    title_en = models.CharField(max_length=64, unique=False, blank=False)
+
42
    title_nl = models.CharField(max_length=64, unique=False, blank=False)
+
43
    title_fr = models.CharField(max_length=64, unique=False, blank=True)
+
44
    title_de = models.CharField(max_length=64, unique=False, blank=True)
+
45
    title_es = models.CharField(max_length=64, unique=False, blank=True)
+
46
    title_eo = models.CharField(max_length=64, unique=False, blank=True)
+
47
    title_af = models.CharField(max_length=64, unique=False, blank=True)
+
48
    title_nl_be=models.CharField(max_length=64, unique=False, blank=True)
+
49
    title_fr_be=models.CharField(max_length=64, unique=False, blank=True)
+
50
47
51
48
52
    def __str__(self):
49
53
        return self.title()
50
54
51
55
52
56
    def articles(self):
53
57
        #print(len(Article.objects.filter(post=self)))
54
58
        return Article.objects.filter(post=self)
55
59
        
56
60
    def article(self):
57
61
        language_code = translation.get_language()
58
62
        print(language_code)
59
63
        # Retrieves all articles that have this post as their foreign key
60
64
        articles = Article.objects.filter(post=self)
61
65
        for a in articles:
62
66
            if a.language_code == language_code:
63
67
                return a
64
68
        # If no exact match was found, try again, but now accept other dialects
65
69
        # as well:
66
70
        for a in articles:
67
71
            if a.language_code.startswith(language_code):
68
72
                return a
69
73
        
70
74
        # If still no article was found, return None
71
75
        return None
72
76
73
77
    def title(self):
74
78
        language_code = translation.get_language()
75
79
        options = {'af': self.title_af,
76
80
                   'de': self.title_de,
77
81
                   'es': self.title_es,
78
82
                   'en': self.title_en,
79
83
                   'eo': self.title_eo,
80
84
                   'fr': self.title_fr,
81
85
                   'nl-be': self.title_nl_be,
82
86
                   'fr-be': self.title_fr_be,
83
87
                   'nl': self.title_nl}
84
88
        for code, translated_title in options.items():
85
89
            if language_code.startswith(code):
86
90
                return translated_title
87
91
        # If no return has happened, default to English
88
92
        return self.title_en
89
93
90
94
def org_to_html(file_path, return_djhtml_path=False):
91
95
    """ Converts the given org formatted file to HTML.
92
96
    This function directly returns the resulting HTML code. This function uses
93
97
    the amazing Haskell library Pandoc to convert the file (and takes care
94
98
    of header id's and all that stuff).
95
99
    """
96
100
    # FIXME: Remove hardcoded link to media. Replace with media tag!
97
101
    # XXX: The reason I'm first converting all occurences of .jpg][ and .png][
98
102
    # to .jpgPANDOCBUG][ and .pngPANDOCBUG][, is because of a Pandoc bug that
99
103
    # removes the text links for images. It is afterwards converted back, no
100
104
    # worries.
101
105
    file = open(file_path, "r", encoding="utf-8")
102
106
    text = file.read()
103
107
    file.close()
104
108
    text = text.replace(".jpg][", ".jpgPANDOCBUG][")
105
109
    text = text.replace(".png][", ".pngPANDOCBUG][")
106
110
    file = open("/tmp/blog-file.org", "w", encoding="utf-8")
107
111
    file.write(text)
108
112
    file.close()
109
113
    html_text = subprocess.check_output(["pandoc", "--from=org", "--to=html","/tmp/blog-file.org"])
110
114
    html_text = html_text.decode("utf-8").replace(".jpgPANDOCBUG", ".jpg")
111
115
    html_text = html_text.replace(".pngPANDOCBUG", ".png")
112
116
    #rendered_file_path = "file_path.rpartition('.')[0] + ".djhtml"
113
117
    rendered_file_path = "/tmp/blog-file.djhtml"
114
118
    rendered_file = open(rendered_file_path, "w", encoding="utf-8")
115
119
    rendered_file.write(html_text)
116
120
    rendered_file.close()
117
121
    if return_djhtml_path:
118
122
        return rendered_file_path
119
123
    else:
120
124
        return html_text
121
125
122
126
class Article(models.Model):
123
127
    AFRIKAANS = 'af'
124
128
    BELGIAN_FRENCH = 'fr-be'
125
129
    DUTCH = 'nl'
126
130
    ESPERANTO = 'eo'
127
131
    ENGLISH = 'en'
128
132
    FLEMISH = 'nl-be'
129
133
    FRENCH = 'fr'
130
134
    GERMAN = 'de'
131
135
    SPANISH = 'es'
132
136
133
137
    LANGUAGE_CODES = [
134
138
        (AFRIKAANS, 'Afrikaans'),
135
139
        (BELGIAN_FRENCH, 'Français (Belgique)'),
136
140
        (DUTCH, 'Nederlands'),
137
141
        (ESPERANTO, 'Esperanto'),
138
142
        (ENGLISH, 'English'),
139
143
        (FLEMISH, 'Vlaams'),
140
144
        (FRENCH, 'Français'),
141
145
        (GERMAN, 'Deutsch'),
142
146
        (SPANISH, 'Español')]
143
147
144
148
    visible = models.BooleanField(default=True)
145
149
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
146
150
    language_code = models.CharField(max_length=16,
147
151
                                      choices = LANGUAGE_CODES,
148
152
                                      blank=False)
149
153
    # file_path shouldn't be unique, because the same article file could be used
150
154
    # for multiple dialects of the same language.
151
155
    file_path = models.FilePathField(path=settings.MEDIA_ROOT + "blog/articles/",
152
156
                                     blank=False)
153
157
    # Same reason, slug shouldn't be unique
154
158
    slug = models.SlugField(unique=False, blank=False, allow_unicode=True)
155
159
    title = models.CharField(max_length=64, unique=False, blank=True)
156
160
157
161
    def text(self):
158
162
        return org_to_html(self.file_path)
159
163
    def djhtml_file(self):
160
164
        return org_to_html(self.file_path, return_djhtml_path=True)
161
165
162
166
163
167
class Comment(models.Model):
164
168
    """ Represents a comment on a blog post.
165
169
    Comments are not filtered by language; a
166
170
    comment made by someone reading the article in Dutch, that's written in
167
171
    Dutch, will show up (unedited) for somebody whom's reading the Spanish
168
172
    version.
169
173
    """
170
174
    # Allows me to manually hide certain messages if need be
171
175
    visible = models.BooleanField(default=True)
172
176
    date = models.DateTimeField(auto_now_add=True)
173
177
    name = models.CharField(max_length=64, blank=True)
174
178
    text = models.TextField(max_length=10000, blank=False)  # Should be more than enough
175
179
    # reaction_to is null if it's not a reaction to an existing comment
176
180
    reaction_to = models.ForeignKey('Comment', on_delete=models.CASCADE, null=True)
177
181
    from_myself = models.BooleanField(default=False)
178
182
    post = models.ForeignKey(
179
183
        Post,
180
184
        on_delete=models.CASCADE,
181
185
        null=False,
182
186
        )
183
187
    class meta:
184
188
        ordering = ['date']  # When printed, prints the oldest comment first.
185
189
186
190
    def reactions(self):
187
191
        # Should return the comments that are a reaction to this comment
188
192
        return Comment.objects.filter(reaction_to=self).order_by('-date')
189
193
+
194
        return str(self.id) +" | "+ self.name
+
195
190
196
class FeedItem(models.Model):
191
197
    """ An item that shows up in the RSS feed."""
192
198
    title = models.CharField(max_length=64)
193
199
    added = models.DateTimeField(auto_now_add=True)
194
200
    description = models.CharField(max_length=400)
195
201
    link = models.URLField()
196
202

templates/blog/comment.djhtml

1 addition and 0 deletions.

View changes Hide changes
1
1
{% load humanize %}
2
2
3
3
<div class="comment" id="reago-{{ comment.id }}">
4
4
    <p><a href="#reago-{{ comment.id }}">#{{ comment.id }}</a>
5
5
        {{ comment.name }} |
6
6
        {{ comment.date|naturaltime }} 
7
7
       ({{ comment.date|date:"SHORT_DATE_FORMAT" }})
8
8
    </p>
9
9
    <p>{{ comment.text|urlize }}</p>
10
10
    <details>
11
11
        <summary>{% translate "Respond" %}</summary>
12
12
        <form method="POST">
13
13
            {% csrf_token %}
14
14
            <input type="hidden" name="reaction_to" value="{{ comment.id }}">
15
15
            <input type="text" id="name-{{ comment.id }}" name="name" maxlength="64" required>
+
16
            <input type="text" id="name-{{ comment.id }}" name="name" maxlength="64" required>
16
17
            <label for="name-{{ comment.id }}">{% translate "Your name" %}</label><br>
17
18
            <textarea name="text" id="text-{{ comment.id }}" maxlength="10000" required></textarea>
18
19
            <label for="text-{{ comment.id }}">{% translate "Your comment" %}</label><br>
19
20
            <input type="submit" value="{% translate "Submit" %}">
20
21
        </form>
21
22
    </details>
22
23
    {% for subcomment in comment.reactions %}
23
24
        {% include "blog/comment.djhtml" with comment=subcomment %}
24
25
    {% endfor %}
25
26
</div>
26
27

templates/blog/post.djhtml

9 additions and 20 deletions.

View changes Hide changes
1
1
{% load humanize %}
2
2
{% load i18n %}
3
3
{% load static %}
4
4
5
5
6
6
{% block stylesheets %}
7
7
{{ block.super }}
8
8
<style>
9
9
@font-face {
10
10
  font-family: 'Merriweather';
11
11
  font-style: italic;
12
12
  font-weight: 400;
13
13
  src: url({% get_static_prefix %}fonts/merriweather-400-italic.woff2) format('woff2');
14
14
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
15
15
}
16
16
@font-face {
17
17
  font-family: 'Merriweather';
18
18
  font-style: normal;
19
19
  font-weight: 400;
20
20
  src: url({% get_static_prefix %}fonts/merriweather-400-regular.woff2) format('woff2');
21
21
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
22
22
}
23
23
@font-face {
24
24
  font-family: 'Merriweather';
25
25
  font-style: normal;
26
26
  font-weight: 700;
27
27
  src: url({% get_static_prefix %}fonts/merriweather-700-regular.woff2) format('woff2');
28
28
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
29
29
}
30
30
31
31
body {
32
32
    background-color: #0d1521; /*#0d47a1; /* Material blue P900 */
33
33
}
34
34
body video {
35
35
    width: 80%;
36
36
}
37
37
header {
38
38
    background-color: #3e2723;
39
39
}
40
40
section.article {
41
41
    background-color: #efebe9;/*rgb(210, 188, 157);*/
42
42
    font-family: Merriweather, serif;
43
43
}
44
44
</style>
+
45
.comment {
+
46
    margin-left: 1em;
+
47
    padding-left: 1em;
+
48
    border-left-style: solid;
+
49
    border-color: var(--primary);
+
50
}
+
51
</style>
45
52
{% endblock stylesheets %}
46
53
47
54
{% block description %}
48
55
{{ article.text|safe|truncatewords_html:10 }}
49
56
{% endblock description %}
50
57
{% block title %}📚 {{ navbar_title }}{% endblock title %}
51
58
52
59
53
60
{% block header %}
54
61
<header>
55
62
<h1>{{ navbar_title }}</h1>
56
63
</header>
57
64
{% endblock header %}
58
65
{% block main %}
59
66
<section class="article">
60
67
    <!--<article style="font-family:serif;">-->
61
68
    {#{{ article.text|safe }}#}
62
69
    {% include "/tmp/django-templates/blog-file.djhtml" %}
63
-
+
70
64
71
    <!--</article>-->
65
72
</section>
66
73
<section class="reagoj">
67
74
    <h2>{% translate "Comments" %}</h2>
68
75
    <form method="POST">
69
76
        {% csrf_token %}
70
77
        <input type="hidden" name="reaction_to" value="">
71
78
        <input type="text" id="name-root" name="name" maxlength="64" required>
+
79
        <input type="text" id="name-root" name="name" maxlength="64" required>
72
80
        <label for="name-root">{% translate "Your name" %}</label><br>
73
81
        <textarea name="text" id="text-root" maxlength="10000" required></textarea>
74
82
        <label for="text-root">{% translate "Your comment" %}</label><br>
75
83
        <input type="submit" value="{% translate "Submit" %}">
76
84
    </form>
77
85
    <hr>
78
86
    {% for root_comment in root_comments %}
79
87
        {% include "blog/comment.djhtml" with comment=root_comment %}
80
88
    {% endfor %}
81
89
</section>
82
90
83
91
{% comment %}
84
92
<h5 class="white-text">{% trans "This article in other languages" %}</h5>
85
93
86
94
{% get_language_info for 'nl' as LANG %}
87
95
<a {% if dutch_link %} href="{{dutch_link}}" {% endif %}
88
96
   class="btn fill
89
97
   {% if not dutch_link %}disabled{% endif %}">
90
98
    🇧🇪 {{ LANG.name_translated}} 🇳🇱
91
99
</a>
92
100
{% get_current_language as lang %}
93
101
{% get_language_info for 'fr' as LANG %}
94
102
<a {% if french_link %} href="{{french_link}}" {% endif %}
95
103
   class="btn fill
96
104
   {% if not french_link %}disabled{% endif %}">
97
105
    🇧🇪 {{ LANG.name_translated}} 🇫🇷
98
106
</a>
99
107
{% get_language_info for 'en' as LANG %}
100
108
<a {% if english_link %} href="{{english_link}}" {% endif %}
101
109
   class="btn fill
102
110
   {% if not english_link %}disabled{% endif %}">
103
111
    🇬🇧 {{ LANG.name_translated}} 🇺🇸
104
112
</a>
105
113
{% get_language_info for 'de' as LANG %}
106
114
<a {% if german_link %} href="{{german_link}}" {% endif %}
107
115
   class="btn fill
108
116
   {% if not german_link %}disabled{% endif %}">
109
117
    🇧🇪 {{ LANG.name_translated}} 🇩🇪
110
118
</a>
111
119
{% get_language_info for 'es' as LANG %}
112
120
<a {% if spanish_link %} href="{{spanish_link}}" {% endif %}
113
121
   class="btn
114
122
   {% if not spanish_link %}disabled{% endif %}">
115
123
    🇪🇸 {{ LANG.name_translated}} 🇲🇽
116
124
</a>
117
125
{% endcomment %}
118
126
119
127
<h5 class="white-text">{% trans "Comments" %}</h5>
120
-
{% for comment in comments %} {# Whoops =P #}
121
-
    <span class="white-text">{{ comment.name|title }} | </span>
122
-
    <time class="grey-text" datetime="{{ comment.date|date:'c' }}">{{ comment.date|naturaltime }}</time>
123
-
    <br />
124
-
    <p class="white-text">{{ comment.text|urlize }}</p>
125
-
    <hr />
126
-
{% endfor %}
127
-
    {# Form for new comment #}
128
-
    <form action="" method="POST">
129
-
        {% csrf_token %}
130
-
        {{ form.name.label_tag }}
131
-
        <input class="white-text browser-default" type="text" id="id_name" name="name" maxlength="64" required />
132
-
        {{ form.text.label_tag }}
133
-
        <textarea id="id_text" class="white-text" name="text" maxlength="1000" required></textarea>
134
-
        <input type="submit" value="{% trans "Submit" %}" />
135
-
    </form>
136
-
137
-
138
-
{% comment %}
139
128
<a href="{% url 'blog-post' post_slug %}" class="btn {{accent_color}} accent-4 black-text tooltipped" data-position="bottom" data-delay="50" data-tooltip="{% trans "Multilingual link. Links to the version in the viewer's preferred language." %}">🏳️‍🌈 {% trans "All available languages" %}</a>
140
129
    {# TODO: Change to rainbow flag when possible #}
141
130
{% endcomment %}
142
131
    </div>
143
132
144
133
</div>
145
134
{% endblock main %}
146
135

views.py

8 additions and 51 deletions.

View changes Hide changes
1
1
import requests
2
2
3
3
4
4
from django.utils.translation import ugettext as _
5
5
from django.shortcuts import get_object_or_404, render # This allows to render the template with the view here. It's pretty cool and important.
6
6
from django.http import HttpResponseRedirect, HttpResponse
7
7
from django.urls import reverse
8
8
from django.template import loader # This allows to actually load the template.
9
9
from .models import *
10
10
from .forms import CommentForm
11
11
from django.core.exceptions import ObjectDoesNotExist
12
12
from django.utils import translation
13
13
14
14
GERMAN = "de"
15
15
SPANISH = "es"
16
16
FRENCH = "fr"
17
17
DUTCH = "nl"
18
18
ENGLISH = "en"
19
19
20
20
def generate_comments_section(post, comment=None):
21
-
    """Since it's possible to comment on a comment, the comment section needs to
22
-
    be built recursively, which the DTL can't do. So I'll have to prepare it in
23
-
    here, generating the DTL code for the comment section.
24
-
    The returned code should then be rendered using Django's template engine,
25
-
    with appropriate context and request data."""
26
-
    code = ""
27
-
    if comment is None:  # Initial call to the function
28
-
        # To make sure the template formats correctly, we need to build it here
29
-
        # with code
30
-
        code += '<div id="reagoj">\n'
31
-
        root_comments = Comment.objects.filter(reaction_to=None).order_by('-date')
32
-
        for root_comment in root_comments:
33
-
            code += generate_comments_section(post, comment=root_comment)
34
-
    else:
35
-
        code += '<div class="comment" id="reago-'+str(comment.id)+'">\n'
36
-
        code += '<p>{{ comments.'+ str(comment.id) +'.name }} | '
37
-
        code += '{{ comments.'+ str(comment.id) +'.date|naturaltime }} '
38
-
        code += '({{ comments.'+ str(comment.id) +'.date|date:"SHORT_DATE_FORMAT" }})'
39
-
        code += '</p>\n'
40
-
        #code += '<time class="grey-text" datetime="{{ comment.date|date:'c' }}">{{ comment.date|naturaltime }}</time>'
41
-
        code += '<p>{{ comment.'+ str(comment.id) +'.text|urlize }}</p>\n'
42
-
        code += '<summary><details>'
43
-
        code += _('Respond')
44
-
        code += '</details>\n'
45
-
        code += '<form method="POST">\n'
46
-
        code += '{% csrf_token %}\n'
47
-
        code += '<input type="hidden" name="reaction_to" value="'+ str(comment.id) +'">\n'
48
-
        code += '<input type="text" name="name" maxlength="64" required>\n'
49
-
        code += '<textarea id="id_text" name="text" maxlength="10000" required></textarea>\n'
50
-
        code += '<input type="submit" value="'+ _("Submit") +'">\n'
51
-
        code += '</form></details>\n'
52
-
53
-
        # This comment is now written, so let's add the subcomments to this comment
54
-
        subcomments = Comment.objects.filter(reaction_to=comment).order_by('-date')
55
-
        for subcomment in subcomments:
56
-
            code += generate_comments_section(post, comment=subcomment)
57
-
58
-
    # At this point, everything related to this comment is written, so writeback
59
-
    code += '</div>'
60
-
    return code
61
-
62
-
def index(request):
63
21
    template = "blog/index.djhtml"
64
22
    posts = Post.objects.exclude(visible=False)
65
23
66
24
67
25
    context = {
68
26
            'posts': posts,
69
27
            'navbar_title': _("Notepad from a student"),
70
28
            'navbar_backArrow': True,
71
29
            'stylesheet_name': "blog",
72
30
            }
73
31
    return render(request, template, context)
74
32
75
33
def post(request, language_code, post_slug):
76
34
    if request.method == "POST":  # Handling a reply if one is sent
77
35
        form = CommentForm(request.POST)
78
36
        for post in Post.objects.all():
79
-
            if post.slug(language) == post_slug:
80
-
                form.post = post
81
-
                break
82
-
        if form.is_valid():
+
37
        form.post = Post.objects.get(id=request.POST['post'])
+
38
        if form.is_valid():
83
39
            new_comment = form.save(commit=False)
84
40
            for post in Post.objects.all():
85
-
                if post.slug(language) == post_slug:
86
-
                    new_comment.post = post
87
-
                    new_comment.save()
88
-
+
41
                new_comment.reaction_to = Comment.objects.get(id=request.POST['reaction_to'])
+
42
            new_comment.save()
+
43
        else:
+
44
            print("ERROR")
+
45
            print(form.errors)
+
46
89
47
    template = "blog/post.djhtml"
90
48
    article = Article.objects.get(slug=post_slug, language_code=language_code)
91
49
    root_comments = Comment.objects.filter(post=article.post, reaction_to=None)
92
50
    context = {
93
51
            'article': article,
94
52
            'navbar_title': article.post.title(),
95
-
            'root_comments': root_comments,
96
53
            'title': article.post.title(),
97
54
            'navbar_title': article.post.title(),
98
55
            'navbar_backArrow': True,
99
56
            'stylesheet_name': "blog"}
100
57
101
58
    return render(request, template, context)
102
59
103
60
def rss(request):
104
61
    template = "blog/feed.rss"
105
62
    context = {
106
63
        'items': FeedItem.objects.all(),
107
64
        }
108
65
    return render(request, template, context, content_type="application/rss+xml")
109
66
110
67
111
68
def archive(request):
112
69
    template = "blog/monthly_archive.djhtml"
113
70
    language = translation.get_language()
114
71
115
72
    file_2017 = org_to_html("blog/weekly/2017.org")
116
73
    file_2018 = org_to_html("blog/weekly/2018.org")
117
74
    file_2019 = org_to_html("blog/weekly/2019.org")
118
75
119
76
120
77
121
78
    context = {
122
79
        't2017': file_2017,
123
80
        't2018': file_2018,
124
81
        't2019': file_2019,
125
82
            'materialDesign_color': "brown",
126
83
            'materialDesign_accentColor': "blue",
127
84
            'navbar_title': _("Weekly-archief"),
128
85
            'navbar_backArrow': True,
129
86
            'footer_links': footer_links,
130
87
            'footer_description': footer_description,
131
88
            'stylesheet_name': "blog",
132
89
            }
133
90
    return render(request, template, context)
134
91