##// END OF EJS Templates
Added localization (not fully working). Added tags posting. Changed the design a bit.
neko259 -
r24:bb515fee default
parent child Browse files
Show More
@@ -0,0 +1,38 b''
1 # SOME DESCRIPTIVE TITLE.
2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 # This file is distributed under the same license as the PACKAGE package.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5 #
6 #, fuzzy
7 msgid ""
8 msgstr ""
9 "Project-Id-Version: PACKAGE VERSION\n"
10 "Report-Msgid-Bugs-To: \n"
11 "POT-Creation-Date: 2013-04-05 20:55+0300\n"
12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 "Language-Team: LANGUAGE <LL@li.org>\n"
15 "Language: \n"
16 "MIME-Version: 1.0\n"
17 "Content-Type: text/plain; charset=UTF-8\n"
18 "Content-Transfer-Encoding: 8bit\n"
19 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
20 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
21
22 msgid "Title"
23 msgstr "Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ"
24
25 msgid "Text"
26 msgstr "ВСкст"
27
28 msgid "Image"
29 msgstr "ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ°"
30
31 msgid "Post"
32 msgstr "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ"
33
34 msgid "Tags"
35 msgstr "Π’Π΅Π³ΠΈ"
36
37 msgid "View"
38 msgstr "ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€" No newline at end of file
@@ -1,8 +1,8 b''
1 from django import forms
1 from django import forms
2
2
3
3
4 class NewThreadForm(forms.Form):
4 class NewThreadForm(forms.Form):
5 title = forms.CharField(max_length = 100)
5 title = forms.CharField(max_length=100)
6 text = forms.CharField(widget = forms.Textarea)
6 text = forms.CharField(widget=forms.Textarea)
7 image = forms.ImageField()
7 image = forms.ImageField()
8 tags = forms.CharField(max_length=100)
8 tags = forms.CharField(max_length=100)
@@ -1,97 +1,101 b''
1 from django.db import models
1 from django.db import models
2 from django.utils import timezone
2 from django.utils import timezone
3
3
4 from neboard import settings
4 from neboard import settings
5
5
6 import thumbs
6 import thumbs
7
7
8 NO_PARENT = -1
8 NO_PARENT = -1
9 NO_IP = '0.0.0.0'
9 NO_IP = '0.0.0.0'
10 UNKNOWN_UA = ''
10 UNKNOWN_UA = ''
11
11
12
12
13 class PostManager(models.Manager):
13 class PostManager(models.Manager):
14 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
14 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
15 ip=NO_IP):
15 ip=NO_IP, tags=None):
16 post = self.create(title=title,
16 post = self.create(title=title,
17 text=text,
17 text=text,
18 pub_time=timezone.now(),
18 pub_time=timezone.now(),
19 parent=parent_id,
19 parent=parent_id,
20 image=image,
20 image=image,
21 poster_ip=ip,
21 poster_ip=ip,
22 poster_user_agent=UNKNOWN_UA)
22 poster_user_agent=UNKNOWN_UA)
23
23
24 if tags:
25 for tag in tags:
26 post.tags.add(tag)
27
24 return post
28 return post
25
29
26 def delete_post(self, post):
30 def delete_post(self, post):
27 children = self.filter(parent=post.id)
31 children = self.filter(parent=post.id)
28 for child in children:
32 for child in children:
29 self.delete_post(child)
33 self.delete_post(child)
30 post.delete()
34 post.delete()
31
35
32 def delete_posts_by_ip(self, ip):
36 def delete_posts_by_ip(self, ip):
33 posts = self.filter(poster_ip=ip)
37 posts = self.filter(poster_ip=ip)
34 for post in posts:
38 for post in posts:
35 self.delete_post(post)
39 self.delete_post(post)
36
40
37 def get_threads(self, tag=None):
41 def get_threads(self, tag=None):
38 if tag is None:
42 if tag is None:
39 threads = self.filter(parent=NO_PARENT)
43 threads = self.filter(parent=NO_PARENT)
40 else:
44 else:
41 threads = self.filter(parent=NO_PARENT, tag=tag)
45 threads = self.filter(parent=NO_PARENT, tag=tag)
42
46
43 return threads
47 return threads
44
48
45 def get_thread(self, opening_post_id):
49 def get_thread(self, opening_post_id):
46 opening_post = self.get(id=opening_post_id)
50 opening_post = self.get(id=opening_post_id)
47 replies = self.filter(parent=opening_post_id)
51 replies = self.filter(parent=opening_post_id)
48
52
49 thread = [opening_post]
53 thread = [opening_post]
50 thread.extend(replies)
54 thread.extend(replies)
51
55
52 return thread
56 return thread
53
57
54 def exists(self, post_id):
58 def exists(self, post_id):
55 posts = self.filter(id=post_id)
59 posts = self.filter(id=post_id)
56
60
57 return len(posts) > 0
61 return len(posts) > 0
58
62
59
63
60 class Tag(models.Model):
64 class Tag(models.Model):
61 """
65 """
62 A tag is a text node assigned to the post. The tag serves as a board
66 A tag is a text node assigned to the post. The tag serves as a board
63 section. There can be multiple tags for each message
67 section. There can be multiple tags for each message
64 """
68 """
65
69
66 name = models.CharField(max_length=100)
70 name = models.CharField(max_length=100)
67
71
68
72
69 class Post(models.Model):
73 class Post(models.Model):
70 """A post is a message."""
74 """A post is a message."""
71
75
72 objects = PostManager()
76 objects = PostManager()
73
77
74 title = models.CharField(max_length=100)
78 title = models.CharField(max_length=100)
75 pub_time = models.DateTimeField()
79 pub_time = models.DateTimeField()
76 text = models.TextField()
80 text = models.TextField()
77 image = thumbs.ImageWithThumbsField(upload_to='images/',
81 image = thumbs.ImageWithThumbsField(upload_to='images/',
78 blank=True, sizes=((200, 150),))
82 blank=True, sizes=((200, 150),))
79 poster_ip = models.IPAddressField()
83 poster_ip = models.IPAddressField()
80 poster_user_agent = models.TextField()
84 poster_user_agent = models.TextField()
81 parent = models.BigIntegerField()
85 parent = models.BigIntegerField()
82 tags = models.ManyToManyField(Tag)
86 tags = models.ManyToManyField(Tag)
83
87
84 def __unicode__(self):
88 def __unicode__(self):
85 return self.title + ' (' + self.text + ')'
89 return self.title + ' (' + self.text + ')'
86
90
87
91
88 class Admin(models.Model):
92 class Admin(models.Model):
89 """
93 """
90 Model for admin users
94 Model for admin users
91 """
95 """
92 name = models.CharField(max_length=100)
96 name = models.CharField(max_length=100)
93 password = models.CharField(max_length=100)
97 password = models.CharField(max_length=100)
94
98
95 def __unicode__(self):
99 def __unicode__(self):
96 return self.name + '/' + '*' * len(self.password)
100 return self.name + '/' + '*' * len(self.password)
97
101
@@ -1,39 +1,53 b''
1 html {
1 html {
2 background: #333;
2 background: #333;
3 color: #ffffff;
3 }
4 }
4
5
5 #admin_panel {
6 #admin_panel {
6 background: #FF0000;
7 background: #FF0000;
7 color: #00FF00
8 color: #00FF00
8 }
9 }
9
10
10 .title {
11 .title {
11 font-weight: bold;
12 font-weight: bold;
12 color: #ffcc00;
13 color: #ffcc00;
13 }
14 }
14
15
15 .text {
16 color: #ffffff;
17 }
18
19 .post-form {
16 .post-form {
20 text-align: left;
17 text-align: left;
21 color: #ffffff;
18 color: #ffffff;
19 display: table;
20 }
21
22 .form-row {
23 display: table-row;
24 }
25
26 .form-input {
27 display: table-cell;
22 }
28 }
23
29
24 .link {
30 .link {
25 color: #33bb33;
31 color: #33bb33;
26 }
32 }
27
33
28 .link:hover {
34 .link:hover {
29 color: #00ff00;
35 color: #00ff00;
30 }
36 }
31
37
32 .post_id {
38 .post_id {
33 color: #ffffff;
39 color: #ffffff;
34 }
40 }
35
41
36 .block {
42 .block {
37 display: inline-block;
43 display: inline-block;
38 vertical-align: top;
44 vertical-align: top;
45 }
46
47 .tag {
48 color: #bb7766;
49 }
50
51 .tag:hover {
52 color: #dd8888;
39 } No newline at end of file
53 }
@@ -1,97 +1,102 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, Tag
7
7
8
8
9 class BoardTests(TestCase):
9 class BoardTests(TestCase):
10 def _create_post(self):
10 def _create_post(self):
11 return Post.objects.create_post(title='title',
11 return Post.objects.create_post(title='title',
12 text='text')
12 text='text')
13
13
14 def test_post_add(self):
14 def test_post_add(self):
15 post = self._create_post()
15 post = self._create_post()
16
16
17 self.assertIsNotNone(post)
17 self.assertIsNotNone(post)
18 self.assertEqual(boards.models.NO_PARENT, post.parent)
18 self.assertEqual(boards.models.NO_PARENT, post.parent)
19
19
20 def test_delete_post(self):
20 def test_delete_post(self):
21 post = self._create_post()
21 post = self._create_post()
22 post_id = post.id
22 post_id = post.id
23
23
24 Post.objects.delete_post(post)
24 Post.objects.delete_post(post)
25
25
26 self.assertFalse(Post.objects.exists(post_id))
26 self.assertFalse(Post.objects.exists(post_id))
27
27
28 def test_delete_posts_by_ip(self):
28 def test_delete_posts_by_ip(self):
29 post = self._create_post()
29 post = self._create_post()
30 post_id = post.id
30 post_id = post.id
31
31
32 Post.objects.delete_posts_by_ip('0.0.0.0')
32 Post.objects.delete_posts_by_ip('0.0.0.0')
33
33
34 self.assertFalse(Post.objects.exists(post_id))
34 self.assertFalse(Post.objects.exists(post_id))
35
35
36 # Authentication tests
36 # Authentication tests
37
37
38 def _create_test_user(self):
38 def _create_test_user(self):
39 admin = Admin(name='test_username12313584353165',
39 admin = Admin(name='test_username12313584353165',
40 password='test_userpassword135135512')
40 password='test_userpassword135135512')
41
41
42 admin.save()
42 admin.save()
43 return admin
43 return admin
44
44
45 def test_admin_login(self):
45 def test_admin_login(self):
46 client = Client()
46 client = Client()
47
47
48 self.assertFalse('admin' in client.session)
48 self.assertFalse('admin' in client.session)
49
49
50 admin = self._create_test_user()
50 admin = self._create_test_user()
51
51
52 response = client.post('/login',
52 response = client.post('/login',
53 {'name': admin.name, 'password': admin.password})
53 {'name': admin.name, 'password': admin.password})
54
54
55 # it means that login passed and user are redirected to another page
55 # it means that login passed and user are redirected to another page
56 self.assertEqual(302, response.status_code)
56 self.assertEqual(302, response.status_code)
57
57
58 self.assertTrue('admin' in client.session)
58 self.assertTrue('admin' in client.session)
59 self.assertTrue(client.session['admin'])
59 self.assertTrue(client.session['admin'])
60
60
61 admin.delete()
61 admin.delete()
62
62
63 wrong_name = 'sd2f1s3d21fs3d21f'
63 wrong_name = 'sd2f1s3d21fs3d21f'
64 wrong_password = 'sd2f1s3d21fs3d21fsdfsd'
64 wrong_password = 'sd2f1s3d21fs3d21fsdfsd'
65
65
66 client.post('/login', {'name': wrong_name, 'password': wrong_password})
66 client.post('/login', {'name': wrong_name, 'password': wrong_password})
67 self.assertFalse(client.session['admin'])
67 self.assertFalse(client.session['admin'])
68
68
69 def test_admin_logout(self):
69 def test_admin_logout(self):
70 client = Client()
70 client = Client()
71
71
72 self.assertFalse('admin' in client.session)
72 self.assertFalse('admin' in client.session)
73
73
74 admin = self._create_test_user()
74 admin = self._create_test_user()
75
75
76 client.post('/login',
76 client.post('/login',
77 {'name': admin.name, 'password': admin.password})
77 {'name': admin.name, 'password': admin.password})
78
78
79 self.assertTrue(client.session['admin'])
79 self.assertTrue(client.session['admin'])
80
80
81 client.get('/logout')
81 client.get('/logout')
82
82
83 self.assertFalse(client.session['admin'])
83 self.assertFalse(client.session['admin'])
84
84
85 admin.delete()
85 admin.delete()
86
86
87 def test_get_thread(self):
87 def test_get_thread(self):
88 opening_post = self._create_post()
88 opening_post = self._create_post()
89 op_id = opening_post.id
89 op_id = opening_post.id
90
90
91 for i in range(0, 2):
91 for i in range(0, 2):
92 Post.objects.create_post('title', 'text',
92 Post.objects.create_post('title', 'text',
93 parent_id=op_id)
93 parent_id=op_id)
94
94
95 thread = Post.objects.get_thread(op_id)
95 thread = Post.objects.get_thread(op_id)
96
96
97 self.assertEqual(3, len(thread))
97 self.assertEqual(3, len(thread))
98
99 def test_create_post_with_tag(self):
100 tag = Tag.objects.create(name='test_tag')
101 post = Post.objects.create_post(title='title', text='text', tags=[tag])
102 self.assertIsNotNone(post) No newline at end of file
@@ -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'^tag/(?P<tag>\w+)/$', views.tag, name = 'tag'),
15 url(r'^tag/(?P<tag_name>\w+)/$', views.tag, name = 'tag'),
16 # /boards/post_id/
16 # /boards/post_id/
17 url(r'^thread/(?P<id>\w+)/$', views.thread, name = 'thread'),
17 url(r'^thread/(?P<post_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,107 +1,125 b''
1 from django.template import RequestContext
1 from django.template import RequestContext
2 from boards import forms
2 from boards import forms
3 import boards
3 import boards
4 from boards.forms import NewThreadForm
4 from boards.forms import NewThreadForm
5 from boards.models import Post, Admin
5 from boards.models import Post, Admin, Tag
6 from django.shortcuts import render, get_list_or_404, redirect
6 from django.shortcuts import render, get_list_or_404, redirect
7 from django.http import HttpResponseRedirect, Http404
7 from django.http import HttpResponseRedirect, Http404
8
8
9
9
10 def index(request):
10 def index(request):
11 context = RequestContext(request)
11 context = RequestContext(request)
12
12
13 if request.method == 'POST':
13 if request.method == 'POST':
14 return new_post(request)
14 return new_post(request)
15 else:
15 else:
16 threads = Post.objects.get_threads()
16 threads = Post.objects.get_threads()
17
17
18 context['threads'] = None if len(threads) == 0 else threads
18 context['threads'] = None if len(threads) == 0 else threads
19 context['form'] = forms.NewThreadForm()
19 context['form'] = forms.NewThreadForm()
20
20
21 return render(request, 'posting_general.html',
21 return render(request, 'posting_general.html',
22 context)
22 context)
23
23
24
24
25 def new_post(request, thread_id=boards.models.NO_PARENT):
25 def new_post(request, thread_id=boards.models.NO_PARENT):
26 """Add a new post (in thread or as a reply)."""
26 """Add a new post (in thread or as a reply)."""
27
27
28 form = NewThreadForm(request.POST, request.FILES)
28 form = NewThreadForm(request.POST, request.FILES)
29
29
30 title = request.POST['title']
30 title = request.POST['title']
31 text = request.POST['text']
31 text = request.POST['text']
32
32
33 if 'image' in request.FILES.keys():
33 if 'image' in request.FILES.keys():
34 image = request.FILES['image']
34 image = request.FILES['image']
35 else:
35 else:
36 image = None
36 image = None
37
37
38 ip = request.META['REMOTE_ADDR']
38 ip = request.META['REMOTE_ADDR']
39
39
40 # TODO Get tags list, download image (if link is given)
40 tags = []
41 if thread_id == boards.models.NO_PARENT:
42 tag_strings = request.POST['tags']
43
44 if tag_strings:
45 tag_strings = tag_strings.split(',')
46 for tag_name in tag_strings:
47 tag_name = tag_name.strip()
48 if len(tag_name) > 0:
49 tag, created = Tag.objects.get_or_create(name=tag_name)
50 tags.append(tag)
51
52 # TODO Add a possibility to define a link image instead of an image file.
53 # If a link is given, download the image automatically.
41
54
42 post = Post.objects.create_post(title=title, text=text, ip=ip,
55 post = Post.objects.create_post(title=title, text=text, ip=ip,
43 parent_id=thread_id, image=image)
56 parent_id=thread_id, image=image,
57 tags=tags)
44
58
45 thread_to_show = (post.id if thread_id == boards.models.NO_PARENT else
59 thread_to_show = (post.id if thread_id == boards.models.NO_PARENT else
46 thread_id)
60 thread_id)
47 return redirect(thread, id=thread_to_show)
61 return redirect(thread, post_id=thread_to_show)
48
62
49
63
50 def tag(request):
64 def tag(request, tag_name):
51 """Get all tag threads (posts without a parent)."""
65 """Get all tag threads (posts without a parent)."""
52
66
53 tag_name = request.GET['tag']
67 tag = Tag.objects.get(name=tag_name)
54
68 threads = get_list_or_404(Post, tags=tag)
55 threads = get_list_or_404(Post, tag=tag_name)
56
69
57 context = RequestContext(request)
70 if request.method == 'POST':
58 context['threads'] = None if len(threads) == 0 else threads
71 return new_post(request)
59 context['tag'] = tag_name
72 else:
73 context = RequestContext(request)
74 context['threads'] = None if len(threads) == 0 else threads
75 context['tag'] = tag_name
60
76
61 return render(request, 'posting_general.html',
77 context['form'] = forms.NewThreadForm(initial={'tags': tag_name})
62 context)
78
79 return render(request, 'posting_general.html',
80 context)
63
81
64
82
65 def thread(request, id):
83 def thread(request, post_id):
66 """Get all thread posts"""
84 """Get all thread posts"""
67
85
68 if request.method == 'POST':
86 if request.method == 'POST':
69 return new_post(request, id)
87 return new_post(request, post_id)
70 else:
88 else:
71 # TODO Show 404 if there is no such thread
89 # TODO Show 404 if there is no such thread
72 posts = Post.objects.get_thread(id)
90 posts = Post.objects.get_thread(post_id)
73
91
74 context = RequestContext(request)
92 context = RequestContext(request)
75 context['posts'] = posts
93 context['posts'] = posts
76
94
77 context['form'] = forms.NewThreadForm()
95 context['form'] = forms.NewThreadForm()
78
96
79 return render(request, 'thread.html', context)
97 return render(request, 'thread.html', context)
80
98
81
99
82 def login(request):
100 def login(request):
83 """Log in as admin"""
101 """Log in as admin"""
84
102
85 if 'name' in request.POST and 'password' in request.POST:
103 if 'name' in request.POST and 'password' in request.POST:
86 request.session['admin'] = False
104 request.session['admin'] = False
87
105
88 isAdmin = len(Admin.objects.filter(name=request.POST['name'],
106 isAdmin = len(Admin.objects.filter(name=request.POST['name'],
89 password=request.POST[
107 password=request.POST[
90 'password'])) > 0
108 'password'])) > 0
91
109
92 if isAdmin:
110 if isAdmin:
93 request.session['admin'] = True
111 request.session['admin'] = True
94
112
95 response = HttpResponseRedirect('/')
113 response = HttpResponseRedirect('/')
96
114
97 else:
115 else:
98 response = render(request, 'login.html', {'error': 'Login error'})
116 response = render(request, 'login.html', {'error': 'Login error'})
99 else:
117 else:
100 response = render(request, 'login.html', {})
118 response = render(request, 'login.html', {})
101
119
102 return response
120 return response
103
121
104
122
105 def logout(request):
123 def logout(request):
106 request.session['admin'] = False
124 request.session['admin'] = False
107 return HttpResponseRedirect('/') No newline at end of file
125 return HttpResponseRedirect('/')
@@ -1,34 +1,61 b''
1 {% extends "base.html" %}
1 {% extends "base.html" %}
2
2
3 {% load i18n %}
4
3 {% block content %}
5 {% block content %}
4
6
5 {% if threads %}
7 {% if threads %}
6 {% for thread in threads %}
8 {% for thread in threads %}
7 {% if thread.image %}
9 {% if thread.image %}
8 <div class="block">
10 <div class="block">
9 <a href="{{ thread.image.url }}"><img
11 <a href="{{ thread.image.url }}"><img
10 src="{{ thread.image.url_200x150 }}" />
12 src="{{ thread.image.url_200x150 }}" />
11 </a>
13 </a>
12 </div>
14 </div>
13 {% endif %}
15 {% endif %}
14 <div class="block">
16 <div class="block">
15 <span class="title">{{ thread.title }}</span>
17 <span class="title">{{ thread.title }}</span>
16 <a class="link" href="/thread/{{ thread.id }}/">
18 <a class="link" href="/thread/{{ thread.id }}/">
17 [View]</a><br />
19 [{% trans "View" %}]</a><br />
18 <span class="text">{{ thread.text }}</span><br />
20 {{ thread.text }}<br />
21 {% if thread.tags %}
22 <span class="tags">{% trans 'Tags' %}:
23 {% for tag in thread.tags.all %}
24 <a class="tag" href="/tag/{{ tag.name }}">
25 {{ tag.name }}</a>
26 {% endfor %}
27 </span>
28 {% endif %}
19 </div>
29 </div>
20 <hr />
30 <hr />
21 {% endfor %}
31 {% endfor %}
22 {% else %}
32 {% else %}
23 <span class="text">No threads found.</span>
33 No threads found.
24 <hr />
34 <hr />
25 {% endif %}
35 {% endif %}
26
36
27 <div class="post-form">
37 <div class="post-form">
28 <form enctype="multipart/form-data" method="post">{% csrf_token %}
38 <div class="post-form">
29 {{ form.as_p }}
39 <form enctype="multipart/form-data" method="post">{% csrf_token %}
30 <input type="submit" value="Post!" />
40 <div class="form-row">
31 </form>
41 <div class="form-input">{% trans 'Title' %}</div>
42 <div class="form-input">{{ form.title }}</div>
43 </div>
44 <div class="form-row">
45 <div class="form-input">{% trans 'Text' %}</div>
46 <div class="form-input">{{ form.text }}</div>
47 </div>
48 <div class="form-row">
49 <div class="form-input">{% trans 'Image' %}</div>
50 <div class="form-input">{{ form.image }}</div>
51 </div>
52 <div class="form-row">
53 <div class="form-input">{% trans 'Tags' %}</div>
54 <div class="form-input">{{ form.tags }}</div>
55 </div>
56 <input type="submit" value="{% trans 'Post' %}" />
57 </form>
58 </div>
32 </div>
59 </div>
33
60
34 {% endblock %} No newline at end of file
61 {% endblock %}
@@ -1,33 +1,54 b''
1 {% extends "base.html" %}
1 {% extends "base.html" %}
2
2
3 {% load i18n %}
4
3 {% block content %}
5 {% block content %}
4
6
5 {% if posts %}
7 {% if posts %}
6 {% for post in posts %}
8 {% for post in posts %}
7 {% if post.image %}
9 {% if post.image %}
8 <div class="block">
10 <div class="block">
9 <a href="{{ post.image.url }}"><img
11 <a href="{{ post.image.url }}"><img
10 src="{{ post.image.url_200x150 }}" />
12 src="{{ post.image.url_200x150 }}" />
11 </a>
13 </a>
12 </div>
14 </div>
13 {% endif %}
15 {% endif %}
14 <div class="block">
16 <div class="block">
15 <span class="title">{{ post.title }}</span>
17 <span class="title">{{ post.title }}</span>
16 <span class="post_id">(#{{ post.id }})</span><br />
18 <span class="post_id">(#{{ post.id }})</span><br />
17 <span class="text">{{ post.text }}</span><br />
19 {{ post.text }}<br />
20 {% if post.tags %}
21 <span class="tags">{% trans 'Tags' %}:
22 {% for tag in post.tags.all %}
23 <a class="tag" href="/tag/{{ tag.name }}">
24 {{ tag.name }}</a>
25 {% endfor %}
26 </span>
27 {% endif %}
18 </div>
28 </div>
19 <hr />
29 <hr />
20 {% endfor %}
30 {% endfor %}
21 {% else %}
31 {% else %}
22 No threads found.
32 No threads found.
23 <hr />
33 <hr />
24 {% endif %}
34 {% endif %}
25
35
26 <div class="post-form">
36 <div class="post-form">
27 <form enctype="multipart/form-data" method="post">{% csrf_token %}
37 <form enctype="multipart/form-data" method="post">{% csrf_token %}
28 {{ form.as_p }}
38 <div class="form-row">
29 <input type="submit" value="Post!" />
39 <div class="form-input">{% trans 'Title' %}</div>
40 <div class="form-input">{{ form.title }}</div>
41 </div>
42 <div class="form-row">
43 <div class="form-input">{% trans 'Text' %}</div>
44 <div class="form-input">{{ form.text }}</div>
45 </div>
46 <div class="form-row">
47 <div class="form-input">{% trans 'Image' %}</div>
48 <div class="form-input">{{ form.image }}</div>
49 </div>
50 <input type="submit" value="{% trans 'Post' %}" />
30 </form>
51 </form>
31 </div>
52 </div>
32
53
33 {% endblock %} No newline at end of file
54 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now