##// END OF EJS Templates
Fixed getting posts for a thread. Implemented thread getting test.
neko259 -
r17:e40b2431 default
parent child Browse files
Show More
@@ -1,91 +1,94 b''
1 from django.db import models
1 from django.db import models
2 from django.http import Http404
2 from django.http import Http404
3 from django.utils import timezone
3 from django.utils import timezone
4
4
5 NO_PARENT = -1
5 NO_PARENT = -1
6 NO_IP = '0.0.0.0'
6 NO_IP = '0.0.0.0'
7 UNKNOWN_UA = ''
7 UNKNOWN_UA = ''
8 DIR_IMAGES = 'images'
8 DIR_IMAGES = 'images'
9
9
10 class PostManager(models.Manager):
10 class PostManager(models.Manager):
11
11
12 def create_post(self, title, text, image = None, parent_id = NO_PARENT,
12 def create_post(self, title, text, image = None, parent_id = NO_PARENT,
13 ip = NO_IP):
13 ip = NO_IP):
14 post = self.create(title = title,
14 post = self.create(title = title,
15 text = text,
15 text = text,
16 pub_time = timezone.now(),
16 pub_time = timezone.now(),
17 parent = parent_id,
17 parent = parent_id,
18 image = image,
18 image = image,
19 poster_ip = ip,
19 poster_ip = ip,
20 poster_user_agent = UNKNOWN_UA)
20 poster_user_agent = UNKNOWN_UA)
21
21
22 return post
22 return post
23
23
24 def delete_post(self, post):
24 def delete_post(self, post):
25 children = self.filter(parent = post.id)
25 children = self.filter(parent = post.id)
26 for child in children:
26 for child in children:
27 self.delete_post(child)
27 self.delete_post(child)
28 post.delete()
28 post.delete()
29
29
30 def delete_posts_by_ip(self, ip):
30 def delete_posts_by_ip(self, ip):
31 posts = self.filter(poster_ip = ip)
31 posts = self.filter(poster_ip = ip)
32 for post in posts:
32 for post in posts:
33 self.delete_post(post)
33 self.delete_post(post)
34
34
35 def get_threads(self, tag = None):
35 def get_threads(self, tag = None):
36 if tag is None:
36 if tag is None:
37 threads = self.filter(parent = NO_PARENT)
37 threads = self.filter(parent = NO_PARENT)
38 else:
38 else:
39 threads = self.filter(parent = NO_PARENT, tag = tag)
39 threads = self.filter(parent = NO_PARENT, tag = tag)
40
40
41 return threads
41 return threads
42
42
43 def get_thread(self, opening_post_id):
43 def get_thread(self, opening_post_id):
44 opening_post = self.get(opening_post_id)
44 opening_post = self.get(id = opening_post_id)
45 replies = self.filter(parent = opening_post_id)
45 replies = self.filter(parent = opening_post_id)
46
46
47 return [opening_post, replies]
47 thread = [opening_post]
48 thread.extend(replies)
49
50 return thread
48
51
49 def exists(self, post_id):
52 def exists(self, post_id):
50 posts = self.filter(id = post_id)
53 posts = self.filter(id = post_id)
51
54
52 return len(posts) > 0
55 return len(posts) > 0
53
56
54
57
55 class Tag(models.Model):
58 class Tag(models.Model):
56 """
59 """
57 A tag is a text node assigned to the post. The tag serves as a board
60 A tag is a text node assigned to the post. The tag serves as a board
58 section. There can be multiple tags for each message
61 section. There can be multiple tags for each message
59 """
62 """
60
63
61 name = models.CharField(max_length = 100)
64 name = models.CharField(max_length = 100)
62
65
63
66
64 class Post(models.Model):
67 class Post(models.Model):
65 """A post is a message."""
68 """A post is a message."""
66
69
67 objects = PostManager()
70 objects = PostManager()
68
71
69 title = models.CharField(max_length = 100)
72 title = models.CharField(max_length = 100)
70 pub_time = models.DateTimeField()
73 pub_time = models.DateTimeField()
71 text = models.TextField()
74 text = models.TextField()
72 image = models.ImageField(upload_to = DIR_IMAGES, blank = True)
75 image = models.ImageField(upload_to = DIR_IMAGES, blank = True)
73 poster_ip = models.IPAddressField()
76 poster_ip = models.IPAddressField()
74 poster_user_agent = models.TextField()
77 poster_user_agent = models.TextField()
75 parent = models.BigIntegerField()
78 parent = models.BigIntegerField()
76 tags = models.ManyToManyField(Tag)
79 tags = models.ManyToManyField(Tag)
77
80
78 def __unicode__(self):
81 def __unicode__(self):
79 return self.title + ' (' + self.text + ')'
82 return self.title + ' (' + self.text + ')'
80
83
81
84
82 class Admin(models.Model):
85 class Admin(models.Model):
83 """
86 """
84 Model for admin users
87 Model for admin users
85 """
88 """
86 name = models.CharField(max_length = 100)
89 name = models.CharField(max_length = 100)
87 password = models.CharField(max_length = 100)
90 password = models.CharField(max_length = 100)
88
91
89 def __unicode__(self):
92 def __unicode__(self):
90 return self.name + '/' + '*' * len(self.password)
93 return self.name + '/' + '*' * len(self.password)
91
94
@@ -1,88 +1,99 b''
1 from django.utils.unittest import TestCase
1 from django.utils.unittest import TestCase
2 from django.test.client import Client
2 from django.test.client import Client
3
3
4 import boards
4 import boards
5
5
6 from boards.models import Post, Admin
6 from boards.models import Post, Admin
7
7
8
8
9 class BoardTests(TestCase):
9 class BoardTests(TestCase):
10
10
11 def _create_post(self):
11 def _create_post(self):
12 return Post.objects.create_post(title = 'title',
12 return Post.objects.create_post(title = 'title',
13 text = 'text')
13 text = 'text')
14
14
15 def test_post_add(self):
15 def test_post_add(self):
16 post = self._create_post()
16 post = self._create_post()
17
17
18 self.assertIsNotNone(post)
18 self.assertIsNotNone(post)
19 self.assertEqual(boards.models.NO_PARENT, post.parent)
19 self.assertEqual(boards.models.NO_PARENT, post.parent)
20
20
21 def test_delete_post(self):
21 def test_delete_post(self):
22 post = self._create_post()
22 post = self._create_post()
23 post_id = post.id
23 post_id = post.id
24
24
25 Post.objects.delete_post(post)
25 Post.objects.delete_post(post)
26
26
27 self.assertFalse(Post.objects.exists(post_id))
27 self.assertFalse(Post.objects.exists(post_id))
28
28
29 def test_delete_posts_by_ip(self):
29 def test_delete_posts_by_ip(self):
30 post = self._create_post()
30 post = self._create_post()
31 post_id = post.id
31 post_id = post.id
32
32
33 Post.objects.delete_posts_by_ip('0.0.0.0')
33 Post.objects.delete_posts_by_ip('0.0.0.0')
34
34
35 self.assertFalse(Post.objects.exists(post_id))
35 self.assertFalse(Post.objects.exists(post_id))
36
36
37 # Authentication tests
37 # Authentication tests
38
38
39 def _create_test_user(self):
39 def _create_test_user(self):
40 admin = Admin(name = 'test_username12313584353165',
40 admin = Admin(name = 'test_username12313584353165',
41 password = 'test_userpassword135135512')
41 password = 'test_userpassword135135512')
42
42
43 admin.save()
43 admin.save()
44 return admin
44 return admin
45
45
46 def test_admin_login(self):
46 def test_admin_login(self):
47 client = Client()
47 client = Client()
48
48
49 self.assertFalse('admin' in client.session)
49 self.assertFalse('admin' in client.session)
50
50
51 admin = self._create_test_user()
51 admin = self._create_test_user()
52
52
53 response = client.post('/boards/login',
53 response = client.post('/boards/login',
54 {'name': admin.name, 'password': admin.password})
54 {'name': admin.name, 'password': admin.password})
55
55
56 # it means that login passed and user are redirected to another page
56 # it means that login passed and user are redirected to another page
57 self.assertEqual(302, response.status_code)
57 self.assertEqual(302, response.status_code)
58
58
59 self.assertTrue('admin' in client.session)
59 self.assertTrue('admin' in client.session)
60 self.assertTrue(client.session['admin'])
60 self.assertTrue(client.session['admin'])
61
61
62 admin.delete()
62 admin.delete()
63
63
64 wrong_name = 'sd2f1s3d21fs3d21f'
64 wrong_name = 'sd2f1s3d21fs3d21f'
65 wrong_password = 'sd2f1s3d21fs3d21fsdfsd'
65 wrong_password = 'sd2f1s3d21fs3d21fsdfsd'
66
66
67 client.post('/boards/login', {'name': wrong_name, 'password': wrong_password})
67 client.post('/boards/login', {'name': wrong_name, 'password': wrong_password})
68 self.assertFalse(client.session['admin'])
68 self.assertFalse(client.session['admin'])
69
69
70 def test_admin_logout(self):
70 def test_admin_logout(self):
71 client = Client()
71 client = Client()
72
72
73
73
74 self.assertFalse('admin' in client.session)
74 self.assertFalse('admin' in client.session)
75
75
76 admin = self._create_test_user()
76 admin = self._create_test_user()
77
77
78 client.post('/boards/login',
78 client.post('/boards/login',
79 {'name': admin.name, 'password': admin.password})
79 {'name': admin.name, 'password': admin.password})
80
80
81 self.assertTrue(client.session['admin'])
81 self.assertTrue(client.session['admin'])
82
82
83 client.get('/boards/logout')
83 client.get('/boards/logout')
84
84
85 self.assertFalse(client.session['admin'])
85 self.assertFalse(client.session['admin'])
86
86
87 admin.delete()
87 admin.delete()
88
88
89 def test_get_thread(self):
90 opening_post = self._create_post()
91 op_id = opening_post.id
92
93 for i in range(0, 2):
94 Post.objects.create_post('title', 'text',
95 parent_id = op_id)
96
97 thread = Post.objects.get_thread(op_id)
98
99 self.assertEqual(3, thread.__len__())
@@ -1,21 +1,21 b''
1 from django.conf.urls import patterns, url
1 from django.conf.urls import patterns, url
2 from boards import views
2 from boards import views
3
3
4 urlpatterns = patterns('',
4 urlpatterns = patterns('',
5
5
6 # /boards/
6 # /boards/
7 url(r'^$', views.index, name = 'index'),
7 url(r'^$', views.index, name = 'index'),
8
8
9 # login page
9 # login page
10 url(r'^login$', views.login, name='login'),
10 url(r'^login$', views.login, name='login'),
11 # logout page
11 # logout page
12 url(r'^logout$', views.logout, name='logout'),
12 url(r'^logout$', views.logout, name='logout'),
13
13
14 # /boards/tag/
14 # /boards/tag/
15 url(r'^(?P<tag>\w+)/$', views.tag, name = 'tag'),
15 url(r'^tag/(?P<tag>\w+)/$', views.tag, name = 'tag'),
16 # /boards/post_id/
16 # /boards/post_id/
17 url(r'^(?P<post>\w+)/$', views.thread, name = 'thread'),
17 url(r'^post/(?P<id>\w+)/$', views.thread, name = 'thread'),
18 # /boards/tag/post/
18 # /boards/tag/post/
19 url(r'^post.html$', views.new_post,
19 url(r'^post.html$', views.new_post,
20 name='post'),
20 name='post'),
21 )
21 )
@@ -1,86 +1,85 b''
1 from django.template import RequestContext
1 from django.template import RequestContext
2 from boards import forms
2 from boards import forms
3 from boards.models import Post, Admin
3 from boards.models import Post, Admin
4 from django.shortcuts import render, get_list_or_404
4 from django.shortcuts import render, get_list_or_404
5 from django.http import HttpResponseRedirect, Http404
5 from django.http import HttpResponseRedirect, Http404
6
6
7 def index(request):
7 def index(request):
8 context = RequestContext(request)
8 context = RequestContext(request)
9
9
10 if request.method == 'POST':
10 if request.method == 'POST':
11 Post.objects.create_post(request.POST['title'],
11 Post.objects.create_post(request.POST['title'],
12 request.POST['text'], ip = request.META['REMOTE_ADDR'])
12 request.POST['text'], ip = request.META['REMOTE_ADDR'])
13
13
14 threads = Post.objects.get_threads()
14 threads = Post.objects.get_threads()
15
15
16 context['threads'] = None if len(threads) == 0 else threads
16 context['threads'] = None if len(threads) == 0 else threads
17 context['form'] = forms.NewThreadForm()
17 context['form'] = forms.NewThreadForm()
18
18
19 return render(request, 'posting_general.html',
19 return render(request, 'posting_general.html',
20 context)
20 context)
21
21
22 def new_post(request):
22 def new_post(request):
23 """Add a new post (in thread or as a reply)."""
23 """Add a new post (in thread or as a reply)."""
24
24
25 title = request.POST['title']
25 title = request.POST['title']
26 text = request.POST['text']
26 text = request.POST['text']
27
27
28 image = request.POST['image']
28 image = request.POST['image']
29
29
30 # TODO Get tags list, download image (if link is given)
30 # TODO Get tags list, download image (if link is given)
31
31
32 post = Post.objects.create_post(title = title, text = text, image = image)
32 post = Post.objects.create_post(title = title, text = text, image = image)
33
33
34 # TODO Show the thread with a newly created post
34 # TODO Show the thread with a newly created post
35
35
36 def tag(request):
36 def tag(request):
37 """Get all tag threads (posts without a parent)."""
37 """Get all tag threads (posts without a parent)."""
38
38
39 tag_name = request.GET['tag']
39 tag_name = request.GET['tag']
40
40
41 threads = get_list_or_404(Post, tag = tag_name)
41 threads = get_list_or_404(Post, tag = tag_name)
42
42
43 context = RequestContext(request)
43 context = RequestContext(request)
44 context['threads'] = None if len(threads) == 0 else threads
44 context['threads'] = None if len(threads) == 0 else threads
45 context['tag'] = tag_name
45 context['tag'] = tag_name
46
46
47 return render(request, 'posting_general.html',
47 return render(request, 'posting_general.html',
48 context)
48 context)
49
49
50 def thread(request):
50 def thread(request, id):
51 """Get all thread posts"""
51 """Get all thread posts"""
52
52
53 # TODO Show 404 if there is no such thread
53 # TODO Show 404 if there is no such thread
54
54
55 opening_post_id = request.GET['id']
55 posts = Post.objects.get_thread(id)
56 posts = Post.objects.get_thread(opening_post_id)
57
56
58 context = RequestContext(request)
57 context = RequestContext(request)
59 context['posts'] = posts
58 context['posts'] = posts
60
59
61 return render(request), 'thread.html'
60 return render(request, 'thread.html', context)
62
61
63 def login(request):
62 def login(request):
64 """Log in as admin"""
63 """Log in as admin"""
65
64
66 if 'name' in request.POST and 'password' in request.POST:
65 if 'name' in request.POST and 'password' in request.POST:
67 request.session['admin'] = False
66 request.session['admin'] = False
68
67
69 isAdmin = len(Admin.objects.filter(name = request.POST['name'],
68 isAdmin = len(Admin.objects.filter(name = request.POST['name'],
70 password = request.POST['password'])) > 0
69 password = request.POST['password'])) > 0
71
70
72 if isAdmin :
71 if isAdmin :
73 request.session['admin'] = True
72 request.session['admin'] = True
74
73
75 response = HttpResponseRedirect('/boards')
74 response = HttpResponseRedirect('/boards')
76
75
77 else:
76 else:
78 response = render(request, 'login.html', {'error' : 'Login error'})
77 response = render(request, 'login.html', {'error' : 'Login error'})
79 else:
78 else:
80 response = render(request, 'login.html', {})
79 response = render(request, 'login.html', {})
81
80
82 return response
81 return response
83
82
84 def logout(request):
83 def logout(request):
85 request.session['admin'] = False
84 request.session['admin'] = False
86 return HttpResponseRedirect('/boards')
85 return HttpResponseRedirect('/boards')
@@ -1,27 +1,28 b''
1 {% extends "base.html" %}
1 {% extends "base.html" %}
2
2
3 {% block content %}
3 {% block content %}
4
4
5 {% if threads %}
5 {% if threads %}
6 {% for thread in threads %}
6 {% for thread in threads %}
7 <span class="title">{{ thread.title }}</span><br />
7 <span class="title">{{ thread.title }}</span><br />
8 <span class="text">{{ thread.text }}</span><br />
8 <span class="text">{{ thread.text }}</span><br />
9 <a class="link" href="/boards/id/{{ thread.id }}/">View thread</a>
9 <a class="link" href="/boards/post/{{ thread.id }}/">View
10 thread</a>
10 <hr />
11 <hr />
11 {% endfor %}
12 {% endfor %}
12 {% else %}
13 {% else %}
13 No threads found.
14 No threads found.
14 <hr />
15 <hr />
15 {% endif %}
16 {% endif %}
16
17
17 <div class="post-form">
18 <div class="post-form">
18 <form action="/boards/" method="post">{% csrf_token %}
19 <form action="/boards/" method="post">{% csrf_token %}
19 {{ form.as_p }}
20 {{ form.as_p }}
20 <input type="submit" value="Post!" />
21 <input type="submit" value="Post!" />
21 </form>
22 </form>
22 </div>
23 </div>
23
24
24 <HR />
25 <HR />
25
26
26 {% endblock %}
27 {% endblock %}
27
28
General Comments 0
You need to be logged in to leave comments. Login now