Compare commits

...

15 commits
main ... server

Author SHA1 Message Date
590fda99fd Check session expiration and update if still valid 2022-07-12 22:06:53 -06:00
53b4036fcb Implement login and registration 2022-07-12 22:06:53 -06:00
ab4f1e495d Install missing dependencies 2022-07-12 22:06:51 -06:00
3c429e2123 Update publish and package commands to use new syntax 2022-07-12 22:04:27 -06:00
270359d73b Fixes for new Ktor API 2022-07-12 22:03:56 -06:00
eacc18e461 Finish implementing /api/budget routes
Signed-off-by: William Brawner <me@wbrawner.com>
2022-07-12 22:03:56 -06:00
9bc86d620a Check session expiration and update if still valid 2022-07-12 22:03:56 -06:00
f5f4dbe7e1 Implement login and registration 2022-07-12 22:03:55 -06:00
5a8613c701 Set up database migrations to run automatically on server startup 2022-07-12 22:03:12 -06:00
a272c420cd Install missing dependencies 2022-07-12 22:03:10 -06:00
31af400281 Fix sqlite migration 0-1 syntax 2022-07-12 22:00:01 -06:00
4643f00e15 WIP: setup database migrations
Signed-off-by: William Brawner <me@wbrawner.com>
2022-07-12 22:00:01 -06:00
1b2a5e220c Add sqlite3
Signed-off-by: William Brawner <me@wbrawner.com>
2022-07-12 22:00:00 -06:00
621782a3a8 WIP: Implement backend in express
Signed-off-by: William Brawner <me@wbrawner.com>
2022-07-12 21:52:21 -06:00
03bfd1bed3 Move angular code to src/client
Signed-off-by: William Brawner <me@wbrawner.com>
2022-07-12 21:52:20 -06:00
160 changed files with 2466 additions and 1078 deletions

View file

@ -5,7 +5,7 @@
"projects": { "projects": {
"twigs": { "twigs": {
"root": "", "root": "",
"sourceRoot": "src", "sourceRoot": "src/client",
"projectType": "application", "projectType": "application",
"prefix": "app", "prefix": "app",
"schematics": {}, "schematics": {},
@ -13,23 +13,23 @@
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"outputPath": "dist/twigs", "outputPath": "dist/public",
"index": "src/index.html", "index": "src/client/index.html",
"main": "src/main.ts", "main": "src/client/main.ts",
"polyfills": "src/polyfills.ts", "polyfills": "src/client/polyfills.ts",
"tsConfig": "src/tsconfig.app.json", "tsConfig": "src/client/tsconfig.app.json",
"assets": [ "assets": [
"src/browserconfig.xml", "src/client/browserconfig.xml",
"src/favicon-16x16.png", "src/client/favicon-16x16.png",
"src/favicon-32x32.png", "src/client/favicon-32x32.png",
"src/favicon-96x96.png", "src/client/favicon-96x96.png",
"src/favicon.ico", "src/client/favicon.ico",
"src/assets", "src/client/assets",
"src/manifest.json" "src/client/manifest.json"
], ],
"styles": [ "styles": [
"src/styles.css", "src/client/styles.css",
"src/styles.scss" "src/client/styles.scss"
], ],
"scripts": [], "scripts": [],
"vendorChunk": true, "vendorChunk": true,
@ -49,8 +49,8 @@
], ],
"fileReplacements": [ "fileReplacements": [
{ {
"replace": "src/environments/environment.ts", "replace": "src/client/environments/environment.ts",
"with": "src/environments/environment.prod.ts" "with": "src/client/environments/environment.prod.ts"
} }
], ],
"optimization": true, "optimization": true,
@ -71,8 +71,8 @@
], ],
"fileReplacements": [ "fileReplacements": [
{ {
"replace": "src/environments/environment.ts", "replace": "src/client/environments/environment.ts",
"with": "src/environments/environment.codeserver.ts" "with": "src/client/environments/environment.codeserver.ts"
} }
] ]
} }
@ -102,18 +102,18 @@
"test": { "test": {
"builder": "@angular-devkit/build-angular:karma", "builder": "@angular-devkit/build-angular:karma",
"options": { "options": {
"main": "src/test.ts", "main": "src/client/test.ts",
"polyfills": "src/polyfills.ts", "polyfills": "src/client/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json", "tsConfig": "src/client/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js", "karmaConfig": "src/client/karma.conf.js",
"styles": [ "styles": [
"src/styles.css" "src/client/styles.css"
], ],
"scripts": [], "scripts": [],
"assets": [ "assets": [
"src/favicon.ico", "src/client/favicon.ico",
"src/assets", "src/client/assets",
"src/manifest.json" "src/client/manifest.json"
] ]
} }
} }

View file

@ -6,7 +6,7 @@ const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = { exports.config = {
allScriptsTimeout: 11000, allScriptsTimeout: 11000,
specs: [ specs: [
'./src/**/*.e2e-spec.ts' './src/client/**/*.e2e-spec.ts'
], ],
capabilities: { capabilities: {
'browserName': 'chrome' 'browserName': 'chrome'

2673
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -2,12 +2,16 @@
"name": "budget", "name": "budget",
"version": "0.0.0", "version": "0.0.0",
"scripts": { "scripts": {
"ng": "ng", "prestart": "npm run build",
"start": "ng serve --host '0.0.0.0'", "start": "node dist/index.js",
"code-server": "ng serve --configuration=codeserver --host \"0.0.0.0\" --disable-host-check --poll=2000", "code-server": "ng serve --configuration=codeserver --host \"0.0.0.0\" --disable-host-check --poll=2000",
"build": "ng build", "build:client": "ng build",
"package": "ng build --configuration=production --service-worker", "build:server": "tsc -p src/server",
"publish": "ng build --configuration=production --service-worker && firebase deploy", "build": "npm run build:client && npm run build:server",
"watch:client": "ng build --watch",
"watch:server": "nodemon -w src/server -e ts --exec \"npm run build:server && node dist/index.js\"",
"watch": "concurrently -k \"npm run watch:client\" \"npm run watch:server\"",
"package": "ng build --configuration=prod --service-worker",
"test": "ng test", "test": "ng test",
"lint": "ng lint", "lint": "ng lint",
"e2e": "ng e2e", "e2e": "ng e2e",
@ -30,6 +34,7 @@
"core-js": "^3.20.3", "core-js": "^3.20.3",
"ng2-charts": "^3.0.8", "ng2-charts": "^3.0.8",
"rxjs": "^7.5.2", "rxjs": "^7.5.2",
"sqlite3": "^5.0.1",
"tslib": "^2.3.1", "tslib": "^2.3.1",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
@ -38,10 +43,17 @@
"@angular/cli": "^14.0.4", "@angular/cli": "^14.0.4",
"@angular/compiler-cli": "^14.0.4", "@angular/compiler-cli": "^14.0.4",
"@angular/language-service": "^14.0.4", "@angular/language-service": "^14.0.4",
"@types/bcrypt": "^3.0.0",
"@types/express": "^4.17.11",
"@types/express-serve-static-core": "^4.17.18",
"@types/jasmine": "~3.10.3", "@types/jasmine": "~3.10.3",
"@types/jasminewd2": "^2.0.10", "@types/jasminewd2": "^2.0.10",
"@types/node": "^17.0.10", "@types/node": "^17.0.10",
"@types/sqlite3": "^3.1.7",
"bcrypt": "^5.0.0",
"concurrently": "^5.3.0",
"eslint": "^8.7.0", "eslint": "^8.7.0",
"express": "^4.17.1",
"jasmine-core": "~4.0.0", "jasmine-core": "~4.0.0",
"jasmine-spec-reporter": "~7.0.0", "jasmine-spec-reporter": "~7.0.0",
"karma": "~6.3.11", "karma": "~6.3.11",
@ -49,8 +61,10 @@
"karma-coverage-istanbul-reporter": "~3.0.3", "karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~4.0.1", "karma-jasmine": "~4.0.1",
"karma-jasmine-html-reporter": "^1.7.0", "karma-jasmine-html-reporter": "^1.7.0",
"nodemon": "^2.0.7",
"npm-check-updates": "^15.0.1", "npm-check-updates": "^15.0.1",
"protractor": "^7.0.0", "protractor": "^7.0.0",
"sqlite3": "^5.0.1",
"ts-node": "~10.4.0", "ts-node": "~10.4.0",
"tslint": "^6.1.3", "tslint": "^6.1.3",
"typescript": "4.7.4" "typescript": "4.7.4"

View file

@ -5,7 +5,7 @@ import { TWIGS_SERVICE, TwigsService } from './shared/twigs.service';
import { SwUpdate } from '@angular/service-worker'; import { SwUpdate } from '@angular/service-worker';
import { first, filter, map } from 'rxjs/operators'; import { first, filter, map } from 'rxjs/operators';
import { interval, concat, BehaviorSubject } from 'rxjs'; import { interval, concat, BehaviorSubject } from 'rxjs';
import { Router, ActivationEnd, ActivatedRoute } from '@angular/router'; import { Router } from '@angular/router';
import { Actionable, isActionable } from './shared/actionable'; import { Actionable, isActionable } from './shared/actionable';
@Component({ @Component({
@ -43,7 +43,7 @@ export class AppComponent implements OnInit {
let auth = this.storage.getItem('Authorization'); let auth = this.storage.getItem('Authorization');
let userId = this.storage.getItem('userId'); let userId = this.storage.getItem('userId');
let savedUser = JSON.parse(this.storage.getItem('user')) as User; let savedUser = JSON.parse(this.storage.getItem('user')) as User;
if (auth && auth.length == 255 && userId) { if (auth) {
if (savedUser) { if (savedUser) {
this.user.next(savedUser); this.user.next(savedUser);
} }

View file

@ -36,7 +36,7 @@ import { EditProfileComponent } from './users/edit-profile/edit-profile.componen
import { UserComponent } from './users/user.component'; import { UserComponent } from './users/user.component';
import { NewBudgetComponent } from './budgets/new-budget/new-budget.component'; import { NewBudgetComponent } from './budgets/new-budget/new-budget.component';
import { BudgetDetailsComponent } from './budgets/budget-details/budget-details.component'; import { BudgetDetailsComponent } from './budgets/budget-details/budget-details.component';
import { environment } from 'src/environments/environment'; import { environment } from 'src/client/environments/environment';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { ServiceWorkerModule } from '@angular/service-worker'; import { ServiceWorkerModule } from '@angular/service-worker';
import { CategoryBreakdownComponent } from './categories/category-breakdown/category-breakdown.component'; import { CategoryBreakdownComponent } from './categories/category-breakdown/category-breakdown.component';

View file

@ -1,8 +1,9 @@
import { Component, OnInit, Input, Inject, OnDestroy } from '@angular/core'; import { Component, OnInit, Input, Inject, OnDestroy } from '@angular/core';
import { Budget } from '../budget'; import { Budget } from '../budget';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/client/app/app.component';
import { User, UserPermission, Permission } from 'src/app/users/user'; import { User, UserPermission, Permission } from 'src/client/app/users/user';
import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service'; import { TWIGS_SERVICE, TwigsService } from 'src/client/app/shared/twigs.service';
import { Router } from '@angular/router';
@Component({ @Component({
selector: 'app-add-edit-budget', selector: 'app-add-edit-budget',
@ -20,6 +21,7 @@ export class AddEditBudgetComponent {
constructor( constructor(
private app: AppComponent, private app: AppComponent,
@Inject(TWIGS_SERVICE) private twigsService: TwigsService, @Inject(TWIGS_SERVICE) private twigsService: TwigsService,
private router: Router
) { ) {
this.app.setTitle(this.title) this.app.setTitle(this.title)
this.app.setBackEnabled(true); this.app.setBackEnabled(true);
@ -51,7 +53,7 @@ export class AddEditBudgetComponent {
this.isLoading = true; this.isLoading = true;
this.twigsService.deleteBudget(this.budget.id) this.twigsService.deleteBudget(this.budget.id)
.subscribe(() => { .subscribe(() => {
this.app.goBack(); this.router.navigateByUrl('/budgets');
}); });
} }

View file

@ -1,13 +1,13 @@
import { Component, OnInit, Inject, OnDestroy } from '@angular/core'; import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
import { Budget } from '../budget'; import { Budget } from '../budget';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/client/app/app.component';
import { Transaction } from 'src/app/transactions/transaction'; import { Transaction } from 'src/client/app/transactions/transaction';
import { Category } from 'src/app/categories/category'; import { Category } from 'src/client/app/categories/category';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
// import { Label } from 'ng2-charts'; // import { Label } from 'ng2-charts';
import { ChartDataset } from 'chart.js'; import { ChartDataset } from 'chart.js';
import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service'; import { TWIGS_SERVICE, TwigsService } from 'src/client/app/shared/twigs.service';
import { Actionable } from '../../shared/actionable'; import { Actionable } from '../../shared/actionable';
@Component({ @Component({

View file

@ -1,7 +1,7 @@
import { Component, OnInit, Input, OnDestroy, Inject } from '@angular/core'; import { Component, OnInit, Input, OnDestroy, Inject } from '@angular/core';
import { Category } from '../category'; import { Category } from '../category';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/client/app/app.component';
import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service'; import { TWIGS_SERVICE, TwigsService } from 'src/client/app/shared/twigs.service';
@Component({ @Component({
selector: 'app-category-form', selector: 'app-category-form',

View file

@ -122,18 +122,11 @@ export class TwigsHttpService implements TwigsService {
id: string, id: string,
name: string, name: string,
description: string, description: string,
users: UserPermission[],
): Observable<Budget> { ): Observable<Budget> {
const params = { const params = {
'id': id, 'id': id,
'name': name, 'name': name,
'description': description, 'description': description,
'users': users.map(userPermission => {
return {
user: userPermission.user,
permission: Permission[userPermission.permission]
};
})
}; };
return this.http.post<Budget>(this.apiUrl + '/budgets', params, this.options) return this.http.post<Budget>(this.apiUrl + '/budgets', params, this.options)
.pipe(map(budget => { .pipe(map(budget => {
@ -150,12 +143,6 @@ export class TwigsHttpService implements TwigsService {
const params = { const params = {
'name': budget.name, 'name': budget.name,
'description': budget.description, 'description': budget.description,
'users': budget.users.map(userPermission => {
return {
user: userPermission.user,
permission: Permission[userPermission.permission]
};
})
}; };
return this.http.put<Budget>(`${this.apiUrl}/budgets/${id}`, params, this.options) return this.http.put<Budget>(`${this.apiUrl}/budgets/${id}`, params, this.options)
.pipe(map(budget => { .pipe(map(budget => {

View file

@ -1,9 +1,9 @@
import { Component, OnInit, Input, OnChanges, OnDestroy, Inject, SimpleChanges } from '@angular/core'; import { Component, OnInit, Input, OnChanges, OnDestroy, Inject, SimpleChanges } from '@angular/core';
import { Transaction } from '../transaction'; import { Transaction } from '../transaction';
import { TransactionType } from '../transaction.type'; import { TransactionType } from '../transaction.type';
import { Category } from 'src/app/categories/category'; import { Category } from 'src/client/app/categories/category';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/client/app/app.component';
import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service'; import { TWIGS_SERVICE, TwigsService } from 'src/client/app/shared/twigs.service';
import { MatRadioChange } from '@angular/material/radio'; import { MatRadioChange } from '@angular/material/radio';
@Component({ @Component({

View file

@ -1,7 +1,7 @@
import { Component, OnInit, Input, Inject } from '@angular/core'; import { Component, OnInit, Input, Inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Transaction } from '../transaction'; import { Transaction } from '../transaction';
import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service'; import { TWIGS_SERVICE, TwigsService } from 'src/client/app/shared/twigs.service';
@Component({ @Component({
selector: 'app-transaction-details', selector: 'app-transaction-details',

View file

@ -1,7 +1,7 @@
import { Component, OnInit, OnDestroy, Inject, ChangeDetectorRef } from '@angular/core'; import { Component, OnInit, OnDestroy, Inject, ChangeDetectorRef } from '@angular/core';
import { TwigsService, TWIGS_SERVICE } from '../../shared/twigs.service'; import { TwigsService, TWIGS_SERVICE } from '../../shared/twigs.service';
import { User } from '../user'; import { User } from '../user';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/client/app/app.component';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
@Component({ @Component({

Some files were not shown because too many files have changed in this diff Show more