chore: added support for saving a createdBy field
Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
@@ -85,6 +85,32 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
this.db = options.database;
|
||||
}
|
||||
|
||||
async list(options: Partial<SerializedTask>): Promise<SerializedTask[]> {
|
||||
const results = await this.db<RawDbTaskRow>('tasks')
|
||||
.where({
|
||||
created_by: options.createdBy,
|
||||
})
|
||||
.orderBy('created_at', 'desc')
|
||||
.select();
|
||||
|
||||
return results.map(result => ({
|
||||
id: result.id,
|
||||
spec: JSON.parse(result.spec),
|
||||
status: result.status,
|
||||
createdBy: result.created_by,
|
||||
lastHeartbeatAt:
|
||||
typeof result.last_heartbeat_at === 'string'
|
||||
? DateTime.fromSQL(result.last_heartbeat_at, {
|
||||
zone: 'UTC',
|
||||
}).toISO()
|
||||
: result.last_heartbeat_at,
|
||||
createdAt:
|
||||
typeof result.created_at === 'string'
|
||||
? DateTime.fromSQL(result.created_at, { zone: 'UTC' }).toISO()
|
||||
: result.created_at,
|
||||
}));
|
||||
}
|
||||
|
||||
async getTask(taskId: string): Promise<SerializedTask> {
|
||||
const [result] = await this.db<RawDbTaskRow>('tasks')
|
||||
.where({ id: taskId })
|
||||
@@ -99,8 +125,16 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
id: result.id,
|
||||
spec,
|
||||
status: result.status,
|
||||
lastHeartbeatAt: result.last_heartbeat_at,
|
||||
createdAt: result.created_at,
|
||||
lastHeartbeatAt:
|
||||
typeof result.last_heartbeat_at === 'string'
|
||||
? DateTime.fromSQL(result.last_heartbeat_at, {
|
||||
zone: 'UTC',
|
||||
}).toISO()
|
||||
: result.last_heartbeat_at,
|
||||
createdAt:
|
||||
typeof result.created_at === 'string'
|
||||
? DateTime.fromSQL(result.created_at, { zone: 'UTC' }).toISO()
|
||||
: result.created_at,
|
||||
createdBy: result.created_by ?? undefined,
|
||||
secrets,
|
||||
};
|
||||
@@ -119,6 +153,7 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
secrets: options.secrets ? JSON.stringify(options.secrets) : undefined,
|
||||
created_by: options.createdBy ?? null,
|
||||
status: 'open',
|
||||
created_by: ('createdBy' in spec && spec.createdBy) || null,
|
||||
});
|
||||
return { taskId };
|
||||
}
|
||||
|
||||
@@ -150,6 +150,15 @@ export class StorageTaskBroker implements TaskBroker {
|
||||
private readonly storage: TaskStore,
|
||||
private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
async list(options?: Partial<SerializedTask>): Promise<SerializedTask[]> {
|
||||
if (!options || !options.createdBy) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
return await this.storage.list({ createdBy: options.createdBy });
|
||||
}
|
||||
|
||||
private deferredDispatch = defer();
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,7 @@ export type SerializedTask = {
|
||||
lastHeartbeatAt?: string;
|
||||
createdBy?: string;
|
||||
secrets?: TaskSecrets;
|
||||
createdBy: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -132,6 +133,7 @@ export interface TaskBroker {
|
||||
after: number | undefined;
|
||||
}): Observable<{ events: SerializedTaskEvent[] }>;
|
||||
get(taskId: string): Promise<SerializedTask>;
|
||||
list(options?: Partial<SerializedTask>): Promise<SerializedTask[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,6 +194,7 @@ export interface TaskStore {
|
||||
listStaleTasks(options: { timeoutS: number }): Promise<{
|
||||
tasks: { taskId: string }[];
|
||||
}>;
|
||||
list(options: Partial<SerializedTask>): Promise<SerializedTask[]>;
|
||||
|
||||
emitLogEvent({ taskId, body }: TaskStoreEmitOptions): Promise<void>;
|
||||
listEvents({
|
||||
|
||||
@@ -129,6 +129,19 @@ export async function createRouter(
|
||||
actionsToRegister.forEach(action => actionRegistry.register(action));
|
||||
workers.forEach(worker => worker.start());
|
||||
|
||||
const getUserEntityRefFromToken = (backstageToken: string) => {
|
||||
try {
|
||||
const [_header, payload, _signature] = backstageToken.split('.');
|
||||
const parsedToken = JSON.parse(Buffer.from(payload, 'base64').toString());
|
||||
|
||||
return parsedToken.sub;
|
||||
} catch (e) {
|
||||
logger.warn('Could not parse token from request to create template');
|
||||
logger.debug(e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
router
|
||||
.get(
|
||||
'/v2/templates/:namespace/:kind/:name/parameter-schema',
|
||||
@@ -207,6 +220,8 @@ export async function createRouter(
|
||||
|
||||
const baseUrl = getEntityBaseUrl(template);
|
||||
|
||||
const createdBy = token && getUserEntityRefFromToken(token);
|
||||
|
||||
const taskSpec: TaskSpec = {
|
||||
apiVersion: template.apiVersion,
|
||||
steps: template.spec.steps.map((step, index) => ({
|
||||
@@ -228,6 +243,7 @@ export async function createRouter(
|
||||
}),
|
||||
baseUrl,
|
||||
},
|
||||
createdBy,
|
||||
};
|
||||
|
||||
const result = await taskBroker.dispatch({
|
||||
@@ -241,6 +257,22 @@ export async function createRouter(
|
||||
|
||||
res.status(201).json({ id: result.taskId });
|
||||
})
|
||||
.get('/v2/tasks', async (req, res) => {
|
||||
const token = getBearerToken(req.headers.authorization);
|
||||
const userEntityRef = token && getUserEntityRefFromToken(token);
|
||||
|
||||
if (!userEntityRef) {
|
||||
throw new InputError(
|
||||
'Could not find a valid user entity ref in the request',
|
||||
);
|
||||
}
|
||||
|
||||
const tasks = await taskBroker.list({
|
||||
createdBy: userEntityRef,
|
||||
});
|
||||
|
||||
res.status(200).json(tasks);
|
||||
})
|
||||
.get('/v2/tasks/:taskId', async (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = await taskBroker.get(taskId);
|
||||
|
||||
Reference in New Issue
Block a user