diff --git a/blango/__pycache__/__init__.cpython-36.pyc b/blango/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000..cd5352275a Binary files /dev/null and b/blango/__pycache__/__init__.cpython-36.pyc differ diff --git a/blango/__pycache__/settings.cpython-36.pyc b/blango/__pycache__/settings.cpython-36.pyc new file mode 100644 index 0000000000..0029d55222 Binary files /dev/null and b/blango/__pycache__/settings.cpython-36.pyc differ diff --git a/blango/__pycache__/urls.cpython-36.pyc b/blango/__pycache__/urls.cpython-36.pyc new file mode 100644 index 0000000000..0a9c42cbfd Binary files /dev/null and b/blango/__pycache__/urls.cpython-36.pyc differ diff --git a/blango/__pycache__/wsgi.cpython-36.pyc b/blango/__pycache__/wsgi.cpython-36.pyc new file mode 100644 index 0000000000..fd827eac37 Binary files /dev/null and b/blango/__pycache__/wsgi.cpython-36.pyc differ diff --git a/blango/settings.py b/blango/settings.py index f9209bef27..508851e88f 100644 --- a/blango/settings.py +++ b/blango/settings.py @@ -10,8 +10,10 @@ https://docs.djangoproject.com/en/3.2/ref/settings/ """ +import os from pathlib import Path + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -25,8 +27,14 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] - +ALLOWED_HOSTS = ['*'] +X_FRAME_OPTIONS = 'ALLOW-FROM ' + os.environ.get('CODIO_HOSTNAME') + '-8000.codio.io' +CSRF_COOKIE_SAMESITE = None +CSRF_TRUSTED_ORIGINS = ['https://' + os.environ.get('CODIO_HOSTNAME') + '-8000.codio.io'] +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True +CSRF_COOKIE_SAMESITE = 'None' +SESSION_COOKIE_SAMESITE = 'None' # Application definition @@ -37,16 +45,17 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'blog', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', + #'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + #'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'blango.urls' @@ -54,7 +63,7 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -123,3 +132,5 @@ # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + diff --git a/blango/urls.py b/blango/urls.py index cde05802f9..cbde8ad2dc 100644 --- a/blango/urls.py +++ b/blango/urls.py @@ -15,7 +15,9 @@ """ from django.contrib import admin from django.urls import path +import blog.views urlpatterns = [ path('admin/', admin.site.urls), + path("", blog.views.index) ] diff --git a/blog/__init__.py b/blog/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/blog/__pycache__/__init__.cpython-36.pyc b/blog/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000..b95e82d76c Binary files /dev/null and b/blog/__pycache__/__init__.cpython-36.pyc differ diff --git a/blog/__pycache__/admin.cpython-36.pyc b/blog/__pycache__/admin.cpython-36.pyc new file mode 100644 index 0000000000..bbcca53a8e Binary files /dev/null and b/blog/__pycache__/admin.cpython-36.pyc differ diff --git a/blog/__pycache__/apps.cpython-36.pyc b/blog/__pycache__/apps.cpython-36.pyc new file mode 100644 index 0000000000..7ba0b0b5e5 Binary files /dev/null and b/blog/__pycache__/apps.cpython-36.pyc differ diff --git a/blog/__pycache__/models.cpython-36.pyc b/blog/__pycache__/models.cpython-36.pyc new file mode 100644 index 0000000000..ce7142243f Binary files /dev/null and b/blog/__pycache__/models.cpython-36.pyc differ diff --git a/blog/__pycache__/views.cpython-36.pyc b/blog/__pycache__/views.cpython-36.pyc new file mode 100644 index 0000000000..4914adcddf Binary files /dev/null and b/blog/__pycache__/views.cpython-36.pyc differ diff --git a/blog/admin.py b/blog/admin.py new file mode 100644 index 0000000000..b23130c001 --- /dev/null +++ b/blog/admin.py @@ -0,0 +1,10 @@ +from django.contrib import admin +from blog.models import Tag, Post, Comment + +class PostAdmin(admin.ModelAdmin): + prepopulated_fields = {"slug": ("title",)} + +# Register your models here. +admin.site.register(Tag) +admin.site.register(Post, PostAdmin) +admin.site.register(Comment) \ No newline at end of file diff --git a/blog/apps.py b/blog/apps.py new file mode 100644 index 0000000000..94788a5eac --- /dev/null +++ b/blog/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BlogConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'blog' diff --git a/blog/migrations/0001_initial.py b/blog/migrations/0001_initial.py new file mode 100644 index 0000000000..326016aac8 --- /dev/null +++ b/blog/migrations/0001_initial.py @@ -0,0 +1,39 @@ +# Generated by Django 3.2.5 on 2026-07-13 19:07 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('value', models.TextField(max_length=100)), + ], + ), + migrations.CreateModel( + name='Post', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('modified_at', models.DateTimeField(auto_now=True)), + ('published_at', models.DateTimeField(blank=True, null=True)), + ('title', models.TextField(max_length=100)), + ('slug', models.SlugField()), + ('summary', models.TextField(max_length=500)), + ('content', models.TextField()), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), + ('tags', models.ManyToManyField(related_name='posts', to='blog.Tag')), + ], + ), + ] diff --git a/blog/migrations/0002_comment.py b/blog/migrations/0002_comment.py new file mode 100644 index 0000000000..ca99b79c54 --- /dev/null +++ b/blog/migrations/0002_comment.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.5 on 2026-07-13 23:01 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('blog', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('content', models.TextField()), + ('object_id', models.PositiveIntegerField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('modified_at', models.DateTimeField(auto_now=True)), + ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), + ('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/blog/migrations/__init__.py b/blog/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/blog/migrations/__pycache__/0001_initial.cpython-36.pyc b/blog/migrations/__pycache__/0001_initial.cpython-36.pyc new file mode 100644 index 0000000000..2ca29f2c60 Binary files /dev/null and b/blog/migrations/__pycache__/0001_initial.cpython-36.pyc differ diff --git a/blog/migrations/__pycache__/0002_comment.cpython-36.pyc b/blog/migrations/__pycache__/0002_comment.cpython-36.pyc new file mode 100644 index 0000000000..f41d7b0412 Binary files /dev/null and b/blog/migrations/__pycache__/0002_comment.cpython-36.pyc differ diff --git a/blog/migrations/__pycache__/__init__.cpython-36.pyc b/blog/migrations/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000..c5e7abac09 Binary files /dev/null and b/blog/migrations/__pycache__/__init__.cpython-36.pyc differ diff --git a/blog/models.py b/blog/models.py new file mode 100644 index 0000000000..b4a3758e5b --- /dev/null +++ b/blog/models.py @@ -0,0 +1,37 @@ +from django.db import models +from django.conf import settings + +from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation +from django.contrib.contenttypes.models import ContentType + +# Create your models here. +class Tag(models.Model): + value = models.TextField(max_length=100) + + def __str__(self): + return self.value + +class Comment(models.Model): + creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + content = models.TextField() + content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) + object_id = models.PositiveIntegerField() + content_object = GenericForeignKey("content_type", "object_id") + created_at = models.DateTimeField(auto_now_add=True) + modified_at = models.DateTimeField(auto_now=True) + +class Post(models.Model): + author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT) + created_at = models.DateTimeField(auto_now_add=True) + modified_at = models.DateTimeField(auto_now=True) + published_at = models.DateTimeField(blank=True, null=True) + title = models.TextField(max_length=100) + slug = models.SlugField() + summary = models.TextField(max_length=500) + content = models.TextField() + tags = models.ManyToManyField(Tag, related_name="posts") + comments = GenericRelation(Comment) + + def __str__(self): + return self.title + diff --git a/blog/templatetags/__init__.py b/blog/templatetags/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/blog/templatetags/__pycache__/__init__.cpython-36.pyc b/blog/templatetags/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000..4ec5ea84a4 Binary files /dev/null and b/blog/templatetags/__pycache__/__init__.cpython-36.pyc differ diff --git a/blog/templatetags/__pycache__/blog_extras.cpython-36.pyc b/blog/templatetags/__pycache__/blog_extras.cpython-36.pyc new file mode 100644 index 0000000000..1ed2c13560 Binary files /dev/null and b/blog/templatetags/__pycache__/blog_extras.cpython-36.pyc differ diff --git a/blog/templatetags/blog_extras.py b/blog/templatetags/blog_extras.py new file mode 100644 index 0000000000..1a228e6129 --- /dev/null +++ b/blog/templatetags/blog_extras.py @@ -0,0 +1,31 @@ +from django.utils.html import escape +from django.utils.safestring import mark_safe +from django import template +from django.contrib.auth import get_user_model +from django.utils.html import format_html + +register = template.Library() +user_model = get_user_model() + +@register.filter +def author_details(author, current_user=None): + if not isinstance(author, user_model): + # return empty string as safe default + return "" + + if author == current_user: + return format_html("me") + + if author.first_name and author.last_name: + name = f"{author.first_name} {author.last_name}" + else: + name = f"{author.username}" + + if author.email: + prefix = format_html('', author.email) + suffix = format_html("") + else: + prefix = "" + suffix = "" + + return format_html('{}{}{}', prefix, name, suffix) diff --git a/blog/tests.py b/blog/tests.py new file mode 100644 index 0000000000..7ce503c2dd --- /dev/null +++ b/blog/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/blog/views.py b/blog/views.py new file mode 100644 index 0000000000..5d6d3ca745 --- /dev/null +++ b/blog/views.py @@ -0,0 +1,8 @@ +from django.shortcuts import render +from django.utils import timezone +from blog.models import Post + +# Create your views here. +def index(request): + posts = Post.objects.filter(published_at__lte=timezone.now()) + return render(request, "blog/index.html", {"posts": posts}) \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000..909b90f221 Binary files /dev/null and b/db.sqlite3 differ diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000000..2c6ed3737f --- /dev/null +++ b/templates/base.html @@ -0,0 +1,15 @@ + + + + + + + Hello, world! + + + {% block content %} + + {% endblock %} + + + \ No newline at end of file diff --git a/templates/blog/index.html b/templates/blog/index.html new file mode 100644 index 0000000000..a2b286db54 --- /dev/null +++ b/templates/blog/index.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{% load blog_extras %} +{% block content %} +

Blog Posts

+ {% for post in posts %} +
+
+

{{ post.title }}

+ By {{ post.author|author_details:request.user }} on {{ post.published_at|date:"M, d Y" }} +

{{ post.summary }}

+

+ ({{ post.content|wordcount }} words) + Read More +

+
+
+ {% endfor %} +{% endblock %}