address review comments
Signed-off-by: Kashish Mittal <kmittal@redhat.com>
This commit is contained in:
@@ -11,7 +11,6 @@ import { PermissionCriteria } from '@backstage/plugin-permission-common';
|
||||
import { PermissionRule } from '@backstage/plugin-permission-node';
|
||||
import { ResourcePermission } from '@backstage/plugin-permission-common';
|
||||
import { SerializedTask } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskFilter } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateEntityStepV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
|
||||
@@ -89,7 +88,7 @@ export const scaffolderTaskConditions: Conditions<{
|
||||
hasCreatedBy: PermissionRule<
|
||||
SerializedTask,
|
||||
{
|
||||
property: TaskFilter['property'];
|
||||
key: string;
|
||||
values: any;
|
||||
},
|
||||
'scaffolder-task',
|
||||
|
||||
@@ -329,8 +329,6 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
// (undocumented)
|
||||
getTask(taskId: string): Promise<SerializedTask>;
|
||||
// (undocumented)
|
||||
getTasks(taskIds: string[]): Promise<SerializedTask_2[]>;
|
||||
// (undocumented)
|
||||
getTaskState({ taskId }: { taskId: string }): Promise<
|
||||
| {
|
||||
state: JsonObject;
|
||||
@@ -485,8 +483,6 @@ export interface TaskStore {
|
||||
// (undocumented)
|
||||
getTask(taskId: string): Promise<SerializedTask>;
|
||||
// (undocumented)
|
||||
getTasks(taskIds: string[]): Promise<SerializedTask[]>;
|
||||
// (undocumented)
|
||||
getTaskState?({ taskId }: { taskId: string }): Promise<
|
||||
| {
|
||||
state: JsonObject;
|
||||
|
||||
@@ -263,7 +263,7 @@ describe('DatabaseTaskStore', () => {
|
||||
|
||||
const permissionFilters: PermissionCriteria<TaskFilters> = {
|
||||
not: {
|
||||
property: 'createdBy',
|
||||
key: 'created_by',
|
||||
values: ['user:default/three', 'user:default/four'],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -205,7 +205,7 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
}
|
||||
|
||||
private isTaskFilter(filter: any): filter is TaskFilter {
|
||||
return filter.hasOwnProperty('property');
|
||||
return filter.hasOwnProperty('key');
|
||||
}
|
||||
|
||||
private parseFilter(
|
||||
@@ -214,20 +214,16 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
db: Knex,
|
||||
negate: boolean = false,
|
||||
): Knex.QueryBuilder {
|
||||
// handle not criteria
|
||||
if (isNotCriteria(filter)) {
|
||||
return this.parseFilter(filter.not, query, db, !negate);
|
||||
}
|
||||
|
||||
if (this.isTaskFilter(filter)) {
|
||||
const values: string[] = compact(filter.values) ?? [];
|
||||
|
||||
if (filter.property === 'createdBy') {
|
||||
if (negate) {
|
||||
query.whereNotIn('created_by', [...new Set(values)]);
|
||||
} else {
|
||||
query.whereIn('created_by', [...new Set(values)]);
|
||||
}
|
||||
if (negate) {
|
||||
query.whereNotIn(filter.key, values);
|
||||
} else {
|
||||
query.whereIn(filter.key, values);
|
||||
}
|
||||
|
||||
return query;
|
||||
@@ -279,7 +275,7 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
createdByValues.length > 0
|
||||
? {
|
||||
allOf: [
|
||||
{ property: 'createdBy', values: createdByValues },
|
||||
{ key: 'created_by', values: createdByValues },
|
||||
...(permissionFilters ? [permissionFilters] : []),
|
||||
],
|
||||
}
|
||||
@@ -347,22 +343,6 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
}
|
||||
}
|
||||
|
||||
async getTasks(taskIds: string[]): Promise<SerializedTask[]> {
|
||||
const results = await this.db<RawDbTaskRow>('tasks')
|
||||
.whereIn('id', taskIds)
|
||||
.select();
|
||||
|
||||
return results.map(result => {
|
||||
try {
|
||||
return this.parseTaskRow(result);
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to parse spec of task '${result.id}', ${error}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private parseTaskRow(result: RawDbTaskRow): SerializedTask {
|
||||
const spec = JSON.parse(result.spec);
|
||||
const secrets = result.secrets ? JSON.parse(result.secrets) : undefined;
|
||||
|
||||
@@ -403,13 +403,6 @@ export class StorageTaskBroker implements TaskBroker {
|
||||
return this.storage.getTask(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc TaskBroker.getTasks}
|
||||
*/
|
||||
getTasks(taskIds: string[]): Promise<SerializedTask[]> {
|
||||
return this.storage.getTasks(taskIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc TaskBroker.event$}
|
||||
*/
|
||||
|
||||
@@ -110,8 +110,6 @@ export interface TaskStore {
|
||||
|
||||
getTask(taskId: string): Promise<SerializedTask>;
|
||||
|
||||
getTasks(taskIds: string[]): Promise<SerializedTask[]>;
|
||||
|
||||
claimTask(): Promise<SerializedTask | undefined>;
|
||||
|
||||
completeTask(options: {
|
||||
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
import { PermissionRuleParams } from '@backstage/plugin-permission-common';
|
||||
import {
|
||||
SerializedTask,
|
||||
TaskFilter,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
|
||||
/**
|
||||
@@ -82,8 +81,8 @@ export type TaskPermissionRuleInput<
|
||||
> = PermissionRule<
|
||||
SerializedTask,
|
||||
{
|
||||
property: TaskFilter['property'];
|
||||
values: any;
|
||||
key: string;
|
||||
values?: string[];
|
||||
},
|
||||
typeof RESOURCE_TYPE_SCAFFOLDER_TASK,
|
||||
TParams
|
||||
|
||||
@@ -136,6 +136,7 @@ import {
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
|
||||
/**
|
||||
|
||||
* RouterOptions
|
||||
*/
|
||||
export interface RouterOptions {
|
||||
@@ -366,7 +367,6 @@ export async function createRouter(
|
||||
resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK,
|
||||
permissions: scaffolderTaskPermissions,
|
||||
rules: taskRules,
|
||||
getResources: resourceRefs => taskBroker.getTasks(resourceRefs),
|
||||
},
|
||||
],
|
||||
permissions: scaffolderPermissions,
|
||||
|
||||
@@ -586,7 +586,7 @@ describe('hasCreatedBy', () => {
|
||||
hasCreatedBy.toQuery({
|
||||
createdBy: ['user:default/user-1'],
|
||||
}),
|
||||
).toEqual({ property: 'createdBy', values: ['user:default/user-1'] });
|
||||
).toEqual({ key: 'created_by', values: ['user:default/user-1'] });
|
||||
});
|
||||
});
|
||||
it('returns the correct query filter with values (multiple users in createdBy)', () => {
|
||||
@@ -595,7 +595,7 @@ describe('hasCreatedBy', () => {
|
||||
createdBy: ['user:default/user-1', 'user:default/user-2'],
|
||||
}),
|
||||
).toEqual({
|
||||
property: 'createdBy',
|
||||
key: 'created_by',
|
||||
values: ['user:default/user-1', 'user:default/user-2'],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
TemplateParametersV1beta3,
|
||||
} from '@backstage/plugin-scaffolder-common';
|
||||
|
||||
import { SerializedTask, TaskFilter } from '@backstage/plugin-scaffolder-node';
|
||||
import { SerializedTask } from '@backstage/plugin-scaffolder-node';
|
||||
|
||||
import { z } from 'zod';
|
||||
import { JsonObject, JsonPrimitive } from '@backstage/types';
|
||||
@@ -136,7 +136,7 @@ function buildHasProperty<Schema extends z.ZodType<JsonPrimitive>>({
|
||||
export const createTaskPermissionRule = makeCreatePermissionRule<
|
||||
SerializedTask,
|
||||
{
|
||||
property: TaskFilter['property'];
|
||||
key: string;
|
||||
values: any;
|
||||
},
|
||||
typeof RESOURCE_TYPE_SCAFFOLDER_TASK
|
||||
@@ -161,7 +161,7 @@ export const hasCreatedBy = createTaskPermissionRule({
|
||||
},
|
||||
toQuery: ({ createdBy }) => {
|
||||
return {
|
||||
property: 'createdBy' as TaskFilter['property'],
|
||||
key: 'created_by',
|
||||
values: createdBy,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -361,8 +361,6 @@ export interface TaskBroker {
|
||||
// (undocumented)
|
||||
get(taskId: string): Promise<SerializedTask>;
|
||||
// (undocumented)
|
||||
getTasks(taskIds: string[]): Promise<SerializedTask[]>;
|
||||
// (undocumented)
|
||||
list?(options?: {
|
||||
filters?: {
|
||||
createdBy?: string | string[];
|
||||
@@ -470,8 +468,8 @@ export type TaskEventType = 'completion' | 'log' | 'cancelled' | 'recovered';
|
||||
|
||||
// @public
|
||||
export type TaskFilter = {
|
||||
property: 'createdBy';
|
||||
values: Array<string> | undefined;
|
||||
key: string;
|
||||
values?: Array<string> | undefined;
|
||||
};
|
||||
|
||||
// @public
|
||||
|
||||
@@ -110,8 +110,8 @@ export type TaskBrokerDispatchOptions = {
|
||||
* @public
|
||||
*/
|
||||
export type TaskFilter = {
|
||||
property: 'createdBy';
|
||||
values: Array<string> | undefined;
|
||||
key: string;
|
||||
values?: Array<string> | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -204,8 +204,6 @@ export interface TaskBroker {
|
||||
|
||||
get(taskId: string): Promise<SerializedTask>;
|
||||
|
||||
getTasks(taskIds: string[]): Promise<SerializedTask[]>;
|
||||
|
||||
list?(options?: {
|
||||
filters?: {
|
||||
createdBy?: string | string[];
|
||||
|
||||
@@ -161,16 +161,6 @@ describe('OngoingTask', () => {
|
||||
await expect(rendered.findByText('Hide Logs')).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render not found error page when user does not have permission to read the task', async () => {
|
||||
const permissionApi = mockApis.permission({
|
||||
authorize: AuthorizeResult.DENY,
|
||||
});
|
||||
|
||||
await expect(render(permissionApi)).rejects.toThrow(
|
||||
'Reached NotFound Page',
|
||||
);
|
||||
});
|
||||
|
||||
it('should have cancel button be disabled when user has read permission but lacks cancel permission', async () => {
|
||||
const permissionApi = mockApis.permission({
|
||||
authorize: request => {
|
||||
|
||||
@@ -46,7 +46,7 @@ import {
|
||||
TaskSteps,
|
||||
} from '@backstage/plugin-scaffolder-react/alpha';
|
||||
import { useAsync } from '@react-hookz/web';
|
||||
import { usePermission} from '@backstage/plugin-permission-react';
|
||||
import { usePermission } from '@backstage/plugin-permission-react';
|
||||
import {
|
||||
taskCancelPermission,
|
||||
taskCreatePermission,
|
||||
|
||||
Reference in New Issue
Block a user