[WEB - 922]dev: fix workspace member caching (#4147)

* dev: fix workspace member caching

* fix: caching on debug
This commit is contained in:
Nikhil 2024-04-09 13:36:08 +05:30 committed by GitHub
parent 95580d0c62
commit 7e0520d1cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 70 additions and 41 deletions

View File

@ -1,36 +1,39 @@
# Python imports
import jwt
from datetime import datetime
import jwt
# Django imports
from django.conf import settings
from django.utils import timezone
from django.db.models import Count
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from django.db.models import Count
from django.utils import timezone
# Third party modules
from rest_framework import status
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
# Module imports
from plane.app.permissions import WorkSpaceAdminPermission
from plane.app.serializers import (
WorkSpaceMemberSerializer,
WorkSpaceMemberInviteSerializer,
WorkSpaceMemberSerializer,
)
from plane.app.views.base import BaseAPIView
from .. import BaseViewSet
from plane.bgtasks.event_tracking_task import workspace_invite_event
from plane.bgtasks.workspace_invitation_task import workspace_invitation
from plane.db.models import (
User,
Workspace,
WorkspaceMemberInvite,
WorkspaceMember,
WorkspaceMemberInvite,
)
from plane.app.permissions import WorkSpaceAdminPermission
from plane.bgtasks.workspace_invitation_task import workspace_invitation
from plane.bgtasks.event_tracking_task import workspace_invite_event
from plane.utils.cache import invalidate_cache
from plane.utils.cache import invalidate_cache, invalidate_cache_directly
from .. import BaseViewSet
class WorkspaceInvitationsViewset(BaseViewSet):
"""Endpoint for creating, listing and deleting workspaces"""
@ -265,9 +268,6 @@ class UserWorkspaceInvitationsViewSet(BaseViewSet):
@invalidate_cache(path="/api/workspaces/", user=False)
@invalidate_cache(path="/api/users/me/workspaces/")
@invalidate_cache(
path="/api/workspaces/:slug/members/", url_params=True, user=False
)
def create(self, request):
invitations = request.data.get("invitations", [])
workspace_invitations = WorkspaceMemberInvite.objects.filter(
@ -276,6 +276,12 @@ class UserWorkspaceInvitationsViewSet(BaseViewSet):
# If the user is already a member of workspace and was deactivated then activate the user
for invitation in workspace_invitations:
invalidate_cache_directly(
path=f"/api/workspaces/{invitation.workspace.slug}/members/",
user=False,
request=request,
multiple=True,
)
# Update the WorkspaceMember for this specific invitation
WorkspaceMember.objects.filter(
workspace_id=invitation.workspace_id, member=request.user

View File

@ -102,7 +102,10 @@ class WorkSpaceMemberViewSet(BaseViewSet):
return Response(serializer.data, status=status.HTTP_200_OK)
@invalidate_cache(
path="/api/workspaces/:slug/members/", url_params=True, user=False
path="/api/workspaces/:slug/members/",
url_params=True,
user=False,
multiple=True,
)
def partial_update(self, request, slug, pk):
workspace_member = WorkspaceMember.objects.get(
@ -147,9 +150,15 @@ class WorkSpaceMemberViewSet(BaseViewSet):
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@invalidate_cache(
path="/api/workspaces/:slug/members/", url_params=True, user=False
path="/api/workspaces/:slug/members/",
url_params=True,
user=False,
multiple=True,
)
@invalidate_cache(path="/api/users/me/settings/")
@invalidate_cache(
path="/api/users/me/workspaces/", user=False, multiple=True
)
def destroy(self, request, slug, pk):
# Check the user role who is deleting the user
workspace_member = WorkspaceMember.objects.get(
@ -215,9 +224,15 @@ class WorkSpaceMemberViewSet(BaseViewSet):
return Response(status=status.HTTP_204_NO_CONTENT)
@invalidate_cache(
path="/api/workspaces/:slug/members/", url_params=True, user=False
path="/api/workspaces/:slug/members/",
url_params=True,
user=False,
multiple=True,
)
@invalidate_cache(path="/api/users/me/settings/")
@invalidate_cache(
path="api/users/me/workspaces/", user=False, multiple=True
)
def leave(self, request, slug):
workspace_member = WorkspaceMember.objects.get(
workspace__slug=slug,

View File

@ -33,12 +33,12 @@ def cache_response(timeout=60 * 60, path=None, user=True):
custom_path = path if path is not None else request.get_full_path()
key = generate_cache_key(custom_path, auth_header)
cached_result = cache.get(key)
if cached_result is not None:
return Response(
cached_result["data"], status=cached_result["status"]
)
response = view_func(instance, request, *args, **kwargs)
if response.status_code == 200 and not settings.DEBUG:
cache.set(
key,
@ -53,34 +53,42 @@ def cache_response(timeout=60 * 60, path=None, user=True):
return decorator
def invalidate_cache(path=None, url_params=False, user=True):
"""invalidate cache per user"""
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(instance, request, *args, **kwargs):
# Invalidate cache before executing the view function
if url_params:
def invalidate_cache_directly(
path=None, url_params=False, user=True, request=None, multiple=False
):
if url_params and path:
path_with_values = path
for key, value in kwargs.items():
path_with_values = path_with_values.replace(
f":{key}", str(value)
)
# Assuming `kwargs` could be passed directly if needed, otherwise, skip this part
for key, value in request.resolver_match.kwargs.items():
path_with_values = path_with_values.replace(f":{key}", str(value))
custom_path = path_with_values
else:
custom_path = (
path if path is not None else request.get_full_path()
)
custom_path = path if path is not None else request.get_full_path()
auth_header = (
None
if request.user.is_anonymous
else str(request.user.id) if user else None
)
key = generate_cache_key(custom_path, auth_header)
if multiple:
cache.delete_many(keys=cache.keys(f"*{key}*"))
else:
cache.delete(key)
# Execute the view function
def invalidate_cache(path=None, url_params=False, user=True, multiple=False):
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(instance, request, *args, **kwargs):
# invalidate the cache
invalidate_cache_directly(
path=path,
url_params=url_params,
user=user,
request=request,
multiple=multiple,
)
return view_func(instance, request, *args, **kwargs)
return _wrapped_view