Skip to content

Commit

Permalink
Deploying to gh-pages from @ f2f0b36 🚀
Browse files Browse the repository at this point in the history
  • Loading branch information
MarvinOehlerkingCap committed Oct 19, 2023
1 parent 4d4bb48 commit 9bac205
Show file tree
Hide file tree
Showing 795 changed files with 140,066 additions and 144,579 deletions.
6 changes: 3 additions & 3 deletions additional-documentation/nestjs-application.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ <h3>preconditions</h3>
<li>Have RabbitMQ started, run <code>docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:3.8.9-management</code>. This starts RabbitMQ on port 5672 and a web admin console at localhost:15672 (use guest:guest to login).</li>
<li>Have MinIO (S3 compatible object storage), run [optional if you need files-storage module]</li>
</ol>
<div><pre class="line-numbers"><code class="language-bash">docker run \
<b>Example :</b><div><pre class="line-numbers"><code class="language-bash">docker run \
--name minioS3storage \
-p 9000:9000 \
-p 9001:9001 \
Expand All @@ -78,7 +78,7 @@ <h3>preconditions</h3>
<li>Have ErWIn-IDM started [currently not needed, but will be mandatory in the future]. For more information look <a href="https://hpi-schul-cloud.github.io/schulcloud-server/additional-documentation/nestjs-application/keycloak.html">here</a>.</li>
</ol>
<p>Change directory to the <code>schulcloud-server</code> root folder. Execute following command to setup the ErWIn-IDM container:</p>
<div><pre class="line-numbers"><code class="language-bash">docker run \
<b>Example :</b><div><pre class="line-numbers"><code class="language-bash">docker run \
--name erwinidm \
-p 8080:8080 \
-p 8443:8443 \
Expand Down Expand Up @@ -171,7 +171,7 @@ <h3>Content</h3>
<p>For further reading, browse <code>apps/server/doc</code>.</p>
<h4>NestJS CLI</h4>
<p>To use the NestJS CLI, <a href="https://docs.nestjs.com/#installation">install the nest cli globally</a>.</p>
<div><pre class="line-numbers"><code class="language-bash"> npm i -g &#64;nestjs/cli</code></pre></div><p>Then you may use features like <code>nest g service foo</code> within of <code>/apps/server/src</code>.</p>
<b>Example :</b><div><pre class="line-numbers"><code class="language-bash"> npm i -g &#64;nestjs/cli</code></pre></div><p>Then you may use features like <code>nest g service foo</code> within of <code>/apps/server/src</code>.</p>
<h4>Debugging</h4>
<p>There are launch configurations available for VSCode in <code>.vscode/launch.default.json</code></p>
<h3>Tech Stack</h3>
Expand Down
20 changes: 10 additions & 10 deletions additional-documentation/nestjs-application/authorisation.html
Original file line number Diff line number Diff line change
Expand Up @@ -153,19 +153,19 @@ <h2>How to use Authorization Service</h2>
We set empty array as required for passing permissions to make it visible that no string base permission is needed.</p>
</blockquote>
<h3>Example 1 - Execute a Single Operation</h3>
<div><pre class="line-numbers"><code class="language-javascript"> this.authorizationService.checkPermission(user, course, AuthorizationContextBuilder.write([])
<b>Example :</b><div><pre class="line-numbers"><code class="language-javascript"> this.authorizationService.checkPermission(user, course, AuthorizationContextBuilder.write([])
// or
this.authorizationService.hasPermission(user, course, AuthorizationContextBuilder.write([])
// next orchestration steps</code></pre></div><h3>Example 2 - Execute a Single Operation with Loading Resources</h3>
<div><pre class="line-numbers"><code class="language-javascript">// If you don&#39;t have an entity but an entity type and id, you can check permission by reference
<b>Example :</b><div><pre class="line-numbers"><code class="language-javascript">// If you don&#39;t have an entity but an entity type and id, you can check permission by reference
await this.authorizationService.checkPermissionByReferences(userId, AllowedEntity.course, courseId, AuthorizationContextBuilder.read([]));
// or
await this.authorizationService.hasPermissionByReferences(userId, AllowedEntity.course, courseId, AuthorizationContextBuilder.read([]));
// next orchestration steps</code></pre></div><h3>Example 3 - Set Permission(s) of User as Required</h3>
<div><pre class="line-numbers"><code class="language-javascript">// Multiple permissions can be added. For a successful authorization, the user need all of them.
<b>Example :</b><div><pre class="line-numbers"><code class="language-javascript">// Multiple permissions can be added. For a successful authorization, the user need all of them.
await this.authorizationService.hasPermission(userId, course, AuthorizationContextBuilder.read([Permissions.COURSE_VIEW]));
// next orchestration steps</code></pre></div><h3>Example 4 - Define Context for Multiple Places</h3>
<div><pre class="line-numbers"><code class="language-javascript">/** const **/
<b>Example :</b><div><pre class="line-numbers"><code class="language-javascript">/** const **/
export const FileStorageAuthorizationContext = {
create: AuthorizationContextBuilder.write([Permission.FILESTORAGE_CREATE]),
read: AuthorizationContextBuilder.read([Permission.FILESTORAGE_VIEW]),
Expand All @@ -177,7 +177,7 @@ <h3>Example 1 - Execute a Single Operation</h3>
this.authorizationService.hasPermission(userId, course, PermissionContexts.create);
// do other orchestration steps</code></pre></div><h2>How to use in our use cases</h2>
<h3>Example - Create a school by <strong>superhero</strong></h3>
<div><pre class="line-numbers"><code class="language-ts">async createSchoolBySuperhero(userId: EntityId, params: { name: string }) {
<b>Example :</b><div><pre class="line-numbers"><code class="language-ts">async createSchoolBySuperhero(userId: EntityId, params: { name: string }) {

const user = this.authorizationService.getUserWithPermissions(userId);
this.authorizationService.hasAllPermissions(user, [Permission.SCHOOL_CREATE]);
Expand All @@ -189,7 +189,7 @@ <h3>Example - Create a school by <strong>superhero</strong></h3>
return true;
}
</code></pre></div><h3>Example - Create user by <strong>admin</strong></h3>
<div><pre class="line-numbers"><code class="language-ts">
<b>Example :</b><div><pre class="line-numbers"><code class="language-ts">
async createUserByAdmin(userId: EntityId, params: { email: string, firstName: string, lastName: string, schoolId: EntityId }) {

const user = this.authorizationService.getUserWithPermissions(userId);
Expand All @@ -203,7 +203,7 @@ <h3>Example - Create a school by <strong>superhero</strong></h3>
return true;
}
</code></pre></div><h3>Example - Edit course by <strong>admin</strong></h3>
<div><pre class="line-numbers"><code class="language-ts">// admin
<b>Example :</b><div><pre class="line-numbers"><code class="language-ts">// admin
async editCourseByAdmin(userId: EntityId, params: { courseId: EntityId, description: string }) {

const course = this.courseService.getCourse(params.courseId);
Expand All @@ -220,7 +220,7 @@ <h3>Example - Create a school by <strong>superhero</strong></h3>
return true;
}
</code></pre></div><h3>Example - Create a Course</h3>
<div><pre class="line-numbers"><code class="language-ts">// User can create a course in scope a school, you need to check if he can it by school
<b>Example :</b><div><pre class="line-numbers"><code class="language-ts">// User can create a course in scope a school, you need to check if he can it by school
async createCourse(userId: EntityId, params: { schoolId: EntityId }) {
const user = this.authorizationService.getUserWithPermissions(userId);
const school = this.schoolService.getSchool(params.schoolId);
Expand All @@ -239,7 +239,7 @@ <h3>Example - Create a school by <strong>superhero</strong></h3>
return course;
}
</code></pre></div><h3>Example - Create a Lesson</h3>
<div><pre class="line-numbers"><code class="language-ts">// User can create a lesson to course, so you have a courseId
<b>Example :</b><div><pre class="line-numbers"><code class="language-ts">// User can create a lesson to course, so you have a courseId
async createLesson(userId: EntityId, params: { courseId: EntityId }) {
const course = this.courseService.getCourse(params.courseId);
const user = this.authorizationService.getUserWithPermissions(userId);
Expand All @@ -261,7 +261,7 @@ <h3>Example - Create a school by <strong>superhero</strong></h3>
<blockquote>
<p>Attention: The target model must be populated</p>
</blockquote>
<div><pre class="line-numbers"><code class="language-ts">&#64;Injectable()
<b>Example :</b><div><pre class="line-numbers"><code class="language-ts">&#64;Injectable()
export class NewsRule extends BasePermission&lt;News&gt; {
constructor(private readonly authorizationHelper: AuthorizationHelper, private readonly schoolRule: SchoolRule, private readonly courseRule: CourseRule) {
super();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ <h3>Order of declarations</h3>
<li>methods</li>
</ol>
<p>Example:</p>
<div><pre class="line-numbers"><code class="language-Typescript">export class Course {
<b>Example :</b><div><pre class="line-numbers"><code class="language-Typescript">export class Course {
// 1. properties
name: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ <h2>Feathers application</h2>
<p>Based on <a href="https://nodejs.org/en/">Node.js</a> and <a href="https://feathersjs.com/">Feathers</a></p>
<h2>Application seperation</h2>
<p>In order to seperate NestJS and Feathers each application runs in its own express instance. These express instances are then mounted on seperate paths under a common root express instance.</p>
<div><pre class="line-numbers"><code class="language-none">Root-Express-App
<b>Example :</b><div><pre class="line-numbers"><code class="language-none">Root-Express-App
├─ api/v1/ --&gt; Feathers-App
├─ api/v3/ --&gt; NestJS-App</code></pre></div><p>This ensures that each application can run its own middleware stack for authentication, error handling, logging etc.</p>
<p>The mount paths don&#39;t have any impact on the routes inside of the applications, e.g. the path <code>/api/v3/news</code> will translate to the inner path <code>/news</code>. That means that in terms of route matching each child application doesn&#39;t have to take any measures regarding the path prefix. It simply works as it was mounted to <code>/</code>.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<h1>Domain Object Validation</h1>
<p>If you need to validate a domain object, please write an independent class, so that the domain object itself, its repo and services can reuse it.</p>
<p>Eric Evans suggests using the specification pattern.<br>A specification fulfills the following interface:</p>
<div><pre class="line-numbers"><code class="language-typescript">public interface Specification&lt;T&gt; {
<b>Example :</b><div><pre class="line-numbers"><code class="language-typescript">public interface Specification&lt;T&gt; {
boolean isSatisfiedBy(T t);
}</code></pre></div><p>A specification checks if a domain object fulfills the conditions of the specification.</p>
<p>A specification can simply specify that a domain object is valid. E.g. a <code>Task</code> has an owner and a description.<br>A specification can specify more complex and specialized conditions. E.g. <code>Task</code> where every student assigned to the task&#39;s course has handed in a submission. </p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ <h1>Exception Handling</h1>
<p><img src="../../assets/exception-hierarchy.svg" alt="" class="img-responsive"></p>
<p>We separate our business exceptions from technical exceptions. While for technical exceptions, we use the predefined HTTPExceptions from NestJS, business exceptions inherit from abstract BusinessException.</p>
<p>By default, implementations of BusinessException must define</p>
<div><pre class="line-numbers"><code class="language-JSON"> code: 500
<b>Example :</b><div><pre class="line-numbers"><code class="language-JSON"> code: 500
type: &quot;CUSTOM_ERROR_TYPE&quot;,
title: &quot;Custom Error Type&quot;,
message: &quot;Human readable details&quot;,
Expand All @@ -68,15 +68,15 @@ <h1>Exception Handling</h1>
<p>Pipes can be used as input validation. To get errors reported in the correct format, they can define a custom exception factory when they should produce api validation error or other exceptions, handled by clients.</p>
<h2>Chaining errors with the <code>cause</code> property</h2>
<p>If you catch an error and throw a new one, put the original error in the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause"><code>cause</code> property</a> of the new error. See example:</p>
<div><pre class="line-numbers"><code class="language-typescript">try {
<b>Example :</b><div><pre class="line-numbers"><code class="language-typescript">try {
someMethod();
} catch(error) {
throw new ForbiddenException(&#39;some message&#39;, { cause: error });
}</code></pre></div><h2>Loggable exceptions</h2>
<p>If you want the error log to contain more information than just the exception message, use or create an exception which implements the <code>Loggable</code> interface. Don&#39;t put data directly in the exception message!</p>
<p>A loggable exception should extend the respective <a href="https://docs.nestjs.com/exception-filters#built-in-http-exceptions">Built-in HTTP exception</a> from NestJS. For the name just put in &quot;Loggable&quot; before the word &quot;Exception&quot;, e.g. &quot;BadRequestLoggableException&quot;. Except for logging a loggable exception behaves like any other exception, specifically the error response is not affected by this.</p>
<p>See example below.</p>
<div><pre class="line-numbers"><code class="language-TypeScript">export class UnauthorizedLoggableException extends UnauthorizedException implements Loggable {
<b>Example :</b><div><pre class="line-numbers"><code class="language-TypeScript">export class UnauthorizedLoggableException extends UnauthorizedException implements Loggable {
constructor(private readonly username: string, private readonly systemId?: string) {
super();
}
Expand All @@ -93,7 +93,7 @@ <h2>Chaining errors with the <code>cause</code> property</h2>

return message;
}
}</code></pre></div><div><pre class="line-numbers"><code class="language-TypeScript">export class YourService {
}</code></pre></div><b>Example :</b><div><pre class="line-numbers"><code class="language-TypeScript">export class YourService {
public sampleServiceMethod(username, systemId) {
throw new UnauthorizedLoggableException(username, systemId);
}
Expand Down
10 changes: 5 additions & 5 deletions additional-documentation/nestjs-application/file-structure.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ <h1>Architecture mapping to Code</h1>
<h2>Conventions</h2>
<h3>File structure</h3>
<p>The server app located in <code>/apps/server</code> is structured like. Beside each ts-file, a test file _.spec.ts has to be added for unit tests (hidden for simplification). Use index.ts files that combine a folders content and export all files from within of the folder using <code>export _ from &#39;./file&#39;</code> where this makes sense. When there are naming conflicts, use more specific names and correct concepts. Think about not to create sub-folders, when only one concept exist.</p>
<div><pre class="line-numbers"><code class="language-js">src/ // sourcecode &amp; unit tests
<b>Example :</b><div><pre class="line-numbers"><code class="language-js">src/ // sourcecode &amp; unit tests
- config/ // for global definitions
- modules/ // for your NestJS modules
- [module] // where [module] could be like user, homework, school
Expand Down Expand Up @@ -139,15 +139,15 @@ <h2>Components</h2>
<p>Components are defined as NestJS <a href="https://docs.nestjs.com/modules">Modules</a>. </p>
<h3>Communication between components</h3>
<p>To access other modules services, it can be injected anywhere. The usage is allowed only, when the module which owns that service has exported it in the modules definition.</p>
<div><pre class="line-numbers"><code class="language-TypeScript">// modules/feathers/feathers-service.provider.ts
<b>Example :</b><div><pre class="line-numbers"><code class="language-TypeScript">// modules/feathers/feathers-service.provider.ts
// modules/feathers/feathers.module.ts
&#64;Module({
providers: [FeathersServiceProvider],
exports: [FeathersServiceProvider],
})
export class FeathersModule {}
</code></pre></div><p>The feathers module is used to handle how the application is using legacy services, when access them, inject the <code>FeathersServiceProvider</code> but in your module definition, import the <code>FeathersModule</code>.</p>
<div><pre class="line-numbers"><code class="language-TypeScript">// your module, here modules/authorization/authorization.module.ts
<b>Example :</b><div><pre class="line-numbers"><code class="language-TypeScript">// your module, here modules/authorization/authorization.module.ts
&#64;Module({
imports: [FeathersModule], // here import the services module
// providers: [AuthorizationService, FeathersAuthProvider],
Expand Down Expand Up @@ -178,7 +178,7 @@ <h3>Communication between components</h3>
<h3>Access NestJS injectable from Feathers</h3>
<p>To access a NestJS service from a legacy Feathers service you need to make the NestJS service known to the Feathers service-collection in <code>main.ts</code>. <br>
This possibility should not be used for new features in Feathers, but it can help if you want to refactor a Feathers service to NestJs although other Feathers services depend on it.</p>
<div><pre class="line-numbers"><code class="language-TypeScript"> // main.ts
<b>Example :</b><div><pre class="line-numbers"><code class="language-TypeScript"> // main.ts
async function bootstrap() {
// (...)
feathersExpress.services[&#39;nest-rocket-chat&#39;] = nestApp.get(RocketChatService);
Expand All @@ -196,7 +196,7 @@ <h2>Layered Architecture</h2>
<h3>Controller</h3>
<p>A modules api layer is defined within of <a href="https://docs.nestjs.com/controllers">controllers</a>.</p>
<p>The main responsibilities of a controller is to define the REST API interface as openAPI specification and map DTO&#39;s to match the logic layers interfaces.</p>
<div><pre class="line-numbers"><code class="language-TypeScript"> &#64;Post()
<b>Example :</b><div><pre class="line-numbers"><code class="language-TypeScript"> &#64;Post()
async create(&#64;CurrentUser() currentUser: ICurrentUser, &#64;Body() params: CreateNewsParams): Promise&lt;NewsResponse&gt; {
const news = await this.newsUc.create(
currentUser.userId,
Expand Down
4 changes: 2 additions & 2 deletions additional-documentation/nestjs-application/git.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ <h2>Branch name conventions</h2>
</ul>
</li>
</ul>
<div><pre class="line-numbers"><code class="language-none">BC-XXXX-kebab-case-short-description</code></pre></div><h2>Commit message conventions</h2>
<b>Example :</b><div><pre class="line-numbers"><code class="language-none">BC-XXXX-kebab-case-short-description</code></pre></div><h2>Commit message conventions</h2>
<ul>
<li>Squashed commit subject should start with a ticket number, and end with a PR number</li>
<li>Clean body (contains all commits by default)<ul>
Expand All @@ -86,7 +86,7 @@ <h2>Branch name conventions</h2>
</li>
<li>Feel free to write actual text</li>
</ul>
<div><pre class="line-numbers"><code class="language-none">BC-1993 - lesson lernstore and geogebra copy (#3532)
<b>Example :</b><div><pre class="line-numbers"><code class="language-none">BC-1993 - lesson lernstore and geogebra copy (#3532)

In order to make sure developers in the future can find out why changes have been made,
we would like some descriptive text here that explains what we did and why.
Expand Down
Loading

0 comments on commit 9bac205

Please sign in to comment.