FossilRepo

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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button