mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
remove dead code
This commit is contained in:
parent
c56433d8a9
commit
f6d5820ee2
3 changed files with 16 additions and 466 deletions
|
|
@ -5,46 +5,32 @@ import { env } from "@/env.mjs";
|
||||||
import { addUserToOrganization, orgHasAvailability } from "@/lib/authUtils";
|
import { addUserToOrganization, orgHasAvailability } from "@/lib/authUtils";
|
||||||
import { ErrorCode } from "@/lib/errorCodes";
|
import { ErrorCode } from "@/lib/errorCodes";
|
||||||
import { notAuthenticated, notFound, orgNotFound, secretAlreadyExists, ServiceError, ServiceErrorException, unexpectedError } from "@/lib/serviceError";
|
import { notAuthenticated, notFound, orgNotFound, secretAlreadyExists, ServiceError, ServiceErrorException, unexpectedError } from "@/lib/serviceError";
|
||||||
import { CodeHostType, getOrgMetadata, isHttpError, isServiceError } from "@/lib/utils";
|
import { getOrgMetadata, isHttpError, isServiceError } from "@/lib/utils";
|
||||||
import { prisma } from "@/prisma";
|
import { prisma } from "@/prisma";
|
||||||
import { render } from "@react-email/components";
|
import { render } from "@react-email/components";
|
||||||
import * as Sentry from '@sentry/nextjs';
|
import * as Sentry from '@sentry/nextjs';
|
||||||
import { decrypt, encrypt, generateApiKey, getTokenFromConfig, hashSecret } from "@sourcebot/crypto";
|
import { encrypt, generateApiKey, getTokenFromConfig, hashSecret } from "@sourcebot/crypto";
|
||||||
import { ApiKey, ConnectionSyncStatus, Org, OrgRole, Prisma, RepoIndexingStatus, RepoJobStatus, RepoJobType, StripeSubscriptionStatus } from "@sourcebot/db";
|
import { ApiKey, Org, OrgRole, Prisma, RepoJobStatus, RepoJobType, StripeSubscriptionStatus } from "@sourcebot/db";
|
||||||
import { createLogger } from "@sourcebot/logger";
|
import { createLogger } from "@sourcebot/logger";
|
||||||
import { azuredevopsSchema } from "@sourcebot/schemas/v3/azuredevops.schema";
|
|
||||||
import { bitbucketSchema } from "@sourcebot/schemas/v3/bitbucket.schema";
|
|
||||||
import { ConnectionConfig } from "@sourcebot/schemas/v3/connection.type";
|
|
||||||
import { genericGitHostSchema } from "@sourcebot/schemas/v3/genericGitHost.schema";
|
|
||||||
import { gerritSchema } from "@sourcebot/schemas/v3/gerrit.schema";
|
|
||||||
import { giteaSchema } from "@sourcebot/schemas/v3/gitea.schema";
|
|
||||||
import { GiteaConnectionConfig } from "@sourcebot/schemas/v3/gitea.type";
|
import { GiteaConnectionConfig } from "@sourcebot/schemas/v3/gitea.type";
|
||||||
import { githubSchema } from "@sourcebot/schemas/v3/github.schema";
|
|
||||||
import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type";
|
import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type";
|
||||||
import { gitlabSchema } from "@sourcebot/schemas/v3/gitlab.schema";
|
|
||||||
import { GitlabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type";
|
import { GitlabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type";
|
||||||
import { getPlan, hasEntitlement } from "@sourcebot/shared";
|
import { getPlan, hasEntitlement } from "@sourcebot/shared";
|
||||||
import Ajv from "ajv";
|
|
||||||
import { StatusCodes } from "http-status-codes";
|
import { StatusCodes } from "http-status-codes";
|
||||||
import { cookies, headers } from "next/headers";
|
import { cookies, headers } from "next/headers";
|
||||||
import { createTransport } from "nodemailer";
|
import { createTransport } from "nodemailer";
|
||||||
import { Octokit } from "octokit";
|
import { Octokit } from "octokit";
|
||||||
import { auth } from "./auth";
|
import { auth } from "./auth";
|
||||||
import { getConnection } from "./data/connection";
|
|
||||||
import { getOrgFromDomain } from "./data/org";
|
import { getOrgFromDomain } from "./data/org";
|
||||||
import { decrementOrgSeatCount, getSubscriptionForOrg } from "./ee/features/billing/serverUtils";
|
import { decrementOrgSeatCount, getSubscriptionForOrg } from "./ee/features/billing/serverUtils";
|
||||||
import { IS_BILLING_ENABLED } from "./ee/features/billing/stripe";
|
import { IS_BILLING_ENABLED } from "./ee/features/billing/stripe";
|
||||||
import InviteUserEmail from "./emails/inviteUserEmail";
|
import InviteUserEmail from "./emails/inviteUserEmail";
|
||||||
import JoinRequestApprovedEmail from "./emails/joinRequestApprovedEmail";
|
import JoinRequestApprovedEmail from "./emails/joinRequestApprovedEmail";
|
||||||
import JoinRequestSubmittedEmail from "./emails/joinRequestSubmittedEmail";
|
import JoinRequestSubmittedEmail from "./emails/joinRequestSubmittedEmail";
|
||||||
import { AGENTIC_SEARCH_TUTORIAL_DISMISSED_COOKIE_NAME, MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, SEARCH_MODE_COOKIE_NAME, SINGLE_TENANT_ORG_DOMAIN, SOURCEBOT_GUEST_USER_ID, SOURCEBOT_SUPPORT_EMAIL } from "./lib/constants";
|
import { AGENTIC_SEARCH_TUTORIAL_DISMISSED_COOKIE_NAME, MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, SINGLE_TENANT_ORG_DOMAIN, SOURCEBOT_GUEST_USER_ID, SOURCEBOT_SUPPORT_EMAIL } from "./lib/constants";
|
||||||
import { orgDomainSchema, orgNameSchema, repositoryQuerySchema } from "./lib/schemas";
|
import { orgDomainSchema, orgNameSchema, repositoryQuerySchema } from "./lib/schemas";
|
||||||
import { ApiKeyPayload, TenancyMode } from "./lib/types";
|
import { ApiKeyPayload, TenancyMode } from "./lib/types";
|
||||||
import { withAuthV2, withOptionalAuthV2 } from "./withAuthV2";
|
import { withOptionalAuthV2 } from "./withAuthV2";
|
||||||
|
|
||||||
const ajv = new Ajv({
|
|
||||||
validateFormats: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const logger = createLogger('web-actions');
|
const logger = createLogger('web-actions');
|
||||||
const auditService = getAuditService();
|
const auditService = getAuditService();
|
||||||
|
|
@ -187,31 +173,6 @@ export const withTenancyModeEnforcement = async<T>(mode: TenancyMode, fn: () =>
|
||||||
|
|
||||||
////// Actions ///////
|
////// Actions ///////
|
||||||
|
|
||||||
export const createOrg = async (name: string, domain: string): Promise<{ id: number } | ServiceError> => sew(() =>
|
|
||||||
withTenancyModeEnforcement('multi', () =>
|
|
||||||
withAuth(async (userId) => {
|
|
||||||
const org = await prisma.org.create({
|
|
||||||
data: {
|
|
||||||
name,
|
|
||||||
domain,
|
|
||||||
members: {
|
|
||||||
create: {
|
|
||||||
role: "OWNER",
|
|
||||||
user: {
|
|
||||||
connect: {
|
|
||||||
id: userId,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: org.id,
|
|
||||||
}
|
|
||||||
})));
|
|
||||||
|
|
||||||
export const updateOrgName = async (name: string, domain: string) => sew(() =>
|
export const updateOrgName = async (name: string, domain: string) => sew(() =>
|
||||||
withAuth((userId) =>
|
withAuth((userId) =>
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
withOrgMembership(userId, domain, async ({ org }) => {
|
||||||
|
|
@ -573,71 +534,6 @@ export const getUserApiKeys = async (domain: string): Promise<{ name: string; cr
|
||||||
}));
|
}));
|
||||||
})));
|
})));
|
||||||
|
|
||||||
export const getConnections = async (domain: string, filter: { status?: ConnectionSyncStatus[] } = {}) => sew(() =>
|
|
||||||
withAuth((userId) =>
|
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
|
||||||
const connections = await prisma.connection.findMany({
|
|
||||||
where: {
|
|
||||||
orgId: org.id,
|
|
||||||
...(filter.status ? {
|
|
||||||
syncStatus: { in: filter.status }
|
|
||||||
} : {}),
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
repos: {
|
|
||||||
include: {
|
|
||||||
repo: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return connections.map((connection) => ({
|
|
||||||
id: connection.id,
|
|
||||||
name: connection.name,
|
|
||||||
syncStatus: connection.syncStatus,
|
|
||||||
syncStatusMetadata: connection.syncStatusMetadata,
|
|
||||||
connectionType: connection.connectionType,
|
|
||||||
updatedAt: connection.updatedAt,
|
|
||||||
syncedAt: connection.syncedAt ?? undefined,
|
|
||||||
linkedRepos: connection.repos.map(({ repo }) => ({
|
|
||||||
id: repo.id,
|
|
||||||
name: repo.name,
|
|
||||||
repoIndexingStatus: repo.repoIndexingStatus,
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
})
|
|
||||||
));
|
|
||||||
|
|
||||||
export const getConnectionInfo = async (connectionId: number, domain: string) => sew(() =>
|
|
||||||
withAuth((userId) =>
|
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
|
||||||
const connection = await prisma.connection.findUnique({
|
|
||||||
where: {
|
|
||||||
id: connectionId,
|
|
||||||
orgId: org.id,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
repos: true,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!connection) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: connection.id,
|
|
||||||
name: connection.name,
|
|
||||||
syncStatus: connection.syncStatus,
|
|
||||||
syncStatusMetadata: connection.syncStatusMetadata,
|
|
||||||
connectionType: connection.connectionType,
|
|
||||||
updatedAt: connection.updatedAt,
|
|
||||||
syncedAt: connection.syncedAt ?? undefined,
|
|
||||||
numLinkedRepos: connection.repos.length,
|
|
||||||
}
|
|
||||||
})));
|
|
||||||
|
|
||||||
export const getRepos = async ({
|
export const getRepos = async ({
|
||||||
where,
|
where,
|
||||||
take,
|
take,
|
||||||
|
|
@ -781,54 +677,6 @@ export const getRepoInfoByName = async (repoName: string) => sew(() =>
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const createConnection = async (name: string, type: CodeHostType, connectionConfig: string, domain: string): Promise<{ id: number } | ServiceError> => sew(() =>
|
|
||||||
withAuth((userId) =>
|
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
|
||||||
if (env.CONFIG_PATH !== undefined) {
|
|
||||||
return {
|
|
||||||
statusCode: StatusCodes.BAD_REQUEST,
|
|
||||||
errorCode: ErrorCode.CONNECTION_CONFIG_PATH_SET,
|
|
||||||
message: "A configuration file has been provided. New connections cannot be added through the web interface.",
|
|
||||||
} satisfies ServiceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsedConfig = parseConnectionConfig(connectionConfig);
|
|
||||||
if (isServiceError(parsedConfig)) {
|
|
||||||
return parsedConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
const existingConnectionWithName = await prisma.connection.findUnique({
|
|
||||||
where: {
|
|
||||||
name_orgId: {
|
|
||||||
orgId: org.id,
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (existingConnectionWithName) {
|
|
||||||
return {
|
|
||||||
statusCode: StatusCodes.BAD_REQUEST,
|
|
||||||
errorCode: ErrorCode.CONNECTION_ALREADY_EXISTS,
|
|
||||||
message: "A connection with this name already exists.",
|
|
||||||
} satisfies ServiceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const connection = await prisma.connection.create({
|
|
||||||
data: {
|
|
||||||
orgId: org.id,
|
|
||||||
name,
|
|
||||||
config: parsedConfig as unknown as Prisma.InputJsonValue,
|
|
||||||
connectionType: type,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: connection.id,
|
|
||||||
}
|
|
||||||
}, OrgRole.OWNER)
|
|
||||||
));
|
|
||||||
|
|
||||||
export const experimental_addGithubRepositoryByUrl = async (repositoryUrl: string): Promise<{ connectionId: number } | ServiceError> => sew(() =>
|
export const experimental_addGithubRepositoryByUrl = async (repositoryUrl: string): Promise<{ connectionId: number } | ServiceError> => sew(() =>
|
||||||
withOptionalAuthV2(async ({ org, prisma }) => {
|
withOptionalAuthV2(async ({ org, prisma }) => {
|
||||||
if (env.EXPERIMENT_SELF_SERVE_REPO_INDEXING_ENABLED !== 'true') {
|
if (env.EXPERIMENT_SELF_SERVE_REPO_INDEXING_ENABLED !== 'true') {
|
||||||
|
|
@ -965,148 +813,6 @@ export const experimental_addGithubRepositoryByUrl = async (repositoryUrl: strin
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const updateConnectionDisplayName = async (connectionId: number, name: string, domain: string): Promise<{ success: boolean } | ServiceError> => sew(() =>
|
|
||||||
withAuth((userId) =>
|
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
|
||||||
const connection = await getConnection(connectionId, org.id);
|
|
||||||
if (!connection) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const existingConnectionWithName = await prisma.connection.findUnique({
|
|
||||||
where: {
|
|
||||||
name_orgId: {
|
|
||||||
orgId: org.id,
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (existingConnectionWithName) {
|
|
||||||
return {
|
|
||||||
statusCode: StatusCodes.BAD_REQUEST,
|
|
||||||
errorCode: ErrorCode.CONNECTION_ALREADY_EXISTS,
|
|
||||||
message: "A connection with this name already exists.",
|
|
||||||
} satisfies ServiceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.connection.update({
|
|
||||||
where: {
|
|
||||||
id: connectionId,
|
|
||||||
orgId: org.id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
}
|
|
||||||
}, OrgRole.OWNER)
|
|
||||||
));
|
|
||||||
|
|
||||||
export const updateConnectionConfigAndScheduleSync = async (connectionId: number, config: string, domain: string): Promise<{ success: boolean } | ServiceError> => sew(() =>
|
|
||||||
withAuth((userId) =>
|
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
|
||||||
const connection = await getConnection(connectionId, org.id);
|
|
||||||
if (!connection) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsedConfig = parseConnectionConfig(config);
|
|
||||||
if (isServiceError(parsedConfig)) {
|
|
||||||
return parsedConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connection.syncStatus === "SYNC_NEEDED" ||
|
|
||||||
connection.syncStatus === "IN_SYNC_QUEUE" ||
|
|
||||||
connection.syncStatus === "SYNCING") {
|
|
||||||
return {
|
|
||||||
statusCode: StatusCodes.BAD_REQUEST,
|
|
||||||
errorCode: ErrorCode.CONNECTION_SYNC_ALREADY_SCHEDULED,
|
|
||||||
message: "Connection is already syncing. Please wait for the sync to complete before updating the connection.",
|
|
||||||
} satisfies ServiceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.connection.update({
|
|
||||||
where: {
|
|
||||||
id: connectionId,
|
|
||||||
orgId: org.id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
config: parsedConfig as unknown as Prisma.InputJsonValue,
|
|
||||||
syncStatus: "SYNC_NEEDED",
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
}
|
|
||||||
}, OrgRole.OWNER)
|
|
||||||
));
|
|
||||||
|
|
||||||
export const flagConnectionForSync = async (connectionId: number, domain: string): Promise<{ success: boolean } | ServiceError> => sew(() =>
|
|
||||||
withAuth((userId) =>
|
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
|
||||||
const connection = await getConnection(connectionId, org.id);
|
|
||||||
if (!connection || connection.orgId !== org.id) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.connection.update({
|
|
||||||
where: {
|
|
||||||
id: connection.id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
syncStatus: "SYNC_NEEDED",
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
));
|
|
||||||
|
|
||||||
export const flagReposForIndex = async (repoIds: number[]) => sew(() =>
|
|
||||||
withAuthV2(async ({ org, prisma }) => {
|
|
||||||
await prisma.repo.updateMany({
|
|
||||||
where: {
|
|
||||||
id: { in: repoIds },
|
|
||||||
orgId: org.id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
repoIndexingStatus: RepoIndexingStatus.NEW,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const deleteConnection = async (connectionId: number, domain: string): Promise<{ success: boolean } | ServiceError> => sew(() =>
|
|
||||||
withAuth((userId) =>
|
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
|
||||||
const connection = await getConnection(connectionId, org.id);
|
|
||||||
if (!connection) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.connection.delete({
|
|
||||||
where: {
|
|
||||||
id: connectionId,
|
|
||||||
orgId: org.id,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
}
|
|
||||||
}, OrgRole.OWNER)
|
|
||||||
));
|
|
||||||
|
|
||||||
export const getCurrentUserRole = async (domain: string): Promise<OrgRole | ServiceError> => sew(() =>
|
export const getCurrentUserRole = async (domain: string): Promise<OrgRole | ServiceError> => sew(() =>
|
||||||
withAuth((userId) =>
|
withAuth((userId) =>
|
||||||
withOrgMembership(userId, domain, async ({ userRole }) => {
|
withOrgMembership(userId, domain, async ({ userRole }) => {
|
||||||
|
|
@ -1319,13 +1025,6 @@ export const cancelInvite = async (inviteId: string, domain: string): Promise<{
|
||||||
}, /* minRequiredRole = */ OrgRole.OWNER)
|
}, /* minRequiredRole = */ OrgRole.OWNER)
|
||||||
));
|
));
|
||||||
|
|
||||||
export const getOrgInviteId = async (domain: string) => sew(() =>
|
|
||||||
withAuth(async (userId) =>
|
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
|
||||||
return org.inviteLinkId;
|
|
||||||
}, /* minRequiredRole = */ OrgRole.OWNER)
|
|
||||||
));
|
|
||||||
|
|
||||||
export const getMe = async () => sew(() =>
|
export const getMe = async () => sew(() =>
|
||||||
withAuth(async (userId) => {
|
withAuth(async (userId) => {
|
||||||
const user = await prisma.user.findUnique({
|
const user = await prisma.user.findUnique({
|
||||||
|
|
@ -1662,27 +1361,6 @@ export const leaveOrg = async (domain: string): Promise<{ success: boolean } | S
|
||||||
})
|
})
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
export const getOrgMembership = async (domain: string) => sew(() =>
|
|
||||||
withAuth(async (userId) =>
|
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
|
||||||
const membership = await prisma.userToOrg.findUnique({
|
|
||||||
where: {
|
|
||||||
orgId_userId: {
|
|
||||||
orgId: org.id,
|
|
||||||
userId: userId,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!membership) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return membership;
|
|
||||||
})
|
|
||||||
));
|
|
||||||
|
|
||||||
export const getOrgMembers = async (domain: string) => sew(() =>
|
export const getOrgMembers = async (domain: string) => sew(() =>
|
||||||
withAuth(async (userId) =>
|
withAuth(async (userId) =>
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
withOrgMembership(userId, domain, async ({ org }) => {
|
||||||
|
|
@ -1878,20 +1556,6 @@ export const setMemberApprovalRequired = async (domain: string, required: boolea
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getInviteLinkEnabled = async (domain: string): Promise<boolean | ServiceError> => sew(async () => {
|
|
||||||
const org = await prisma.org.findUnique({
|
|
||||||
where: {
|
|
||||||
domain,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!org) {
|
|
||||||
return orgNotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return org.inviteLinkEnabled;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setInviteLinkEnabled = async (domain: string, enabled: boolean): Promise<{ success: boolean } | ServiceError> => sew(async () =>
|
export const setInviteLinkEnabled = async (domain: string, enabled: boolean): Promise<{ success: boolean } | ServiceError> => sew(async () =>
|
||||||
withAuth(async (userId) =>
|
withAuth(async (userId) =>
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
withOrgMembership(userId, domain, async ({ org }) => {
|
||||||
|
|
@ -2023,10 +1687,6 @@ export const rejectAccountRequest = async (requestId: string, domain: string) =>
|
||||||
}, /* minRequiredRole = */ OrgRole.OWNER)
|
}, /* minRequiredRole = */ OrgRole.OWNER)
|
||||||
));
|
));
|
||||||
|
|
||||||
export const dismissMobileUnsupportedSplashScreen = async () => sew(async () => {
|
|
||||||
await (await cookies()).set(MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, 'true');
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const getSearchContexts = async (domain: string) => sew(() =>
|
export const getSearchContexts = async (domain: string) => sew(() =>
|
||||||
withAuth((userId) =>
|
withAuth((userId) =>
|
||||||
|
|
@ -2179,126 +1839,17 @@ export const setAnonymousAccessStatus = async (domain: string, enabled: boolean)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function setSearchModeCookie(searchMode: "precise" | "agentic") {
|
export const setAgenticSearchTutorialDismissedCookie = async (dismissed: boolean) => sew(async () => {
|
||||||
const cookieStore = await cookies();
|
|
||||||
cookieStore.set(SEARCH_MODE_COOKIE_NAME, searchMode, {
|
|
||||||
httpOnly: false, // Allow client-side access
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function setAgenticSearchTutorialDismissedCookie(dismissed: boolean) {
|
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
cookieStore.set(AGENTIC_SEARCH_TUTORIAL_DISMISSED_COOKIE_NAME, dismissed ? "true" : "false", {
|
cookieStore.set(AGENTIC_SEARCH_TUTORIAL_DISMISSED_COOKIE_NAME, dismissed ? "true" : "false", {
|
||||||
httpOnly: false, // Allow client-side access
|
httpOnly: false, // Allow client-side access
|
||||||
|
maxAge: 365 * 24 * 60 * 60, // 1 year in seconds
|
||||||
});
|
});
|
||||||
}
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
////// Helpers ///////
|
export const dismissMobileUnsupportedSplashScreen = async () => sew(async () => {
|
||||||
|
const cookieStore = await cookies();
|
||||||
const parseConnectionConfig = (config: string) => {
|
cookieStore.set(MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, 'true');
|
||||||
let parsedConfig: ConnectionConfig;
|
return true;
|
||||||
try {
|
});
|
||||||
parsedConfig = JSON.parse(config);
|
|
||||||
} catch (_e) {
|
|
||||||
return {
|
|
||||||
statusCode: StatusCodes.BAD_REQUEST,
|
|
||||||
errorCode: ErrorCode.INVALID_REQUEST_BODY,
|
|
||||||
message: "config must be a valid JSON object."
|
|
||||||
} satisfies ServiceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const connectionType = parsedConfig.type;
|
|
||||||
const schema = (() => {
|
|
||||||
switch (connectionType) {
|
|
||||||
case "github":
|
|
||||||
return githubSchema;
|
|
||||||
case "gitlab":
|
|
||||||
return gitlabSchema;
|
|
||||||
case 'gitea':
|
|
||||||
return giteaSchema;
|
|
||||||
case 'gerrit':
|
|
||||||
return gerritSchema;
|
|
||||||
case 'bitbucket':
|
|
||||||
return bitbucketSchema;
|
|
||||||
case 'azuredevops':
|
|
||||||
return azuredevopsSchema;
|
|
||||||
case 'git':
|
|
||||||
return genericGitHostSchema;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (!schema) {
|
|
||||||
return {
|
|
||||||
statusCode: StatusCodes.BAD_REQUEST,
|
|
||||||
errorCode: ErrorCode.INVALID_REQUEST_BODY,
|
|
||||||
message: "invalid connection type",
|
|
||||||
} satisfies ServiceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isValidConfig = ajv.validate(schema, parsedConfig);
|
|
||||||
if (!isValidConfig) {
|
|
||||||
return {
|
|
||||||
statusCode: StatusCodes.BAD_REQUEST,
|
|
||||||
errorCode: ErrorCode.INVALID_REQUEST_BODY,
|
|
||||||
message: `config schema validation failed with errors: ${ajv.errorsText(ajv.errors)}`,
|
|
||||||
} satisfies ServiceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('token' in parsedConfig && parsedConfig.token && 'env' in parsedConfig.token) {
|
|
||||||
return {
|
|
||||||
statusCode: StatusCodes.BAD_REQUEST,
|
|
||||||
errorCode: ErrorCode.INVALID_REQUEST_BODY,
|
|
||||||
message: "Environment variables are not supported for connections created in the web UI. Please use a secret instead.",
|
|
||||||
} satisfies ServiceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { numRepos, hasToken } = (() => {
|
|
||||||
switch (connectionType) {
|
|
||||||
case "gitea":
|
|
||||||
case "github":
|
|
||||||
case "bitbucket":
|
|
||||||
case "azuredevops": {
|
|
||||||
return {
|
|
||||||
numRepos: parsedConfig.repos?.length,
|
|
||||||
hasToken: !!parsedConfig.token,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "gitlab": {
|
|
||||||
return {
|
|
||||||
numRepos: parsedConfig.projects?.length,
|
|
||||||
hasToken: !!parsedConfig.token,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "gerrit": {
|
|
||||||
return {
|
|
||||||
numRepos: parsedConfig.projects?.length,
|
|
||||||
hasToken: true, // gerrit doesn't use a token atm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "git": {
|
|
||||||
return {
|
|
||||||
numRepos: 1,
|
|
||||||
hasToken: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (!hasToken && numRepos && numRepos > env.CONFIG_MAX_REPOS_NO_TOKEN) {
|
|
||||||
return {
|
|
||||||
statusCode: StatusCodes.BAD_REQUEST,
|
|
||||||
errorCode: ErrorCode.INVALID_REQUEST_BODY,
|
|
||||||
message: `You must provide a token to sync more than ${env.CONFIG_MAX_REPOS_NO_TOKEN} repositories.`,
|
|
||||||
} satisfies ServiceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const encryptValue = async (value: string) => {
|
|
||||||
return encrypt(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const decryptValue = async (iv: string, encryptedValue: string) => {
|
|
||||||
return decrypt(iv, encryptedValue);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,13 @@ export const NavigationItems = ({
|
||||||
<NavigationMenuList className="gap-2">
|
<NavigationMenuList className="gap-2">
|
||||||
<NavigationMenuItem className="relative">
|
<NavigationMenuItem className="relative">
|
||||||
<NavigationMenuLink
|
<NavigationMenuLink
|
||||||
href={`/${domain}`}
|
href={`/${domain}/search`}
|
||||||
className={cn(navigationMenuTriggerStyle(), "gap-2")}
|
className={cn(navigationMenuTriggerStyle(), "gap-2")}
|
||||||
>
|
>
|
||||||
<SearchIcon className="w-4 h-4 mr-1" />
|
<SearchIcon className="w-4 h-4 mr-1" />
|
||||||
Search
|
Search
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
{isActive(`/${domain}`) && <ActiveIndicator />}
|
{((isActive(`/${domain}`) || isActive(`/${domain}/search`)) && <ActiveIndicator />)}
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
<NavigationMenuItem className="relative">
|
<NavigationMenuItem className="relative">
|
||||||
<NavigationMenuLink
|
<NavigationMenuLink
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ export const TEAM_FEATURES = [
|
||||||
]
|
]
|
||||||
|
|
||||||
export const MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME = 'sb.mobile-unsupported-splash-screen-dismissed';
|
export const MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME = 'sb.mobile-unsupported-splash-screen-dismissed';
|
||||||
export const SEARCH_MODE_COOKIE_NAME = 'sb.search-mode';
|
|
||||||
export const AGENTIC_SEARCH_TUTORIAL_DISMISSED_COOKIE_NAME = 'sb.agentic-search-tutorial-dismissed';
|
export const AGENTIC_SEARCH_TUTORIAL_DISMISSED_COOKIE_NAME = 'sb.agentic-search-tutorial-dismissed';
|
||||||
|
|
||||||
// NOTE: changing SOURCEBOT_GUEST_USER_ID may break backwards compatibility since this value is used
|
// NOTE: changing SOURCEBOT_GUEST_USER_ID may break backwards compatibility since this value is used
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue