diff --git a/swh/web/auth/mailmap.py b/swh/web/auth/mailmap.py --- a/swh/web/auth/mailmap.py +++ b/swh/web/auth/mailmap.py @@ -4,7 +4,13 @@ # See top-level LICENSE file for more information from django.conf.urls import url -from django.http.response import HttpResponse, HttpResponseForbidden +from django.db.models import Q +from django.http.response import ( + HttpResponse, + HttpResponseBadRequest, + HttpResponseForbidden, + HttpResponseNotFound, +) from rest_framework import serializers from rest_framework.decorators import api_view from rest_framework.request import Request @@ -37,10 +43,28 @@ if not request.user.has_perm(MAILMAP_PERMISSION): return HttpResponseForbidden() - UserMailmap.objects.update(user_id=str(request.user.id), **request.data) - mm = UserMailmap.objects.get( - user_id=str(request.user.id), from_email=request.data.get("from_email") - ) + try: + from_email = request.data.pop("from_email") + except KeyError: + return HttpResponseBadRequest("Missing from_email value") + + user_id = str(request.user.id) + + try: + to_update = ( + UserMailmap.objects.filter(Q(user_id__isnull=True) | Q(user_id=user_id)) + .filter(from_email=from_email) + .get() + ) + except UserMailmap.DoesNotExist: + return HttpResponseNotFound() + + for attr, value in request.data.items(): + setattr(to_update, attr, value) + + to_update.save() + + mm = UserMailmap.objects.get(user_id=user_id, from_email=from_email) return Response(UserMailmapSerializer(mm).data) diff --git a/swh/web/tests/auth/test_mailmap.py b/swh/web/tests/auth/test_mailmap.py --- a/swh/web/tests/auth/test_mailmap.py +++ b/swh/web/tests/auth/test_mailmap.py @@ -3,6 +3,7 @@ # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information +import datetime from io import StringIO from typing import Dict @@ -48,10 +49,67 @@ @pytest.mark.django_db(transaction=True) def test_mailmap_endpoints_error_response(api_client, mailmap_user): api_client.force_login(mailmap_user) - for view_name in ("profile-mailmap-add", "profile-mailmap-update"): - url = reverse(view_name) - resp = check_api_post_response(api_client, url, status_code=500) - assert "exception" in resp.data + + url = reverse("profile-mailmap-add") + resp = check_api_post_response(api_client, url, status_code=500) + assert "exception" in resp.data + + url = reverse("profile-mailmap-update") + resp = check_api_post_response(api_client, url, status_code=400) + + +@pytest.mark.django_db(transaction=True) +def test_mailmap_update(api_client, mailmap_user): + api_client.force_login(mailmap_user) + + before_add = datetime.datetime.now(tz=datetime.timezone.utc) + + check_api_post_response( + api_client, + reverse("profile-mailmap-add"), + data={"from_email": "orig1@example.org", "display_name": "Display Name 1"}, + status_code=200, + ) + check_api_post_response( + api_client, + reverse("profile-mailmap-add"), + data={"from_email": "orig2@example.org", "display_name": "Display Name 2"}, + status_code=200, + ) + after_add = datetime.datetime.now(tz=datetime.timezone.utc) + + mailmaps = list(UserMailmap.objects.order_by("from_email").all()) + assert len(mailmaps) == 2, mailmaps + + assert mailmaps[0].from_email == "orig1@example.org", mailmaps + assert mailmaps[0].display_name == "Display Name 1", mailmaps + assert before_add <= mailmaps[0].last_update_date <= after_add + + assert mailmaps[1].from_email == "orig2@example.org", mailmaps + assert mailmaps[1].display_name == "Display Name 2", mailmaps + assert before_add <= mailmaps[0].last_update_date <= after_add + + before_update = datetime.datetime.now(tz=datetime.timezone.utc) + + check_api_post_response( + api_client, + reverse("profile-mailmap-update"), + data={"from_email": "orig1@example.org", "display_name": "Display Name 1b"}, + status_code=200, + ) + + after_update = datetime.datetime.now(tz=datetime.timezone.utc) + + mailmaps = list(UserMailmap.objects.order_by("from_email").all()) + assert len(mailmaps) == 2, mailmaps + + assert mailmaps[0].from_email == "orig1@example.org", mailmaps + assert mailmaps[0].display_name == "Display Name 1b", mailmaps + assert before_update <= mailmaps[0].last_update_date <= after_update + + assert mailmaps[1].from_email == "orig2@example.org", mailmaps + assert mailmaps[1].display_name == "Display Name 2", mailmaps + assert before_add <= mailmaps[1].last_update_date <= after_add def populate_mailmap():