mirror of
https://github.com/matrix-org/matrix-hookshot.git
synced 2025-03-10 13:17:08 +00:00
Add support for deleting connections
This commit is contained in:
parent
9140c4d1bc
commit
95e23473b2
@ -435,8 +435,8 @@ export class Bridge {
|
||||
);
|
||||
connManager.push(discussionConnection);
|
||||
} catch (ex) {
|
||||
log.error(ex);
|
||||
throw Error('Failed to create discussion room');
|
||||
log.error("Failed to create discussion room", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,11 +351,12 @@ export class ConnectionManager {
|
||||
return this.connections.filter((c) => (c instanceof GitLabRepoConnection && c.path === pathWithNamespace)) as GitLabRepoConnection[];
|
||||
}
|
||||
|
||||
public getConnectionsForJiraProject(project: JiraProject, eventName: string): JiraProjectConnection[] {
|
||||
public getConnectionsForJiraProject(project: {id: string, self: string, key: string}, eventName?: string): JiraProjectConnection[] {
|
||||
return this.connections.filter((c) =>
|
||||
(c instanceof JiraProjectConnection &&
|
||||
c.interestedInProject(project) &&
|
||||
c.isInterestedInHookEvent(eventName))) as JiraProjectConnection[];
|
||||
(!eventName || c.isInterestedInHookEvent(eventName))
|
||||
)) as JiraProjectConnection[];
|
||||
}
|
||||
|
||||
|
||||
@ -388,12 +389,12 @@ export class ConnectionManager {
|
||||
return this.connections.find((c) => c.connectionId === connectionId && c.roomId === roomId);
|
||||
}
|
||||
|
||||
public async purgeConnection(roomId: string, connectionId: string, requireNoRemoveHandler = true) {
|
||||
public async purgeConnection(roomId: string, connectionId: string, requireRemoveHandler = true) {
|
||||
const connection = this.connections.find((c) => c.connectionId === connectionId && c.roomId == roomId);
|
||||
if (!connection) {
|
||||
throw Error("Connection not found");
|
||||
}
|
||||
if (requireNoRemoveHandler && !connection.onRemove) {
|
||||
if (requireRemoveHandler && !connection.onRemove) {
|
||||
throw Error("Connection doesn't support removal, and so cannot be safely removed");
|
||||
}
|
||||
await connection.onRemove?.();
|
||||
|
@ -487,7 +487,13 @@ export class GitHubRepoConnection extends CommandConnection implements IConnecti
|
||||
}
|
||||
const orgRepoName = event.repository.full_name;
|
||||
|
||||
let message = `**${event.issue.user.login}** created new issue [${orgRepoName}#${event.issue.number}](${event.issue.html_url}): "${event.issue.title}"`;
|
||||
let actionText = "created new issue"
|
||||
if (event.issue.comments > 0) {
|
||||
// This was tranferred
|
||||
actionText = "transferred issue"
|
||||
}
|
||||
|
||||
let message = `**${event.issue.user.login}** ${actionText} [${orgRepoName}#${event.issue.number}](${event.issue.html_url}): "${event.issue.title}"`;
|
||||
message += (event.issue.assignee ? ` assigned to ${event.issue.assignee.login}` : '');
|
||||
if (this.showIssueRoomLink) {
|
||||
const appInstance = await this.githubInstance.getSafeOctokitForRepo(this.org, this.repo);
|
||||
|
@ -109,7 +109,7 @@ export class JiraProjectConnection extends CommandConnection implements IConnect
|
||||
return !this.state.events || this.state.events?.includes(eventName as JiraAllowedEventsNames);
|
||||
}
|
||||
|
||||
public interestedInProject(project: JiraProject) {
|
||||
public interestedInProject(project: {id: string, self: string, key: string}) {
|
||||
if (this.projectId === project.id) {
|
||||
return true;
|
||||
}
|
||||
|
@ -13,8 +13,11 @@ import markdown from "markdown-it";
|
||||
import { FigmaFileConnection } from "./FigmaFileConnection";
|
||||
import { URL } from "url";
|
||||
import { AdminRoom } from "../AdminRoom";
|
||||
import { ConnectionManager } from "../ConnectionManager";
|
||||
const md = new markdown();
|
||||
|
||||
const GITHUB_REGEX = /^https:\/\/github\.com\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/;
|
||||
const JIRA_REGEX = /.+\/projects\/(\w+)\/?(\w+\/?)*$/;
|
||||
/**
|
||||
* Handles setting up a room with connections. This connection is "virtual" in that it has
|
||||
* no state, and is only invoked when messages from other clients fall through.
|
||||
@ -28,6 +31,7 @@ export class SetupConnection extends CommandConnection {
|
||||
private readonly as: Appservice,
|
||||
private readonly tokenStore: UserTokenStore,
|
||||
private readonly config: BridgeConfig,
|
||||
private readonly connectionManager: ConnectionManager,
|
||||
private readonly getOrCreateAdminRoom: (userId: string) => Promise<AdminRoom>,
|
||||
private readonly githubInstance?: GithubInstance,) {
|
||||
super(
|
||||
@ -59,7 +63,7 @@ export class SetupConnection extends CommandConnection {
|
||||
if (!octokit) {
|
||||
throw new CommandError("User not logged in", "You are not logged into GitHub. Start a DM with this bot and use the command `github login`.");
|
||||
}
|
||||
const urlParts = /^https:\/\/github\.com\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/.exec(url.trim().toLowerCase());
|
||||
const urlParts = GITHUB_REGEX.exec(url.trim().toLowerCase());
|
||||
if (!urlParts) {
|
||||
throw new CommandError("Invalid GitHub url", "The GitHub url you entered was not valid");
|
||||
}
|
||||
@ -69,6 +73,38 @@ export class SetupConnection extends CommandConnection {
|
||||
await this.as.botClient.sendNotice(this.roomId, `Room configured to bridge ${org}/${repo}`);
|
||||
}
|
||||
|
||||
@botCommand("remove github repo", "Remove a GitHub repository connection.", ["url"], [], true)
|
||||
public async onRemoveGitHubRepo(userId: string, url: string) {
|
||||
if (!this.githubInstance || !this.config.github) {
|
||||
throw new CommandError("not-configured", "The bridge is not configured to support GitHub");
|
||||
}
|
||||
if (!this.config.checkPermission(userId, "github", BridgePermissionLevel.manageConnections)) {
|
||||
throw new CommandError('You are not permitted to remove connections for GitHub');
|
||||
}
|
||||
if (!await this.as.botClient.userHasPowerLevelFor(userId, this.roomId, "", true)) {
|
||||
throw new CommandError("not-configured", "You must be able to set state in a room ('Change settings') in order to remove integrations.");
|
||||
}
|
||||
if (!await this.as.botClient.userHasPowerLevelFor(this.as.botUserId, this.roomId, GitHubRepoConnection.CanonicalEventType, true)) {
|
||||
throw new CommandError("Bot lacks power level to set room state", "I do not have permission to remove a bridge in this room. Please promote me to an Admin/Moderator");
|
||||
}
|
||||
const urlParts = GITHUB_REGEX.exec(url.trim().toLowerCase());
|
||||
if (!urlParts) {
|
||||
throw new CommandError("Invalid GitHub url", "The GitHub url you entered was not valid");
|
||||
}
|
||||
const [, org, repo] = urlParts;
|
||||
const connections = await this.connectionManager.getConnectionsForGithubRepo(org, repo);
|
||||
for (const connection of connections) {
|
||||
await this.connectionManager.purgeConnection(connection.roomId, connection.connectionId, false);
|
||||
}
|
||||
if (connections.length === 0) {
|
||||
throw new CommandError("no-connections-found", "No connections found matching that url");
|
||||
} else if (connections.length === 1) {
|
||||
await this.as.botClient.sendNotice(this.roomId, `Removed connection from this room`);
|
||||
} else {
|
||||
await this.as.botClient.sendNotice(this.roomId, `Removed ${connections.length} connections from this room`);
|
||||
}
|
||||
}
|
||||
|
||||
@botCommand("jira project", "Create a connection for a JIRA project. (You must be logged in with JIRA to do this)", ["url"], [], true)
|
||||
public async onJiraProject(userId: string, urlStr: string) {
|
||||
const url = new URL(urlStr);
|
||||
@ -88,7 +124,7 @@ export class SetupConnection extends CommandConnection {
|
||||
if (!jiraClient) {
|
||||
throw new CommandError("User not logged in", "You are not logged into Jira. Start a DM with this bot and use the command `jira login`.");
|
||||
}
|
||||
const urlParts = /.+\/projects\/(\w+)\/?(\w+\/?)*$/.exec(url.pathname.toLowerCase());
|
||||
const urlParts = JIRA_REGEX.exec(url.pathname.toLowerCase());
|
||||
const projectKey = urlParts?.[1] || url.searchParams.get('projectKey');
|
||||
if (!projectKey) {
|
||||
throw new CommandError("Invalid Jira url", "The JIRA project url you entered was not valid. It should be in the format of `https://jira-instance/.../projects/PROJECTKEY/...` or `.../RapidBoard.jspa?projectKey=TEST`");
|
||||
@ -99,6 +135,44 @@ export class SetupConnection extends CommandConnection {
|
||||
await this.as.botClient.sendNotice(this.roomId, `Room configured to bridge Jira project ${res.connection.projectKey}`);
|
||||
}
|
||||
|
||||
@botCommand("remove jira project", "Remove a GitHub repository connection.", ["url"], [], true)
|
||||
public async onRemoveJiraProject(userId: string, urlStr: string) {
|
||||
const url = new URL(urlStr);
|
||||
if (!this.config.jira) {
|
||||
throw new CommandError("not-configured", "The bridge is not configured to support Jira");
|
||||
}
|
||||
if (!this.config.checkPermission(userId, "jira", BridgePermissionLevel.manageConnections)) {
|
||||
throw new CommandError('You are not permitted to remove connections for Jira');
|
||||
}
|
||||
if (!await this.as.botClient.userHasPowerLevelFor(userId, this.roomId, "", true)) {
|
||||
throw new CommandError("not-configured", "You must be able to set state in a room ('Change settings') in order to remove connections.");
|
||||
}
|
||||
if (!await this.as.botClient.userHasPowerLevelFor(this.as.botUserId, this.roomId, GitHubRepoConnection.CanonicalEventType, true)) {
|
||||
throw new CommandError("Bot lacks power level to set room state", "I do not have permission to remove a connection in this room. Please promote me to an Admin/Moderator");
|
||||
}
|
||||
const urlParts = JIRA_REGEX.exec(url.pathname.toLowerCase());
|
||||
const projectKey = urlParts?.[1] || url.searchParams.get('projectKey');
|
||||
if (!projectKey) {
|
||||
throw new CommandError("Invalid Jira url", "The JIRA project url you entered was not valid. It should be in the format of `https://jira-instance/.../projects/PROJECTKEY/...` or `.../RapidBoard.jspa?projectKey=TEST`");
|
||||
}
|
||||
const safeUrl = `https://${url.host}/projects/${projectKey}`;
|
||||
const connections = await this.connectionManager.getConnectionsForJiraProject({
|
||||
id: "none",
|
||||
self: safeUrl,
|
||||
key: projectKey,
|
||||
});
|
||||
for (const connection of connections) {
|
||||
await this.connectionManager.purgeConnection(connection.roomId, connection.connectionId, false);
|
||||
}
|
||||
if (connections.length === 0) {
|
||||
throw new CommandError("no-connections-found", "No connections found matching that url");
|
||||
} else if (connections.length === 1) {
|
||||
await this.as.botClient.sendNotice(this.roomId, `Removed connection from this room`);
|
||||
} else {
|
||||
await this.as.botClient.sendNotice(this.roomId, `Removed ${connections.length} connections from this room`);
|
||||
}
|
||||
}
|
||||
|
||||
@botCommand("webhook", "Create an inbound webhook", ["name"], [], true)
|
||||
public async onWebhook(userId: string, name: string) {
|
||||
if (!this.config.generic?.enabled) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user