##// END OF EJS Templates
Use python-magic to get file types
neko259 -
r1369:224c8f01 default
parent child Browse files
Show More
@@ -1,43 +1,46 b''
1 import magic
2
1 3 from django.db import models
2 4
3 5 from boards import utils
4 6 from boards.models.attachment.viewers import get_viewers, AbstractViewer
5 7 from boards.utils import get_upload_filename
6 8
7 9 FILES_DIRECTORY = 'files/'
8 10 FILE_EXTENSION_DELIMITER = '.'
9 11
10 12
11 13 class AttachmentManager(models.Manager):
12 14 def create_with_hash(self, file):
13 15 file_hash = utils.get_file_hash(file)
14 16 existing = self.filter(hash=file_hash)
15 17 if len(existing) > 0:
16 18 attachment = existing[0]
17 19 else:
18 file_type = file.name.split(FILE_EXTENSION_DELIMITER)[-1].lower()
20 file_type = magic.from_buffer(file.chunks().__next__(), mime=True)\
21 .decode().split('/')[-1]
19 22 attachment = Attachment.objects.create(
20 23 file=file, mimetype=file_type, hash=file_hash)
21 24
22 25 return attachment
23 26
24 27
25 28 class Attachment(models.Model):
26 29 objects = AttachmentManager()
27 30
28 31 file = models.FileField(upload_to=get_upload_filename)
29 32 mimetype = models.CharField(max_length=50)
30 33 hash = models.CharField(max_length=36)
31 34
32 35 def get_view(self):
33 36 file_viewer = None
34 37 for viewer in get_viewers():
35 38 if viewer.supports(self.mimetype):
36 39 file_viewer = viewer
37 40 break
38 41 if file_viewer is None:
39 42 file_viewer = AbstractViewer
40 43
41 44 return file_viewer(self.file, self.mimetype).get_view()
42 45
43 46
@@ -1,138 +1,142 b''
1 1 """
2 2 This module contains helper functions and helper classes.
3 3 """
4 4 import hashlib
5 5 from random import random
6 6 import time
7 7 import hmac
8 8
9 9 from django.core.cache import cache
10 10 from django.db.models import Model
11 11 from django import forms
12 12 from django.utils import timezone
13 13 from django.utils.translation import ugettext_lazy as _
14 14 from portage import os
15 15
16 16 import boards
17 17 from boards.settings import get_bool
18 18 from neboard import settings
19 19
20 20 CACHE_KEY_DELIMITER = '_'
21 21 PERMISSION_MODERATE = 'moderation'
22 22
23 23 HTTP_FORWARDED = 'HTTP_X_FORWARDED_FOR'
24 24 META_REMOTE_ADDR = 'REMOTE_ADDR'
25 25
26 26 SETTING_MESSAGES = 'Messages'
27 27 SETTING_ANON_MODE = 'AnonymousMode'
28 28
29 29 ANON_IP = '127.0.0.1'
30 30
31 31 UPLOAD_DIRS ={
32 32 'PostImage': 'images/',
33 33 'Attachment': 'files/',
34 34 }
35 35 FILE_EXTENSION_DELIMITER = '.'
36 36
37 37
38 38 def is_anonymous_mode():
39 39 return get_bool(SETTING_MESSAGES, SETTING_ANON_MODE)
40 40
41 41
42 42 def get_client_ip(request):
43 43 if is_anonymous_mode():
44 44 ip = ANON_IP
45 45 else:
46 46 x_forwarded_for = request.META.get(HTTP_FORWARDED)
47 47 if x_forwarded_for:
48 48 ip = x_forwarded_for.split(',')[-1].strip()
49 49 else:
50 50 ip = request.META.get(META_REMOTE_ADDR)
51 51 return ip
52 52
53 53
54 54 # TODO The output format is not epoch because it includes microseconds
55 55 def datetime_to_epoch(datetime):
56 56 return int(time.mktime(timezone.localtime(
57 57 datetime,timezone.get_current_timezone()).timetuple())
58 58 * 1000000 + datetime.microsecond)
59 59
60 60
61 61 def get_websocket_token(user_id='', timestamp=''):
62 62 """
63 63 Create token to validate information provided by new connection.
64 64 """
65 65
66 66 sign = hmac.new(settings.CENTRIFUGE_PROJECT_SECRET.encode())
67 67 sign.update(settings.CENTRIFUGE_PROJECT_ID.encode())
68 68 sign.update(user_id.encode())
69 69 sign.update(timestamp.encode())
70 70 token = sign.hexdigest()
71 71
72 72 return token
73 73
74 74
75 75 def cached_result(key_method=None):
76 76 """
77 77 Caches method result in the Django's cache system, persisted by object name,
78 78 object name and model id if object is a Django model.
79 79 """
80 80 def _cached_result(function):
81 81 def inner_func(obj, *args, **kwargs):
82 82 # TODO Include method arguments to the cache key
83 83 cache_key_params = [obj.__class__.__name__, function.__name__]
84 84 if isinstance(obj, Model):
85 85 cache_key_params.append(str(obj.id))
86 86
87 87 if key_method is not None:
88 88 cache_key_params += [str(arg) for arg in key_method(obj)]
89 89
90 90 cache_key = CACHE_KEY_DELIMITER.join(cache_key_params)
91 91
92 92 persisted_result = cache.get(cache_key)
93 93 if persisted_result is not None:
94 94 result = persisted_result
95 95 else:
96 96 result = function(obj, *args, **kwargs)
97 97 cache.set(cache_key, result)
98 98
99 99 return result
100 100
101 101 return inner_func
102 102 return _cached_result
103 103
104 104
105 105 def is_moderator(request):
106 106 try:
107 107 moderate = request.user.has_perm(PERMISSION_MODERATE)
108 108 except AttributeError:
109 109 moderate = False
110 110
111 111 return moderate
112 112
113 113
114 114 def get_file_hash(file) -> str:
115 115 md5 = hashlib.md5()
116 116 for chunk in file.chunks():
117 117 md5.update(chunk)
118 118 return md5.hexdigest()
119 119
120 120
121 121 def validate_file_size(size: int):
122 122 max_size = boards.settings.get_int('Forms', 'MaxFileSize')
123 123 if size > max_size:
124 124 raise forms.ValidationError(
125 125 _('File must be less than %s bytes')
126 126 % str(max_size))
127 127
128 128
129 129 def get_upload_filename(model_instance, old_filename):
130 130 # TODO Use something other than random number in file name
131 if hasattr(model_instance, 'file_type'):
132 extension = model_instance.file_type
133 else:
134 extension = old_filename.split(FILE_EXTENSION_DELIMITER)[-1:][0]
131 135 new_name = '{}{}.{}'.format(
132 136 str(int(time.mktime(time.gmtime()))),
133 137 str(int(random() * 1000)),
134 old_filename.split(FILE_EXTENSION_DELIMITER)[-1:][0])
138 extension)
135 139
136 140 directory = UPLOAD_DIRS[type(model_instance).__name__]
137 141
138 142 return os.path.join(directory, new_name)
@@ -1,9 +1,10 b''
1 magic
1 2 pytube
2 3 requests
3 4 adjacent
4 5 django-haystack
5 6 pillow
6 7 django>=1.8
7 8 bbcode
8 9 django-debug-toolbar
9 10 pytz
General Comments 0
You need to be logged in to leave comments. Login now