Including the gravatar id in the responses and not generating the gravatar avatar url by default

remotes/origin/issue/4795/notification_even_they_are_disabled
Alejandro Alonso 2016-07-07 13:57:07 +02:00
parent c3022f4f74
commit 20a7595ca3
9 changed files with 77 additions and 120 deletions

View File

@ -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", TAGS_PREDEFINED_COLORS = ["#fce94f", "#edd400", "#c4a000", "#8ae234",
"#73d216", "#4e9a06", "#d3d7cf", "#fcaf3e", "#73d216", "#4e9a06", "#d3d7cf", "#fcaf3e",
"#f57900", "#ce5c00", "#729fcf", "#3465a4", "#f57900", "#ce5c00", "#729fcf", "#3465a4",

View File

@ -19,7 +19,8 @@
from taiga.base.api import serializers from taiga.base.api import serializers
from taiga.base.fields import I18NJsonField, Field, MethodField 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") HISTORY_ENTRY_I18N_FIELDS = ("points", "status", "severity", "priority", "type")
@ -46,7 +47,8 @@ class HistoryEntrySerializer(serializers.LightSerializer):
def get_user(self, entry): def get_user(self, entry):
user = {"pk": None, "username": None, "name": None, "photo": None, "is_active": False} user = {"pk": None, "username": None, "name": None, "photo": None, "is_active": False}
user.update(entry.user) 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: if entry.owner:
user["is_active"] = entry.owner.is_active user["is_active"] = entry.owner.is_active

View File

@ -22,7 +22,8 @@ from taiga.base.api import serializers
from taiga.base.fields import Field, MethodField, I18NField from taiga.base.fields import Field, MethodField, I18NField
from taiga.permissions import services as permissions_services 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.users.serializers import UserBasicInfoSerializer
from taiga.permissions.services import calculate_permissions from taiga.permissions.services import calculate_permissions
@ -106,12 +107,16 @@ class MembershipDictSerializer(serializers.LightDictSerializer):
color = Field() color = Field()
username = Field() username = Field()
photo = MethodField() photo = MethodField()
gravatar_id = MethodField()
def get_full_name_display(self, obj): def get_full_name_display(self, obj):
return obj["full_name"] or obj["username"] or obj["email"] return obj["full_name"] or obj["username"] or obj["email"]
def get_photo(self, obj): 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): class MembershipSerializer(serializers.LightSerializer):
@ -129,6 +134,7 @@ class MembershipSerializer(serializers.LightSerializer):
is_user_active = MethodField() is_user_active = MethodField()
color = MethodField() color = MethodField()
photo = MethodField() photo = MethodField()
gravatar_id = MethodField()
project_name = MethodField() project_name = MethodField()
project_slug = MethodField() project_slug = MethodField()
invited_by = UserBasicInfoSerializer() invited_by = UserBasicInfoSerializer()
@ -147,7 +153,10 @@ class MembershipSerializer(serializers.LightSerializer):
return obj.user.color if obj.user else None return obj.user.color if obj.user else None
def get_photo(self, obj): 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): def get_project_name(self, obj):
return obj.project.name if obj and obj.project else "" return obj.project.name if obj and obj.project else ""

View File

@ -20,7 +20,8 @@ from django.contrib.auth import get_user_model
from taiga.base.api import serializers from taiga.base.api import serializers
from taiga.base.fields import Field, MethodField 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 from . import models
@ -56,8 +57,9 @@ class TimelineSerializer(serializers.LightSerializer):
obj.data["user"] = { obj.data["user"] = {
"id": user.pk, "id": user.pk,
"name": user.get_full_name(), "name": user.get_full_name(),
"photo": get_user_photo_or_gravatar_url(user), "photo": get_user_photo_url(user),
"big_photo": get_big_photo_or_gravatar_url(user), "big_photo": get_user_big_photo_url(user),
"gravatar_id": get_user_gravatar_id(user),
"username": user.username, "username": user.username,
"is_profile_visible": user.is_active and not user.is_system, "is_profile_visible": user.is_active and not user.is_system,
"date_joined": user.date_joined "date_joined": user.date_joined

View File

@ -18,45 +18,22 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import hashlib 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: def get_gravatar_id(email: str) -> str:
"""Get the gravatar url associated to an email. """Get the gravatar id associated to an email.
:param options: Additional options to gravatar. :return: Gravatar id.
- `default` defines what image url to show if no gravatar exists
- `size` defines the size of the avatar.
:return: Gravatar url.
""" """
params = copy.copy(options) return hashlib.md5(email.lower().encode()).hexdigest()
default_avatar = getattr(settings, "GRAVATAR_DEFAULT_AVATAR", None) def get_user_gravatar_id(user: object) -> str:
default_size = getattr(settings, "GRAVATAR_AVATAR_SIZE", None) """Get the gravatar id associated to a user.
avatar = options.get("default", None) :return: Gravatar id.
size = options.get("size", None) """
if user and user.email:
return get_gravatar_id(user.email)
if avatar: return None
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

View File

@ -24,8 +24,8 @@ from taiga.base.fields import PgArrayField, Field, MethodField, I18NField
from taiga.base.utils.thumbnails import get_thumbnail_url from taiga.base.utils.thumbnails import get_thumbnail_url
from taiga.projects.models import Project from taiga.projects.models import Project
from .services import get_user_photo_or_gravatar_url, get_big_photo_or_gravatar_url from .services import get_user_photo_url, get_big_photo_url, get_user_big_photo_url
from .gravatar import get_gravatar_url from taiga.users.gravatar import get_user_gravatar_id
from collections import namedtuple from collections import namedtuple
@ -53,7 +53,7 @@ class UserSerializer(serializers.LightSerializer):
is_active = Field() is_active = Field()
photo = MethodField() photo = MethodField()
big_photo = MethodField() big_photo = MethodField()
gravatar_url = MethodField() gravatar_id = MethodField()
roles = MethodField() roles = MethodField()
projects_with_me = MethodField() projects_with_me = MethodField()
@ -61,13 +61,13 @@ class UserSerializer(serializers.LightSerializer):
return obj.get_full_name() if obj else "" return obj.get_full_name() if obj else ""
def get_photo(self, user): 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): 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): def get_gravatar_id(self, user):
return get_gravatar_url(user.email) return get_user_gravatar_id(user)
def get_roles(self, user): def get_roles(self, user):
return user.memberships. order_by("role__name").values_list("role__name", flat=True).distinct() 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() full_name_display = MethodField()
photo = MethodField() photo = MethodField()
big_photo = MethodField() big_photo = MethodField()
gravatar_id = MethodField()
is_active = Field() is_active = Field()
id = Field() id = Field()
@ -115,10 +116,13 @@ class UserBasicInfoSerializer(serializers.LightSerializer):
return obj.get_full_name() return obj.get_full_name()
def get_photo(self, obj): 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): 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): def to_value(self, instance):
if instance is None: if instance is None:
@ -181,6 +185,7 @@ class HighLightedContentSerializer(serializers.LightSerializer):
assigned_to_username = Field() assigned_to_username = Field()
assigned_to_full_name = Field() assigned_to_full_name = Field()
assigned_to_photo = MethodField() assigned_to_photo = MethodField()
assigned_to_gravatar_id = MethodField()
is_watcher = MethodField() is_watcher = MethodField()
total_watchers = Field() total_watchers = Field()
@ -237,7 +242,16 @@ class HighLightedContentSerializer(serializers.LightSerializer):
UserData = namedtuple("UserData", ["photo", "email"]) UserData = namedtuple("UserData", ["photo", "email"])
user_data = UserData(photo=obj.assigned_to_photo, email=obj.assigned_to_email or "") 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): def get_tags_colors(self, obj):
tags = getattr(obj, "tags", []) tags = getattr(obj, "tags", [])

View File

@ -37,9 +37,6 @@ from taiga.base.utils.urls import get_absolute_url
from taiga.projects.notifications.choices import NotifyLevel from taiga.projects.notifications.choices import NotifyLevel
from taiga.projects.notifications.services import get_projects_watched 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): def get_user_by_username_or_email(username_or_email):
user_model = get_user_model() user_model = get_user_model()
@ -75,6 +72,8 @@ def get_and_validate_user(*, username:str, password:str) -> bool:
def get_photo_url(photo): def get_photo_url(photo):
"""Get a photo absolute url and the photo automatically cropped.""" """Get a photo absolute url and the photo automatically cropped."""
if not photo:
return None
try: try:
url = get_thumbnailer(photo)[settings.THN_AVATAR_SMALL].url url = get_thumbnailer(photo)[settings.THN_AVATAR_SMALL].url
return get_absolute_url(url) return get_absolute_url(url)
@ -82,24 +81,17 @@ def get_photo_url(photo):
return None return None
def get_photo_or_gravatar_url(photo=None, email=None): def get_user_photo_url(user):
"""Get the user's photo/gravatar url.""" """Get the user's photo url."""
if photo: if not user:
return get_photo_url(photo) return None
if email: return get_photo_url(user.photo)
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_big_photo_url(photo): def get_big_photo_url(photo):
"""Get a big photo absolute url and the photo automatically cropped.""" """Get a big photo absolute url and the photo automatically cropped."""
if not photo:
return None
try: try:
url = get_thumbnailer(photo)[settings.THN_AVATAR_BIG].url url = get_thumbnailer(photo)[settings.THN_AVATAR_BIG].url
return get_absolute_url(url) return get_absolute_url(url)
@ -107,15 +99,11 @@ def get_big_photo_url(photo):
return None return None
def get_big_photo_or_gravatar_url(user): def get_user_big_photo_url(user):
"""Get the user's big photo/gravatar url.""" """Get the user's big photo url."""
if not user: if not user:
return "" return None
if user.photo:
return get_big_photo_url(user.photo) return get_big_photo_url(user.photo)
else:
return get_gravatar_url(user.email, size=settings.THN_AVATAR_BIG_SIZE)
def get_visible_project_ids(from_user, by_user): def get_visible_project_ids(from_user, by_user):

View File

@ -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.projects.services import get_logo_big_thumbnail_url
from taiga.users.gravatar import get_gravatar_url from taiga.users.services import get_user_photo_url
from taiga.users.services import get_user_photo_or_gravatar_url from taiga.users.gravatar import get_user_gravatar_id
######################################################################## ########################################################################
# WebHooks # WebHooks
######################################################################## ########################################################################
class WebhookSerializer(serializers.LightSerializer): class WebhookSerializer(serializers.LightSerializer):
id = Field() id = Field()
project = Field(attr="project_id") project = Field(attr="project_id")
@ -64,17 +64,14 @@ class WebhookLogSerializer(serializers.LightSerializer):
class UserSerializer(serializers.LightSerializer): class UserSerializer(serializers.LightSerializer):
id = Field(attr="pk") id = Field(attr="pk")
permalink = MethodField() permalink = MethodField()
gravatar_url = MethodField()
username = MethodField() username = MethodField()
full_name = MethodField() full_name = MethodField()
photo = MethodField() photo = MethodField()
gravatar_id = MethodField()
def get_permalink(self, obj): def get_permalink(self, obj):
return resolve_front_url("user", obj.username) return resolve_front_url("user", obj.username)
def get_gravatar_url(self, obj):
return get_gravatar_url(obj.email)
def get_username(self, obj): def get_username(self, obj):
return obj.get_username() return obj.get_username()
@ -82,7 +79,10 @@ class UserSerializer(serializers.LightSerializer):
return obj.get_full_name() return obj.get_full_name()
def get_photo(self, obj): 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): def to_value(self, instance):
if instance is None: if instance is None:

View File

@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
# 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 <http://www.gnu.org/licenses/>.
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