basic login/logout

This commit is contained in:
eneller
2026-03-07 14:48:19 +01:00
parent 111d1a7b48
commit f5ae9ac9e6
7 changed files with 49 additions and 16 deletions

View File

@@ -11,6 +11,7 @@
<i class="bi bi-wallet2 fs-4"></i> <i class="bi bi-wallet2 fs-4"></i>
<h3 class="mb-0">{{ balance | currency}}</h3> <h3 class="mb-0">{{ balance | currency}}</h3>
</div> </div>
<button type="button" (click)="logOut()" class="btn btn-outline-secondary">Log out</button>
</div> </div>
</div> </div>

View File

@@ -2,6 +2,7 @@ import { CommonModule, CurrencyPipe, DatePipe } from '@angular/common';
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { APIService } from '../../services/api'; import { APIService } from '../../services/api';
import Transaction from '@model/transaction'; import Transaction from '@model/transaction';
import { Router } from '@angular/router';
@Component({ @Component({
selector: 'app-screen-profile', selector: 'app-screen-profile',
@@ -15,7 +16,10 @@ export class ScreenProfile implements OnInit{
balance = 200; balance = 200;
transactions!: Transaction[]; transactions!: Transaction[];
constructor(private api: APIService){} constructor(
private api: APIService,
private router: Router,
){}
ngOnInit(): void { ngOnInit(): void {
// FIXME transactions displaying delayed (only on second nav click) // FIXME transactions displaying delayed (only on second nav click)
@@ -28,5 +32,15 @@ export class ScreenProfile implements OnInit{
}, },
}) })
} }
logOut(){
this.api.logout().subscribe({
next: () => {
this.router.navigate(['login'])
},
error: (err) => {
console.error('Error logging out:', err)
}
})
}
} }

View File

@@ -17,4 +17,7 @@ export class APIService {
login(username: string, password: string): Observable<any>{ login(username: string, password: string): Observable<any>{
return this.http.post(this.apiUrl + '/auth/login',{ 'username': username, 'password': password}); return this.http.post(this.apiUrl + '/auth/login',{ 'username': username, 'password': password});
} }
logout(): Observable<any>{
return this.http.post(this.apiUrl + '/auth/logout', {});
}
} }

View File

@@ -4,22 +4,22 @@ import User from './user';
@Table @Table
export default class Transaction extends Model{ export default class Transaction extends Model{
@Column @Column
amount!: number; declare amount: number;
@Column @Column
@ForeignKey(()=> User) @ForeignKey(()=> User)
senderID!: string; declare senderID: string;
@BelongsTo(() => User, 'senderID') @BelongsTo(() => User, 'senderID')
sender!: User; declare sender: User;
@Column @Column
@ForeignKey(()=> User) @ForeignKey(()=> User)
receiverID!: string; declare receiverID: string;
@BelongsTo(() => User, 'receiverID') @BelongsTo(() => User, 'receiverID')
receiver!: User; declare receiver: User;
@CreatedAt @CreatedAt
date!: Date; declare date: Date;
} }

View File

@@ -4,18 +4,18 @@ import { Table, Column, Model, CreatedAt, DataType} from 'sequelize-typescript';
export default class User extends Model{ export default class User extends Model{
@Column({primaryKey: true, unique: true, allowNull: false}) @Column({primaryKey: true, unique: true, allowNull: false})
userID!: string; declare userID: string;
@Column @Column
displayName!: string; declare displayName: string;
@Column(DataType.DECIMAL(20,2)) @Column(DataType.DECIMAL(20,2))
balance!: number; declare balance: number;
@Column @Column
password!: string; declare password: string;
@CreatedAt @CreatedAt
creationDate!: Date; declare creationDate: Date;
} }

View File

@@ -1,14 +1,28 @@
import express from 'express'; import express from 'express';
import { logger } from '../util/logging';
import User from '../model/user';
const router = express.Router(); const router = express.Router();
router.post('/login', async (req, res) => { router.post('/login', async (req, res) => {
try { try {
res.json('abc'); const { username, password } = req.body;
const user = await User.findOne({where: { userID: username}});
if (!user) return res.status(401).json({ message: 'Invalid credentials' });
const isMatch = (password == user.password);
//TODO hash passwords
//const isMatch = await bcrypt.compare(password, user.passwordHash);
if (!isMatch) return res.status(401).json({ message: 'Invalid credentials' });
res.json({ message: 'Logged in successfully' });
}catch (err) { }catch (err) {
console.error('Failed to authenticate:', err); logger.error('Failed to authenticate:', err);
res.status(500).json({ error: 'Failed to authenticate' }); res.status(500).json({ error: 'Failed to authenticate' });
} }
}); });
router.post('/logout', (req, res) => {
res.clearCookie('jwt');
res.json({ message: 'Logged out successfully' });
});
export default router; export default router;

View File

@@ -1,4 +1,5 @@
import express from 'express'; import express from 'express';
import { logger } from '../util/logging';
import Transaction from '../model/transaction'; import Transaction from '../model/transaction';
const router = express.Router(); const router = express.Router();
@@ -8,7 +9,7 @@ router.get('/', async (req, res) => {
const transactions = await Transaction.findAll({ limit: 10 }); const transactions = await Transaction.findAll({ limit: 10 });
res.json(transactions); res.json(transactions);
} catch (err) { } catch (err) {
console.error('Failed to fetch transactions:', err); logger.error('Failed to fetch transactions:', err);
res.status(500).json({ error: 'Failed to fetch transactions' }); res.status(500).json({ error: 'Failed to fetch transactions' });
} }
}); });