Show More
@@ -0,0 +1,1 | |||
|
1 | FILE_DIRECTORY = 'files/' |
@@ -0,0 +1,42 | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | # Generated by Django 1.9.5 on 2016-05-21 07:43 | |
|
3 | from __future__ import unicode_literals | |
|
4 | ||
|
5 | from boards.signals import generate_thumb | |
|
6 | from boards.utils import get_extension | |
|
7 | from django.db import migrations, models | |
|
8 | ||
|
9 | ||
|
10 | class Migration(migrations.Migration): | |
|
11 | ||
|
12 | def images_to_attachments(apps, schema_editor): | |
|
13 | PostImage = apps.get_model('boards', 'PostImage') | |
|
14 | Attachment = apps.get_model('boards', 'Attachment') | |
|
15 | ||
|
16 | count = 0 | |
|
17 | images = PostImage.objects.all() | |
|
18 | for image in images: | |
|
19 | file_type = get_extension(image.image.name) | |
|
20 | attachment = Attachment.objects.create( | |
|
21 | file=image.image.file, mimetype=file_type, hash=image.hash, | |
|
22 | alias=image.alias) | |
|
23 | generate_thumb(attachment) | |
|
24 | count += 1 | |
|
25 | print('Processed {} of {} images'.format(count, len(images))) | |
|
26 | for post in image.post_images.all(): | |
|
27 | post.attachments.add(attachment) | |
|
28 | ||
|
29 | image.image.close() | |
|
30 | ||
|
31 | dependencies = [ | |
|
32 | ('boards', '0046_auto_20160520_2307'), | |
|
33 | ] | |
|
34 | ||
|
35 | operations = [ | |
|
36 | migrations.AddField( | |
|
37 | model_name='attachment', | |
|
38 | name='alias', | |
|
39 | field=models.TextField(blank=True, null=True, unique=True), | |
|
40 | ), | |
|
41 | migrations.RunPython(images_to_attachments), | |
|
42 | ] |
@@ -0,0 +1,19 | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | # Generated by Django 1.9.5 on 2016-05-21 08:25 | |
|
3 | from __future__ import unicode_literals | |
|
4 | ||
|
5 | from django.db import migrations | |
|
6 | ||
|
7 | ||
|
8 | class Migration(migrations.Migration): | |
|
9 | ||
|
10 | dependencies = [ | |
|
11 | ('boards', '0047_attachment_alias'), | |
|
12 | ] | |
|
13 | ||
|
14 | operations = [ | |
|
15 | migrations.RemoveField( | |
|
16 | model_name='post', | |
|
17 | name='images', | |
|
18 | ), | |
|
19 | ] |
@@ -0,0 +1,18 | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | # Generated by Django 1.9.5 on 2016-05-21 08:29 | |
|
3 | from __future__ import unicode_literals | |
|
4 | ||
|
5 | from django.db import migrations | |
|
6 | ||
|
7 | ||
|
8 | class Migration(migrations.Migration): | |
|
9 | ||
|
10 | dependencies = [ | |
|
11 | ('boards', '0048_remove_post_images'), | |
|
12 | ] | |
|
13 | ||
|
14 | operations = [ | |
|
15 | migrations.DeleteModel( | |
|
16 | name='PostImage', | |
|
17 | ), | |
|
18 | ] |
@@ -1,5 +1,6 | |||
|
1 | 1 | from boards.abstracts.settingsmanager import SessionSettingsManager |
|
2 |
from boards.models import |
|
|
2 | from boards.models import Attachment | |
|
3 | ||
|
3 | 4 | |
|
4 | 5 | class AttachmentAlias: |
|
5 | 6 | def get_image(alias): |
@@ -17,7 +18,7 class SessionAttachmentAlias(AttachmentA | |||
|
17 | 18 | |
|
18 | 19 | class ModelAttachmentAlias(AttachmentAlias): |
|
19 | 20 | def get_image(self, alias): |
|
20 |
return |
|
|
21 | return Attachment.objects.filter(alias=alias).first() | |
|
21 | 22 | |
|
22 | 23 | |
|
23 | 24 | def get_image_by_alias(alias, session): |
@@ -1,8 +1,8 | |||
|
1 | from boards.models.attachment import FILE_TYPES_IMAGE | |
|
1 | 2 | from django.contrib import admin |
|
2 | 3 | from django.utils.translation import ugettext_lazy as _ |
|
3 | 4 | from django.core.urlresolvers import reverse |
|
4 | from django.db.models import F | |
|
5 | from boards.models import Post, Tag, Ban, Thread, Banner, PostImage, KeyPair, GlobalId | |
|
5 | from boards.models import Post, Tag, Ban, Thread, Banner, Attachment, KeyPair, GlobalId | |
|
6 | 6 | |
|
7 | 7 | |
|
8 | 8 | @admin.register(Post) |
@@ -40,11 +40,11 class PostAdmin(admin.ModelAdmin): | |||
|
40 | 40 | self.message_user(request, _('{} posters were banned, {} messages were hidden').format(bans, hidden)) |
|
41 | 41 | |
|
42 | 42 | def linked_images(self, obj: Post): |
|
43 | images = obj.images.all() | |
|
43 | images = obj.attachments.filter(mimetype__in=FILE_TYPES_IMAGE) | |
|
44 | 44 | image_urls = ['<a href="{}"><img src="{}" /></a>'.format( |
|
45 | 45 | reverse('admin:%s_%s_change' % (image._meta.app_label, |
|
46 | 46 | image._meta.model_name), |
|
47 |
args=[image.id]), image. |
|
|
47 | args=[image.id]), image.file.url_200x150) for image in images] | |
|
48 | 48 | return ', '.join(image_urls) |
|
49 | 49 | linked_images.allow_tags = True |
|
50 | 50 | |
@@ -142,8 +142,8 class BannerAdmin(admin.ModelAdmin): | |||
|
142 | 142 | list_display = ('title', 'text') |
|
143 | 143 | |
|
144 | 144 | |
|
145 |
@admin.register( |
|
|
146 |
class |
|
|
145 | @admin.register(Attachment) | |
|
146 | class AttachmentAdmin(admin.ModelAdmin): | |
|
147 | 147 | search_fields = ('alias',) |
|
148 | 148 | |
|
149 | 149 |
@@ -1,46 +1,36 | |||
|
1 | 1 | import os |
|
2 | from boards.abstracts.constants import FILE_DIRECTORY | |
|
2 | 3 | |
|
3 | 4 | from django.core.management import BaseCommand |
|
4 | 5 | from django.db import transaction |
|
5 | 6 | from boards.models import Attachment |
|
6 | from boards.models.attachment import FILES_DIRECTORY | |
|
7 | 7 | |
|
8 | from boards.models.image import IMAGES_DIRECTORY, PostImage, IMAGE_THUMB_SIZE | |
|
9 | 8 | from neboard.settings import MEDIA_ROOT |
|
10 | 9 | |
|
11 | 10 | |
|
12 | 11 | __author__ = 'neko259' |
|
13 | 12 | |
|
13 | THUMB_SIZE = (200, 150) | |
|
14 | ||
|
14 | 15 | |
|
15 | 16 | class Command(BaseCommand): |
|
16 | 17 | help = 'Remove files whose models were deleted' |
|
17 | 18 | |
|
18 | 19 | @transaction.atomic |
|
19 | 20 | def handle(self, *args, **options): |
|
20 | count = 0 | |
|
21 | thumb_prefix = '.{}x{}'.format(*IMAGE_THUMB_SIZE) | |
|
22 | ||
|
23 | model_files = os.listdir(MEDIA_ROOT + IMAGES_DIRECTORY) | |
|
24 | for file in model_files: | |
|
25 | image_name = file if thumb_prefix not in file else file.replace(thumb_prefix, '') | |
|
26 | found = PostImage.objects.filter( | |
|
27 | image=IMAGES_DIRECTORY + image_name).exists() | |
|
28 | ||
|
29 | if not found: | |
|
30 | print('Missing {}'.format(image_name)) | |
|
31 | os.remove(MEDIA_ROOT + IMAGES_DIRECTORY + file) | |
|
32 | count += 1 | |
|
33 | print('Deleted {} image files.'.format(count)) | |
|
21 | thumb_prefix = '.{}x{}'.format(*THUMB_SIZE) | |
|
34 | 22 | |
|
35 | 23 | count = 0 |
|
36 |
model_files = os.listdir(MEDIA_ROOT + FILE |
|
|
24 | model_files = os.listdir(MEDIA_ROOT + FILE_DIRECTORY) | |
|
37 | 25 | for file in model_files: |
|
38 | found = Attachment.objects.filter(file=FILES_DIRECTORY + file)\ | |
|
26 | model_filename = file if thumb_prefix not in file else file.replace( | |
|
27 | thumb_prefix, '') | |
|
28 | found = Attachment.objects.filter(file=FILE_DIRECTORY + model_filename)\ | |
|
39 | 29 | .exists() |
|
40 | 30 | |
|
41 | 31 | if not found: |
|
42 | 32 | print('Missing {}'.format(file)) |
|
43 |
os.remove(MEDIA_ROOT + FILE |
|
|
33 | os.remove(MEDIA_ROOT + FILE_DIRECTORY + file) | |
|
44 | 34 | count += 1 |
|
45 | 35 | |
|
46 | 36 | print('Deleted {} attachment files.'.format(count)) |
@@ -2,7 +2,6 | |||
|
2 | 2 | from __future__ import unicode_literals |
|
3 | 3 | |
|
4 | 4 | from django.db import models, migrations |
|
5 | import boards.models.image | |
|
6 | 5 | import boards.models.base |
|
7 | 6 | import boards.thumbs |
|
8 | 7 |
@@ -5,7 +5,6 STATUS_ARCHIVE = 'archived' | |||
|
5 | 5 | |
|
6 | 6 | from boards.models.sync_key import KeyPair |
|
7 | 7 | from boards.models.signature import GlobalId, Signature |
|
8 | from boards.models.image import PostImage | |
|
9 | 8 | from boards.models.attachment import Attachment |
|
10 | 9 | from boards.models.thread import Thread |
|
11 | 10 | from boards.models.post import Post |
@@ -1,8 +1,12 | |||
|
1 | import boards | |
|
2 | from boards.models import STATUS_ARCHIVE | |
|
3 | from django.core.files.images import get_image_dimensions | |
|
1 | 4 | from django.db import models |
|
2 | 5 | |
|
3 | 6 | from boards import utils |
|
4 | from boards.models.attachment.viewers import get_viewers, AbstractViewer | |
|
5 | from boards.utils import get_upload_filename, get_file_mimetype, get_extension | |
|
7 | from boards.models.attachment.viewers import get_viewers, AbstractViewer, \ | |
|
8 | FILE_TYPES_IMAGE | |
|
9 | from boards.utils import get_upload_filename, get_extension, cached_result | |
|
6 | 10 | |
|
7 | 11 | |
|
8 | 12 | class AttachmentManager(models.Manager): |
@@ -19,6 +23,13 class AttachmentManager(models.Manager): | |||
|
19 | 23 | |
|
20 | 24 | return attachment |
|
21 | 25 | |
|
26 | def get_random_images(self, count, tags=None): | |
|
27 | images = self.filter(mimetype__in=FILE_TYPES_IMAGE).exclude( | |
|
28 | post_attachments__thread__status=STATUS_ARCHIVE) | |
|
29 | if tags is not None: | |
|
30 | images = images.filter(post_attachments__threads__tags__in=tags) | |
|
31 | return images.order_by('?')[:count] | |
|
32 | ||
|
22 | 33 | |
|
23 | 34 | class Attachment(models.Model): |
|
24 | 35 | objects = AttachmentManager() |
@@ -26,6 +37,7 class Attachment(models.Model): | |||
|
26 | 37 | file = models.FileField(upload_to=get_upload_filename) |
|
27 | 38 | mimetype = models.CharField(max_length=50) |
|
28 | 39 | hash = models.CharField(max_length=36) |
|
40 | alias = models.TextField(unique=True, null=True, blank=True) | |
|
29 | 41 | |
|
30 | 42 | def get_view(self): |
|
31 | 43 | file_viewer = None |
@@ -40,3 +52,27 class Attachment(models.Model): | |||
|
40 | 52 | |
|
41 | 53 | def __str__(self): |
|
42 | 54 | return self.file.url |
|
55 | ||
|
56 | def get_random_associated_post(self): | |
|
57 | posts = boards.models.Post.objects.filter(attachments__in=[self]) | |
|
58 | return posts.order_by('?').first() | |
|
59 | ||
|
60 | @cached_result() | |
|
61 | def get_size(self): | |
|
62 | if self.mimetype in FILE_TYPES_IMAGE: | |
|
63 | return get_image_dimensions(self.file) | |
|
64 | else: | |
|
65 | return 200, 150 | |
|
66 | ||
|
67 | def get_thumb_url(self): | |
|
68 | split = self.file.url.rsplit('.', 1) | |
|
69 | w, h = 200, 150 | |
|
70 | return '%s.%sx%s.%s' % (split[0], w, h, split[1]) | |
|
71 | ||
|
72 | @cached_result() | |
|
73 | def get_preview_size(self): | |
|
74 | if self.mimetype in FILE_TYPES_IMAGE: | |
|
75 | preview_path = self.file.path.replace('.', '.200x150.') | |
|
76 | return get_image_dimensions(preview_path) | |
|
77 | else: | |
|
78 | return 200, 150 |
@@ -1,3 +1,4 | |||
|
1 | from django.core.files.images import get_image_dimensions | |
|
1 | 2 | from django.template.defaultfilters import filesizeformat |
|
2 | 3 | from django.contrib.staticfiles.templatetags.staticfiles import static |
|
3 | 4 | |
@@ -15,6 +16,13 FILE_TYPES_AUDIO = ( | |||
|
15 | 16 | 'mp3', |
|
16 | 17 | 'opus', |
|
17 | 18 | ) |
|
19 | FILE_TYPES_IMAGE = ( | |
|
20 | 'jpeg', | |
|
21 | 'jpg', | |
|
22 | 'png', | |
|
23 | 'bmp', | |
|
24 | 'gif', | |
|
25 | ) | |
|
18 | 26 | |
|
19 | 27 | PLAIN_FILE_FORMATS = { |
|
20 | 28 | 'pdf': 'pdf', |
@@ -22,6 +30,9 PLAIN_FILE_FORMATS = { | |||
|
22 | 30 | 'txt': 'txt', |
|
23 | 31 | } |
|
24 | 32 | |
|
33 | CSS_CLASS_IMAGE = 'image' | |
|
34 | CSS_CLASS_THUMB = 'thumb' | |
|
35 | ||
|
25 | 36 | |
|
26 | 37 | def get_viewers(): |
|
27 | 38 | return AbstractViewer.__subclasses__() |
@@ -83,3 +94,35 class SvgViewer(AbstractViewer): | |||
|
83 | 94 | return '<a class="thumb" href="{}">'\ |
|
84 | 95 | '<img class="post-image-preview" width="200" height="150" src="{}" />'\ |
|
85 | 96 | '</a>'.format(self.file.url, self.file.url) |
|
97 | ||
|
98 | ||
|
99 | class ImageViewer(AbstractViewer): | |
|
100 | @staticmethod | |
|
101 | def supports(file_type): | |
|
102 | return file_type in FILE_TYPES_IMAGE | |
|
103 | ||
|
104 | def get_format_view(self): | |
|
105 | metadata = '{}, {}'.format(self.file.name.split('.')[-1], | |
|
106 | filesizeformat(self.file.size)) | |
|
107 | width, height = get_image_dimensions(self.file.file) | |
|
108 | preview_path = self.file.path.replace('.', '.200x150.') | |
|
109 | pre_width, pre_height = get_image_dimensions(preview_path) | |
|
110 | ||
|
111 | split = self.file.url.rsplit('.', 1) | |
|
112 | w, h = 200, 150 | |
|
113 | thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1]) | |
|
114 | ||
|
115 | return '<a class="{}" href="{full}">' \ | |
|
116 | '<img class="post-image-preview"' \ | |
|
117 | ' src="{}"' \ | |
|
118 | ' width="{}"' \ | |
|
119 | ' height="{}"' \ | |
|
120 | ' data-width="{}"' \ | |
|
121 | ' data-height="{}" />' \ | |
|
122 | '</a>' \ | |
|
123 | .format(CSS_CLASS_THUMB, | |
|
124 | thumb_url, | |
|
125 | str(pre_width), | |
|
126 | str(pre_height), str(width), str(height), | |
|
127 | full=self.file.url, image_meta=metadata) | |
|
128 |
@@ -3,7 +3,8 import uuid | |||
|
3 | 3 | import re |
|
4 | 4 | from boards import settings |
|
5 | 5 | from boards.abstracts.tripcode import Tripcode |
|
6 |
from boards.models import |
|
|
6 | from boards.models import Attachment, KeyPair, GlobalId | |
|
7 | from boards.models.attachment import FILE_TYPES_IMAGE | |
|
7 | 8 | from boards.models.base import Viewable |
|
8 | 9 | from boards.models.post.export import get_exporter, DIFF_TYPE_JSON |
|
9 | 10 | from boards.models.post.manager import PostManager |
@@ -27,8 +28,6 APP_LABEL_BOARDS = 'boards' | |||
|
27 | 28 | |
|
28 | 29 | BAN_REASON_AUTO = 'Auto' |
|
29 | 30 | |
|
30 | IMAGE_THUMB_SIZE = (200, 150) | |
|
31 | ||
|
32 | 31 | TITLE_MAX_LENGTH = 200 |
|
33 | 32 | |
|
34 | 33 | REGEX_REPLY = re.compile(r'\[post\](\d+)\[/post\]') |
@@ -74,8 +73,6 class Post(models.Model, Viewable): | |||
|
74 | 73 | text = TextField(blank=True, null=True) |
|
75 | 74 | _text_rendered = TextField(blank=True, null=True, editable=False) |
|
76 | 75 | |
|
77 | images = models.ManyToManyField(PostImage, null=True, blank=True, | |
|
78 | related_name='post_images', db_index=True) | |
|
79 | 76 | attachments = models.ManyToManyField(Attachment, null=True, blank=True, |
|
80 | 77 | related_name='attachment_posts') |
|
81 | 78 | |
@@ -212,8 +209,8 class Post(models.Model, Viewable): | |||
|
212 | 209 | def get_search_view(self, *args, **kwargs): |
|
213 | 210 | return self.get_view(need_op_data=True, *args, **kwargs) |
|
214 | 211 | |
|
215 |
def get_first_image(self) -> |
|
|
216 |
return self. |
|
|
212 | def get_first_image(self) -> Attachment: | |
|
213 | return self.attachments.filter(mimetype__in=FILE_TYPES_IMAGE).earliest('id') | |
|
217 | 214 | |
|
218 | 215 | def set_global_id(self, key_pair=None): |
|
219 | 216 | """ |
@@ -11,19 +11,11 import boards | |||
|
11 | 11 | |
|
12 | 12 | from boards.models.user import Ban |
|
13 | 13 | from boards.mdx_neboard import Parser |
|
14 |
from boards.models import |
|
|
14 | from boards.models import Attachment | |
|
15 | 15 | from boards import utils |
|
16 | 16 | |
|
17 | 17 | __author__ = 'neko259' |
|
18 | 18 | |
|
19 | IMAGE_TYPES = ( | |
|
20 | 'jpeg', | |
|
21 | 'jpg', | |
|
22 | 'png', | |
|
23 | 'bmp', | |
|
24 | 'gif', | |
|
25 | ) | |
|
26 | ||
|
27 | 19 | POSTS_PER_DAY_RANGE = 7 |
|
28 | 20 | NO_IP = '0.0.0.0' |
|
29 | 21 | |
@@ -186,8 +178,4 class PostManager(models.Manager): | |||
|
186 | 178 | list(map(thread.tags.add, tags)) |
|
187 | 179 | |
|
188 | 180 | def _add_file_to_post(self, file, post): |
|
189 | file_type = file.name.split('.')[-1].lower() | |
|
190 | if file_type in IMAGE_TYPES: | |
|
191 | post.images.add(PostImage.objects.create_with_hash(file)) | |
|
192 | else: | |
|
193 | 181 |
|
@@ -72,16 +72,11 class SyncManager: | |||
|
72 | 72 | |
|
73 | 73 | global_id = post.global_id |
|
74 | 74 | |
|
75 | images = post.images.all() | |
|
76 | 75 | attachments = post.attachments.all() |
|
77 | 76 | if global_id.content: |
|
78 | 77 | model.append(et.fromstring(global_id.content)) |
|
79 |
if |
|
|
78 | if len(attachments) > 0: | |
|
80 | 79 | attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS) |
|
81 | for image in images: | |
|
82 | SyncManager._attachment_to_xml( | |
|
83 | None, attachment_refs, image.image.file, | |
|
84 | image.hash, image.image.url) | |
|
85 | 80 | for file in attachments: |
|
86 | 81 | SyncManager._attachment_to_xml( |
|
87 | 82 | None, attachment_refs, file.file.file, |
@@ -116,14 +111,10 class SyncManager: | |||
|
116 | 111 | tripcode = et.SubElement(content_tag, TAG_TRIPCODE) |
|
117 | 112 | tripcode.text = post.tripcode |
|
118 | 113 | |
|
119 |
if |
|
|
114 | if len(attachments) > 0: | |
|
120 | 115 | attachments_tag = et.SubElement(content_tag, TAG_ATTACHMENTS) |
|
121 | 116 | attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS) |
|
122 | 117 | |
|
123 | for image in images: | |
|
124 | SyncManager._attachment_to_xml( | |
|
125 | attachments_tag, attachment_refs, image.image.file, | |
|
126 | image.hash, image.image.url) | |
|
127 | 118 | for file in attachments: |
|
128 | 119 | SyncManager._attachment_to_xml( |
|
129 | 120 | attachments_tag, attachment_refs, file.file.file, |
@@ -1,10 +1,11 | |||
|
1 | 1 | import hashlib |
|
2 | from boards.models.attachment import FILE_TYPES_IMAGE | |
|
2 | 3 | from django.template.loader import render_to_string |
|
3 | 4 | from django.db import models |
|
4 | 5 | from django.db.models import Count |
|
5 | 6 | from django.core.urlresolvers import reverse |
|
6 | 7 | |
|
7 |
from boards.models import |
|
|
8 | from boards.models import Attachment | |
|
8 | 9 | from boards.models.base import Viewable |
|
9 | 10 | from boards.models.thread import STATUS_ACTIVE, STATUS_BUMPLIMIT, STATUS_ARCHIVE |
|
10 | 11 | from boards.utils import cached_result |
@@ -107,8 +108,9 class Tag(models.Model, Viewable): | |||
|
107 | 108 | return self.description |
|
108 | 109 | |
|
109 | 110 | def get_random_image_post(self, status=[STATUS_ACTIVE, STATUS_BUMPLIMIT]): |
|
110 |
posts = boards.models.Post.objects. |
|
|
111 | 'images')).filter(images_count__gt=0, threads__tags__in=[self]) | |
|
111 | posts = boards.models.Post.objects.filter(attachments__mimetype__in=FILE_TYPES_IMAGE)\ | |
|
112 | .annotate(images_count=Count( | |
|
113 | 'attachments')).filter(images_count__gt=0, threads__tags__in=[self]) | |
|
112 | 114 | if status is not None: |
|
113 | 115 | posts = posts.filter(thread__status__in=status) |
|
114 | 116 | return posts.order_by('?').first() |
@@ -143,5 +145,6 class Tag(models.Model, Viewable): | |||
|
143 | 145 | return self.children |
|
144 | 146 | |
|
145 | 147 | def get_images(self): |
|
146 | return PostImage.objects.filter(post_images__thread__tags__in=[self])\ | |
|
147 | .order_by('-post_images__pub_time') No newline at end of file | |
|
148 | return Attachment.objects.filter( | |
|
149 | post_attachments__thread__tags__in=[self]).filter( | |
|
150 | mimetype__in=FILE_TYPES_IMAGE).order_by('-post_images__pub_time') No newline at end of file |
@@ -1,5 +1,6 | |||
|
1 | 1 | import logging |
|
2 | 2 | from adjacent import Client |
|
3 | from boards.models.attachment import FILE_TYPES_IMAGE | |
|
3 | 4 | |
|
4 | 5 | from django.db.models import Count, Sum, QuerySet, Q |
|
5 | 6 | from django.utils import timezone |
@@ -138,8 +139,10 class Thread(models.Model): | |||
|
138 | 139 | |
|
139 | 140 | @cached_result(key_method=_get_cache_key) |
|
140 | 141 | def get_images_count(self) -> int: |
|
141 |
return self.get_replies(). |
|
|
142 | 'images')).aggregate(Sum('images_count'))['images_count__sum'] | |
|
142 | return self.get_replies().filter( | |
|
143 | attachments__mimetype__in=FILE_TYPES_IMAGE)\ | |
|
144 | .annotate(images_count=Count( | |
|
145 | 'attachments')).aggregate(Sum('images_count'))['images_count__sum'] | |
|
143 | 146 | |
|
144 | 147 | def can_bump(self) -> bool: |
|
145 | 148 | """ |
@@ -181,7 +184,7 class Thread(models.Model): | |||
|
181 | 184 | """ |
|
182 | 185 | |
|
183 | 186 | query = self.multi_replies.order_by('pub_time').prefetch_related( |
|
184 |
|
|
|
187 | 'thread', 'attachments') | |
|
185 | 188 | if view_fields_only: |
|
186 | 189 | query = query.defer('poster_ip') |
|
187 | 190 | return query |
@@ -193,9 +196,9 class Thread(models.Model): | |||
|
193 | 196 | """ |
|
194 | 197 | Gets replies that have at least one image attached |
|
195 | 198 | """ |
|
196 | ||
|
197 | return self.get_replies(view_fields_only).annotate(images_count=Count( | |
|
198 |
' |
|
|
199 | return self.get_replies(view_fields_only).filter( | |
|
200 | attachments__mimetype__in=FILE_TYPES_IMAGE).annotate(images_count=Count( | |
|
201 | 'attachments')).filter(images_count__gt=0) | |
|
199 | 202 | |
|
200 | 203 | def get_opening_post(self, only_id=False) -> Post: |
|
201 | 204 | """ |
@@ -1,7 +1,9 | |||
|
1 | 1 | import re |
|
2 | from boards import thumbs | |
|
2 | 3 | from boards.mdx_neboard import get_parser |
|
3 | 4 | |
|
4 | from boards.models import Post, GlobalId | |
|
5 | from boards.models import Post, GlobalId, Attachment | |
|
6 | from boards.models.attachment.viewers import FILE_TYPES_IMAGE | |
|
5 | 7 | from boards.models.post import REGEX_NOTIFICATION, REGEX_REPLY,\ |
|
6 | 8 | REGEX_GLOBAL_REPLY |
|
7 | 9 | from boards.models.post.manager import post_import_deps |
@@ -12,6 +14,9 from django.dispatch import receiver | |||
|
12 | 14 | from django.utils import timezone |
|
13 | 15 | |
|
14 | 16 | |
|
17 | THUMB_SIZES = ((200, 150),) | |
|
18 | ||
|
19 | ||
|
15 | 20 | @receiver(post_save, sender=Post) |
|
16 | 21 | def connect_replies(instance, **kwargs): |
|
17 | 22 | for reply_number in re.finditer(REGEX_REPLY, instance.get_raw_text()): |
@@ -90,3 +95,22 def update_thread_on_delete(instance, ** | |||
|
90 | 95 | def delete_global_id(instance, **kwargs): |
|
91 | 96 | if instance.global_id and instance.global_id.id: |
|
92 | 97 | instance.global_id.delete() |
|
98 | ||
|
99 | ||
|
100 | @receiver(post_save, sender=Attachment) | |
|
101 | def generate_thumb(instance, **kwargs): | |
|
102 | if instance.mimetype in FILE_TYPES_IMAGE: | |
|
103 | for size in THUMB_SIZES: | |
|
104 | (w, h) = size | |
|
105 | split = instance.file.name.rsplit('.', 1) | |
|
106 | thumb_name = '%s.%sx%s.%s' % (split[0], w, h, split[1]) | |
|
107 | ||
|
108 | if not instance.file.storage.exists(thumb_name): | |
|
109 | # you can use another thumbnailing function if you like | |
|
110 | thumb_content = thumbs.generate_thumb(instance.file, size, split[1]) | |
|
111 | ||
|
112 | thumb_name_ = instance.file.storage.save(thumb_name, thumb_content) | |
|
113 | ||
|
114 | if not thumb_name == thumb_name_: | |
|
115 | raise ValueError( | |
|
116 | 'There is already a file named %s' % thumb_name_) |
@@ -40,11 +40,11 | |||
|
40 | 40 | <div class="tag_info" style="border-bottom: solid .5ex #{{ tag.get_color }}"> |
|
41 | 41 | {% if random_image_post %} |
|
42 | 42 | <div class="tag-image"> |
|
43 |
{% with image=random_image_post. |
|
|
43 | {% with image=random_image_post.get_first_image %} | |
|
44 | 44 | <a href="{{ random_image_post.get_absolute_url }}"><img |
|
45 |
src="{{ image. |
|
|
46 |
width="{{ image. |
|
|
47 |
height="{{ image. |
|
|
45 | src="{{ image.get_thumb_url }}" | |
|
46 | width="{{ image.get_preview_size.0 }}" | |
|
47 | height="{{ image.get_preview_size.1 }}" | |
|
48 | 48 | alt="{{ random_image_post.id }}"/></a> |
|
49 | 49 | {% endwith %} |
|
50 | 50 | </div> |
@@ -26,7 +26,7 | |||
|
26 | 26 | {% endif %} |
|
27 | 27 | |
|
28 | 28 | {% for image in image_aliases %} |
|
29 |
|
|
|
29 | <div>{{ image.alias }}: {{ image.get_view|safe }}</div> | |
|
30 | 30 | {% endfor %} |
|
31 | 31 | </div> |
|
32 | 32 |
@@ -23,7 +23,7 | |||
|
23 | 23 | {% autoescape off %} |
|
24 | 24 | {{ image.get_view }} |
|
25 | 25 | <div class="gallery_image_metadata"> |
|
26 |
{{ image. |
|
|
26 | {{ image.get_size.0 }}x{{ image.get_size.1 }} | |
|
27 | 27 | {% image_actions image.image.url request.get_host %} |
|
28 | 28 | <br /> |
|
29 | 29 | <a href="{{ post.get_absolute_url }}">>>{{ post.id }}</a> |
@@ -2,6 +2,7 | |||
|
2 | 2 | This module contains helper functions and helper classes. |
|
3 | 3 | """ |
|
4 | 4 | import hashlib |
|
5 | from boards.abstracts.constants import FILE_DIRECTORY | |
|
5 | 6 | from random import random |
|
6 | 7 | import time |
|
7 | 8 | import hmac |
@@ -29,10 +30,6 SETTING_ANON_MODE = 'AnonymousMode' | |||
|
29 | 30 | |
|
30 | 31 | ANON_IP = '127.0.0.1' |
|
31 | 32 | |
|
32 | UPLOAD_DIRS ={ | |
|
33 | 'PostImage': 'images/', | |
|
34 | 'Attachment': 'files/', | |
|
35 | } | |
|
36 | 33 | FILE_EXTENSION_DELIMITER = '.' |
|
37 | 34 | |
|
38 | 35 | |
@@ -136,9 +133,7 def get_upload_filename(model_instance, | |||
|
136 | 133 | str(int(random() * 1000)), |
|
137 | 134 | extension) |
|
138 | 135 | |
|
139 | directory = UPLOAD_DIRS[type(model_instance).__name__] | |
|
140 | ||
|
141 | return os.path.join(directory, new_name) | |
|
136 | return os.path.join(FILE_DIRECTORY, new_name) | |
|
142 | 137 | |
|
143 | 138 | |
|
144 | 139 | def get_file_mimetype(file) -> str: |
@@ -5,7 +5,6 from django.core.paginator import EmptyP | |||
|
5 | 5 | from django.db import transaction |
|
6 | 6 | from django.http import Http404 |
|
7 | 7 | from django.shortcuts import render, redirect |
|
8 | import requests | |
|
9 | 8 | from django.utils.decorators import method_decorator |
|
10 | 9 | from django.views.decorators.csrf import csrf_protect |
|
11 | 10 | |
@@ -13,7 +12,7 from boards import utils, settings | |||
|
13 | 12 | from boards.abstracts.paginator import get_paginator |
|
14 | 13 | from boards.abstracts.settingsmanager import get_settings_manager |
|
15 | 14 | from boards.forms import ThreadForm, PlainErrorList |
|
16 |
from boards.models import Post, Thread, Ban, |
|
|
15 | from boards.models import Post, Thread, Ban, Banner | |
|
17 | 16 | from boards.views.banned import BannedView |
|
18 | 17 | from boards.views.base import BaseBoardView, CONTEXT_FORM |
|
19 | 18 | from boards.views.posting_mixin import PostMixin |
@@ -1,7 +1,7 | |||
|
1 | 1 | from django.shortcuts import render |
|
2 | 2 | from django.views.generic import View |
|
3 | 3 | |
|
4 |
from boards.models import |
|
|
4 | from boards.models import Attachment | |
|
5 | 5 | |
|
6 | 6 | __author__ = 'neko259' |
|
7 | 7 | |
@@ -16,7 +16,7 class RandomImageView(View): | |||
|
16 | 16 | def get(self, request): |
|
17 | 17 | params = dict() |
|
18 | 18 | |
|
19 |
params[CONTEXT_IMAGES] = |
|
|
19 | params[CONTEXT_IMAGES] = Attachment.objects.get_random_images( | |
|
20 | 20 | RANDOM_POST_COUNT) |
|
21 | 21 | |
|
22 | 22 | return render(request, TEMPLATE, params) |
@@ -8,7 +8,7 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 |
|
|
11 | from boards.models import Attachment | |
|
12 | 12 | |
|
13 | 13 | FORM_THEME = 'theme' |
|
14 | 14 | FORM_USERNAME = 'username' |
@@ -43,7 +43,7 class SettingsView(BaseBoardView): | |||
|
43 | 43 | |
|
44 | 44 | params[CONTEXT_FORM] = form |
|
45 | 45 | params[CONTEXT_HIDDEN_TAGS] = settings_manager.get_hidden_tags() |
|
46 |
params[CONTEXT_IMAGE_ALIASES] = |
|
|
46 | params[CONTEXT_IMAGE_ALIASES] = Attachment.objects.exclude(alias='').exclude(alias=None) | |
|
47 | 47 | |
|
48 | 48 | return render(request, TEMPLATE, params) |
|
49 | 49 |
@@ -3,8 +3,8 from django.core.urlresolvers import rev | |||
|
3 | 3 | |
|
4 | 4 | from boards.abstracts.settingsmanager import get_settings_manager, \ |
|
5 | 5 | SETTING_FAVORITE_TAGS, SETTING_HIDDEN_TAGS |
|
6 |
from boards.models import Tag |
|
|
7 |
from boards.views.all_threads import AllThreadsView |
|
|
6 | from boards.models import Tag | |
|
7 | from boards.views.all_threads import AllThreadsView | |
|
8 | 8 | from boards.views.mixins import DispatcherMixin, PARAMETER_METHOD |
|
9 | 9 | from boards.forms import ThreadForm, PlainErrorList |
|
10 | 10 |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now