mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-22 14:13:21 +00:00
Fix wiki, plus clean up and add tests
This commit is contained in:
parent
8753e020a1
commit
9a9541088d
1
core/fixtures/pages.json
Normal file
1
core/fixtures/pages.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"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}}]
|
19
core/migrations/0002_page_full_name.py
Normal file
19
core/migrations/0002_page_full_name.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# -*- 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):
|
|||||||
|
|
||||||
|
|
||||||
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):
|
|||||||
|
|
||||||
@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):
|
|||||||
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):
|
|||||||
|
|
||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user