##// END OF EJS Templates
Implemented form validation. When the form fails validation, showing the index page.
neko259 -
r29:575870f6 default
parent child Browse files
Show More
@@ -1,8 +1,41 b''
1 1 from django import forms
2 2
3 3
4 class NewThreadForm(forms.Form):
5 title = forms.CharField(max_length=100)
6 text = forms.CharField(widget=forms.Textarea)
7 image = forms.ImageField()
8 tags = forms.CharField(max_length=100)
4 class PostForm(forms.Form):
5 MAX_TEXT_LENGTH = 10000
6 MAX_IMAGE_SIZE = 8 * 1024 * 1024
7
8 title = forms.CharField(max_length=50, required=False)
9 text = forms.CharField(widget=forms.Textarea, required=False)
10 image = forms.ImageField(required=False)
11 tags = forms.CharField(max_length=100, required=False)
12
13 def clean_text(self):
14 text = self.cleaned_data['text']
15 if text:
16 if len(text) > self.MAX_TEXT_LENGTH:
17 raise forms.ValidationError('Too many text')
18 return text
19
20 def clean_image(self):
21 image = self.cleaned_data['image']
22 if image:
23 if image._size > self.MAX_IMAGE_SIZE:
24 raise forms.ValidationError('Too large image: more than ' +
25 str(self.MAX_IMAGE_SIZE) + ' bytes')
26 return image
27
28 def clean(self):
29 cleaned_data = super(PostForm, self).clean()
30
31 text = cleaned_data.get('text')
32 image = cleaned_data.get('image')
33
34 if (not text) and (not image):
35 raise forms.ValidationError('Enter either text or image')
36
37 return cleaned_data
38
39
40 class ThreadForm(PostForm):
41 tags = forms.CharField(max_length=100) No newline at end of file
@@ -1,135 +1,145 b''
1 import os
1 2 from django.db import models
2 3 from django.utils import timezone
4 import time
3 5
4 6 from neboard import settings
5 7
6 8 import thumbs
7 9
8 10 NO_PARENT = -1
9 11 NO_IP = '0.0.0.0'
10 12 UNKNOWN_UA = ''
11 13
12 14
15 def update_image_filename(instance, filename):
16 """Get unique image filename"""
17
18 path = 'images/'
19 new_name = str(int(time.mktime(time.gmtime()))) + '_' + filename
20 return os.path.join(path, new_name)
21
22
13 23 class PostManager(models.Manager):
14 24 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
15 25 ip=NO_IP, tags=None):
16 26 post = self.create(title=title,
17 27 text=text,
18 28 pub_time=timezone.now(),
19 29 parent=parent_id,
20 30 image=image,
21 31 poster_ip=ip,
22 32 poster_user_agent=UNKNOWN_UA,
23 33 last_edit_time=timezone.now())
24 34
25 35 if tags:
26 36 for tag in tags:
27 37 post.tags.add(tag)
28 38
29 39 if parent_id != NO_PARENT:
30 40 parent = self.get(id=parent_id)
31 41 parent.last_edit_time=timezone.now()
32 42 parent.save()
33 43 else:
34 44 self._delete_old_threads()
35 45
36 46 return post
37 47
38 48 def delete_post(self, post):
39 49 children = self.filter(parent=post.id)
40 50 for child in children:
41 51 self.delete_post(child)
42 52 post.delete()
43 53
44 54 def delete_posts_by_ip(self, ip):
45 55 posts = self.filter(poster_ip=ip)
46 56 for post in posts:
47 57 self.delete_post(post)
48 58
49 59 def get_threads(self, tag=None):
50 60 if tag:
51 61 threads = self.filter(parent=NO_PARENT, tags=tag)
52 62 else:
53 63 threads = self.filter(parent=NO_PARENT)
54 64 threads = list(threads.order_by('-last_edit_time'))
55 65
56 66 return threads
57 67
58 68 def get_thread(self, opening_post_id):
59 69 opening_post = self.get(id=opening_post_id)
60 70 replies = self.filter(parent=opening_post_id)
61 71
62 72 thread = [opening_post]
63 73 thread.extend(replies)
64 74
65 75 return thread
66 76
67 77 def exists(self, post_id):
68 78 posts = self.filter(id=post_id)
69 79
70 80 return len(posts) > 0
71 81
72 82 def _delete_old_threads(self):
73 83 """
74 84 Preserves maximum thread count. If there are too many threads,
75 85 delete the old ones.
76 86 """
77 87
78 88 # TODO Try to find a better way to get the active thread count.
79 89
80 90 # TODO Move old threads to the archive instead of deleting them.
81 91 # Maybe make some 'old' field in the model to indicate the thread
82 92 # must not be shown and be able for replying.
83 93
84 94 threads = self.get_threads()
85 95 thread_count = len(threads)
86 96
87 97 if thread_count > settings.MAX_THREAD_COUNT:
88 98 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
89 99 old_threads = threads[-num_threads_to_delete:]
90 100
91 101 for thread in old_threads:
92 102 self.delete_post(thread)
93 103
94 104
95 105 class Tag(models.Model):
96 106 """
97 107 A tag is a text node assigned to the post. The tag serves as a board
98 108 section. There can be multiple tags for each message
99 109 """
100 110
101 111 name = models.CharField(max_length=100)
102 112 # TODO Connect the tag to its posts to check the number of threads for
103 113 # the tag.
104 114
105 115
106 116 class Post(models.Model):
107 117 """A post is a message."""
108 118
109 119 objects = PostManager()
110 120
111 title = models.CharField(max_length=100)
121 title = models.CharField(max_length=50)
112 122 pub_time = models.DateTimeField()
113 123 text = models.TextField()
114 image = thumbs.ImageWithThumbsField(upload_to='images/',
124 image = thumbs.ImageWithThumbsField(upload_to=update_image_filename,
115 125 blank=True, sizes=((200, 150),))
116 126 poster_ip = models.IPAddressField()
117 127 poster_user_agent = models.TextField()
118 128 parent = models.BigIntegerField()
119 129 tags = models.ManyToManyField(Tag)
120 130 last_edit_time = models.DateTimeField()
121 131
122 132 def __unicode__(self):
123 133 return self.title + ' (' + self.text + ')'
124 134
125 135
126 136 class Admin(models.Model):
127 137 """
128 138 Model for admin users
129 139 """
130 140 name = models.CharField(max_length=100)
131 141 password = models.CharField(max_length=100)
132 142
133 143 def __unicode__(self):
134 144 return self.name + '/' + '*' * len(self.password)
135 145
@@ -1,72 +1,71 b''
1 1 html {
2 background: #333;
2 background: #444;
3 3 color: #ffffff;
4 4 }
5 5
6 6 #admin_panel {
7 7 background: #FF0000;
8 8 color: #00FF00
9 9 }
10 10
11 11 .title {
12 12 font-weight: bold;
13 13 color: #ffcc00;
14 14 }
15 15
16 16 .post-form {
17 17 text-align: left;
18 color: #ffffff;
19 18 display: table;
20 border: dashed 1px;
21 padding: 3px;
19 border-radius: 5px;
20 padding: 5px;
22 21 margin: 5px;
22 background: #334;
23 23 }
24 24
25 25 .form-row {
26 26 display: table-row;
27 27 }
28 28
29 29 .form-input {
30 30 display: table-cell;
31 31 }
32 32
33 33 .link {
34 34 color: #829dba;
35 35 }
36 36
37 37 .link:hover {
38 38 color: #ba9f82;
39 39 }
40 40
41 41 .post_id {
42 42 color: #ffffff;
43 43 }
44 44
45 45 .block {
46 46 display: inline-block;
47 47 vertical-align: top;
48 48 }
49 49
50 50 .tag {
51 51 color: #b4cfec;
52 52 }
53 53
54 54 .tag:hover {
55 55 color: #d0edb4;
56 56 }
57 57
58 58 .post_id {
59 59 color: #fff380;
60 60 }
61 61
62 62 .post {
63 background: #222;
63 background: #333;
64 64 margin: 5px;
65 padding: 5px;
66 border: solid 1px;
65 padding: 10px;
67 66 border-radius: 5px;
68 67 }
69 68
70 69 .form-title {
71 70 font-weight: bolder;
72 71 } No newline at end of file
@@ -1,125 +1,133 b''
1 1 from django.template import RequestContext
2 2 from boards import forms
3 3 import boards
4 from boards.forms import NewThreadForm
4 from boards.forms import ThreadForm, PostForm
5 5 from boards.models import Post, Admin, Tag
6 6 from django.shortcuts import render, get_list_or_404, redirect
7 7 from django.http import HttpResponseRedirect, Http404
8 8
9 9
10 10 def index(request):
11 11 context = RequestContext(request)
12 12
13 13 if request.method == 'POST':
14 14 return new_post(request)
15 15 else:
16 16 threads = Post.objects.get_threads()
17 17
18 18 context['threads'] = None if len(threads) == 0 else threads
19 context['form'] = forms.NewThreadForm()
19 context['form'] = forms.ThreadForm()
20 20
21 21 return render(request, 'posting_general.html',
22 22 context)
23 23
24 24
25 25 def new_post(request, thread_id=boards.models.NO_PARENT):
26 26 """Add a new post (in thread or as a reply)."""
27 27
28 form = NewThreadForm(request.POST, request.FILES)
28 if thread_id == boards.models.NO_PARENT:
29 form = ThreadForm(request.POST, request.FILES)
30 else:
31 form = PostForm(request.POST, request.FILES)
29 32
30 title = request.POST['title']
31 text = request.POST['text']
33 if form.is_valid():
34 data = form.cleaned_data
35 else:
36 return redirect(index)
32 37
33 if 'image' in request.FILES.keys():
34 image = request.FILES['image']
38 title = data['title']
39 text = data['text']
40
41 if 'image' in data.keys():
42 image = data['image']
35 43 else:
36 44 image = None
37 45
38 46 ip = request.META['REMOTE_ADDR']
39 47
40 48 tags = []
41 49 if thread_id == boards.models.NO_PARENT:
42 tag_strings = request.POST['tags']
50 tag_strings = data['tags']
43 51
44 52 if tag_strings:
45 53 tag_strings = tag_strings.split(',')
46 54 for tag_name in tag_strings:
47 55 tag_name = tag_name.strip()
48 56 if len(tag_name) > 0:
49 57 tag, created = Tag.objects.get_or_create(name=tag_name)
50 58 tags.append(tag)
51 59
52 60 # TODO Add a possibility to define a link image instead of an image file.
53 61 # If a link is given, download the image automatically.
54 62
55 63 post = Post.objects.create_post(title=title, text=text, ip=ip,
56 64 parent_id=thread_id, image=image,
57 65 tags=tags)
58 66
59 67 thread_to_show = (post.id if thread_id == boards.models.NO_PARENT else
60 68 thread_id)
61 69 return redirect(thread, post_id=thread_to_show)
62 70
63 71
64 72 def tag(request, tag_name):
65 73 """Get all tag threads (posts without a parent)."""
66 74
67 75 tag = Tag.objects.get(name=tag_name)
68 76 threads = Post.objects.get_threads(tag=tag)
69 77
70 78 if request.method == 'POST':
71 79 return new_post(request)
72 80 else:
73 81 context = RequestContext(request)
74 82 context['threads'] = None if len(threads) == 0 else threads
75 83 context['tag'] = tag_name
76 84
77 context['form'] = forms.NewThreadForm(initial={'tags': tag_name})
85 context['form'] = forms.ThreadForm(initial={'tags': tag_name})
78 86
79 87 return render(request, 'posting_general.html',
80 88 context)
81 89
82 90
83 91 def thread(request, post_id):
84 92 """Get all thread posts"""
85 93
86 94 if request.method == 'POST':
87 95 return new_post(request, post_id)
88 96 else:
89 97 # TODO Show 404 if there is no such thread
90 98 posts = Post.objects.get_thread(post_id)
91 99
92 100 context = RequestContext(request)
93 101 context['posts'] = posts
94 102
95 context['form'] = forms.NewThreadForm()
103 context['form'] = forms.PostForm()
96 104
97 105 return render(request, 'thread.html', context)
98 106
99 107
100 108 def login(request):
101 109 """Log in as admin"""
102 110
103 111 if 'name' in request.POST and 'password' in request.POST:
104 112 request.session['admin'] = False
105 113
106 114 isAdmin = len(Admin.objects.filter(name=request.POST['name'],
107 115 password=request.POST[
108 116 'password'])) > 0
109 117
110 118 if isAdmin:
111 119 request.session['admin'] = True
112 120
113 121 response = HttpResponseRedirect('/')
114 122
115 123 else:
116 124 response = render(request, 'login.html', {'error': 'Login error'})
117 125 else:
118 126 response = render(request, 'login.html', {})
119 127
120 128 return response
121 129
122 130
123 131 def logout(request):
124 132 request.session['admin'] = False
125 133 return HttpResponseRedirect('/') No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now