store.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import os
  2. from hashlib import md5
  3. from django.utils.encoding import force_bytes
  4. from path import Path
  5. from PIL import Image
  6. from misago.conf import settings
  7. from .paths import AVATARS_STORE
  8. def normalize_image(image):
  9. """if image is gif, strip it of animation"""
  10. image.seek(0)
  11. return image.copy().convert('RGBA')
  12. def get_avatar_hash(user, suffix=None):
  13. avatars_dir = get_existing_avatars_dir(user)
  14. avatar_suffix = suffix or max(settings.MISAGO_AVATARS_SIZES)
  15. avatar_file = '%s_%s.png' % (user.pk, avatar_suffix)
  16. avatar_file = Path(os.path.join(avatars_dir, avatar_file))
  17. md5_hash = md5()
  18. with open(avatar_file, 'rb') as f:
  19. while True:
  20. data = f.read(128)
  21. if not data:
  22. break
  23. md5_hash.update(data)
  24. return md5_hash.hexdigest()[:8]
  25. def store_avatar(user, image):
  26. avatars_dir = get_existing_avatars_dir(user)
  27. normalize_image(image)
  28. for size in sorted(settings.MISAGO_AVATARS_SIZES, reverse=True):
  29. avatar_file = '%s_%s.png' % (user.pk, size)
  30. avatar_file = Path(os.path.join(avatars_dir, avatar_file))
  31. image = image.resize((size, size), Image.ANTIALIAS)
  32. image.save(avatar_file, "PNG")
  33. def delete_avatar(user):
  34. avatars_dir = get_existing_avatars_dir(user)
  35. suffixes_to_delete = settings.MISAGO_AVATARS_SIZES + ('org', 'tmp')
  36. for size in suffixes_to_delete:
  37. avatar_file = '%s_%s.png' % (user.pk, size)
  38. avatar_file = Path(os.path.join(avatars_dir, avatar_file))
  39. if avatar_file.exists():
  40. avatar_file.remove()
  41. def get_user_avatar_tokens(user):
  42. token_seeds = (user.email, user.avatar_hash, settings.SECRET_KEY)
  43. tokens = {
  44. 'org': md5(force_bytes('org:%s:%s:%s' % token_seeds)).hexdigest()[:8],
  45. 'tmp': md5(force_bytes('tmp:%s:%s:%s' % token_seeds)).hexdigest()[:8],
  46. }
  47. tokens.update({
  48. tokens['org']: 'org',
  49. tokens['tmp']: 'tmp',
  50. })
  51. return tokens
  52. def store_temporary_avatar(user, image):
  53. avatars_dir = get_existing_avatars_dir(user)
  54. avatar_file = '%s_tmp.png' % user.pk
  55. normalize_image(image)
  56. image.save(os.path.join(avatars_dir, avatar_file), "PNG")
  57. def store_original_avatar(user):
  58. org_path = avatar_file_path(user, 'org')
  59. if org_path.exists():
  60. org_path.remove()
  61. avatar_file_path(user, 'tmp').rename(org_path)
  62. def avatar_file_path(user, size):
  63. avatars_dir = get_existing_avatars_dir(user)
  64. avatar_file = '%s_%s.png' % (user.pk, size)
  65. return Path(os.path.join(avatars_dir, avatar_file))
  66. def avatar_file_exists(user, size):
  67. return avatar_file_path(user, size).exists()
  68. def store_new_avatar(user, image):
  69. """
  70. Deletes old image before storing new one
  71. """
  72. delete_avatar(user)
  73. store_avatar(user, image)
  74. def get_avatars_dir_path(user=None):
  75. if user:
  76. try:
  77. user_pk = user.pk
  78. except AttributeError:
  79. user_pk = user
  80. dir_hash = md5(str(user_pk).encode()).hexdigest()
  81. hash_path = [dir_hash[0:1], dir_hash[2:3]]
  82. return Path(os.path.join(AVATARS_STORE, *hash_path))
  83. else:
  84. return Path(os.path.join(AVATARS_STORE, 'blank'))
  85. def get_existing_avatars_dir(user=None):
  86. avatars_dir = get_avatars_dir_path(user)
  87. if not avatars_dir.exists():
  88. avatars_dir.makedirs()
  89. return avatars_dir