chore: added support for saving a createdBy field

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2022-02-11 03:46:02 +01:00
parent 0ac523dd02
commit be2d445177
4 changed files with 81 additions and 2 deletions
@@ -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);