|
1
|
import markdown |
|
2
|
from django.contrib import messages |
|
3
|
from django.contrib.auth.decorators import login_required |
|
4
|
from django.core.paginator import Paginator |
|
5
|
from django.http import HttpResponse |
|
6
|
from django.shortcuts import get_object_or_404, redirect, render |
|
7
|
from django.utils.safestring import mark_safe |
|
8
|
|
|
9
|
from core.pagination import PER_PAGE_OPTIONS, get_per_page |
|
10
|
from core.permissions import P |
|
11
|
from core.sanitize import sanitize_html |
|
12
|
from organization.views import get_org |
|
13
|
|
|
14
|
from .forms import PageForm |
|
15
|
from .models import Page |
|
16
|
|
|
17
|
|
|
18
|
def page_list(request): |
|
19
|
# Published pages are visible to everyone (including anonymous users). |
|
20
|
# Authenticated editors/admins can also see unpublished drafts. |
|
21
|
if request.user.is_authenticated and (request.user.has_perm("pages.change_page") or request.user.is_superuser): |
|
22
|
pages = Page.objects.all() |
|
23
|
else: |
|
24
|
pages = Page.objects.filter(is_published=True) |
|
25
|
|
|
26
|
search = request.GET.get("search", "").strip() |
|
27
|
if search: |
|
28
|
pages = pages.filter(name__icontains=search) |
|
29
|
|
|
30
|
per_page = get_per_page(request) |
|
31
|
paginator = Paginator(pages, per_page) |
|
32
|
page_obj = paginator.get_page(request.GET.get("page", 1)) |
|
33
|
|
|
34
|
ctx = {"pages": page_obj, "page_obj": page_obj, "search": search, "per_page": per_page, "per_page_options": PER_PAGE_OPTIONS} |
|
35
|
|
|
36
|
if request.headers.get("HX-Request"): |
|
37
|
return render(request, "pages/partials/page_table.html", ctx) |
|
38
|
|
|
39
|
return render(request, "pages/page_list.html", ctx) |
|
40
|
|
|
41
|
|
|
42
|
@login_required |
|
43
|
def page_create(request): |
|
44
|
P.PAGE_ADD.check(request.user) |
|
45
|
org = get_org() |
|
46
|
|
|
47
|
if request.method == "POST": |
|
48
|
form = PageForm(request.POST) |
|
49
|
if form.is_valid(): |
|
50
|
page = form.save(commit=False) |
|
51
|
page.organization = org |
|
52
|
page.created_by = request.user |
|
53
|
page.save() |
|
54
|
messages.success(request, f'Page "{page.name}" created.') |
|
55
|
return redirect("pages:detail", slug=page.slug) |
|
56
|
else: |
|
57
|
form = PageForm() |
|
58
|
|
|
59
|
return render(request, "pages/page_form.html", {"form": form, "title": "New Page"}) |
|
60
|
|
|
61
|
|
|
62
|
def page_detail(request, slug): |
|
63
|
from django.core.exceptions import PermissionDenied |
|
64
|
|
|
65
|
page = get_object_or_404(Page, slug=slug, deleted_at__isnull=True) |
|
66
|
# Published pages are public. Unpublished drafts require auth + edit permission. |
|
67
|
if not page.is_published: |
|
68
|
if not request.user.is_authenticated: |
|
69
|
raise PermissionDenied("Authentication required.") |
|
70
|
if not (request.user.has_perm("pages.change_page") or request.user.is_superuser): |
|
71
|
raise PermissionDenied("You don't have permission to view this draft page.") |
|
72
|
content_html = mark_safe(sanitize_html(markdown.markdown(page.content, extensions=["fenced_code", "tables", "toc"]))) |
|
73
|
return render(request, "pages/page_detail.html", {"page": page, "content_html": content_html}) |
|
74
|
|
|
75
|
|
|
76
|
@login_required |
|
77
|
def page_update(request, slug): |
|
78
|
P.PAGE_CHANGE.check(request.user) |
|
79
|
page = get_object_or_404(Page, slug=slug, deleted_at__isnull=True) |
|
80
|
|
|
81
|
if request.method == "POST": |
|
82
|
form = PageForm(request.POST, instance=page) |
|
83
|
if form.is_valid(): |
|
84
|
page = form.save(commit=False) |
|
85
|
page.updated_by = request.user |
|
86
|
page.save() |
|
87
|
messages.success(request, f'Page "{page.name}" updated.') |
|
88
|
return redirect("pages:detail", slug=page.slug) |
|
89
|
else: |
|
90
|
form = PageForm(instance=page) |
|
91
|
|
|
92
|
return render(request, "pages/page_form.html", {"form": form, "page": page, "title": "Edit Page"}) |
|
93
|
|
|
94
|
|
|
95
|
@login_required |
|
96
|
def page_delete(request, slug): |
|
97
|
P.PAGE_DELETE.check(request.user) |
|
98
|
page = get_object_or_404(Page, slug=slug, deleted_at__isnull=True) |
|
99
|
|
|
100
|
if request.method == "POST": |
|
101
|
page.soft_delete(user=request.user) |
|
102
|
messages.success(request, f'Page "{page.name}" deleted.') |
|
103
|
|
|
104
|
if request.headers.get("HX-Request"): |
|
105
|
return HttpResponse(status=200, headers={"HX-Redirect": "/kb/"}) |
|
106
|
|
|
107
|
return redirect("pages:list") |
|
108
|
|
|
109
|
return render(request, "pages/page_confirm_delete.html", {"page": page}) |
|
110
|
|