building a foundation and breaking prisma
Co-authored-by: Spacelord <Spacelord09@users.noreply.github.com>
This commit is contained in:
commit
18a4393765
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
config.js
|
||||
node_modules
|
||||
.env
|
||||
config.json
|
||||
dist
|
20
.prettierrc.json
Normal file
20
.prettierrc.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"tabWidth": 8,
|
||||
"useTabs": true,
|
||||
"arrowParens": "always",
|
||||
|
||||
"bracketSameLine": true,
|
||||
"bracketSpacing": true,
|
||||
"embeddedLanguageFormatting": "auto",
|
||||
"endOfLine": "lf",
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"insertPragma": false,
|
||||
"jsxSingleQuote": false,
|
||||
"printWidth": 200,
|
||||
"proseWrap": "preserve",
|
||||
"quoteProps": "as-needed",
|
||||
"requirePragma": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none"
|
||||
}
|
12
allowedStaticPaths.json
Normal file
12
allowedStaticPaths.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"allowedStaticFiles": [
|
||||
"bootstrap-icons/font/bootstrap-icons.css",
|
||||
"bootstrap/dist/css/bootstrap.min.css",
|
||||
"bootstrap/dist/js/bootstrap.bundle.min.js",
|
||||
"jquery/dist/jquery.min.js",
|
||||
"darkreader/darkreader.js",
|
||||
"bootstrap-icons/font/fonts/bootstrap-icons.woff2",
|
||||
"bootstrap/dist/css/bootstrap.min.css.map"
|
||||
],
|
||||
"debugMode": false
|
||||
}
|
52
eslintrc.json
Normal file
52
eslintrc.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"extends": ["eslint:recommended", "prettier"],
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2021
|
||||
},
|
||||
"rules": {
|
||||
"arrow-spacing": ["warn", { "before": true, "after": true }],
|
||||
"brace-style": ["error", "stroustrup", { "allowSingleLine": true }],
|
||||
"comma-dangle": ["error", "always-multiline"],
|
||||
"comma-spacing": "error",
|
||||
"comma-style": "error",
|
||||
"curly": ["error", "multi-line", "consistent"],
|
||||
"dot-location": ["error", "property"],
|
||||
"handle-callback-err": "off",
|
||||
"indent": ["error", "tab"],
|
||||
"keyword-spacing": "error",
|
||||
"max-nested-callbacks": ["error", { "max": 4 }],
|
||||
"max-statements-per-line": ["error", { "max": 2 }],
|
||||
"no-console": "off",
|
||||
"no-empty-function": "error",
|
||||
"no-floating-decimal": "error",
|
||||
"no-inline-comments": "error",
|
||||
"no-lonely-if": "error",
|
||||
"no-multi-spaces": "error",
|
||||
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }],
|
||||
"no-shadow": ["error", { "allow": ["err", "resolve", "reject"] }],
|
||||
"no-trailing-spaces": ["error"],
|
||||
"no-var": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"prefer-const": "error",
|
||||
"quotes": ["error", "single"],
|
||||
"semi": ["error", "always"],
|
||||
"space-before-blocks": "error",
|
||||
"space-before-function-paren": [
|
||||
"error",
|
||||
{
|
||||
"anonymous": "never",
|
||||
"named": "never",
|
||||
"asyncArrow": "always"
|
||||
}
|
||||
],
|
||||
"space-in-parens": "error",
|
||||
"space-infix-ops": "error",
|
||||
"space-unary-ops": "error",
|
||||
"spaced-comment": "error",
|
||||
"yoda": "error"
|
||||
}
|
||||
}
|
2221
package-lock.json
generated
Normal file
2221
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
package.json
Normal file
38
package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "assetflow",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"prestart": "npm run build",
|
||||
"start": "node .",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"assets",
|
||||
"inventory",
|
||||
"storage"
|
||||
],
|
||||
"author": "[Project-Name-Here]",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@prisma/client": "^4.13.0",
|
||||
"bootstrap": "^5.3.0-alpha3",
|
||||
"bootstrap-icons": "^1.10.5",
|
||||
"eta": "^2.0.1",
|
||||
"express": "^4.18.2",
|
||||
"jquery": "^3.6.4",
|
||||
"lodash": "^4.17.21",
|
||||
"prisma": "^4.13.0",
|
||||
"signale": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/signale": "^1.4.4",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"typescript": "^5.0.4"
|
||||
}
|
||||
}
|
60
prisma/schema.prisma
Normal file
60
prisma/schema.prisma
Normal file
@ -0,0 +1,60 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "mysql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum Category {
|
||||
Light
|
||||
Audio
|
||||
Laptop
|
||||
Adapter
|
||||
Other
|
||||
}
|
||||
|
||||
enum Status {
|
||||
normal
|
||||
borrowed
|
||||
stolen
|
||||
lost
|
||||
}
|
||||
|
||||
model Item {
|
||||
id Int @id @default(autoincrement())
|
||||
SKU String @unique
|
||||
Amount Int
|
||||
Comment String?
|
||||
name String
|
||||
manufacturer String
|
||||
category Category
|
||||
status Status
|
||||
StorageLocation StorageLocation @relation(fields: [storageLocationId], references: [id])
|
||||
storageLocationId Int
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model StorageLocation {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
storageBuilding StorageBuilding @relation(fields: [storageBuildingId], references: [id])
|
||||
storageBuildingId Int
|
||||
Item Item[]
|
||||
}
|
||||
|
||||
model StorageBuilding {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
street String
|
||||
houseNumber String
|
||||
zipCode String
|
||||
city String
|
||||
country String
|
||||
StorageLocation StorageLocation[]
|
||||
}
|
83
src/assets/configHandler.ts
Normal file
83
src/assets/configHandler.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import fs from 'node:fs';
|
||||
import _ from 'lodash';
|
||||
|
||||
export type configObject = Record<any, any>
|
||||
|
||||
/**
|
||||
* This class is responsible to save/edit config files.
|
||||
*
|
||||
* @export
|
||||
* @class config
|
||||
* @typedef {config}
|
||||
*/
|
||||
export default class config {
|
||||
#configPath: string;
|
||||
//global = {[key: string] : string}
|
||||
global: configObject
|
||||
|
||||
/**
|
||||
* Creates an instance of config.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} configPath Path to config file.
|
||||
* @param {object} configPreset Default config object with default values.
|
||||
*/
|
||||
constructor(configPath: string, configPreset: object) {
|
||||
this.#configPath = configPath;
|
||||
this.global = configPreset;
|
||||
|
||||
try {
|
||||
// Read config
|
||||
const data = fs.readFileSync(this.#configPath, 'utf8');
|
||||
|
||||
// Extend config with missing parameters from configPreset.
|
||||
this.global = _.defaultsDeep(JSON.parse(data), this.global);
|
||||
// Save config.
|
||||
this.save_config();
|
||||
} catch (err) {
|
||||
console.error('Could not read config file at ' + this.#configPath + ' due to: ' + err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the jsonified config object to the config file.
|
||||
*/
|
||||
save_config() {
|
||||
try {
|
||||
fs.writeFileSync(this.#configPath, JSON.stringify(this.global, null, 8));
|
||||
} catch (err) {
|
||||
console.error('Could not write config file at ' + this.#configPath + ' due to: ' + err);
|
||||
return;
|
||||
}
|
||||
console.log('Successfully written config file to ' + this.#configPath);
|
||||
}
|
||||
}
|
||||
|
||||
// BUG: If file does'nt exist -> fail.
|
||||
// ToDo: Check for SyntaxError on fileread and ask if the user wants to continue -> overwrite everything. This behavior is currently standard.
|
||||
|
||||
/*
|
||||
|
||||
**** Example ****
|
||||
|
||||
const default_config = {
|
||||
token: 'your-token-goes-here',
|
||||
clientId: '',
|
||||
devserverID: '',
|
||||
devmode: true
|
||||
};
|
||||
|
||||
|
||||
import configHandler from './assets/config.js';
|
||||
const config = new configHandler(__path + '/config.json', default_config);
|
||||
|
||||
console.log('Base Config:');
|
||||
console.log(config.global);
|
||||
|
||||
console.log('Add some new key to config and call save_config.');
|
||||
config.global.NewKey = 'ThisIsANewKey!'
|
||||
config.save_config()
|
||||
|
||||
console.log('Complete Config:');
|
||||
console.log(config.global);
|
||||
*/
|
31
src/frontend/publicInfoPage.eta.html
Normal file
31
src/frontend/publicInfoPage.eta.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<title>AssetFlow - Info about item</title>
|
||||
<meta name="description" content="A simple HTML5 Template for new projects." />
|
||||
<meta name="author" content="[Project-Name-Here]" />
|
||||
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
|
||||
<script src="/static/jquery/dist/jquery.min.js"></script>
|
||||
<link href="/static/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/static/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<script src="/static/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="ui raised very padded text container segment">
|
||||
<h2 class="ui header"><%= it.name %></h2>
|
||||
<p><strong>Category:</strong> <%= it.category%></p>
|
||||
<p><strong>Amount:</strong> <%= it.Amount %></p>
|
||||
<p><strong>SKU:</strong> <%= it.SKU %></p>
|
||||
<p><strong>Comment:</strong> <%= it.comment %></p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
0
src/frontend/style.css
Normal file
0
src/frontend/style.css
Normal file
139
src/index.ts
Normal file
139
src/index.ts
Normal file
@ -0,0 +1,139 @@
|
||||
import { Signale } from 'signale';
|
||||
import ConfigHandler from './assets/configHandler';
|
||||
import express, { Request, Response } from 'express';
|
||||
import * as Eta from 'eta';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { Status, Category } from '@prisma/client';
|
||||
import * as Path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import routes from './routes/index.js'
|
||||
|
||||
// Get app directory.
|
||||
const __path = process.argv[1];
|
||||
|
||||
const logger_settings = {
|
||||
disabled: false,
|
||||
logLevel: 'info',
|
||||
scope: 'Core',
|
||||
stream: process.stdout,
|
||||
displayFilename: true
|
||||
};
|
||||
|
||||
const coreLogger = new Signale(logger_settings);
|
||||
const log = {
|
||||
core: coreLogger,
|
||||
db: coreLogger.scope('DB'),
|
||||
web: coreLogger.scope('WEB')
|
||||
};
|
||||
|
||||
// Create a new config instance.
|
||||
const config = new ConfigHandler(__path + '/config.json', {
|
||||
db_connection_string: 'mysql://USER:PASSWORD@HOST:3306/DATABASE',
|
||||
http_listen_address: '127.0.0.1',
|
||||
http_port: 3000
|
||||
});
|
||||
|
||||
const prisma = new PrismaClient({
|
||||
datasources: {
|
||||
db: {
|
||||
url: config.global.db_connection_string
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const app = express();
|
||||
|
||||
app.get('/dev/fillWithDemoData', (req, res) => {
|
||||
// fill database with demo data
|
||||
prisma.StorageBuilding.create({
|
||||
data: {
|
||||
name: "Test Storage Building",
|
||||
street: "Test Street",
|
||||
houseNumber: "1",
|
||||
zipCode: "12345",
|
||||
city: "Test City",
|
||||
country: "Test Country",
|
||||
}
|
||||
}).then(() => {
|
||||
prisma.StorageLocation.create({
|
||||
data: {
|
||||
name: "Test Storage Location",
|
||||
StorageBuilding: {
|
||||
connect: {
|
||||
id: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}).then(() => {
|
||||
prisma.item
|
||||
.create({
|
||||
data: {
|
||||
SKU: 'ee189749',
|
||||
Amount: 1,
|
||||
name: 'Test Item',
|
||||
manufacturer: 'Test Manufacturer',
|
||||
category: Category.Other,
|
||||
status: Status.normal,
|
||||
storageLocation: {
|
||||
connect: {
|
||||
id: 1
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
res.send('Demo data added');
|
||||
})
|
||||
.catch((err) => {
|
||||
res.send('Error adding demo data: ' + err);
|
||||
});
|
||||
})
|
||||
})
|
||||
res.send('Demo data added (not)');
|
||||
});
|
||||
|
||||
app.get('/:id', (req, res) => {
|
||||
// retrieve data from database using id from url
|
||||
prisma.item
|
||||
.findFirst({
|
||||
where: {
|
||||
SKU: req.params.id
|
||||
}
|
||||
})
|
||||
.then((item) => {
|
||||
if (item) {
|
||||
Eta.renderFile(__path + '/src/frontend/publicInfoPage.eta.html', item).then((html) => {
|
||||
res.send(html);
|
||||
});
|
||||
} else {
|
||||
res.send('Item not found');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Load from allowsStaticPaths.json file
|
||||
const allowedURLs: Array<string> = JSON.parse(fs.readFileSync("allowedStaticPaths.json", "utf8")).allowedStaticFiles;
|
||||
const recordedURLs: Array<string> = [];
|
||||
const debugMode: boolean = JSON.parse(fs.readFileSync("allowedStaticPaths.json", "utf8")).debugMode;
|
||||
|
||||
app.use('/static/*', function handleModuleFiles(req: Request, res: Response) {
|
||||
if(debugMode) {
|
||||
res.sendFile(Path.join(__dirname, 'node_modules', req.params[0]));
|
||||
recordedURLs.push(req.params[0]);
|
||||
log.web.debug(recordedURLs);
|
||||
} else {
|
||||
if (allowedURLs.indexOf(req.params[0]) > -1) {
|
||||
res.sendFile(Path.join(__dirname, 'node_modules', req.params[0]));
|
||||
} else {
|
||||
log.web.warn('Attempt to access restricted asset file ' + req.params[0]);
|
||||
res.status(403).json({ status: 'error', reason: 'Access to restricted asset file denied' });
|
||||
}
|
||||
}
|
||||
// console.log(recordedURLs)
|
||||
});
|
||||
|
||||
routes(app);
|
||||
|
||||
app.listen(config.global.http_port, config.global.http_listen_address, () => {
|
||||
log.web.info(`Listening at http://${config.global.http_listen_address}:${config.global.http_port}`);
|
||||
});
|
9
src/routes/api/index.ts
Normal file
9
src/routes/api/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import express from 'express';
|
||||
const Router = express.Router();
|
||||
|
||||
import testRoute from './test.js';
|
||||
|
||||
Router.use("/api/test", testRoute)
|
||||
|
||||
|
||||
export default Router;
|
4
src/routes/api/test.ts
Normal file
4
src/routes/api/test.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import express, { Request, Response } from 'express';
|
||||
export default (req: Request, res: Response) => {
|
||||
res.status(200).send("Test Successful!");
|
||||
};
|
8
src/routes/frontend/index.ts
Normal file
8
src/routes/frontend/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import express from 'express';
|
||||
const Router = express.Router();
|
||||
|
||||
import testRoute from './test.js';
|
||||
|
||||
Router.use("/test", testRoute)
|
||||
|
||||
export default Router;
|
4
src/routes/frontend/test.ts
Normal file
4
src/routes/frontend/test.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import express, { Request, Response } from 'express';
|
||||
export default (req: Request, res: Response) => {
|
||||
res.status(200).send("Test Successful!");
|
||||
};
|
8
src/routes/index.ts
Normal file
8
src/routes/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { Express } from 'express';
|
||||
import frontend_routes from './frontend/index.js';
|
||||
import api_routes from './frontend/index.js';
|
||||
|
||||
export default (app: Express) => {
|
||||
app.use('/', frontend_routes);
|
||||
app.use('/api', api_routes);
|
||||
};
|
22
tsconfig.json
Normal file
22
tsconfig.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"target": "es6",
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"sourceRoot": "src",
|
||||
"outDir": "dist",
|
||||
"baseUrl": ".",
|
||||
"skipLibCheck": true,
|
||||
"paths": {
|
||||
"*": [
|
||||
"node_modules/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
}
|
Loading…
Reference in New Issue
Block a user