@enonic/mock-xp
Version:
Mock Enonic XP API JavaScript Library
409 lines (373 loc) • 8.75 kB
text/typescript
import type {
CreateUserParams,
LoginParams,
UserKey,
} from '@enonic-types/lib-auth';
import type {
ContextAttributes,
ContextUserParams,
PrincipalKey,
} from '@enonic-types/lib-context';
import type {
ConnectParams,
CreateNodeParams,
ModifyNodeParams,
} from '@enonic-types/lib-node';
import type {
CreateRepositoryParams,
RepositorySettings,
} from '@enonic-types/lib-repo';
import type {
LogLevel
} from './Log';
import type {
// CreateRepoParams,
Log as LogType,
} from '../types';
import type {App} from './App';
import type {Branch} from './Branch';
import type {Repos} from './Repo';
import {vol} from 'memfs';
import {
ROLE_SYSTEM_EVERYONE,
SYSTEM_REPO,
USER_SYSTEM_ANONYMOUS,
} from '../constants';
import {Auth} from './Auth';
import {ContentConnection} from './ContentConnection';
import {Context} from './Context';
import {Log} from './Log';
import {Project} from './Project';
import {Repo} from './Repo';
import {RepoConnection} from './RepoConnection';
import {RepositoryNotFoundException} from './repo/RepositoryNotFoundException';
import {setupSystemRepo} from './server/setupSystemRepo';
import {Version} from './Version';
export class Server {
readonly applications: App[] = [];
readonly auth: Auth;
readonly indexWarnings: boolean = false;
readonly log: LogType = Log.createLogger({loglevel: 'info'});
readonly projects: Record<string, Project> = {};
readonly repos: Repos = {};
readonly systemRepoConnection: RepoConnection;
readonly version: string = '7.14.0';
readonly vol = vol;
// At some point these should live somewhere else, but this simplification
// is fine for now:
public userKey?: UserKey | undefined
public context: Context
constructor({
indexWarnings = false,
log,
loglevel,
version,
}: {
indexWarnings?: boolean
log?: LogType,
loglevel?: LogLevel
version?: string
} = {}) {
if (indexWarnings) {
this.indexWarnings = indexWarnings;
}
if (log) {
this.log = log;
} else if (loglevel) {
this.log = Log.createLogger({loglevel});
}
if (version) {
this.version = version;
}
this.vol.fromJSON({}, '/');
this.createRepo({
id: SYSTEM_REPO
});
this.systemRepoConnection = this.connect({
branchId: 'master',
repoId: SYSTEM_REPO
});
this.auth = new Auth({
server: this
});
setupSystemRepo({server: this});
this.context = new Context({
branch: 'master',
repository: SYSTEM_REPO,
server: this,
principals: [
USER_SYSTEM_ANONYMOUS,
ROLE_SYSTEM_EVERYONE
],
});
} // constructor
public connect({
repoId,
branchId// ,
// user,
// principals
}: {
repoId: ConnectParams['repoId']
branchId: ConnectParams['branch']
principals?: ConnectParams['principals']
user?: ConnectParams['user']
}): RepoConnection {
if (!repoId) {
throw new Error('connect: No repoId provided!');
}
if(!branchId) {
throw new Error('connect: No branchId provided!');
}
const repo = this.getRepo(repoId);
const branch = repo.getBranch(branchId);
return new RepoConnection({
branch
});
}
public contentConnect({
branchId,
projectId,
}: {
branchId: string
projectId: string
}): ContentConnection {
if (!projectId) {
throw new Error('Server: contentConnect: No projectId provided!');
}
if(!branchId) {
throw new Error('Server: contentConnect: No branchId provided!');
}
return new ContentConnection({
branch: this.getBranch({
branchId,
repoId: Project.repoIdFromProjectName(projectId)
})
});
}
public createBranch({
branchId,
repoId
}: {
branchId: string
repoId: string
}) {
return this.getRepo(repoId).createBranch(branchId);
}
// This can't be chainable or there is no way to get the created node,
// since we need to know the createdNode._id to get it later.
public createNode<NodeData = unknown>({
_trace = false,
branchId,
repoId,
node
}: {
_trace?: boolean;
branchId: string
node: CreateNodeParams<NodeData>
repoId: string
}) {
return this.connect({
branchId,
repoId
}).create<NodeData>({
_trace,
...node
});
}
public createRepo({
id,
// rootChildOrder,
// rootPermissions,
settings
}: CreateRepositoryParams): Server {
const repo = new Repo({
id,
server: this,
// rootPermissions,
settings
});
this.repos[id] = repo;
// return repo;
return this; // Chainable
}
public createProject({
projectName,
settings = {}
}: {
projectName: string
settings?: RepositorySettings
}): Server {
if (!projectName) {
throw new Error('Server: createProject: No projectName provided!');
}
if (this.projects[projectName]) {
// TODO Compare settings and throw if different
this.log.info(`Project ${projectName} already exists.`);
return this; // Chainable
}
this.projects[projectName] = new Project({
projectName,
server: this,
settings
});
return this; // Chainable
}
public createUser(params: Omit<CreateUserParams, 'idProvider'> & {
idProvider?: string
password?: string
profile?: Record<string, unknown>
}): Server {
this.auth.createUser(params);
return this; // Chainable
}
public deleteRepo({
repoId
}: {
repoId:string
}): Server {
// TODO throw new RepositoryExeption( "No allowed to delete repository [" + repositoryId + "]" );
if (!this.repos[repoId]) {
throw new RepositoryNotFoundException(repoId);
}
delete this.repos[repoId];
return this; // Chainable
}
public getBranch({
branchId,
repoId,
}: {
branchId: string
repoId: string
}): Branch {
return this.getRepo(repoId).getBranch(branchId);
}
public getNode<NodeData = Record<string, unknown>>({
branchId,
key,
repoId,
}: {
branchId: string
key: string
repoId: string
}) {
return this.connect({
branchId,
repoId
})._getSingle<NodeData>(key);
}
public getProject(projectName: string): Project {
if (!projectName) {
throw new Error('Server: getProject: No projectName provided!');
}
const project = this.projects[projectName];
if (!project) {
throw new Error(`Server: getProject: Project ${projectName} not found!`);
// TODO Perhaps just return null?
}
return project;
}
public getRepo(repoId: string): Repo {
const repo = this.repos[repoId];
if (!repo) {
throw new RepositoryNotFoundException(repoId);
}
return repo;
}
install(app: App): Server {
const systemVersion = new Version(this.version);
if (app.minSystemVersion && systemVersion.lessThan(new Version(app.minSystemVersion))) {
throw new Error(`System version ${this.version} is lower than App minSystemVersion ${app.minSystemVersion}!`);
}
if (app.maxSystemVersion && systemVersion.greaterThan(new Version(app.maxSystemVersion))) {
throw new Error(`System version ${this.version} is higher than App maxSystemVersion ${app.maxSystemVersion}!`);
}
const index = this.applications.findIndex(a => a.key === app.key);
if (index !== -1) {
this.log.info(`Application ${app.key} already installed, replacing it.`);
this.applications[index] = app;
} else {
this.applications.push(app);
this.log.debug(`Application ${app.key} installed.`);
}
return this; // Chainable
} // install
public listRepos(): Repo[] {
return Object.values(this.repos);
}
public login(params: LoginParams): Server {
this.auth.login(params);
return this; // Chainable
}
public logout(): Server {
this.auth.logout();
return this; // Chainable
}
public modifyNode<NodeData = Record<string, unknown>>({
branchId,
editor,
key,
repoId,
}: {
branchId: string
editor: ModifyNodeParams<NodeData>['editor']
key: string
repoId: string
}) {
this.connect({
branchId,
repoId
}).modify<NodeData>({
editor,
key,
});
return this; // Can be chainable, since key is known
}
public setContext({
attributes,
principals,
projectName,
branch = projectName ? 'draft' : 'master',
repository = `com.enonic.cms.${projectName}`,
idProvider = 'system',
login,
user = login
? {login, idProvider}
: undefined,
}: {
attributes?: ContextAttributes
branch?: string
idProvider?: string
login?: string
principals?: PrincipalKey[]
projectName?: string
repository?: string
user?: ContextUserParams
}): Server {
if (!user) {
const currentUser = this.auth.getUser();
if (currentUser) {
user = {
idProvider: currentUser.idProvider,
login: currentUser.login,
};
}
}
this.context = new Context({
attributes,
branch,
principals,
repository,
server: this,
user: user,
});
return this; // Chainable
}
public su(): Server {
this.login({
idProvider: 'system',
// password: '',
user: 'su',
});
return this; // Chainable
}
} // class Server