7 Commits fd8caed83a ... 450ce95c1c

Author SHA1 Message Date
  Owen Diffey 450ce95c1c chore: Update workflow action version 1 month ago
  Owen Diffey 54441c078a fix(musare.sh): All tests always run 1 month ago
  Owen Diffey 2c9a7304a7 chore: Update workflows 1 month ago
  Owen Diffey 23a1e4909c refactor: Add compose file for local mounts 1 month ago
  Owen Diffey da2f73d176 fix(musare.sh): Removes quotes from optional arguments 1 month ago
  Kristian Vos 2d4b0ec702 chore: fix some eslint/typescript issues 1 month ago
  Owen Diffey f410f44bad fix: Eslint issues 1 month ago

+ 1 - 0
.env.example

@@ -1,5 +1,6 @@
 COMPOSE_PROJECT_NAME=musare
 DOCKER_COMMAND=docker
+CONTAINER_MODE=production
 
 APP_ENV=production
 

+ 3 - 2
.github/workflows/automated-tests.yml

@@ -4,7 +4,7 @@ on: [ push, pull_request, workflow_dispatch ]
 
 env:
     COMPOSE_PROJECT_NAME: musare
-    APP_ENV: production
+    APP_ENV: development
     BACKEND_HOST: 127.0.0.1
     BACKEND_PORT: 8080
     FRONTEND_HOST: 127.0.0.1
@@ -25,10 +25,11 @@ jobs:
     tests:
         runs-on: ubuntu-latest
         steps:
-            - uses: actions/checkout@v3
+            - uses: actions/checkout@v4
             - name: Build Musare
               run: |
                   cp .env.example .env
+                  sed -i 's/APP_ENV=production/APP_ENV=development/g' .env
                   ./musare.sh build
             - name: Start Musare
               run: ./musare.sh start

+ 33 - 0
.github/workflows/build.yml

@@ -0,0 +1,33 @@
+name: Musare Build
+
+on: [ push, pull_request, workflow_dispatch ]
+
+env:
+    COMPOSE_PROJECT_NAME: musare
+    APP_ENV: production
+    BACKEND_HOST: 127.0.0.1
+    BACKEND_PORT: 8080
+    FRONTEND_HOST: 127.0.0.1
+    FRONTEND_PORT: 80
+    MONGO_HOST: 127.0.0.1
+    MONGO_PORT: 27017
+    MONGO_ROOT_PASSWORD: PASSWORD_HERE
+    MONGO_USER_USERNAME: musare
+    MONGO_USER_PASSWORD: OTHER_PASSWORD_HERE
+    MONGO_DATA_LOCATION: .db
+    MONGO_VERSION: 5.0
+    REDIS_HOST: 127.0.0.1
+    REDIS_PORT: 6379
+    REDIS_PASSWORD: PASSWORD
+    REDIS_DATA_LOCATION: .redis
+
+jobs:
+    build:
+        runs-on: ubuntu-latest
+        steps:
+            - uses: actions/checkout@v4
+            - name: Build Musare
+              run: |
+                  cp .env.example .env
+                  ./musare.sh build
+

+ 1 - 1
.github/workflows/codeql-analysis.yml

@@ -18,7 +18,7 @@ jobs:
 
     steps:
     - name: Checkout repository
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     - name: Initialize CodeQL
       uses: github/codeql-action/init@v2

+ 5 - 8
.github/workflows/build-lint.yml → .github/workflows/lint.yml

@@ -1,10 +1,10 @@
-name: Musare Build and Lint
+name: Musare Lint
 
 on: [ push, pull_request, workflow_dispatch ]
 
 env:
     COMPOSE_PROJECT_NAME: musare
-    APP_ENV: production
+    APP_ENV: development
     BACKEND_HOST: 127.0.0.1
     BACKEND_PORT: 8080
     FRONTEND_HOST: 127.0.0.1
@@ -22,24 +22,21 @@ env:
     REDIS_DATA_LOCATION: .redis
 
 jobs:
-    build-lint:
+    lint:
         runs-on: ubuntu-latest
         steps:
-            - uses: actions/checkout@v3
+            - uses: actions/checkout@v4
             - name: Build Musare
               run: |
                   cp .env.example .env
+                  sed -i 's/APP_ENV=production/APP_ENV=development/g' .env
                   ./musare.sh build
             - name: Start Musare
               run: ./musare.sh start
             - name: Backend Lint
               run: ./musare.sh lint backend
-            - name: Backend Typescript
-              run: ./musare.sh typescript backend
             - name: Frontend Lint
               run: ./musare.sh lint frontend
-#            - name: Frontend Typescript
-#              run: ./musare.sh typescript frontend
             - name: Docs Lint
               run: ./musare.sh lint docs
             - name: Shell Lint

+ 1 - 0
.wiki/Configuration.md

@@ -26,6 +26,7 @@ machine, even though the application within the container is listening on `21017
 | --- | --- |
 | `COMPOSE_PROJECT_NAME` | Should be a unique name for this installation, especially if you have multiple instances of Musare on the same machine. |
 | `DOCKER_COMMAND` | Should be either `docker` or `podman`.  |
+| `CONTAINER_MODE` | Should be either `production` or `local`.  |
 | `APP_ENV` | Should be either `production` or `development`.  |
 | `BACKEND_HOST` | Backend container host. Only used for development mode. |
 | `BACKEND_PORT` | Backend container port. Only used for development mode. |

+ 2 - 1
backend/.eslintrc

@@ -83,7 +83,8 @@
 				"message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize."
 			}
 		],
-		"import/prefer-default-export": "off"
+		"import/prefer-default-export": "off",
+		"@typescript-eslint/no-explicit-any": 0
 	},
 	"overrides": [
 		{

+ 8 - 5
backend/src/JobContext.ts

@@ -1,3 +1,4 @@
+import { forEachIn } from "@common/utils/forEachIn";
 import { SessionSchema } from "@/modules/DataModule/models/sessions/schema";
 import Job, { JobOptions } from "@/Job";
 import { Log } from "@/LogBook";
@@ -5,9 +6,11 @@ import DataModule from "@/modules/DataModule";
 import { UserModel } from "@/modules/DataModule/models/users/schema";
 import { JobDerived } from "./types/JobDerived";
 import assertJobDerived from "./utils/assertJobDerived";
-import { GetModelPermissionsResult } from "./modules/DataModule/models/users/jobs/GetModelPermissions";
+import {
+	GetMultipleModelPermissionsResult,
+	GetSingleModelPermissionsResult
+} from "./modules/DataModule/models/users/jobs/GetModelPermissions";
 import { GetPermissionsResult } from "./modules/DataModule/models/users/jobs/GetPermissions";
-import { forEachIn } from "@common/utils/forEachIn";
 
 const permissionRegex =
 	/^(?<moduleName>[a-z]+)\.(?<modelOrJobName>[A-z]+)\.(?<jobName>[A-z]+)(?:\.(?<modelId>[A-z0-9]{24}))?(?:\.(?<extra>[A-z]+))?$/;
@@ -107,7 +110,7 @@ export default class JobContext {
 			const permissions = (await this.executeJob(GetModelPermissions, {
 				modelName: modelOrJobName,
 				modelId
-			})) as GetModelPermissionsResult;
+			})) as GetSingleModelPermissionsResult;
 
 			let modelPermission = `data.${modelOrJobName}.${jobName}`;
 
@@ -131,7 +134,7 @@ export default class JobContext {
 	}
 
 	public async assertPermissions(permissions: string[]) {
-		let hasPermission: { [permission: string]: boolean } = {};
+		const hasPermission: { [permission: string]: boolean } = {};
 		permissions.forEach(permission => {
 			hasPermission[permission] = false;
 		});
@@ -199,7 +202,7 @@ export default class JobContext {
 						modelName,
 						modelIds
 					}
-				)) as GetModelPermissionsResult;
+				)) as GetMultipleModelPermissionsResult;
 
 				dataPermissionsForThisModel.forEach(
 					({

+ 0 - 1
backend/src/main.ts

@@ -1,5 +1,4 @@
 import * as readline from "node:readline";
-import mongoose from "mongoose";
 import ModuleManager from "@/ModuleManager";
 import LogBook from "@/LogBook";
 import JobQueue from "@/JobQueue";

+ 2 - 1
backend/src/modules/DataModule/DataModuleJob.ts

@@ -5,7 +5,8 @@ import { UserSchema } from "./models/users/schema";
 
 export default abstract class DataModuleJob extends Job {
 	protected static _modelName: string;
-	protected static _isBulk: boolean = false;
+
+	protected static _isBulk = false;
 
 	protected static _hasPermission:
 		| boolean

+ 2 - 2
backend/src/modules/DataModule/DeleteManyByIdJob.ts

@@ -3,7 +3,7 @@ import DataModule from "../DataModule";
 import DataModuleJob from "./DataModuleJob";
 
 export default abstract class FindManyByIdJob extends DataModuleJob {
-	protected static _isBulk: boolean = true;
+	protected static _isBulk = true;
 
 	protected override async _validate() {
 		if (typeof this._payload !== "object" || this._payload === null)
@@ -19,7 +19,7 @@ export default abstract class FindManyByIdJob extends DataModuleJob {
 	protected async _execute() {
 		const model = await DataModule.getModel(this.getModelName());
 
-		const _ids = this._payload._ids;
+		const { _ids } = this._payload;
 		const query = model.deleteMany({
 			_id: _ids
 		});

+ 2 - 2
backend/src/modules/DataModule/FindManyByIdJob.ts

@@ -3,7 +3,7 @@ import DataModule from "../DataModule";
 import DataModuleJob from "./DataModuleJob";
 
 export default abstract class FindManyByIdJob extends DataModuleJob {
-	protected static _isBulk: boolean = true;
+	protected static _isBulk = true;
 
 	protected override async _validate() {
 		if (typeof this._payload !== "object" || this._payload === null)
@@ -19,7 +19,7 @@ export default abstract class FindManyByIdJob extends DataModuleJob {
 	protected async _execute() {
 		const model = await DataModule.getModel(this.getModelName());
 
-		const _ids = this._payload._ids;
+		const { _ids } = this._payload;
 		const query = model.find({
 			_id: _ids
 		});

+ 7 - 2
backend/src/modules/DataModule/models/users/jobs/GetModelPermissions.ts

@@ -6,9 +6,14 @@ import ModuleManager from "@/ModuleManager";
 import GetPermissions, { GetPermissionsResult } from "./GetPermissions";
 import DataModuleJob from "@/modules/DataModule/DataModuleJob";
 
+export type GetSingleModelPermissionsResult = Record<string, boolean>; // Returned when getting permissions for a single modelId
+export type GetMultipleModelPermissionsResult = Record<
+	string,
+	Record<string, boolean>
+>; // Returned when getting permissions for several modelIds
 export type GetModelPermissionsResult =
-	| Record<string, boolean>
-	| Record<string, Record<string, boolean>>;
+	| GetSingleModelPermissionsResult
+	| GetMultipleModelPermissionsResult;
 
 export default class GetModelPermissions extends DataModuleJob {
 	protected static _modelName = "users";

+ 0 - 1
backend/src/modules/EventsModule/jobs/SubscribeMany.ts

@@ -1,4 +1,3 @@
-import { forEachIn } from "@common/utils/forEachIn";
 import Job, { JobOptions } from "@/Job";
 import EventsModule from "@/modules/EventsModule";
 

+ 0 - 12
docker-compose.dev.yml

@@ -5,11 +5,6 @@ services:
     ports:
       - "${BACKEND_HOST:-0.0.0.0}:${BACKEND_PORT:-8080}:8080"
       - "${BACKEND_HOST:-0.0.0.0}:${BACKEND_DEBUG_PORT:-9229}:9229"
-    volumes:
-      - ./.git:/opt/.git:ro
-      - ./common:/opt/common
-      - ./types:/opt/types
-      - ./backend:/opt/app
     environment:
       - APP_ENV=${APP_ENV:-development}
       - BACKEND_DEBUG=${BACKEND_DEBUG:-false}
@@ -17,11 +12,6 @@ services:
   frontend:
     build:
       dockerfile: ./Dockerfile.dev
-    volumes:
-      - ./.git:/opt/.git:ro
-      - ./common:/opt/common
-      - ./types:/opt/types
-      - ./frontend:/opt/app
     environment:
       - APP_ENV=${APP_ENV:-development}
 
@@ -32,5 +22,3 @@ services:
   redis:
     ports:
       - "${REDIS_HOST:-0.0.0.0}:${REDIS_PORT:-6379}:6379"
-    volumes:
-      - ${REDIS_DATA_LOCATION:-./redis}:/data

+ 18 - 0
docker-compose.local.yml

@@ -0,0 +1,18 @@
+services:
+  backend:
+    volumes:
+      - ./.git:/opt/.git:ro
+      - ./common:/opt/common
+      - ./types:/opt/types
+      - ./backend:/opt/app
+
+  frontend:
+    volumes:
+      - ./.git:/opt/.git:ro
+      - ./common:/opt/common
+      - ./types:/opt/types
+      - ./frontend:/opt/app
+
+  redis:
+    volumes:
+      - ${REDIS_DATA_LOCATION:-./redis}:/data

+ 14 - 7
musare.sh

@@ -73,6 +73,9 @@ composeFiles="-f docker-compose.yml"
 if [[ ${APP_ENV} == "development" ]]; then
     composeFiles="${composeFiles} -f docker-compose.dev.yml"
 fi
+if [[ ${CONTAINER_MODE} == "local" ]]; then
+    composeFiles="${composeFiles} -f docker-compose.local.yml"
+fi
 if [[ -f docker-compose.override.yml ]]; then
     composeFiles="${composeFiles} -f docker-compose.override.yml"
 fi
@@ -305,17 +308,20 @@ handleLinting()
     set +e
     if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *frontend* ]]; then
         echo -e "${CYAN}Running frontend lint...${NC}"
-        ${dockerCompose} exec -T frontend npm run lint -- "${cache}" "${fix}"
+        # shellcheck disable=SC2086
+        ${dockerCompose} exec -T frontend npm run lint -- ${cache} ${fix}
         frontendExitValue=$?
     fi
     if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *backend* ]]; then
         echo -e "${CYAN}Running backend lint...${NC}"
-        ${dockerCompose} exec -T backend npm run lint -- "${cache}" "${fix}"
+        # shellcheck disable=SC2086
+        ${dockerCompose} exec -T backend npm run lint -- ${cache} ${fix}
         backendExitValue=$?
     fi
     if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *docs* ]]; then
         echo -e "${CYAN}Running docs lint...${NC}"
-        ${docker} run --rm -v "${scriptLocation}":/workdir ghcr.io/igorshubovych/markdownlint-cli:latest ".wiki" "*.md" "${fix}"
+        # shellcheck disable=SC2086
+        ${docker} run --rm -v "${scriptLocation}":/workdir ghcr.io/igorshubovych/markdownlint-cli:latest ".wiki" "*.md" ${fix}
         docsExitValue=$?
     fi
     if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *shell* ]]; then
@@ -351,12 +357,14 @@ handleTypescript()
     set +e
     if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *frontend* ]]; then
         echo -e "${CYAN}Running frontend typescript check...${NC}"
-        ${dockerCompose} exec -T frontend npm run typescript -- "${strict}"
+        # shellcheck disable=SC2086
+        ${dockerCompose} exec -T frontend npm run typescript -- ${strict}
         frontendExitValue=$?
     fi
     if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *backend* ]]; then
         echo -e "${CYAN}Running backend typescript check...${NC}"
-        ${dockerCompose} exec -T backend npm run typescript -- "${strict}"
+        # shellcheck disable=SC2086
+        ${dockerCompose} exec -T backend npm run typescript -- ${strict}
         backendExitValue=$?
     fi
     set -e
@@ -368,8 +376,7 @@ handleTypescript()
 # Execute automated tests in services
 handleTests()
 {
-    # shellcheck disable=SC2068
-    servicesString=$(handleServices "backend frontend" ${services[@]})
+    servicesString=$(handleServices "backend frontend" "${@:2}")
     if [[ ${servicesString:0:1} != 1 ]]; then
         throw "${servicesString:2}\n${YELLOW}Usage: ${1} [backend, frontend]"
     fi