##// END OF EJS Templates
Switch to show only favorite tags (BB-94)
neko259 -
r1691:8a821ff8 default
parent child Browse files
Show More
@@ -1,199 +1,200 b''
1 from boards import settings
1 from boards import settings
2 from boards.models import Tag
2 from boards.models import Tag
3 from boards.models.thread import FAV_THREAD_NO_UPDATES
3 from boards.models.thread import FAV_THREAD_NO_UPDATES
4
4
5 MAX_TRIPCODE_COLLISIONS = 50
5 MAX_TRIPCODE_COLLISIONS = 50
6
6
7 __author__ = 'neko259'
7 __author__ = 'neko259'
8
8
9 SESSION_SETTING = 'setting'
9 SESSION_SETTING = 'setting'
10
10
11 # Remove this, it is not used any more cause there is a user's permission
11 # Remove this, it is not used any more cause there is a user's permission
12 PERMISSION_MODERATE = 'moderator'
12 PERMISSION_MODERATE = 'moderator'
13
13
14 SETTING_THEME = 'theme'
14 SETTING_THEME = 'theme'
15 SETTING_FAVORITE_TAGS = 'favorite_tags'
15 SETTING_FAVORITE_TAGS = 'favorite_tags'
16 SETTING_FAVORITE_THREADS = 'favorite_threads'
16 SETTING_FAVORITE_THREADS = 'favorite_threads'
17 SETTING_HIDDEN_TAGS = 'hidden_tags'
17 SETTING_HIDDEN_TAGS = 'hidden_tags'
18 SETTING_PERMISSIONS = 'permissions'
18 SETTING_PERMISSIONS = 'permissions'
19 SETTING_USERNAME = 'username'
19 SETTING_USERNAME = 'username'
20 SETTING_LAST_NOTIFICATION_ID = 'last_notification'
20 SETTING_LAST_NOTIFICATION_ID = 'last_notification'
21 SETTING_IMAGE_VIEWER = 'image_viewer'
21 SETTING_IMAGE_VIEWER = 'image_viewer'
22 SETTING_TRIPCODE = 'tripcode'
22 SETTING_TRIPCODE = 'tripcode'
23 SETTING_IMAGES = 'images_aliases'
23 SETTING_IMAGES = 'images_aliases'
24 SETTING_ONLY_FAVORITES = 'only_favorites'
24
25
25 DEFAULT_THEME = 'md'
26 DEFAULT_THEME = 'md'
26
27
27
28
28 class SettingsManager:
29 class SettingsManager:
29 """
30 """
30 Base settings manager class. get_setting and set_setting methods should
31 Base settings manager class. get_setting and set_setting methods should
31 be overriden.
32 be overriden.
32 """
33 """
33 def __init__(self):
34 def __init__(self):
34 pass
35 pass
35
36
36 def get_theme(self) -> str:
37 def get_theme(self) -> str:
37 theme = self.get_setting(SETTING_THEME)
38 theme = self.get_setting(SETTING_THEME)
38 if not theme:
39 if not theme:
39 theme = DEFAULT_THEME
40 theme = DEFAULT_THEME
40 self.set_setting(SETTING_THEME, theme)
41 self.set_setting(SETTING_THEME, theme)
41
42
42 return theme
43 return theme
43
44
44 def set_theme(self, theme):
45 def set_theme(self, theme):
45 self.set_setting(SETTING_THEME, theme)
46 self.set_setting(SETTING_THEME, theme)
46
47
47 def has_permission(self, permission):
48 def has_permission(self, permission):
48 permissions = self.get_setting(SETTING_PERMISSIONS)
49 permissions = self.get_setting(SETTING_PERMISSIONS)
49 if permissions:
50 if permissions:
50 return permission in permissions
51 return permission in permissions
51 else:
52 else:
52 return False
53 return False
53
54
54 def get_setting(self, setting, default=None):
55 def get_setting(self, setting, default=None):
55 pass
56 pass
56
57
57 def set_setting(self, setting, value):
58 def set_setting(self, setting, value):
58 pass
59 pass
59
60
60 def add_permission(self, permission):
61 def add_permission(self, permission):
61 permissions = self.get_setting(SETTING_PERMISSIONS)
62 permissions = self.get_setting(SETTING_PERMISSIONS)
62 if not permissions:
63 if not permissions:
63 permissions = [permission]
64 permissions = [permission]
64 else:
65 else:
65 permissions.append(permission)
66 permissions.append(permission)
66 self.set_setting(SETTING_PERMISSIONS, permissions)
67 self.set_setting(SETTING_PERMISSIONS, permissions)
67
68
68 def del_permission(self, permission):
69 def del_permission(self, permission):
69 permissions = self.get_setting(SETTING_PERMISSIONS)
70 permissions = self.get_setting(SETTING_PERMISSIONS)
70 if not permissions:
71 if not permissions:
71 permissions = []
72 permissions = []
72 else:
73 else:
73 permissions.remove(permission)
74 permissions.remove(permission)
74 self.set_setting(SETTING_PERMISSIONS, permissions)
75 self.set_setting(SETTING_PERMISSIONS, permissions)
75
76
76 def get_fav_tags(self) -> list:
77 def get_fav_tags(self) -> list:
77 tag_names = self.get_setting(SETTING_FAVORITE_TAGS)
78 tag_names = self.get_setting(SETTING_FAVORITE_TAGS)
78 tags = []
79 tags = []
79 if tag_names:
80 if tag_names:
80 tags = list(Tag.objects.filter(name__in=tag_names))
81 tags = list(Tag.objects.filter(name__in=tag_names))
81 return tags
82 return tags
82
83
83 def add_fav_tag(self, tag):
84 def add_fav_tag(self, tag):
84 tags = self.get_setting(SETTING_FAVORITE_TAGS)
85 tags = self.get_setting(SETTING_FAVORITE_TAGS)
85 if not tags:
86 if not tags:
86 tags = [tag.name]
87 tags = [tag.name]
87 else:
88 else:
88 if not tag.name in tags:
89 if not tag.name in tags:
89 tags.append(tag.name)
90 tags.append(tag.name)
90
91
91 tags.sort()
92 tags.sort()
92 self.set_setting(SETTING_FAVORITE_TAGS, tags)
93 self.set_setting(SETTING_FAVORITE_TAGS, tags)
93
94
94 def del_fav_tag(self, tag):
95 def del_fav_tag(self, tag):
95 tags = self.get_setting(SETTING_FAVORITE_TAGS)
96 tags = self.get_setting(SETTING_FAVORITE_TAGS)
96 if tag.name in tags:
97 if tag.name in tags:
97 tags.remove(tag.name)
98 tags.remove(tag.name)
98 self.set_setting(SETTING_FAVORITE_TAGS, tags)
99 self.set_setting(SETTING_FAVORITE_TAGS, tags)
99
100
100 def get_hidden_tags(self) -> list:
101 def get_hidden_tags(self) -> list:
101 tag_names = self.get_setting(SETTING_HIDDEN_TAGS)
102 tag_names = self.get_setting(SETTING_HIDDEN_TAGS)
102 tags = []
103 tags = []
103 if tag_names:
104 if tag_names:
104 tags = list(Tag.objects.filter(name__in=tag_names))
105 tags = list(Tag.objects.filter(name__in=tag_names))
105
106
106 return tags
107 return tags
107
108
108 def add_hidden_tag(self, tag):
109 def add_hidden_tag(self, tag):
109 tags = self.get_setting(SETTING_HIDDEN_TAGS)
110 tags = self.get_setting(SETTING_HIDDEN_TAGS)
110 if not tags:
111 if not tags:
111 tags = [tag.name]
112 tags = [tag.name]
112 else:
113 else:
113 if not tag.name in tags:
114 if not tag.name in tags:
114 tags.append(tag.name)
115 tags.append(tag.name)
115
116
116 tags.sort()
117 tags.sort()
117 self.set_setting(SETTING_HIDDEN_TAGS, tags)
118 self.set_setting(SETTING_HIDDEN_TAGS, tags)
118
119
119 def del_hidden_tag(self, tag):
120 def del_hidden_tag(self, tag):
120 tags = self.get_setting(SETTING_HIDDEN_TAGS)
121 tags = self.get_setting(SETTING_HIDDEN_TAGS)
121 if tag.name in tags:
122 if tag.name in tags:
122 tags.remove(tag.name)
123 tags.remove(tag.name)
123 self.set_setting(SETTING_HIDDEN_TAGS, tags)
124 self.set_setting(SETTING_HIDDEN_TAGS, tags)
124
125
125 def get_fav_threads(self) -> dict:
126 def get_fav_threads(self) -> dict:
126 return self.get_setting(SETTING_FAVORITE_THREADS, default=dict())
127 return self.get_setting(SETTING_FAVORITE_THREADS, default=dict())
127
128
128 def add_or_read_fav_thread(self, opening_post):
129 def add_or_read_fav_thread(self, opening_post):
129 threads = self.get_fav_threads()
130 threads = self.get_fav_threads()
130
131
131 max_fav_threads = settings.get_int('View', 'MaxFavoriteThreads')
132 max_fav_threads = settings.get_int('View', 'MaxFavoriteThreads')
132 if (str(opening_post.id) in threads) or (len(threads) < max_fav_threads):
133 if (str(opening_post.id) in threads) or (len(threads) < max_fav_threads):
133 thread = opening_post.get_thread()
134 thread = opening_post.get_thread()
134 # Don't check for new posts if the thread is archived already
135 # Don't check for new posts if the thread is archived already
135 if thread.is_archived():
136 if thread.is_archived():
136 last_id = FAV_THREAD_NO_UPDATES
137 last_id = FAV_THREAD_NO_UPDATES
137 else:
138 else:
138 last_id = thread.get_replies().last().id
139 last_id = thread.get_replies().last().id
139 threads[str(opening_post.id)] = last_id
140 threads[str(opening_post.id)] = last_id
140 self.set_setting(SETTING_FAVORITE_THREADS, threads)
141 self.set_setting(SETTING_FAVORITE_THREADS, threads)
141
142
142 def del_fav_thread(self, opening_post):
143 def del_fav_thread(self, opening_post):
143 threads = self.get_fav_threads()
144 threads = self.get_fav_threads()
144 if self.thread_is_fav(opening_post):
145 if self.thread_is_fav(opening_post):
145 del threads[str(opening_post.id)]
146 del threads[str(opening_post.id)]
146 self.set_setting(SETTING_FAVORITE_THREADS, threads)
147 self.set_setting(SETTING_FAVORITE_THREADS, threads)
147
148
148 def thread_is_fav(self, opening_post):
149 def thread_is_fav(self, opening_post):
149 return str(opening_post.id) in self.get_fav_threads()
150 return str(opening_post.id) in self.get_fav_threads()
150
151
151 def get_notification_usernames(self):
152 def get_notification_usernames(self):
152 names = set()
153 names = set()
153 name_list = self.get_setting(SETTING_USERNAME)
154 name_list = self.get_setting(SETTING_USERNAME)
154 if name_list is not None:
155 if name_list is not None:
155 name_list = name_list.strip()
156 name_list = name_list.strip()
156 if len(name_list) > 0:
157 if len(name_list) > 0:
157 names = name_list.lower().split(',')
158 names = name_list.lower().split(',')
158 names = set(name.strip() for name in names)
159 names = set(name.strip() for name in names)
159 return names
160 return names
160
161
161 def get_image_by_alias(self, alias):
162 def get_image_by_alias(self, alias):
162 images = self.get_setting(SETTING_IMAGES)
163 images = self.get_setting(SETTING_IMAGES)
163 if images is not None and len(images) > 0:
164 if images is not None and len(images) > 0:
164 return images.get(alias)
165 return images.get(alias)
165
166
166 def add_image_alias(self, alias, image):
167 def add_image_alias(self, alias, image):
167 images = self.get_setting(SETTING_IMAGES)
168 images = self.get_setting(SETTING_IMAGES)
168 if images is None:
169 if images is None:
169 images = dict()
170 images = dict()
170 images.put(alias, image)
171 images.put(alias, image)
171
172
172
173
173 class SessionSettingsManager(SettingsManager):
174 class SessionSettingsManager(SettingsManager):
174 """
175 """
175 Session-based settings manager. All settings are saved to the user's
176 Session-based settings manager. All settings are saved to the user's
176 session.
177 session.
177 """
178 """
178 def __init__(self, session):
179 def __init__(self, session):
179 SettingsManager.__init__(self)
180 SettingsManager.__init__(self)
180 self.session = session
181 self.session = session
181
182
182 def get_setting(self, setting, default=None):
183 def get_setting(self, setting, default=None):
183 if setting in self.session:
184 if setting in self.session:
184 return self.session[setting]
185 return self.session[setting]
185 else:
186 else:
186 self.set_setting(setting, default)
187 self.set_setting(setting, default)
187 return default
188 return default
188
189
189 def set_setting(self, setting, value):
190 def set_setting(self, setting, value):
190 self.session[setting] = value
191 self.session[setting] = value
191
192
192
193
193 def get_settings_manager(request) -> SettingsManager:
194 def get_settings_manager(request) -> SettingsManager:
194 """
195 """
195 Get settings manager based on the request object. Currently only
196 Get settings manager based on the request object. Currently only
196 session-based manager is supported. In the future, cookie-based or
197 session-based manager is supported. In the future, cookie-based or
197 database-based managers could be implemented.
198 database-based managers could be implemented.
198 """
199 """
199 return SessionSettingsManager(request.session)
200 return SessionSettingsManager(request.session)
@@ -1,88 +1,91 b''
1 from boards.abstracts.settingsmanager import get_settings_manager, \
1 from boards.abstracts.settingsmanager import get_settings_manager, \
2 SETTING_LAST_NOTIFICATION_ID, SETTING_IMAGE_VIEWER
2 SETTING_LAST_NOTIFICATION_ID, SETTING_IMAGE_VIEWER, SETTING_ONLY_FAVORITES
3 from boards.models.user import Notification
3 from boards.models.user import Notification
4 from boards.models import Banner
4 from boards.models import Banner
5
5
6 __author__ = 'neko259'
6 __author__ = 'neko259'
7
7
8 import neboard
8 import neboard
9 from boards import settings
9 from boards import settings
10 from boards.models import Post, Tag, Thread
10 from boards.models import Post, Tag, Thread
11
11
12 CONTEXT_SITE_NAME = 'site_name'
12 CONTEXT_SITE_NAME = 'site_name'
13 CONTEXT_VERSION = 'version'
13 CONTEXT_VERSION = 'version'
14 CONTEXT_THEME_CSS = 'theme_css'
14 CONTEXT_THEME_CSS = 'theme_css'
15 CONTEXT_THEME = 'theme'
15 CONTEXT_THEME = 'theme'
16 CONTEXT_PPD = 'posts_per_day'
16 CONTEXT_PPD = 'posts_per_day'
17 CONTEXT_USER = 'user'
17 CONTEXT_USER = 'user'
18 CONTEXT_NEW_NOTIFICATIONS_COUNT = 'new_notifications_count'
18 CONTEXT_NEW_NOTIFICATIONS_COUNT = 'new_notifications_count'
19 CONTEXT_USERNAMES = 'usernames'
19 CONTEXT_USERNAMES = 'usernames'
20 CONTEXT_TAGS_STR = 'tags_str'
20 CONTEXT_TAGS_STR = 'tags_str'
21 CONTEXT_IMAGE_VIEWER = 'image_viewer'
21 CONTEXT_IMAGE_VIEWER = 'image_viewer'
22 CONTEXT_HAS_FAV_THREADS = 'has_fav_threads'
22 CONTEXT_HAS_FAV_THREADS = 'has_fav_threads'
23 CONTEXT_POW_DIFFICULTY = 'pow_difficulty'
23 CONTEXT_POW_DIFFICULTY = 'pow_difficulty'
24 CONTEXT_NEW_POST_COUNT = 'new_post_count'
24 CONTEXT_NEW_POST_COUNT = 'new_post_count'
25 CONTEXT_SEARCH_ENABLED = 'search_enabled'
25 CONTEXT_SEARCH_ENABLED = 'search_enabled'
26 CONTEXT_BANNERS = 'banners'
26 CONTEXT_BANNERS = 'banners'
27 CONTEXT_ONLY_FAVORITES = 'only_favorites'
27
28
28
29
29 def get_notifications(context, settings_manager):
30 def get_notifications(context, settings_manager):
30 usernames = settings_manager.get_notification_usernames()
31 usernames = settings_manager.get_notification_usernames()
31 new_notifications_count = 0
32 new_notifications_count = 0
32 if usernames:
33 if usernames:
33 last_notification_id = settings_manager.get_setting(
34 last_notification_id = settings_manager.get_setting(
34 SETTING_LAST_NOTIFICATION_ID)
35 SETTING_LAST_NOTIFICATION_ID)
35
36
36 new_notifications_count = Notification.objects.get_notification_posts(
37 new_notifications_count = Notification.objects.get_notification_posts(
37 usernames=usernames, last=last_notification_id).only('id').count()
38 usernames=usernames, last=last_notification_id).only('id').count()
38 context[CONTEXT_NEW_NOTIFICATIONS_COUNT] = new_notifications_count
39 context[CONTEXT_NEW_NOTIFICATIONS_COUNT] = new_notifications_count
39 context[CONTEXT_USERNAMES] = usernames
40 context[CONTEXT_USERNAMES] = usernames
40
41
41
42
42 def get_new_post_count(context, settings_manager):
43 def get_new_post_count(context, settings_manager):
43 fav_threads = settings_manager.get_fav_threads()
44 fav_threads = settings_manager.get_fav_threads()
44 if fav_threads:
45 if fav_threads:
45 fav_thread_ops = Post.objects.filter(id__in=fav_threads.keys()) \
46 fav_thread_ops = Post.objects.filter(id__in=fav_threads.keys()) \
46 .order_by('-pub_time').only('thread_id', 'pub_time')
47 .order_by('-pub_time').only('thread_id', 'pub_time')
47 ops = [{'op': op, 'last_id': fav_threads[str(op.id)]} for op in fav_thread_ops]
48 ops = [{'op': op, 'last_id': fav_threads[str(op.id)]} for op in fav_thread_ops]
48 count = Thread.objects.get_new_post_count(ops)
49 count = Thread.objects.get_new_post_count(ops)
49 if count > 0:
50 if count > 0:
50 context[CONTEXT_NEW_POST_COUNT] = '(+{})'.format(count)
51 context[CONTEXT_NEW_POST_COUNT] = '(+{})'.format(count)
51
52
52
53
53 def user_and_ui_processor(request):
54 def user_and_ui_processor(request):
54 context = dict()
55 context = dict()
55
56
56 context[CONTEXT_PPD] = float(Post.objects.get_posts_per_day())
57 context[CONTEXT_PPD] = float(Post.objects.get_posts_per_day())
57
58
58 settings_manager = get_settings_manager(request)
59 settings_manager = get_settings_manager(request)
59 fav_tags = settings_manager.get_fav_tags()
60 fav_tags = settings_manager.get_fav_tags()
60
61
61 context[CONTEXT_TAGS_STR] = Tag.objects.get_tag_url_list(fav_tags)
62 context[CONTEXT_TAGS_STR] = Tag.objects.get_tag_url_list(fav_tags)
62 theme = settings_manager.get_theme()
63 theme = settings_manager.get_theme()
63 context[CONTEXT_THEME] = theme
64 context[CONTEXT_THEME] = theme
64
65
65 # TODO Use static here
66 # TODO Use static here
66 context[CONTEXT_THEME_CSS] = 'css/' + theme + '/base_page.css'
67 context[CONTEXT_THEME_CSS] = 'css/' + theme + '/base_page.css'
67
68
68 context[CONTEXT_VERSION] = settings.get('Version', 'Version')
69 context[CONTEXT_VERSION] = settings.get('Version', 'Version')
69 context[CONTEXT_SITE_NAME] = settings.get('Version', 'SiteName')
70 context[CONTEXT_SITE_NAME] = settings.get('Version', 'SiteName')
70
71
71 if (settings.get_bool('Forms', 'LimitFirstPosting') and not settings_manager.get_setting('confirmed_user'))\
72 if (settings.get_bool('Forms', 'LimitFirstPosting') and not settings_manager.get_setting('confirmed_user'))\
72 or settings.get_bool('Forms', 'LimitPostingSpeed'):
73 or settings.get_bool('Forms', 'LimitPostingSpeed'):
73 context[CONTEXT_POW_DIFFICULTY] = settings.get_int('Forms', 'PowDifficulty')
74 context[CONTEXT_POW_DIFFICULTY] = settings.get_int('Forms', 'PowDifficulty')
74
75
75 context[CONTEXT_IMAGE_VIEWER] = settings_manager.get_setting(
76 context[CONTEXT_IMAGE_VIEWER] = settings_manager.get_setting(
76 SETTING_IMAGE_VIEWER,
77 SETTING_IMAGE_VIEWER,
77 default=settings.get('View', 'DefaultImageViewer'))
78 default=settings.get('View', 'DefaultImageViewer'))
78
79
79 context[CONTEXT_HAS_FAV_THREADS] =\
80 context[CONTEXT_HAS_FAV_THREADS] =\
80 len(settings_manager.get_fav_threads()) > 0
81 len(settings_manager.get_fav_threads()) > 0
81
82
82 context[CONTEXT_SEARCH_ENABLED] = 'haystack' in neboard.settings.INSTALLED_APPS
83 context[CONTEXT_SEARCH_ENABLED] = 'haystack' in neboard.settings.INSTALLED_APPS
83 context[CONTEXT_BANNERS] = Banner.objects.order_by('-id')
84 context[CONTEXT_BANNERS] = Banner.objects.order_by('-id')
85 context[CONTEXT_ONLY_FAVORITES] = settings_manager.get_setting(
86 SETTING_ONLY_FAVORITES, False)
84
87
85 get_notifications(context, settings_manager)
88 get_notifications(context, settings_manager)
86 get_new_post_count(context, settings_manager)
89 get_new_post_count(context, settings_manager)
87
90
88 return context
91 return context
@@ -1,90 +1,96 b''
1 {% load staticfiles %}
1 {% load staticfiles %}
2 {% load i18n %}
2 {% load i18n %}
3 {% load l10n %}
3 {% load l10n %}
4 {% load static from staticfiles %}
4 {% load static from staticfiles %}
5
5
6 <!DOCTYPE html>
6 <!DOCTYPE html>
7 <html>
7 <html>
8 <head>
8 <head>
9 <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}" media="all"/>
9 <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}" media="all"/>
10 <link rel="stylesheet" type="text/css" href="{% static 'css/3party/highlight.css' %}" media="all"/>
10 <link rel="stylesheet" type="text/css" href="{% static 'css/3party/highlight.css' %}" media="all"/>
11 <link rel="stylesheet" type="text/css" href="{% static 'css/3party/jquery-ui.min.css' %}" media="all"/>
11 <link rel="stylesheet" type="text/css" href="{% static 'css/3party/jquery-ui.min.css' %}" media="all"/>
12 <link rel="stylesheet" type="text/css" href="{% static theme_css %}" media="all"/>
12 <link rel="stylesheet" type="text/css" href="{% static theme_css %}" media="all"/>
13
13
14 {% if rss_url %}
14 {% if rss_url %}
15 <link rel="alternate" type="application/rss+xml" href="{{ rss_url }}" title="{% trans 'Feed' %}"/>
15 <link rel="alternate" type="application/rss+xml" href="{{ rss_url }}" title="{% trans 'Feed' %}"/>
16 {% endif %}
16 {% endif %}
17
17
18 <link rel="icon" type="image/png"
18 <link rel="icon" type="image/png"
19 href="{% static 'favicon.png' %}">
19 href="{% static 'favicon.png' %}">
20
20
21 <meta name="viewport" content="width=device-width, initial-scale=1"/>
21 <meta name="viewport" content="width=device-width, initial-scale=1"/>
22 <meta charset="utf-8"/>
22 <meta charset="utf-8"/>
23
23
24 {% block head %}{% endblock %}
24 {% block head %}{% endblock %}
25 </head>
25 </head>
26 <body data-image-viewer="{{ image_viewer }}"
26 <body data-image-viewer="{{ image_viewer }}"
27 data-pow-difficulty="{{ pow_difficulty }}"
27 data-pow-difficulty="{{ pow_difficulty }}"
28 data-update-script="{% static 'js/updates.js' %}">
28 data-update-script="{% static 'js/updates.js' %}">
29 <script src="{% static 'js/jquery-2.2.0.min.js' %}"></script>
29 <script src="{% static 'js/jquery-2.2.0.min.js' %}"></script>
30
30
31 <header class="navigation_panel">
31 <header class="navigation_panel">
32 <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a>
32 <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a>
33 {% if tags_str %}
33 {% if tags_str %}
34 <a href="{% url 'index' %}?filter=fav_tags" title="{% trans "interesting" %}">β˜…</a>,
34 <form action="{% url 'index' %}" method="post" class="post-button-form">{% csrf_token %}
35 {% if only_favorites %}
36 <button name="method" value="toggle_fav" class="fav">β˜…</button>,
37 {% else %}
38 <button name="method" value="toggle_fav" class="not_fav">β˜…</button>,
39 {% endif %}
40 </form>
35 {{ tags_str|safe }},
41 {{ tags_str|safe }},
36 {% else %}
42 {% else %}
37 {% trans 'Add tags' %} β†’
43 {% trans 'Add tags' %} β†’
38 {% endif %}
44 {% endif %}
39 <a href="{% url 'tags' 'required'%}" title="{% trans 'Tag management' %}">{% trans "tags" %}</a>,
45 <a href="{% url 'tags' 'required'%}" title="{% trans 'Tag management' %}">{% trans "tags" %}</a>,
40 {% if search_enabled %}
46 {% if search_enabled %}
41 <a href="{% url 'search' %}" title="{% trans 'Search' %}">{% trans 'search' %}</a>,
47 <a href="{% url 'search' %}" title="{% trans 'Search' %}">{% trans 'search' %}</a>,
42 {% endif %}
48 {% endif %}
43 <a href="{% url 'feed' %}" title="{% trans 'Feed' %}">{% trans 'feed' %}</a>,
49 <a href="{% url 'feed' %}" title="{% trans 'Feed' %}">{% trans 'feed' %}</a>,
44 <a href="{% url 'random' %}" title="{% trans 'Random images' %}">{% trans 'images' %}</a>{% if has_fav_threads %},
50 <a href="{% url 'random' %}" title="{% trans 'Random images' %}">{% trans 'images' %}</a>{% if has_fav_threads %},
45
51
46 <a href="{% url 'feed' %}?favorites" id="fav-panel-btn">{% trans 'favorites' %} <span id="new-fav-post-count" {% if not new_post_count %}style="display: none" {% endif %}>{{ new_post_count }}</span></a>
52 <a href="{% url 'feed' %}?favorites" id="fav-panel-btn">{% trans 'favorites' %} <span id="new-fav-post-count" {% if not new_post_count %}style="display: none" {% endif %}>{{ new_post_count }}</span></a>
47 {% endif %}
53 {% endif %}
48
54
49 {% if usernames %}
55 {% if usernames %}
50 <a class="right-link link" href="{% url 'notifications' %}" title="{% trans 'Notifications' %}">
56 <a class="right-link link" href="{% url 'notifications' %}" title="{% trans 'Notifications' %}">
51 {% trans 'Notifications' %}
57 {% trans 'Notifications' %}
52 {% ifnotequal new_notifications_count 0 %}
58 {% ifnotequal new_notifications_count 0 %}
53 (<b>{{ new_notifications_count }}</b>)
59 (<b>{{ new_notifications_count }}</b>)
54 {% endifnotequal %}
60 {% endifnotequal %}
55 </a>
61 </a>
56 {% endif %}
62 {% endif %}
57
63
58 <a class="right-link link" href="{% url 'settings' %}">{% trans 'Settings' %}</a>
64 <a class="right-link link" href="{% url 'settings' %}">{% trans 'Settings' %}</a>
59 </header>
65 </header>
60
66
61 <div id="fav-panel"><div class="post">{% trans "Loading..." %}</div></div>
67 <div id="fav-panel"><div class="post">{% trans "Loading..." %}</div></div>
62
68
63 {% block content %}{% endblock %}
69 {% block content %}{% endblock %}
64
70
65 <script src="{% static 'js/3party/jquery-ui.min.js' %}"></script>
71 <script src="{% static 'js/3party/jquery-ui.min.js' %}"></script>
66 <script src="{% static 'js/jquery.mousewheel.js' %}"></script>
72 <script src="{% static 'js/jquery.mousewheel.js' %}"></script>
67 <script src="{% static 'js/3party/highlight.min.js' %}"></script>
73 <script src="{% static 'js/3party/highlight.min.js' %}"></script>
68
74
69 <script src="{% url 'js_info_dict' %}"></script>
75 <script src="{% url 'js_info_dict' %}"></script>
70
76
71 <script src="{% static 'js/popup.js' %}"></script>
77 <script src="{% static 'js/popup.js' %}"></script>
72 <script src="{% static 'js/image.js' %}"></script>
78 <script src="{% static 'js/image.js' %}"></script>
73 <script src="{% static 'js/refpopup.js' %}"></script>
79 <script src="{% static 'js/refpopup.js' %}"></script>
74 <script src="{% static 'js/main.js' %}"></script>
80 <script src="{% static 'js/main.js' %}"></script>
75
81
76 <footer class="navigation_panel">
82 <footer class="navigation_panel">
77 {% block metapanel %}{% endblock %}
83 {% block metapanel %}{% endblock %}
78 {% if rss_url %}
84 {% if rss_url %}
79 [<a href="{{ rss_url }}">RSS</a>]
85 [<a href="{{ rss_url }}">RSS</a>]
80 {% endif %}
86 {% endif %}
81 [<a href="{% url 'admin:index' %}">{% trans 'Admin' %}</a>]
87 [<a href="{% url 'admin:index' %}">{% trans 'Admin' %}</a>]
82 [<a href="{% url 'index' %}?order=pub">{% trans 'New threads' %}</a>]
88 [<a href="{% url 'index' %}?order=pub">{% trans 'New threads' %}</a>]
83 {% with ppd=posts_per_day|floatformat:2 %}
89 {% with ppd=posts_per_day|floatformat:2 %}
84 {% blocktrans %}Speed: {{ ppd }} posts per day{% endblocktrans %}
90 {% blocktrans %}Speed: {{ ppd }} posts per day{% endblocktrans %}
85 {% endwith %}
91 {% endwith %}
86 <a class="link" href="#top" id="up">{% trans 'Up' %}</a>
92 <a class="link" href="#top" id="up">{% trans 'Up' %}</a>
87 </footer>
93 </footer>
88
94
89 </body>
95 </body>
90 </html>
96 </html>
@@ -1,172 +1,184 b''
1 from django.core.urlresolvers import reverse
1 from django.core.urlresolvers import reverse
2 from django.core.files import File
2 from django.core.files import File
3 from django.core.files.temp import NamedTemporaryFile
3 from django.core.files.temp import NamedTemporaryFile
4 from django.core.paginator import EmptyPage
4 from django.core.paginator import EmptyPage
5 from django.db import transaction
5 from django.db import transaction
6 from django.http import Http404
6 from django.http import Http404
7 from django.shortcuts import render, redirect
7 from django.shortcuts import render, redirect
8 from django.utils.decorators import method_decorator
8 from django.utils.decorators import method_decorator
9 from django.views.decorators.csrf import csrf_protect
9 from django.views.decorators.csrf import csrf_protect
10
10
11 from boards import utils, settings
11 from boards import utils, settings
12 from boards.abstracts.paginator import get_paginator
12 from boards.abstracts.paginator import get_paginator
13 from boards.abstracts.settingsmanager import get_settings_manager
13 from boards.abstracts.settingsmanager import get_settings_manager,\
14 SETTING_ONLY_FAVORITES
14 from boards.forms import ThreadForm, PlainErrorList
15 from boards.forms import ThreadForm, PlainErrorList
15 from boards.models import Post, Thread, Ban
16 from boards.models import Post, Thread, Ban
16 from boards.views.banned import BannedView
17 from boards.views.banned import BannedView
17 from boards.views.base import BaseBoardView, CONTEXT_FORM
18 from boards.views.base import BaseBoardView, CONTEXT_FORM
18 from boards.views.posting_mixin import PostMixin
19 from boards.views.posting_mixin import PostMixin
19 from boards.views.mixins import FileUploadMixin, PaginatedMixin
20 from boards.views.mixins import FileUploadMixin, PaginatedMixin,\
21 DispatcherMixin, PARAMETER_METHOD
20
22
21 FORM_TAGS = 'tags'
23 FORM_TAGS = 'tags'
22 FORM_TEXT = 'text'
24 FORM_TEXT = 'text'
23 FORM_TITLE = 'title'
25 FORM_TITLE = 'title'
24 FORM_IMAGE = 'image'
26 FORM_IMAGE = 'image'
25 FORM_THREADS = 'threads'
27 FORM_THREADS = 'threads'
26
28
27 TAG_DELIMITER = ' '
29 TAG_DELIMITER = ' '
28
30
29 PARAMETER_CURRENT_PAGE = 'current_page'
31 PARAMETER_CURRENT_PAGE = 'current_page'
30 PARAMETER_PAGINATOR = 'paginator'
32 PARAMETER_PAGINATOR = 'paginator'
31 PARAMETER_THREADS = 'threads'
33 PARAMETER_THREADS = 'threads'
32 PARAMETER_ADDITIONAL = 'additional_params'
34 PARAMETER_ADDITIONAL = 'additional_params'
33 PARAMETER_MAX_FILE_SIZE = 'max_file_size'
35 PARAMETER_MAX_FILE_SIZE = 'max_file_size'
34 PARAMETER_RSS_URL = 'rss_url'
36 PARAMETER_RSS_URL = 'rss_url'
35
37
36 TEMPLATE = 'boards/all_threads.html'
38 TEMPLATE = 'boards/all_threads.html'
37 DEFAULT_PAGE = 1
39 DEFAULT_PAGE = 1
38
40
39
41
40 class AllThreadsView(PostMixin, FileUploadMixin, BaseBoardView, PaginatedMixin):
42 class AllThreadsView(PostMixin, FileUploadMixin, BaseBoardView, PaginatedMixin, DispatcherMixin):
41
43
42 def __init__(self):
44 def __init__(self):
43 self.settings_manager = None
45 self.settings_manager = None
44 super(AllThreadsView, self).__init__()
46 super(AllThreadsView, self).__init__()
45
47
46 @method_decorator(csrf_protect)
48 @method_decorator(csrf_protect)
47 def get(self, request, form: ThreadForm=None):
49 def get(self, request, form: ThreadForm=None):
48 page = request.GET.get('page', DEFAULT_PAGE)
50 page = request.GET.get('page', DEFAULT_PAGE)
49
51
50 params = self.get_context_data(request=request)
52 params = self.get_context_data(request=request)
51
53
52 if not form:
54 if not form:
53 form = ThreadForm(error_class=PlainErrorList)
55 form = ThreadForm(error_class=PlainErrorList)
54
56
55 self.settings_manager = get_settings_manager(request)
57 self.settings_manager = get_settings_manager(request)
56
58
57 threads = self.get_threads()
59 threads = self.get_threads()
58
60
59 order = request.GET.get('order', 'bump')
61 order = request.GET.get('order', 'bump')
60 if order == 'bump':
62 if order == 'bump':
61 threads = threads.order_by('-bump_time')
63 threads = threads.order_by('-bump_time')
62 else:
64 else:
63 threads = threads.filter(multi_replies__opening=True).order_by('-multi_replies__pub_time')
65 threads = threads.filter(multi_replies__opening=True).order_by('-multi_replies__pub_time')
64 filter = request.GET.get('filter')
66 filter = request.GET.get('filter')
65 if filter == 'fav_tags':
67 if self.settings_manager.get_setting(SETTING_ONLY_FAVORITES):
66 fav_tags = self.settings_manager.get_fav_tags()
68 fav_tags = self.settings_manager.get_fav_tags()
67 if len(fav_tags) > 0:
69 if len(fav_tags) > 0:
68 threads = threads.filter(tags__in=fav_tags)
70 threads = threads.filter(tags__in=fav_tags)
69 threads = threads.distinct()
71 threads = threads.distinct()
70
72
71 paginator = get_paginator(threads,
73 paginator = get_paginator(threads,
72 settings.get_int('View', 'ThreadsPerPage'))
74 settings.get_int('View', 'ThreadsPerPage'))
73 paginator.current_page = int(page)
75 paginator.current_page = int(page)
74
76
75 try:
77 try:
76 threads = paginator.page(page).object_list
78 threads = paginator.page(page).object_list
77 except EmptyPage:
79 except EmptyPage:
78 raise Http404()
80 raise Http404()
79
81
80 params[PARAMETER_THREADS] = threads
82 params[PARAMETER_THREADS] = threads
81 params[CONTEXT_FORM] = form
83 params[CONTEXT_FORM] = form
82 params[PARAMETER_MAX_FILE_SIZE] = self.get_max_upload_size()
84 params[PARAMETER_MAX_FILE_SIZE] = self.get_max_upload_size()
83 params[PARAMETER_RSS_URL] = self.get_rss_url()
85 params[PARAMETER_RSS_URL] = self.get_rss_url()
84
86
85 paginator.set_url(self.get_reverse_url(), request.GET.dict())
87 paginator.set_url(self.get_reverse_url(), request.GET.dict())
86 self.get_page_context(paginator, params, page)
88 self.get_page_context(paginator, params, page)
87
89
88 return render(request, TEMPLATE, params)
90 return render(request, TEMPLATE, params)
89
91
90 @method_decorator(csrf_protect)
92 @method_decorator(csrf_protect)
91 def post(self, request):
93 def post(self, request):
94 if PARAMETER_METHOD in request.POST:
95 self.dispatch_method(request)
96
97 return redirect('index') # FIXME Different for different modes
98
92 form = ThreadForm(request.POST, request.FILES,
99 form = ThreadForm(request.POST, request.FILES,
93 error_class=PlainErrorList)
100 error_class=PlainErrorList)
94 form.session = request.session
101 form.session = request.session
95
102
96 if form.is_valid():
103 if form.is_valid():
97 return self.create_thread(request, form)
104 return self.create_thread(request, form)
98 if form.need_to_ban:
105 if form.need_to_ban:
99 # Ban user because he is suspected to be a bot
106 # Ban user because he is suspected to be a bot
100 self._ban_current_user(request)
107 self._ban_current_user(request)
101
108
102 return self.get(request, form)
109 return self.get(request, form)
103
110
104 def get_page_context(self, paginator, params, page):
111 def get_page_context(self, paginator, params, page):
105 """
112 """
106 Get pagination context variables
113 Get pagination context variables
107 """
114 """
108
115
109 params[PARAMETER_PAGINATOR] = paginator
116 params[PARAMETER_PAGINATOR] = paginator
110 current_page = paginator.page(int(page))
117 current_page = paginator.page(int(page))
111 params[PARAMETER_CURRENT_PAGE] = current_page
118 params[PARAMETER_CURRENT_PAGE] = current_page
112 self.set_page_urls(paginator, params)
119 self.set_page_urls(paginator, params)
113
120
114 def get_reverse_url(self):
121 def get_reverse_url(self):
115 return reverse('index')
122 return reverse('index')
116
123
117 @transaction.atomic
124 @transaction.atomic
118 def create_thread(self, request, form: ThreadForm, html_response=True):
125 def create_thread(self, request, form: ThreadForm, html_response=True):
119 """
126 """
120 Creates a new thread with an opening post.
127 Creates a new thread with an opening post.
121 """
128 """
122
129
123 ip = utils.get_client_ip(request)
130 ip = utils.get_client_ip(request)
124 is_banned = Ban.objects.filter(ip=ip).exists()
131 is_banned = Ban.objects.filter(ip=ip).exists()
125
132
126 if is_banned:
133 if is_banned:
127 if html_response:
134 if html_response:
128 return redirect(BannedView().as_view())
135 return redirect(BannedView().as_view())
129 else:
136 else:
130 return
137 return
131
138
132 data = form.cleaned_data
139 data = form.cleaned_data
133
140
134 title = form.get_title()
141 title = form.get_title()
135 text = data[FORM_TEXT]
142 text = data[FORM_TEXT]
136 file = form.get_file()
143 file = form.get_file()
137 file_url = form.get_file_url()
144 file_url = form.get_file_url()
138 threads = data[FORM_THREADS]
145 threads = data[FORM_THREADS]
139 images = form.get_images()
146 images = form.get_images()
140
147
141 text = self._remove_invalid_links(text)
148 text = self._remove_invalid_links(text)
142
149
143 tags = data[FORM_TAGS]
150 tags = data[FORM_TAGS]
144 monochrome = form.is_monochrome()
151 monochrome = form.is_monochrome()
145
152
146 post = Post.objects.create_post(title=title, text=text, file=file,
153 post = Post.objects.create_post(title=title, text=text, file=file,
147 ip=ip, tags=tags, opening_posts=threads,
154 ip=ip, tags=tags, opening_posts=threads,
148 tripcode=form.get_tripcode(),
155 tripcode=form.get_tripcode(),
149 monochrome=monochrome, images=images,
156 monochrome=monochrome, images=images,
150 file_url = file_url)
157 file_url = file_url)
151
158
152 # This is required to update the threads to which posts we have replied
159 # This is required to update the threads to which posts we have replied
153 # when creating this one
160 # when creating this one
154 post.notify_clients()
161 post.notify_clients()
155
162
156 if form.is_subscribe():
163 if form.is_subscribe():
157 settings_manager = get_settings_manager(request)
164 settings_manager = get_settings_manager(request)
158 settings_manager.add_or_read_fav_thread(post)
165 settings_manager.add_or_read_fav_thread(post)
159
166
160 if html_response:
167 if html_response:
161 return redirect(post.get_absolute_url())
168 return redirect(post.get_absolute_url())
162
169
163 def get_threads(self):
170 def get_threads(self):
164 """
171 """
165 Gets list of threads that will be shown on a page.
172 Gets list of threads that will be shown on a page.
166 """
173 """
167
174
168 return Thread.objects\
175 return Thread.objects\
169 .exclude(tags__in=self.settings_manager.get_hidden_tags())
176 .exclude(tags__in=self.settings_manager.get_hidden_tags())
170
177
171 def get_rss_url(self):
178 def get_rss_url(self):
172 return self.get_reverse_url() + 'rss/'
179 return self.get_reverse_url() + 'rss/'
180
181 def toggle_fav(self, request):
182 settings_manager = get_settings_manager(request)
183 settings_manager.set_setting(SETTING_ONLY_FAVORITES,
184 not settings_manager.get_setting(SETTING_ONLY_FAVORITES, False))
General Comments 0
You need to be logged in to leave comments. Login now