forked from github/plane
[WEB - 922]dev: fix workspace member caching (#4147)
* dev: fix workspace member caching * fix: caching on debug
This commit is contained in:
parent
95580d0c62
commit
7e0520d1cf
@ -1,36 +1,39 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
import jwt
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
import jwt
|
||||||
|
|
||||||
# Django imports
|
# Django imports
|
||||||
from django.conf import settings
|
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.exceptions import ValidationError
|
||||||
from django.core.validators import validate_email
|
from django.core.validators import validate_email
|
||||||
|
from django.db.models import Count
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
# Third party modules
|
# Third party modules
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.response import Response
|
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
|
from rest_framework.response import Response
|
||||||
|
|
||||||
# Module imports
|
# Module imports
|
||||||
|
from plane.app.permissions import WorkSpaceAdminPermission
|
||||||
from plane.app.serializers import (
|
from plane.app.serializers import (
|
||||||
WorkSpaceMemberSerializer,
|
|
||||||
WorkSpaceMemberInviteSerializer,
|
WorkSpaceMemberInviteSerializer,
|
||||||
|
WorkSpaceMemberSerializer,
|
||||||
)
|
)
|
||||||
from plane.app.views.base import BaseAPIView
|
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 (
|
from plane.db.models import (
|
||||||
User,
|
User,
|
||||||
Workspace,
|
Workspace,
|
||||||
WorkspaceMemberInvite,
|
|
||||||
WorkspaceMember,
|
WorkspaceMember,
|
||||||
|
WorkspaceMemberInvite,
|
||||||
)
|
)
|
||||||
from plane.app.permissions import WorkSpaceAdminPermission
|
from plane.utils.cache import invalidate_cache, invalidate_cache_directly
|
||||||
from plane.bgtasks.workspace_invitation_task import workspace_invitation
|
|
||||||
from plane.bgtasks.event_tracking_task import workspace_invite_event
|
from .. import BaseViewSet
|
||||||
from plane.utils.cache import invalidate_cache
|
|
||||||
|
|
||||||
class WorkspaceInvitationsViewset(BaseViewSet):
|
class WorkspaceInvitationsViewset(BaseViewSet):
|
||||||
"""Endpoint for creating, listing and deleting workspaces"""
|
"""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/workspaces/", user=False)
|
||||||
@invalidate_cache(path="/api/users/me/workspaces/")
|
@invalidate_cache(path="/api/users/me/workspaces/")
|
||||||
@invalidate_cache(
|
|
||||||
path="/api/workspaces/:slug/members/", url_params=True, user=False
|
|
||||||
)
|
|
||||||
def create(self, request):
|
def create(self, request):
|
||||||
invitations = request.data.get("invitations", [])
|
invitations = request.data.get("invitations", [])
|
||||||
workspace_invitations = WorkspaceMemberInvite.objects.filter(
|
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
|
# If the user is already a member of workspace and was deactivated then activate the user
|
||||||
for invitation in workspace_invitations:
|
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
|
# Update the WorkspaceMember for this specific invitation
|
||||||
WorkspaceMember.objects.filter(
|
WorkspaceMember.objects.filter(
|
||||||
workspace_id=invitation.workspace_id, member=request.user
|
workspace_id=invitation.workspace_id, member=request.user
|
||||||
|
@ -102,7 +102,10 @@ class WorkSpaceMemberViewSet(BaseViewSet):
|
|||||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
@invalidate_cache(
|
@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):
|
def partial_update(self, request, slug, pk):
|
||||||
workspace_member = WorkspaceMember.objects.get(
|
workspace_member = WorkspaceMember.objects.get(
|
||||||
@ -147,9 +150,15 @@ class WorkSpaceMemberViewSet(BaseViewSet):
|
|||||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
@invalidate_cache(
|
@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/settings/")
|
||||||
|
@invalidate_cache(
|
||||||
|
path="/api/users/me/workspaces/", user=False, multiple=True
|
||||||
|
)
|
||||||
def destroy(self, request, slug, pk):
|
def destroy(self, request, slug, pk):
|
||||||
# Check the user role who is deleting the user
|
# Check the user role who is deleting the user
|
||||||
workspace_member = WorkspaceMember.objects.get(
|
workspace_member = WorkspaceMember.objects.get(
|
||||||
@ -215,9 +224,15 @@ class WorkSpaceMemberViewSet(BaseViewSet):
|
|||||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
@invalidate_cache(
|
@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/settings/")
|
||||||
|
@invalidate_cache(
|
||||||
|
path="api/users/me/workspaces/", user=False, multiple=True
|
||||||
|
)
|
||||||
def leave(self, request, slug):
|
def leave(self, request, slug):
|
||||||
workspace_member = WorkspaceMember.objects.get(
|
workspace_member = WorkspaceMember.objects.get(
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
|
@ -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()
|
custom_path = path if path is not None else request.get_full_path()
|
||||||
key = generate_cache_key(custom_path, auth_header)
|
key = generate_cache_key(custom_path, auth_header)
|
||||||
cached_result = cache.get(key)
|
cached_result = cache.get(key)
|
||||||
|
|
||||||
if cached_result is not None:
|
if cached_result is not None:
|
||||||
return Response(
|
return Response(
|
||||||
cached_result["data"], status=cached_result["status"]
|
cached_result["data"], status=cached_result["status"]
|
||||||
)
|
)
|
||||||
response = view_func(instance, request, *args, **kwargs)
|
response = view_func(instance, request, *args, **kwargs)
|
||||||
|
|
||||||
if response.status_code == 200 and not settings.DEBUG:
|
if response.status_code == 200 and not settings.DEBUG:
|
||||||
cache.set(
|
cache.set(
|
||||||
key,
|
key,
|
||||||
@ -53,34 +53,42 @@ def cache_response(timeout=60 * 60, path=None, user=True):
|
|||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
def invalidate_cache(path=None, url_params=False, user=True):
|
def invalidate_cache_directly(
|
||||||
"""invalidate cache per user"""
|
path=None, url_params=False, user=True, request=None, multiple=False
|
||||||
|
):
|
||||||
|
if url_params and path:
|
||||||
|
path_with_values = path
|
||||||
|
# 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()
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
def invalidate_cache(path=None, url_params=False, user=True, multiple=False):
|
||||||
def decorator(view_func):
|
def decorator(view_func):
|
||||||
@wraps(view_func)
|
@wraps(view_func)
|
||||||
def _wrapped_view(instance, request, *args, **kwargs):
|
def _wrapped_view(instance, request, *args, **kwargs):
|
||||||
# Invalidate cache before executing the view function
|
# invalidate the cache
|
||||||
if url_params:
|
invalidate_cache_directly(
|
||||||
path_with_values = path
|
path=path,
|
||||||
for key, value in kwargs.items():
|
url_params=url_params,
|
||||||
path_with_values = path_with_values.replace(
|
user=user,
|
||||||
f":{key}", str(value)
|
request=request,
|
||||||
)
|
multiple=multiple,
|
||||||
|
|
||||||
custom_path = path_with_values
|
|
||||||
else:
|
|
||||||
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)
|
|
||||||
cache.delete(key)
|
|
||||||
# Execute the view function
|
|
||||||
return view_func(instance, request, *args, **kwargs)
|
return view_func(instance, request, *args, **kwargs)
|
||||||
|
|
||||||
return _wrapped_view
|
return _wrapped_view
|
||||||
|
Loading…
Reference in New Issue
Block a user