aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2024-12-17 19:25:04 +0000
committerBobby <[email protected]>2024-12-17 19:25:04 +0000
commit79d44e676adeb998c3072b4a58d08815b45d4676 (patch)
tree13dd865f0b809b0e77d5cfc491fa5909c1ea15c1
parenta12bd485351559af96d019d55a4b0f8dbc1b7265 (diff)
downloadthatcomputerscientist-79d44e676adeb998c3072b4a58d08815b45d4676.tar.xz
thatcomputerscientist-79d44e676adeb998c3072b4a58d08815b45d4676.zip
journal stuff
-rw-r--r--apps/core/urls.py2
-rw-r--r--apps/core/views.py15
-rw-r--r--apps/journals/__init__.py0
-rw-r--r--apps/journals/admin.py7
-rw-r--r--apps/journals/apps.py6
-rw-r--r--apps/journals/migrations/0001_initial.py78
-rw-r--r--apps/journals/migrations/0002_journal_slug.py19
-rw-r--r--apps/journals/migrations/__init__.py0
-rw-r--r--apps/journals/models.py39
-rw-r--r--apps/journals/tests.py3
-rw-r--r--apps/journals/urls.py6
-rw-r--r--apps/journals/views.py3
-rw-r--r--middleware/globalmetamiddleware.py2
-rw-r--r--static/css/shared/core.css36
-rw-r--r--static/css/shared/login-area.css4
-rw-r--r--templates/en/core/my/journals.html88
-rw-r--r--templates/en/pagoda/home.html2
-rw-r--r--templates/en/pagoda/site_dashboard.html7
-rw-r--r--templates/en/pagoda/site_verification.html12
-rw-r--r--templates/ja/pagoda/home.html2
-rw-r--r--templates/ja/pagoda/site_verification.html14
-rw-r--r--templates/shared/left_sidebar.html2
-rw-r--r--thatcomputerscientist/settings.py1
-rw-r--r--thatcomputerscientist/urls.py1
24 files changed, 340 insertions, 9 deletions
diff --git a/apps/core/urls.py b/apps/core/urls.py
index db770dd0..3d64a60d 100644
--- a/apps/core/urls.py
+++ b/apps/core/urls.py
@@ -5,4 +5,6 @@ from . import views
app_name = "core"
urlpatterns = [
path("", views.home, name="home"),
+ # My Pages
+ path("my/journals/", views.my_journals, name="my_journals"),
]
diff --git a/apps/core/views.py b/apps/core/views.py
index 037f52c2..1790098a 100644
--- a/apps/core/views.py
+++ b/apps/core/views.py
@@ -1,6 +1,7 @@
from django.shortcuts import render
from thatcomputerscientist.utils import i18npatterns
from apps.administration.models import Announcement
+from apps.journals.models import Journal
from internal.mal_wrapper import get_mal_recent_activity
from internal.weblog_utilities import recent_weblogs
@@ -20,3 +21,17 @@ def home(request):
"recent_weblogs": recent_weblogs(lang=LANGUAGE_CODE),
}
return render(request, f"{LANGUAGE_CODE}/core/home.html", context)
+
+
+# My Pages
+def my_journals(request):
+ META = {
+ "title": "My Journals",
+ }
+ LANGUAGE_CODE = i18npatterns(request.LANGUAGE_CODE)
+ request.META.update(META)
+ journals = Journal.objects.filter(owner=request.user).order_by("-created_at")
+ context = {
+ "journals": journals,
+ }
+ return render(request, f"{LANGUAGE_CODE}/core/my/journals.html", context)
diff --git a/apps/journals/__init__.py b/apps/journals/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/apps/journals/__init__.py
diff --git a/apps/journals/admin.py b/apps/journals/admin.py
new file mode 100644
index 00000000..e619370d
--- /dev/null
+++ b/apps/journals/admin.py
@@ -0,0 +1,7 @@
+from django.contrib import admin
+
+# Register your models here.
+from apps.journals.models import Journal, JournalEntry
+
+admin.site.register(Journal)
+admin.site.register(JournalEntry)
diff --git a/apps/journals/apps.py b/apps/journals/apps.py
new file mode 100644
index 00000000..6b3c8ae9
--- /dev/null
+++ b/apps/journals/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class JournalsConfig(AppConfig):
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "apps.journals"
diff --git a/apps/journals/migrations/0001_initial.py b/apps/journals/migrations/0001_initial.py
new file mode 100644
index 00000000..485a5314
--- /dev/null
+++ b/apps/journals/migrations/0001_initial.py
@@ -0,0 +1,78 @@
+# Generated by Django 5.1.4 on 2024-12-17 17:38
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="Journal",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=128)),
+ ("description", models.TextField(blank=True)),
+ ("private", models.BooleanField(default=False)),
+ ("custom_css", models.TextField(blank=True)),
+ ("created_at", models.DateTimeField(auto_now_add=True)),
+ ("updated_at", models.DateTimeField(auto_now=True)),
+ (
+ "owner",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ (
+ "shared_with",
+ models.ManyToManyField(
+ blank=True,
+ related_name="shared_journals",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ ),
+ migrations.CreateModel(
+ name="JournalEntry",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("title", models.CharField(max_length=128)),
+ ("body", models.TextField()),
+ ("created_at", models.DateTimeField(auto_now_add=True)),
+ ("updated_at", models.DateTimeField(auto_now=True)),
+ (
+ "journal",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="entries",
+ to="journals.journal",
+ ),
+ ),
+ ],
+ ),
+ ]
diff --git a/apps/journals/migrations/0002_journal_slug.py b/apps/journals/migrations/0002_journal_slug.py
new file mode 100644
index 00000000..67082c3c
--- /dev/null
+++ b/apps/journals/migrations/0002_journal_slug.py
@@ -0,0 +1,19 @@
+# Generated by Django 5.1.4 on 2024-12-17 18:37
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("journals", "0001_initial"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="journal",
+ name="slug",
+ field=models.SlugField(default="", max_length=256, unique=True),
+ preserve_default=False,
+ ),
+ ]
diff --git a/apps/journals/migrations/__init__.py b/apps/journals/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/apps/journals/migrations/__init__.py
diff --git a/apps/journals/models.py b/apps/journals/models.py
new file mode 100644
index 00000000..96214d56
--- /dev/null
+++ b/apps/journals/models.py
@@ -0,0 +1,39 @@
+from django.db import models
+from django.conf import settings
+
+
+class Journal(models.Model):
+ owner = models.ForeignKey(
+ settings.AUTH_USER_MODEL,
+ on_delete=models.CASCADE,
+ )
+ name = models.CharField(max_length=128)
+ slug = models.SlugField(max_length=256, unique=True)
+ description = models.TextField(blank=True)
+ private = models.BooleanField(default=False)
+ shared_with = models.ManyToManyField(
+ settings.AUTH_USER_MODEL,
+ related_name="shared_journals",
+ blank=True,
+ )
+ custom_css = models.TextField(blank=True)
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
+
+ def __str__(self):
+ return self.name
+
+
+class JournalEntry(models.Model):
+ journal = models.ForeignKey(
+ Journal,
+ on_delete=models.CASCADE,
+ related_name="entries",
+ )
+ title = models.CharField(max_length=128)
+ body = models.TextField()
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
+
+ def __str__(self):
+ return self.title
diff --git a/apps/journals/tests.py b/apps/journals/tests.py
new file mode 100644
index 00000000..7ce503c2
--- /dev/null
+++ b/apps/journals/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/apps/journals/urls.py b/apps/journals/urls.py
new file mode 100644
index 00000000..1f7413c2
--- /dev/null
+++ b/apps/journals/urls.py
@@ -0,0 +1,6 @@
+from django.urls import path
+
+from . import views
+
+app_name = "journal"
+urlpatterns = []
diff --git a/apps/journals/views.py b/apps/journals/views.py
new file mode 100644
index 00000000..91ea44a2
--- /dev/null
+++ b/apps/journals/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/middleware/globalmetamiddleware.py b/middleware/globalmetamiddleware.py
index 1a9a1d6b..f5e00555 100644
--- a/middleware/globalmetamiddleware.py
+++ b/middleware/globalmetamiddleware.py
@@ -8,7 +8,7 @@ class GlobalMetaMiddleware:
def __call__(self, request):
request.meta = {
# Default General Meta Tags
- "title": "Shifoo",
+ "title": "Home",
"description": "Welcome to the home of Shifoo. This is my personal website where I share all of my thoughts, ideas, and experiences.",
"image": "https://shi.foo/static/images/favicons/android-chrome-512x512.png",
"url": "{}://{}{}".format(request.scheme, request.get_host(), request.path),
diff --git a/static/css/shared/core.css b/static/css/shared/core.css
index ac629b03..c02be71e 100644
--- a/static/css/shared/core.css
+++ b/static/css/shared/core.css
@@ -99,6 +99,41 @@ a:hover {
text-decoration: underline;
}
+.link-button {
+ background: rgba(134, 99, 229, 0.2);
+ padding: 8px 16px;
+ border-radius: 4px;
+ color: #8d8dff;
+ text-decoration: none;
+ border: 1px solid #8d8dff;
+ transition: all 0.3s ease;
+ font-size: 12px;
+}
+
+.link-button:hover {
+ background: rgba(223, 35, 196, 0.2);
+ border-color: #df23c4;
+ color: #df23c4;
+ text-decoration: none;
+ transform: translateY(-2px);
+}
+
+.action-button {
+ padding: 4px 8px;
+ border-radius: 4px;
+ color: #8d8dff;
+ text-decoration: none;
+ font-size: 11px;
+ transition: all 0.2s ease;
+ background: rgba(141, 141, 255, 0.1);
+}
+
+.action-button:hover {
+ color: #df23c4;
+ background: rgba(223, 35, 196, 0.1);
+ text-decoration: none;
+}
+
textarea {
resize: none;
background: transparent;
@@ -143,6 +178,7 @@ img {
z-index: 1;
width: 1200px;
margin: 0 auto;
+ right: 10px;
}
#content-wrapper {
diff --git a/static/css/shared/login-area.css b/static/css/shared/login-area.css
index 47cee42d..3ea863fb 100644
--- a/static/css/shared/login-area.css
+++ b/static/css/shared/login-area.css
@@ -60,8 +60,8 @@
#login-error>.messageBox {
position: absolute;
- top: -88px;
- left: -120px;
+ top: -120px;
+ right: 48px;
z-index: 2;
width: 200px;
height: 132px;
diff --git a/templates/en/core/my/journals.html b/templates/en/core/my/journals.html
new file mode 100644
index 00000000..a3be14bb
--- /dev/null
+++ b/templates/en/core/my/journals.html
@@ -0,0 +1,88 @@
+{% extends 'shared/base.html' %}
+{% load static %}
+{% block head %}
+<style>
+ .my-journals {
+ padding: 12px 0px;
+ }
+
+ .my-journals-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 12px;
+ padding-bottom: 12px;
+ border-bottom: 2px solid #8d8dff;
+ }
+
+ .journal-list {
+ background: rgba(0, 0, 0, 0.3);
+ border-radius: 8px;
+ overflow: hidden;
+ }
+
+ .journal-list-header, .journal-list-item {
+ display: grid;
+ grid-template-columns: 2fr 1fr 1fr 1fr;
+ padding: 12px;
+ }
+
+ .journal-list-header {
+ background: linear-gradient(90deg, #4444b1, #623795);
+ border-bottom: 1px solid #8d8dff;
+ }
+
+
+ .journal-list-header-title {
+ font-weight: 600;
+ text-align: center;
+ }
+
+ .journal-list-item {
+ border-bottom: 1px solid rgba(141, 141, 255, 0.2);
+ background: rgba(98, 55, 149, 0.1);
+ transition: background 0.3s ease;
+ }
+
+ .journal-list-item:nth-child(odd) {
+ background: rgba(68, 68, 177, 0.1);
+ }
+
+ .journal-alignment-left {
+ justify-content: flex-start !important;
+ }
+
+ .journal-alignment-center {
+ display: flex;
+ justify-content: center !important;
+ gap: 8px;
+ }
+</style>
+{% endblock head %}
+{% block content %}
+<div class="my-journals">
+ <div class="my-journals-header">
+ <h1 class="navigation-title" style="font-size: 24px;">My Journals</h1>
+ <a href="#create" class="link-button">Create a Journal</a>
+ </div>
+ <div class="journal-list">
+ <div class="journal-list-header">
+ <div class="journal-list-header-title">Title</div>
+ <div class="journal-list-header-title">Private</div>
+ <div class="journal-list-header-title">Entries</div>
+ <div class="journal-list-header-title">Actions</div>
+ </div>
+ {% for journal in journals %}
+ <div class="journal-list-item">
+ <div class="journal-alignment-left">{{ journal.name }}</div>
+ <div class="journal-alignment-center">{{ journal.private }}</div>
+ <div class="journal-alignment-center">{{ journal.entries.all|length }}</div>
+ <div class="journal-alignment-center">
+ <a href="#view" class="action-button">View</a>
+ <a href="#manage" class="action-button">Manage</a>
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+</div>
+{% endblock content %}
diff --git a/templates/en/pagoda/home.html b/templates/en/pagoda/home.html
index d5910d11..306dfe44 100644
--- a/templates/en/pagoda/home.html
+++ b/templates/en/pagoda/home.html
@@ -125,7 +125,7 @@
future, so stay tuned for more updates. If you have any questions or feedback, please feel free to contact me. I hope
you enjoy using The Pagoda Realm!</p>
<p>Thank you for using The Pagoda Realm!</p>
- <button onclick="document.cookie = 'visitedPagodaRealm=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'; window.location.reload();">I Understand What I Must Do!</button>
+ <button onclick="window.scrollTo(0, 0); document.cookie = 'visitedPagodaRealm=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'; window.location.reload();">I Understand What I Must Do!</button>
</div>
{% else %}
{% if not pagoda_sites %}
diff --git a/templates/en/pagoda/site_dashboard.html b/templates/en/pagoda/site_dashboard.html
index e69de29b..a4344c26 100644
--- a/templates/en/pagoda/site_dashboard.html
+++ b/templates/en/pagoda/site_dashboard.html
@@ -0,0 +1,7 @@
+{% extends 'shared/base.html' %}
+{% load static %}
+{% block head %}
+{% endblock head %}
+{% block content %}
+Site Dashboard
+{% endblock content %} \ No newline at end of file
diff --git a/templates/en/pagoda/site_verification.html b/templates/en/pagoda/site_verification.html
index 9d5e1aad..dd5e661d 100644
--- a/templates/en/pagoda/site_verification.html
+++ b/templates/en/pagoda/site_verification.html
@@ -160,6 +160,16 @@
<p>Once you've added the details, click the button below to check the verification status.</p>
<button class="verify-button" onclick="window.location.href = '{% url 'pagoda:site_status' site.siteUniqueIdentifier %}'">Check Verification Status</button>
- <button class="delete-button" onclick="window.location.href = '{% url 'pagoda:delete_site' site.siteUniqueIdentifier %}'">Delete Site</button>
+ <button class="delete-button" onclick="javascript:deleteSite();">Delete Site</button>
</div>
{% endblock %}
+{% block scripts %}
+<script type="text/javascript">
+ function deleteSite() {
+ if (confirm("Are you sure you want to remove this connected website? This action is permanent and cannot be undone.")) {
+ const deletionURL = "{% url 'pagoda:delete_site' site.siteUniqueIdentifier %}";
+ window.location.href = deletionURL;
+ }
+ }
+</script>
+{% endblock scripts %}
diff --git a/templates/ja/pagoda/home.html b/templates/ja/pagoda/home.html
index 48e2e0a3..e3388994 100644
--- a/templates/ja/pagoda/home.html
+++ b/templates/ja/pagoda/home.html
@@ -86,7 +86,7 @@
</ul>
<p>これらは、The Pagoda Realmで利用できるサービスの一部にすぎません。今後さらにサービスを追加していく予定なので、アップデートをお楽しみに!質問やフィードバックがありましたら、お気軽にご連絡ください。The Pagoda Realmをお楽しみください!</p>
<p>The Pagoda Realmをご利用いただき、ありがとうございます!</p>
- <button onclick="document.cookie = 'visitedPagodaRealm=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'; window.location.reload();">理解しました!</button>
+ <button onclick="window.scrollTo(0, 0); document.cookie = 'visitedPagodaRealm=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'; window.location.reload();">理解しました!</button>
</div>
{% else %}
{% if not pagoda_sites %}
diff --git a/templates/ja/pagoda/site_verification.html b/templates/ja/pagoda/site_verification.html
index a92c167e..789b8372 100644
--- a/templates/ja/pagoda/site_verification.html
+++ b/templates/ja/pagoda/site_verification.html
@@ -160,6 +160,16 @@
<p>情報を追加したら、下のボタンをクリックして認証状態を確認してください。</p>
<button class="verify-button" onclick="window.location.href = '{% url 'pagoda:site_status' site.siteUniqueIdentifier %}'">認証状態を確認</button>
- <button class="delete-button" onclick="window.location.href = '{% url 'pagoda:delete_site' site.siteUniqueIdentifier %}'">サイトを削除</button>
+ <button class="delete-button" onclick="javascript:deleteSite();'">サイトを削除</button>
</div>
-{% endblock %} \ No newline at end of file
+{% endblock %}
+{% block scripts %}
+<script type="text/javascript">
+ function deleteSite() {
+ if (confirm("Are you sure you want to remove this connected website? This action is permanent and cannot be undone.")) {
+ const deletionURL = "{% url 'pagoda:delete_site' site.siteUniqueIdentifier %}";
+ window.location.href = deletionURL;
+ }
+ }
+</script>
+{% endblock scripts %} \ No newline at end of file
diff --git a/templates/shared/left_sidebar.html b/templates/shared/left_sidebar.html
index 5815b373..ee667db2 100644
--- a/templates/shared/left_sidebar.html
+++ b/templates/shared/left_sidebar.html
@@ -34,7 +34,7 @@
<div class="user-items-container">
<div class="user-item">
<img src="{% static 'images/core/icons/journals.png' %}" alt="Journals Icon" />
- <a href="#journals">{% if request.LANGUAGE_CODE == 'ja' %}ジャーナル{% else %}Journals{% endif %}</a>
+ <a href="{% url "core:my_journals" %}">{% if request.LANGUAGE_CODE == 'ja' %}ジャーナル{% else %}Journals{% endif %}</a>
</div>
<div class="user-item">
<img src="{% static 'images/core/icons/pagodarealm.png' %}" alt="The Pagoda Realm Icon" />
diff --git a/thatcomputerscientist/settings.py b/thatcomputerscientist/settings.py
index 43b069ec..a2f3b817 100644
--- a/thatcomputerscientist/settings.py
+++ b/thatcomputerscientist/settings.py
@@ -80,6 +80,7 @@ INSTALLED_APPS = [
"apps.administration",
"apps.blog",
"apps.pagoda",
+ "apps.journals",
"services.users",
"services.stream",
"services.pamphlet",
diff --git a/thatcomputerscientist/urls.py b/thatcomputerscientist/urls.py
index 76f41dbe..97d51fcf 100644
--- a/thatcomputerscientist/urls.py
+++ b/thatcomputerscientist/urls.py
@@ -41,6 +41,7 @@ handler404 = "thatcomputerscientist.error_handler.custom_404"
urlpatterns = [
path("", include("apps.core.urls", namespace="core")),
+ path("journal/", include("apps.journals.urls", namespace="journal")),
path("weblog/", include("apps.blog.urls", namespace="weblog")),
path("pagoda/", include("apps.pagoda.urls", namespace="pagoda")),
path("services/stream/", include("services.stream.urls", namespace="stream")),