Show More
@@ -11,6 +11,7 b" PERMISSION_MODERATE = 'moderator'" | |||||
11 |
|
11 | |||
12 | SETTING_THEME = 'theme' |
|
12 | SETTING_THEME = 'theme' | |
13 | SETTING_FAVORITE_TAGS = 'favorite_tags' |
|
13 | SETTING_FAVORITE_TAGS = 'favorite_tags' | |
|
14 | SETTING_FAVORITE_THREADS = 'favorite_threads' | |||
14 | SETTING_HIDDEN_TAGS = 'hidden_tags' |
|
15 | SETTING_HIDDEN_TAGS = 'hidden_tags' | |
15 | SETTING_PERMISSIONS = 'permissions' |
|
16 | SETTING_PERMISSIONS = 'permissions' | |
16 | SETTING_USERNAME = 'username' |
|
17 | SETTING_USERNAME = 'username' | |
@@ -118,6 +119,23 b' class SettingsManager:' | |||||
118 | tags.remove(tag.name) |
|
119 | tags.remove(tag.name) | |
119 | self.set_setting(SETTING_HIDDEN_TAGS, tags) |
|
120 | self.set_setting(SETTING_HIDDEN_TAGS, tags) | |
120 |
|
121 | |||
|
122 | def get_fav_threads(self) -> dict: | |||
|
123 | return self.get_setting(SETTING_FAVORITE_THREADS, default=dict()) | |||
|
124 | ||||
|
125 | def add_or_read_fav_thread(self, opening_post): | |||
|
126 | threads = self.get_fav_threads() | |||
|
127 | threads[str(opening_post.id)] = opening_post.get_thread().get_replies()\ | |||
|
128 | .last().id | |||
|
129 | self.set_setting(SETTING_FAVORITE_THREADS, threads) | |||
|
130 | ||||
|
131 | def del_fav_thread(self, opening_post): | |||
|
132 | threads = self.get_fav_threads() | |||
|
133 | if self.thread_is_fav(opening_post): | |||
|
134 | del threads[str(opening_post.id)] | |||
|
135 | self.set_setting(SETTING_FAVORITE_THREADS, threads) | |||
|
136 | ||||
|
137 | def thread_is_fav(self, opening_post): | |||
|
138 | return str(opening_post.id) in self.get_fav_threads() | |||
121 |
|
139 | |||
122 | class SessionSettingsManager(SettingsManager): |
|
140 | class SessionSettingsManager(SettingsManager): | |
123 | """ |
|
141 | """ |
@@ -19,6 +19,7 b" CONTEXT_NEW_NOTIFICATIONS_COUNT = 'new_n" | |||||
19 | CONTEXT_USERNAME = 'username' |
|
19 | CONTEXT_USERNAME = 'username' | |
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_FAV_THREADS = 'fav_threads' | |||
22 |
|
23 | |||
23 |
|
24 | |||
24 | def get_notifications(context, request): |
|
25 | def get_notifications(context, request): | |
@@ -43,6 +44,9 b' def user_and_ui_processor(request):' | |||||
43 | settings_manager = get_settings_manager(request) |
|
44 | settings_manager = get_settings_manager(request) | |
44 | fav_tags = settings_manager.get_fav_tags() |
|
45 | fav_tags = settings_manager.get_fav_tags() | |
45 | context[CONTEXT_TAGS] = fav_tags |
|
46 | context[CONTEXT_TAGS] = fav_tags | |
|
47 | ||||
|
48 | _get_fav_threads(context, settings_manager) | |||
|
49 | ||||
46 | context[CONTEXT_TAGS_STR] = Tag.objects.get_tag_url_list(fav_tags) |
|
50 | context[CONTEXT_TAGS_STR] = Tag.objects.get_tag_url_list(fav_tags) | |
47 | theme = settings_manager.get_theme() |
|
51 | theme = settings_manager.get_theme() | |
48 | context[CONTEXT_THEME] = theme |
|
52 | context[CONTEXT_THEME] = theme | |
@@ -61,3 +65,15 b' def user_and_ui_processor(request):' | |||||
61 | get_notifications(context, request) |
|
65 | get_notifications(context, request) | |
62 |
|
66 | |||
63 | return context |
|
67 | return context | |
|
68 | ||||
|
69 | ||||
|
70 | def _get_fav_threads(context, settings_manager): | |||
|
71 | fav_threads_setting = settings_manager.get_fav_threads() | |||
|
72 | if fav_threads_setting: | |||
|
73 | fav_threads = Post.objects.filter( | |||
|
74 | id__in=fav_threads_setting.keys()).only('url', 'id', 'thread')\ | |||
|
75 | .select_related('thread') | |||
|
76 | context[CONTEXT_FAV_THREADS] = [ | |||
|
77 | (post, post.get_thread().get_replies_newer( | |||
|
78 | fav_threads_setting[str(post.id)]).count()) | |||
|
79 | for post in fav_threads] |
@@ -253,7 +253,6 b' class Post(models.Model, Viewable):' | |||||
253 | post_url += '#' + str(self.id) |
|
253 | post_url += '#' + str(self.id) | |
254 | return post_url |
|
254 | return post_url | |
255 |
|
255 | |||
256 |
|
||||
257 | def get_thread(self): |
|
256 | def get_thread(self): | |
258 | return self.thread |
|
257 | return self.thread | |
259 |
|
258 | |||
@@ -449,7 +448,7 b' class Post(models.Model, Viewable):' | |||||
449 | """ |
|
448 | """ | |
450 |
|
449 | |||
451 | result = '<a href="{}">>>{}</a>'.format(self.get_absolute_url(), |
|
450 | result = '<a href="{}">>>{}</a>'.format(self.get_absolute_url(), | |
452 | self.id) |
|
451 | self.id) | |
453 | if self.is_opening(): |
|
452 | if self.is_opening(): | |
454 | result = '<b>{}</b>'.format(result) |
|
453 | result = '<b>{}</b>'.format(result) | |
455 |
|
454 |
@@ -228,3 +228,7 b' class Thread(models.Model):' | |||||
228 |
|
228 | |||
229 | def get_required_tags(self): |
|
229 | def get_required_tags(self): | |
230 | return self.get_tags().filter(required=True) |
|
230 | return self.get_tags().filter(required=True) | |
|
231 | ||||
|
232 | def get_replies_newer(self, post_id): | |||
|
233 | return self.get_replies().filter(id__gt=post_id) | |||
|
234 |
@@ -510,6 +510,11 b' ul {' | |||||
510 | border: 1px solid #777; |
|
510 | border: 1px solid #777; | |
511 | background: #000; |
|
511 | background: #000; | |
512 | padding: 4px; |
|
512 | padding: 4px; | |
|
513 | opacity: 0.3; | |||
|
514 | } | |||
|
515 | ||||
|
516 | #up:hover { | |||
|
517 | opacity: 1; | |||
513 | } |
|
518 | } | |
514 |
|
519 | |||
515 | .user-cast { |
|
520 | .user-cast { |
@@ -439,11 +439,11 b' function updateNodeAttr(oldNode, newNode' | |||||
439 | if (form.length > 0) { |
|
439 | if (form.length > 0) { | |
440 | var options = { |
|
440 | var options = { | |
441 | beforeSubmit: function(arr, $form, options) { |
|
441 | beforeSubmit: function(arr, $form, options) { | |
442 | showAsErrors($('form'), gettext('Sending message...')); |
|
442 | showAsErrors($('#form'), gettext('Sending message...')); | |
443 | }, |
|
443 | }, | |
444 | success: updateOnPost, |
|
444 | success: updateOnPost, | |
445 | error: function() { |
|
445 | error: function() { | |
446 | showAsErrors($('form'), gettext('Server error!')); |
|
446 | showAsErrors($('#form'), gettext('Server error!')); | |
447 | }, |
|
447 | }, | |
448 | url: '/api/add_post/' + threadId + '/' |
|
448 | url: '/api/add_post/' + threadId + '/' | |
449 | }; |
|
449 | }; |
@@ -28,6 +28,7 b'' | |||||
28 | <script src="{% url 'js_info_dict' %}"></script> |
|
28 | <script src="{% url 'js_info_dict' %}"></script> | |
29 |
|
29 | |||
30 | <div class="navigation_panel header"> |
|
30 | <div class="navigation_panel header"> | |
|
31 | <div> | |||
31 | <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a> |
|
32 | <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a> | |
32 | {% if tags_str %} |
|
33 | {% if tags_str %} | |
33 | {% autoescape off %} |
|
34 | {% autoescape off %} | |
@@ -51,6 +52,18 b'' | |||||
51 | {% endif %} |
|
52 | {% endif %} | |
52 |
|
53 | |||
53 | <a class="right-link link" href="{% url 'settings' %}">{% trans 'Settings' %}</a> |
|
54 | <a class="right-link link" href="{% url 'settings' %}">{% trans 'Settings' %}</a> | |
|
55 | </div> | |||
|
56 | {% if fav_threads %} | |||
|
57 | <div> | |||
|
58 | <span class="fav">β </span> | |||
|
59 | {% for thread in fav_threads %} | |||
|
60 | {% comment %} | |||
|
61 | If there are new posts in the thread, show their count. | |||
|
62 | {% endcomment %} | |||
|
63 | {{ thread.0.get_link_view|safe }}{% if thread.1 %} (+{{ thread.1 }}){% endif %}{% if not forloop.last %}, {% endif %} | |||
|
64 | {% endfor %} | |||
|
65 | </div> | |||
|
66 | {% endif %} | |||
54 | </div> |
|
67 | </div> | |
55 |
|
68 | |||
56 | {% block content %}{% endblock %} |
|
69 | {% block content %}{% endblock %} |
@@ -9,6 +9,19 b'' | |||||
9 | {% get_current_language as LANGUAGE_CODE %} |
|
9 | {% get_current_language as LANGUAGE_CODE %} | |
10 | {% get_current_timezone as TIME_ZONE %} |
|
10 | {% get_current_timezone as TIME_ZONE %} | |
11 |
|
11 | |||
|
12 | <div class="tag_info"> | |||
|
13 | <h2> | |||
|
14 | <form action="{% url 'thread' opening_post.id %}" method="post" class="post-button-form"> | |||
|
15 | {% if is_favorite %} | |||
|
16 | <button name="method" value="unsubscribe" class="fav">β </button> | |||
|
17 | {% else %} | |||
|
18 | <button name="method" value="subscribe" class="not_fav">β </button> | |||
|
19 | {% endif %} | |||
|
20 | </form> | |||
|
21 | {{ opening_post.get_title|striptags|truncatewords:10 }} | |||
|
22 | </h2> | |||
|
23 | </div> | |||
|
24 | ||||
12 | {% if bumpable and thread.has_post_limit %} |
|
25 | {% if bumpable and thread.has_post_limit %} | |
13 | <div class="bar-bg"> |
|
26 | <div class="bar-bg"> | |
14 | <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress"> |
|
27 | <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress"> |
@@ -5,6 +5,7 b' from django.db import transaction' | |||||
5 | from django.http import HttpResponse |
|
5 | from django.http import HttpResponse | |
6 | from django.shortcuts import get_object_or_404 |
|
6 | from django.shortcuts import get_object_or_404 | |
7 | from django.core import serializers |
|
7 | from django.core import serializers | |
|
8 | from boards.abstracts.settingsmanager import get_settings_manager | |||
8 |
|
9 | |||
9 | from boards.forms import PostForm, PlainErrorList |
|
10 | from boards.forms import PostForm, PlainErrorList | |
10 | from boards.models import Post, Thread, Tag |
|
11 | from boards.models import Post, Thread, Tag | |
@@ -45,7 +46,8 b' def api_get_threaddiff(request):' | |||||
45 | uids_str = request.POST.get(PARAMETER_UIDS).strip() |
|
46 | uids_str = request.POST.get(PARAMETER_UIDS).strip() | |
46 | uids = uids_str.split(' ') |
|
47 | uids = uids_str.split(' ') | |
47 |
|
48 | |||
48 |
|
|
49 | opening_post = get_object_or_404(Post, id=thread_id) | |
|
50 | thread = opening_post.get_thread() | |||
49 |
|
51 | |||
50 | json_data = { |
|
52 | json_data = { | |
51 | PARAMETER_UPDATED: [], |
|
53 | PARAMETER_UPDATED: [], | |
@@ -60,6 +62,12 b' def api_get_threaddiff(request):' | |||||
60 | request)) |
|
62 | request)) | |
61 | json_data[PARAMETER_LAST_UPDATE] = str(thread.last_edit_time) |
|
63 | json_data[PARAMETER_LAST_UPDATE] = str(thread.last_edit_time) | |
62 |
|
64 | |||
|
65 | # If the tag is favorite, update the counter | |||
|
66 | settings_manager = get_settings_manager(request) | |||
|
67 | favorite = settings_manager.thread_is_fav(opening_post) | |||
|
68 | if favorite: | |||
|
69 | settings_manager.add_or_read_fav_thread(opening_post) | |||
|
70 | ||||
63 | return HttpResponse(content=json.dumps(json_data)) |
|
71 | return HttpResponse(content=json.dumps(json_data)) | |
64 |
|
72 | |||
65 |
|
73 |
@@ -7,9 +7,11 b' from django.utils import timezone' | |||||
7 | from django.utils.dateformat import format |
|
7 | from django.utils.dateformat import format | |
8 |
|
8 | |||
9 | from boards import utils, settings |
|
9 | from boards import utils, settings | |
|
10 | from boards.abstracts.settingsmanager import get_settings_manager | |||
10 | from boards.forms import PostForm, PlainErrorList |
|
11 | from boards.forms import PostForm, PlainErrorList | |
11 | from boards.models import Post |
|
12 | from boards.models import Post | |
12 | from boards.views.base import BaseBoardView, CONTEXT_FORM |
|
13 | from boards.views.base import BaseBoardView, CONTEXT_FORM | |
|
14 | from boards.views.mixins import DispatcherMixin | |||
13 | from boards.views.posting_mixin import PostMixin |
|
15 | from boards.views.posting_mixin import PostMixin | |
14 |
|
16 | |||
15 | import neboard |
|
17 | import neboard | |
@@ -24,6 +26,7 b" CONTEXT_WS_PORT = 'ws_port'" | |||||
24 | CONTEXT_WS_TIME = 'ws_token_time' |
|
26 | CONTEXT_WS_TIME = 'ws_token_time' | |
25 | CONTEXT_MODE = 'mode' |
|
27 | CONTEXT_MODE = 'mode' | |
26 | CONTEXT_OP = 'opening_post' |
|
28 | CONTEXT_OP = 'opening_post' | |
|
29 | CONTEXT_FAVORITE = 'is_favorite' | |||
27 |
|
30 | |||
28 | FORM_TITLE = 'title' |
|
31 | FORM_TITLE = 'title' | |
29 | FORM_TEXT = 'text' |
|
32 | FORM_TEXT = 'text' | |
@@ -31,7 +34,7 b" FORM_IMAGE = 'image'" | |||||
31 | FORM_THREADS = 'threads' |
|
34 | FORM_THREADS = 'threads' | |
32 |
|
35 | |||
33 |
|
36 | |||
34 | class ThreadView(BaseBoardView, PostMixin, FormMixin): |
|
37 | class ThreadView(BaseBoardView, PostMixin, FormMixin, DispatcherMixin): | |
35 |
|
38 | |||
36 | def get(self, request, post_id, form: PostForm=None): |
|
39 | def get(self, request, post_id, form: PostForm=None): | |
37 | try: |
|
40 | try: | |
@@ -39,10 +42,21 b' class ThreadView(BaseBoardView, PostMixi' | |||||
39 | except ObjectDoesNotExist: |
|
42 | except ObjectDoesNotExist: | |
40 | raise Http404 |
|
43 | raise Http404 | |
41 |
|
44 | |||
|
45 | if 'method' in request.POST: | |||
|
46 | self.dispatch_method(request, opening_post) | |||
|
47 | ||||
|
48 | return redirect('thread', post_id) # FIXME Different for different modes | |||
|
49 | ||||
|
50 | # If the tag is favorite, update the counter | |||
|
51 | settings_manager = get_settings_manager(request) | |||
|
52 | favorite = settings_manager.thread_is_fav(opening_post) | |||
|
53 | if favorite: | |||
|
54 | settings_manager.add_or_read_fav_thread(opening_post) | |||
|
55 | ||||
42 | # If this is not OP, don't show it as it is |
|
56 | # If this is not OP, don't show it as it is | |
43 | if not opening_post.is_opening(): |
|
57 | if not opening_post.is_opening(): | |
44 | return redirect(opening_post.get_thread().get_opening_post() |
|
58 | return redirect(opening_post.get_thread().get_opening_post() | |
45 | .get_absolute_url()) |
|
59 | .get_absolute_url()) | |
46 |
|
60 | |||
47 | if not form: |
|
61 | if not form: | |
48 | form = PostForm(error_class=PlainErrorList) |
|
62 | form = PostForm(error_class=PlainErrorList) | |
@@ -56,6 +70,7 b' class ThreadView(BaseBoardView, PostMixi' | |||||
56 | params[CONTEXT_THREAD] = thread_to_show |
|
70 | params[CONTEXT_THREAD] = thread_to_show | |
57 | params[CONTEXT_MODE] = self.get_mode() |
|
71 | params[CONTEXT_MODE] = self.get_mode() | |
58 | params[CONTEXT_OP] = opening_post |
|
72 | params[CONTEXT_OP] = opening_post | |
|
73 | params[CONTEXT_FAVORITE] = favorite | |||
59 |
|
74 | |||
60 | if settings.get_bool('External', 'WebsocketsEnabled'): |
|
75 | if settings.get_bool('External', 'WebsocketsEnabled'): | |
61 | token_time = format(timezone.now(), u'U') |
|
76 | token_time = format(timezone.now(), u'U') | |
@@ -138,3 +153,11 b' class ThreadView(BaseBoardView, PostMixi' | |||||
138 |
|
153 | |||
139 | def get_mode(self) -> str: |
|
154 | def get_mode(self) -> str: | |
140 | pass |
|
155 | pass | |
|
156 | ||||
|
157 | def subscribe(self, request, opening_post): | |||
|
158 | settings_manager = get_settings_manager(request) | |||
|
159 | settings_manager.add_or_read_fav_thread(opening_post) | |||
|
160 | ||||
|
161 | def unsubscribe(self, request, opening_post): | |||
|
162 | settings_manager = get_settings_manager(request) | |||
|
163 | settings_manager.del_fav_thread(opening_post) |
General Comments 0
You need to be logged in to leave comments.
Login now