Show More
@@ -0,0 +1,27 b'' | |||||
|
1 | from boards.abstracts.settingsmanager import SessionSettingsManager | |||
|
2 | from boards.models import PostImage | |||
|
3 | ||||
|
4 | class AttachmentAlias: | |||
|
5 | def get_image(alias): | |||
|
6 | pass | |||
|
7 | ||||
|
8 | ||||
|
9 | class SessionAttachmentAlias(AttachmentAlias): | |||
|
10 | def __init__(self, session): | |||
|
11 | self.session = session | |||
|
12 | ||||
|
13 | def get_image(self, alias): | |||
|
14 | settings_manager = SessionSettingsManager(self.session) | |||
|
15 | return settings_manager.get_image_by_alias(alias) | |||
|
16 | ||||
|
17 | ||||
|
18 | class ModelAttachmentAlias(AttachmentAlias): | |||
|
19 | def get_image(self, alias): | |||
|
20 | return PostImage.objects.filter(alias=alias).first() | |||
|
21 | ||||
|
22 | ||||
|
23 | def get_image_by_alias(alias, session): | |||
|
24 | image = SessionAttachmentAlias(session).get_image(alias) or ModelAttachmentAlias().get_image(alias) | |||
|
25 | ||||
|
26 | if image is not None: | |||
|
27 | return image |
@@ -0,0 +1,24 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | from __future__ import unicode_literals | |||
|
3 | ||||
|
4 | from django.db import migrations, models | |||
|
5 | ||||
|
6 | ||||
|
7 | class Migration(migrations.Migration): | |||
|
8 | ||||
|
9 | dependencies = [ | |||
|
10 | ('boards', '0040_thread_monochrome'), | |||
|
11 | ] | |||
|
12 | ||||
|
13 | operations = [ | |||
|
14 | migrations.AddField( | |||
|
15 | model_name='attachment', | |||
|
16 | name='original_filename', | |||
|
17 | field=models.TextField(null=True), | |||
|
18 | ), | |||
|
19 | migrations.AddField( | |||
|
20 | model_name='postimage', | |||
|
21 | name='original_filename', | |||
|
22 | field=models.TextField(null=True), | |||
|
23 | ), | |||
|
24 | ] |
@@ -0,0 +1,28 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | # Generated by Django 1.9.5 on 2016-04-22 07:53 | |||
|
3 | from __future__ import unicode_literals | |||
|
4 | ||||
|
5 | from django.db import migrations, models | |||
|
6 | ||||
|
7 | ||||
|
8 | class Migration(migrations.Migration): | |||
|
9 | ||||
|
10 | dependencies = [ | |||
|
11 | ('boards', '0041_auto_20160124_2341'), | |||
|
12 | ] | |||
|
13 | ||||
|
14 | operations = [ | |||
|
15 | migrations.RemoveField( | |||
|
16 | model_name='attachment', | |||
|
17 | name='original_filename', | |||
|
18 | ), | |||
|
19 | migrations.RemoveField( | |||
|
20 | model_name='postimage', | |||
|
21 | name='original_filename', | |||
|
22 | ), | |||
|
23 | migrations.AddField( | |||
|
24 | model_name='postimage', | |||
|
25 | name='alias', | |||
|
26 | field=models.TextField(blank=True, null=True, unique=True), | |||
|
27 | ), | |||
|
28 | ] |
@@ -19,6 +19,7 b" SETTING_USERNAME = 'username'" | |||||
19 | SETTING_LAST_NOTIFICATION_ID = 'last_notification' |
|
19 | SETTING_LAST_NOTIFICATION_ID = 'last_notification' | |
20 | SETTING_IMAGE_VIEWER = 'image_viewer' |
|
20 | SETTING_IMAGE_VIEWER = 'image_viewer' | |
21 | SETTING_TRIPCODE = 'tripcode' |
|
21 | SETTING_TRIPCODE = 'tripcode' | |
|
22 | SETTING_IMAGES = 'images_aliases' | |||
22 |
|
23 | |||
23 | DEFAULT_THEME = 'md' |
|
24 | DEFAULT_THEME = 'md' | |
24 |
|
25 | |||
@@ -153,6 +154,17 b' class SettingsManager:' | |||||
153 | names = set(name.strip() for name in names) |
|
154 | names = set(name.strip() for name in names) | |
154 | return names |
|
155 | return names | |
155 |
|
156 | |||
|
157 | def get_image_by_alias(self, alias): | |||
|
158 | images = self.get_setting(SETTING_IMAGES) | |||
|
159 | if images is not None and len(images) > 0: | |||
|
160 | return images.get(alias) | |||
|
161 | ||||
|
162 | def add_image_alias(self, alias, image): | |||
|
163 | images = self.get_setting(SETTING_IMAGES) | |||
|
164 | if images is None: | |||
|
165 | images = dict() | |||
|
166 | images.put(alias, image) | |||
|
167 | ||||
156 |
|
168 | |||
157 | class SessionSettingsManager(SettingsManager): |
|
169 | class SessionSettingsManager(SettingsManager): | |
158 | """ |
|
170 | """ |
@@ -1,16 +1,17 b'' | |||||
1 | from django.contrib import admin |
|
1 | from django.contrib import admin | |
2 | from boards.models import Post, Tag, Ban, Thread, Banner |
|
|||
3 | from django.utils.translation import ugettext_lazy as _ |
|
2 | from django.utils.translation import ugettext_lazy as _ | |
|
3 | from django.core.urlresolvers import reverse | |||
|
4 | from boards.models import Post, Tag, Ban, Thread, Banner, PostImage | |||
4 |
|
5 | |||
5 |
|
6 | |||
6 | @admin.register(Post) |
|
7 | @admin.register(Post) | |
7 | class PostAdmin(admin.ModelAdmin): |
|
8 | class PostAdmin(admin.ModelAdmin): | |
8 |
|
9 | |||
9 | list_display = ('id', 'title', 'text', 'poster_ip') |
|
10 | list_display = ('id', 'title', 'text', 'poster_ip', 'linked_images') | |
10 | list_filter = ('pub_time',) |
|
11 | list_filter = ('pub_time',) | |
11 | search_fields = ('id', 'title', 'text', 'poster_ip') |
|
12 | search_fields = ('id', 'title', 'text', 'poster_ip') | |
12 | exclude = ('referenced_posts', 'refmap') |
|
13 | exclude = ('referenced_posts', 'refmap') | |
13 | readonly_fields = ('poster_ip', 'threads', 'thread', 'images', |
|
14 | readonly_fields = ('poster_ip', 'threads', 'thread', 'linked_images', | |
14 | 'attachments', 'uid', 'url', 'pub_time', 'opening') |
|
15 | 'attachments', 'uid', 'url', 'pub_time', 'opening') | |
15 |
|
16 | |||
16 | def ban_poster(self, request, queryset): |
|
17 | def ban_poster(self, request, queryset): | |
@@ -35,6 +36,12 b' class PostAdmin(admin.ModelAdmin):' | |||||
35 | posts.update(hidden=True) |
|
36 | posts.update(hidden=True) | |
36 | self.message_user(request, _('{} posters were banned, {} messages were hidden').format(bans, hidden)) |
|
37 | self.message_user(request, _('{} posters were banned, {} messages were hidden').format(bans, hidden)) | |
37 |
|
38 | |||
|
39 | def linked_images(self, obj: Post): | |||
|
40 | images = obj.images.all() | |||
|
41 | image_urls = ['<a href="{}">{}</a>'.format(reverse('admin:%s_%s_change' %(image._meta.app_label, image._meta.model_name), args=[image.id]), image.hash) for image in images] | |||
|
42 | return ', '.join(image_urls) | |||
|
43 | linked_images.allow_tags = True | |||
|
44 | ||||
38 |
|
45 | |||
39 | actions = ['ban_poster', 'ban_with_hiding'] |
|
46 | actions = ['ban_poster', 'ban_with_hiding'] | |
40 |
|
47 | |||
@@ -97,3 +104,8 b' class BanAdmin(admin.ModelAdmin):' | |||||
97 | @admin.register(Banner) |
|
104 | @admin.register(Banner) | |
98 | class BannerAdmin(admin.ModelAdmin): |
|
105 | class BannerAdmin(admin.ModelAdmin): | |
99 | list_display = ('title', 'text') |
|
106 | list_display = ('title', 'text') | |
|
107 | ||||
|
108 | ||||
|
109 | @admin.register(PostImage) | |||
|
110 | class PostImageAdmin(admin.ModelAdmin): | |||
|
111 | search_fields = ('alias',) |
@@ -13,6 +13,7 b' from django.utils.translation import uge' | |||||
13 | from django.utils import timezone |
|
13 | from django.utils import timezone | |
14 |
|
14 | |||
15 | from boards.abstracts.settingsmanager import get_settings_manager |
|
15 | from boards.abstracts.settingsmanager import get_settings_manager | |
|
16 | from boards.abstracts.attachment_alias import get_image_by_alias | |||
16 | from boards.mdx_neboard import formatters |
|
17 | from boards.mdx_neboard import formatters | |
17 | from boards.models.attachment.downloaders import Downloader |
|
18 | from boards.models.attachment.downloaders import Downloader | |
18 | from boards.models.post import TITLE_MAX_LENGTH |
|
19 | from boards.models.post import TITLE_MAX_LENGTH | |
@@ -183,6 +184,7 b' class PostForm(NeboardForm):' | |||||
183 |
|
184 | |||
184 | session = None |
|
185 | session = None | |
185 | need_to_ban = False |
|
186 | need_to_ban = False | |
|
187 | image = None | |||
186 |
|
188 | |||
187 | def _update_file_extension(self, file): |
|
189 | def _update_file_extension(self, file): | |
188 | if file: |
|
190 | if file: | |
@@ -229,9 +231,16 b' class PostForm(NeboardForm):' | |||||
229 | url = self.cleaned_data['file_url'] |
|
231 | url = self.cleaned_data['file_url'] | |
230 |
|
232 | |||
231 | file = None |
|
233 | file = None | |
|
234 | ||||
232 | if url: |
|
235 | if url: | |
|
236 | file = get_image_by_alias(url, self.session) | |||
|
237 | self.image = file | |||
|
238 | ||||
|
239 | if file is not None: | |||
|
240 | return | |||
|
241 | ||||
|
242 | if file is None: | |||
233 | file = self._get_file_from_url(url) |
|
243 | file = self._get_file_from_url(url) | |
234 |
|
||||
235 | if not file: |
|
244 | if not file: | |
236 | raise forms.ValidationError(_('Invalid URL')) |
|
245 | raise forms.ValidationError(_('Invalid URL')) | |
237 | else: |
|
246 | else: | |
@@ -312,11 +321,18 b' class PostForm(NeboardForm):' | |||||
312 | else: |
|
321 | else: | |
313 | return title |
|
322 | return title | |
314 |
|
323 | |||
|
324 | def get_images(self): | |||
|
325 | if self.image: | |||
|
326 | return [self.image] | |||
|
327 | else: | |||
|
328 | return [] | |||
|
329 | ||||
315 | def _clean_text_file(self): |
|
330 | def _clean_text_file(self): | |
316 | text = self.cleaned_data.get('text') |
|
331 | text = self.cleaned_data.get('text') | |
317 | file = self.get_file() |
|
332 | file = self.get_file() | |
|
333 | images = self.get_images() | |||
318 |
|
334 | |||
319 | if (not text) and (not file): |
|
335 | if (not text) and (not file) and len(images) == 0: | |
320 | error_message = _('Either text or file must be entered.') |
|
336 | error_message = _('Either text or file must be entered.') | |
321 | self._errors['text'] = self.error_class([error_message]) |
|
337 | self._errors['text'] = self.error_class([error_message]) | |
322 |
|
338 |
@@ -67,3 +67,4 b' class YouTubeDownloader(Downloader):' | |||||
67 | @staticmethod |
|
67 | @staticmethod | |
68 | def handles(url: str) -> bool: |
|
68 | def handles(url: str) -> bool: | |
69 | return YOUTUBE_URL.match(url) |
|
69 | return YOUTUBE_URL.match(url) | |
|
70 |
@@ -56,6 +56,7 b' class PostImage(models.Model, Viewable):' | |||||
56 | preview_width_field='pre_width', |
|
56 | preview_width_field='pre_width', | |
57 | preview_height_field='pre_height') |
|
57 | preview_height_field='pre_height') | |
58 | hash = models.CharField(max_length=HASH_LENGTH) |
|
58 | hash = models.CharField(max_length=HASH_LENGTH) | |
|
59 | alias = models.TextField(unique=True, null=True, blank=True) | |||
59 |
|
60 | |||
60 | def save(self, *args, **kwargs): |
|
61 | def save(self, *args, **kwargs): | |
61 | """ |
|
62 | """ |
@@ -31,7 +31,7 b' class PostManager(models.Manager):' | |||||
31 | @transaction.atomic |
|
31 | @transaction.atomic | |
32 | def create_post(self, title: str, text: str, file=None, thread=None, |
|
32 | def create_post(self, title: str, text: str, file=None, thread=None, | |
33 | ip=NO_IP, tags: list=None, opening_posts: list=None, |
|
33 | ip=NO_IP, tags: list=None, opening_posts: list=None, | |
34 | tripcode='', monochrome=False): |
|
34 | tripcode='', monochrome=False, images=[]): | |
35 | """ |
|
35 | """ | |
36 | Creates new post |
|
36 | Creates new post | |
37 | """ |
|
37 | """ | |
@@ -87,6 +87,8 b' class PostManager(models.Manager):' | |||||
87 | post.images.add(PostImage.objects.create_with_hash(file)) |
|
87 | post.images.add(PostImage.objects.create_with_hash(file)) | |
88 | else: |
|
88 | else: | |
89 | post.attachments.add(Attachment.objects.create_with_hash(file)) |
|
89 | post.attachments.add(Attachment.objects.create_with_hash(file)) | |
|
90 | for image in images: | |||
|
91 | post.images.add(image) | |||
90 |
|
92 | |||
91 | post.connect_threads(opening_posts) |
|
93 | post.connect_threads(opening_posts) | |
92 |
|
94 |
@@ -24,6 +24,10 b'' | |||||
24 | {% else %} |
|
24 | {% else %} | |
25 | <p>{% trans 'No hidden tags.' %}</p> |
|
25 | <p>{% trans 'No hidden tags.' %}</p> | |
26 | {% endif %} |
|
26 | {% endif %} | |
|
27 | ||||
|
28 | {% for image in image_aliases %} | |||
|
29 | {{ image.alias }}: <img src="{{ image.image.url_200x150 }}" /> <br /> | |||
|
30 | {% endfor %} | |||
27 | </div> |
|
31 | </div> | |
28 |
|
32 | |||
29 | <div class="post-form-w"> |
|
33 | <div class="post-form-w"> |
@@ -138,6 +138,7 b' class AllThreadsView(PostMixin, FileUplo' | |||||
138 | text = data[FORM_TEXT] |
|
138 | text = data[FORM_TEXT] | |
139 | file = form.get_file() |
|
139 | file = form.get_file() | |
140 | threads = data[FORM_THREADS] |
|
140 | threads = data[FORM_THREADS] | |
|
141 | images = form.get_images() | |||
141 |
|
142 | |||
142 | text = self._remove_invalid_links(text) |
|
143 | text = self._remove_invalid_links(text) | |
143 |
|
144 | |||
@@ -147,7 +148,7 b' class AllThreadsView(PostMixin, FileUplo' | |||||
147 | post = Post.objects.create_post(title=title, text=text, file=file, |
|
148 | post = Post.objects.create_post(title=title, text=text, file=file, | |
148 | ip=ip, tags=tags, opening_posts=threads, |
|
149 | ip=ip, tags=tags, opening_posts=threads, | |
149 | tripcode=form.get_tripcode(), |
|
150 | tripcode=form.get_tripcode(), | |
150 | monochrome=monochrome) |
|
151 | monochrome=monochrome, images=images) | |
151 |
|
152 | |||
152 | # This is required to update the threads to which posts we have replied |
|
153 | # This is required to update the threads to which posts we have replied | |
153 | # when creating this one |
|
154 | # when creating this one |
@@ -8,6 +8,7 b' from boards.middlewares import SESSION_T' | |||||
8 | from boards.views.base import BaseBoardView, CONTEXT_FORM |
|
8 | from boards.views.base import BaseBoardView, CONTEXT_FORM | |
9 | from boards.forms import SettingsForm, PlainErrorList |
|
9 | from boards.forms import SettingsForm, PlainErrorList | |
10 | from boards import settings |
|
10 | from boards import settings | |
|
11 | from boards.models import PostImage | |||
11 |
|
12 | |||
12 | FORM_THEME = 'theme' |
|
13 | FORM_THEME = 'theme' | |
13 | FORM_USERNAME = 'username' |
|
14 | FORM_USERNAME = 'username' | |
@@ -15,6 +16,7 b" FORM_TIMEZONE = 'timezone'" | |||||
15 | FORM_IMAGE_VIEWER = 'image_viewer' |
|
16 | FORM_IMAGE_VIEWER = 'image_viewer' | |
16 |
|
17 | |||
17 | CONTEXT_HIDDEN_TAGS = 'hidden_tags' |
|
18 | CONTEXT_HIDDEN_TAGS = 'hidden_tags' | |
|
19 | CONTEXT_IMAGE_ALIASES = 'image_aliases' | |||
18 |
|
20 | |||
19 | TEMPLATE = 'boards/settings.html' |
|
21 | TEMPLATE = 'boards/settings.html' | |
20 |
|
22 | |||
@@ -41,6 +43,7 b' class SettingsView(BaseBoardView):' | |||||
41 |
|
43 | |||
42 | params[CONTEXT_FORM] = form |
|
44 | params[CONTEXT_FORM] = form | |
43 | params[CONTEXT_HIDDEN_TAGS] = settings_manager.get_hidden_tags() |
|
45 | params[CONTEXT_HIDDEN_TAGS] = settings_manager.get_hidden_tags() | |
|
46 | params[CONTEXT_IMAGE_ALIASES] = PostImage.objects.exclude(alias='').exclude(alias=None) | |||
44 |
|
47 | |||
45 | return render(request, TEMPLATE, params) |
|
48 | return render(request, TEMPLATE, params) | |
46 |
|
49 |
@@ -129,6 +129,7 b' class ThreadView(BaseBoardView, PostMixi' | |||||
129 | text = data[FORM_TEXT] |
|
129 | text = data[FORM_TEXT] | |
130 | file = form.get_file() |
|
130 | file = form.get_file() | |
131 | threads = data[FORM_THREADS] |
|
131 | threads = data[FORM_THREADS] | |
|
132 | images = form.get_images() | |||
132 |
|
133 | |||
133 | text = self._remove_invalid_links(text) |
|
134 | text = self._remove_invalid_links(text) | |
134 |
|
135 | |||
@@ -137,7 +138,8 b' class ThreadView(BaseBoardView, PostMixi' | |||||
137 | post = Post.objects.create_post(title=title, text=text, file=file, |
|
138 | post = Post.objects.create_post(title=title, text=text, file=file, | |
138 | thread=post_thread, ip=ip, |
|
139 | thread=post_thread, ip=ip, | |
139 | opening_posts=threads, |
|
140 | opening_posts=threads, | |
140 |
tripcode=form.get_tripcode() |
|
141 | tripcode=form.get_tripcode(), | |
|
142 | images=images) | |||
141 | post.notify_clients() |
|
143 | post.notify_clients() | |
142 |
|
144 | |||
143 | if html_response: |
|
145 | if html_response: |
General Comments 0
You need to be logged in to leave comments.
Login now