diff --git a/settings/common.py b/settings/common.py index f227d97c..3ee3b3f3 100644 --- a/settings/common.py +++ b/settings/common.py @@ -477,10 +477,6 @@ THUMBNAIL_ALIASES = { }, } -# GRAVATAR_DEFAULT_AVATAR = "img/user-noimage.png" -GRAVATAR_DEFAULT_AVATAR = "" -GRAVATAR_AVATAR_SIZE = THN_AVATAR_SIZE - TAGS_PREDEFINED_COLORS = ["#fce94f", "#edd400", "#c4a000", "#8ae234", "#73d216", "#4e9a06", "#d3d7cf", "#fcaf3e", "#f57900", "#ce5c00", "#729fcf", "#3465a4", diff --git a/taiga/projects/history/serializers.py b/taiga/projects/history/serializers.py index 224cc6df..0f2dc658 100644 --- a/taiga/projects/history/serializers.py +++ b/taiga/projects/history/serializers.py @@ -19,7 +19,8 @@ from taiga.base.api import serializers from taiga.base.fields import I18NJsonField, Field, MethodField -from taiga.users.services import get_user_photo_or_gravatar_url +from taiga.users.services import get_user_photo_url +from taiga.users.gravatar import get_user_gravatar_id HISTORY_ENTRY_I18N_FIELDS = ("points", "status", "severity", "priority", "type") @@ -46,7 +47,8 @@ class HistoryEntrySerializer(serializers.LightSerializer): def get_user(self, entry): user = {"pk": None, "username": None, "name": None, "photo": None, "is_active": False} user.update(entry.user) - user["photo"] = get_user_photo_or_gravatar_url(entry.owner) + user["photo"] = get_user_photo_url(entry.owner) + user["gravatar_id"] = get_user_gravatar_id(entry.owner) if entry.owner: user["is_active"] = entry.owner.is_active diff --git a/taiga/projects/serializers.py b/taiga/projects/serializers.py index d4c93155..1d8a5799 100644 --- a/taiga/projects/serializers.py +++ b/taiga/projects/serializers.py @@ -22,7 +22,8 @@ from taiga.base.api import serializers from taiga.base.fields import Field, MethodField, I18NField from taiga.permissions import services as permissions_services -from taiga.users.services import get_user_photo_or_gravatar_url, get_photo_or_gravatar_url +from taiga.users.services import get_photo_url, get_user_photo_url +from taiga.users.gravatar import get_gravatar_id, get_user_gravatar_id from taiga.users.serializers import UserBasicInfoSerializer from taiga.permissions.services import calculate_permissions @@ -106,12 +107,16 @@ class MembershipDictSerializer(serializers.LightDictSerializer): color = Field() username = Field() photo = MethodField() + gravatar_id = MethodField() def get_full_name_display(self, obj): return obj["full_name"] or obj["username"] or obj["email"] def get_photo(self, obj): - return get_photo_or_gravatar_url(obj['photo'], obj['email']) + return get_photo_url(obj['photo']) + + def get_gravatar_id(self, obj): + return get_gravatar_id(obj['email']) class MembershipSerializer(serializers.LightSerializer): @@ -129,6 +134,7 @@ class MembershipSerializer(serializers.LightSerializer): is_user_active = MethodField() color = MethodField() photo = MethodField() + gravatar_id = MethodField() project_name = MethodField() project_slug = MethodField() invited_by = UserBasicInfoSerializer() @@ -147,7 +153,10 @@ class MembershipSerializer(serializers.LightSerializer): return obj.user.color if obj.user else None def get_photo(self, obj): - return get_user_photo_or_gravatar_url(obj.user) + return get_user_photo_url(obj.user) + + def get_gravatar_id(self, obj): + return get_user_gravatar_id(obj.user) def get_project_name(self, obj): return obj.project.name if obj and obj.project else "" diff --git a/taiga/timeline/serializers.py b/taiga/timeline/serializers.py index a7f607c9..0b831d04 100644 --- a/taiga/timeline/serializers.py +++ b/taiga/timeline/serializers.py @@ -20,7 +20,8 @@ from django.contrib.auth import get_user_model from taiga.base.api import serializers from taiga.base.fields import Field, MethodField -from taiga.users.services import get_user_photo_or_gravatar_url, get_big_photo_or_gravatar_url +from taiga.users.services import get_user_photo_url, get_user_big_photo_url +from taiga.users.gravatar import get_user_gravatar_id from . import models @@ -56,8 +57,9 @@ class TimelineSerializer(serializers.LightSerializer): obj.data["user"] = { "id": user.pk, "name": user.get_full_name(), - "photo": get_user_photo_or_gravatar_url(user), - "big_photo": get_big_photo_or_gravatar_url(user), + "photo": get_user_photo_url(user), + "big_photo": get_user_big_photo_url(user), + "gravatar_id": get_user_gravatar_id(user), "username": user.username, "is_profile_visible": user.is_active and not user.is_system, "date_joined": user.date_joined diff --git a/taiga/users/gravatar.py b/taiga/users/gravatar.py index 7793e59d..b8329d95 100644 --- a/taiga/users/gravatar.py +++ b/taiga/users/gravatar.py @@ -18,45 +18,22 @@ # along with this program. If not, see . import hashlib -import copy - -from urllib.parse import urlencode - -from django.conf import settings -from django.templatetags.static import static - -GRAVATAR_BASE_URL = "//www.gravatar.com/avatar/{}?{}" -def get_gravatar_url(email: str, **options) -> str: - """Get the gravatar url associated to an email. +def get_gravatar_id(email: str) -> str: + """Get the gravatar id associated to an email. - :param options: Additional options to gravatar. - - `default` defines what image url to show if no gravatar exists - - `size` defines the size of the avatar. - - :return: Gravatar url. + :return: Gravatar id. """ - params = copy.copy(options) + return hashlib.md5(email.lower().encode()).hexdigest() - default_avatar = getattr(settings, "GRAVATAR_DEFAULT_AVATAR", None) - default_size = getattr(settings, "GRAVATAR_AVATAR_SIZE", None) +def get_user_gravatar_id(user: object) -> str: + """Get the gravatar id associated to a user. - avatar = options.get("default", None) - size = options.get("size", None) + :return: Gravatar id. + """ + if user and user.email: + return get_gravatar_id(user.email) - if avatar: - params["default"] = avatar - elif default_avatar: - params["default"] = static(default_avatar) - - if size: - params["size"] = size - elif default_size: - params["size"] = default_size - - email_hash = hashlib.md5(email.lower().encode()).hexdigest() - url = GRAVATAR_BASE_URL.format(email_hash, urlencode(params)) - - return url + return None diff --git a/taiga/users/serializers.py b/taiga/users/serializers.py index a943183d..76fa6141 100644 --- a/taiga/users/serializers.py +++ b/taiga/users/serializers.py @@ -24,8 +24,8 @@ from taiga.base.fields import PgArrayField, Field, MethodField, I18NField from taiga.base.utils.thumbnails import get_thumbnail_url from taiga.projects.models import Project -from .services import get_user_photo_or_gravatar_url, get_big_photo_or_gravatar_url -from .gravatar import get_gravatar_url +from .services import get_user_photo_url, get_big_photo_url, get_user_big_photo_url +from taiga.users.gravatar import get_user_gravatar_id from collections import namedtuple @@ -53,7 +53,7 @@ class UserSerializer(serializers.LightSerializer): is_active = Field() photo = MethodField() big_photo = MethodField() - gravatar_url = MethodField() + gravatar_id = MethodField() roles = MethodField() projects_with_me = MethodField() @@ -61,13 +61,13 @@ class UserSerializer(serializers.LightSerializer): return obj.get_full_name() if obj else "" def get_photo(self, user): - return get_user_photo_or_gravatar_url(user) + return get_user_photo_url(user) def get_big_photo(self, user): - return get_big_photo_or_gravatar_url(user) + return get_user_big_photo_url(user) - def get_gravatar_url(self, user): - return get_gravatar_url(user.email) + def get_gravatar_id(self, user): + return get_user_gravatar_id(user) def get_roles(self, user): return user.memberships. order_by("role__name").values_list("role__name", flat=True).distinct() @@ -108,6 +108,7 @@ class UserBasicInfoSerializer(serializers.LightSerializer): full_name_display = MethodField() photo = MethodField() big_photo = MethodField() + gravatar_id = MethodField() is_active = Field() id = Field() @@ -115,10 +116,13 @@ class UserBasicInfoSerializer(serializers.LightSerializer): return obj.get_full_name() def get_photo(self, obj): - return get_user_photo_or_gravatar_url(obj) + return get_user_photo_url(obj) def get_big_photo(self, obj): - return get_big_photo_or_gravatar_url(obj) + return get_user_big_photo_url(obj) + + def get_gravatar_id(self, obj): + return get_user_gravatar_id(obj) def to_value(self, instance): if instance is None: @@ -181,6 +185,7 @@ class HighLightedContentSerializer(serializers.LightSerializer): assigned_to_username = Field() assigned_to_full_name = Field() assigned_to_photo = MethodField() + assigned_to_gravatar_id = MethodField() is_watcher = MethodField() total_watchers = Field() @@ -237,7 +242,16 @@ class HighLightedContentSerializer(serializers.LightSerializer): UserData = namedtuple("UserData", ["photo", "email"]) user_data = UserData(photo=obj.assigned_to_photo, email=obj.assigned_to_email or "") - return get_user_photo_or_gravatar_url(user_data) + return get_user_photo_url(user_data) + + def get_assigned_to_gravatar_id(self, obj): + type = getattr(obj, "type", "") + if type == "project": + return None + + UserData = namedtuple("UserData", ["photo", "email"]) + user_data = UserData(photo=obj.assigned_to_photo, email=obj.assigned_to_email or "") + return get_user_gravatar_id(user_data) def get_tags_colors(self, obj): tags = getattr(obj, "tags", []) diff --git a/taiga/users/services.py b/taiga/users/services.py index 73ae2d74..98b813b1 100644 --- a/taiga/users/services.py +++ b/taiga/users/services.py @@ -37,9 +37,6 @@ from taiga.base.utils.urls import get_absolute_url from taiga.projects.notifications.choices import NotifyLevel from taiga.projects.notifications.services import get_projects_watched -from .gravatar import get_gravatar_url - - def get_user_by_username_or_email(username_or_email): user_model = get_user_model() @@ -75,6 +72,8 @@ def get_and_validate_user(*, username:str, password:str) -> bool: def get_photo_url(photo): """Get a photo absolute url and the photo automatically cropped.""" + if not photo: + return None try: url = get_thumbnailer(photo)[settings.THN_AVATAR_SMALL].url return get_absolute_url(url) @@ -82,24 +81,17 @@ def get_photo_url(photo): return None -def get_photo_or_gravatar_url(photo=None, email=None): - """Get the user's photo/gravatar url.""" - if photo: - return get_photo_url(photo) - if email: - return get_gravatar_url(email) - return settings.GRAVATAR_DEFAULT_AVATAR - - -def get_user_photo_or_gravatar_url(user): - """Get the user's photo/gravatar url.""" - if user: - return get_photo_url(user.photo) if user.photo else get_gravatar_url(user.email) - return settings.GRAVATAR_DEFAULT_AVATAR +def get_user_photo_url(user): + """Get the user's photo url.""" + if not user: + return None + return get_photo_url(user.photo) def get_big_photo_url(photo): """Get a big photo absolute url and the photo automatically cropped.""" + if not photo: + return None try: url = get_thumbnailer(photo)[settings.THN_AVATAR_BIG].url return get_absolute_url(url) @@ -107,15 +99,11 @@ def get_big_photo_url(photo): return None -def get_big_photo_or_gravatar_url(user): - """Get the user's big photo/gravatar url.""" +def get_user_big_photo_url(user): + """Get the user's big photo url.""" if not user: - return "" - - if user.photo: - return get_big_photo_url(user.photo) - else: - return get_gravatar_url(user.email, size=settings.THN_AVATAR_BIG_SIZE) + return None + return get_big_photo_url(user.photo) def get_visible_project_ids(from_user, by_user): diff --git a/taiga/webhooks/serializers.py b/taiga/webhooks/serializers.py index f08f4ae7..61eea6cb 100644 --- a/taiga/webhooks/serializers.py +++ b/taiga/webhooks/serializers.py @@ -24,14 +24,14 @@ from taiga.front.templatetags.functions import resolve as resolve_front_url from taiga.projects.services import get_logo_big_thumbnail_url -from taiga.users.gravatar import get_gravatar_url -from taiga.users.services import get_user_photo_or_gravatar_url - +from taiga.users.services import get_user_photo_url +from taiga.users.gravatar import get_user_gravatar_id ######################################################################## # WebHooks ######################################################################## + class WebhookSerializer(serializers.LightSerializer): id = Field() project = Field(attr="project_id") @@ -64,17 +64,14 @@ class WebhookLogSerializer(serializers.LightSerializer): class UserSerializer(serializers.LightSerializer): id = Field(attr="pk") permalink = MethodField() - gravatar_url = MethodField() username = MethodField() full_name = MethodField() photo = MethodField() + gravatar_id = MethodField() def get_permalink(self, obj): return resolve_front_url("user", obj.username) - def get_gravatar_url(self, obj): - return get_gravatar_url(obj.email) - def get_username(self, obj): return obj.get_username() @@ -82,7 +79,10 @@ class UserSerializer(serializers.LightSerializer): return obj.get_full_name() def get_photo(self, obj): - return get_user_photo_or_gravatar_url(obj) + return get_user_photo_url(obj) + + def get_gravatar_id(self, obj): + return get_user_gravatar_id(obj) def to_value(self, instance): if instance is None: diff --git a/tests/unit/test_gravatar.py b/tests/unit/test_gravatar.py deleted file mode 100644 index b6246fa8..00000000 --- a/tests/unit/test_gravatar.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino -# Copyright (C) 2014-2016 David Barragán -# Copyright (C) 2014-2016 Alejandro Alonso -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import hashlib - -from taiga.users.gravatar import get_gravatar_url - - -def test_get_gravatar_url(): - email = "user@email.com" - email_hash = hashlib.md5(email.encode()).hexdigest() - url = get_gravatar_url(email, s=40, d="default-image-url") - - assert email_hash in url - assert 's=40' in url - assert 'd=default-image-url' in url