Skip to content

Commit

Permalink
Merge commit '5f4875cc6004485e47a91b36b0582d4740e23716' into preview
Browse files Browse the repository at this point in the history
  • Loading branch information
torbenraab committed Oct 10, 2024
2 parents d0658ce + 5f4875c commit 90da19b
Show file tree
Hide file tree
Showing 37 changed files with 251 additions and 195 deletions.
2 changes: 1 addition & 1 deletion admin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "admin",
"version": "0.23.0",
"version": "0.23.1",
"private": true,
"scripts": {
"dev": "turbo run develop",
Expand Down
2 changes: 1 addition & 1 deletion apiserver/package.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"name": "plane-api",
"version": "0.23.0"
"version": "0.23.1"
}
2 changes: 1 addition & 1 deletion apiserver/plane/api/views/inbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def patch(self, request, slug, project_id, issue_id):
)

# Only project admins and members can edit inbox issue attributes
if project_member.role > 5:
if project_member.role > 15:
serializer = InboxIssueSerializer(
inbox_issue, data=request.data, partial=True
)
Expand Down
4 changes: 2 additions & 2 deletions apiserver/plane/app/views/inbox/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ def create(self, request, slug, project_id):
serializer.errors, status=status.HTTP_400_BAD_REQUEST
)

@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
@allow_permission(allowed_roles=[ROLE.ADMIN], creator=True, model=Issue)
def partial_update(self, request, slug, project_id, pk):
inbox_id = Inbox.objects.filter(
workspace__slug=slug, project_id=project_id
Expand Down Expand Up @@ -418,7 +418,7 @@ def partial_update(self, request, slug, project_id, pk):
)

# Only project admins and members can edit inbox issue attributes
if project_member.role > 5:
if project_member.role > 15:
serializer = InboxIssueSerializer(
inbox_issue, data=request.data, partial=True
)
Expand Down
13 changes: 12 additions & 1 deletion apiserver/plane/app/views/project/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,20 @@ def create(self, request, slug):
status=status.HTTP_410_GONE,
)

@allow_permission([ROLE.ADMIN])
def partial_update(self, request, slug, pk=None):
try:
if not ProjectMember.objects.filter(
member=request.user,
workspace__slug=slug,
project_id=pk,
role=20,
is_active=True,
).exists():
return Response(
{"error": "You don't have the required permissions."},
status=status.HTTP_403_FORBIDDEN,
)

workspace = Workspace.objects.get(slug=slug)

project = Project.objects.get(pk=pk)
Expand Down
4 changes: 4 additions & 0 deletions apiserver/plane/celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
"task": "plane.bgtasks.deletion_task.hard_delete",
"schedule": crontab(hour=0, minute=0),
},
"run-every-6-hours-for-instance-trace": {
"task": "plane.license.bgtasks.tracer.instance_traces",
"schedule": crontab(hour="*/6"),
},
}

# Load task modules from all registered Django app configs.
Expand Down
2 changes: 1 addition & 1 deletion apiserver/requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# base requirements

# django
Django==4.2.15
Django==4.2.16
# rest framework
djangorestframework==3.15.2
# postgres
Expand Down
2 changes: 1 addition & 1 deletion live/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "live",
"version": "0.23.0",
"version": "0.23.1",
"description": "",
"main": "./src/server.ts",
"private": true,
Expand Down
15 changes: 0 additions & 15 deletions live/src/ce/lib/authentication.ts

This file was deleted.

8 changes: 1 addition & 7 deletions live/src/core/hocuspocus-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,26 @@ export const getHocusPocusServer = async () => {
name: serverName,
onAuthenticate: async ({
requestHeaders,
requestParameters,
connection,
// user id used as token for authentication
token,
}) => {
// request headers
const cookie = requestHeaders.cookie?.toString();
// params
const params = requestParameters;

if (!cookie) {
throw Error("Credentials not provided");
}

try {
await handleAuthentication({
connection,
cookie,
params,
token,
});
} catch (error) {
throw Error("Authentication unsuccessful!");
}
},
extensions,
debounce: 10000
debounce: 10000,
});
};
47 changes: 1 addition & 46 deletions live/src/core/lib/authentication.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,17 @@
import { ConnectionConfiguration } from "@hocuspocus/server";
// services
import { UserService } from "@/core/services/user.service.js";
// types
import { TDocumentTypes } from "@/core/types/common.js";
// plane live lib
import { authenticateUser } from "@/plane-live/lib/authentication.js";
// core helpers
import { manualLogger } from "@/core/helpers/logger.js";

const userService = new UserService();

type Props = {
connection: ConnectionConfiguration;
cookie: string;
params: URLSearchParams;
token: string;
};

export const handleAuthentication = async (props: Props) => {
const { connection, cookie, params, token } = props;
// params
const documentType = params.get("documentType")?.toString() as
| TDocumentTypes
| undefined;
const { cookie, token } = props;
// fetch current user info
let response;
try {
Expand All @@ -35,40 +24,6 @@ export const handleAuthentication = async (props: Props) => {
throw Error("Authentication failed: Token doesn't match the current user.");
}

if (documentType === "project_page") {
// params
const workspaceSlug = params.get("workspaceSlug")?.toString();
const projectId = params.get("projectId")?.toString();
if (!workspaceSlug || !projectId) {
throw Error(
"Authentication failed: Incomplete query params. Either workspaceSlug or projectId is missing."
);
}
// fetch current user's project membership info
try {
const projectMembershipInfo = await userService.getUserProjectMembership(
workspaceSlug,
projectId,
cookie
);
const projectRole = projectMembershipInfo.role;
// make the connection read only for roles lower than a member
if (projectRole < 15) {
connection.readOnly = true;
}
} catch (error) {
manualLogger.error("Failed to fetch project membership info:", error);
throw error;
}
} else {
await authenticateUser({
connection,
cookie,
documentType,
params,
});
}

return {
user: {
id: response.id,
Expand Down
35 changes: 1 addition & 34 deletions live/src/core/services/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// types
import type { IProjectMember, IUser } from "@plane/types";
import type { IUser } from "@plane/types";
// services
import { API_BASE_URL, APIService } from "@/core/services/api.service.js";

Expand All @@ -25,37 +25,4 @@ export class UserService extends APIService {
throw error;
});
}

async getUserWorkspaceMembership(
workspaceSlug: string,
cookie: string
): Promise<IProjectMember> {
return this.get(`/api/workspaces/${workspaceSlug}/workspace-members/me/`,
{
headers: {
Cookie: cookie,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}

async getUserProjectMembership(
workspaceSlug: string,
projectId: string,
cookie: string
): Promise<IProjectMember> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-members/me/`,
{
headers: {
Cookie: cookie,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"repository": "https://github.com/torbenraab/plane.git",
"version": "0.23.0",
"version": "0.23.1",
"license": "AGPL-3.0",
"private": true,
"workspaces": [
Expand Down
2 changes: 1 addition & 1 deletion packages/constants/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@plane/constants",
"version": "0.23.0",
"version": "0.23.1",
"private": true,
"main": "./index.ts"
}
2 changes: 1 addition & 1 deletion packages/editor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@plane/editor",
"version": "0.23.0",
"version": "0.23.1",
"description": "Core Editor that powers Plane",
"private": true,
"main": "./dist/index.mjs",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,10 @@ export const CustomImageBlock: React.FC<CustomImageBlockProps> = (props) => {
// show the image loader if the remote image's src or preview image from filesystem is not set yet (while loading the image post upload) (or)
// if the initial resize (from 35% width and "auto" height attrs to the actual size in px) is not complete
const showImageLoader = !(remoteImageSrc || imageFromFileSystem) || !initialResizeComplete;
// show the image utils only if the editor is editable, the remote image's (post upload) src is set and the initial resize is complete (but not while we're showing the preview imageFromFileSystem)
const showImageUtils = editor.isEditable && remoteImageSrc && initialResizeComplete;
// show the image utils only if the remote image's (post upload) src is set and the initial resize is complete (but not while we're showing the preview imageFromFileSystem)
const showImageUtils = remoteImageSrc && initialResizeComplete;
// show the image resizer only if the editor is editable, the remote image's (post upload) src is set and the initial resize is complete (but not while we're showing the preview imageFromFileSystem)
const showImageResizer = editor.isEditable && remoteImageSrc && initialResizeComplete;
// show the preview image from the file system if the remote image's src is not set
const displayedImageSrc = remoteImageSrc ?? imageFromFileSystem;

Expand Down Expand Up @@ -258,7 +260,7 @@ export const CustomImageBlock: React.FC<CustomImageBlockProps> = (props) => {
{selected && displayedImageSrc === remoteImageSrc && (
<div className="absolute inset-0 size-full bg-custom-primary-500/30" />
)}
{showImageUtils && (
{showImageResizer && (
<>
<div
className={cn(
Expand Down
2 changes: 1 addition & 1 deletion packages/editor/src/core/extensions/side-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const SideMenuExtension = (props: Props) => {
ai: aiEnabled,
dragDrop: dragDropEnabled,
},
scrollThreshold: { up: 300, down: 100 },
scrollThreshold: { up: 200, down: 100 },
}),
];
},
Expand Down
44 changes: 38 additions & 6 deletions packages/editor/src/core/plugins/drag-handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,46 @@ export const DragHandlePlugin = (options: SideMenuPluginProps): SideMenuHandleOp
dragHandleElement.addEventListener("click", (e) => handleClick(e, view));
dragHandleElement.addEventListener("contextmenu", (e) => handleClick(e, view));

const isScrollable = (node: HTMLElement | SVGElement) => {
if (!(node instanceof HTMLElement || node instanceof SVGElement)) {
return false;
}
const style = getComputedStyle(node);
return ["overflow", "overflow-y"].some((propertyName) => {
const value = style.getPropertyValue(propertyName);
return value === "auto" || value === "scroll";
});
};

const getScrollParent = (node: HTMLElement | SVGElement) => {
let currentParent = node.parentElement;
while (currentParent) {
if (isScrollable(currentParent)) {
return currentParent;
}
currentParent = currentParent.parentElement;
}
return document.scrollingElement || document.documentElement;
};

const maxScrollSpeed = 100;

dragHandleElement.addEventListener("drag", (e) => {
hideDragHandle();
const frameRenderer = document.querySelector(".frame-renderer");
if (!frameRenderer) return;
if (e.clientY < options.scrollThreshold.up) {
frameRenderer.scrollBy({ top: -70, behavior: "smooth" });
} else if (window.innerHeight - e.clientY < options.scrollThreshold.down) {
frameRenderer.scrollBy({ top: 70, behavior: "smooth" });
const scrollableParent = getScrollParent(dragHandleElement);
if (!scrollableParent) return;
const scrollThreshold = options.scrollThreshold;

if (e.clientY < scrollThreshold.up) {
const overflow = scrollThreshold.up - e.clientY;
const ratio = Math.min(overflow / scrollThreshold.up, 1);
const scrollAmount = -maxScrollSpeed * ratio;
scrollableParent.scrollBy({ top: scrollAmount });
} else if (window.innerHeight - e.clientY < scrollThreshold.down) {
const overflow = e.clientY - (window.innerHeight - scrollThreshold.down);
const ratio = Math.min(overflow / scrollThreshold.down, 1);
const scrollAmount = maxScrollSpeed * ratio;
scrollableParent.scrollBy({ top: scrollAmount });
}
});

Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-config/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@plane/eslint-config",
"private": true,
"version": "0.23.0",
"version": "0.23.1",
"files": [
"library.js",
"next.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/helpers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@plane/helpers",
"version": "0.23.0",
"version": "0.23.1",
"description": "Helper functions shared across multiple apps internally",
"private": true,
"main": "./dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/tailwind-config-custom/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tailwind-config-custom",
"version": "0.23.0",
"version": "0.23.1",
"description": "common tailwind configuration across monorepo",
"main": "index.js",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/types/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@plane/types",
"version": "0.23.0",
"version": "0.23.1",
"private": true,
"types": "./src/index.d.ts",
"main": "./src/index.d.ts"
Expand Down
Loading

0 comments on commit 90da19b

Please sign in to comment.