blog

Big overhaul for 2022

Author
Maarten Vangeneugden
Date
Feb. 20, 2022, 5:55 p.m.
Hash
68708a08cb93b5efe5d9d30733855940c45a0c46
Parent
d3256e09ca8dd1f736407a83edf49f2ca60d16d6
Modified files
models.py
templates/blog/index.djhtml
templates/blog/post.djhtml
urls.py
views.py

models.py

125 additions and 116 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
import datetime
+
5
import datetime
5
6
import os
6
7
7
8
def post_title_directory(instance, filename):
8
-
    """ Files will be uploaded to MEDIA_ROOT/blog/<year of publishing>/<blog
9
-
    title>
10
-
    The blog title is determined by the text before the first period (".") in
11
-
    the filename. So if the file has the name "Trains are bæ.en.md", the file
12
-
    will be stored in "blog/<this year>/Trains are bæ". Name your files
13
-
    properly!
14
-
    It should also be noted that all files are stored in the same folder if they
15
-
    belong to the same blogpost, regardless of language. The titles that are
16
-
    displayed to the user however, should be the titles of the files themselves,
17
-
    which should be in the native language. So if a blog post is titled
18
-
    "Universities of Belgium", its Dutch counterpart should be titled
19
-
    "Universiteiten van België", so the correct title can be derived from the
20
-
    filename.
21
-
22
-
    Recommended way to name the uploaded file: "<name of blog post in language
23
-
    it's written>.org". This removes the maximum amount of redundancy (e.g. the
24
-
    language of the file can be derived from the title, no ".fr.org" or something
25
-
    like that necessary), and can directly be used for the end user (the title
26
-
    is what should be displayed).
27
-
    """
+
9
- For each post, there's no longer a mandatory Dutch and English
+
10
  version. Instead, only the title needs to be in multiple languages.
+
11
- There's a new table for the links to the articles themselves. These include a
+
12
  language code and a foreign key to the post they belong to.
+
13
- If an article is available in the active language, but not tagged for the same
+
14
  dialect, then it should just show up without any warnings.
+
15
- If an article is not available in the active language, only the title should
+
16
  show up, but where the short intro text would normally be, there should be an
+
17
  explanation that it's only available in other languages, and provide links to
+
18
  those versions.
+
19
"""
+
20
+
21
def org_to_html(file_path):
+
22
    """ Converts the given org formatted file to HTML.
+
23
    This function directly returns the resulting HTML code. This function uses
+
24
    the amazing Haskell library Pandoc to convert the file (and takes care
+
25
    of header id's and all that stuff).
+
26
    """
28
27
    english_file_name = os.path.basename(instance.english_file.name) # TODO: Test if this returns the file name!
29
-
    english_title = english_file_name.rpartition(".")[0]
30
-
    year = datetime.date.today().year
31
-
+
28
    # XXX: The reason I'm first converting all occurences of .jpg][ and .png][
+
29
    # to .jpgPANDOCBUG][ and .pngPANDOCBUG][, is because of a Pandoc bug that
+
30
    # removes the text links for images. It is afterwards converted back, no
+
31
    # worries.
+
32
    file = open("/srv/django/website/media/"+file_path, "r", encoding="utf-8")
+
33
    text = file.read()
+
34
    file.close()
+
35
    text = text.replace(".jpg][", ".jpgPANDOCBUG][")
+
36
    text = text.replace(".png][", ".pngPANDOCBUG][")
+
37
    file = open("/tmp/blog-file.org", "w", encoding="utf-8")
+
38
    file.write(text)
+
39
    file.close()
+
40
    html_text = subprocess.check_output(["pandoc", "--from=org", "--to=html","/tmp/blog-file.org"])
+
41
    html_text = html_text.decode("utf-8").replace(".jpgPANDOCBUG", ".jpg")
+
42
    html_text = html_text.replace(".pngPANDOCBUG", ".png")
+
43
    return html_text
+
44
+
45
class Article(models.Model):
+
46
    AFRIKAANS = 'af'
+
47
    BELGIAN_FRENCH = 'fr-be'
+
48
    DUTCH = 'nl'
+
49
    ESPERANTO = 'eo'
+
50
    FLEMISH = 'nl-be'
+
51
    FRENCH = 'fr'
+
52
    GERMAN = 'de'
+
53
    SPANISH = 'es'
+
54
+
55
    LANGUAGE_CODES = [
+
56
        (AFRIKAANS, 'Afrikaans'),
+
57
        (BELGIAN_FRENCH, 'Français (Belgique)'),
+
58
        (DUTCH, 'Nederlands'),
+
59
        (ESPERANTO, 'Esperanto'),
+
60
        (FLEMISH, 'Vlaams'),
+
61
        (FRENCH, 'Français'),
+
62
        (GERMAN, 'Deutsch'),
+
63
        (SPANISH, 'Español')]
+
64
+
65
    # auto_now_add should normally be True, but by changing a lot of the
+
66
    # internals I had to temporary disable it
+
67
    visible = models.BooleanField(default=True)
+
68
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
+
69
    language_code = models.CharField(max_length=16,
+
70
                                      choices = LANGUAGE_CODES,
+
71
                                      blank=False)
+
72
    # file_path shouldn't be unique, because the same article file could be used
+
73
    # for multiple dialects of the same language.
+
74
    file_path = models.FilePathField(path=settings.MEDIA_ROOT + "blog/articles/",
+
75
                                     blank=False)
+
76
    # Same reason, slug shouldn't be unique
+
77
    slug = models.SlugField(unique=False, blank=False, allow_unicode=True)
+
78
+
79
    def text(self):
+
80
        return org_to_html(self.file_path)
+
81
+
82
    def title(self):
+
83
        return self.post.title(self.language_code)
+
84
        
+
85
32
86
    return "blog/{0}/{1}/{2}".format(year, english_title, filename)
33
-
34
87
class Post(models.Model):
35
88
    """ Represents a blog post. The title of the blog post is determnined by the name
36
-
    of the files.
37
-
    A blog post can be in 5 different languages: German, Spanish, English, French,
38
-
    and Dutch. For all these languages, a seperate field exists. Thus, a
39
-
    translated blog post has a seperate file for each translation, and is
40
-
    seperated from Django's internationalization/localization system.
41
-
    Only the English field is mandatory. The others may contain a value if a
42
-
    translated version exists, which will be displayed accordingly.
43
-
    """
44
-
    published = models.DateTimeField(auto_now_add=True)
45
-
    english_file = models.FileField(upload_to=post_title_directory, blank=False)
46
-
    dutch_file = models.FileField(upload_to=post_title_directory, blank=False)
47
-
    french_file = models.FileField(upload_to=post_title_directory, blank=True)
48
-
    german_file = models.FileField(upload_to=post_title_directory, blank=True)
49
-
    spanish_file = models.FileField(upload_to=post_title_directory, blank=True)
50
-
+
89
    published = models.DateTimeField(auto_now_add=False)
+
90
51
91
    title_en = models.CharField(max_length=64, unique=True, blank=False)
52
92
    title_nl = models.CharField(max_length=64, unique=True, blank=False)
53
93
    title_fr = models.CharField(max_length=64, blank=True)
54
-
    title_de = models.CharField(max_length=64, blank=True)
55
-
    title_es = models.CharField(max_length=64, blank=True)
56
-
    # PostgreSQL sees two null values as not unique, therefore I can't ask for unique names.
57
-
+
94
    title_de = models.CharField(max_length=64, unique=True, blank=True)
+
95
    title_es = models.CharField(max_length=64, unique=True, blank=True)
+
96
    title_eo = models.CharField(max_length=64, unique=True, blank=True)
+
97
    title_af = models.CharField(max_length=64, unique=True, blank=True)
+
98
58
99
    slug_en  = models.SlugField(unique=True, blank=False, allow_unicode=True)
59
-
    slug_nl  = models.SlugField(unique=True, blank=False, allow_unicode=True)
60
-
    slug_fr  = models.SlugField(blank=True, allow_unicode=True)
61
-
    slug_de  = models.SlugField(blank=True, allow_unicode=True)
62
-
    slug_es  = models.SlugField(blank=True, allow_unicode=True)
63
-
64
100
    def __str__(self):
65
101
        return self.slug("en")
66
-
67
-
    def text_file(self, language_code=translation.get_language()):
68
-
        if language_code == "en":
69
-
            return self.english_file
70
-
        elif language_code == "nl":
71
-
            return self.dutch_file
72
-
        elif language_code == "de":
73
-
            if self.german_file == "":
74
-
                return self.english_file
75
-
            else:
76
-
                return self.german_file
77
-
        elif language_code == "fr":
78
-
            if self.french_file == "":
79
-
                return self.english_file
80
-
            else:
81
-
                return self.french_file
82
-
        elif language_code == "es":
83
-
            if self.spanish_file == "":
84
-
                return self.english_file
85
-
            else:
86
-
                return self.spanish_file
87
-
        return self.english_file
88
-
+
102
+
103
+
104
    def articles(self):
+
105
        return Article.objects.filter(post=self)  
+
106
        
+
107
    def article(self, language_code=translation.get_language()):
+
108
        # Retrieves all articles that have this post as their foreign key
+
109
        articles = Article.objects.filter(post=self)  
+
110
        for a in articles:
+
111
            if a.language_code == language_code:
+
112
                return a
+
113
        # If no exact match was found, try again, but now accept other dialects
+
114
        # as well:
+
115
        for a in articles:
+
116
            if language_code.startswith(a.language_code):
+
117
                return a
+
118
        
+
119
        # If still no article was found, return None
+
120
        return None
+
121
89
122
    def title(self, language_code=translation.get_language()):
90
123
        if language_code == "en":
91
-
            return self.title_en
92
-
        elif language_code == "nl":
93
-
            return self.title_nl
94
-
        elif language_code == "de":
95
-
            if self.title_de == "":
96
-
                return self.title_en
97
-
            else:
98
-
                return self.title_de
99
-
        elif language_code == "fr":
100
-
            if self.title_fr == "":
101
-
                return self.title_en
102
-
            else:
103
-
                return self.title_fr
104
-
        elif language_code == "es":
105
-
            if self.title_es == "":
106
-
                return self.title_en
107
-
            else:
108
-
                return self.title_es
109
-
        return self.title_en
+
124
                   'de': self.title_de,
+
125
                   'es': self.title_es,
+
126
                   'en': self.title_en,
+
127
                   'eo': self.title_eo,
+
128
                   'fr': self.title_fr,
+
129
                   'nl': self.title_nl}
+
130
        for code, translated_title in options.items():
+
131
            if language_code.startswith(code):
+
132
                return translated_title
+
133
        # If no return has happened, default to English
+
134
        return self.title_en
110
135
111
-
    def slug(self, language_code=translation.get_language()):
112
-
        """ Returns a slug of the requested language, or None if no version exists in that language. """
113
-
        if language_code == "en":
114
-
            return self.slug_en
115
-
        elif language_code == "nl":
116
-
            return self.slug_nl
117
-
        elif language_code == "de":
118
-
            if self.slug_de == "":
119
-
                return self.slug_en
120
-
            else:
121
-
                return self.slug_de
122
-
        elif language_code == "fr":
123
-
            if self.slug_fr == "":
124
-
                return self.slug_en
125
-
            else:
126
-
                return self.slug_fr
127
-
        elif language_code == "es":
128
-
            if self.slug_es == "":
129
-
                return self.slug_en
130
-
            else:
131
-
                return self.slug_es
132
-
        return self.slug_en
133
-
+
136
134
137
class Comment(models.Model):
135
138
    """ Represents a comment on a blog post.
136
139
    Comments are not filtered by language; a
137
140
    comment made by someone reading the article in Dutch, that's written in
138
141
    Dutch, will show up (unedited) for somebody whom's reading the Spanish
139
142
    version.
140
143
    """
141
144
    date = models.DateTimeField(auto_now_add=True)
142
-
    name = models.CharField(max_length=64)
143
-
    text = models.TextField(max_length=1000)  # Should be more than enough.
144
-
    post = models.ForeignKey(
+
145
    visible = models.BooleanField(default=True)
+
146
    # auto_now_add should normally be True, but by changing a lot of the
+
147
    # internals I had to temporary disable it
+
148
    date = models.DateTimeField(auto_now_add=False)
+
149
    name = models.CharField(max_length=64, blank=True)
+
150
    text = models.TextField(max_length=10000, blank=False)  # Should be more than enough
+
151
    # reaction_to is null if it's not a reaction to an existing comment
+
152
    reaction_to = models.ForeignKey(Comment, on_delete=models.CASCADE, null=True)
+
153
    post = models.ForeignKey(
145
154
        Post,
146
155
        on_delete=models.CASCADE,
147
156
        null=False,
148
157
        )
149
158
    class meta:
150
159
        ordering = ['date']  # When printed, prints the oldest comment first.
151
160
152
161
class FeedItem(models.Model):
153
162
    """ An item that shows up in the RSS feed."""
154
163
    title = models.CharField(max_length=64)
155
164
    added = models.DateTimeField(auto_now_add=True)
156
165
    description = models.CharField(max_length=400)
157
166
    link = models.URLField()
158
167

templates/blog/index.djhtml

36 additions and 3 deletions.

View changes Hide changes
1
1
{% load i18n %}
2
2
{% load static %}
3
3
4
4
{% block stylesheets %}
5
5
    {{ block.super }}
6
6
    <style>
7
7
    img {
8
8
    width: 80%;
9
9
     display: block;
10
10
  margin-left: auto;
11
11
  margin-right: auto;
12
12
    }
13
13
    video {
14
14
    width: 80%;
15
15
    } 
16
16
    </style>
17
17
{% endblock %}
18
18
19
19
{% block title %}{% trans "Maarten's blog" %}{% endblock title %}
20
20
21
21
{% block description %}{% blocktrans %}The always coherently put together, yet
22
22
fuzzy blog of whatever sprouts in my mind.{% endblocktrans %}
23
23
{% endblock description %}
24
24
25
25
{% block header %}
26
26
<header>                                                                                                                                                                                         
27
27
    <h1>{% trans "Notepad of a student" %}</h1>  
28
28
    <label for="nav-drawer-toggle"></label>
29
29
</header>
30
30
{% endblock header %}
31
31
32
32
{% block nav %}
33
33
<input id="nav-drawer-toggle" type="checkbox" />
34
34
<nav>
35
35
    <label for="nav-drawer-toggle"><!--🡨-->🡠</label>
36
36
    <h2>{% trans "Navigation" %}</h2>
37
37
    {% for title, date, blog_text, link in posts %}
38
38
    <a class="nav-link" href="{{ link }}">{{ title }}</a>
39
39
    {% endfor %}
40
40
    <hr class="half" />
41
41
    <a class="nav-link" href="{% url 'about-index' %}">{% trans "Front page" %}</a>
42
42
  </nav>
43
43
{% endblock nav %}
44
44
45
45
{% block main %}
46
46
47
47
<section class="emphasis">
48
48
    <h1>{% trans "Blog" %}</h1>
49
49
    <p>
50
50
        {% blocktrans %}Welcome to my blog. Here, I write
51
51
        about things that interest me. Politics, coding,
52
52
        studying, life, or anything else I fancy rambling
53
53
        about. If you're in luck, I may've written it in a
54
54
        language that you understand better than English.
55
55
        {% endblocktrans %}
56
56
    </p>
57
57
</section>
58
58
59
59
<div class="fab">
60
60
    <a href="{% url 'blog-feed' %}" id="feed-fab"> 
61
61
    <b>RSS</b>
62
62
    </a>
63
63
</div>
64
64
65
65
<section>
66
66
    <h1>Monthly</h1>
67
67
    <a class="btn fill" href="{% url "monthly-archive" %}"> {% trans "Open archive" %}</a>
68
-
    {% include "blog/monthly.html" %}
+
68
    {% include "blog/monthly.html" %}
69
69
</section>
70
70
71
71
<div class="cards">
72
72
    {% for title, date, blog_text, link in posts %}
+
73
        <div class="card">
+
74
            <h3>{{ post.title }}</h3>
+
75
            <h4>{{ post.published|date:"DATE_FORMAT" }}</h4>
+
76
            {% if post.article %}
+
77
                {# No need for surrounding <p> tags #}
+
78
                {{ post.article_text|safe|truncatewords_html:100 }}
+
79
                {# Pandoc automatically makes those #}
+
80
                <a class="btn outline" href="{% url 'blog-post' post.article.language_code post.article.slug %}">
+
81
                    📚 {% translate "Read on" %}</a>
+
82
            {% else %}
+
83
                {% get_current_language as CUR_LANG %}
+
84
                <p>{% blocktranslate cur_lang=CUR_LANG.name_translated %}This blog
+
85
               post is not available in {{ cur_lang }}.{% endblocktranslate %}
+
86
                    {% blocktranslate count counter=post.articles|length %}
+
87
                    However, it is available in 
+
88
                    {% plural %}
+
89
                    If you want, you can choose to read it in one of these
+
90
                    languages: <br>
+
91
                    {% endblocktranslate %}
+
92
                    {% for article in post.articles %}
+
93
                        {% get_language_info for article.language_code as lang %}
+
94
                        {{ lang.name_translated }}: 
+
95
                        <a href="{% url blog-post article.language_code article.slug %}">
+
96
                            {{ article.title }}
+
97
                        </a>
+
98
                        {% if not forloop.last %}<br>{% endif %}
+
99
                    {% endfor %}
+
100
                </p>
+
101
            {% endif %}
+
102
        </div>
+
103
    {% endfor %}
+
104
    {% comment %}
+
105
    {% for title, date, blog_text, link in posts %}
73
106
        <div class="card">
74
107
            <h3>{{ title }}</h3>
75
108
            <h4>{{ date|date:"DATE_FORMAT" }}</h4>
76
109
        <p>{{ blog_text|safe|truncatewords_html:100 }}</p>
77
-
        <a class="btn outline" href="{{link}}">📚 {% trans "Read on" %}</a>
78
-
        </div>
+
110
        </div>
79
111
    {% endfor %}
80
112
</div>
+
113
</div>
81
114
82
115
{% endblock main %}
83
116

templates/blog/post.djhtml

4 additions and 17 deletions.

View changes Hide changes
1
1
{% load humanize %}
2
2
{% load i18n %}
3
3
{% load static %}
4
4
5
5
{% block description %}
6
6
{{ article|safe|truncatewords_html:10 }}
7
-
{% endblock description %}
+
7
{% endblock description %}
8
8
{% block title %}📚 {{ navbar_title }}{% endblock title %}
9
9
10
10
11
11
{% block header %}
12
12
<header>
13
13
<h1>{{ navbar_title }}</h1>
14
14
</header>
15
15
{% endblock header %}
16
16
{% block main %}
17
17
<section style="font-family: serif;">
18
18
    <!--<article style="font-family:serif;">-->
19
19
        {{ article|safe }}
20
-
    <!--</article>-->
+
20
    <!--</article>-->
21
21
</section>
22
22
23
23
<h5 class="white-text">{% trans "This article in other languages" %}</h5>
+
24
<h5 class="white-text">{% trans "This article in other languages" %}</h5>
24
25
25
26
{% get_language_info for 'nl' as LANG %}
26
27
<a {% if dutch_link %} href="{{dutch_link}}" {% endif %}
27
28
   class="btn fill
28
29
   {% if not dutch_link %}disabled{% endif %}">
29
30
    🇧🇪 {{ LANG.name_translated}} 🇳🇱
30
31
</a>
31
32
{% get_current_language as lang %}
32
33
{% get_language_info for 'fr' as LANG %}
33
34
<a {% if french_link %} href="{{french_link}}" {% endif %}
34
35
   class="btn fill
35
36
   {% if not french_link %}disabled{% endif %}">
36
37
    🇧🇪 {{ LANG.name_translated}} 🇫🇷
37
38
</a>
38
39
{% get_language_info for 'en' as LANG %}
39
40
<a {% if english_link %} href="{{english_link}}" {% endif %}
40
41
   class="btn fill
41
42
   {% if not english_link %}disabled{% endif %}">
42
43
    🇬🇧 {{ LANG.name_translated}} 🇺🇸
43
44
</a>
44
45
{% comment %}
45
-
{% get_language_info for 'de' as LANG %}
46
46
<a {% if german_link %} href="{{german_link}}" {% endif %}
47
47
   class="btn fill
48
48
   {% if not german_link %}disabled{% endif %}">
49
49
    🇧🇪 {{ LANG.name_translated}} 🇩🇪
50
50
</a>
51
51
{% comment %}
52
-
{% get_language_info for 'es' as LANG %}
53
52
<a {% if spanish_link %} href="{{spanish_link}}" {% endif %}
54
53
   class="btn
55
54
   {% if not spanish_link %}disabled{% endif %}">
56
55
    🇪🇸 {{ LANG.name_translated}} 🇲🇽
57
56
</a>
58
57
+
58
59
59
<h5 class="white-text">{% trans "Comments" %}</h5>
60
60
{% for comment in comments %} {# Whoops =P #}
61
61
    <span class="white-text">{{ comment.name|title }} | </span>
62
62
    <time class="grey-text" datetime="{{ comment.date|date:'c' }}">{{ comment.date|naturaltime }}</time>
63
63
    <br />
64
64
    <p class="white-text">{{ comment.text|urlize }}</p>
65
65
    <hr />
66
66
{% endfor %}
67
67
    {# Form for new comment #}
68
68
    <form action="" method="POST">
69
69
        {% csrf_token %}
70
70
        {{ form.name.label_tag }}
71
71
        <input class="white-text browser-default" type="text" id="id_name" name="name" maxlength="64" required />
72
72
        {{ form.text.label_tag }}
73
73
        <textarea id="id_text" class="white-text" name="text" maxlength="1000" required></textarea>
74
74
        <input type="submit" value="{% trans "Submit" %}" />
75
75
    </form>
76
76
77
77
78
78
{% comment %}
79
79
<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>
80
80
    {# TODO: Change to rainbow flag when possible #}
81
81
{% endcomment %}
82
82
    </div>
83
83
84
84
</div>
85
85
<div class="container">
86
-
    {% for title, date, description, link in post_links %}
87
-
        <h2 class="{{ color}}-text">{{ title }}</h2>
88
-
        {# FIXME: Date is in all languages of the same format. Fix for each language #}
89
-
        <span class="grey-text">{{ date|date:"l j F Y" }}</span>
90
-
        {#<p class="hide-on-small-only">{{ description }}</p>#}
91
-
        <p class="hide-on-small-only">{% lorem %}</p>
92
-
        <a class="btn {{accent_color}} accent-3" href="{{link}}">
93
-
            {% trans "Read on"%}
94
-
        </a>
95
-
        <hr />
96
-
    {% endfor %}
97
-
</div>
98
-
{% endblock main %}
99
86

urls.py

10 additions and 2 deletions.

View changes Hide changes
1
-
+
1
2
2
from . import views # Imports the views from the same directory (which is views.py).
3
3
4
4
urlpatterns = [
+
5
    path('', views.index, name='blog-index'),
+
6
    path('feed.rss', views.rss, name='blog-feed'),
+
7
    path('<slug:language_code>/<slug:post_slug>', views.post, name='blog-post'),
+
8
    path('arkivo' views.archive, name='blog-archive'),
+
9
    ]
+
10
+
11
"""
+
12
urlpatterns = [
5
13
    url(r'^$', views.index, name='blog-index'),
6
14
    url(r'^feed.rss$', views.rss, name='blog-feed'),
7
15
    url(r'^(?P<language>(.){2})/(?P<post_slug>(.)+)$', views.post, name='blog-post-language'),
8
16
    url(r'^monthly-archive$', views.monthly_archive, name="monthly-archive"),
9
17
    url(r'^(?P<post_slug>(.)+)$', views.post, name='blog-post'),
10
18
        ]
11
19
12
-
+
20

views.py

15 additions and 56 deletions.

View changes Hide changes
1
1
import subprocess
2
2
import requests
3
3
4
4
5
5
from django.utils.translation import ugettext as _
6
6
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.
7
7
from django.http import HttpResponseRedirect, HttpResponse
8
8
from django.urls import reverse
9
9
from django.template import loader # This allows to actually load the template.
10
10
from .models import *
11
11
from .forms import CommentForm
12
12
from django.core.exceptions import ObjectDoesNotExist
13
13
from django.utils import translation
14
14
15
15
GERMAN = "de"
16
16
SPANISH = "es"
17
17
FRENCH = "fr"
18
18
DUTCH = "nl"
19
19
ENGLISH = "en"
20
20
21
21
footer_links = [
22
-
        [_("Back to main page"), "/blog"],
23
-
        [_("Contact"), "mailto:maarten.vangeneugden@student.uhasselt.be"],
24
-
        ]
25
-
footer_description = _("Maarten's personal blog, with sprinkles and a dollop of healthy bugs.")
26
-
27
-
def org_to_html(file_path):
28
-
    """ Converts the given org formatted file to HTML.
29
-
    This function directly returns the resulting HTML code. This function uses
30
-
    the amazing Haskell library Pandoc to convert the file (and takes care
31
-
    of header id's and all that stuff).
32
-
    """
33
-
    # FIXME: Remove hardcoded link to media. Replace with media tag!
34
-
    # XXX: The reason I'm first converting all occurences of .jpg][ and .png][
35
-
    # to .jpgPANDOCBUG][ and .pngPANDOCBUG][, is because of a Pandoc bug that
36
-
    # removes the text links for images. It is afterwards converted back, no
37
-
    # worries.
38
-
    file = open("/srv/django/website/media/"+file_path, "r", encoding="utf-8")
39
-
    text = file.read()
40
-
    file.close()
41
-
    text = text.replace(".jpg][", ".jpgPANDOCBUG][")
42
-
    text = text.replace(".png][", ".pngPANDOCBUG][")
43
-
    file = open("/tmp/blog-file.org", "w", encoding="utf-8")
44
-
    file.write(text)
45
-
    file.close()
46
-
    html_text = subprocess.check_output(["pandoc", "--from=org", "--to=html","/tmp/blog-file.org"])
47
-
    html_text = html_text.decode("utf-8").replace(".jpgPANDOCBUG", ".jpg")
48
-
    html_text = html_text.replace(".pngPANDOCBUG", ".png")
49
-
    return html_text
50
-
51
22
def get_available_post_languages(post):
52
23
    """ Returns the language codes for which a blog post exists. This function
53
24
    always returns English (because that field mustn't be empty).
54
25
    So say a blog post has an English, Dutch and French version (which means
55
26
    english_file, french_file and dutch_file aren't empty), the function will return {"en",
56
27
    "fr", "nl"}. """
57
28
    available_languages = {ENGLISH}
58
29
    if post.german_file != "":
59
30
        available_languages.add(GERMAN)
60
31
    if post.spanish_file != "":
61
32
        available_languages.add(SPANISH)
62
33
    if post.french_file != "":
63
34
        available_languages.add(FRENCH)
64
35
    if post.dutch_file != "":
65
36
        available_languages.add(DUTCH)
66
37
    return available_languages
67
38
68
39
def index(request):
69
40
    template = "blog/index.djhtml"
70
41
    posts = Post.objects.all()
71
42
    language = translation.get_language()
72
-
73
43
    post_links = []
74
-
    for post in posts:
75
-
        blog_file = post.text_file(language)
76
-
        blog_text = org_to_html(blog_file.name)
77
-
        # TODO: The link can possibly be reversed in the DTL using the title, which is actually
78
-
        # a cleaner way to do it. Investigate.
79
-
        link = reverse("blog-post-language", args=[language, post.slug(language)])
80
-
        post_links.append([post.title(language), post.published, blog_text, link])
81
-
82
44
    context = {
83
45
            'posts': post_links,
84
-
            'materialDesign_color': "brown",
85
-
            'materialDesign_accentColor': "blue",
86
-
            'navbar_title': _("Notepad from a student"),
+
46
            'navbar_title': _("Notepad from a student"),
87
47
            'navbar_backArrow': True,
88
48
            'footer_links': footer_links,
89
-
            'footer_description': footer_description,
90
-
            'stylesheet_name': "blog",
91
49
            }
92
50
    if not request.session.get("feed-fab-introduction-seen", default=False):
93
-
        context['introduce_feed'] = True
94
-
        request.session['feed-fab-introduction-seen'] = True
95
-
    return render(request, template, context)
96
51
97
52
def post(request, post_slug, language=None):
98
-
    if request.method == "POST":  # Handling a reply if one is sent
+
53
    if request.method == "POST":  # Handling a reply if one is sent
99
54
        form = CommentForm(request.POST)
100
55
        for post in Post.objects.all():
101
56
            if post.slug(language) == post_slug:
102
57
                form.post = post
103
58
                break
104
59
        if form.is_valid():
105
60
            new_comment = form.save(commit=False)
106
61
            for post in Post.objects.all():
107
62
                if post.slug(language) == post_slug:
108
63
                    new_comment.post = post
109
64
                    new_comment.save()
110
65
    if language is not None:
111
-
        if translation.check_for_language(language):
112
-
            translation.activate(language)
113
-
            request.session[translation.LANGUAGE_SESSION_KEY] = language
114
-
            #return post(request, post_slug)
115
-
    else:
116
-
        language = translation.get_language()
117
-
118
66
    template = "blog/post.djhtml"
119
67
    posts = Post.objects.all()
120
-
    #comments = Comment.objects.filter(post
+
68
    comments = Comment.objects.filter(post=article.post)
+
69
    context = {
+
70
            'article': article,
+
71
            'navbar_title': article.post.title(),
+
72
            'title': article.post.title(),
+
73
            'navbar_title': article.post.title(),
+
74
            'navbar_backArrow': True,
+
75
            'stylesheet_name': "blog",
+
76
    #posts = Post.objects.all()
+
77
    #comments = Comment.objects.filter(post
121
78
    for post in posts:
+
79
    for post in posts:
122
80
        if post.slug(language) == post_slug:
123
81
            comments = Comment.objects.filter(post=post)
124
82
            form = CommentForm()
125
83
            post_file = post.text_file(language)
126
84
            post_text = org_to_html(post_file.name)
127
85
            context = {
128
86
                'comments': comments,
129
87
                'form' : form,
130
88
                'human_post_title': post.title(language),
131
89
                'materialDesign_color': "brown",
132
90
                'materialDesign_accentColor': "blue",
133
91
                'article': post_text,
134
92
                'title': post.title(language),
135
93
                'navbar_title': post.title(language),
136
94
                'navbar_backArrow': False,
137
95
                'post_slug': post_slug,
138
96
                'footer_links': footer_links,
139
97
                'footer_description': footer_description,
140
98
                'stylesheet_name': "blog",
141
99
                }
142
100
143
101
            # Getting all available article links
144
102
            available = get_available_post_languages(post)
145
103
            if ENGLISH in available:
146
104
                context['english_link'] = reverse("blog-post-language", args=[ENGLISH, post.slug(ENGLISH)])
147
105
            if DUTCH in available:
148
106
                context['dutch_link'] = reverse("blog-post-language", args=[DUTCH, post.slug(DUTCH)])
149
107
150
108
            if FRENCH in available:
151
109
                context['french_link'] = reverse("blog-post-language", args=[FRENCH, post.slug(FRENCH)])
152
110
153
111
            if SPANISH in available:
154
112
                context['spanish_link'] = reverse("blog-post-language", args=[SPANISH, post.slug(SPANISH)])
155
113
156
114
            if GERMAN in available:
157
115
                context['german_link'] = reverse("blog-post-language", args=[GERMAN, post.slug(GERMAN)])
158
116
+
117
159
118
            return render(request, template, context)
160
-
+
119
161
120
def rss(request):
162
121
    template = "blog/feed.rss"
163
122
    context = {
164
123
        'items': FeedItem.objects.all(),
165
124
        }
166
125
    return render(request, template, context, content_type="application/rss+xml")
167
126
168
127
169
128
def monthly_archive(request):
170
129
    template = "blog/monthly_archive.djhtml"
171
130
    language = translation.get_language()
172
131
173
132
    file_2017 = org_to_html("blog/weekly/2017.org")
174
133
    file_2018 = org_to_html("blog/weekly/2018.org")
175
134
    file_2019 = org_to_html("blog/weekly/2019.org")
176
135
177
136
178
137
179
138
    context = {
180
139
        't2017': file_2017,
181
140
        't2018': file_2018,
182
141
        't2019': file_2019,
183
142
            'materialDesign_color': "brown",
184
143
            'materialDesign_accentColor': "blue",
185
144
            'navbar_title': _("Weekly-archief"),
186
145
            'navbar_backArrow': True,
187
146
            'footer_links': footer_links,
188
147
            'footer_description': footer_description,
189
148
            'stylesheet_name': "blog",
190
149
            }
191
150
    return render(request, template, context)
192
151