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