##// END OF EJS Templates
Truncating thread text in threads list. Fixed tag threads order.
neko259 -
r27:26364823 default
parent child Browse files
Show More
@@ -1,109 +1,109 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, tags=None):
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 last_edit_time=timezone.now())
23 last_edit_time=timezone.now())
24
24
25 if tags:
25 if tags:
26 for tag in tags:
26 for tag in tags:
27 post.tags.add(tag)
27 post.tags.add(tag)
28
28
29 if parent_id != NO_PARENT:
29 if parent_id != NO_PARENT:
30 parent = self.get(id=parent_id)
30 parent = self.get(id=parent_id)
31 parent.last_edit_time=timezone.now()
31 parent.last_edit_time=timezone.now()
32 parent.save()
32 parent.save()
33
33
34 return post
34 return post
35
35
36 def delete_post(self, post):
36 def delete_post(self, post):
37 children = self.filter(parent=post.id)
37 children = self.filter(parent=post.id)
38 for child in children:
38 for child in children:
39 self.delete_post(child)
39 self.delete_post(child)
40 post.delete()
40 post.delete()
41
41
42 def delete_posts_by_ip(self, ip):
42 def delete_posts_by_ip(self, ip):
43 posts = self.filter(poster_ip=ip)
43 posts = self.filter(poster_ip=ip)
44 for post in posts:
44 for post in posts:
45 self.delete_post(post)
45 self.delete_post(post)
46
46
47 def get_threads(self, tag=None):
47 def get_threads(self, tag=None):
48 if tag is None:
48 if tag:
49 threads = self.filter(parent=NO_PARENT, tags=tag)
50 else:
49 threads = self.filter(parent=NO_PARENT)
51 threads = self.filter(parent=NO_PARENT)
50 else:
51 threads = self.filter(parent=NO_PARENT, tag=tag)
52 threads = list(threads.order_by('-last_edit_time'))
52 threads = list(threads.order_by('-last_edit_time'))
53
53
54 return threads
54 return threads
55
55
56 def get_thread(self, opening_post_id):
56 def get_thread(self, opening_post_id):
57 opening_post = self.get(id=opening_post_id)
57 opening_post = self.get(id=opening_post_id)
58 replies = self.filter(parent=opening_post_id)
58 replies = self.filter(parent=opening_post_id)
59
59
60 thread = [opening_post]
60 thread = [opening_post]
61 thread.extend(replies)
61 thread.extend(replies)
62
62
63 return thread
63 return thread
64
64
65 def exists(self, post_id):
65 def exists(self, post_id):
66 posts = self.filter(id=post_id)
66 posts = self.filter(id=post_id)
67
67
68 return len(posts) > 0
68 return len(posts) > 0
69
69
70
70
71 class Tag(models.Model):
71 class Tag(models.Model):
72 """
72 """
73 A tag is a text node assigned to the post. The tag serves as a board
73 A tag is a text node assigned to the post. The tag serves as a board
74 section. There can be multiple tags for each message
74 section. There can be multiple tags for each message
75 """
75 """
76
76
77 name = models.CharField(max_length=100)
77 name = models.CharField(max_length=100)
78
78
79
79
80 class Post(models.Model):
80 class Post(models.Model):
81 """A post is a message."""
81 """A post is a message."""
82
82
83 objects = PostManager()
83 objects = PostManager()
84
84
85 title = models.CharField(max_length=100)
85 title = models.CharField(max_length=100)
86 pub_time = models.DateTimeField()
86 pub_time = models.DateTimeField()
87 text = models.TextField()
87 text = models.TextField()
88 image = thumbs.ImageWithThumbsField(upload_to='images/',
88 image = thumbs.ImageWithThumbsField(upload_to='images/',
89 blank=True, sizes=((200, 150),))
89 blank=True, sizes=((200, 150),))
90 poster_ip = models.IPAddressField()
90 poster_ip = models.IPAddressField()
91 poster_user_agent = models.TextField()
91 poster_user_agent = models.TextField()
92 parent = models.BigIntegerField()
92 parent = models.BigIntegerField()
93 tags = models.ManyToManyField(Tag)
93 tags = models.ManyToManyField(Tag)
94 last_edit_time = models.DateTimeField()
94 last_edit_time = models.DateTimeField()
95
95
96 def __unicode__(self):
96 def __unicode__(self):
97 return self.title + ' (' + self.text + ')'
97 return self.title + ' (' + self.text + ')'
98
98
99
99
100 class Admin(models.Model):
100 class Admin(models.Model):
101 """
101 """
102 Model for admin users
102 Model for admin users
103 """
103 """
104 name = models.CharField(max_length=100)
104 name = models.CharField(max_length=100)
105 password = models.CharField(max_length=100)
105 password = models.CharField(max_length=100)
106
106
107 def __unicode__(self):
107 def __unicode__(self):
108 return self.name + '/' + '*' * len(self.password)
108 return self.name + '/' + '*' * len(self.password)
109
109
@@ -1,125 +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, Tag
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 tags = []
40 tags = []
41 if thread_id == boards.models.NO_PARENT:
41 if thread_id == boards.models.NO_PARENT:
42 tag_strings = request.POST['tags']
42 tag_strings = request.POST['tags']
43
43
44 if tag_strings:
44 if tag_strings:
45 tag_strings = tag_strings.split(',')
45 tag_strings = tag_strings.split(',')
46 for tag_name in tag_strings:
46 for tag_name in tag_strings:
47 tag_name = tag_name.strip()
47 tag_name = tag_name.strip()
48 if len(tag_name) > 0:
48 if len(tag_name) > 0:
49 tag, created = Tag.objects.get_or_create(name=tag_name)
49 tag, created = Tag.objects.get_or_create(name=tag_name)
50 tags.append(tag)
50 tags.append(tag)
51
51
52 # TODO Add a possibility to define a link image instead of an image file.
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.
53 # If a link is given, download the image automatically.
54
54
55 post = Post.objects.create_post(title=title, text=text, ip=ip,
55 post = Post.objects.create_post(title=title, text=text, ip=ip,
56 parent_id=thread_id, image=image,
56 parent_id=thread_id, image=image,
57 tags=tags)
57 tags=tags)
58
58
59 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
60 thread_id)
60 thread_id)
61 return redirect(thread, post_id=thread_to_show)
61 return redirect(thread, post_id=thread_to_show)
62
62
63
63
64 def tag(request, tag_name):
64 def tag(request, tag_name):
65 """Get all tag threads (posts without a parent)."""
65 """Get all tag threads (posts without a parent)."""
66
66
67 tag = Tag.objects.get(name=tag_name)
67 tag = Tag.objects.get(name=tag_name)
68 threads = get_list_or_404(Post, tags=tag)
68 threads = Post.objects.get_threads(tag=tag)
69
69
70 if request.method == 'POST':
70 if request.method == 'POST':
71 return new_post(request)
71 return new_post(request)
72 else:
72 else:
73 context = RequestContext(request)
73 context = RequestContext(request)
74 context['threads'] = None if len(threads) == 0 else threads
74 context['threads'] = None if len(threads) == 0 else threads
75 context['tag'] = tag_name
75 context['tag'] = tag_name
76
76
77 context['form'] = forms.NewThreadForm(initial={'tags': tag_name})
77 context['form'] = forms.NewThreadForm(initial={'tags': tag_name})
78
78
79 return render(request, 'posting_general.html',
79 return render(request, 'posting_general.html',
80 context)
80 context)
81
81
82
82
83 def thread(request, post_id):
83 def thread(request, post_id):
84 """Get all thread posts"""
84 """Get all thread posts"""
85
85
86 if request.method == 'POST':
86 if request.method == 'POST':
87 return new_post(request, post_id)
87 return new_post(request, post_id)
88 else:
88 else:
89 # TODO Show 404 if there is no such thread
89 # TODO Show 404 if there is no such thread
90 posts = Post.objects.get_thread(post_id)
90 posts = Post.objects.get_thread(post_id)
91
91
92 context = RequestContext(request)
92 context = RequestContext(request)
93 context['posts'] = posts
93 context['posts'] = posts
94
94
95 context['form'] = forms.NewThreadForm()
95 context['form'] = forms.NewThreadForm()
96
96
97 return render(request, 'thread.html', context)
97 return render(request, 'thread.html', context)
98
98
99
99
100 def login(request):
100 def login(request):
101 """Log in as admin"""
101 """Log in as admin"""
102
102
103 if 'name' in request.POST and 'password' in request.POST:
103 if 'name' in request.POST and 'password' in request.POST:
104 request.session['admin'] = False
104 request.session['admin'] = False
105
105
106 isAdmin = len(Admin.objects.filter(name=request.POST['name'],
106 isAdmin = len(Admin.objects.filter(name=request.POST['name'],
107 password=request.POST[
107 password=request.POST[
108 'password'])) > 0
108 'password'])) > 0
109
109
110 if isAdmin:
110 if isAdmin:
111 request.session['admin'] = True
111 request.session['admin'] = True
112
112
113 response = HttpResponseRedirect('/')
113 response = HttpResponseRedirect('/')
114
114
115 else:
115 else:
116 response = render(request, 'login.html', {'error': 'Login error'})
116 response = render(request, 'login.html', {'error': 'Login error'})
117 else:
117 else:
118 response = render(request, 'login.html', {})
118 response = render(request, 'login.html', {})
119
119
120 return response
120 return response
121
121
122
122
123 def logout(request):
123 def logout(request):
124 request.session['admin'] = False
124 request.session['admin'] = False
125 return HttpResponseRedirect('/') No newline at end of file
125 return HttpResponseRedirect('/')
@@ -1,63 +1,63 b''
1 {% extends "base.html" %}
1 {% extends "base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4
4
5 {% block content %}
5 {% block content %}
6
6
7 {% if threads %}
7 {% if threads %}
8 {% for thread in threads %}
8 {% for thread in threads %}
9 {% if thread.image %}
9 {% if thread.image %}
10 <div class="block">
10 <div class="block">
11 <a href="{{ thread.image.url }}"><img
11 <a href="{{ thread.image.url }}"><img
12 src="{{ thread.image.url_200x150 }}" />
12 src="{{ thread.image.url_200x150 }}" />
13 </a>
13 </a>
14 </div>
14 </div>
15 {% endif %}
15 {% endif %}
16 <div class="block">
16 <div class="block">
17 <span class="title">{{ thread.title }}</span>
17 <span class="title">{{ thread.title }}</span>
18 <span class="post_id">(#{{ thread.id }})</span>
18 <span class="post_id">(#{{ thread.id }})</span>
19 [{{ thread.pub_time }}]
19 [{{ thread.pub_time }}]
20 <a class="link" href="/thread/{{ thread.id }}/">
20 <a class="link" href="/thread/{{ thread.id }}/">
21 [{% trans "View" %}]</a><br />
21 [{% trans "View" %}]</a><br />
22 {{ thread.text }}<br />
22 {{ thread.text|truncatechars:300 }}<br />
23 {% if thread.tags %}
23 {% if thread.tags %}
24 <span class="tags">{% trans 'Tags' %}:
24 <span class="tags">{% trans 'Tags' %}:
25 {% for tag in thread.tags.all %}
25 {% for tag in thread.tags.all %}
26 <a class="tag" href="/tag/{{ tag.name }}">
26 <a class="tag" href="/tag/{{ tag.name }}">
27 {{ tag.name }}</a>
27 {{ tag.name }}</a>
28 {% endfor %}
28 {% endfor %}
29 </span>
29 </span>
30 {% endif %}
30 {% endif %}
31 </div>
31 </div>
32 <hr />
32 <hr />
33 {% endfor %}
33 {% endfor %}
34 {% else %}
34 {% else %}
35 No threads found.
35 No threads found.
36 <hr />
36 <hr />
37 {% endif %}
37 {% endif %}
38
38
39 <div class="post-form">
39 <div class="post-form">
40 <div class="post-form">
40 <div class="post-form">
41 <form enctype="multipart/form-data" method="post">{% csrf_token %}
41 <form enctype="multipart/form-data" method="post">{% csrf_token %}
42 <div class="form-row">
42 <div class="form-row">
43 <div class="form-input">{% trans 'Title' %}</div>
43 <div class="form-input">{% trans 'Title' %}</div>
44 <div class="form-input">{{ form.title }}</div>
44 <div class="form-input">{{ form.title }}</div>
45 </div>
45 </div>
46 <div class="form-row">
46 <div class="form-row">
47 <div class="form-input">{% trans 'Text' %}</div>
47 <div class="form-input">{% trans 'Text' %}</div>
48 <div class="form-input">{{ form.text }}</div>
48 <div class="form-input">{{ form.text }}</div>
49 </div>
49 </div>
50 <div class="form-row">
50 <div class="form-row">
51 <div class="form-input">{% trans 'Image' %}</div>
51 <div class="form-input">{% trans 'Image' %}</div>
52 <div class="form-input">{{ form.image }}</div>
52 <div class="form-input">{{ form.image }}</div>
53 </div>
53 </div>
54 <div class="form-row">
54 <div class="form-row">
55 <div class="form-input">{% trans 'Tags' %}</div>
55 <div class="form-input">{% trans 'Tags' %}</div>
56 <div class="form-input">{{ form.tags }}</div>
56 <div class="form-input">{{ form.tags }}</div>
57 </div>
57 </div>
58 <input type="submit" value="{% trans 'Post' %}" />
58 <input type="submit" value="{% trans 'Post' %}" />
59 </form>
59 </form>
60 </div>
60 </div>
61 </div>
61 </div>
62
62
63 {% endblock %} No newline at end of file
63 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now