Repository: twentyhq/twenty
File: packages/twenty-server/src/engine/metadata-modules/view-permissions/services/view-access.service.ts (TypeScript)

Code before:
  ): Promise<boolean> {
    const permissions = isDefined(userWorkspaceId)
      ? await this.permissionsService.getUserWorkspacePermissions({
          userWorkspaceId,
          workspaceId,
        })
      : null;

    const hasViewsPermission =
      permissions?.permissionFlags[PermissionFlagType.VIEWS] ?? false;

    // Users with VIEWS permission can manipulate all views
    if (hasViewsPermission) {
      return true;
    }

    // API keys with VIEWS permission can manipulate workspace views
    // (userWorkspaceId is undefined for API keys, and createdByUserWorkspaceId is null for workspace views created by API keys)
    if (
      !isDefined(userWorkspaceId) &&
      !isDefined(view.createdByUserWorkspaceId) &&
      view.visibility === ViewVisibility.WORKSPACE
    ) {
      return true;
    }

    // Users without VIEWS permission can only manipulate their own unlisted views
    const canAccess =
      view.visibility === ViewVisibility.UNLISTED &&
      view.createdByUserWorkspaceId === userWorkspaceId;

    if (!canAccess) {
      throw new ViewException(
        generateViewExceptionMessage(
          ViewExceptionMessageKey.VIEW_MODIFY_PERMISSION_DENIED,
        ),
        ViewExceptionCode.VIEW_MODIFY_PERMISSION_DENIED,
        {
          userFriendlyMessage: generateViewUserFriendlyExceptionMessage(
            ViewExceptionMessageKey.VIEW_MODIFY_PERMISSION_DENIED,
          ),
        },
      );
    }

    return true;
  }
}


Review comment (suggestion):
The condition checks if both `userWorkspaceId` and `view.createdByUserWorkspaceId` are undefined/null. However, the comment states that API keys can manipulate workspace views they created, but this logic allows API keys to manipulate ANY workspace view created by any API key (where `createdByUserWorkspaceId` is null). Consider adding an API key identifier check to ensure API keys can only manage views they specifically created.
```suggestion

```

Code after:
            ),
          },
        );
      }
    }

    // For UNLISTED views, allow creation
    return true;
  }

  private async checkViewAccess(
    view: ViewEntity,
    userWorkspaceId: string | undefined,
    workspaceId: string,
    apiKeyId?: string,
  ): Promise<boolean> {
    let hasViewsPermission = false;

    if (isDefined(userWorkspaceId)) {
      const permissions =
        await this.permissionsService.getUserWorkspacePermissions({
          userWorkspaceId,
          workspaceId,
        });

      hasViewsPermission =
        permissions.permissionFlags[PermissionFlagType.VIEWS] ?? false;
    } else if (isDefined(apiKeyId)) {
      hasViewsPermission =
        await this.permissionsService.userHasWorkspaceSettingPermission({
          workspaceId,
          apiKeyId,
          setting: PermissionFlagType.VIEWS,
        });
    }

    // Users/API keys with VIEWS permission can manipulate all views
    if (hasViewsPermission) {
      return true;
    }

    // Users without VIEWS permission can only manipulate their own unlisted views
    const canAccess =
      view.visibility === ViewVisibility.UNLISTED &&
      view.createdByUserWorkspaceId === userWorkspaceId;

    if (!canAccess) {
      throw new ViewException(
        generateViewExceptionMessage(
          ViewExceptionMessageKey.VIEW_MODIFY_PERMISSION_DENIED,
        ),