Commit 9a954108 authored by Skia's avatar Skia

Fix wiki, plus clean up and add tests

parent 8753e020
[{"model": "core.page", "pk": 1, "fields": {"title": "TROLL", "full_name": "guy2", "content": "ZZZZZZZZZZZZZZZZZZZZZ", "name": "guy2", "parent": null, "revision": 1, "is_locked": false}}, {"model": "core.page", "pk": 2, "fields": {"title": "Bibou", "full_name": "guy/bibou", "content": "Bibou Troll", "name": "bibou", "parent": 4, "revision": 1, "is_locked": false}}, {"model": "core.page", "pk": 3, "fields": {"title": "Troll", "full_name": "guy/bibou/troll", "content": "blbbllblbl", "name": "troll", "parent": 2, "revision": 1, "is_locked": false}}, {"model": "core.page", "pk": 4, "fields": {"title": "TROLL", "full_name": "guy", "content": "", "name": "guy", "parent": null, "revision": 1, "is_locked": false}}, {"model": "core.page", "pk": 5, "fields": {"title": "Bibou", "full_name": "bibou", "content": "", "name": "bibou", "parent": null, "revision": 1, "is_locked": false}}, {"model": "core.page", "pk": 6, "fields": {"title": "Bibou-Guy", "full_name": "bibou/guy", "content": "Bwahahahahahaha", "name": "guy", "parent": 5, "revision": 1, "is_locked": false}}]
\ No newline at end of file
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='page',
name='full_name',
field=models.CharField(blank=True, verbose_name='page name', max_length=255),
),
]
...@@ -109,12 +109,25 @@ class User(AbstractBaseUser, PermissionsMixin): ...@@ -109,12 +109,25 @@ class User(AbstractBaseUser, PermissionsMixin):
class Page(models.Model): class Page(models.Model):
"""
The page class to build a Wiki
Each page may have a parent and it's URL is of the form my.site/page/<grd_pa>/<parent>/<mypage>
It has an ID field, but don't use it, since it's only there for DB part, and because compound primary key is
awkward!
Prefere querying pages with Page.get_page_by_full_name()
Be careful with the full_name attribute: this field may not be valid until you call save(). It's made for fast
query, but don't rely on it when playing with a Page object, use get_full_name() instead!
"""
name = models.CharField(_('page name'), max_length=30, blank=False) name = models.CharField(_('page name'), max_length=30, blank=False)
title = models.CharField(_("page title"), max_length=255, blank=True) title = models.CharField(_("page title"), max_length=255, blank=True)
content = models.TextField(_("page content"), blank=True) content = models.TextField(_("page content"), blank=True)
revision = models.PositiveIntegerField(_("current revision"), default=1) revision = models.PositiveIntegerField(_("current revision"), default=1)
is_locked = models.BooleanField(_("page mutex"), default=False) is_locked = models.BooleanField(_("page mutex"), default=False)
parent = models.ForeignKey('self', related_name="children", null=True, blank=True, on_delete=models.SET_NULL) parent = models.ForeignKey('self', related_name="children", null=True, blank=True, on_delete=models.SET_NULL)
# Attention: this field may not be valid until you call save(). It's made for fast query, but don't rely on it when
# playing with a Page object, use get_full_name() instead!
full_name = models.CharField(_('page name'), max_length=255, blank=True)
class Meta: class Meta:
unique_together = ('name', 'parent') unique_together = ('name', 'parent')
...@@ -125,38 +138,43 @@ class Page(models.Model): ...@@ -125,38 +138,43 @@ class Page(models.Model):
@staticmethod @staticmethod
def get_page_by_full_name(name): def get_page_by_full_name(name):
parent_name = '/'.join(name.split('/')[:-1]) """
name = name.split('/')[-1] Quicker to get a page with that method rather than building the request every time
if parent_name == "": """
qs = Page.objects.filter(name=name, parent=None) return Page.objects.filter(full_name=name).first()
else:
qs = Page.objects.filter(name=name, parent__name=parent_name)
return qs.first()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Page, self).__init__(*args, **kwargs) super(Page, self).__init__(*args, **kwargs)
def clean(self): def clean(self):
""" """
This function maintains coherence between full_name, name, and parent.full_name Cleans up only the name for the moment, but this can be used to make any treatment before saving the object
Be careful modifying it, it could break the entire page table!
This function is mandatory since Django does not support compound primary key,
otherwise, Page class would have had PRIMARY_KEY(name, parent)
""" """
if '/' in self.name: if '/' in self.name:
self.name = self.name.split('/')[-1] self.name = self.name.split('/')[-1]
if Page.objects.exclude(pk=self.pk).filter(full_name=self.get_full_name()).exists():
raise ValidationError(
_('Duplicate page'),
code='duplicate',
)
super(Page, self).clean() super(Page, self).clean()
print("name: "+self.name)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.full_clean() self.full_clean()
# This reset the full_name just before saving to maintain a coherent field quicker for queries than the
# recursive method
self.full_name = self.get_full_name()
super(Page, self).save(*args, **kwargs) super(Page, self).save(*args, **kwargs)
def __str__(self): def __str__(self):
return self.get_full_name() return self.get_full_name()
def get_full_name(self): def get_full_name(self):
"""
Computes the real full_name of the page based on its name and its parent's name
You can and must rely on this function when working on a page object that is not freshly fetched from the DB
(For example when treating a Page object coming from a form)
"""
if self.parent is None: if self.parent is None:
return self.name return self.name
return '/'.join([self.parent.get_full_name(), self.name]) return '/'.join([self.parent.get_full_name(), self.name])
......
...@@ -148,3 +148,64 @@ class UserRegistrationTest(SimpleTestCase): ...@@ -148,3 +148,64 @@ class UserRegistrationTest(SimpleTestCase):
response = c.post(reverse('core:login'), {'username': 'gcarlier', 'password': 'guy'}) response = c.post(reverse('core:login'), {'username': 'gcarlier', 'password': 'guy'})
self.assertTrue(response.status_code == 200) self.assertTrue(response.status_code == 200)
self.assertTrue('LOGIN_FAIL' in str(response.content)) self.assertTrue('LOGIN_FAIL' in str(response.content))
def test_create_page_ok(self):
"""
Should create a page correctly
"""
c = Client()
response = c.post(reverse('core:page_edit', kwargs={'page_name': 'guy'}), {'parent': '',
'name': 'guy',
'title': 'Guy',
'Content': 'Guyéuyuyé',
})
self.assertTrue(response.status_code == 200)
self.assertTrue('PAGE_SAVED' in str(response.content))
def test_create_child_page_ok(self):
"""
Should create a page correctly
"""
c = Client()
c.post(reverse('core:page_edit', kwargs={'page_name': 'guy'}), {'parent': '',
'name': 'guy',
'title': 'Guy',
'Content': 'Guyéuyuyé',
})
response = c.post(reverse('core:page_edit', kwargs={'page_name': 'guy/bibou'}), {'parent': '1',
'name': 'bibou',
'title': 'Bibou',
'Content':
'Bibibibiblblblblblbouuuuuuuuu',
})
self.assertTrue(response.status_code == 200)
self.assertTrue('PAGE_SAVED' in str(response.content))
def test_access_child_page_ok(self):
"""
Should display a page correctly
"""
c = Client()
c.post(reverse('core:page_edit', kwargs={'page_name': 'guy'}), {'parent': '',
'name': 'guy',
'title': 'Guy',
'Content': 'Guyéuyuyé',
})
c.post(reverse('core:page_edit', kwargs={'page_name': 'guy/bibou'}), {'parent': '1',
'name': 'bibou',
'title': 'Bibou',
'Content':
'Bibibibiblblblblblbouuuuuuuuu',
})
response = c.get(reverse('core:page', kwargs={'page_name': 'guy/bibou'}))
self.assertTrue(response.status_code == 200)
self.assertTrue('PAGE_FOUND : Bibou' in str(response.content))
def test_access_page_not_found(self):
"""
Should not display a page correctly
"""
c = Client()
response = c.get(reverse('core:page', kwargs={'page_name': 'swagg'}))
self.assertTrue(response.status_code == 200)
self.assertTrue('PAGE_NOT_FOUND' in str(response.content))
...@@ -64,12 +64,15 @@ def login(request): ...@@ -64,12 +64,15 @@ def login(request):
def logout(request): def logout(request):
""" """
The logout view:w The logout view
""" """
auth_logout(request) auth_logout(request)
return redirect('core:index') return redirect('core:index')
def user(request, user_id=None): def user(request, user_id=None):
"""
Display a user's profile
"""
context = {'title': 'View a user'} context = {'title': 'View a user'}
if user_id == None: if user_id == None:
context['user_list'] = User.objects.all context['user_list'] = User.objects.all
...@@ -78,6 +81,9 @@ def user(request, user_id=None): ...@@ -78,6 +81,9 @@ def user(request, user_id=None):
return render(request, "core/user.html", context) return render(request, "core/user.html", context)
def user_edit(request, user_id=None): def user_edit(request, user_id=None):
"""
This view allows a user, or the allowed users to modify a profile
"""
user_id = int(user_id) user_id = int(user_id)
context = {'title': 'Edit a user'} context = {'title': 'Edit a user'}
if user_id is not None: if user_id is not None:
...@@ -88,6 +94,9 @@ def user_edit(request, user_id=None): ...@@ -88,6 +94,9 @@ def user_edit(request, user_id=None):
return user(request, user_id) return user(request, user_id)
def page(request, page_name=None): def page(request, page_name=None):
"""
This view displays a page or the link to create it if 404
"""
context = {'title': 'View a Page'} context = {'title': 'View a Page'}
if page_name == None: if page_name == None:
context['page_list'] = Page.objects.all context['page_list'] = Page.objects.all
...@@ -96,21 +105,30 @@ def page(request, page_name=None): ...@@ -96,21 +105,30 @@ def page(request, page_name=None):
if context['page'] is not None: if context['page'] is not None:
context['view_page'] = True context['view_page'] = True
context['title'] = context['page'].title context['title'] = context['page'].title
context['test'] = "PAGE_FOUND" context['tests'] = "PAGE_FOUND : "+context['page'].title
else: else:
context['title'] = "This page does not exist" context['title'] = "This page does not exist"
context['new_page'] = page_name context['new_page'] = page_name
context['test'] = "PAGE_NOT_FOUND" context['tests'] = "PAGE_NOT_FOUND"
return render(request, "core/page.html", context) return render(request, "core/page.html", context)
def page_edit(request, page_name=None): def page_edit(request, page_name=None):
"""
page_edit view, able to create a page, save modifications, and display the page ModelForm
"""
context = {'title': 'Edit a page', context = {'title': 'Edit a page',
'page_name': page_name} 'page_name': page_name}
p = Page.get_page_by_full_name(page_name) p = Page.get_page_by_full_name(page_name)
# New page
if p == None: if p == None:
# TODO: guess page name by splitting on '/' parent_name = '/'.join(page_name.split('/')[:-1])
# Same for the parent, try to guess name = page_name.split('/')[-1]
p = Page(name=page_name) if parent_name == "":
p = Page(name=name)
else:
parent = Page.get_page_by_full_name(parent_name)
p = Page(name=name, parent=parent)
# Saving page
if request.method == 'POST': if request.method == 'POST':
f = PageForm(request.POST, instance=p) f = PageForm(request.POST, instance=p)
if f.is_valid(): if f.is_valid():
...@@ -118,6 +136,7 @@ def page_edit(request, page_name=None): ...@@ -118,6 +136,7 @@ def page_edit(request, page_name=None):
context['tests'] = "PAGE_SAVED" context['tests'] = "PAGE_SAVED"
else: else:
context['tests'] = "PAGE_NOT_SAVED" context['tests'] = "PAGE_NOT_SAVED"
# Default: display the edit form without change
else: else:
context['tests'] = "POST_NOT_RECEIVED" context['tests'] = "POST_NOT_RECEIVED"
f = PageForm(instance=p) f = PageForm(instance=p)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment