diff --git a/blango/__pycache__/__init__.cpython-36.pyc b/blango/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000..1cc8c93d9c 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..bf1bae5a4e 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..4daf36d92d 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..4316f89c66 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..cf53e5f9c3 100644 --- a/blango/settings.py +++ b/blango/settings.py @@ -10,116 +10,195 @@ 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 - - -# 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', - ], +from configurations import Configuration, 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-ym=d)ft4%)xiukqr&tgstl6i2091+x_#&o%*%n6g^epgy(bpd6" + + AUTH_USER_MODEL = "blango_auth.User" + EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" + ACCOUNT_ACTIVATION_DAYS = 7 + SITE_ID = 1 + ACCOUNT_USER_MODEL_USERNAME_FIELD = None + ACCOUNT_EMAIL_REQUIRED = True + ACCOUNT_USERNAME_REQUIRED = False + ACCOUNT_AUTHENTICATION_METHOD = "email" + # SECURITY WARNING: don't run with debug turned on in production! + DEBUG = True + + ALLOWED_HOSTS = values.ListValue(["localhost", "0.0.0.0", ".codio.io"]) + # 7 rows below belong are codio related and upper line was ALLOWED_HOSTS = [] by default + 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 + + INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.sites', + 'django.contrib.staticfiles', + 'blango_auth', + 'blog', + "crispy_forms", + "crispy_bootstrap5", + "debug_toolbar", + "allauth", + "allauth.account", + "allauth.socialaccount", + "allauth.socialaccount.providers.google", + ] + + MIDDLEWARE = [ + "debug_toolbar.middleware.DebugToolbarMiddleware", + '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' + + INTERNAL_IPS = ["192.168.11.179"] # for usage of DjDT + + 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 = values.DatabaseURLValue(f"sqlite:///{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', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, + ] + PASSWORD_HASHERS = [ + 'django.contrib.auth.hashers.Argon2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', + 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', + ] + + # Internationalization + # https://docs.djangoproject.com/en/3.2/topics/i18n/ + + LANGUAGE_CODE = 'en-us' + + TIME_ZONE = values.Value("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' + + # Settings enabling usage of Crispy forms ( as well as adding "crispy_forms" and "crispy_bootstrap5" to INSTALLED_APPS ) + CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" + CRISPY_TEMPLATE_PACK = "bootstrap5" + 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' +class Prod(Dev): + DEBUG = values.BooleanValue(True) + SECRET_KEY = values.SecretValue() \ No newline at end of file diff --git a/blango/urls.py b/blango/urls.py index cde05802f9..0c0c4b5702 100644 --- a/blango/urls.py +++ b/blango/urls.py @@ -13,9 +13,33 @@ 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 blango_auth.views +import blog.views +from django_registration.backends.activation.views import RegistrationView +from blango_auth.forms import BlangoRegistrationForm 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), + path("accounts/", include("django.contrib.auth.urls")), + path("accounts/", include("allauth.urls")), + path("accounts/profile/", blango_auth.views.profile, name="profile"), + path( + "accounts/register/", + RegistrationView.as_view(form_class=BlangoRegistrationForm), + name="django_registration_register", +), +path("accounts/", include("django_registration.backends.activation.urls")), ] + + +if settings.DEBUG: + urlpatterns += [ + path("__debug__/", include(debug_toolbar.urls)), + ] \ No newline at end of file diff --git a/blango/wsgi.py b/blango/wsgi.py index 83565cf12c..6a49229799 100644 --- a/blango/wsgi.py +++ b/blango/wsgi.py @@ -6,11 +6,11 @@ For more information on this file, see https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ """ - import os -from django.core.wsgi import get_wsgi_application +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "blango.settings") +os.environ.setdefault("DJANGO_CONFIGURATION", "Prod") -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blango.settings') +from configurations.wsgi import get_wsgi_application -application = get_wsgi_application() +application = get_wsgi_application() \ No newline at end of file diff --git a/blango_auth/__init__.py b/blango_auth/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/blango_auth/__pycache__/__init__.cpython-36.pyc b/blango_auth/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000..b5c3bdf1cc Binary files /dev/null and b/blango_auth/__pycache__/__init__.cpython-36.pyc differ diff --git a/blango_auth/__pycache__/admin.cpython-36.pyc b/blango_auth/__pycache__/admin.cpython-36.pyc new file mode 100644 index 0000000000..fd95710536 Binary files /dev/null and b/blango_auth/__pycache__/admin.cpython-36.pyc differ diff --git a/blango_auth/__pycache__/apps.cpython-36.pyc b/blango_auth/__pycache__/apps.cpython-36.pyc new file mode 100644 index 0000000000..5a8a529de0 Binary files /dev/null and b/blango_auth/__pycache__/apps.cpython-36.pyc differ diff --git a/blango_auth/__pycache__/forms.cpython-36.pyc b/blango_auth/__pycache__/forms.cpython-36.pyc new file mode 100644 index 0000000000..0458ddd65c Binary files /dev/null and b/blango_auth/__pycache__/forms.cpython-36.pyc differ diff --git a/blango_auth/__pycache__/models.cpython-36.pyc b/blango_auth/__pycache__/models.cpython-36.pyc new file mode 100644 index 0000000000..400a4d79e7 Binary files /dev/null and b/blango_auth/__pycache__/models.cpython-36.pyc differ diff --git a/blango_auth/__pycache__/views.cpython-36.pyc b/blango_auth/__pycache__/views.cpython-36.pyc new file mode 100644 index 0000000000..61a34e06c0 Binary files /dev/null and b/blango_auth/__pycache__/views.cpython-36.pyc differ diff --git a/blango_auth/admin.py b/blango_auth/admin.py new file mode 100644 index 0000000000..61068aba5f --- /dev/null +++ b/blango_auth/admin.py @@ -0,0 +1,40 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from blango_auth.models import User, BlangoUserManager +from django.utils.translation import gettext_lazy as _ +# Register your models here. + + +class BlangoUserAdmin(UserAdmin): + fieldsets = ( + (None, {"fields": ("email", "password")}), + (_("Personal info"), {"fields": ("first_name", "last_name")}), + ( + _("Permissions"), + { + "fields": ( + "is_active", + "is_staff", + "is_superuser", + "groups", + "user_permissions", + ) + }, + ), + (_("Important dates"), {"fields": ("last_login", "date_joined")}), + ) + add_fieldsets = ( + ( + None, + { + "classes": ("wide",), + "fields": ("email", "password1", "password2"), + }, + ), + ) + list_display = ("email", "first_name", "last_name", "is_staff") + search_fields = ("email", "first_name", "last_name") + ordering = ("email",) + + +admin.site.register(User, BlangoUserAdmin) \ No newline at end of file diff --git a/blango_auth/apps.py b/blango_auth/apps.py new file mode 100644 index 0000000000..3619a45e56 --- /dev/null +++ b/blango_auth/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BlangoAuthConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'blango_auth' diff --git a/blango_auth/forms.py b/blango_auth/forms.py new file mode 100644 index 0000000000..bc7abbac83 --- /dev/null +++ b/blango_auth/forms.py @@ -0,0 +1,15 @@ +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Submit +from django_registration.forms import RegistrationForm + +from blango_auth.models import User + + +class BlangoRegistrationForm(RegistrationForm): + class Meta(RegistrationForm.Meta): + model = User + + def __init__(self, *args, **kwargs): + super(BlangoRegistrationForm, self).__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.add_input(Submit("submit", "Register")) \ No newline at end of file diff --git a/blango_auth/migrations/0001_initial.py b/blango_auth/migrations/0001_initial.py new file mode 100644 index 0000000000..d6a7ea2985 --- /dev/null +++ b/blango_auth/migrations/0001_initial.py @@ -0,0 +1,44 @@ +# Generated by Django 3.2.6 on 2023-03-25 19:57 + +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/blango_auth/migrations/0002_auto_20230325_2021.py b/blango_auth/migrations/0002_auto_20230325_2021.py new file mode 100644 index 0000000000..a3e4e5d3cd --- /dev/null +++ b/blango_auth/migrations/0002_auto_20230325_2021.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.6 on 2023-03-25 20:21 + +import blango_auth.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blango_auth', '0001_initial'), + ] + + operations = [ + migrations.AlterModelManagers( + name='user', + managers=[ + ('objects', blango_auth.models.BlangoUserManager()), + ], + ), + migrations.RemoveField( + model_name='user', + name='username', + ), + migrations.AlterField( + model_name='user', + name='email', + field=models.EmailField(max_length=254, unique=True, verbose_name='email address'), + ), + ] diff --git a/blango_auth/migrations/__init__.py b/blango_auth/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/blango_auth/migrations/__pycache__/0001_initial.cpython-36.pyc b/blango_auth/migrations/__pycache__/0001_initial.cpython-36.pyc new file mode 100644 index 0000000000..e92f412bb5 Binary files /dev/null and b/blango_auth/migrations/__pycache__/0001_initial.cpython-36.pyc differ diff --git a/blango_auth/migrations/__pycache__/0002_auto_20230325_2021.cpython-36.pyc b/blango_auth/migrations/__pycache__/0002_auto_20230325_2021.cpython-36.pyc new file mode 100644 index 0000000000..f8f547eb0e Binary files /dev/null and b/blango_auth/migrations/__pycache__/0002_auto_20230325_2021.cpython-36.pyc differ diff --git a/blango_auth/migrations/__pycache__/__init__.cpython-36.pyc b/blango_auth/migrations/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000..a9c6017e0f Binary files /dev/null and b/blango_auth/migrations/__pycache__/__init__.cpython-36.pyc differ diff --git a/blango_auth/models.py b/blango_auth/models.py new file mode 100644 index 0000000000..cb48ee960c --- /dev/null +++ b/blango_auth/models.py @@ -0,0 +1,50 @@ +from django.db import models +from django.contrib.auth.models import AbstractUser, UserManager +from django.utils.translation import gettext_lazy as _ +# Create your models here. + + + + +class BlangoUserManager(UserManager): + def _create_user(self, email, password, **extra_fields): + if not email: + raise ValueError("Email must be set") + email = self.normalize_email(email) + user = self.model(email=email, **extra_fields) + user.set_password(password) + user.save(using=self._db) + return user + + def create_user(self, email, password=None, **extra_fields): + extra_fields.setdefault("is_staff", False) + extra_fields.setdefault("is_superuser", False) + return self._create_user(email, password, **extra_fields) + + def create_superuser(self, email, password, **extra_fields): + extra_fields.setdefault("is_staff", True) + extra_fields.setdefault("is_superuser", True) + + if extra_fields.get("is_staff") is not True: + raise ValueError("Superuser must have is_staff=True.") + if extra_fields.get("is_superuser") is not True: + raise ValueError("Superuser must have is_superuser=True.") + + return self._create_user(email, password, **extra_fields) + + + +class User(AbstractUser): + username = None + email = models.EmailField( + _("email address"), + unique=True, + ) + + objects = BlangoUserManager() + + USERNAME_FIELD = "email" + REQUIRED_FIELDS = [] + + def __str__(self): + return self.email \ No newline at end of file diff --git a/blango_auth/templates/blango_auth/profile.html b/blango_auth/templates/blango_auth/profile.html new file mode 100644 index 0000000000..e86c690ee5 --- /dev/null +++ b/blango_auth/templates/blango_auth/profile.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% load blog_extras %} +{% block title %}Blango Profile{% endblock %} +{% block content %} +{% row %} + {% col %} +

Logged in as {{ request.user }}.

+

Log Out

+ {% endcol %} +{% endrow %} +{% endblock content %} \ No newline at end of file diff --git a/blango_auth/templates/django_registration/activation_complete.html b/blango_auth/templates/django_registration/activation_complete.html new file mode 100644 index 0000000000..1453e28091 --- /dev/null +++ b/blango_auth/templates/django_registration/activation_complete.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% load crispy_forms_tags blog_extras %} +{% block title %}Activation Complete{% endblock %} +{% block content %} +{% row "justify-content-center" %} + {% col "col-md-6" %} +

Activation Complete

+

Your account is now activated! You can now log in and use Blango.

+

Log In

+ {% endcol %} +{% endrow %} +{% endblock %} \ No newline at end of file diff --git a/blango_auth/templates/django_registration/activation_email_body.txt b/blango_auth/templates/django_registration/activation_email_body.txt new file mode 100644 index 0000000000..5faf606264 --- /dev/null +++ b/blango_auth/templates/django_registration/activation_email_body.txt @@ -0,0 +1,10 @@ +Hi, + +You registered for Blango, but you need to activate your account within {{ expiration_days }} days. + +To do that, please visit this page: + +{{ scheme }}://{{ request.get_host }}{% url "django_registration_activate" activation_key %} + +Thanks, +The Blango Team \ No newline at end of file diff --git a/blango_auth/templates/django_registration/activation_email_subject.txt b/blango_auth/templates/django_registration/activation_email_subject.txt new file mode 100644 index 0000000000..67646d771b --- /dev/null +++ b/blango_auth/templates/django_registration/activation_email_subject.txt @@ -0,0 +1 @@ +Activate your Blango account! You have {{ expiration_days }} days! \ No newline at end of file diff --git a/blango_auth/templates/django_registration/activation_failed.html b/blango_auth/templates/django_registration/activation_failed.html new file mode 100644 index 0000000000..5631e8a64b --- /dev/null +++ b/blango_auth/templates/django_registration/activation_failed.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% load crispy_forms_tags blog_extras %} +{% block title %}Activation Failed{% endblock %} +{% block content %} +{% row "justify-content-center" %} + {% col "col-md-6" %} +

Activation Failed

+

Sorry, we couldn't activate your account.

+

{{ activation_error.message }}

+ {% endcol %} +{% endrow %} +{% endblock %} \ No newline at end of file diff --git a/blango_auth/templates/django_registration/registration_closed.html b/blango_auth/templates/django_registration/registration_closed.html new file mode 100644 index 0000000000..b15b741712 --- /dev/null +++ b/blango_auth/templates/django_registration/registration_closed.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} +{% load crispy_forms_tags blog_extras %} +{% block title %}Registration Closed{% endblock %} +{% block content %} +{% row "justify-content-center" %} + {% col "col-md-6" %} +

Registration is currently closed

+ {% endcol %} +{% endrow %} +{% endblock %} \ No newline at end of file diff --git a/blango_auth/templates/django_registration/registration_complete.html b/blango_auth/templates/django_registration/registration_complete.html new file mode 100644 index 0000000000..5a37d3ce5f --- /dev/null +++ b/blango_auth/templates/django_registration/registration_complete.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% load crispy_forms_tags blog_extras %} +{% block title %}Registration Successful{% endblock %} +{% block content %} +{% row "justify-content-center" %} + {% col "col-md-6" %} +

Your registration was successful

+

Check your email to validate your account.

+ {% endcol %} +{% endrow %} +{% endblock %} \ No newline at end of file diff --git a/blango_auth/templates/django_registration/registration_form.html b/blango_auth/templates/django_registration/registration_form.html new file mode 100644 index 0000000000..c7f501a423 --- /dev/null +++ b/blango_auth/templates/django_registration/registration_form.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% load crispy_forms_tags blog_extras %} +{% block title %}Register for Blango{% endblock %} +{% block content %} +{% row "justify-content-center" %} + {% col "col-md-6" %} +

Register for Blango

+ {% crispy form %} + {% endcol %} +{% endrow %} +{% endblock %} \ No newline at end of file diff --git a/blango_auth/templates/registration/login.html b/blango_auth/templates/registration/login.html new file mode 100644 index 0000000000..a86f3e1ef8 --- /dev/null +++ b/blango_auth/templates/registration/login.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} +{% load crispy_forms_tags blog_extras %} +{% block title %}Log In to Blango{% endblock %} +{% block content %} +{% row "justify-content-center" %} + {% col "col-md-6" %} + {% if next %} + {% if user.is_authenticated %} +

Your account doesn't have access to this page. To proceed, + please login with an account that has access.

+ {% else %} +

Please login to see this page.

+ {% endif %} + {% endif %} + {% endcol %} +{% endrow %} + +{% row "justify-content-center" %} + {% col "col-md-6" %} +
+ {% csrf_token %} + {{ form|crispy }} + + +
+ +

Lost password?

+

+ Log in with Google +

+ {% endcol %} +{% endrow %} +{% endblock %} \ No newline at end of file diff --git a/blango_auth/tests.py b/blango_auth/tests.py new file mode 100644 index 0000000000..7ce503c2dd --- /dev/null +++ b/blango_auth/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/blango_auth/views.py b/blango_auth/views.py new file mode 100644 index 0000000000..eaee49d0e7 --- /dev/null +++ b/blango_auth/views.py @@ -0,0 +1,12 @@ +from django.contrib.auth.decorators import login_required +from django.shortcuts import render + + + +# Create your views here. + + +@login_required +def profile(request): + return render(request, "blango_auth/profile.html") + 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..b756c99954 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..771bb92db7 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..4cdf45b589 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..46413109d9 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..6850f1c804 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..68abd1273f 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..d3da56c8c2 --- /dev/null +++ b/blog/admin.py @@ -0,0 +1,11 @@ +from django.contrib import admin +from blog.models import Tag, Post, Comment, AuthorProfile + +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) +admin.site.register(AuthorProfile) 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..a309c40264 --- /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..fbebf9def8 --- /dev/null +++ b/blog/migrations/0001_initial.py @@ -0,0 +1,39 @@ +# Generated by Django 3.2.5 on 2023-03-23 07:40 + +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..0d7de1e4d6 --- /dev/null +++ b/blog/migrations/0002_comment.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.5 on 2023-03-23 12: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_20230323_1221.py b/blog/migrations/0003_auto_20230323_1221.py new file mode 100644 index 0000000000..c80877e7cd --- /dev/null +++ b/blog/migrations/0003_auto_20230323_1221.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.5 on 2023-03-23 12:21 + +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..f84c3cab24 --- /dev/null +++ b/blog/migrations/0004_alter_post_published_at.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.18 on 2023-03-25 18:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0003_auto_20230323_1221'), + ] + + 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_20230325_1842.py b/blog/migrations/0005_auto_20230325_1842.py new file mode 100644 index 0000000000..011d14c60c --- /dev/null +++ b/blog/migrations/0005_auto_20230325_1842.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.18 on 2023-03-25 18:42 + +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/0006_authorprofile.py b/blog/migrations/0006_authorprofile.py new file mode 100644 index 0000000000..1977c7419f --- /dev/null +++ b/blog/migrations/0006_authorprofile.py @@ -0,0 +1,24 @@ +# Generated by Django 3.2.6 on 2023-03-25 20:07 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('blog', '0005_auto_20230325_1842'), + ] + + operations = [ + migrations.CreateModel( + name='AuthorProfile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('bio', models.TextField()), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', 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..bf0b9cfd7f 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..6afb647742 Binary files /dev/null and b/blog/migrations/__pycache__/0002_comment.cpython-36.pyc differ diff --git a/blog/migrations/__pycache__/0003_auto_20230323_1221.cpython-36.pyc b/blog/migrations/__pycache__/0003_auto_20230323_1221.cpython-36.pyc new file mode 100644 index 0000000000..b1efeb3b02 Binary files /dev/null and b/blog/migrations/__pycache__/0003_auto_20230323_1221.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..7ea701e968 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_20230325_1842.cpython-36.pyc b/blog/migrations/__pycache__/0005_auto_20230325_1842.cpython-36.pyc new file mode 100644 index 0000000000..ecebd65bb4 Binary files /dev/null and b/blog/migrations/__pycache__/0005_auto_20230325_1842.cpython-36.pyc differ diff --git a/blog/migrations/__pycache__/0006_authorprofile.cpython-36.pyc b/blog/migrations/__pycache__/0006_authorprofile.cpython-36.pyc new file mode 100644 index 0000000000..9ec5f19948 Binary files /dev/null and b/blog/migrations/__pycache__/0006_authorprofile.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..40e6294ab4 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..3ecce643a9 --- /dev/null +++ b/blog/models.py @@ -0,0 +1,46 @@ +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() + 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 + + +class AuthorProfile(models.Model): + user = models.OneToOneField( + settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile" + ) + bio = models.TextField() + + def __str__(self): + return f"{self.__class__.__name__} object for {self.user}" \ No newline at end of file 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..2b76aecf07 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..1ab77dbdc4 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..bee5e46b0e --- /dev/null +++ b/blog/templatetags/blog_extras.py @@ -0,0 +1,62 @@ + +from django.contrib.auth import get_user_model +from django import template +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 +import logging + +user_model = get_user_model() +register = template.Library() +logger = logging.getLogger(__name__) + + +@register.filter +def author_details(author, current_user): + 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) + + + +@register.simple_tag +def row(extra_classes=""): + return format_html('
', extra_classes) + +@register.simple_tag +def endrow(): + 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} + + +@register.simple_tag +def col(extra_classes=""): + return format_html('
', extra_classes) + + +@register.simple_tag +def endcol(): + return format_html("
") \ 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/urls.py b/blog/urls.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/blog/views.py b/blog/views.py new file mode 100644 index 0000000000..5940964bbe --- /dev/null +++ b/blog/views.py @@ -0,0 +1,44 @@ +from django.shortcuts import render, redirect, get_object_or_404 +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__) + +# Create your views here. +def index(request): + posts = Post.objects.filter(published_at__lte=timezone.now()).select_related("author") + 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} + ) + + +def get_ip(request): + from django.http import HttpResponse + return HttpResponse(request.META['REMOTE_ADDR']) \ No newline at end of file diff --git a/data.json b/data.json new file mode 100644 index 0000000000..3beb2a9a04 --- /dev/null +++ b/data.json @@ -0,0 +1 @@ +[{"model": "blog.comment", "pk": 2, "fields": {"creator": 1, "content": "I like myself!", "content_type": 4, "object_id": 1, "created_at": "2023-03-23T12:22:47.979Z", "modified_at": "2023-03-23T12:22:47.995Z"}}, {"model": "blog.comment", "pk": 3, "fields": {"creator": 1, "content": "Crissssspyh!", "content_type": 8, "object_id": 1, "created_at": "2023-03-23T19:00:29.352Z", "modified_at": "2023-03-23T19:00:29.352Z"}}, {"model": "blog.comment", "pk": 4, "fields": {"creator": 1, "content": "Test1", "content_type": 8, "object_id": 1, "created_at": "2023-03-25T14:42:38.554Z", "modified_at": "2023-03-25T14:42:38.554Z"}}, {"model": "blog.tag", "pk": 1, "fields": {"value": "django"}}, {"model": "blog.tag", "pk": 2, "fields": {"value": "example"}}, {"model": "blog.post", "pk": 1, "fields": {"author": 1, "created_at": "2023-03-23T07:48:21.333Z", "modified_at": "2023-03-23T07:48:21.333Z", "published_at": "2023-03-23T07:46:45Z", "title": "Example post", "slug": "example-post", "summary": "short example post", "content": "

Example post

\r\n

This is an example post using html to render itself

", "tags": [1, 2]}}, {"model": "blog.post", "pk": 2, "fields": {"author": 1, "created_at": "2023-03-23T13:40:25.663Z", "modified_at": "2023-03-23T13:40:25.663Z", "published_at": "2023-03-23T13:39:40Z", "title": "Tsesting codio blod post no 1", "slug": "tsesting-codio-blod-post-no-1", "summary": "Example blog post no1", "content": "Some random words", "tags": [1]}}, {"model": "blog.post", "pk": 3, "fields": {"author": 1, "created_at": "2023-03-23T13:41:09.346Z", "modified_at": "2023-03-23T13:41:09.346Z", "published_at": "2023-03-23T13:40:36Z", "title": "Experimental blog post no 2", "slug": "experimental-blog-post-no-2", "summary": "ANother one to be tested", "content": "Again for fun", "tags": [2]}}, {"model": "blog.post", "pk": 4, "fields": {"author": 2, "created_at": "2023-03-23T13:41:32.936Z", "modified_at": "2023-03-23T13:41:32.936Z", "published_at": "2023-03-23T13:41:14Z", "title": "Another post with another author", "slug": "another-post-with-another-author", "summary": "CHeck check check", "content": "bla bla bla", "tags": [2]}}, {"model": "blango_auth.User", "pk": 1, "fields": {"password": "pbkdf2_sha256$260000$Ao3f7nZlRY0CYIgJsLFxNY$bINqlSyLyhcF4ObxiA4LBpg1vljZEYakB8mpUGkExkI=", "last_login": "2023-03-25T14:42:25.058Z", "is_superuser": true, "username": "codio", "first_name": "", "last_name": "", "email": "codio@example.com", "is_staff": true, "is_active": true, "date_joined": "2023-03-23T07:36:34.069Z", "groups": [], "user_permissions": []}}, {"model": "blango_auth.User", "pk": 2, "fields": {"password": "pbkdf2_sha256$260000$DWiZCN1apDeclG1Ps01jRT$a/CGPeefohx2owkq4Spo2ybUsjswTRINUaVPa8Mitzk=", "last_login": null, "is_superuser": false, "username": "codio2", "first_name": "", "last_name": "", "email": "", "is_staff": true, "is_active": true, "date_joined": "2023-03-23T13:38:53Z", "groups": [], "user_permissions": []}}] \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000..9f6271f788 Binary files /dev/null and b/db.sqlite3 differ diff --git a/manage.py b/manage.py index c66b327f71..0fee295e18 100644 --- a/manage.py +++ b/manage.py @@ -7,8 +7,9 @@ def main(): """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 " diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000..94be970cd4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,50 @@ +ansible==2.7.5 +asn1crypto==0.24.0 +backports.functools-lru-cache==1.6.1 +backports.shutil-get-terminal-size==1.0.0 +certifi==2018.1.18 +chardet==3.0.4 +cryptography==2.1.4 +cycler==0.10.0 +decorator==4.1.2 +enum34==1.1.6 +httplib2==0.9.2 +idna==2.6 +ipaddress==1.0.17 +ipython==5.5.0 +ipython-genutils==0.2.0 +Jinja2==2.10 +keyring==10.6.0 +keyrings.alt==3.0 +kiwisolver==1.1.0 +MarkupSafe==1.0 +matplotlib==2.2.4 +numpy==1.16.5 +paramiko==2.0.0 +pathlib2==2.3.0 +pexpect==4.2.1 +pickleshare==0.7.4 +prompt-toolkit==1.0.15 +pyasn1==0.4.2 +pycodestyle==2.5.0 +pycrypto==2.6.1 +pygame==1.9.6 +Pygments==2.2.0 +pygobject==3.26.1 +pyOpenSSL==17.5.0 +pyparsing==2.4.5 +python-apt==1.6.5+ubuntu0.3 +python-dateutil==2.8.1 +pytz==2019.3 +pyxdg==0.25 +PyYAML==3.12 +requests==2.18.4 +scandir==1.7 +scipy==1.2.2 +SecretStorage==2.3.1 +simplegeneric==0.8.1 +six==1.13.0 +subprocess32==3.5.4 +traitlets==4.3.2 +urllib3==1.22 +wcwidth==0.1.7 diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000000..b0bc88b71e --- /dev/null +++ b/templates/base.html @@ -0,0 +1,32 @@ + + + + + + + {% block title %}Welcome to Blango{% endblock %} + + +
+ + {% 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..ec9337524e --- /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" %} +
+

{{ post.title }}

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

{{ post.summary }}

+

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

+
+ {% 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..0a4633b9b7 --- /dev/null +++ b/templates/blog/post-byline.html @@ -0,0 +1,2 @@ +{% load blog_extras %} +By {{ post.author|author_details:request.user }} on {{ post.published_at|date:"M, d Y" }} \ No newline at end of file diff --git a/templates/blog/post-comments.html b/templates/blog/post-comments.html new file mode 100644 index 0000000000..fd9948750e --- /dev/null +++ b/templates/blog/post-comments.html @@ -0,0 +1,28 @@ +{% 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 %} + {% endcol %} +{% endrow %} +{% endif %} \ 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..2564e9930d --- /dev/null +++ b/templates/blog/post-detail.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} +{% load blog_extras cache %} + +{% block content %} +

{{ post.title }}

+{% row %} +
+ {% include "blog/post-byline.html" %} +
+{% endrow %} +{% row %} +
+ {{ post.content|safe }} +
+{% endrow %} +{% if post.author.profile %} + {% row %} + {% col %} +

About the author

+

{{ post.author.profile.bio }}

+ {% endcol %} + {% endrow %} +{% endif %} +{% include "blog/post-comments.html" %} +{% row %} + {% col %} + {% cache 3600 recent_posts %} + {% recent_posts post %} +{% endcache %} + {% endcol %} +{% endrow %} +{% endblock %} diff --git a/templates/blog/post-list.html b/templates/blog/post-list.html new file mode 100644 index 0000000000..35e5572af5 --- /dev/null +++ b/templates/blog/post-list.html @@ -0,0 +1,6 @@ +

{{ title }}

+ \ No newline at end of file