##// END OF EJS Templates
Speed up getting tag's random image
neko259 -
r1264:50888044 default
parent child Browse files
Show More
@@ -1,125 +1,123 b''
1 import hashlib
1 import hashlib
2 import os
2 import os
3 from random import random
3 from random import random
4 import time
4 import time
5
5
6 from django.db import models
6 from django.db import models
7 from django.template.defaultfilters import filesizeformat
7 from django.template.defaultfilters import filesizeformat
8
8
9 from boards import thumbs
9 from boards import thumbs
10 import boards
10 import boards
11 from boards.models.base import Viewable
11 from boards.models.base import Viewable
12
12
13 __author__ = 'neko259'
13 __author__ = 'neko259'
14
14
15
15
16 IMAGE_THUMB_SIZE = (200, 150)
16 IMAGE_THUMB_SIZE = (200, 150)
17 IMAGES_DIRECTORY = 'images/'
17 IMAGES_DIRECTORY = 'images/'
18 FILE_EXTENSION_DELIMITER = '.'
18 FILE_EXTENSION_DELIMITER = '.'
19 HASH_LENGTH = 36
19 HASH_LENGTH = 36
20
20
21 CSS_CLASS_IMAGE = 'image'
21 CSS_CLASS_IMAGE = 'image'
22 CSS_CLASS_THUMB = 'thumb'
22 CSS_CLASS_THUMB = 'thumb'
23
23
24
24
25 class PostImageManager(models.Manager):
25 class PostImageManager(models.Manager):
26 def create_with_hash(self, image):
26 def create_with_hash(self, image):
27 image_hash = self.get_hash(image)
27 image_hash = self.get_hash(image)
28 existing = self.filter(hash=image_hash)
28 existing = self.filter(hash=image_hash)
29 if len(existing) > 0:
29 if len(existing) > 0:
30 post_image = existing[0]
30 post_image = existing[0]
31 else:
31 else:
32 post_image = PostImage.objects.create(image=image)
32 post_image = PostImage.objects.create(image=image)
33
33
34 return post_image
34 return post_image
35
35
36 def get_hash(self, image):
36 def get_hash(self, image):
37 """
37 """
38 Gets hash of an image.
38 Gets hash of an image.
39 """
39 """
40 md5 = hashlib.md5()
40 md5 = hashlib.md5()
41 for chunk in image.chunks():
41 for chunk in image.chunks():
42 md5.update(chunk)
42 md5.update(chunk)
43 return md5.hexdigest()
43 return md5.hexdigest()
44
44
45 def get_random_images(self, count, include_archived=False, tags=None):
45 def get_random_images(self, count, include_archived=False, tags=None):
46 images = self.filter(post_images__thread__archived=include_archived)
46 images = self.filter(post_images__thread__archived=include_archived)
47 if tags is not None:
47 if tags is not None:
48 images = images.filter(post_images__threads__tags__in=tags)
48 images = images.filter(post_images__threads__tags__in=tags)
49 return images.order_by('?')[:count]
49 return images.order_by('?')[:count]
50
50
51
51
52 class PostImage(models.Model, Viewable):
52 class PostImage(models.Model, Viewable):
53 objects = PostImageManager()
53 objects = PostImageManager()
54
54
55 class Meta:
55 class Meta:
56 app_label = 'boards'
56 app_label = 'boards'
57 ordering = ('id',)
57 ordering = ('id',)
58
58
59 def _update_image_filename(self, filename):
59 def _update_image_filename(self, filename):
60 """
60 """
61 Gets unique image filename
61 Gets unique image filename
62 """
62 """
63
63
64 path = IMAGES_DIRECTORY
64 path = IMAGES_DIRECTORY
65
65
66 # TODO Use something other than random number in file name
66 # TODO Use something other than random number in file name
67 new_name = '{}{}.{}'.format(
67 new_name = '{}{}.{}'.format(
68 str(int(time.mktime(time.gmtime()))),
68 str(int(time.mktime(time.gmtime()))),
69 str(int(random() * 1000)),
69 str(int(random() * 1000)),
70 filename.split(FILE_EXTENSION_DELIMITER)[-1:][0])
70 filename.split(FILE_EXTENSION_DELIMITER)[-1:][0])
71
71
72 return os.path.join(path, new_name)
72 return os.path.join(path, new_name)
73
73
74 width = models.IntegerField(default=0)
74 width = models.IntegerField(default=0)
75 height = models.IntegerField(default=0)
75 height = models.IntegerField(default=0)
76
76
77 pre_width = models.IntegerField(default=0)
77 pre_width = models.IntegerField(default=0)
78 pre_height = models.IntegerField(default=0)
78 pre_height = models.IntegerField(default=0)
79
79
80 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
80 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
81 blank=True, sizes=(IMAGE_THUMB_SIZE,),
81 blank=True, sizes=(IMAGE_THUMB_SIZE,),
82 width_field='width',
82 width_field='width',
83 height_field='height',
83 height_field='height',
84 preview_width_field='pre_width',
84 preview_width_field='pre_width',
85 preview_height_field='pre_height')
85 preview_height_field='pre_height')
86 hash = models.CharField(max_length=HASH_LENGTH)
86 hash = models.CharField(max_length=HASH_LENGTH)
87
87
88 def save(self, *args, **kwargs):
88 def save(self, *args, **kwargs):
89 """
89 """
90 Saves the model and computes the image hash for deduplication purposes.
90 Saves the model and computes the image hash for deduplication purposes.
91 """
91 """
92
92
93 if not self.pk and self.image:
93 if not self.pk and self.image:
94 self.hash = PostImage.objects.get_hash(self.image)
94 self.hash = PostImage.objects.get_hash(self.image)
95 super(PostImage, self).save(*args, **kwargs)
95 super(PostImage, self).save(*args, **kwargs)
96
96
97 def __str__(self):
97 def __str__(self):
98 return self.image.url
98 return self.image.url
99
99
100 def get_view(self):
100 def get_view(self):
101 metadata = '{}, {}'.format(self.image.name.split('.')[-1],
101 metadata = '{}, {}'.format(self.image.name.split('.')[-1],
102 filesizeformat(self.image.size))
102 filesizeformat(self.image.size))
103 return '<div class="{}">' \
103 return '<div class="{}">' \
104 '<a class="{}" href="{full}">' \
104 '<a class="{}" href="{full}">' \
105 '<img class="post-image-preview"' \
105 '<img class="post-image-preview"' \
106 ' src="{}"' \
106 ' src="{}"' \
107 ' alt="{}"' \
107 ' alt="{}"' \
108 ' width="{}"' \
108 ' width="{}"' \
109 ' height="{}"' \
109 ' height="{}"' \
110 ' data-width="{}"' \
110 ' data-width="{}"' \
111 ' data-height="{}" />' \
111 ' data-height="{}" />' \
112 '</a>' \
112 '</a>' \
113 '<div class="image-metadata">{image_meta}</div>' \
113 '<div class="image-metadata">{image_meta}</div>' \
114 '</div>'\
114 '</div>'\
115 .format(CSS_CLASS_IMAGE, CSS_CLASS_THUMB,
115 .format(CSS_CLASS_IMAGE, CSS_CLASS_THUMB,
116 self.image.url_200x150,
116 self.image.url_200x150,
117 str(self.hash), str(self.pre_width),
117 str(self.hash), str(self.pre_width),
118 str(self.pre_height), str(self.width), str(self.height),
118 str(self.pre_height), str(self.width), str(self.height),
119 full=self.image.url, image_meta=metadata)
119 full=self.image.url, image_meta=metadata)
120
120
121 def get_random_associated_post(self, tags=None):
121 def get_random_associated_post(self):
122 posts = boards.models.Post.objects.filter(images__in=[self])
122 posts = boards.models.Post.objects.filter(images__in=[self])
123 if tags is not None:
124 posts = posts.filter(threads__tags__in=tags)
125 return posts.order_by('?').first()
123 return posts.order_by('?').first()
@@ -1,92 +1,98 b''
1 from django.template.loader import render_to_string
1 from django.template.loader import render_to_string
2 from django.db import models
2 from django.db import models
3 from django.db.models import Count
3 from django.db.models import Count
4 from django.core.urlresolvers import reverse
4 from django.core.urlresolvers import reverse
5
5
6 from boards.models.base import Viewable
6 from boards.models.base import Viewable
7 from boards.utils import cached_result
7 from boards.utils import cached_result
8
8 import boards
9
9
10 __author__ = 'neko259'
10 __author__ = 'neko259'
11
11
12
12
13 class TagManager(models.Manager):
13 class TagManager(models.Manager):
14
14
15 def get_not_empty_tags(self):
15 def get_not_empty_tags(self):
16 """
16 """
17 Gets tags that have non-archived threads.
17 Gets tags that have non-archived threads.
18 """
18 """
19
19
20 return self.annotate(num_threads=Count('thread')).filter(num_threads__gt=0)\
20 return self.annotate(num_threads=Count('thread')).filter(num_threads__gt=0)\
21 .order_by('-required', 'name')
21 .order_by('-required', 'name')
22
22
23 def get_tag_url_list(self, tags: list) -> str:
23 def get_tag_url_list(self, tags: list) -> str:
24 """
24 """
25 Gets a comma-separated list of tag links.
25 Gets a comma-separated list of tag links.
26 """
26 """
27
27
28 return ', '.join([tag.get_view() for tag in tags])
28 return ', '.join([tag.get_view() for tag in tags])
29
29
30
30
31 class Tag(models.Model, Viewable):
31 class Tag(models.Model, Viewable):
32 """
32 """
33 A tag is a text node assigned to the thread. The tag serves as a board
33 A tag is a text node assigned to the thread. The tag serves as a board
34 section. There can be multiple tags for each thread
34 section. There can be multiple tags for each thread
35 """
35 """
36
36
37 objects = TagManager()
37 objects = TagManager()
38
38
39 class Meta:
39 class Meta:
40 app_label = 'boards'
40 app_label = 'boards'
41 ordering = ('name',)
41 ordering = ('name',)
42
42
43 name = models.CharField(max_length=100, db_index=True, unique=True)
43 name = models.CharField(max_length=100, db_index=True, unique=True)
44 required = models.BooleanField(default=False, db_index=True)
44 required = models.BooleanField(default=False, db_index=True)
45 description = models.TextField(blank=True)
45 description = models.TextField(blank=True)
46
46
47 def __str__(self):
47 def __str__(self):
48 return self.name
48 return self.name
49
49
50 def is_empty(self) -> bool:
50 def is_empty(self) -> bool:
51 """
51 """
52 Checks if the tag has some threads.
52 Checks if the tag has some threads.
53 """
53 """
54
54
55 return self.get_thread_count() == 0
55 return self.get_thread_count() == 0
56
56
57 def get_thread_count(self, archived=None) -> int:
57 def get_thread_count(self, archived=None) -> int:
58 threads = self.get_threads()
58 threads = self.get_threads()
59 if archived is not None:
59 if archived is not None:
60 threads = threads.filter(archived=archived)
60 threads = threads.filter(archived=archived)
61 return threads.count()
61 return threads.count()
62
62
63 def get_active_thread_count(self) -> int:
63 def get_active_thread_count(self) -> int:
64 return self.get_thread_count(archived=False)
64 return self.get_thread_count(archived=False)
65
65
66 def get_absolute_url(self):
66 def get_absolute_url(self):
67 return reverse('tag', kwargs={'tag_name': self.name})
67 return reverse('tag', kwargs={'tag_name': self.name})
68
68
69 def get_threads(self):
69 def get_threads(self):
70 return self.thread_set.order_by('-bump_time')
70 return self.thread_set.order_by('-bump_time')
71
71
72 def is_required(self):
72 def is_required(self):
73 return self.required
73 return self.required
74
74
75 def get_view(self):
75 def get_view(self):
76 link = '<a class="tag" href="{}">{}</a>'.format(
76 link = '<a class="tag" href="{}">{}</a>'.format(
77 self.get_absolute_url(), self.name)
77 self.get_absolute_url(), self.name)
78 if self.is_required():
78 if self.is_required():
79 link = '<b>{}</b>'.format(link)
79 link = '<b>{}</b>'.format(link)
80 return link
80 return link
81
81
82 def get_search_view(self, *args, **kwargs):
82 def get_search_view(self, *args, **kwargs):
83 return render_to_string('boards/tag.html', {
83 return render_to_string('boards/tag.html', {
84 'tag': self,
84 'tag': self,
85 })
85 })
86
86
87 @cached_result()
87 @cached_result()
88 def get_post_count(self):
88 def get_post_count(self):
89 return self.get_threads().aggregate(num_posts=Count('post'))['num_posts']
89 return self.get_threads().aggregate(num_posts=Count('post'))['num_posts']
90
90
91 def get_description(self):
91 def get_description(self):
92 return self.description
92 return self.description
93
94 def get_random_image_post(self):
95 return boards.models.Post.objects.annotate(images_count=Count(
96 'images')).filter(images_count__gt=0, threads__tags__in=[self])\
97 .order_by('?').first()
98
@@ -1,179 +1,181 b''
1 {% extends "boards/base.html" %}
1 {% extends "boards/base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4 {% load board %}
4 {% load board %}
5 {% load static %}
5 {% load static %}
6 {% load tz %}
6 {% load tz %}
7
7
8 {% block head %}
8 {% block head %}
9 <meta name="robots" content="noindex">
9 <meta name="robots" content="noindex">
10
10
11 {% if tag %}
11 {% if tag %}
12 <title>{{ tag.name }} - {{ site_name }}</title>
12 <title>{{ tag.name }} - {{ site_name }}</title>
13 {% else %}
13 {% else %}
14 <title>{{ site_name }}</title>
14 <title>{{ site_name }}</title>
15 {% endif %}
15 {% endif %}
16
16
17 {% if prev_page_link %}
17 {% if prev_page_link %}
18 <link rel="prev" href="{{ prev_page_link }}" />
18 <link rel="prev" href="{{ prev_page_link }}" />
19 {% endif %}
19 {% endif %}
20 {% if next_page_link %}
20 {% if next_page_link %}
21 <link rel="next" href="{{ next_page_link }}" />
21 <link rel="next" href="{{ next_page_link }}" />
22 {% endif %}
22 {% endif %}
23
23
24 {% endblock %}
24 {% endblock %}
25
25
26 {% block content %}
26 {% block content %}
27
27
28 {% get_current_language as LANGUAGE_CODE %}
28 {% get_current_language as LANGUAGE_CODE %}
29 {% get_current_timezone as TIME_ZONE %}
29 {% get_current_timezone as TIME_ZONE %}
30
30
31 {% for banner in banners %}
31 {% for banner in banners %}
32 <div class="post">
32 <div class="post">
33 <div class="title">{{ banner.title }}</div>
33 <div class="title">{{ banner.title }}</div>
34 <div>{{ banner.text }}</div>
34 <div>{{ banner.text }}</div>
35 <div>{% trans 'Related message' %}: <a href="{{ banner.post.get_absolute_url }}">>>{{ banner.post.id }}</a></div>
35 <div>{% trans 'Related message' %}: <a href="{{ banner.post.get_absolute_url }}">>>{{ banner.post.id }}</a></div>
36 </div>
36 </div>
37 {% endfor %}
37 {% endfor %}
38
38
39 {% if tag %}
39 {% if tag %}
40 <div class="tag_info">
40 <div class="tag_info">
41 <div class="tag-image">
41 <div class="tag-image">
42 <a href="{{ random_image_post.get_absolute_url }}"><img
42 {% with image=random_image_post.images.first %}
43 src="{{ random_image.image.url_200x150 }}"
43 <a href="{{ random_image_post.get_absolute_url }}"><img
44 width="{{ random_image.pre_width }}"
44 src="{{ image.image.url_200x150 }}"
45 height="{{ random_image.pre_height }}"/></a>
45 width="{{ image.pre_width }}"
46 height="{{ image.pre_height }}"/></a>
47 {% endwith %}
46 </div>
48 </div>
47 <div class="tag-text-data">
49 <div class="tag-text-data">
48 <h2>
50 <h2>
49 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
51 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
50 {% if is_favorite %}
52 {% if is_favorite %}
51 <button name="method" value="unsubscribe" class="fav">β˜…</button>
53 <button name="method" value="unsubscribe" class="fav">β˜…</button>
52 {% else %}
54 {% else %}
53 <button name="method" value="subscribe" class="not_fav">β˜…</button>
55 <button name="method" value="subscribe" class="not_fav">β˜…</button>
54 {% endif %}
56 {% endif %}
55 </form>
57 </form>
56 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
58 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
57 {% if is_hidden %}
59 {% if is_hidden %}
58 <button name="method" value="unhide" class="fav">H</button>
60 <button name="method" value="unhide" class="fav">H</button>
59 {% else %}
61 {% else %}
60 <button name="method" value="hide" class="not_fav">H</button>
62 <button name="method" value="hide" class="not_fav">H</button>
61 {% endif %}
63 {% endif %}
62 </form>
64 </form>
63 {% autoescape off %}
65 {% autoescape off %}
64 {{ tag.get_view }}
66 {{ tag.get_view }}
65 {% endautoescape %}
67 {% endautoescape %}
66 {% if moderator %}
68 {% if moderator %}
67 <span class="moderator_info">| <a href="{% url 'admin:boards_tag_change' tag.id %}">{% trans 'Edit tag' %}</a></span>
69 <span class="moderator_info">| <a href="{% url 'admin:boards_tag_change' tag.id %}">{% trans 'Edit tag' %}</a></span>
68 {% endif %}
70 {% endif %}
69 </h2>
71 </h2>
70 {% if tag.get_description %}
72 {% if tag.get_description %}
71 {% autoescape off %}
73 {% autoescape off %}
72 <p>{{ tag.get_description }}</p>
74 <p>{{ tag.get_description }}</p>
73 {% endautoescape %}
75 {% endautoescape %}
74 {% endif %}
76 {% endif %}
75 <p>{% blocktrans with active_thread_count=tag.get_active_thread_count thread_count=tag.get_thread_count post_count=tag.get_post_count %}This tag has {{ active_thread_count}}/{{ thread_count }} threads and {{ post_count }} posts.{% endblocktrans %}</p>
77 <p>{% blocktrans with active_thread_count=tag.get_active_thread_count thread_count=tag.get_thread_count post_count=tag.get_post_count %}This tag has {{ active_thread_count}}/{{ thread_count }} threads and {{ post_count }} posts.{% endblocktrans %}</p>
76 </div>
78 </div>
77 </div>
79 </div>
78 {% endif %}
80 {% endif %}
79
81
80 {% if threads %}
82 {% if threads %}
81 {% if prev_page_link %}
83 {% if prev_page_link %}
82 <div class="page_link">
84 <div class="page_link">
83 <a href="{{ prev_page_link }}">{% trans "Previous page" %}</a>
85 <a href="{{ prev_page_link }}">{% trans "Previous page" %}</a>
84 </div>
86 </div>
85 {% endif %}
87 {% endif %}
86
88
87 {% for thread in threads %}
89 {% for thread in threads %}
88 <div class="thread">
90 <div class="thread">
89 {% post_view thread.get_opening_post moderator=moderator is_opening=True thread=thread truncated=True need_open_link=True %}
91 {% post_view thread.get_opening_post moderator=moderator is_opening=True thread=thread truncated=True need_open_link=True %}
90 {% if not thread.archived %}
92 {% if not thread.archived %}
91 {% with last_replies=thread.get_last_replies %}
93 {% with last_replies=thread.get_last_replies %}
92 {% if last_replies %}
94 {% if last_replies %}
93 {% with skipped_replies_count=thread.get_skipped_replies_count %}
95 {% with skipped_replies_count=thread.get_skipped_replies_count %}
94 {% if skipped_replies_count %}
96 {% if skipped_replies_count %}
95 <div class="skipped_replies">
97 <div class="skipped_replies">
96 <a href="{% url 'thread' thread.get_opening_post_id %}">
98 <a href="{% url 'thread' thread.get_opening_post_id %}">
97 {% blocktrans with count=skipped_replies_count %}Skipped {{ count }} replies. Open thread to see all replies.{% endblocktrans %}
99 {% blocktrans with count=skipped_replies_count %}Skipped {{ count }} replies. Open thread to see all replies.{% endblocktrans %}
98 </a>
100 </a>
99 </div>
101 </div>
100 {% endif %}
102 {% endif %}
101 {% endwith %}
103 {% endwith %}
102 <div class="last-replies">
104 <div class="last-replies">
103 {% for post in last_replies %}
105 {% for post in last_replies %}
104 {% post_view post is_opening=False moderator=moderator truncated=True %}
106 {% post_view post is_opening=False moderator=moderator truncated=True %}
105 {% endfor %}
107 {% endfor %}
106 </div>
108 </div>
107 {% endif %}
109 {% endif %}
108 {% endwith %}
110 {% endwith %}
109 {% endif %}
111 {% endif %}
110 </div>
112 </div>
111 {% endfor %}
113 {% endfor %}
112
114
113 {% if next_page_link %}
115 {% if next_page_link %}
114 <div class="page_link">
116 <div class="page_link">
115 <a href="{{ next_page_link }}">{% trans "Next page" %}</a>
117 <a href="{{ next_page_link }}">{% trans "Next page" %}</a>
116 </div>
118 </div>
117 {% endif %}
119 {% endif %}
118 {% else %}
120 {% else %}
119 <div class="post">
121 <div class="post">
120 {% trans 'No threads exist. Create the first one!' %}</div>
122 {% trans 'No threads exist. Create the first one!' %}</div>
121 {% endif %}
123 {% endif %}
122
124
123 <div class="post-form-w">
125 <div class="post-form-w">
124 <script src="{% static 'js/panel.js' %}"></script>
126 <script src="{% static 'js/panel.js' %}"></script>
125 <div class="post-form">
127 <div class="post-form">
126 <div class="form-title">{% trans "Create new thread" %}</div>
128 <div class="form-title">{% trans "Create new thread" %}</div>
127 <div class="swappable-form-full">
129 <div class="swappable-form-full">
128 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
130 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
129 {{ form.as_div }}
131 {{ form.as_div }}
130 <div class="form-submit">
132 <div class="form-submit">
131 <input type="submit" value="{% trans "Post" %}"/>
133 <input type="submit" value="{% trans "Post" %}"/>
132 </div>
134 </div>
133 </form>
135 </form>
134 </div>
136 </div>
135 <div>
137 <div>
136 {% trans 'Tags must be delimited by spaces. Text or image is required.' %}
138 {% trans 'Tags must be delimited by spaces. Text or image is required.' %}
137 </div>
139 </div>
138 <div><button id="preview-button">{% trans 'Preview' %}</button></div>
140 <div><button id="preview-button">{% trans 'Preview' %}</button></div>
139 <div id="preview-text"></div>
141 <div id="preview-text"></div>
140 <div><a href="{% url "staticpage" name="help" %}">{% trans 'Text syntax' %}</a></div>
142 <div><a href="{% url "staticpage" name="help" %}">{% trans 'Text syntax' %}</a></div>
141 <div><a href="{% url "tags" "required" %}">{% trans 'Tags' %}</a></div>
143 <div><a href="{% url "tags" "required" %}">{% trans 'Tags' %}</a></div>
142 </div>
144 </div>
143 </div>
145 </div>
144
146
145 <script src="{% static 'js/form.js' %}"></script>
147 <script src="{% static 'js/form.js' %}"></script>
146 <script src="{% static 'js/thread_create.js' %}"></script>
148 <script src="{% static 'js/thread_create.js' %}"></script>
147
149
148 {% endblock %}
150 {% endblock %}
149
151
150 {% block metapanel %}
152 {% block metapanel %}
151
153
152 <span class="metapanel">
154 <span class="metapanel">
153 <b><a href="{% url "authors" %}">{{ site_name }}</a> {{ version }}</b>
155 <b><a href="{% url "authors" %}">{{ site_name }}</a> {{ version }}</b>
154 {% trans "Pages:" %}
156 {% trans "Pages:" %}
155 [
157 [
156 {% with dividers=paginator.get_dividers %}
158 {% with dividers=paginator.get_dividers %}
157 {% for page in paginator.get_divided_range %}
159 {% for page in paginator.get_divided_range %}
158 {% if page in dividers %}
160 {% if page in dividers %}
159 …,
161 …,
160 {% endif %}
162 {% endif %}
161 <a
163 <a
162 {% ifequal page current_page.number %}
164 {% ifequal page current_page.number %}
163 class="current_page"
165 class="current_page"
164 {% endifequal %}
166 {% endifequal %}
165 href="
167 href="
166 {% if tag %}
168 {% if tag %}
167 {% url "tag" tag_name=tag.name %}?page={{ page }}
169 {% url "tag" tag_name=tag.name %}?page={{ page }}
168 {% else %}
170 {% else %}
169 {% url "index" %}?page={{ page }}
171 {% url "index" %}?page={{ page }}
170 {% endif %}
172 {% endif %}
171 ">{{ page }}</a>
173 ">{{ page }}</a>
172 {% if not forloop.last %},{% endif %}
174 {% if not forloop.last %},{% endif %}
173 {% endfor %}
175 {% endfor %}
174 {% endwith %}
176 {% endwith %}
175 ]
177 ]
176 [<a href="rss/">RSS</a>]
178 [<a href="rss/">RSS</a>]
177 </span>
179 </span>
178
180
179 {% endblock %}
181 {% endblock %}
@@ -1,126 +1,123 b''
1 from django.shortcuts import get_object_or_404, redirect
1 from django.shortcuts import get_object_or_404, redirect
2 from django.core.urlresolvers import reverse
2 from django.core.urlresolvers import reverse
3
3
4 from boards.abstracts.settingsmanager import get_settings_manager, \
4 from boards.abstracts.settingsmanager import get_settings_manager, \
5 SETTING_FAVORITE_TAGS, SETTING_HIDDEN_TAGS
5 SETTING_FAVORITE_TAGS, SETTING_HIDDEN_TAGS
6 from boards.models import Tag, PostImage
6 from boards.models import Tag, PostImage
7 from boards.views.all_threads import AllThreadsView, DEFAULT_PAGE
7 from boards.views.all_threads import AllThreadsView, DEFAULT_PAGE
8 from boards.views.mixins import DispatcherMixin
8 from boards.views.mixins import DispatcherMixin
9 from boards.forms import ThreadForm, PlainErrorList
9 from boards.forms import ThreadForm, PlainErrorList
10
10
11 PARAM_HIDDEN_TAGS = 'hidden_tags'
11 PARAM_HIDDEN_TAGS = 'hidden_tags'
12 PARAM_TAG = 'tag'
12 PARAM_TAG = 'tag'
13 PARAM_IS_FAVORITE = 'is_favorite'
13 PARAM_IS_FAVORITE = 'is_favorite'
14 PARAM_IS_HIDDEN = 'is_hidden'
14 PARAM_IS_HIDDEN = 'is_hidden'
15 PARAM_RANDOM_IMAGE = 'random_image'
16 PARAM_RANDOM_IMAGE_POST = 'random_image_post'
15 PARAM_RANDOM_IMAGE_POST = 'random_image_post'
17
16
18 __author__ = 'neko259'
17 __author__ = 'neko259'
19
18
20
19
21 class TagView(AllThreadsView, DispatcherMixin):
20 class TagView(AllThreadsView, DispatcherMixin):
22
21
23 tag_name = None
22 tag_name = None
24
23
25 def get_threads(self):
24 def get_threads(self):
26 tag = get_object_or_404(Tag, name=self.tag_name)
25 tag = get_object_or_404(Tag, name=self.tag_name)
27
26
28 hidden_tags = self.settings_manager.get_hidden_tags()
27 hidden_tags = self.settings_manager.get_hidden_tags()
29
28
30 try:
29 try:
31 hidden_tags.remove(tag)
30 hidden_tags.remove(tag)
32 except ValueError:
31 except ValueError:
33 pass
32 pass
34
33
35 return tag.get_threads().exclude(
34 return tag.get_threads().exclude(
36 tags__in=hidden_tags)
35 tags__in=hidden_tags)
37
36
38 def get_context_data(self, **kwargs):
37 def get_context_data(self, **kwargs):
39 params = super(TagView, self).get_context_data(**kwargs)
38 params = super(TagView, self).get_context_data(**kwargs)
40
39
41 settings_manager = get_settings_manager(kwargs['request'])
40 settings_manager = get_settings_manager(kwargs['request'])
42
41
43 tag = get_object_or_404(Tag, name=self.tag_name)
42 tag = get_object_or_404(Tag, name=self.tag_name)
44 params[PARAM_TAG] = tag
43 params[PARAM_TAG] = tag
45
44
46 fav_tag_names = settings_manager.get_setting(SETTING_FAVORITE_TAGS)
45 fav_tag_names = settings_manager.get_setting(SETTING_FAVORITE_TAGS)
47 hidden_tag_names = settings_manager.get_setting(SETTING_HIDDEN_TAGS)
46 hidden_tag_names = settings_manager.get_setting(SETTING_HIDDEN_TAGS)
48
47
49 params[PARAM_IS_FAVORITE] = fav_tag_names is not None and tag.name in fav_tag_names
48 params[PARAM_IS_FAVORITE] = fav_tag_names is not None and tag.name in fav_tag_names
50 params[PARAM_IS_HIDDEN] = hidden_tag_names is not None and tag.name in hidden_tag_names
49 params[PARAM_IS_HIDDEN] = hidden_tag_names is not None and tag.name in hidden_tag_names
51
50
52 image = PostImage.objects.get_random_images(1, tags=[tag])[0]
51 params[PARAM_RANDOM_IMAGE_POST] = tag.get_random_image_post()
53 params[PARAM_RANDOM_IMAGE] = image
54 params[PARAM_RANDOM_IMAGE_POST] = image.get_random_associated_post(tags=[tag])
55
52
56 return params
53 return params
57
54
58 def get_previous_page_link(self, current_page):
55 def get_previous_page_link(self, current_page):
59 return reverse('tag', kwargs={
56 return reverse('tag', kwargs={
60 'tag_name': self.tag_name,
57 'tag_name': self.tag_name,
61 }) + '?page=' + str(current_page.previous_page_number())
58 }) + '?page=' + str(current_page.previous_page_number())
62
59
63 def get_next_page_link(self, current_page):
60 def get_next_page_link(self, current_page):
64 return reverse('tag', kwargs={
61 return reverse('tag', kwargs={
65 'tag_name': self.tag_name,
62 'tag_name': self.tag_name,
66 }) + '?page=' + str(current_page.next_page_number())
63 }) + '?page=' + str(current_page.next_page_number())
67
64
68 def get(self, request, tag_name, form=None):
65 def get(self, request, tag_name, form=None):
69 self.tag_name = tag_name
66 self.tag_name = tag_name
70
67
71 return super(TagView, self).get(request, form)
68 return super(TagView, self).get(request, form)
72
69
73
70
74 def post(self, request, tag_name):
71 def post(self, request, tag_name):
75 self.tag_name = tag_name
72 self.tag_name = tag_name
76
73
77 if 'method' in request.POST:
74 if 'method' in request.POST:
78 self.dispatch_method(request)
75 self.dispatch_method(request)
79 form = None
76 form = None
80
77
81 return redirect('tag', tag_name)
78 return redirect('tag', tag_name)
82 else:
79 else:
83 form = ThreadForm(request.POST, request.FILES,
80 form = ThreadForm(request.POST, request.FILES,
84 error_class=PlainErrorList)
81 error_class=PlainErrorList)
85 form.session = request.session
82 form.session = request.session
86
83
87 if form.is_valid():
84 if form.is_valid():
88 return self.create_thread(request, form)
85 return self.create_thread(request, form)
89 if form.need_to_ban:
86 if form.need_to_ban:
90 # Ban user because he is suspected to be a bot
87 # Ban user because he is suspected to be a bot
91 self._ban_current_user(request)
88 self._ban_current_user(request)
92
89
93 return self.get(request, tag_name, page, form)
90 return self.get(request, tag_name, page, form)
94
91
95 def subscribe(self, request):
92 def subscribe(self, request):
96 tag = get_object_or_404(Tag, name=self.tag_name)
93 tag = get_object_or_404(Tag, name=self.tag_name)
97
94
98 settings_manager = get_settings_manager(request)
95 settings_manager = get_settings_manager(request)
99 settings_manager.add_fav_tag(tag)
96 settings_manager.add_fav_tag(tag)
100
97
101 def unsubscribe(self, request):
98 def unsubscribe(self, request):
102 tag = get_object_or_404(Tag, name=self.tag_name)
99 tag = get_object_or_404(Tag, name=self.tag_name)
103
100
104 settings_manager = get_settings_manager(request)
101 settings_manager = get_settings_manager(request)
105 settings_manager.del_fav_tag(tag)
102 settings_manager.del_fav_tag(tag)
106
103
107 def hide(self, request):
104 def hide(self, request):
108 """
105 """
109 Adds tag to user's hidden tags. Threads with this tag will not be
106 Adds tag to user's hidden tags. Threads with this tag will not be
110 shown.
107 shown.
111 """
108 """
112
109
113 tag = get_object_or_404(Tag, name=self.tag_name)
110 tag = get_object_or_404(Tag, name=self.tag_name)
114
111
115 settings_manager = get_settings_manager(request)
112 settings_manager = get_settings_manager(request)
116 settings_manager.add_hidden_tag(tag)
113 settings_manager.add_hidden_tag(tag)
117
114
118 def unhide(self, request):
115 def unhide(self, request):
119 """
116 """
120 Removed tag from user's hidden tags.
117 Removed tag from user's hidden tags.
121 """
118 """
122
119
123 tag = get_object_or_404(Tag, name=self.tag_name)
120 tag = get_object_or_404(Tag, name=self.tag_name)
124
121
125 settings_manager = get_settings_manager(request)
122 settings_manager = get_settings_manager(request)
126 settings_manager.del_hidden_tag(tag)
123 settings_manager.del_hidden_tag(tag)
General Comments 0
You need to be logged in to leave comments. Login now