mirror of
https://github.com/Kong/insomnia.git
synced 2026-09-19 20:37:14 -04:00
160 lines
5.2 KiB
TypeScript
160 lines
5.2 KiB
TypeScript
import { fetchTeamProjects } from 'insomnia-api';
|
|
import type { Project, Query, RemoteProject } from 'insomnia-data';
|
|
import { database as db, models } from 'insomnia-data';
|
|
|
|
import * as userSessionService from './user-session';
|
|
|
|
const { type } = models.project;
|
|
|
|
export function create(patch: Partial<Project> = {}) {
|
|
return db.docCreate<Project>(type, patch);
|
|
}
|
|
|
|
export function list(query?: Query<Project>, sort?: Record<string, any>, limit?: number) {
|
|
return db.find<Project>(type, query, sort, limit);
|
|
}
|
|
|
|
export function count(query?: Query<Project>) {
|
|
return db.count<Project>(type, query);
|
|
}
|
|
|
|
export function get(query?: Query<Project>, sort?: Record<string, any>) {
|
|
return db.findOne<Project>(type, query, sort);
|
|
}
|
|
|
|
const _getProjectByIdOrProject = async (idOrProject: string | Project) => {
|
|
const project = typeof idOrProject === 'string' ? await getById(idOrProject) : idOrProject;
|
|
if (!project) {
|
|
throw new Error(
|
|
`Project not found: ${typeof idOrProject === 'string' ? idOrProject : `_id=${idOrProject._id}, name=${idOrProject.name}`}`,
|
|
);
|
|
}
|
|
return project;
|
|
};
|
|
|
|
export async function update(idOrProject: string | Project, patch: Partial<Project>) {
|
|
const project = await _getProjectByIdOrProject(idOrProject);
|
|
return db.docUpdate(project, patch);
|
|
}
|
|
|
|
export async function remove(idOrProject: string | Project) {
|
|
const project = await _getProjectByIdOrProject(idOrProject);
|
|
return db.remove(project);
|
|
}
|
|
|
|
export function getById(id: string) {
|
|
return get({ _id: id });
|
|
}
|
|
|
|
export function getByRemoteId(remoteId: string) {
|
|
return get({ remoteId }) as Promise<RemoteProject | null>;
|
|
}
|
|
|
|
export function listByOrganizationIds(organizationIds: string | string[]) {
|
|
const ids = Array.isArray(organizationIds) ? organizationIds : [organizationIds];
|
|
return list({
|
|
parentId: ids.length === 1 ? ids[0] : { $in: ids },
|
|
});
|
|
}
|
|
|
|
export function listByGitRepositoryIds(gitRepositoryIds: string | string[]) {
|
|
const ids = Array.isArray(gitRepositoryIds) ? gitRepositoryIds : [gitRepositoryIds];
|
|
const queryIds = ids.flatMap(id => models.project.getQueryableGitRepositoryIds(id));
|
|
return list({ gitRepositoryId: { $in: queryIds } });
|
|
}
|
|
|
|
export async function getFirstProjectOfOrganization(organizationId: string) {
|
|
return db.findOne<Project>(type, { parentId: organizationId });
|
|
}
|
|
|
|
export async function getAllTeamProjects(organizationId: string) {
|
|
const { id: sessionId } = await userSessionService.get();
|
|
if (!sessionId) {
|
|
return [];
|
|
}
|
|
|
|
console.log('[project] Fetching', organizationId);
|
|
const response = await fetchTeamProjects({ sessionId, organizationId });
|
|
return response.data;
|
|
}
|
|
|
|
interface TeamProject {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
|
|
export async function syncTeamProjects({
|
|
organizationId,
|
|
teamProjects,
|
|
}: {
|
|
teamProjects: TeamProject[];
|
|
organizationId: string;
|
|
}) {
|
|
// assumption: api teamProjects is the source of truth for migrated projects
|
|
// once migrated orgs become the source of truth for projects
|
|
// its important that migration be completed before this code is run
|
|
const existingRemoteProjects = await list({
|
|
remoteId: { $in: teamProjects.map(p => p.id) },
|
|
});
|
|
|
|
const existingRemoteProjectsRemoteIds = existingRemoteProjects.map(p => p.remoteId);
|
|
const remoteProjectsThatNeedToBeCreated = teamProjects.filter(p => !existingRemoteProjectsRemoteIds.includes(p.id));
|
|
|
|
// this will create a new project for any remote projects that don't exist in the current organization
|
|
await Promise.all(
|
|
remoteProjectsThatNeedToBeCreated.map(async prj => {
|
|
await create({
|
|
remoteId: prj.id,
|
|
name: prj.name,
|
|
parentId: organizationId,
|
|
});
|
|
}),
|
|
);
|
|
|
|
const remoteProjectsThatNeedToBeUpdated = await list({
|
|
// Remote ID is in the list of remote projects
|
|
remoteId: { $in: teamProjects.map(p => p.id) },
|
|
});
|
|
|
|
await Promise.all(
|
|
remoteProjectsThatNeedToBeUpdated.map(async prj => {
|
|
const remoteProject = teamProjects.find(p => p.id === prj.remoteId);
|
|
if (remoteProject && remoteProject.name !== prj.name) {
|
|
await update(prj, {
|
|
name: remoteProject.name,
|
|
});
|
|
}
|
|
}),
|
|
);
|
|
|
|
// Turn remote projects from the current organization that are not in the list of remote projects into local projects.
|
|
const removedRemoteProjects = await list({
|
|
// filter by this organization so no legacy data can be accidentally removed, because legacy had null parentId
|
|
parentId: organizationId,
|
|
// Remote ID is not in the list of remote projects.
|
|
// add `$ne: null` condition because if remoteId is already null, we dont need to remove it again.
|
|
// nedb use append-only format, all updates and deletes actually result in lines added
|
|
remoteId: {
|
|
$nin: teamProjects.map(p => p.id),
|
|
$ne: null,
|
|
},
|
|
});
|
|
|
|
await Promise.all(
|
|
removedRemoteProjects.map(async prj => {
|
|
await update(prj, {
|
|
remoteId: null,
|
|
});
|
|
}),
|
|
);
|
|
}
|
|
|
|
export async function syncProjects(organizationId: string) {
|
|
const user = await userSessionService.get();
|
|
const teamProjects = await getAllTeamProjects(organizationId);
|
|
// ensure we don't sync projects in the wrong place
|
|
if (Array.isArray(teamProjects) && user.id && !models.organization.isScratchpadOrganizationId(organizationId)) {
|
|
await syncTeamProjects({ teamProjects, organizationId });
|
|
}
|
|
}
|