Make the upload location of avatars configurable
Review Request #8841 — Created March 25, 2017 and submitted
The upload location of avatars via the
FileUploadService
is now
configurable through theUPLOADED_AVATARS_PATH
Django setting and the
get_unique_filename
method. If theUPLOADED_AVATARS_PATH
setting is
not set, a default ofuploaded/avatars
will be used.To enable this customizability,
AvatarServiceConfigForm
s are now
passed the instance of the service that instantiated them as a keyword
argument. This allows the forms to look up static settings on the
services.
Ran unit tests.
Description | From | Last Updated |
---|---|---|
Why not just put service=None into the method signature? |
david | |
Can you not fit this all on one line? |
david | |
, optional |
chipx86 | |
I'd like to propose some changes to this logic that will better handle larger files and let Django backends retain … |
chipx86 | |
We should make sure to add a / if file_path_prefix doesn't end with it. It's safe to use this as … |
chipx86 | |
Contents are indented 1 space too far. |
chipx86 | |
We don't use "Returns" for properties. |
chipx86 | |
We should use os.path.join for the uploaded/avatars/ (which also shouldn't have a leading /). |
chipx86 | |
Mind using keyword arguments for this one too? |
chipx86 | |
Typo. |
chipx86 | |
Should just import os. os.path is implied when doing that. |
chipx86 | |
We access the username 3 times. Let's pull it out into a variable to avoid accessor lookups. |
chipx86 | |
No need for the 0. |
chipx86 | |
Minor thing, but for consistency... Most classes use "Unit tests for ..." |
chipx86 | |
Looks unintentional. Blank line should remain. |
chipx86 |
- Commit:
-
adb4d0aee68a78ee955ed620ee6459f328413efc932c73fd9de2a4d8538889fdfbae9046dc0b39ff
Checks run (3 succeeded)
-
-
-
I'd like to propose some changes to this logic that will better handle larger files and let Django backends retain control over the saving process a bit better.
First, it's generally better not to read in all the file data at once. Imagine if someone tried to upload a 100MB file as an avatar. We'd try to read it in all at once and swamp the server, crashing things and effectively taking Review Board down. Instead, we can use chunking to build the hash, like so:
uploaded_file = self.cleaned_data['avatar_upload'] file_hash = md5() for chunk in uploaded_file.chunks(): file_hash.update(chunk)
For path building, there's a couple things we need to do. Paths are expected to go in as OS-specific paths, and are then normalized in the backend, so we can use
os.path.join
. We'll want to do this for the default value fofile_path_prefix
(I'll cover this in another comment) and we want to build it here, so that we can be sure things work iffile_path_prefix
doesn't leave off the trailing/
.For saving, we should let
Storage.save
do its job. This is a bit better than usingopen
andwrite
, and gives the backends a lot more control of the process (and is, I think, actually necessary for some backends). By default,save
will ensure we don't end up with a duplicate filename under any circumstances. It will also ensure paths exist, and it will handle chunking (like above). So the rest of this logic in this comment should be:file_path = storage.save( os.path.join( self.service.file_path_prefix, self.service.get_unique_filename( storage.get_valid_filename(filename))), uploaded_file)
We're using
get_valid_name
on the user-provided filename, instead of the resulting path, helping to catch problems, and doing the hash thing there. We're then creating an OS-level path, which storages expect. The result from the method will be the normalized file path that we can return (which always uses "/" for the delimiter, but also takes care of any alterations that need to be made to make the path more correct).Give that a try. It should result in better future-compatible avatar saving.
-
We should make sure to add a
/
iffile_path_prefix
doesn't end with it.It's safe to use this as the delimiter for paths in storage. Django will normalize to this on Windows, anyway.
-
-
-
- Commit:
-
932c73fd9de2a4d8538889fdfbae9046dc0b39ff31d1f27ba82b2b2bb3aca017d70e0769551b3042
Checks run (3 succeeded)
- Change Summary:
-
Added unit tests & addressed Christian's issues.
- Commit:
-
31d1f27ba82b2b2bb3aca017d70e0769551b3042be008c0051da773c6bcb018be57928527c9297e5
Checks run (3 succeeded)
- Commit:
-
be008c0051da773c6bcb018be57928527c9297e567a061378acd6e9e02cec8c47be98c97c3b2e365
Checks run (3 succeeded)
- Commit:
-
67a061378acd6e9e02cec8c47be98c97c3b2e3652dce883a56f983137e3df6da7f7cc76c91461b37
Checks run (3 succeeded)
- Commit:
-
2dce883a56f983137e3df6da7f7cc76c91461b37d9f01d5da0d40edbbc2fef4883e2f074588205d0
Checks run (3 succeeded)
- Commit:
-
d9f01d5da0d40edbbc2fef4883e2f074588205d017c6185c6c835210b089a44bc1085f509dcde699
Checks run (3 succeeded)
- Description:
-
The upload location of avatars via the
FileUploadService
is now~ configurable through the file_path_prefix
attribute and the~ get_unique_filename
method. This allows consumers to customize the~ behaviour by modifying the file_path_prefix
attribute in a subclass,~ configurable through the UPLOADED_AVATARS_PATH
Django setting and the~ get_unique_filename
method. If theUPLOADED_AVATARS_PATH
setting is~ not set, a default of uploaded/avatars
will be used.- which defaults to an empty string. To enable this customizability,
AvatarServiceConfigForm
s are nowpassed the instance of the service that instantiated them as a keyword argument. This allows the forms to look up static settings on the services. - Testing Done:
-
~ Tested this with /r/8842/. Saw that the upload location was correct.
~ Ran unit tests.
- Depends On:
-
- Commit:
17c6185c6c835210b089a44bc1085f509dcde69945052d2a908769e8d0ad21ed782d189c6ed96fcc- Diff:
Revision 9 (+176 -13)
Checks run (3 succeeded)
JSHint passed.PEP8 Style Checker passed.Pyflakes passed.