Merge branch 'develop' of github.com:makeplane/plane into feat/notifications

This commit is contained in:
pablohashescobar 2023-06-22 20:56:53 +05:30
commit 8260e2f897
16 changed files with 126 additions and 53 deletions

View File

@ -21,10 +21,12 @@ NEXT_PUBLIC_TRACK_EVENTS=0
NEXT_PUBLIC_SLACK_CLIENT_ID=""
# Backend
# Debug value for api server use it as 0 for production use
DEBUG=0
# Error logs
SENTRY_DSN=""
# Database Settings
PGUSER="plane"
PGPASSWORD="plane"

View File

@ -22,7 +22,7 @@ from plane.db.models import (
State,
IssueLink,
IssueAttachment,
IssueActivity,
ProjectMember,
)
from plane.api.serializers import (
IssueSerializer,
@ -246,13 +246,28 @@ class InboxIssueViewSet(BaseViewSet):
inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
)
# Get the project member
project_member = ProjectMember.objects.get(workspace__slug=slug, project_id=project_id, member=request.user)
# Only project members admins and created_by users can access this endpoint
if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(request.user.id):
return Response({"error": "You cannot edit inbox issues"}, status=status.HTTP_400_BAD_REQUEST)
# Get issue data
issue_data = request.data.pop("issue", False)
if bool(issue_data):
issue = Issue.objects.get(
pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id
)
# Only allow guests and viewers to edit name and description
if project_member <= 10:
# viewers and guests since only viewers and guests
issue_data = {
"name": issue_data.get("name", issue.name),
"description_html": issue_data.get("description_html", issue.description_html),
"description": issue_data.get("description", issue.description)
}
issue_serializer = IssueCreateSerializer(
issue, data=issue_data, partial=True
)
@ -279,46 +294,50 @@ class InboxIssueViewSet(BaseViewSet):
issue_serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
serializer = InboxIssueSerializer(
inbox_issue, data=request.data, partial=True
)
# Only project admins and members can edit inbox issue attributes
if project_member.role > 10:
serializer = InboxIssueSerializer(
inbox_issue, data=request.data, partial=True
)
if serializer.is_valid():
serializer.save()
# Update the issue state if the issue is rejected or marked as duplicate
if serializer.data["status"] in [-1, 2]:
issue = Issue.objects.get(
pk=inbox_issue.issue_id,
workspace__slug=slug,
project_id=project_id,
)
state = State.objects.filter(
group="cancelled", workspace__slug=slug, project_id=project_id
).first()
if state is not None:
issue.state = state
issue.save()
# Update the issue state if it is accepted
if serializer.data["status"] in [1]:
issue = Issue.objects.get(
pk=inbox_issue.issue_id,
workspace__slug=slug,
project_id=project_id,
)
# Update the issue state only if it is in triage state
if issue.state.name == "Triage":
# Move to default state
if serializer.is_valid():
serializer.save()
# Update the issue state if the issue is rejected or marked as duplicate
if serializer.data["status"] in [-1, 2]:
issue = Issue.objects.get(
pk=inbox_issue.issue_id,
workspace__slug=slug,
project_id=project_id,
)
state = State.objects.filter(
workspace__slug=slug, project_id=project_id, default=True
group="cancelled", workspace__slug=slug, project_id=project_id
).first()
if state is not None:
issue.state = state
issue.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# Update the issue state if it is accepted
if serializer.data["status"] in [1]:
issue = Issue.objects.get(
pk=inbox_issue.issue_id,
workspace__slug=slug,
project_id=project_id,
)
# Update the issue state only if it is in triage state
if issue.state.name == "Triage":
# Move to default state
state = State.objects.filter(
workspace__slug=slug, project_id=project_id, default=True
).first()
if state is not None:
issue.state = state
issue.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
return Response(InboxIssueSerializer(inbox_issue).data, status=status.HTTP_200_OK)
except InboxIssue.DoesNotExist:
return Response(
{"error": "Inbox Issue does not exist"},
@ -347,3 +366,25 @@ class InboxIssueViewSet(BaseViewSet):
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, inbox_id, pk):
try:
inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
)
# Get the project member
project_member = ProjectMember.objects.get(workspace__slug=slug, project_id=project_id, member=request.user)
if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(request.user.id):
return Response({"error": "You cannot delete inbox issue"}, status=status.HTTP_400_BAD_REQUEST)
inbox_issue.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except InboxIssue.DoesNotExist:
return Response({"error": "Inbox Issue does not exists"}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@ -592,6 +592,20 @@ class SubIssuesEndpoint(BaseAPIView):
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
)
state_distribution = (

View File

@ -98,20 +98,6 @@ class UpdateUserOnBoardedEndpoint(BaseAPIView):
user = User.objects.get(pk=request.user.id)
user.is_onboarded = request.data.get("is_onboarded", False)
user.save()
if user.last_workspace_id is not None:
user_role = WorkspaceMember.objects.filter(
workspace_id=user.last_workspace_id, member=request.user.id
).first()
return Response(
{
"message": "Updated successfully",
"role": user_role.company_role
if user_role is not None
else None,
},
status=status.HTTP_200_OK,
)
return Response(
{"message": "Updated successfully"}, status=status.HTTP_200_OK
)

View File

@ -169,6 +169,8 @@ def analytic_export_task(email, data, slug):
msg.send(fail_silently=False)
except Exception as e:
print(e)
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@ -39,5 +39,8 @@ def email_verification(first_name, email, token, current_site):
msg.send()
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@ -37,5 +37,8 @@ def forgot_password(first_name, email, uidb64, token, current_site):
msg.send()
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@ -175,5 +175,8 @@ def service_importer(service, importer_id):
importer = Importer.objects.get(pk=importer_id)
importer.status = "failed"
importer.save()
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@ -1047,5 +1047,8 @@ def issue_activity(
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@ -31,4 +31,7 @@ def magic_link(email, key, token, current_site):
return
except Exception as e:
capture_exception(e)
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
return

View File

@ -50,5 +50,8 @@ def project_invitation(email, project_id, token, current_site):
except (Project.DoesNotExist, ProjectMemberInvite.DoesNotExist) as e:
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@ -29,5 +29,8 @@ def send_welcome_slack(user_id, created, message):
print(f"Got an error: {e.response['error']}")
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@ -66,5 +66,8 @@ def workspace_invitation(email, workspace_id, token, current_site, invitor):
except (Workspace.DoesNotExist, WorkspaceMemberInvite.DoesNotExist) as e:
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@ -98,7 +98,7 @@ export const InboxFiltersList = () => {
type="button"
onClick={() =>
setFilters({
priority: null,
inbox_status: null,
})
}
>

View File

@ -28,6 +28,8 @@ services:
env_file:
- .env
environment:
DEBUG: ${DEBUG}
SENTRY_DSN: ${SENTRY_DSN}
DJANGO_SETTINGS_MODULE: plane.settings.production
DATABASE_URL: postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:5432/${PGDATABASE}
REDIS_URL: redis://plane-redis:6379/
@ -52,7 +54,6 @@ services:
DEFAULT_EMAIL: ${DEFAULT_EMAIL}
DEFAULT_PASSWORD: ${DEFAULT_PASSWORD}
USE_MINIO: ${USE_MINIO}
DEBUG: ${DEBUG}
depends_on:
- plane-db
- plane-redis
@ -65,6 +66,8 @@ services:
env_file:
- .env
environment:
DEBUG: ${DEBUG}
SENTRY_DSN: ${SENTRY_DSN}
DJANGO_SETTINGS_MODULE: plane.settings.production
DATABASE_URL: postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:5432/${PGDATABASE}
REDIS_URL: redis://plane-redis:6379/
@ -89,7 +92,6 @@ services:
DEFAULT_EMAIL: ${DEFAULT_EMAIL}
DEFAULT_PASSWORD: ${DEFAULT_PASSWORD}
USE_MINIO: ${USE_MINIO}
DEBUG: ${DEBUG}
depends_on:
- plane-api
- plane-db

View File

@ -38,6 +38,7 @@ services:
- .env
environment:
DEBUG: ${DEBUG}
SENTRY_DSN: ${SENTRY_DSN}
DJANGO_SETTINGS_MODULE: plane.settings.production
DATABASE_URL: postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:5432/${PGDATABASE}
REDIS_URL: redis://plane-redis:6379/
@ -80,6 +81,7 @@ services:
- .env
environment:
DEBUG: ${DEBUG}
SENTRY_DSN: ${SENTRY_DSN}
DJANGO_SETTINGS_MODULE: plane.settings.production
DATABASE_URL: postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:5432/${PGDATABASE}
REDIS_URL: redis://plane-redis:6379/