mirror of
https://github.com/docmost/docmost.git
synced 2026-05-20 00:14:10 +08:00
fix
This commit is contained in:
@@ -18,6 +18,8 @@ const providerIcons: Record<string, string> = {
|
|||||||
gitlab: "https://gitlab.com/assets/favicon-72a2cad5025aa931d6ea56c3201d1f18e68a8571da3c2571592f63571e0c5571.png",
|
gitlab: "https://gitlab.com/assets/favicon-72a2cad5025aa931d6ea56c3201d1f18e68a8571da3c2571592f63571e0c5571.png",
|
||||||
jira: "https://wac-cdn.atlassian.com/assets/img/favicons/atlassian/favicon.png",
|
jira: "https://wac-cdn.atlassian.com/assets/img/favicons/atlassian/favicon.png",
|
||||||
linear: "https://linear.app/favicon.ico",
|
linear: "https://linear.app/favicon.ico",
|
||||||
|
google_docs: "https://ssl.gstatic.com/docs/documents/images/kix-favicon7.ico",
|
||||||
|
figma: "https://static.figma.com/app/icon/1/favicon.png",
|
||||||
};
|
};
|
||||||
|
|
||||||
function IntegrationLinkView(props: any) {
|
function IntegrationLinkView(props: any) {
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ export enum IntegrationType {
|
|||||||
GITLAB = 'gitlab',
|
GITLAB = 'gitlab',
|
||||||
JIRA = 'jira',
|
JIRA = 'jira',
|
||||||
LINEAR = 'linear',
|
LINEAR = 'linear',
|
||||||
|
GOOGLE_DOCS = 'google_docs',
|
||||||
|
FIGMA = 'figma',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,11 +75,11 @@ export class OAuthController {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const appUrl = this.environmentService.getAppUrl();
|
const appUrl = this.environmentService.getAppUrl();
|
||||||
return res.redirect(`${appUrl}/settings/integrations`);
|
return res.redirect(`${appUrl}/settings/integrations`, 302).send();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error(`OAuth callback error for ${type}: ${(err as Error).message}`);
|
this.logger.error(`OAuth callback error for ${type}: ${(err as Error).message}`);
|
||||||
const appUrl = this.environmentService.getAppUrl();
|
const appUrl = this.environmentService.getAppUrl();
|
||||||
return res.redirect(`${appUrl}/settings/integrations?error=oauth_failed`);
|
return res.redirect(`${appUrl}/settings/integrations?error=oauth_failed`, 302).send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ import { IntegrationRegistry } from '../registry/integration-registry';
|
|||||||
import { IntegrationConnectionRepo } from '../repos/integration-connection.repo';
|
import { IntegrationConnectionRepo } from '../repos/integration-connection.repo';
|
||||||
import { IntegrationRepo } from '../repos/integration.repo';
|
import { IntegrationRepo } from '../repos/integration.repo';
|
||||||
import { OAuthService } from '../oauth/oauth.service';
|
import { OAuthService } from '../oauth/oauth.service';
|
||||||
import { UnfurlResult, IntegrationProvider } from '../registry/integration-provider.interface';
|
import {
|
||||||
|
UnfurlResult,
|
||||||
|
IntegrationProvider,
|
||||||
|
} from '../registry/integration-provider.interface';
|
||||||
import { RedisService } from '@nestjs-labs/nestjs-ioredis';
|
import { RedisService } from '@nestjs-labs/nestjs-ioredis';
|
||||||
import type { Redis } from 'ioredis';
|
import type { Redis } from 'ioredis';
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
@@ -38,6 +41,7 @@ export class UnfurlService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const resolved = await this.resolveProvider(url, workspaceId);
|
const resolved = await this.resolveProvider(url, workspaceId);
|
||||||
|
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -58,7 +62,8 @@ export class UnfurlService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const accessToken = await this.oauthService.getValidAccessToken(connection);
|
const accessToken =
|
||||||
|
await this.oauthService.getValidAccessToken(connection);
|
||||||
|
|
||||||
const unfurlResult = await provider.unfurl({
|
const unfurlResult = await provider.unfurl({
|
||||||
url,
|
url,
|
||||||
@@ -123,7 +128,11 @@ export class UnfurlService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private buildCacheKey(workspaceId: string, url: string): string {
|
private buildCacheKey(workspaceId: string, url: string): string {
|
||||||
const hash = crypto.createHash('sha256').update(url).digest('hex').slice(0, 16);
|
const hash = crypto
|
||||||
|
.createHash('sha256')
|
||||||
|
.update(url)
|
||||||
|
.digest('hex')
|
||||||
|
.slice(0, 16);
|
||||||
return `${UNFURL_CACHE_PREFIX}${workspaceId}:${hash}`;
|
return `${UNFURL_CACHE_PREFIX}${workspaceId}:${hash}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
Submodule apps/server/src/ee updated: 41b27c951f...010a833e1a
@@ -4,28 +4,158 @@ export type IntegrationLinkPattern = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const integrationLinkPatterns: IntegrationLinkPattern[] = [
|
export const integrationLinkPatterns: IntegrationLinkPattern[] = [
|
||||||
// GitHub (cloud + GHE): /:owner/:repo/pull/:num or /issues/:num
|
// GitHub PR commit (must be before generic PR pattern)
|
||||||
{
|
{
|
||||||
provider: "github",
|
provider: "github",
|
||||||
regex:
|
regex:
|
||||||
/^https?:\/\/[^\/]+\/([^\/]+)\/([^\/]+)\/(pull|issues)\/(\d+)/,
|
/^https?:\/\/[^\/]+\/([^\/]+)\/([^\/]+)\/pull\/(\d+)\/commits\/([a-f0-9]+)/,
|
||||||
},
|
},
|
||||||
// GitLab (cloud + self-hosted): /-/issues/:num or /-/merge_requests/:num
|
// GitHub PR (with optional /checks, /commits, /files sub-pages)
|
||||||
|
{
|
||||||
|
provider: "github",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/([^\/]+)\/([^\/]+)\/pull\/(\d+)/,
|
||||||
|
},
|
||||||
|
// GitHub issue
|
||||||
|
{
|
||||||
|
provider: "github",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/([^\/]+)\/([^\/]+)\/issues\/(\d+)/,
|
||||||
|
},
|
||||||
|
// GitHub commit
|
||||||
|
{
|
||||||
|
provider: "github",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/([^\/]+)\/([^\/]+)\/commits?\/([a-f0-9]+)/,
|
||||||
|
},
|
||||||
|
// GitHub file/blob
|
||||||
|
{
|
||||||
|
provider: "github",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/([^\/]+)\/([^\/]+)\/blob\/([^\/]+)\/(.+?)(?:#L(\d+)(?:-L(\d+))?)?$/,
|
||||||
|
},
|
||||||
|
// GitHub pulls list
|
||||||
|
{
|
||||||
|
provider: "github",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/([^\/]+)\/([^\/]+)\/pulls(?:\/.*)?(?:\?.*)?$/,
|
||||||
|
},
|
||||||
|
// GitHub releases list
|
||||||
|
{
|
||||||
|
provider: "github",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/([^\/]+)\/([^\/]+)\/releases(?:\/.*)?(?:\?.*)?$/,
|
||||||
|
},
|
||||||
|
// GitHub issues list
|
||||||
|
{
|
||||||
|
provider: "github",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/([^\/]+)\/([^\/]+)\/issues(?:\/(?:created_by|assigned)\/[\w.\/-]+)?\/?(?:\?.*)?$/,
|
||||||
|
},
|
||||||
|
// GitHub repo
|
||||||
|
{
|
||||||
|
provider: "github",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/([a-zA-Z0-9\-_.]+)\/([a-zA-Z0-9\-_.]+)\/?$/,
|
||||||
|
},
|
||||||
|
// GitLab commit in MR diff (must be before generic MR pattern)
|
||||||
{
|
{
|
||||||
provider: "gitlab",
|
provider: "gitlab",
|
||||||
regex:
|
regex:
|
||||||
/^https?:\/\/[^\/]+\/(.+)\/-\/(issues|merge_requests)\/(\d+)/,
|
/^https?:\/\/[^\/]+\/(.+)\/-\/merge_requests\/(\d+)\/diffs\?.*commit_id=([a-f0-9]+)/,
|
||||||
|
},
|
||||||
|
// GitLab merge request
|
||||||
|
{
|
||||||
|
provider: "gitlab",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/(.+)\/-\/merge_requests\/(\d+)/,
|
||||||
|
},
|
||||||
|
// GitLab issue
|
||||||
|
{
|
||||||
|
provider: "gitlab",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/(.+)\/-\/issues\/(\d+)/,
|
||||||
|
},
|
||||||
|
// GitLab commit
|
||||||
|
{
|
||||||
|
provider: "gitlab",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/(.+)\/-\/commits?\/([a-f0-9]+)/,
|
||||||
|
},
|
||||||
|
// GitLab issues list
|
||||||
|
{
|
||||||
|
provider: "gitlab",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/(.+)\/-\/issues\/?(?:\?.*)?$/,
|
||||||
|
},
|
||||||
|
// GitLab merge requests list
|
||||||
|
{
|
||||||
|
provider: "gitlab",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/(.+)\/-\/merge_requests\/?(?:\?.*)?$/,
|
||||||
|
},
|
||||||
|
// GitLab project
|
||||||
|
{
|
||||||
|
provider: "gitlab",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/[^\/]+\/([a-zA-Z0-9\-_.]+)\/([a-zA-Z0-9\-_]+)\/?$/,
|
||||||
|
},
|
||||||
|
// Google Docs
|
||||||
|
{
|
||||||
|
provider: "google_docs",
|
||||||
|
regex: /^https?:\/\/docs\.google\.com\/document\/d\/([\w-]+)/,
|
||||||
|
},
|
||||||
|
// Google Sheets
|
||||||
|
{
|
||||||
|
provider: "google_docs",
|
||||||
|
regex: /^https?:\/\/docs\.google\.com\/spreadsheets\/d\/([\w-]+)/,
|
||||||
|
},
|
||||||
|
// Google Slides
|
||||||
|
{
|
||||||
|
provider: "google_docs",
|
||||||
|
regex: /^https?:\/\/docs\.google\.com\/presentation\/d\/([\w-]+)/,
|
||||||
|
},
|
||||||
|
// Google Forms
|
||||||
|
{
|
||||||
|
provider: "google_docs",
|
||||||
|
regex: /^https?:\/\/docs\.google\.com\/forms\/d\/([\w-]+)/,
|
||||||
|
},
|
||||||
|
// Google Drive file
|
||||||
|
{
|
||||||
|
provider: "google_docs",
|
||||||
|
regex: /^https?:\/\/drive\.google\.com\/file\/d\/([\w-]+)/,
|
||||||
|
},
|
||||||
|
// Figma file (design, file, proto, board)
|
||||||
|
{
|
||||||
|
provider: "figma",
|
||||||
|
regex:
|
||||||
|
/^https?:\/\/([\w.-]+\.)?figma\.com\/(file|proto|board|design)\/([0-9a-zA-Z]{22,128})/,
|
||||||
},
|
},
|
||||||
// Jira (cloud + server): /browse/KEY-123
|
// Jira (cloud + server): /browse/KEY-123
|
||||||
{
|
{
|
||||||
provider: "jira",
|
provider: "jira",
|
||||||
regex: /^https?:\/\/[^\/]+\/browse\/([A-Z][A-Z0-9]+-\d+)/,
|
regex: /^https?:\/\/[^\/]+\/browse\/([A-Z][A-Z0-9]+-\d+)/,
|
||||||
},
|
},
|
||||||
// Linear (cloud only): /team/issue/KEY-123
|
// Linear issue: /team/issue/KEY-123(/:title-slug)?
|
||||||
{
|
{
|
||||||
provider: "linear",
|
provider: "linear",
|
||||||
regex: /^https?:\/\/linear\.app\/([^\/]+)\/issue\/([A-Z]+-\d+)/,
|
regex: /^https?:\/\/linear\.app\/([^\/]+)\/issue\/([A-Z]+-\d+)/,
|
||||||
},
|
},
|
||||||
|
// Linear project: /team/project/:slug(/:tab)?
|
||||||
|
{
|
||||||
|
provider: "linear",
|
||||||
|
regex: /^https?:\/\/linear\.app\/([^\/]+)\/project\/([^\/]+)/,
|
||||||
|
},
|
||||||
|
// Linear initiative: /team/initiative/:slug(/:tab)?
|
||||||
|
{
|
||||||
|
provider: "linear",
|
||||||
|
regex: /^https?:\/\/linear\.app\/([^\/]+)\/initiative\/([^\/]+)/,
|
||||||
|
},
|
||||||
|
// Linear view: /team/view/:id(/:tab)?
|
||||||
|
{
|
||||||
|
provider: "linear",
|
||||||
|
regex: /^https?:\/\/linear\.app\/([^\/]+)\/view\/([^\/]+)/,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function matchIntegrationLink(
|
export function matchIntegrationLink(
|
||||||
|
|||||||
Reference in New Issue
Block a user