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 | 19 | SETTING_LAST_NOTIFICATION_ID = 'last_notification' |
|
20 | 20 | SETTING_IMAGE_VIEWER = 'image_viewer' |
|
21 | 21 | SETTING_TRIPCODE = 'tripcode' |
|
22 | SETTING_IMAGES = 'images_aliases' | |
|
22 | 23 | |
|
23 | 24 | DEFAULT_THEME = 'md' |
|
24 | 25 | |
@@ -153,6 +154,17 b' class SettingsManager:' | |||
|
153 | 154 | names = set(name.strip() for name in names) |
|
154 | 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 | 169 | class SessionSettingsManager(SettingsManager): |
|
158 | 170 | """ |
@@ -1,16 +1,17 b'' | |||
|
1 | 1 | from django.contrib import admin |
|
2 | from boards.models import Post, Tag, Ban, Thread, Banner | |
|
3 | 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 | 7 | @admin.register(Post) |
|
7 | 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 | 11 | list_filter = ('pub_time',) |
|
11 | 12 | search_fields = ('id', 'title', 'text', 'poster_ip') |
|
12 | 13 | exclude = ('referenced_posts', 'refmap') |
|
13 | readonly_fields = ('poster_ip', 'threads', 'thread', 'images', | |
|
14 | readonly_fields = ('poster_ip', 'threads', 'thread', 'linked_images', | |
|
14 | 15 | 'attachments', 'uid', 'url', 'pub_time', 'opening') |
|
15 | 16 | |
|
16 | 17 | def ban_poster(self, request, queryset): |
@@ -35,6 +36,12 b' class PostAdmin(admin.ModelAdmin):' | |||
|
35 | 36 | posts.update(hidden=True) |
|
36 | 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 | 46 | actions = ['ban_poster', 'ban_with_hiding'] |
|
40 | 47 | |
@@ -97,3 +104,8 b' class BanAdmin(admin.ModelAdmin):' | |||
|
97 | 104 | @admin.register(Banner) |
|
98 | 105 | class BannerAdmin(admin.ModelAdmin): |
|
99 | 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 | 13 | from django.utils import timezone |
|
14 | 14 | |
|
15 | 15 | from boards.abstracts.settingsmanager import get_settings_manager |
|
16 | from boards.abstracts.attachment_alias import get_image_by_alias | |
|
16 | 17 | from boards.mdx_neboard import formatters |
|
17 | 18 | from boards.models.attachment.downloaders import Downloader |
|
18 | 19 | from boards.models.post import TITLE_MAX_LENGTH |
@@ -183,6 +184,7 b' class PostForm(NeboardForm):' | |||
|
183 | 184 | |
|
184 | 185 | session = None |
|
185 | 186 | need_to_ban = False |
|
187 | image = None | |
|
186 | 188 | |
|
187 | 189 | def _update_file_extension(self, file): |
|
188 | 190 | if file: |
@@ -229,13 +231,20 b' class PostForm(NeboardForm):' | |||
|
229 | 231 | url = self.cleaned_data['file_url'] |
|
230 | 232 | |
|
231 | 233 | file = None |
|
234 | ||
|
232 | 235 | if url: |
|
233 | file = self._get_file_from_url(url) | |
|
236 | file = get_image_by_alias(url, self.session) | |
|
237 | self.image = file | |
|
234 | 238 | |
|
235 |
if not |
|
|
236 | raise forms.ValidationError(_('Invalid URL')) | |
|
237 | else: | |
|
238 | validate_file_size(file.size) | |
|
239 | if file is not None: | |
|
240 | return | |
|
241 | ||
|
242 | if file is None: | |
|
243 | file = self._get_file_from_url(url) | |
|
244 | if not file: | |
|
245 | raise forms.ValidationError(_('Invalid URL')) | |
|
246 | else: | |
|
247 | validate_file_size(file.size) | |
|
239 | 248 | self._update_file_extension(file) |
|
240 | 249 | |
|
241 | 250 | return file |
@@ -312,11 +321,18 b' class PostForm(NeboardForm):' | |||
|
312 | 321 | else: |
|
313 | 322 | return title |
|
314 | 323 | |
|
324 | def get_images(self): | |
|
325 | if self.image: | |
|
326 | return [self.image] | |
|
327 | else: | |
|
328 | return [] | |
|
329 | ||
|
315 | 330 | def _clean_text_file(self): |
|
316 | 331 | text = self.cleaned_data.get('text') |
|
317 | 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 | 336 | error_message = _('Either text or file must be entered.') |
|
321 | 337 | self._errors['text'] = self.error_class([error_message]) |
|
322 | 338 |
@@ -67,3 +67,4 b' class YouTubeDownloader(Downloader):' | |||
|
67 | 67 | @staticmethod |
|
68 | 68 | def handles(url: str) -> bool: |
|
69 | 69 | return YOUTUBE_URL.match(url) |
|
70 |
@@ -56,6 +56,7 b' class PostImage(models.Model, Viewable):' | |||
|
56 | 56 | preview_width_field='pre_width', |
|
57 | 57 | preview_height_field='pre_height') |
|
58 | 58 | hash = models.CharField(max_length=HASH_LENGTH) |
|
59 | alias = models.TextField(unique=True, null=True, blank=True) | |
|
59 | 60 | |
|
60 | 61 | def save(self, *args, **kwargs): |
|
61 | 62 | """ |
@@ -31,7 +31,7 b' class PostManager(models.Manager):' | |||
|
31 | 31 | @transaction.atomic |
|
32 | 32 | def create_post(self, title: str, text: str, file=None, thread=None, |
|
33 | 33 | ip=NO_IP, tags: list=None, opening_posts: list=None, |
|
34 | tripcode='', monochrome=False): | |
|
34 | tripcode='', monochrome=False, images=[]): | |
|
35 | 35 | """ |
|
36 | 36 | Creates new post |
|
37 | 37 | """ |
@@ -87,6 +87,8 b' class PostManager(models.Manager):' | |||
|
87 | 87 | post.images.add(PostImage.objects.create_with_hash(file)) |
|
88 | 88 | else: |
|
89 | 89 | post.attachments.add(Attachment.objects.create_with_hash(file)) |
|
90 | for image in images: | |
|
91 | post.images.add(image) | |
|
90 | 92 | |
|
91 | 93 | post.connect_threads(opening_posts) |
|
92 | 94 |
@@ -24,6 +24,10 b'' | |||
|
24 | 24 | {% else %} |
|
25 | 25 | <p>{% trans 'No hidden tags.' %}</p> |
|
26 | 26 | {% endif %} |
|
27 | ||
|
28 | {% for image in image_aliases %} | |
|
29 | {{ image.alias }}: <img src="{{ image.image.url_200x150 }}" /> <br /> | |
|
30 | {% endfor %} | |
|
27 | 31 | </div> |
|
28 | 32 | |
|
29 | 33 | <div class="post-form-w"> |
@@ -138,6 +138,7 b' class AllThreadsView(PostMixin, FileUplo' | |||
|
138 | 138 | text = data[FORM_TEXT] |
|
139 | 139 | file = form.get_file() |
|
140 | 140 | threads = data[FORM_THREADS] |
|
141 | images = form.get_images() | |
|
141 | 142 | |
|
142 | 143 | text = self._remove_invalid_links(text) |
|
143 | 144 | |
@@ -147,7 +148,7 b' class AllThreadsView(PostMixin, FileUplo' | |||
|
147 | 148 | post = Post.objects.create_post(title=title, text=text, file=file, |
|
148 | 149 | ip=ip, tags=tags, opening_posts=threads, |
|
149 | 150 | tripcode=form.get_tripcode(), |
|
150 | monochrome=monochrome) | |
|
151 | monochrome=monochrome, images=images) | |
|
151 | 152 | |
|
152 | 153 | # This is required to update the threads to which posts we have replied |
|
153 | 154 | # when creating this one |
@@ -8,6 +8,7 b' from boards.middlewares import SESSION_T' | |||
|
8 | 8 | from boards.views.base import BaseBoardView, CONTEXT_FORM |
|
9 | 9 | from boards.forms import SettingsForm, PlainErrorList |
|
10 | 10 | from boards import settings |
|
11 | from boards.models import PostImage | |
|
11 | 12 | |
|
12 | 13 | FORM_THEME = 'theme' |
|
13 | 14 | FORM_USERNAME = 'username' |
@@ -15,6 +16,7 b" FORM_TIMEZONE = 'timezone'" | |||
|
15 | 16 | FORM_IMAGE_VIEWER = 'image_viewer' |
|
16 | 17 | |
|
17 | 18 | CONTEXT_HIDDEN_TAGS = 'hidden_tags' |
|
19 | CONTEXT_IMAGE_ALIASES = 'image_aliases' | |
|
18 | 20 | |
|
19 | 21 | TEMPLATE = 'boards/settings.html' |
|
20 | 22 | |
@@ -41,6 +43,7 b' class SettingsView(BaseBoardView):' | |||
|
41 | 43 | |
|
42 | 44 | params[CONTEXT_FORM] = form |
|
43 | 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 | 48 | return render(request, TEMPLATE, params) |
|
46 | 49 |
@@ -129,6 +129,7 b' class ThreadView(BaseBoardView, PostMixi' | |||
|
129 | 129 | text = data[FORM_TEXT] |
|
130 | 130 | file = form.get_file() |
|
131 | 131 | threads = data[FORM_THREADS] |
|
132 | images = form.get_images() | |
|
132 | 133 | |
|
133 | 134 | text = self._remove_invalid_links(text) |
|
134 | 135 | |
@@ -137,7 +138,8 b' class ThreadView(BaseBoardView, PostMixi' | |||
|
137 | 138 | post = Post.objects.create_post(title=title, text=text, file=file, |
|
138 | 139 | thread=post_thread, ip=ip, |
|
139 | 140 | opening_posts=threads, |
|
140 |
tripcode=form.get_tripcode() |
|
|
141 | tripcode=form.get_tripcode(), | |
|
142 | images=images) | |
|
141 | 143 | post.notify_clients() |
|
142 | 144 | |
|
143 | 145 | if html_response: |
General Comments 0
You need to be logged in to leave comments.
Login now