This commit is contained in:
Theenoro 2023-12-14 11:15:56 +01:00
parent 55f5869385
commit f6f9819058
21 changed files with 3516 additions and 0 deletions

View File

@ -1,2 +1,3 @@
# backend # backend
- database

2609
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

29
package.json Normal file
View File

@ -0,0 +1,29 @@
{
"name": "smol-budget-backend",
"version": "1.0.0",
"description": "- database",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rm -rf ./build && tsc",
"start": "npm run build && node build/index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.2",
"express": "^4.18.2",
"express-session": "^1.17.3",
"mariadb": "^3.2.2",
"moment": "^2.29.4",
"pug": "^3.0.2",
"sequelize": "^6.35.2",
"sqlite3": "^5.1.6"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^20.10.4",
"@types/pug": "^2.0.10",
"typescript": "^5.3.3"
}
}

46
public/css/app.css Normal file
View File

@ -0,0 +1,46 @@
:root{
--dark: #222f3e;
--light-grey: #576574;
--light: #c8d6e5;
--green: #1dd1a1;
--yellow: #feca57;
--red: #ff6b6b;
--pink: #ff9ff3;
--purple: #5f27cd;
--cyan: #48dbfb;
--blue: #54a0ff;
}
@font-face {
font-family: 'robotomono-light';
src: url('/assets/font/RobotoMono-Light.ttf');
}
*{
font-family: "robotomono-light";
}
body{
background-color: var(--dark);
color:var(--light);
}
.container{
width: 1200px;
margin: auto;
padding: 10px;
border: 1px solid;
}
table{
width: 100%;
}
table .amount{
text-align: right;
}
table .income{
color:var(--green);
}
table .expense{
color: var(--red);
}
table .transfer{
color: var(--pink);
}

0
public/font/dummy Normal file
View File

View File

@ -0,0 +1,53 @@
// Account model definition
import { Sequelize, DataTypes, Model, Optional, Attributes, CreateOptions, ModelStatic } from 'sequelize';
import { HookReturn } from 'sequelize/types/hooks';
import { Transaction } from './Transaction'; // Import the Transaction model
interface AccountAttributes {
AccountID: number;
Name: string;
// Other account fields...
}
interface AccountCreationAttributes extends Optional<AccountAttributes, 'AccountID'> { }
class Account extends Model<AccountAttributes, AccountCreationAttributes> implements AccountAttributes {
public AccountID!: number;
public Name!: string;
static initialize(sequelize: Sequelize): void {
Account.init(
{
AccountID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Name: {
type: DataTypes.STRING,
allowNull: false,
},
// Other account fields...
},
{
sequelize,
modelName: 'Account',
hooks: {
afterCreate: (attributes: Account, options: CreateOptions<AccountAttributes>) => {
console.log(attributes)
},
beforeCreate(attributes: Account, options: CreateOptions<AccountAttributes>) {
console.log(attributes)
},
}
}
);
}
static associate(models: { Transaction: typeof Transaction }): void {
Account.hasMany(models.Transaction, { foreignKey: 'AccountID' }); // An account can have multiple transactions
}
}
export { Account };

View File

@ -0,0 +1,54 @@
import { Sequelize, DataTypes, Model, Optional } from 'sequelize';
import { User } from './User';
import { Transaction } from './Transaction';
// Category attributes interface
interface CategoryAttributes {
CategoryID: number;
Name: string;
Description: string | null;
// Other fields...
}
// Category creation attributes (optional fields)
interface CategoryCreationAttributes extends Optional<CategoryAttributes, 'CategoryID'> {}
// Define the Category model
class Category extends Model<CategoryAttributes, CategoryCreationAttributes> implements CategoryAttributes {
public CategoryID!: number;
public Name!: string;
public Description!: string | null;
// Other fields...
static initialize(sequelize: Sequelize): void {
Category.init(
{
CategoryID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Name: {
type: DataTypes.STRING,
allowNull: false,
},
Description: {
type: DataTypes.STRING,
allowNull: true,
},
// Other fields...
},
{
sequelize,
modelName: 'Category',
// Other model options...
}
);
}
static associate(models: { User: typeof User; Transaction: typeof Transaction }): void {
Category.belongsToMany(models.Transaction,{through:"TransactionCategory"}); // A category can have multiple transactions
}
}
export {Category };

View File

@ -0,0 +1,114 @@
// MonthlyReport model definition
import { Sequelize, DataTypes, Model, Optional, Op, fn, col } from 'sequelize';
import moment from 'moment';
import { Transaction } from './Transaction'; // Assuming you have a Transaction model
import { Account } from './Account';
interface MonthlyReportAttributes {
MonthlyReportID: number;
Month: number;
Year: number;
TotalAmount: number;
// Other report fields...
AccountID: number;
}
interface MonthlyReportCreationAttributes extends Optional<MonthlyReportAttributes, 'MonthlyReportID'> { }
class MonthlyReport extends Model<MonthlyReportAttributes, MonthlyReportCreationAttributes> implements MonthlyReportAttributes {
public MonthlyReportID!: number;
public Month!: number;
public Year!: number;
public TotalAmount!: number;
public AccountID!: number;
static initialize(sequelize: Sequelize): void {
MonthlyReport.init(
{
MonthlyReportID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Month: {
type: DataTypes.INTEGER,
allowNull: false,
},
Year: {
type: DataTypes.INTEGER,
allowNull: false,
},
TotalAmount: {
type: DataTypes.FLOAT,
allowNull: false,
},
AccountID: {
type: DataTypes.INTEGER,
allowNull: false,
}
// Other report fields...
},
{
sequelize,
modelName: 'MonthlyReport',
}
);
}
static associate(models: { Transaction: typeof Transaction, Account: typeof Account }): void {
MonthlyReport.hasMany(models.Transaction, { foreignKey: 'MonthlyReportID' }); // A report can have multiple transactions
MonthlyReport.belongsTo(models.Account)
}
static async generateMonthlyReport(month: number, year: number, AccountID: number|null = null): Promise<void> {
try {
moment.locale("de")
let m = moment();
m.set({year:year,month:month-1,day:15});
let startDate = moment(m).startOf('month');
let endDate = moment(m).endOf('month');
// Fetch transaction data and calculate total amount
let transactions = null;
if(AccountID==null){
transactions = await Transaction.findAll({
where: {
Date: {
[Op.between]: [startDate, endDate],
}
},
});
}else{
transactions = await Transaction.findAll({
where: {
Date: {
[Op.between]: [startDate, endDate],
},
AccountID: AccountID
},
});
}
console.log(transactions)
const totalAmount = transactions.reduce((total, transaction) => total + transaction.Amount, 0);
console.log(totalAmount)
// Create a MonthlyReport entry with the generated data
await MonthlyReport.create({
Month: month,
Year: year,
TotalAmount: totalAmount,
AccountID: 0
});
console.log(`Monthly report generated for ${month}/${year}`);
} catch (err) {
console.error('Error generating monthly report:', err);
} finally {
}
}
}
export { MonthlyReport };

View File

@ -0,0 +1,129 @@
import { Sequelize, DataTypes, Model, Optional, Attributes, CreateOptions, ModelStatic } from 'sequelize';
import { User } from './User';
import { Category } from './Category';
import { Account } from './Account';
import { HookReturn } from 'sequelize/types/hooks';
import { MonthlyReport } from './MonthlyReport';
// Transaction attributes interface
interface TransactionAttributes {
TransactionID: number;
Date: Date;
Description: string | null;
UserID: number;
Amount: number;
Type: 'income' | 'expense' | 'transfer';
AccountID: number;
// Other fields...
}
// Transaction creation attributes (optional fields)
interface TransactionCreationAttributes extends Optional<TransactionAttributes, 'TransactionID'> { }
// Define the Transaction model
class Transaction extends Model<TransactionAttributes, TransactionCreationAttributes> implements TransactionAttributes {
public TransactionID!: number;
public Date!: Date;
public Description!: string | null;
public Amount!: number;
public Type!: 'income' | 'expense' | 'transfer';
// Other fields...
public UserID!: number;
public AccountID!: number;
public CategoryID!: number;
static initialize(sequelize: Sequelize): void {
Transaction.init(
{
TransactionID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Date: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: new Date()
},
Description: {
type: DataTypes.STRING,
allowNull: true,
},
UserID: {
type: DataTypes.INTEGER,
allowNull: false,
},
AccountID: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1,
},
Amount: {
type: DataTypes.FLOAT,
allowNull: false,
},
Type: {
type: DataTypes.ENUM('income', 'expense','transfer'),
allowNull: false,
},
// Other fields...
},
{
sequelize,
modelName: 'Transaction',
// Other model options...
hooks: {
afterCreate: (attributes: Transaction, options: CreateOptions<TransactionAttributes>) => {
console.log(attributes)
},
beforeCreate(attributes: Transaction, options: CreateOptions<TransactionAttributes>) {
if (attributes.Type == "expense") {
attributes.Amount = -0 - attributes.Amount;
}
},
}
}
);
}
static associate(models: { User: typeof User; Category: typeof Category; Account: typeof Account; MonthlyReport: typeof MonthlyReport }): void {
Transaction.belongsTo(models.User); // A transaction belongs to a user
Transaction.belongsTo(models.Category, { foreignKey: 'CategoryID' }); // A transaction belongs to a category
Transaction.belongsTo(models.Account, { foreignKey: 'AccountID' }); // A transaction belongs to an account
}
static async getTotalAmountForUser(userId: number): Promise<number> {
const result = await Transaction.sum('Amount', { where: { UserID: userId } });
return result || 0;
}
static async transferAmountFromTo(userID: number, fromAccountID: number = 1, toAccountID: number = 1, Amount: number = 0){
console.log(`User: ${userID}, fromAccount: ${fromAccountID}, toAccount${toAccountID}, Amount: ${Amount}`)
await Transaction.create({
Amount:-Amount,
Date:new Date(),
Type:"transfer",
//@ts-ignore
UserID: userID, // Associate the transaction with the user
//@ts-ignore
CategoryID: 1,
AccountID: fromAccountID
})
await Transaction.create({
Amount:Amount,
Date:new Date(),
Type:"transfer",
//@ts-ignore
UserID: userID, // Associate the transaction with the user
//@ts-ignore
CategoryID: 1,
AccountID: toAccountID
})
}
}
export { Transaction };

View File

@ -0,0 +1,62 @@
import { Sequelize, DataTypes, Model, Optional } from 'sequelize';
import { Category } from './Category';
import { Transaction } from './Transaction';
// User attributes interface
interface UserAttributes {
UserID: number;
Name: string;
Email: string;
Password: string;
// Other fields...
}
// User creation attributes (optional fields)
interface UserCreationAttributes extends Optional<UserAttributes, 'UserID'> { }
// Define the User model
class User extends Model<UserAttributes, UserCreationAttributes> implements UserAttributes {
public UserID!: number;
public Name!: string;
public Email!: string;
public Password!: string;
// Other fields...
static initialize(sequelize: Sequelize): void {
User.init(
{
UserID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Name: {
type: DataTypes.STRING,
allowNull: false,
},
Email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
Password: {
type: DataTypes.STRING,
allowNull: false,
},
// Other fields...
},
{
sequelize,
modelName: 'User',
// Other model options...
}
);
}
static associate(models: { Category: typeof Category; Transaction: typeof Transaction }): void {
User.hasMany(models.Transaction, { foreignKey: 'UserID' });
}
}
export { User };

View File

@ -0,0 +1,4 @@
export { Category } from "./Category";
export { Transaction } from "./Transaction";
export { User } from "./User";
export { Account } from "./Account";

109
src/controller/router.ts Normal file
View File

@ -0,0 +1,109 @@
// server.ts
import express, { Request, Response } from 'express';
import { User, Category, Transaction, Account } from './models'; // Adjust the path to your models
import pug from "pug"
import path from 'path';
export class Router {
app: any;
constructor(Path = "", PORT = 3000) {
let app = express();
// Set the view engine to Pug
app.set('view engine', 'pug');
app.set('views', './views'); // Set the views directory
console.log(Path)
app.use('/assets', express.static(Path));
app.get('/', async (req: Request, res: Response) => {
try {
const users = await User.findAll();
const categories = await Category.findAll();
const transactions = await Transaction.findAll();
res.render('index', {
title: 'Home',
userCount: users.length,
categoryCount: categories.length,
transactionCount: transactions.length,
});
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/users', async (req: Request, res: Response) => {
try {
const users = await User.findAll();
res.render('users', { title: 'Users', users });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/categories', async (req: Request, res: Response) => {
try {
const categories = await Category.findAll();
res.render('categories', { title: 'Categories', categories });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/transactions', async (req: Request, res: Response) => {
try {
const transactions = await Transaction.findAll({
include: Account
});
console.log(transactions)
res.render('transactions/transactions', { title: 'Transactions', transactions });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/transactions/acc/:acc', async (req: Request, res: Response) => {
try {
const transactions = await Transaction.findAll({
include: Account,
where: {
AccountID: req.params.acc
}
});
console.log(transactions)
res.render('transactions/transactions', { title: 'Transactions', transactions });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/transactions/cat/:cat', async (req: Request, res: Response) => {
try {
const transactions = await Transaction.findAll({
include: [Account, Category],
where: {
//@ts-ignore
CategoryID: req.params.cat
}
});
console.log(transactions)
res.render('transactions/transactions', { title: 'Transactions', transactions });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
this.app = app;
}
}

View File

@ -0,0 +1,5 @@
export class Storage{
static Path=""
static __filename: string;
static __dirname: string;
}

7
src/database.ts Normal file
View File

@ -0,0 +1,7 @@
import { Sequelize, DataTypes, Model, Optional } from 'sequelize';
export { Category, Transaction, User, Account } from './controller/models';
// Set associations between models (similarly as before)
// Sync models with the database (similarly as before)

120
src/index.ts Normal file
View File

@ -0,0 +1,120 @@
import { Sequelize, DataTypes, Model, Optional } from 'sequelize';
import { Account, Category, Transaction, User } from './controller/models';
import { Router } from './controller/router';
import path from 'path';
import { fileURLToPath } from 'url';
import { Storage } from './controller/storage';
import { MonthlyReport } from './controller/models/MonthlyReport';
Storage.__dirname = __dirname
let init = async () => {
// Initialize Sequelize instance and define database connection
const sequelize = new Sequelize('sqlite::memory:', {
host: 'localhost',
dialect: 'sqlite', // Change this to your database dialect
// Other options...
});
User.initialize(sequelize);
Category.initialize(sequelize);
Transaction.initialize(sequelize);
Account.initialize(sequelize);
MonthlyReport.initialize(sequelize);
// Set up associations between models
User.associate({ Transaction, Category });
Category.associate({ User, Transaction });
Transaction.associate({ User, Category, Account, MonthlyReport });
Account.associate({Transaction})
MonthlyReport.associate({ Transaction, Account });
await sequelize.sync({ force: true });
await User.create({
Name: "Max Mustermann",
Email: "test@test.de",
Password: "sdfsf"
})
await Category.create({
Name: "Allgemein",
Description: null
})
await Category.create({
Name:"Games",
Description:"Games"
})
await Account.create({
Name:"None"
})
await Account.create({
Name:"Bar"
})
await Account.create({
Name:"Konto1"
})
let z = await Transaction.create({
Amount:50.0,
Date:new Date(),
Type:"expense",
//@ts-ignore
UserID: 1, // Associate the transaction with the user
//@ts-ignore
CategoryID: 1,
})
await Transaction.create({
Amount:10.0,
Date:new Date(),
Type:"expense",
//@ts-ignore
UserID: 1, // Associate the transaction with the user
//@ts-ignore
CategoryID: 1,
})
await Transaction.create({
Amount:60.0,
Date:new Date(),
Type:"income",
//@ts-ignore
UserID: 1, // Associate the transaction with the user
//@ts-ignore
CategoryID: 1,
})
await Transaction.create({
Amount:60.0,
Date:new Date(),
Type:"income",
//@ts-ignore
UserID: 1, // Associate the transaction with the user
//@ts-ignore
CategoryID: 2,
})
//await Transaction.transferAmountFromTo(1,1,2,50);
let x = await Transaction.getTotalAmountForUser(1)
await Transaction.transferAmountFromTo(1,1,2,50);
console.log(x)
new Router(path.join(__dirname,'../public'));
console.log(path.join(__dirname,'../public'))
MonthlyReport.generateMonthlyReport(12,2023,2)
}
init();

109
tsconfig.json Normal file
View File

@ -0,0 +1,109 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"lib": ["es6","ES2023"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"rootDir": "src", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
"resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "build", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

0
views/categories.pug Normal file
View File

19
views/index.pug Normal file
View File

@ -0,0 +1,19 @@
doctype html
html
head
title= title
body
h1 Welcome to our Web App!
p This is a simple example using Express and Pug.
a(href='/users') View Users
div
div
p Transactions
p=transactionCount
div
p Categorys
p=categoryCount
div
p Users
p=userCount

13
views/layout/base.pug Normal file
View File

@ -0,0 +1,13 @@
doctype html
html
head
title= title
link(href="/assets/css/app.css",rel="stylesheet")
block additionalAssets
body
div.container
block headline
block content

View File

@ -0,0 +1,24 @@
extends ../layout/base.pug
block headline
h1 Transactions
block content
form(action="/tansactions",method="POST")
table
thead
th ID
th Date
th Description
th Account
th Amount
tbody
each transaction in transactions
tr
td=transaction.TransactionID
td=transaction.Date
td=transaction.Description
td=transaction.Account.Name
td(class=`${transaction.Type} amount` )=transaction.Amount

9
views/users.pug Normal file
View File

@ -0,0 +1,9 @@
doctype html
html
head
title= title
body
h1 Users
ul
each user in users
li= user.Name