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