# HG changeset patch # User Brian Neal # Date 1683494533 18000 # Node ID 7fc6c42b2f5bc52f0d725ff1054bd7213925b6b4 # Parent d437d5b88c2734ff3511b971baed7c7eae98813e Adding a local user photo upload option. diff -r d437d5b88c27 -r 7fc6c42b2f5b core/images/upload.py --- a/core/images/upload.py Sun Mar 19 10:36:38 2023 -0500 +++ b/core/images/upload.py Sun May 07 16:22:13 2023 -0500 @@ -4,19 +4,47 @@ """ from base64 import b64encode +import datetime import logging from io import BytesIO import os.path +import shutil import uuid +from django.conf import settings +from django.contrib.sites.models import Site from PIL import Image from .utils import orient_image +from core.s3 import S3Bucket logger = logging.getLogger(__name__) +def process_upload(user, filename): + if settings.USER_PHOTOS_LOCAL_UPLOAD: + url, thumb_url = _process_local_upload( + filename, + new_size=settings.USER_PHOTOS_MAX_SIZE, + thumb_size=settings.USER_PHOTOS_THUMB_SIZE) + else: + now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + metadata = {'user': user.username, 'date': now} + + bucket = S3Bucket(access_key=settings.USER_PHOTOS_ACCESS_KEY, + secret_key=settings.USER_PHOTOS_SECRET_KEY, + base_url=settings.USER_PHOTOS_BASE_URL, + bucket_name=settings.USER_PHOTOS_BUCKET) + + url, thumb_url = upload(filename, + bucket=bucket, + metadata=metadata, + new_size=settings.USER_PHOTOS_MAX_SIZE, + thumb_size=settings.USER_PHOTOS_THUMB_SIZE) + return (url, thumb_url) + + def make_key(): """Generate a random key suitable for a filename""" return b64encode(uuid.uuid4().bytes, '-_').rstrip('=') @@ -92,3 +120,64 @@ logger.info('Completed processing image file: %s', filename) return (image_url, thumb_url) + + +def _process_local_upload(filename, new_size=None, thumb_size=None): + # Re-orient if necessary + image = Image.open(filename) + changed, image = orient_image(image) + if changed: + image.save(filename) + + # Resize image if necessary + if new_size: + image = Image.open(filename) + if image.size > new_size: + logger.debug('Resizing from {} to {}'.format(image.size, new_size)) + image.thumbnail(new_size, Image.ANTIALIAS) + image.save(filename) + + # Create thumbnail if necessary + thumb = None + if thumb_size: + logger.debug('Creating thumbnail {}'.format(thumb_size)) + image = Image.open(filename) + image.thumbnail(thumb_size, Image.ANTIALIAS) + thumb = BytesIO() + image.save(thumb, format=image.format) + + # Copy file and thumbnail to our user upload files directory. + upload_dir = os.path.join(settings.MEDIA_ROOT, + settings.USER_PHOTOS_LOCAL_UPLOAD_DIR) + unique_name = uuid.uuid4().hex + ext = os.path.splitext(filename)[1] + image_name = '%s%s' % (unique_name, ext) + thumb_name = '%st%s' % (unique_name, ext) + image_path = os.path.join(upload_dir, image_name) + thumb_path = os.path.join(upload_dir, thumb_name) + + shutil.copy(filename, image_path) + if thumb: + shutil.copyfileobj(thumb, thumb_path) + + # Generate URLs for the image and thumb. + site = Site.objects.get_current() + + url_pattern = '%s://%s%s%s/%s' + + image_url = url_pattern % ( + settings.SITE_SCHEME, + site.domain, + settings.MEDIA_URL, + settings.USER_PHOTOS_LOCAL_UPLOAD_DIR, + image_name) + + thumb_url = url_pattern % ( + settings.SITE_SCHEME, + site.domain, + settings.MEDIA_URL, + settings.USER_PHOTOS_LOCAL_UPLOAD_DIR, + thumb_name) + + return (image_url, thumb_url) + diff -r d437d5b88c27 -r 7fc6c42b2f5b sg101/settings/base.py --- a/sg101/settings/base.py Sun Mar 19 10:36:38 2023 -0500 +++ b/sg101/settings/base.py Sun May 07 16:22:13 2023 -0500 @@ -307,6 +307,9 @@ 'lh3.googleusercontent.com', ] +USER_PHOTOS_LOCAL_UPLOAD = False +USER_PHOTOS_LOCAL_UPLOAD_DIR = 'user_photos' + # If this flag is False, the queued_search queue will not be processed. This is # useful when we are rebuilding the search index. SEARCH_QUEUE_ENABLED = True diff -r d437d5b88c27 -r 7fc6c42b2f5b sg101/settings/production.py --- a/sg101/settings/production.py Sun Mar 19 10:36:38 2023 -0500 +++ b/sg101/settings/production.py Sun May 07 16:22:13 2023 -0500 @@ -54,6 +54,8 @@ DONATIONS_DEBUG = False +USER_PHOTOS_LOCAL_UPLOAD = False + # SSL related settings SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True diff -r d437d5b88c27 -r 7fc6c42b2f5b user_photos/forms.py --- a/user_photos/forms.py Sun Mar 19 10:36:38 2023 -0500 +++ b/user_photos/forms.py Sun May 07 16:22:13 2023 -0500 @@ -1,5 +1,4 @@ """Forms for the user_photos application.""" -import datetime import hashlib import os.path import urlparse @@ -9,8 +8,7 @@ from core.download import download_file from core.functions import remove_file, TemporaryFile -from core.images.upload import upload -from core.s3 import S3Bucket +from core.images.upload import process_upload from core.services import get_redis_connection from user_photos.models import Photo @@ -70,12 +68,6 @@ except Photo.DoesNotExist: pass - # This must not be a duplicate, proceed with upload to S3 - bucket = S3Bucket(access_key=settings.USER_PHOTOS_ACCESS_KEY, - secret_key=settings.USER_PHOTOS_SECRET_KEY, - base_url=settings.USER_PHOTOS_BASE_URL, - bucket_name=settings.USER_PHOTOS_BUCKET) - # Trying to use PIL (or Pillow) on a Django UploadedFile is often # problematic because the file is often an in-memory file if it is under # a certain size. This complicates matters and many of the operations we try @@ -91,14 +83,7 @@ t.file.write(chunk) t.file.close() - now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - metadata = {'user': self.user.username, 'date': now} - - url, thumb_url = upload(filename=t.filename, - bucket=bucket, - metadata=metadata, - new_size=settings.USER_PHOTOS_MAX_SIZE, - thumb_size=settings.USER_PHOTOS_THUMB_SIZE) + url, thumb_url = process_upload(self.user, t.filename) photo = Photo(user=self.user, url=url, thumb_url=thumb_url, signature=signature) @@ -151,19 +136,6 @@ # Try to download the file with remove_file(download_file(url)) as path: - - # Upload it to our S3 bucket - bucket = S3Bucket(access_key=settings.USER_PHOTOS_ACCESS_KEY, - secret_key=settings.USER_PHOTOS_SECRET_KEY, - base_url=settings.HOT_LINK_PHOTOS_BASE_URL, - bucket_name=settings.HOT_LINK_PHOTOS_BUCKET) - - now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - metadata = {'user': self.user.username, 'date': now} - - url, _ = upload(filename=path, - bucket=bucket, - metadata=metadata, - new_size=settings.USER_PHOTOS_MAX_SIZE) + url, _ = process_upload(self.user, path) return url