wagtail-cjkcms 23.9.2__py2.py3-none-any.whl → 23.10.2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. cjkcms/__init__.py +1 -1
  2. cjkcms/blocks/__init__.py +6 -0
  3. cjkcms/blocks/content/events.py +16 -0
  4. cjkcms/migrations/0015_eventcalendar.py +49 -0
  5. cjkcms/migrations/0016_layoutsettings_breadcrumb_icon_and_more.py +32 -0
  6. cjkcms/models/admin_sidebar.py +12 -1
  7. cjkcms/models/snippet_models.py +47 -1
  8. cjkcms/models/wagtailsettings_models.py +22 -2
  9. cjkcms/static/cjkcms/css/cjkcms-front.css +6 -0
  10. cjkcms/static/cjkcms/images/icons/calendar-day.svg +1 -0
  11. cjkcms/static/cjkcms/images/icons/caret-right-fill.svg +3 -0
  12. cjkcms/static/cjkcms/images/icons/caret-right.svg +3 -0
  13. cjkcms/static/cjkcms/images/icons/chevron-right.svg +3 -0
  14. cjkcms/static/cjkcms/images/icons/slash.svg +3 -0
  15. cjkcms/static/cjkcms/images/icons/world.svg +3 -0
  16. cjkcms/templates/cjkcms/blocks/event_calendar_block.html +6 -0
  17. cjkcms/templates/cjkcms/blocks/public_event_block.html +14 -3
  18. cjkcms/templates/cjkcms/pages/base.html +5 -0
  19. cjkcms/templates/cjkcms/pages/search.html +2 -2
  20. cjkcms/templates/cjkcms/pages/web_page_notitle.html +4 -0
  21. cjkcms/templates/cjkcms/snippets/breadcrumbs.html +27 -0
  22. cjkcms/templates/cjkcms/snippets/navbar_search.html +2 -5
  23. cjkcms/templatetags/cjkcms_tags.py +24 -1
  24. cjkcms/tests/manage.py +10 -0
  25. cjkcms/tests/settings.py +88 -0
  26. cjkcms/tests/test_advsettings.py +198 -0
  27. cjkcms/tests/test_templatetags.py +41 -2
  28. cjkcms/tests/testapp/__init__.py +0 -0
  29. cjkcms/tests/testapp/apps.py +6 -0
  30. cjkcms/tests/testapp/migrations/0001_initial.py +144 -0
  31. cjkcms/tests/testapp/migrations/0002_create_homepage.py +62 -0
  32. cjkcms/tests/testapp/migrations/__init__.py +0 -0
  33. cjkcms/tests/testapp/models.py +19 -0
  34. cjkcms/tests/urls.py +26 -0
  35. cjkcms/utils.py +5 -2
  36. cjkcms/wagtail_hooks.py +2 -1
  37. {wagtail_cjkcms-23.9.2.dist-info → wagtail_cjkcms-23.10.2.dist-info}/METADATA +3 -2
  38. {wagtail_cjkcms-23.9.2.dist-info → wagtail_cjkcms-23.10.2.dist-info}/RECORD +44 -25
  39. cjkcms/draftail/draftail_icons.py +0 -17
  40. /cjkcms/{media → tests/media}/images/test.original.png +0 -0
  41. /cjkcms/{media → tests/media}/original_images/test.png +0 -0
  42. {wagtail_cjkcms-23.9.2.dist-info → wagtail_cjkcms-23.10.2.dist-info}/LICENSE +0 -0
  43. {wagtail_cjkcms-23.9.2.dist-info → wagtail_cjkcms-23.10.2.dist-info}/WHEEL +0 -0
  44. {wagtail_cjkcms-23.9.2.dist-info → wagtail_cjkcms-23.10.2.dist-info}/entry_points.txt +0 -0
  45. {wagtail_cjkcms-23.9.2.dist-info → wagtail_cjkcms-23.10.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,198 @@
1
+ from datetime import datetime, timedelta, timezone
2
+ from wagtail.test.utils import WagtailPageTests
3
+ from django.contrib.auth.models import User, Group
4
+
5
+ from wagtail.models import Page
6
+ from cjkcms.models.cms_models import ArticlePage
7
+ import uuid
8
+
9
+
10
+ class AdvSettingsTests(WagtailPageTests):
11
+ """Tests AdvSettings class functionality: custom id, customs class,
12
+ visibility options, start/end visible.
13
+ """
14
+
15
+ def setUp(self):
16
+ # create a test user
17
+ test_user1 = User.objects.create_user(username="testuser1", password="12345")
18
+ test_user1.save()
19
+
20
+ self.group22 = Group(name="Group22")
21
+ self.group22.save()
22
+ test_user2 = User.objects.create_user(username="testuser2", password="12345")
23
+ test_user2.groups.add(self.group22)
24
+ test_user2.save()
25
+
26
+ self.group23 = Group(name="Group23")
27
+ self.group23.save()
28
+ test_user3 = User.objects.create_user(username="testuser3", password="12345")
29
+ test_user3.groups.add(self.group23)
30
+ test_user3.save()
31
+
32
+ test_user4 = User.objects.create_user(username="testuser4", password="12345")
33
+ test_user4.groups.add(self.group22)
34
+ test_user4.groups.add(self.group23)
35
+ test_user4.save()
36
+
37
+ self.in_the_past = datetime.now(tz=timezone.utc) - timedelta(days=1)
38
+ self.in_the_future = datetime.now(tz=timezone.utc) + timedelta(days=1)
39
+
40
+ def createArticlePage(self, title: str, settings: dict):
41
+ # Get the HomePage
42
+ home_page = Page.objects.get(path="00010001")
43
+
44
+ body = [
45
+ {
46
+ "type": "quote",
47
+ "value": {
48
+ "settings": settings,
49
+ "text": "Quotably interesting",
50
+ "author": "By Mr Nobody",
51
+ },
52
+ "id": str(uuid.uuid1()),
53
+ }
54
+ ]
55
+
56
+ article_page = ArticlePage(title=title, body=body)
57
+
58
+ home_page.add_child(instance=article_page)
59
+ article_page.save_revision().publish()
60
+
61
+ return article_page
62
+
63
+ def test_visible_from_to(self):
64
+ settings = {
65
+ "visible_from": self.in_the_past.isoformat(),
66
+ "visible_to": self.in_the_future.isoformat(),
67
+ }
68
+
69
+ self.createArticlePage(title="Test Article", settings=settings)
70
+
71
+ ap = ArticlePage.objects.get(slug="test-article")
72
+
73
+ response = self.client.get(ap.url)
74
+ self.assertContains(response, "Quotably interesting", status_code=200)
75
+
76
+ def test_not_visible_from(self):
77
+ settings = {
78
+ "visible_from": self.in_the_future.isoformat(),
79
+ }
80
+
81
+ self.createArticlePage(title="Test Article2", settings=settings)
82
+
83
+ ap = ArticlePage.objects.get(slug="test-article2")
84
+
85
+ response = self.client.get(ap.url)
86
+ self.assertNotContains(response, "Quotably interesting", status_code=200)
87
+
88
+ def test_not_visible_to(self):
89
+ settings = {
90
+ "visible_to": self.in_the_past.isoformat(),
91
+ }
92
+
93
+ self.createArticlePage(title="Test Article3", settings=settings)
94
+
95
+ ap = ArticlePage.objects.get(slug="test-article3")
96
+
97
+ response = self.client.get(ap.url)
98
+ self.assertNotContains(response, "Quotably interesting", status_code=200)
99
+
100
+ def test_visible_to_loggedin(self):
101
+ settings = {
102
+ "visibility": "auth-only",
103
+ "visibility_groups": "",
104
+ }
105
+
106
+ self.createArticlePage(title="Test Article4", settings=settings)
107
+
108
+ ap = ArticlePage.objects.get(slug="test-article4")
109
+
110
+ response = self.client.get(ap.url)
111
+ self.assertNotContains(response, "Quotably interesting", status_code=200)
112
+
113
+ self.client.login(username="testuser1", password="12345")
114
+
115
+ response = self.client.get(ap.url)
116
+ # print(response.content)
117
+ self.assertContains(response, "Quotably interesting", status_code=200)
118
+
119
+ def test_invisible_to_loggedin(self):
120
+ settings = {
121
+ "visibility": "non-auth-only",
122
+ "visibility_groups": "",
123
+ }
124
+
125
+ self.createArticlePage(title="Test Article5", settings=settings)
126
+
127
+ ap = ArticlePage.objects.get(slug="test-article5")
128
+
129
+ response = self.client.get(ap.url)
130
+ self.assertContains(response, "Quotably interesting", status_code=200)
131
+
132
+ self.client.login(username="testuser1", password="12345")
133
+
134
+ ap = ArticlePage.objects.get(slug="test-article5")
135
+ response = self.client.get(ap.url)
136
+ print(response.content)
137
+
138
+ # @TODO: improve the test
139
+ # note: the page meta description will contain the "Quotably interesting",
140
+ # because the "body_preview" call gets the content rendered without context,
141
+ # and so it sees the page as not-logged-in
142
+
143
+ self.assertContains(
144
+ response, '<div class="block-quote"></div>', status_code=200
145
+ )
146
+
147
+ def test_visible_to_specific_group(self):
148
+ # sourcery skip: extract-duplicate-method
149
+ settings = {
150
+ "visibility": "include-groups",
151
+ "visibility_groups": "Group22,Group23",
152
+ }
153
+
154
+ self.createArticlePage(title="Test Article6", settings=settings)
155
+
156
+ ap = ArticlePage.objects.get(slug="test-article6")
157
+
158
+ response = self.client.get(ap.url)
159
+ self.assertNotContains(response, "Quotably interesting", status_code=200)
160
+
161
+ # wrong group
162
+ self.client.login(username="testuser1", password="12345")
163
+ response = self.client.get(ap.url)
164
+ self.assertNotContains(response, "Quotably interesting", status_code=200)
165
+
166
+ self.client.logout()
167
+ self.client.login(username="testuser2", password="12345")
168
+ response = self.client.get(ap.url)
169
+ self.assertContains(response, "Quotably interesting", status_code=200)
170
+
171
+ self.client.logout()
172
+ self.client.login(username="testuser4", password="12345")
173
+ response = self.client.get(ap.url)
174
+ self.assertContains(response, "Quotably interesting", status_code=200)
175
+
176
+ def test_invisible_to_specific_group(self):
177
+ # sourcery skip: extract-duplicate-method
178
+ settings = {
179
+ "visibility": "exclude-groups",
180
+ "visibility_groups": "Group22",
181
+ }
182
+
183
+ self.createArticlePage(title="Test Article6", settings=settings)
184
+
185
+ ap = ArticlePage.objects.get(slug="test-article6")
186
+
187
+ response = self.client.get(ap.url)
188
+ self.assertNotContains(response, "Quotably interesting", status_code=200)
189
+
190
+ # wrong group
191
+ self.client.login(username="testuser1", password="12345")
192
+ response = self.client.get(ap.url)
193
+ self.assertContains(response, "Quotably interesting", status_code=200)
194
+
195
+ self.client.logout()
196
+ self.client.login(username="testuser2", password="12345")
197
+ response = self.client.get(ap.url)
198
+ self.assertNotContains(response, "Quotably interesting", status_code=200)
@@ -1,11 +1,14 @@
1
1
  import re
2
- from datetime import datetime
3
2
 
4
3
  from django.template import engines
5
- from django.test import TestCase
6
4
  from wagtail.models import Site
7
5
 
8
6
  from cjkcms.models import AdobeApiSettings
7
+ from datetime import datetime, timedelta
8
+ from django.test import TestCase
9
+ from django.template import Template, Context
10
+ from cjkcms.templatetags.cjkcms_tags import is_in_future, is_in_past
11
+
9
12
 
10
13
  django_engine = engines["django"]
11
14
  html_id_re = re.compile(r"^[A-Za-z][A-Za-z0-9_:.-]*$")
@@ -103,3 +106,39 @@ class TemplateTagTests(TestCase):
103
106
  "{% load cjkcms_tags %}{% define 'test' %}{{ test }}"
104
107
  ).render(None)
105
108
  self.assertEqual(rt, "test", "define tag did not return 'test'")
109
+
110
+ def test_is_in_future_with_future_date(self):
111
+ future_date = datetime.now() + timedelta(days=1)
112
+ result = is_in_future(future_date)
113
+ self.assertTrue(result)
114
+
115
+ def test_is_in_future_with_past_date(self):
116
+ past_date = datetime.now() - timedelta(days=1)
117
+ result = is_in_future(past_date)
118
+ self.assertFalse(result)
119
+
120
+ def test_is_in_past_with_future_date(self):
121
+ future_date = datetime.now() + timedelta(days=1)
122
+ result = is_in_past(future_date)
123
+ self.assertFalse(result)
124
+
125
+ def test_is_in_past_with_past_date(self):
126
+ past_date = datetime.now() - timedelta(days=1)
127
+ result = is_in_past(past_date)
128
+ self.assertTrue(result)
129
+
130
+ def test_is_in_future_template_tag(self):
131
+ template = Template(
132
+ """{% load cjkcms_tags %}{% if the_date|is_in_future %}future{% else %}not future{% endif %}""" # noqa: E501
133
+ )
134
+ context = Context({"the_date": datetime.now() + timedelta(days=1)})
135
+ result = template.render(context)
136
+ self.assertEqual(result, "future")
137
+
138
+ def test_is_in_past_template_tag(self):
139
+ template = Template(
140
+ "{% load cjkcms_tags %}{% if the_date|is_in_past %}past{% else %}not past{% endif %}"
141
+ )
142
+ context = Context({"the_date": datetime.now() - timedelta(days=1)})
143
+ result = template.render(context)
144
+ self.assertEqual(result, "past")
File without changes
@@ -0,0 +1,6 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class TestAppConfig(AppConfig):
5
+ name = "cjkcms.tests.testapp" # replace `myapp` with your app name
6
+ verbose_name = "TestApp"
@@ -0,0 +1,144 @@
1
+ # Generated by Django 4.1.4 on 2022-12-28 06:28
2
+
3
+ import cjkcms.fields
4
+ from django.conf import settings
5
+ from django.db import migrations, models
6
+ import django.db.models.deletion
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+ initial = True
11
+
12
+ dependencies = [
13
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14
+ ("wagtailcore", "0040_page_draft_title"),
15
+ ("cjkcms", "0004_layoutsettings_articles_date_format_and_more"),
16
+ ]
17
+
18
+ operations = [
19
+ migrations.CreateModel(
20
+ name="ProjectArticleIndexPage",
21
+ fields=[
22
+ (
23
+ "cjkcmspage_ptr",
24
+ models.OneToOneField(
25
+ auto_created=True,
26
+ on_delete=django.db.models.deletion.CASCADE,
27
+ parent_link=True,
28
+ primary_key=True,
29
+ serialize=False,
30
+ to="cjkcms.cjkcmspage",
31
+ ),
32
+ ),
33
+ (
34
+ "show_images",
35
+ models.BooleanField(default=True, verbose_name="Show images"),
36
+ ),
37
+ ("show_captions", models.BooleanField(default=True)),
38
+ (
39
+ "show_meta",
40
+ models.BooleanField(
41
+ default=True, verbose_name="Show author and date info"
42
+ ),
43
+ ),
44
+ (
45
+ "show_preview_text",
46
+ models.BooleanField(default=True, verbose_name="Show preview text"),
47
+ ),
48
+ (
49
+ "body",
50
+ cjkcms.fields.CjkcmsStreamField(
51
+ blank=True, null=True, use_json_field=True
52
+ ),
53
+ ),
54
+ ],
55
+ options={
56
+ "verbose_name": "App Article Landing Page",
57
+ },
58
+ bases=("cjkcms.cjkcmspage",),
59
+ ),
60
+ migrations.CreateModel(
61
+ name="ProjectWebPage",
62
+ fields=[
63
+ (
64
+ "cjkcmspage_ptr",
65
+ models.OneToOneField(
66
+ auto_created=True,
67
+ on_delete=django.db.models.deletion.CASCADE,
68
+ parent_link=True,
69
+ primary_key=True,
70
+ serialize=False,
71
+ to="cjkcms.cjkcmspage",
72
+ ),
73
+ ),
74
+ (
75
+ "body",
76
+ cjkcms.fields.CjkcmsStreamField(
77
+ blank=True, null=True, use_json_field=True
78
+ ),
79
+ ),
80
+ ],
81
+ options={
82
+ "verbose_name": "App Web Page",
83
+ },
84
+ bases=("cjkcms.cjkcmspage",),
85
+ ),
86
+ migrations.CreateModel(
87
+ name="ProjectArticlePage",
88
+ fields=[
89
+ (
90
+ "cjkcmspage_ptr",
91
+ models.OneToOneField(
92
+ auto_created=True,
93
+ on_delete=django.db.models.deletion.CASCADE,
94
+ parent_link=True,
95
+ primary_key=True,
96
+ serialize=False,
97
+ to="cjkcms.cjkcmspage",
98
+ ),
99
+ ),
100
+ (
101
+ "caption",
102
+ models.CharField(
103
+ blank=True, max_length=255, verbose_name="Caption"
104
+ ),
105
+ ),
106
+ (
107
+ "author_display",
108
+ models.CharField(
109
+ blank=True,
110
+ help_text="Override how the author’s name displays on this article.",
111
+ max_length=255,
112
+ verbose_name="Display author as",
113
+ ),
114
+ ),
115
+ (
116
+ "date_display",
117
+ models.DateField(
118
+ blank=True, null=True, verbose_name="Display publish date"
119
+ ),
120
+ ),
121
+ (
122
+ "body",
123
+ cjkcms.fields.CjkcmsStreamField(
124
+ blank=True, null=True, use_json_field=True
125
+ ),
126
+ ),
127
+ (
128
+ "author",
129
+ models.ForeignKey(
130
+ blank=True,
131
+ null=True,
132
+ on_delete=django.db.models.deletion.SET_NULL,
133
+ to=settings.AUTH_USER_MODEL,
134
+ verbose_name="Author",
135
+ ),
136
+ ),
137
+ ],
138
+ options={
139
+ "verbose_name": "App Article",
140
+ "ordering": ["-first_published_at"],
141
+ },
142
+ bases=("cjkcms.cjkcmspage",),
143
+ ),
144
+ ]
@@ -0,0 +1,62 @@
1
+ # -*- coding: utf-8 -*-
2
+ from django.db import migrations
3
+ from wagtail.models import Locale
4
+
5
+
6
+ def create_homepage(apps, schema_editor):
7
+ """Create app homepage based on CjkCMS WebPage model"""
8
+ # Get models
9
+ ContentType = apps.get_model("contenttypes.ContentType")
10
+ Page = apps.get_model("wagtailcore.Page")
11
+ Site = apps.get_model("wagtailcore.Site")
12
+ ProjectWebPage = apps.get_model("testapp.ProjectWebPage")
13
+
14
+ # Delete the default homepage
15
+ # If migration is run multiple times, it may have already been deleted
16
+ Page.objects.filter(slug="home").delete()
17
+
18
+ # Create content type for homepage model
19
+ project_webpage_content_type, __ = ContentType.objects.get_or_create(
20
+ model="projectwebpage", app_label="testapp"
21
+ )
22
+
23
+ # Create a new homepage
24
+ homepage = ProjectWebPage.objects.create(
25
+ title="app Home",
26
+ draft_title="app Home",
27
+ slug="home",
28
+ content_type=project_webpage_content_type,
29
+ path="00010001",
30
+ depth=2,
31
+ numchild=0,
32
+ url_path="/home/",
33
+ locale_id=Locale.get_default().id,
34
+ )
35
+
36
+ # Create a site with the new homepage set as the root
37
+ Site.objects.create(hostname="localhost", root_page=homepage, is_default_site=True)
38
+
39
+
40
+ def remove_homepage(apps, schema_editor):
41
+ # Get models
42
+ content_type = apps.get_model("contenttypes.ContentType")
43
+ project_web_page = apps.get_model("testapp.ProjectWebPage")
44
+
45
+ # Delete the default homepage
46
+ # Page and Site objects CASCADE
47
+ project_web_page.objects.filter(slug="home", depth=2).delete()
48
+
49
+ # Delete content type for app webpage model
50
+ content_type.objects.filter(model="projectwebpage", app_label="home").delete()
51
+
52
+
53
+ class Migration(migrations.Migration):
54
+ dependencies = [
55
+ ("cjkcms", "0001_initial"),
56
+ ("wagtailcore", "0057_page_locale_fields_notnull"),
57
+ ("testapp", "0001_initial"),
58
+ ]
59
+
60
+ operations = [
61
+ migrations.RunPython(create_homepage, remove_homepage),
62
+ ]
File without changes
@@ -0,0 +1,19 @@
1
+ from cjkcms.models import (
2
+ CjkcmsArticlePage,
3
+ CjkcmsArticleIndexPage,
4
+ CjkcmsWebPage,
5
+ )
6
+
7
+
8
+ class ProjectArticlePage(CjkcmsArticlePage):
9
+ template = "cjkcms/pages/article_page.html"
10
+ search_template = "cjkcms/pages/article_page.search.html"
11
+
12
+
13
+ class ProjectArticleIndexPage(CjkcmsArticleIndexPage):
14
+ template = "cjkcms/pages/article_index_page.html"
15
+
16
+
17
+ class ProjectWebPage(CjkcmsWebPage):
18
+ # use cjkcms template by default
19
+ template = "cjkcms/pages/web_page.html"
cjkcms/tests/urls.py ADDED
@@ -0,0 +1,26 @@
1
+ from django.urls import include, path
2
+ from django.conf.urls.static import static
3
+ from django.contrib import admin
4
+ from django.conf import settings
5
+
6
+ from wagtail import urls as wagtail_urls
7
+ from cjkcms import urls as cjkcms_urls
8
+ from wagtail.admin import urls as wagtailadmin_urls
9
+ from wagtail.documents import urls as wagtaildocs_urls
10
+
11
+
12
+ urlpatterns = [
13
+ path("django-admin/", admin.site.urls),
14
+ path("admin/", include(wagtailadmin_urls)),
15
+ path("documents/", include(wagtaildocs_urls)),
16
+ path("", include(cjkcms_urls)),
17
+ path("", include(wagtail_urls)),
18
+ ]
19
+
20
+
21
+ if settings.DEBUG:
22
+ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
23
+
24
+ # Serve static and media files from development server
25
+ urlpatterns += staticfiles_urlpatterns()
26
+ urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
cjkcms/utils.py CHANGED
@@ -43,10 +43,13 @@ def can_show_block(
43
43
  if item_visibility == "all":
44
44
  return True
45
45
 
46
+ # if context is None or "request" not in context:
47
+ # is_auth = False
48
+ # else:
46
49
  try:
47
50
  is_auth = context["request"].user.is_authenticated
48
- except KeyError:
49
- return False
51
+ except (KeyError, TypeError):
52
+ is_auth = False
50
53
 
51
54
  if not is_auth:
52
55
  return item_visibility == "non-auth-only"
cjkcms/wagtail_hooks.py CHANGED
@@ -7,7 +7,7 @@ from cjkcms.draftail import (
7
7
  register_inline_styling,
8
8
  )
9
9
 
10
- from cjkcms.models.admin_sidebar import NavbarSnippet
10
+ from cjkcms.models.admin_sidebar import NavbarSnippet, EventCalendarSnippet
11
11
  from django.http.response import HttpResponse
12
12
  from django.templatetags.static import static
13
13
  from django.utils.html import format_html
@@ -199,3 +199,4 @@ def register_external_link(features):
199
199
 
200
200
 
201
201
  register_snippet(NavbarSnippet)
202
+ register_snippet(EventCalendarSnippet)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wagtail-cjkcms
3
- Version: 23.9.2
3
+ Version: 23.10.2
4
4
  Summary: Wagtail Content Management System, installable as a Django app into any Wagtail 4.1.x/5.x site.
5
5
  Author-email: Grzegorz Krol <gk@cjk.pl>
6
6
  License: BSD-3-Clause
@@ -32,7 +32,8 @@ License: BSD-3-Clause
32
32
  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33
33
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34
34
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
- Project-URL: Homepage, https://github.com/cjkpl/wagtail-cjkcms
35
+ Project-URL: Homepage, https://cjkcms.com
36
+ Project-URL: Repository, https://github.com/cjkpl/wagtail-cjkcms/issues
36
37
  Keywords: wagtail,django,cms
37
38
  Classifier: Environment :: Web Environment
38
39
  Classifier: Framework :: Django