##// END OF EJS Templates
Use UUID as a unique file name for uploads
neko259 -
r1767:56a71883 default
parent child Browse files
Show More
@@ -1,179 +1,177 b''
1 1 """
2 2 This module contains helper functions and helper classes.
3 3 """
4 4 import hashlib
5 import uuid
6
5 7 from boards.abstracts.constants import FILE_DIRECTORY
6 8 from random import random
7 9 import time
8 10 import hmac
9 11
10 12 from django.core.cache import cache
11 13 from django.db.models import Model
12 14 from django import forms
13 15 from django.template.defaultfilters import filesizeformat
14 16 from django.utils import timezone
15 17 from django.utils.translation import ugettext_lazy as _
16 18 import magic
17 19 import os
18 20
19 21 import boards
20 22 from boards.settings import get_bool
21 23 from neboard import settings
22 24
23 25 CACHE_KEY_DELIMITER = '_'
24 26
25 27 HTTP_FORWARDED = 'HTTP_X_FORWARDED_FOR'
26 28 META_REMOTE_ADDR = 'REMOTE_ADDR'
27 29
28 30 SETTING_MESSAGES = 'Messages'
29 31 SETTING_ANON_MODE = 'AnonymousMode'
30 32
31 33 ANON_IP = '127.0.0.1'
32 34
33 35 FILE_EXTENSION_DELIMITER = '.'
34 36
35 37 KNOWN_DOMAINS = (
36 38 'org.ru',
37 39 )
38 40
39 41
40 42 def is_anonymous_mode():
41 43 return get_bool(SETTING_MESSAGES, SETTING_ANON_MODE)
42 44
43 45
44 46 def get_client_ip(request):
45 47 if is_anonymous_mode():
46 48 ip = ANON_IP
47 49 else:
48 50 x_forwarded_for = request.META.get(HTTP_FORWARDED)
49 51 if x_forwarded_for:
50 52 ip = x_forwarded_for.split(',')[-1].strip()
51 53 else:
52 54 ip = request.META.get(META_REMOTE_ADDR)
53 55 return ip
54 56
55 57
56 58 # TODO The output format is not epoch because it includes microseconds
57 59 def datetime_to_epoch(datetime):
58 60 return int(time.mktime(timezone.localtime(
59 61 datetime,timezone.get_current_timezone()).timetuple())
60 62 * 1000000 + datetime.microsecond)
61 63
62 64
63 65 def get_websocket_token(user_id='', timestamp=''):
64 66 """
65 67 Create token to validate information provided by new connection.
66 68 """
67 69
68 70 sign = hmac.new(settings.CENTRIFUGE_PROJECT_SECRET.encode())
69 71 sign.update(settings.CENTRIFUGE_PROJECT_ID.encode())
70 72 sign.update(user_id.encode())
71 73 sign.update(timestamp.encode())
72 74 token = sign.hexdigest()
73 75
74 76 return token
75 77
76 78
77 79 # TODO Test this carefully
78 80 def cached_result(key_method=None):
79 81 """
80 82 Caches method result in the Django's cache system, persisted by object name,
81 83 object name, model id if object is a Django model, args and kwargs if any.
82 84 """
83 85 def _cached_result(function):
84 86 def inner_func(obj, *args, **kwargs):
85 87 cache_key_params = [obj.__class__.__name__, function.__name__]
86 88
87 89 cache_key_params += args
88 90 for key, value in kwargs:
89 91 cache_key_params.append(key + ':' + value)
90 92
91 93 if isinstance(obj, Model):
92 94 cache_key_params.append(str(obj.id))
93 95
94 96 if key_method is not None:
95 97 cache_key_params += [str(arg) for arg in key_method(obj)]
96 98
97 99 cache_key = CACHE_KEY_DELIMITER.join(cache_key_params)
98 100
99 101 persisted_result = cache.get(cache_key)
100 102 if persisted_result is not None:
101 103 result = persisted_result
102 104 else:
103 105 result = function(obj, *args, **kwargs)
104 106 if result is not None:
105 107 cache.set(cache_key, result)
106 108
107 109 return result
108 110
109 111 return inner_func
110 112 return _cached_result
111 113
112 114
113 115 def get_file_hash(file) -> str:
114 116 md5 = hashlib.md5()
115 117 for chunk in file.chunks():
116 118 md5.update(chunk)
117 119 return md5.hexdigest()
118 120
119 121
120 122 def validate_file_size(size: int):
121 123 max_size = boards.settings.get_int('Forms', 'MaxFileSize')
122 124 if size > max_size:
123 125 raise forms.ValidationError(
124 126 _('File must be less than %s but is %s.')
125 127 % (filesizeformat(max_size), filesizeformat(size)))
126 128
127 129
128 130 def get_extension(filename):
129 131 return filename.split(FILE_EXTENSION_DELIMITER)[-1:][0]
130 132
131 133
132 134 def get_upload_filename(model_instance, old_filename):
133 # TODO Use something other than random number in file name
134 135 extension = get_extension(old_filename)
135 new_name = '{}{}.{}'.format(
136 str(int(time.mktime(time.gmtime()))),
137 str(int(random() * 1000)),
138 extension)
136 new_name = '{}.{}'.format(uuid.uuid4(), extension)
139 137
140 138 return os.path.join(FILE_DIRECTORY, new_name)
141 139
142 140
143 141 def get_file_mimetype(file) -> str:
144 142 file_type = magic.from_buffer(file.chunks().__next__(), mime=True)
145 143 if file_type is None:
146 144 file_type = 'application/octet-stream'
147 145 elif type(file_type) == bytes:
148 146 file_type = file_type.decode()
149 147 return file_type
150 148
151 149
152 150 def get_domain(url: str) -> str:
153 151 """
154 152 Gets domain from an URL with random number of domain levels.
155 153 """
156 154 domain_parts = url.split('/')
157 155 if len(domain_parts) >= 2:
158 156 full_domain = domain_parts[2]
159 157 else:
160 158 full_domain = ''
161 159
162 160 result = full_domain
163 161 if full_domain:
164 162 levels = full_domain.split('.')
165 163 if len(levels) >= 2:
166 164 top = levels[-1]
167 165 second = levels[-2]
168 166
169 167 has_third_level = len(levels) > 2
170 168 if has_third_level:
171 169 third = levels[-3]
172 170
173 171 if has_third_level and ('{}.{}'.format(second, top) in KNOWN_DOMAINS):
174 172 result = '{}.{}.{}'.format(third, second, top)
175 173 else:
176 174 result = '{}.{}'.format(second, top)
177 175
178 176 return result
179 177
General Comments 0
You need to be logged in to leave comments. Login now