diff --git a/blango/__pycache__/__init__.cpython-36.pyc b/blango/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000..c3de377c2d 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..4226e2a491 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..4f058f5d73 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..ca6590568d 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..91a5ed4223 100644 --- a/blango/settings.py +++ b/blango/settings.py @@ -11,115 +11,198 @@ """ from pathlib import Path - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-+sn%dpa!086+g+%44z9*^j^q-u4n!j(#wl)x9a%_1op@zz2+1-' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'blango.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], +import os +from configurations import Configuration +from configurations import values + +class Dev(Configuration): + # Build paths inside the project like this: BASE_DIR / 'subdir'. + BASE_DIR = Path(__file__).resolve().parent.parent + + + # Quick-start development settings - unsuitable for production + # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ + + # SECURITY WARNING: keep the secret key used in production secret! + SECRET_KEY = 'django-insecure-+sn%dpa!086+g+%44z9*^j^q-u4n!j(#wl)x9a%_1op@zz2+1-' + + # SECURITY WARNING: don't run with debug turned on in production! + DEBUG = True + + 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' + CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" + CRISPY_TEMPLATE_PACK = "bootstrap5" + + # Application definition + + INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'blog', + 'crispy_forms', + 'crispy_bootstrap5', + 'debug_toolbar', + ] + + MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + # 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + # 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "debug_toolbar.middleware.DebugToolbarMiddleware", + ] + + INTERNAL_IPS = ["192.168.10.226"] + ROOT_URLCONF = 'blango.urls' + + TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [BASE_DIR / 'templates'], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, + ] + + WSGI_APPLICATION = 'blango.wsgi.application' + + + # Database + # https://docs.djangoproject.com/en/3.2/ref/settings/#databases + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } + } + + LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "filters": { + "require_debug_false": { + "()": "django.utils.log.RequireDebugFalse", }, }, -] - -WSGI_APPLICATION = 'blango.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/3.2/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', - } -} - - -# Password validation -# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "formatters": { + "verbose": { + "format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}", + "style": "{", + }, }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "handlers": { + "console": { + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + "formatter": "verbose", + }, + "mail_admins": { + "level": "ERROR", + "class": "django.utils.log.AdminEmailHandler", + "filters": ["require_debug_false"], + }, }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "loggers": { + "django.request": { + "handlers": ["mail_admins"], + "level": "ERROR", + "propagate": True, + }, }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "root": { + "handlers": ["console"], + "level": "DEBUG", }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/3.2/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/3.2/howto/static-files/ - -STATIC_URL = '/static/' - -# Default primary key field type -# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field - -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +} +# "handlers": { +# "file": {"class": "logging.FileHandler", "filename": "/var/log/blango.log"}, +# } + # Password validation + # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators + + AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, + ] + + + # Internationalization + # https://docs.djangoproject.com/en/3.2/topics/i18n/ + + LANGUAGE_CODE = 'en-us' + + # TIME_ZONE = 'UTC' + TIME_ZONE = values.Value("UTC") + # TIME_ZONE = values.Value("UTC", environ_prefix="BLANGO") + + USE_I18N = True + + USE_L10N = True + + USE_TZ = True + + + # Static files (CSS, JavaScript, Images) + # https://docs.djangoproject.com/en/3.2/howto/static-files/ + + STATIC_URL = '/static/' + + # Default primary key field type + # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field + + DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + PASSWORD_HASHERS = [ + 'django.contrib.auth.hashers.Argon2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', + 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', + ] + + +# import dj_database_url +# class Prod(Dev): +# DEBUG = False +# # SECRET_KEY = values.SecretValue('''django-insecure-+sn%dpa!086+g+%44z9*^j^q-u4n!j(#wl)x9a%_1op@zz2+1-''') +# # ALLOWED_HOSTS = values.ListValue(["localhost", "0.0.0.0", ".codio.io"]) +# # mysql://username:password@mysql-host.example.com:3306/db_name?option1=value1&option2=value2 +# # DATABASES = values.DatabaseURLValue(f"sqlite:///{BASE_DIR}/db.sqlite3") +# DATABASES = { +# "default": dj_database_url.config(default=f"sqlite:///{BASE_DIR}/db.sqlite3"), +# "alternative": dj_database_url.config( +# "ALTERNATIVE_DATABASE_URL", +# default=f"sqlite:///{BASE_DIR}/alternative_db.sqlite3", +# ), +# } \ No newline at end of file diff --git a/blango/urls.py b/blango/urls.py index cde05802f9..ab536d7a91 100644 --- a/blango/urls.py +++ b/blango/urls.py @@ -13,9 +13,21 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ +import debug_toolbar +from django.conf import settings from django.contrib import admin -from django.urls import path +from django.urls import path, include + +import blog.views urlpatterns = [ path('admin/', admin.site.urls), + path("",blog.views.index), + path("post//", blog.views.post_detail, name="blog-post-detail"), + path("ip/", blog.views.get_ip), ] + +if settings.DEBUG: + urlpatterns += [ + path("__debug__/", include(debug_toolbar.urls)), + ] diff --git a/blango/wsgi.py b/blango/wsgi.py index 83565cf12c..b0e6b7321f 100644 --- a/blango/wsgi.py +++ b/blango/wsgi.py @@ -9,8 +9,10 @@ import os -from django.core.wsgi import get_wsgi_application +# from django.core.wsgi import get_wsgi_application +from configurations.wsgi import get_wsgi_application +os.environ.setdefault("DJANGO_CONFIGURATION", "Prod") os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blango.settings') application = get_wsgi_application() 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..7664e172b8 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..673abe474c 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..fd3229c594 Binary files /dev/null and b/blog/__pycache__/apps.cpython-36.pyc differ diff --git a/blog/__pycache__/forms.cpython-36.pyc b/blog/__pycache__/forms.cpython-36.pyc new file mode 100644 index 0000000000..f5a4cc425e Binary files /dev/null and b/blog/__pycache__/forms.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..365127313a 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..86545430e0 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..6920745ea0 --- /dev/null +++ b/blog/admin.py @@ -0,0 +1,12 @@ +from django.contrib import admin +from blog.models import Tag,Post,Comment + +# Register your models here. + +admin.site.register(Tag) + +class PostAdmin(admin.ModelAdmin): + prepopulated_fields = {"slug": ("title",)} + +admin.site.register(Post, PostAdmin) +admin.site.register(Comment) 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/forms.py b/blog/forms.py new file mode 100644 index 0000000000..293c688276 --- /dev/null +++ b/blog/forms.py @@ -0,0 +1,15 @@ +from django import forms +from crispy_forms.layout import Submit +from crispy_forms.helper import FormHelper + +from blog.models import Comment + + +class CommentForm(forms.ModelForm): + class Meta: + model = Comment + fields = ["content"] + def __init__(self, *args, **kwargs): + super(CommentForm, self).__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.add_input(Submit('submit', 'Submit')) \ No newline at end of file diff --git a/blog/migrations/0001_initial.py b/blog/migrations/0001_initial.py new file mode 100644 index 0000000000..76b890c486 --- /dev/null +++ b/blog/migrations/0001_initial.py @@ -0,0 +1,39 @@ +# Generated by Django 3.2.5 on 2024-03-25 06:41 + +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='Post', to='blog.Tag')), + ], + ), + ] diff --git a/blog/migrations/0002_comment.py b/blog/migrations/0002_comment.py new file mode 100644 index 0000000000..4ad8a7f016 --- /dev/null +++ b/blog/migrations/0002_comment.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.5 on 2024-03-27 18:03 + +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()), + ('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/0003_auto_20240327_1820.py b/blog/migrations/0003_auto_20240327_1820.py new file mode 100644 index 0000000000..6a180edcb6 --- /dev/null +++ b/blog/migrations/0003_auto_20240327_1820.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.5 on 2024-03-27 18:20 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0002_comment'), + ] + + operations = [ + migrations.AddField( + model_name='comment', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='comment', + name='modified_at', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/blog/migrations/0004_alter_post_published_at.py b/blog/migrations/0004_alter_post_published_at.py new file mode 100644 index 0000000000..69fb3d93c7 --- /dev/null +++ b/blog/migrations/0004_alter_post_published_at.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.25 on 2024-04-17 06:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0003_auto_20240327_1820'), + ] + + operations = [ + migrations.AlterField( + model_name='post', + name='published_at', + field=models.DateTimeField(blank=True, db_index=True, null=True), + ), + ] diff --git a/blog/migrations/0005_auto_20240422_0621.py b/blog/migrations/0005_auto_20240422_0621.py new file mode 100644 index 0000000000..8cd8be5ba6 --- /dev/null +++ b/blog/migrations/0005_auto_20240422_0621.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.25 on 2024-04-22 06:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0004_alter_post_published_at'), + ] + + operations = [ + migrations.AlterField( + model_name='comment', + name='created_at', + field=models.DateTimeField(auto_now_add=True, db_index=True), + ), + migrations.AlterField( + model_name='comment', + name='object_id', + field=models.PositiveIntegerField(db_index=True), + ), + ] 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..143a392924 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..5ba8e8afb5 Binary files /dev/null and b/blog/migrations/__pycache__/0002_comment.cpython-36.pyc differ diff --git a/blog/migrations/__pycache__/0003_auto_20240327_1820.cpython-36.pyc b/blog/migrations/__pycache__/0003_auto_20240327_1820.cpython-36.pyc new file mode 100644 index 0000000000..0701c98e5f Binary files /dev/null and b/blog/migrations/__pycache__/0003_auto_20240327_1820.cpython-36.pyc differ diff --git a/blog/migrations/__pycache__/0004_alter_post_published_at.cpython-36.pyc b/blog/migrations/__pycache__/0004_alter_post_published_at.cpython-36.pyc new file mode 100644 index 0000000000..fa9e8f64b2 Binary files /dev/null and b/blog/migrations/__pycache__/0004_alter_post_published_at.cpython-36.pyc differ diff --git a/blog/migrations/__pycache__/0005_auto_20240422_0621.cpython-36.pyc b/blog/migrations/__pycache__/0005_auto_20240422_0621.cpython-36.pyc new file mode 100644 index 0000000000..efa023ab5a Binary files /dev/null and b/blog/migrations/__pycache__/0005_auto_20240422_0621.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..7279255c53 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..ccd6df3265 --- /dev/null +++ b/blog/models.py @@ -0,0 +1,40 @@ +from django.db import models +from django.conf import settings + +from django.contrib.contenttypes.fields import GenericForeignKey +from django.contrib.contenttypes.models import ContentType +from django.contrib.contenttypes.fields import GenericRelation + + +# 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(db_index=True) + content_object = GenericForeignKey("content_type", "object_id") + created_at = models.DateTimeField(auto_now_add=True,db_index=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,db_index=True) + title = models.TextField(max_length=100) + slug = models.SlugField() #default 50 characters + summary = models.TextField(max_length=500) + content = models.TextField() + tags = models.ManyToManyField(Tag,related_name="Post") + 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..7d2b4ae07d 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..be002827ad 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..7219f9ab72 --- /dev/null +++ b/blog/templatetags/blog_extras.py @@ -0,0 +1,63 @@ +from django.contrib.auth import get_user_model +from django import template + +import logging + +from django.utils.html import escape +from django.utils.safestring import mark_safe +from django.utils.html import format_html + +from blog.models import Post + +logger = logging.getLogger(__name__) + +register = template.Library() +user_model = get_user_model() + +@register.simple_tag(takes_context=True) +def author_details_tag(context): + request = context["request"] + current_user = request.user + post = context["post"] + author = post.author + + 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) + +@register.simple_tag +def row(extra_classes=""): + return format_html('
', extra_classes) + + +@register.simple_tag +def endrow(): + return format_html("
") + +@register.simple_tag +def col(extra_classes=""): + return format_html('
', extra_classes) + + +@register.simple_tag +def endcol(): + return format_html("
") + +@register.inclusion_tag("blog/post-list.html") +def recent_posts(post): + posts = Post.objects.exclude(pk=post.pk)[:5] + logger.debug("Loaded %d recent posts for post %d", len(posts), post.pk) + return {"title": "Recent Posts", "posts": posts} \ No newline at end of file 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..9ce8d1b1aa --- /dev/null +++ b/blog/views.py @@ -0,0 +1,43 @@ +from django.shortcuts import render, get_object_or_404,redirect +from django.utils import timezone +from blog.models import Post +from blog.forms import CommentForm +import logging +from django.views.decorators.cache import cache_page +from django.views.decorators.vary import vary_on_cookie + +logger = logging.getLogger(__name__) + +def get_ip(request): + from django.http import HttpResponse + return HttpResponse(request.META['REMOTE_ADDR']) +# @cache_page(300) +# @vary_on_cookie +def index(request): + # from django.http import HttpResponse + # logger.debug("Index function is called!") + # return HttpResponse(str(request.user).encode("ascii")) + posts = Post.objects.filter(published_at__lte=timezone.now()).select_related("author") #.defer("created_at", "modified_at") + # .only("title", "summary", "content", "author", "published_at", "slug") + logger.debug("Got %d posts", len(posts)) + return render(request, "blog/index.html", {"posts": posts}) + +def post_detail(request, slug): + post = get_object_or_404(Post, slug=slug) + if request.user.is_active: + if request.method == "POST": + comment_form = CommentForm(request.POST) + if comment_form.is_valid(): + comment = comment_form.save(commit=False) + comment.content_object = post + comment.creator = request.user + comment.save() + logger.info("Created comment on Post %d for user %s",post.pk,request.user) + return redirect(request.path_info) + else: + comment_form = CommentForm() + else: + comment_form = None + return render( + request, "blog/post-detail.html", {"post": post, "comment_form": comment_form} + ) \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000..f2150a1786 Binary files /dev/null and b/db.sqlite3 differ diff --git a/manage.py b/manage.py index c66b327f71..d7d5e38265 100644 --- a/manage.py +++ b/manage.py @@ -5,17 +5,19 @@ def main(): - """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blango.settings') - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blango.settings') + os.environ.setdefault("DJANGO_CONFIGURATION", "Dev") + try: + # from django.core.management import execute_from_command_line + from configurations.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) if __name__ == '__main__': diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000000..be3e6ce21d --- /dev/null +++ b/templates/base.html @@ -0,0 +1,15 @@ + + + + + + + blong + + + {% block content %} + + {% endblock %} + + + diff --git a/templates/blog/comments.html b/templates/blog/comments.html new file mode 100644 index 0000000000..0c2a206bb6 --- /dev/null +++ b/templates/blog/comments.html @@ -0,0 +1,32 @@ +{% load blog_extras crispy_forms_tags%} +

Comments

+{% for comment in post.comments.all %} +{% row "border-top pt-2" %} + {% col %} +
Posted by {{ comment.creator }} at {{ comment.created_at|date:"M, d Y h:i" }}
+ {% endcol %} +{% endrow %} +{% row "border-bottom" %} + {% col %} +

{{ comment.content }}

+ {% endcol %} +{% endrow %} +{% empty %} + {% row "border-top border-bottom" %} + {% col %} +

No comments.

+ {% endcol %} + {% endrow %} +{% endfor %} +{% if request.user.is_active %} +{% row "mt-4" %} + {% col %} +

Add Comment

+ {% crispy comment_form %} + {{ comment_form|crispy }} +

+ +

+ {% endcol %} +{% endrow %} +{% endif %} \ No newline at end of file diff --git a/templates/blog/index.html b/templates/blog/index.html new file mode 100644 index 0000000000..4cf4fc1281 --- /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 %} + {% row "border-bottom" %} + {% col %} +

{{ post.title }}

+ {% include "blog/post-byline.html" %} +

{{ post.summary }}

+

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

+ {% endcol %} + {% endrow %} + {% endfor %} +{% endblock %} \ No newline at end of file diff --git a/templates/blog/post-byline.html b/templates/blog/post-byline.html new file mode 100644 index 0000000000..90d70c95c0 --- /dev/null +++ b/templates/blog/post-byline.html @@ -0,0 +1,2 @@ +{% load blog_extras %} +By {% author_details_tag %} on {{ post.published_at|date:"M, d Y" }} \ No newline at end of file diff --git a/templates/blog/post-detail.html b/templates/blog/post-detail.html new file mode 100644 index 0000000000..abc2298087 --- /dev/null +++ b/templates/blog/post-detail.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} +{% load blog_extras cache %} +{% block content %} +

{{ post.title }}

+{% row %} + {% col %} + {% include "blog/post-byline.html" %} + {% endcol %} +{% endrow %} +{% row %} + {% col %} + {{ post.content|safe }} + {% endcol %} +{% endrow %} +{% row %} + {% col %} + {% cache 3600 recent_posts post %} + {% recent_posts post %} + {% endcache %} + {% endcol %} +{% endrow %} +{% include "blog/comments.html" %} +{% endblock %} \ No newline at end of file diff --git a/templates/blog/post-list.html b/templates/blog/post-list.html new file mode 100644 index 0000000000..5032493417 --- /dev/null +++ b/templates/blog/post-list.html @@ -0,0 +1,6 @@ +

{{ title }}

+ \ No newline at end of file