diff --git a/README.md b/README.md index 8b25e14..6c89247 100644 --- a/README.md +++ b/README.md @@ -20,3 +20,7 @@ npm install npm start ``` Ezután a http://localhost:3000/ cimen érhető el az oldal. + +## Használat +* Felhasználónév: admin +* Jelszó: admin123 diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts new file mode 100644 index 0000000..a462469 --- /dev/null +++ b/client/src/app/app-routing.module.ts @@ -0,0 +1,38 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AuthCheck } from './auth-check'; +import { ProductListComponent } from './product-list/product-list.component'; +import { LoginComponent } from './login/login.component'; +import { UserListComponent } from './user-list/user-list.component'; + +const routes: Routes = [ + { + path: '', + canActivate: [AuthCheck], + children: [ + { + path: 'users', + component: UserListComponent + }, + { + path: '', + component: ProductListComponent + } + ] + }, + { + path: '', + children: [ + {path: '', component: LoginComponent} + ] + } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { +} + +export type RouteData = { title: string; }; diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index f6842f4..7d16ecd 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -13,9 +13,12 @@ - + -

Termékek

- +
+ + +
+ diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index a1bea9e..294d699 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -14,7 +14,9 @@ export class AppComponent implements OnInit { password: new FormControl() }); - constructor(public userService: UserService, private router: Router) { + toggle = false; + + constructor(public userService: UserService, public router: Router) { } ngOnInit() { @@ -31,4 +33,7 @@ export class AppComponent implements OnInit { alert("Hiba: " + (e?.error?.error ?? JSON.stringify(e))); } } + + async doRegister() { + } } diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 93db176..4ab8b34 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -12,11 +12,20 @@ import { MatTableModule } from '@angular/material/table'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatSortModule } from '@angular/material/sort'; import { HttpClientModule } from '@angular/common/http'; +import { AppRoutingModule } from './app-routing.module'; +import { LoginComponent } from './login/login.component'; +import { UserListComponent } from './user-list/user-list.component'; +import { AuthCheck } from './auth-check'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { RegisterComponent } from './register/register.component'; @NgModule({ declarations: [ AppComponent, - ProductListComponent + ProductListComponent, + LoginComponent, + UserListComponent, + RegisterComponent ], imports: [ BrowserModule, @@ -28,9 +37,13 @@ import { HttpClientModule } from '@angular/common/http'; MatTableModule, MatPaginatorModule, MatSortModule, - HttpClientModule + HttpClientModule, + AppRoutingModule, + MatSlideToggleModule + ], + providers: [ + AuthCheck ], - providers: [], bootstrap: [AppComponent] }) export class AppModule { } diff --git a/client/src/app/auth-check.ts b/client/src/app/auth-check.ts new file mode 100644 index 0000000..6cc568c --- /dev/null +++ b/client/src/app/auth-check.ts @@ -0,0 +1,13 @@ +import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router'; +import { Injectable } from '@angular/core'; +import { UserService } from './services/user.service'; + +@Injectable() +export class AuthCheck implements CanActivate { + constructor(private userService: UserService) { + } + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + return !!this.userService.user; + } +} diff --git a/client/src/app/login/login.component.css b/client/src/app/login/login.component.css new file mode 100644 index 0000000..e69de29 diff --git a/client/src/app/login/login.component.html b/client/src/app/login/login.component.html new file mode 100644 index 0000000..ef9f337 --- /dev/null +++ b/client/src/app/login/login.component.html @@ -0,0 +1 @@ +

Jelentkezz be

diff --git a/client/src/app/login/login.component.spec.ts b/client/src/app/login/login.component.spec.ts new file mode 100644 index 0000000..360f9f2 --- /dev/null +++ b/client/src/app/login/login.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginComponent } from './login.component'; + +describe('LoginComponent', () => { + let component: LoginComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [LoginComponent] + }); + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/login/login.component.ts b/client/src/app/login/login.component.ts new file mode 100644 index 0000000..80a60e8 --- /dev/null +++ b/client/src/app/login/login.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.css'] +}) +export class LoginComponent { + +} diff --git a/client/src/app/model/product.model.ts b/client/src/app/model/product.model.ts new file mode 100644 index 0000000..1cb3a2a --- /dev/null +++ b/client/src/app/model/product.model.ts @@ -0,0 +1,6 @@ +export interface Product { + name: string; + price: number; + description: string; + id: string; +} diff --git a/client/src/app/product-list/product-list-datasource.ts b/client/src/app/product-list/product-list-datasource.ts deleted file mode 100644 index 79e2eb8..0000000 --- a/client/src/app/product-list/product-list-datasource.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { DataSource } from '@angular/cdk/collections'; -import { MatPaginator } from '@angular/material/paginator'; -import { MatSort } from '@angular/material/sort'; -import { map } from 'rxjs/operators'; -import { Observable, of as observableOf, merge } from 'rxjs'; - -// TODO: Replace this with your own data model type -export interface ProductListItem { - name: string; - id: number; -} - -// TODO: replace this with real data from your application -const EXAMPLE_DATA: ProductListItem[] = [ - {id: 1, name: 'Hydrogen'}, - {id: 2, name: 'Helium'}, - {id: 3, name: 'Lithium'}, - {id: 4, name: 'Beryllium'}, - {id: 5, name: 'Boron'}, - {id: 6, name: 'Carbon'}, - {id: 7, name: 'Nitrogen'}, - {id: 8, name: 'Oxygen'}, - {id: 9, name: 'Fluorine'}, - {id: 10, name: 'Neon'}, - {id: 11, name: 'Sodium'}, - {id: 12, name: 'Magnesium'}, - {id: 13, name: 'Aluminum'}, - {id: 14, name: 'Silicon'}, - {id: 15, name: 'Phosphorus'}, - {id: 16, name: 'Sulfur'}, - {id: 17, name: 'Chlorine'}, - {id: 18, name: 'Argon'}, - {id: 19, name: 'Potassium'}, - {id: 20, name: 'Calcium'}, -]; - -/** - * Data source for the ProductList view. This class should - * encapsulate all logic for fetching and manipulating the displayed data - * (including sorting, pagination, and filtering). - */ -export class ProductListDataSource extends DataSource { - data: ProductListItem[] = EXAMPLE_DATA; - paginator: MatPaginator | undefined; - sort: MatSort | undefined; - - constructor() { - super(); - } - - /** - * Connect this data source to the table. The table will only update when - * the returned stream emits new items. - * @returns A stream of the items to be rendered. - */ - connect(): Observable { - if (this.paginator && this.sort) { - // Combine everything that affects the rendered data into one update - // stream for the data-table to consume. - return merge(observableOf(this.data), this.paginator.page, this.sort.sortChange) - .pipe(map(() => { - return this.getPagedData(this.getSortedData([...this.data ])); - })); - } else { - throw Error('Please set the paginator and sort on the data source before connecting.'); - } - } - - /** - * Called when the table is being destroyed. Use this function, to clean up - * any open connections or free any held resources that were set up during connect. - */ - disconnect(): void {} - - /** - * Paginate the data (client-side). If you're using server-side pagination, - * this would be replaced by requesting the appropriate data from the server. - */ - private getPagedData(data: ProductListItem[]): ProductListItem[] { - if (this.paginator) { - const startIndex = this.paginator.pageIndex * this.paginator.pageSize; - return data.splice(startIndex, this.paginator.pageSize); - } else { - return data; - } - } - - /** - * Sort the data (client-side). If you're using server-side sorting, - * this would be replaced by requesting the appropriate data from the server. - */ - private getSortedData(data: ProductListItem[]): ProductListItem[] { - if (!this.sort || !this.sort.active || this.sort.direction === '') { - return data; - } - - return data.sort((a, b) => { - const isAsc = this.sort?.direction === 'asc'; - switch (this.sort?.active) { - case 'name': return compare(a.name, b.name, isAsc); - case 'id': return compare(+a.id, +b.id, isAsc); - default: return 0; - } - }); - } -} - -/** Simple sort comparator for example ID/Name columns (for client-side sorting). */ -function compare(a: string | number, b: string | number, isAsc: boolean): number { - return (a < b ? -1 : 1) * (isAsc ? 1 : -1); -} diff --git a/client/src/app/product-list/product-list.component.html b/client/src/app/product-list/product-list.component.html index de4cced..f950952 100644 --- a/client/src/app/product-list/product-list.component.html +++ b/client/src/app/product-list/product-list.component.html @@ -1,15 +1,18 @@
- - - - + + + - - - - + + + + + + + + @@ -17,7 +20,7 @@
Id{{row.id}}Név{{row.name}} Name{{row.name}}Leirás{{row.description}}Ár{{row.price}}
; - dataSource: ProductListDataSource; + @ViewChild(MatTable) table!: MatTable; + + products: Observable /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ - displayedColumns = ['id', 'name']; + displayedColumns = ['name', 'description', 'price']; - constructor() { - this.dataSource = new ProductListDataSource(); + constructor(private service: ProductService) { + this.products = service.getList().pipe(map(value => value as Product[])); } ngAfterViewInit(): void { - this.dataSource.sort = this.sort; - this.dataSource.paginator = this.paginator; - this.table.dataSource = this.dataSource; + this.table.dataSource = this.products; } } diff --git a/client/src/app/register/register.component.css b/client/src/app/register/register.component.css new file mode 100644 index 0000000..e69de29 diff --git a/client/src/app/register/register.component.html b/client/src/app/register/register.component.html new file mode 100644 index 0000000..6b0ba2e --- /dev/null +++ b/client/src/app/register/register.component.html @@ -0,0 +1 @@ +

register works!

diff --git a/client/src/app/register/register.component.spec.ts b/client/src/app/register/register.component.spec.ts new file mode 100644 index 0000000..9c4c73c --- /dev/null +++ b/client/src/app/register/register.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RegisterComponent } from './register.component'; + +describe('RegisterComponent', () => { + let component: RegisterComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [RegisterComponent] + }); + fixture = TestBed.createComponent(RegisterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/register/register.component.ts b/client/src/app/register/register.component.ts new file mode 100644 index 0000000..21647df --- /dev/null +++ b/client/src/app/register/register.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-register', + templateUrl: './register.component.html', + styleUrls: ['./register.component.css'] +}) +export class RegisterComponent { + +} diff --git a/client/src/app/services/product.service.ts b/client/src/app/services/product.service.ts new file mode 100644 index 0000000..50d7c39 --- /dev/null +++ b/client/src/app/services/product.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +@Injectable({ + providedIn: 'root' +}) +export class ProductService { + constructor(private http: HttpClient) { } + + getList() { + return this.http.get('/api/products') + } +} diff --git a/client/src/app/services/user.service.ts b/client/src/app/services/user.service.ts index d2d67d2..b8ca3de 100644 --- a/client/src/app/services/user.service.ts +++ b/client/src/app/services/user.service.ts @@ -32,4 +32,8 @@ export class UserService { this._user = undefined; } } + + getList() { + return this.http.get('/api/users') + } } diff --git a/client/src/app/user-list/user-list.component.css b/client/src/app/user-list/user-list.component.css new file mode 100644 index 0000000..e69de29 diff --git a/client/src/app/user-list/user-list.component.html b/client/src/app/user-list/user-list.component.html new file mode 100644 index 0000000..0db22af --- /dev/null +++ b/client/src/app/user-list/user-list.component.html @@ -0,0 +1,29 @@ +
+ + + + + + + + + + + + + + + + + + +
Felhasználónév{{row.username}}Hozzáférési szint{{row.accessLevel}}Születési dátum{{row.birthdate | date}}
+ + + +
diff --git a/client/src/app/user-list/user-list.component.spec.ts b/client/src/app/user-list/user-list.component.spec.ts new file mode 100644 index 0000000..88251ff --- /dev/null +++ b/client/src/app/user-list/user-list.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserListComponent } from './user-list.component'; + +describe('UserListComponent', () => { + let component: UserListComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [UserListComponent] + }); + fixture = TestBed.createComponent(UserListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/user-list/user-list.component.ts b/client/src/app/user-list/user-list.component.ts new file mode 100644 index 0000000..b95f5d2 --- /dev/null +++ b/client/src/app/user-list/user-list.component.ts @@ -0,0 +1,32 @@ +import { AfterViewInit, Component, ViewChild } from '@angular/core'; +import { MatTable } from '@angular/material/table'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { UserService } from '../services/user.service'; +import { User } from '../model/user.model'; +import { map } from 'rxjs/operators'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'app-user-list', + templateUrl: './user-list.component.html', + styleUrls: ['./user-list.component.css'] +}) +export class UserListComponent implements AfterViewInit { + @ViewChild(MatPaginator) paginator!: MatPaginator; + @ViewChild(MatSort) sort!: MatSort; + @ViewChild(MatTable) table!: MatTable; + + users: Observable + + /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ + displayedColumns = ['username', 'accessLevel', 'birthdate']; + + constructor(private service: UserService) { + this.users = service.getList().pipe(map(value => value as User[])); + } + + ngAfterViewInit(): void { + this.table.dataSource = this.users; + } +} diff --git a/server/index.js b/server/index.js index 2dac319..59e53d0 100644 --- a/server/index.js +++ b/server/index.js @@ -58,6 +58,13 @@ app.use(passport.session({})); app.use('/api/users', require('./usersRouter')) app.use('/api/products', require('./productsRouter')) +app.use(function (req, _, next) { + if (!req.url.startsWith('/api') && req.url.indexOf('.') === -1) { + req.url = '/'; + } + next(); +}) + app.use('', express.static('public')) app.listen(3000, () => { diff --git a/server/productsRouter.js b/server/productsRouter.js index d59366b..852f269 100644 --- a/server/productsRouter.js +++ b/server/productsRouter.js @@ -29,7 +29,7 @@ router.get('/', async (req, res) => { } try { const products = await Product.find(); - res.status(200).json(products); + res.status(200).json(products.map(product => getProductData(product))); } catch (error) { res.status(500).json({ message: error.message }); } @@ -40,7 +40,7 @@ router.get('/:id', getProduct, (req, res) => { if (!req.isAuthenticated()) { return res.status(403).json({ message: "Unauthenticated" }); } - res.json(res.product); + res.json(getProductData(res.product)); }); // POST /products - új termék létrehozása