##// END OF EJS Templates
Fixed posting a message without sticker
neko259 -
r1938:42e6fbb6 default
parent child Browse files
Show More
@@ -1,168 +1,171 b''
1 from itertools import zip_longest
1 from itertools import zip_longest
2
2
3 import boards
3 import boards
4 from boards.models import STATUS_ARCHIVE
4 from boards.models import STATUS_ARCHIVE
5 from django.core.files.images import get_image_dimensions
5 from django.core.files.images import get_image_dimensions
6 from django.db import models
6 from django.db import models
7
7
8 from boards import utils
8 from boards import utils
9 from boards.models.attachment.viewers import get_viewers, AbstractViewer, \
9 from boards.models.attachment.viewers import get_viewers, AbstractViewer, \
10 FILE_TYPES_IMAGE
10 FILE_TYPES_IMAGE
11 from boards.utils import get_upload_filename, get_extension, cached_result, \
11 from boards.utils import get_upload_filename, get_extension, cached_result, \
12 get_file_mimetype
12 get_file_mimetype
13
13
14
14
15 class AttachmentManager(models.Manager):
15 class AttachmentManager(models.Manager):
16 def create_with_hash(self, file):
16 def create_with_hash(self, file):
17 file_hash = utils.get_file_hash(file)
17 file_hash = utils.get_file_hash(file)
18 attachment = self.get_existing_duplicate(file_hash, file)
18 attachment = self.get_existing_duplicate(file_hash, file)
19 if not attachment:
19 if not attachment:
20 file_type = get_file_mimetype(file)
20 file_type = get_file_mimetype(file)
21 attachment = self.create(file=file, mimetype=file_type,
21 attachment = self.create(file=file, mimetype=file_type,
22 hash=file_hash)
22 hash=file_hash)
23
23
24 return attachment
24 return attachment
25
25
26 def create_from_url(self, url):
26 def create_from_url(self, url):
27 existing = self.filter(url=url)
27 existing = self.filter(url=url)
28 if len(existing) > 0:
28 if len(existing) > 0:
29 attachment = existing[0]
29 attachment = existing[0]
30 else:
30 else:
31 attachment = self.create(url=url)
31 attachment = self.create(url=url)
32 return attachment
32 return attachment
33
33
34 def get_random_images(self, count, tags=None):
34 def get_random_images(self, count, tags=None):
35 images = self.filter(mimetype__in=FILE_TYPES_IMAGE).exclude(
35 images = self.filter(mimetype__in=FILE_TYPES_IMAGE).exclude(
36 attachment_posts__thread__status=STATUS_ARCHIVE)
36 attachment_posts__thread__status=STATUS_ARCHIVE)
37 if tags is not None:
37 if tags is not None:
38 images = images.filter(attachment_posts__threads__tags__in=tags)
38 images = images.filter(attachment_posts__threads__tags__in=tags)
39 return images.order_by('?')[:count]
39 return images.order_by('?')[:count]
40
40
41 def get_existing_duplicate(self, file_hash, file):
41 def get_existing_duplicate(self, file_hash, file):
42 """
42 """
43 Gets an attachment with the same file if one exists.
43 Gets an attachment with the same file if one exists.
44 """
44 """
45 existing = self.filter(hash=file_hash)
45 existing = self.filter(hash=file_hash)
46 attachment = None
46 attachment = None
47 for existing_attachment in existing:
47 for existing_attachment in existing:
48 existing_file = existing_attachment.file
48 existing_file = existing_attachment.file
49
49
50 file_chunks = file.chunks()
50 file_chunks = file.chunks()
51 existing_file_chunks = existing_file.chunks()
51 existing_file_chunks = existing_file.chunks()
52
52
53 if self._compare_chunks(file_chunks, existing_file_chunks):
53 if self._compare_chunks(file_chunks, existing_file_chunks):
54 attachment = existing_attachment
54 attachment = existing_attachment
55 return attachment
55 return attachment
56
56
57 def get_by_alias(self, name):
57 def get_by_alias(self, name):
58 try:
58 return AttachmentSticker.objects.get(name=name).attachment
59 return AttachmentSticker.objects.get(name=name).attachment
60 except AttachmentSticker.DoesNotExist:
61 return None
59
62
60 def _compare_chunks(self, chunks1, chunks2):
63 def _compare_chunks(self, chunks1, chunks2):
61 """
64 """
62 Compares 2 chunks of different sizes (e.g. first chunk array contains
65 Compares 2 chunks of different sizes (e.g. first chunk array contains
63 all data in 1 chunk, and other one -- in a multiple of smaller ones.
66 all data in 1 chunk, and other one -- in a multiple of smaller ones.
64 """
67 """
65 equal = True
68 equal = True
66
69
67 position1 = 0
70 position1 = 0
68 position2 = 0
71 position2 = 0
69 chunk1 = None
72 chunk1 = None
70 chunk2 = None
73 chunk2 = None
71 chunk1ended = False
74 chunk1ended = False
72 chunk2ended = False
75 chunk2ended = False
73 while True:
76 while True:
74 if not chunk1 or len(chunk1) <= position1:
77 if not chunk1 or len(chunk1) <= position1:
75 try:
78 try:
76 chunk1 = chunks1.__next__()
79 chunk1 = chunks1.__next__()
77 position1 = 0
80 position1 = 0
78 except StopIteration:
81 except StopIteration:
79 chunk1ended = True
82 chunk1ended = True
80 if not chunk2 or len(chunk2) <= position2:
83 if not chunk2 or len(chunk2) <= position2:
81 try:
84 try:
82 chunk2 = chunks2.__next__()
85 chunk2 = chunks2.__next__()
83 position2 = 0
86 position2 = 0
84 except StopIteration:
87 except StopIteration:
85 chunk2ended = True
88 chunk2ended = True
86
89
87 if chunk1ended and chunk2ended:
90 if chunk1ended and chunk2ended:
88 # Same size chunksm checked for equality previously
91 # Same size chunksm checked for equality previously
89 break
92 break
90 elif chunk1ended or chunk2ended:
93 elif chunk1ended or chunk2ended:
91 # Different size chunks, not equal
94 # Different size chunks, not equal
92 equal = False
95 equal = False
93 break
96 break
94 elif chunk1[position1] != chunk2[position2]:
97 elif chunk1[position1] != chunk2[position2]:
95 # Different bytes, not equal
98 # Different bytes, not equal
96 equal = False
99 equal = False
97 break
100 break
98 else:
101 else:
99 position1 += 1
102 position1 += 1
100 position2 += 1
103 position2 += 1
101 return equal
104 return equal
102
105
103
106
104 class Attachment(models.Model):
107 class Attachment(models.Model):
105 objects = AttachmentManager()
108 objects = AttachmentManager()
106
109
107 class Meta:
110 class Meta:
108 app_label = 'boards'
111 app_label = 'boards'
109 ordering = ('id',)
112 ordering = ('id',)
110
113
111 file = models.FileField(upload_to=get_upload_filename, null=True)
114 file = models.FileField(upload_to=get_upload_filename, null=True)
112 mimetype = models.CharField(max_length=200, null=True)
115 mimetype = models.CharField(max_length=200, null=True)
113 hash = models.CharField(max_length=36, null=True)
116 hash = models.CharField(max_length=36, null=True)
114 url = models.TextField(blank=True, default='')
117 url = models.TextField(blank=True, default='')
115
118
116 def get_view(self):
119 def get_view(self):
117 file_viewer = None
120 file_viewer = None
118 for viewer in get_viewers():
121 for viewer in get_viewers():
119 if viewer.supports(self.mimetype):
122 if viewer.supports(self.mimetype):
120 file_viewer = viewer
123 file_viewer = viewer
121 break
124 break
122 if file_viewer is None:
125 if file_viewer is None:
123 file_viewer = AbstractViewer
126 file_viewer = AbstractViewer
124
127
125 return file_viewer(self.file, self.mimetype, self.hash, self.url).get_view()
128 return file_viewer(self.file, self.mimetype, self.hash, self.url).get_view()
126
129
127 def __str__(self):
130 def __str__(self):
128 return self.url or self.file.url
131 return self.url or self.file.url
129
132
130 def get_random_associated_post(self):
133 def get_random_associated_post(self):
131 posts = boards.models.Post.objects.filter(attachments__in=[self])
134 posts = boards.models.Post.objects.filter(attachments__in=[self])
132 return posts.order_by('?').first()
135 return posts.order_by('?').first()
133
136
134 @cached_result()
137 @cached_result()
135 def get_size(self):
138 def get_size(self):
136 if self.file:
139 if self.file:
137 if self.mimetype in FILE_TYPES_IMAGE:
140 if self.mimetype in FILE_TYPES_IMAGE:
138 return get_image_dimensions(self.file)
141 return get_image_dimensions(self.file)
139 else:
142 else:
140 return 200, 150
143 return 200, 150
141
144
142 def get_thumb_url(self):
145 def get_thumb_url(self):
143 split = self.file.url.rsplit('.', 1)
146 split = self.file.url.rsplit('.', 1)
144 w, h = 200, 150
147 w, h = 200, 150
145 return '%s.%sx%s.%s' % (split[0], w, h, split[1])
148 return '%s.%sx%s.%s' % (split[0], w, h, split[1])
146
149
147 @cached_result()
150 @cached_result()
148 def get_preview_size(self):
151 def get_preview_size(self):
149 size = 200, 150
152 size = 200, 150
150 if self.mimetype in FILE_TYPES_IMAGE:
153 if self.mimetype in FILE_TYPES_IMAGE:
151 preview_path = self.file.path.replace('.', '.200x150.')
154 preview_path = self.file.path.replace('.', '.200x150.')
152 try:
155 try:
153 size = get_image_dimensions(preview_path)
156 size = get_image_dimensions(preview_path)
154 except Exception:
157 except Exception:
155 pass
158 pass
156
159
157 return size
160 return size
158
161
159 def is_internal(self):
162 def is_internal(self):
160 return self.url is None or len(self.url) == 0
163 return self.url is None or len(self.url) == 0
161
164
162
165
163 class AttachmentSticker(models.Model):
166 class AttachmentSticker(models.Model):
164 attachment = models.ForeignKey('Attachment')
167 attachment = models.ForeignKey('Attachment')
165 name = models.TextField(unique=True)
168 name = models.TextField(unique=True)
166
169
167 def __str__(self):
170 def __str__(self):
168 return self.name
171 return self.name
General Comments 0
You need to be logged in to leave comments. Login now