##// END OF EJS Templates
Added domain image for linux.org.ru, added ability to make images for third-level domains when it is an org.ru, com.ua, co.uk etc domain
neko259 -
r1724:70ff8482 default
parent child Browse files
Show More
1 NO CONTENT: new file 100644, binary diff hidden
@@ -1,192 +1,192 b''
1 1 import re
2 2
3 3 from django.contrib.staticfiles import finders
4 4 from django.contrib.staticfiles.templatetags.staticfiles import static
5 5 from django.core.files.images import get_image_dimensions
6 6 from django.template.defaultfilters import filesizeformat
7 7
8 from boards.utils import get_domain
8 9
9 REGEX_DOMAIN = re.compile(r'(\w+\.)*(\w+\.\w+)')
10 10
11 11 FILE_STUB_IMAGE = 'images/file.png'
12 12 FILE_STUB_URL = 'url'
13 13
14 14 FILE_TYPES_VIDEO = (
15 15 'webm',
16 16 'mp4',
17 17 'mpeg',
18 18 'ogv',
19 19 )
20 20 FILE_TYPE_SVG = 'svg'
21 21 FILE_TYPES_AUDIO = (
22 22 'ogg',
23 23 'mp3',
24 24 'opus',
25 25 )
26 26 FILE_TYPES_IMAGE = (
27 27 'jpeg',
28 28 'jpg',
29 29 'png',
30 30 'bmp',
31 31 'gif',
32 32 )
33 33
34 34 PLAIN_FILE_FORMATS = {
35 35 'pdf': 'pdf',
36 36 'djvu': 'djvu',
37 37 'txt': 'txt',
38 38 'tex': 'tex',
39 39 'xcf': 'xcf',
40 40 'zip': 'archive',
41 41 'tar': 'archive',
42 42 'gz': 'archive',
43 43 }
44 44
45 45 URL_PROTOCOLS = {
46 46 'magnet': 'magnet',
47 47 }
48 48
49 49 CSS_CLASS_IMAGE = 'image'
50 50 CSS_CLASS_THUMB = 'thumb'
51 51
52 52
53 53 def get_viewers():
54 54 return AbstractViewer.__subclasses__()
55 55
56 56
57 57 def get_static_dimensions(filename):
58 58 file_path = finders.find(filename)
59 59 return get_image_dimensions(file_path)
60 60
61 61
62 62 # TODO Move this to utils
63 63 def file_exists(filename):
64 64 return finders.find(filename) is not None
65 65
66 66
67 67 class AbstractViewer:
68 68 def __init__(self, file, file_type, hash, url):
69 69 self.file = file
70 70 self.file_type = file_type
71 71 self.hash = hash
72 72 self.url = url
73 73
74 74 @staticmethod
75 75 def supports(file_type):
76 76 return True
77 77
78 78 def get_view(self):
79 79 return '<div class="image">'\
80 80 '{}'\
81 81 '<div class="image-metadata"><a href="{}" download >{}, {}</a></div>'\
82 82 '</div>'.format(self.get_format_view(), self.file.url,
83 83 self.file_type, filesizeformat(self.file.size))
84 84
85 85 def get_format_view(self):
86 86 if self.file_type in PLAIN_FILE_FORMATS:
87 87 image = 'images/fileformats/{}.png'.format(
88 88 PLAIN_FILE_FORMATS[self.file_type])
89 89 else:
90 90 image = FILE_STUB_IMAGE
91 91
92 92 w, h = get_static_dimensions(image)
93 93
94 94 return '<a href="{}">'\
95 95 '<img class="url-image" src="{}" width="{}" height="{}"/>'\
96 96 '</a>'.format(self.file.url, static(image), w, h)
97 97
98 98
99 99 class VideoViewer(AbstractViewer):
100 100 @staticmethod
101 101 def supports(file_type):
102 102 return file_type in FILE_TYPES_VIDEO
103 103
104 104 def get_format_view(self):
105 105 return '<video width="200" height="150" controls src="{}"></video>'\
106 106 .format(self.file.url)
107 107
108 108
109 109 class AudioViewer(AbstractViewer):
110 110 @staticmethod
111 111 def supports(file_type):
112 112 return file_type in FILE_TYPES_AUDIO
113 113
114 114 def get_format_view(self):
115 115 return '<audio controls src="{}"></audio>'.format(self.file.url)
116 116
117 117
118 118 class SvgViewer(AbstractViewer):
119 119 @staticmethod
120 120 def supports(file_type):
121 121 return file_type == FILE_TYPE_SVG
122 122
123 123 def get_format_view(self):
124 124 return '<a class="thumb" href="{}">'\
125 125 '<img class="post-image-preview" width="200" height="150" src="{}" />'\
126 126 '</a>'.format(self.file.url, self.file.url)
127 127
128 128
129 129 class ImageViewer(AbstractViewer):
130 130 @staticmethod
131 131 def supports(file_type):
132 132 return file_type in FILE_TYPES_IMAGE
133 133
134 134 def get_format_view(self):
135 135 metadata = '{}, {}'.format(self.file.name.split('.')[-1],
136 136 filesizeformat(self.file.size))
137 137 width, height = get_image_dimensions(self.file.file)
138 138 preview_path = self.file.path.replace('.', '.200x150.')
139 139 pre_width, pre_height = get_image_dimensions(preview_path)
140 140
141 141 split = self.file.url.rsplit('.', 1)
142 142 w, h = 200, 150
143 143 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
144 144
145 145 return '<a class="{}" href="{full}">' \
146 146 '<img class="post-image-preview"' \
147 147 ' src="{}"' \
148 148 ' alt="{}"' \
149 149 ' width="{}"' \
150 150 ' height="{}"' \
151 151 ' data-width="{}"' \
152 152 ' data-height="{}" />' \
153 153 '</a>' \
154 154 .format(CSS_CLASS_THUMB,
155 155 thumb_url,
156 156 self.hash,
157 157 str(pre_width),
158 158 str(pre_height), str(width), str(height),
159 159 full=self.file.url, image_meta=metadata)
160 160
161 161
162 162 class UrlViewer(AbstractViewer):
163 163 @staticmethod
164 164 def supports(file_type):
165 165 return file_type is None
166 166
167 167 def get_view(self):
168 168 return '<div class="image">' \
169 169 '{}' \
170 170 '</div>'.format(self.get_format_view())
171 171
172 172 def get_format_view(self):
173 173 protocol = self.url.split('://')[0]
174 174 full_domain = self.url.split('/')[2]
175 domain = REGEX_DOMAIN.search(full_domain).group(2)
175 domain = get_domain(full_domain)
176 176
177 177 if protocol in URL_PROTOCOLS:
178 178 url_image_name = URL_PROTOCOLS.get(protocol)
179 179 else:
180 180 filename = 'images/domains/{}.png'.format(domain)
181 181 if file_exists(filename):
182 182 url_image_name = 'domains/' + domain
183 183 else:
184 184 url_image_name = FILE_STUB_URL
185 185
186 186 image_path = 'images/{}.png'.format(url_image_name)
187 187 image = static(image_path)
188 188 w, h = get_static_dimensions(image_path)
189 189
190 190 return '<a href="{}">' \
191 191 '<img class="url-image" src="{}" width="{}" height="{}"/>' \
192 192 '</a>'.format(self.url, image, w, h)
@@ -1,145 +1,170 b''
1 1 """
2 2 This module contains helper functions and helper classes.
3 3 """
4 4 import hashlib
5 5 from boards.abstracts.constants import FILE_DIRECTORY
6 6 from random import random
7 7 import time
8 8 import hmac
9 9
10 10 from django.core.cache import cache
11 11 from django.db.models import Model
12 12 from django import forms
13 13 from django.template.defaultfilters import filesizeformat
14 14 from django.utils import timezone
15 15 from django.utils.translation import ugettext_lazy as _
16 16 import magic
17 17 import os
18 18
19 19 import boards
20 20 from boards.settings import get_bool
21 21 from neboard import settings
22 22
23 23 CACHE_KEY_DELIMITER = '_'
24 24
25 25 HTTP_FORWARDED = 'HTTP_X_FORWARDED_FOR'
26 26 META_REMOTE_ADDR = 'REMOTE_ADDR'
27 27
28 28 SETTING_MESSAGES = 'Messages'
29 29 SETTING_ANON_MODE = 'AnonymousMode'
30 30
31 31 ANON_IP = '127.0.0.1'
32 32
33 33 FILE_EXTENSION_DELIMITER = '.'
34 34
35 KNOWN_DOMAINS = (
36 'org.ru',
37 )
38
35 39
36 40 def is_anonymous_mode():
37 41 return get_bool(SETTING_MESSAGES, SETTING_ANON_MODE)
38 42
39 43
40 44 def get_client_ip(request):
41 45 if is_anonymous_mode():
42 46 ip = ANON_IP
43 47 else:
44 48 x_forwarded_for = request.META.get(HTTP_FORWARDED)
45 49 if x_forwarded_for:
46 50 ip = x_forwarded_for.split(',')[-1].strip()
47 51 else:
48 52 ip = request.META.get(META_REMOTE_ADDR)
49 53 return ip
50 54
51 55
52 56 # TODO The output format is not epoch because it includes microseconds
53 57 def datetime_to_epoch(datetime):
54 58 return int(time.mktime(timezone.localtime(
55 59 datetime,timezone.get_current_timezone()).timetuple())
56 60 * 1000000 + datetime.microsecond)
57 61
58 62
59 63 def get_websocket_token(user_id='', timestamp=''):
60 64 """
61 65 Create token to validate information provided by new connection.
62 66 """
63 67
64 68 sign = hmac.new(settings.CENTRIFUGE_PROJECT_SECRET.encode())
65 69 sign.update(settings.CENTRIFUGE_PROJECT_ID.encode())
66 70 sign.update(user_id.encode())
67 71 sign.update(timestamp.encode())
68 72 token = sign.hexdigest()
69 73
70 74 return token
71 75
72 76
73 77 # TODO Test this carefully
74 78 def cached_result(key_method=None):
75 79 """
76 80 Caches method result in the Django's cache system, persisted by object name,
77 81 object name, model id if object is a Django model, args and kwargs if any.
78 82 """
79 83 def _cached_result(function):
80 84 def inner_func(obj, *args, **kwargs):
81 85 cache_key_params = [obj.__class__.__name__, function.__name__]
82 86
83 87 cache_key_params += args
84 88 for key, value in kwargs:
85 89 cache_key_params.append(key + ':' + value)
86 90
87 91 if isinstance(obj, Model):
88 92 cache_key_params.append(str(obj.id))
89 93
90 94 if key_method is not None:
91 95 cache_key_params += [str(arg) for arg in key_method(obj)]
92 96
93 97 cache_key = CACHE_KEY_DELIMITER.join(cache_key_params)
94 98
95 99 persisted_result = cache.get(cache_key)
96 100 if persisted_result is not None:
97 101 result = persisted_result
98 102 else:
99 103 result = function(obj, *args, **kwargs)
100 104 if result is not None:
101 105 cache.set(cache_key, result)
102 106
103 107 return result
104 108
105 109 return inner_func
106 110 return _cached_result
107 111
108 112
109 113 def get_file_hash(file) -> str:
110 114 md5 = hashlib.md5()
111 115 for chunk in file.chunks():
112 116 md5.update(chunk)
113 117 return md5.hexdigest()
114 118
115 119
116 120 def validate_file_size(size: int):
117 121 max_size = boards.settings.get_int('Forms', 'MaxFileSize')
118 122 if size > max_size:
119 123 raise forms.ValidationError(
120 124 _('File must be less than %s but is %s.')
121 125 % (filesizeformat(max_size), filesizeformat(size)))
122 126
123 127
124 128 def get_extension(filename):
125 129 return filename.split(FILE_EXTENSION_DELIMITER)[-1:][0]
126 130
127 131
128 132 def get_upload_filename(model_instance, old_filename):
129 133 # TODO Use something other than random number in file name
130 134 extension = get_extension(old_filename)
131 135 new_name = '{}{}.{}'.format(
132 136 str(int(time.mktime(time.gmtime()))),
133 137 str(int(random() * 1000)),
134 138 extension)
135 139
136 140 return os.path.join(FILE_DIRECTORY, new_name)
137 141
138 142
139 143 def get_file_mimetype(file) -> str:
140 144 file_type = magic.from_buffer(file.chunks().__next__(), mime=True)
141 145 if file_type is None:
142 146 file_type = 'application/octet-stream'
143 147 elif type(file_type) == bytes:
144 148 file_type = file_type.decode()
145 149 return file_type
150
151
152 def get_domain(url: str) -> str:
153 """
154 Gets domain from an URL with random number of domain levels.
155 """
156 levels = url.split('.')
157 top = levels[-1]
158 second = levels[-2]
159
160 has_third_level = len(levels) > 2
161 if has_third_level:
162 third = levels[-3]
163
164 if has_third_level and ('{}.{}'.format(second, top) in KNOWN_DOMAINS):
165 result = '{}.{}.{}'.format(third, second, top)
166 else:
167 result = '{}.{}'.format(second, top)
168
169 return result
170
General Comments 0
You need to be logged in to leave comments. Login now