Repository: solid/community-server
Pull request #68 (2020-08-25 08:54:15)

Move ACL init into dedicated Setup component
This is a requirement for enabling dependency injection.

ACL init will likely change in the future, but other things may be added in this setup component in the future.

rubensworks: Ah right, conventional commits :-)

You should add a commit check for that!

Anyways, you can squash to rewrite the commit message.
joachimvh: Ah true, forgot I can just rewrite that. Not sure how to add a commit check for that one actually.

Patch:
diff --git a/bin/server.ts b/bin/server.ts
index 6408ddb74..acfaeaeb1 100644
--- a/bin/server.ts
+++ b/bin/server.ts
@@ -1,6 +1,4 @@
 #!/usr/bin/env node
-import { DATA_TYPE_BINARY } from '../src/util/ContentTypes';
-import streamifyArray from 'streamify-array';
 import yargs from 'yargs';
 import {
   AcceptPreferenceParser,
@@ -13,6 +11,7 @@ import {
   QuadToTurtleConverter,
   Representation,
   RepresentationConvertingStore,
+  Setup,
   SimpleAclAuthorizer,
   SimpleBodyParser,
   SimpleCredentialsExtractor,
@@ -98,38 +97,8 @@ const httpHandler = new AuthenticatedLdpHandler({
 
 const httpServer = new ExpressHttpServer(httpHandler);
 
-// Set up acl so everything can still be done by default
-// Note that this will need to be adapted to go through all the correct channels later on
-const aclSetup = async(): Promise<void> => {
-  const acl = `@prefix   acl:  <http://www.w3.org/ns/auth/acl#>.
-@prefix  foaf:  <http://xmlns.com/foaf/0.1/>.
-
-<#authorization>
-    a               acl:Authorization;
-    acl:agentClass  foaf:Agent;
-    acl:mode        acl:Read;
-    acl:mode        acl:Write;
-    acl:mode        acl:Append;
-    acl:mode        acl:Delete;
-    acl:mode        acl:Control;
-    acl:accessTo    <${base}>;
-    acl:default     <${base}>.`;
-  await store.setRepresentation(
-    await aclManager.getAcl({ path: base }),
-    {
-      dataType: DATA_TYPE_BINARY,
-      data: streamifyArray([ acl ]),
-      metadata: {
-        raw: [],
-        profiles: [],
-        contentType: 'text/turtle',
-      },
-    },
-  );
-};
-aclSetup().then((): void => {
-  httpServer.listen(port);
-
+const setup = new Setup(httpServer, store, aclManager);
+setup.setup(port, base).then((): void => {
   process.stdout.write(`Running at ${base}\n`);
 }).catch((error): void => {
   process.stderr.write(`${error}\n`);
diff --git a/index.ts b/index.ts
index a811b8483..7b57a8b8d 100644
--- a/index.ts
+++ b/index.ts
@@ -10,6 +10,9 @@ export * from './src/authorization/SimpleAclAuthorizer';
 export * from './src/authorization/SimpleAuthorizer';
 export * from './src/authorization/SimpleExtensionAclManager';
 
+// Init
+export * from './src/init/Setup';
+
 // LDP/HTTP
 export * from './src/ldp/http/AcceptPreferenceParser';
 export * from './src/ldp/http/BodyParser';
diff --git a/src/init/Setup.ts b/src/init/Setup.ts
new file mode 100644
index 000000000..9aa3d9a18
--- /dev/null
+++ b/src/init/Setup.ts
@@ -0,0 +1,61 @@
+import { AclManager } from '../authorization/AclManager';
+import { DATA_TYPE_BINARY } from '../util/ContentTypes';
+import { ExpressHttpServer } from '../server/ExpressHttpServer';
+import { ResourceStore } from '../storage/ResourceStore';
+import streamifyArray from 'streamify-array';
+
+/**
+ * Invokes all logic to setup a server.
+ */
+export class Setup {
+  private readonly httpServer: ExpressHttpServer;
+  private readonly store: ResourceStore;
+  private readonly aclManager: AclManager;
+
+  public constructor(httpServer: ExpressHttpServer, store: ResourceStore, aclManager: AclManager) {
+    this.httpServer = httpServer;
+    this.store = store;
+    this.aclManager = aclManager;
+  }
+
+  /**
+   * Set up a server at the given port and base URL.
+   * @param port - A port number.
+   * @param base - A base URL.
+   */
+  public async setup(port: number, base: string): Promise<void> {
+    // Set up acl so everything can still be done by default
+    // Note that this will need to be adapted to go through all the correct channels later on
+    const aclSetup = async(): Promise<void> => {
+      const acl = `@prefix   acl:  <http://www.w3.org/ns/auth/acl#>.
+@prefix  foaf:  <http://xmlns.com/foaf/0.1/>.
+
+<#authorization>
+    a               acl:Authorization;
+    acl:agentClass  foaf:Agent;
+    acl:mode        acl:Read;
+    acl:mode        acl:Write;
+    acl:mode        acl:Append;
+    acl:mode        acl:Delete;
+    acl:mode        acl:Control;
+    acl:accessTo    <${base}>;
+    acl:default     <${base}>.`;
+      await this.store.setRepresentation(
+        await this.aclManager.getAcl({ path: base }),
+        {
+          dataType: DATA_TYPE_BINARY,
+          data: streamifyArray([ acl ]),
+          metadata: {
+            raw: [],
+            profiles: [],
+            contentType: 'text/turtle',
+          },
+        },
+      );
+    };
+
+    await aclSetup();
+
+    this.httpServer.listen(port);
+  }
+}


Test patch:
diff --git a/test/unit/init/Setup.test.ts b/test/unit/init/Setup.test.ts
new file mode 100644
index 000000000..230c70901
--- /dev/null
+++ b/test/unit/init/Setup.test.ts
@@ -0,0 +1,31 @@
+import { Setup } from '../../../src/init/Setup';
+
+describe('Setup', (): void => {
+  let httpServer: any;
+  let store: any;
+  let aclManager: any;
+  let setup: Setup;
+  beforeEach(async(): Promise<void> => {
+    store = {
+      setRepresentation: jest.fn(async(): Promise<void> => undefined),
+    };
+    aclManager = {
+      getAcl: jest.fn(async(): Promise<void> => undefined),
+    };
+    httpServer = {
+      listen: jest.fn(),
+    };
+    setup = new Setup(httpServer, store, aclManager);
+  });
+
+  it('starts an HTTP server.', async(): Promise<void> => {
+    await setup.setup(3000, 'http://localhost:3000/');
+    expect(httpServer.listen).toHaveBeenCalledWith(3000);
+  });
+
+  it('invokes ACL initialization.', async(): Promise<void> => {
+    await setup.setup(3000, 'http://localhost:3000/');
+    expect(aclManager.getAcl).toHaveBeenCalledWith({ path: 'http://localhost:3000/' });
+    expect(store.setRepresentation).toHaveBeenCalledTimes(1);
+  });
+});