Compare commits
15 Commits
da484b08a9
...
v.0.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 7dc392631d | |||
| 98f8e0b79b | |||
| 4c31ccd021 | |||
| 57d35a01ba | |||
| 6f6efa5886 | |||
| 4498c865f2 | |||
| a58adbcc8d | |||
| 8a18b95031 | |||
| c867d9d51f | |||
| 4905ef607b | |||
| 2c18c59f51 | |||
| d622fda7a9 | |||
| 831a667a27 | |||
| 947ed225b6 | |||
| b74da2dc3b |
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,3 +1,30 @@
|
|||||||
|
# v.0.3.0 (Release Candidate 1)
|
||||||
|
## 🚀 Features
|
||||||
|
- Swagger Documentation
|
||||||
|
|
||||||
|
## 🐛 Bugfixes
|
||||||
|
- Bugfix on search page for Band datasets
|
||||||
|
|
||||||
|
# v.0.2.0 (Beta)
|
||||||
|
## 🚀 Features
|
||||||
|
- Adding "Test Environment" banner in the bottom right corner
|
||||||
|
- License handling system
|
||||||
|
- New SQL-Injection exercise 2.1
|
||||||
|
- Solution code based on Matrikelnummer and number of completed exercises
|
||||||
|
|
||||||
|
## 🌟 Enhancements
|
||||||
|
- Improve exercise solution of 2.1, 2.2, 2.3, 2.4 and 2.6
|
||||||
|
- Light mode improvements
|
||||||
|
- Global color schema
|
||||||
|
- More feedback through notifications
|
||||||
|
- More hints on text fields
|
||||||
|
- Redesign account pages, split payments and addresses, new dashboard
|
||||||
|
|
||||||
|
## 🐛 Bugfixes
|
||||||
|
- More server stability
|
||||||
|
- Bugfix file manager in Electron application
|
||||||
|
|
||||||
|
|
||||||
# v.0.1.0 (Alpha)
|
# v.0.1.0 (Alpha)
|
||||||
## 🚀 Features
|
## 🚀 Features
|
||||||
- Frontend
|
- Frontend
|
||||||
|
|||||||
425
README.md
425
README.md
@@ -1,6 +1,6 @@
|
|||||||
# HackMyCart
|
# EventMaster
|
||||||
|
|
||||||
The most hackable Web Shop!
|
The most hackable Ticket-Shop!
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
@@ -47,424 +47,3 @@ The frontend runs on `http://localhost:5173/` and the backend on `http://localho
|
|||||||
|
|
||||||
### Database
|
### Database
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
### Backend API endpoints
|
|
||||||
|
|
||||||
The application host it's data in a SQLite database. The access is managed by an [ExpressJs](https://expressjs.com/) server which offers many REST-API endpoints for the frontend. The REST-API server runs on port 3000.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Listing existing
|
|
||||||
|
|
||||||
<details open>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/accounts/</b></code> <code> (Get all Accounts)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> None
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<Account + AccountRole>` |
|
|
||||||
|
|
||||||
##### Example Response
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": 421,
|
|
||||||
"username": "hagemeister93",
|
|
||||||
"password": "Xjt3qb5t",
|
|
||||||
"email": "hagemeister93@gmail.com",
|
|
||||||
"firstName": "Laurin",
|
|
||||||
"lastName": "Hagemeister",
|
|
||||||
"accountRoleId": 2,
|
|
||||||
"accountRole": {
|
|
||||||
"id": 2,
|
|
||||||
"name": "Admin",
|
|
||||||
"privilegeBuy": true,
|
|
||||||
"privilegeAdminPanel": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details open>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/api/files</b></code> <code> (Get all public files)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> None
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<{folder: String, files: Array<{name: String, size: Number, url: String}> }>` |
|
|
||||||
|
|
||||||
##### Example Response
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"folder": "artists",
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"name": "alex-turner.jpg",
|
|
||||||
"size": 56473,
|
|
||||||
"url": "http://localhost:3000/static/artists/alex-turner.jpg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "andy-nicholson.jpg",
|
|
||||||
"size": 68983,
|
|
||||||
"url": "http://localhost:3000/static/artists/andy-nicholson.jpg"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details open>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/bands/</b></code> <code> (Get all bands)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | :---: | --- | --- | --- |
|
|
||||||
> | `sort` | optional | string | Sort by number of concerts ascending (asc) or descending (desc) |
|
|
||||||
> | `count` | optional | number | Number of items to responde |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<>` |
|
|
||||||
|
|
||||||
##### Example Response
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"folder": "artists",
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"name": "alex-turner.jpg",
|
|
||||||
"size": 56473,
|
|
||||||
"url": "http://localhost:3000/static/artists/alex-turner.jpg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "andy-nicholson.jpg",
|
|
||||||
"size": 68983,
|
|
||||||
"url": "http://localhost:3000/static/artists/andy-nicholson.jpg"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/events?city=cityName&genre=genreName&count=nrOfItems&sort=sortDirection</b></code> <code> (Get all events, filtered by city and genre)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | :---: | --- | --- | --- |
|
|
||||||
> | `cityName` | optional | string | Name of the city to filter for |
|
|
||||||
> | `genreName` | optional | string | Name of the genre to filter for |
|
|
||||||
> | `nrOfItems` | optional | number | Limits number of results |
|
|
||||||
> | `sortDirection` | optional | string | Sort by number of concerts, 'asc' or 'desc' |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<Event + Array<Concert + Location + City> + Band & Genre>` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/locations?count=nrOfItems&sort=sortDirection</b></code> <code> (Get all locations)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | :---: | --- | --- | --- |
|
|
||||||
> | `nrOfItems` | optional | number | Limits number of results |
|
|
||||||
> | `sortDirection` | optional | string | Sort by number of concerts, 'asc' or 'desc' |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<Location + City + Array<Concert + Event>>` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
Down here: todo!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/bands</b></code> <code> (Get all bands)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> None
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<Band>` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/bands/:id</b></code> <code> (Get all information about one band)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | :---: | --- | --- | --- |
|
|
||||||
> | `id` | required | string | ID of product in the database |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Band` + `Array<Rating>` + `Array<Member>` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/shows/:id</b></code> <code> (Get all information about one show)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | :---: | --- | --- | --- |
|
|
||||||
> | `id` | required | string | ID of product in the database |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Show` + `Tour` + `Location` + `City` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/tours</b></code> <code> (Get all tours)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> None
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<Tours>` + `Band` + `Show` + `Location` + `City` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/genres</b></code> <code> (Get all genres)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> None
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<Genre>` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/orders/:id</b></code> <code> (Get all orders of an user)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | --- | --- | --- | --- |
|
|
||||||
> | `id` | required | string | ID of userAccount in the database |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `ProductModel` + `Order`, `OrderItem`, `Product` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/categories/</b></code> <code> (Get all Categories)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> None
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<Categories>` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/brands</b></code> <code> (Get all Brands)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> None
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `Array<Brand>` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
#### Creating new
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#69CA92"><b>POST</b></span></code> <code><b>/accounts/</b></code> <code> (Create a new account)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | :---: | --- | --- | --- |
|
|
||||||
> | None | required | object (JSON) | Model of an Account |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `201` | `application/json` | `AccountModel` |
|
|
||||||
> | `400` | `application/json` | `{code: 400, message: "Username too short!"}` |
|
|
||||||
> | `400` | `application/json` | `{code: 400, message: "Password too short!"}` |
|
|
||||||
> | `409` | `application/json` | `{code: 409, message: "Username already in use"}` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#69CA92"><b>POST</b></span></code> <code><b>/orders/</b></code> <code> (Create a new order)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | :---: | --- | --- | --- |
|
|
||||||
> | None | required | object (JSON) | Model of an Order |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `201` | `application/json` | `OrderModel` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Updating existing
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#F3A63D"><b>PATCH</b></span></code> <code><b>/accounts/</b></code> <code> (Update data of an existing account)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | :---: | --- | --- | --- |
|
|
||||||
> | None | required | object (JSON) | Model of an Account |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | AccountModel |
|
|
||||||
> | `400` | `application/json` | `{code: 400, message: "..."}` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Delete existing
|
|
||||||
|
|
||||||
<!-- <details>
|
|
||||||
<summary><code><span style="color:#EB5246"><b>DELETE</b></span></code> <code><b>/product/:id</b></code> <code> (Delete a product)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | :---: | --- | --- | --- |
|
|
||||||
> | `id` | required | string | ID of product in the database |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `ProductModel` |
|
|
||||||
> | `400` | `application/json` | `{code: 400, message: "..."}` |
|
|
||||||
</details> -->
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Miscs
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/api/</b></code> <code> (Check if server runs)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> None
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | None | None |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/resetDatabase/</b></code> <code> (Reset the database to it's default values)</code>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> None
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | None | None |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
#### Validate
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><code><span style="color:#69CA92"><b>POST</b></span></code> <code><b>/accounts/login</b></code> <code> (Login for user)</code></summary>
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
> | name | type | data type | description |
|
|
||||||
> | --- | --- | --- | --- |
|
|
||||||
> | username | required | string | Username of the account |
|
|
||||||
> | password | required | string | Password of the account |
|
|
||||||
|
|
||||||
##### Responses
|
|
||||||
> | http code | content-type | response |
|
|
||||||
> | :---: | --- | --- |
|
|
||||||
> | `200` | `application/json` | `AccountObject` + `Addresses`, `Payments`, `AccountRole` |
|
|
||||||
> | `400` | `application/json` | `{code: 400, message: "Bad Request"}` |
|
|
||||||
> | `401` | `application/json` | `{code: 401, message: "Unauthorized"}` |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
---
|
|
||||||
@@ -4,29 +4,19 @@
|
|||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "Unregistered",
|
"name": "Unregistered",
|
||||||
"privilegeBuy": false,
|
"privilegeBuy": false,
|
||||||
"privilegeAdminPanel": false,
|
"privilegeAdminPanel": false
|
||||||
"privilegeFileAccess": false
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "User",
|
"name": "User",
|
||||||
"privilegeBuy": true,
|
"privilegeBuy": true,
|
||||||
"privilegeAdminPanel": false,
|
"privilegeAdminPanel": false
|
||||||
"privilegeFileAccess": false
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"name": "Admin",
|
"name": "Admin",
|
||||||
"privilegeBuy": true,
|
"privilegeBuy": true,
|
||||||
"privilegeAdminPanel": true,
|
"privilegeAdminPanel": true
|
||||||
"privilegeFileAccess": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"name": "Super-Admin",
|
|
||||||
"privilegeBuy": true,
|
|
||||||
"privilegeAdminPanel": true,
|
|
||||||
"privilegeFileAccess": true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"iban": "DE92500105175721645777"
|
"iban": "DE92500105175721645777"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"accountRoleId": 2
|
"accountRoleId": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"username": "katjaStoiber",
|
"username": "katjaStoiber",
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
"iban": "DE41500105172184936679"
|
"iban": "DE41500105172184936679"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"accountRoleId": 3
|
"accountRoleId": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"username": "guitarhero",
|
"username": "guitarhero",
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ export class AccountRole extends Model {
|
|||||||
@Column
|
@Column
|
||||||
privilegeAdminPanel: boolean
|
privilegeAdminPanel: boolean
|
||||||
|
|
||||||
@Column
|
|
||||||
privilegeFileAccess: boolean
|
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
@HasMany(() => Account)
|
@HasMany(() => Account)
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Account
|
||||||
|
* description: API to manage accounts
|
||||||
|
*/
|
||||||
import { Router, Request, Response } from "express";
|
import { Router, Request, Response } from "express";
|
||||||
import { Account } from "../models/user/account.model";
|
import { Account } from "../models/user/account.model";
|
||||||
import { validateString } from "../scripts/validateHelper";
|
import { validateString } from "../scripts/validateHelper";
|
||||||
@@ -11,60 +17,132 @@ import { encryptString } from "../scripts/encryptScripts";
|
|||||||
|
|
||||||
export const account = Router()
|
export const account = Router()
|
||||||
|
|
||||||
account.get("/", verifyToken, (req: Request, res: Response) => {
|
/**
|
||||||
Account.findAll({
|
* @swagger
|
||||||
include: [ AccountRole ]
|
* /accounts/login:
|
||||||
})
|
* get:
|
||||||
.then(accounts => {
|
* summary: Start login process
|
||||||
res.status(200).json(accounts)
|
* tags: [Account]
|
||||||
})
|
* parameters:
|
||||||
})
|
* - in: query
|
||||||
|
* name: username
|
||||||
// Login user
|
* schema:
|
||||||
account.get("/account/login", async (req: Request, res: Response) => {
|
* type: string
|
||||||
|
* required: true
|
||||||
|
* description: Username
|
||||||
|
* - in: query
|
||||||
|
* name: password
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: true
|
||||||
|
* description: User password
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Login successful
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/loginResponse'
|
||||||
|
* 401:
|
||||||
|
* description: Wrong credentials
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
|
account.get("/login", async (req: Request, res: Response) => {
|
||||||
const encryptedPassword = encryptString(String(req.query.password))
|
const encryptedPassword = encryptString(String(req.query.password))
|
||||||
|
|
||||||
// Using raw SQL code for SQL injections!
|
try {
|
||||||
const [results, metadata] =
|
// Using raw SQL code for SQL injections!
|
||||||
await sequelize.query(
|
const [results, metadata] =
|
||||||
"SELECT * FROM Accounts " +
|
await sequelize.query(
|
||||||
"WHERE (username='" + req.query.username +
|
"SELECT * FROM Accounts " +
|
||||||
"' AND password='" + encryptedPassword + "')"
|
"WHERE (username='" + req.query.username +
|
||||||
)
|
"' AND password='" + encryptedPassword + "')"
|
||||||
|
)
|
||||||
|
|
||||||
if (results.length != 0) {
|
if (results.length != 0) {
|
||||||
// Creating session token
|
// Creating session token
|
||||||
const token = jwt.sign({ userId: results[0]["id"] }, 'sjcucjdkdf')
|
const token = jwt.sign({ userId: results[0]["id"] }, 'sjcucjdkdf')
|
||||||
|
|
||||||
// Status: 200 OK
|
// Status: 200 OK
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
token: token
|
token: token
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// Status: 401 Unauthorized
|
// Status: 401 Unauthorized
|
||||||
res.status(401).json({
|
res.status(401).send()
|
||||||
code: 401,
|
}
|
||||||
message: "Unauthorized"
|
} catch (e) {
|
||||||
})
|
res.status(500).send()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
account.get("/account/data", verifyToken, async(req: Request, res: Response) => {
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /accounts/account:
|
||||||
|
* get:
|
||||||
|
* summary: Get all data about an user account
|
||||||
|
* tags: [Account]
|
||||||
|
* security:
|
||||||
|
* - JWT: []
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Success
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/useraccount'
|
||||||
|
* 401:
|
||||||
|
* description: Unauthorized
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
|
account.get("/account", verifyToken, async(req: Request, res: Response) => {
|
||||||
Account.findOne({
|
Account.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: req["id"]
|
id: req["id"]
|
||||||
},
|
},
|
||||||
include: [ Address, AccountRole, Payment ]
|
include: [ Address, AccountRole, Payment ],
|
||||||
|
attributes: {
|
||||||
|
exclude: [ "accountRoleId" ]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.then(account => {
|
.then(account => {
|
||||||
res.status(200).json(account)
|
res.status(200).json(account)
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Creating a new user
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /accounts/account:
|
||||||
|
* post:
|
||||||
|
* summary: Create a new user account
|
||||||
|
* tags: [Account]
|
||||||
|
* requestBody:
|
||||||
|
* description: Minimal user data body
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/minimalAccount'
|
||||||
|
* responses:
|
||||||
|
* 201:
|
||||||
|
* description: Created
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/useraccount'
|
||||||
|
* 400:
|
||||||
|
* description: Username/password too short
|
||||||
|
* 409:
|
||||||
|
* description: Username already in use
|
||||||
|
*/
|
||||||
account.post("/account", async (req: Request, res: Response) => {
|
account.post("/account", async (req: Request, res: Response) => {
|
||||||
// Check if username is valid
|
// Check if username is valid
|
||||||
if (!validateString(req.body.username, 4))
|
if (!validateString(req.body.username, 4))
|
||||||
@@ -102,7 +180,7 @@ account.post("/account", async (req: Request, res: Response) => {
|
|||||||
.then(account => {
|
.then(account => {
|
||||||
// Status: 201 Created
|
// Status: 201 Created
|
||||||
res.status(201).json(account)
|
res.status(201).json(account)
|
||||||
}).catch(reason => {
|
}).catch(error => {
|
||||||
// Status: 409 Conflict
|
// Status: 409 Conflict
|
||||||
res.status(409).json({
|
res.status(409).json({
|
||||||
code: 409,
|
code: 409,
|
||||||
@@ -111,38 +189,56 @@ account.post("/account", async (req: Request, res: Response) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /accounts/account:
|
||||||
|
* patch:
|
||||||
|
* summary: Update an user accounts data
|
||||||
|
* tags: [Account]
|
||||||
|
* security:
|
||||||
|
* - JWT: []
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Success
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/useraccount'
|
||||||
|
* 401:
|
||||||
|
* description: Unauthorized
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
account.patch("/account", verifyToken, (req: Request, res: Response) => {
|
account.patch("/account", verifyToken, (req: Request, res: Response) => {
|
||||||
Account.update(req.body,
|
Account.update(req.body,
|
||||||
{
|
{
|
||||||
where: { id: req.body.id }
|
where: { id: req.body.id }
|
||||||
})
|
})
|
||||||
.then(async result => {
|
.then(async result => {
|
||||||
for (let payment of req.body.payments) {
|
Payment.destroy({
|
||||||
if (payment.id == undefined) {
|
where: {
|
||||||
payment["accountId"] = req.body.id
|
accountId: req.body.id
|
||||||
|
|
||||||
await Payment.create(payment)
|
|
||||||
} else {
|
|
||||||
await Payment.update(payment,
|
|
||||||
{
|
|
||||||
where: { id: payment.id }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Address.destroy({
|
||||||
|
where: {
|
||||||
|
accountId: req.body.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let payment of req.body.payments) {
|
||||||
|
payment["accountId"] = req.body.id
|
||||||
|
|
||||||
|
await Payment.create(payment)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let address of req.body.addresses) {
|
for (let address of req.body.addresses) {
|
||||||
if (address.id == undefined) {
|
address["accountId"] = req.body.id
|
||||||
address["accountId"] = req.body.id
|
|
||||||
|
|
||||||
await Address.create(address)
|
await Address.create(address)
|
||||||
} else {
|
|
||||||
await Address.update(address,
|
|
||||||
{
|
|
||||||
where: { id: address.id }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status: 200 OK
|
// Status: 200 OK
|
||||||
@@ -158,7 +254,31 @@ account.patch("/account", verifyToken, (req: Request, res: Response) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
account.delete("/account/:id", (req: Request, res: Response) => {
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /accounts/account/{id}:
|
||||||
|
* delete:
|
||||||
|
* summary: Delete an user account
|
||||||
|
* tags: [Account]
|
||||||
|
* security:
|
||||||
|
* - JWT: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* schema:
|
||||||
|
* type: number
|
||||||
|
* required: true
|
||||||
|
* description: ID of user account
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Success
|
||||||
|
* 401:
|
||||||
|
* description: Unauthorized
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
|
account.delete("/account/:id", verifyToken, (req: Request, res: Response) => {
|
||||||
Account.destroy({
|
Account.destroy({
|
||||||
where: {
|
where: {
|
||||||
id: req.params.id
|
id: req.params.id
|
||||||
@@ -167,4 +287,40 @@ account.delete("/account/:id", (req: Request, res: Response) => {
|
|||||||
.then(account => {
|
.then(account => {
|
||||||
res.status(200).send()
|
res.status(200).send()
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /accounts/:
|
||||||
|
* get:
|
||||||
|
* summary: Request all user accounts
|
||||||
|
* tags: [Account]
|
||||||
|
* security:
|
||||||
|
* - JWT: []
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Success
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/useraccount'
|
||||||
|
* 401:
|
||||||
|
* description: Unauthorized
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
|
account.get("/", verifyToken, (req: Request, res: Response) => {
|
||||||
|
Account.findAll({
|
||||||
|
include: [ AccountRole ]
|
||||||
|
})
|
||||||
|
.then(accounts => {
|
||||||
|
res.status(200).json(accounts)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -1,18 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Api
|
||||||
|
* description: Main API access point for misc events
|
||||||
|
*/
|
||||||
import { Request, Response, NextFunction, Router } from 'express'
|
import { Request, Response, NextFunction, Router } from 'express'
|
||||||
import { deleteAllTables, deleteExerciseProgressTables, prepopulateDatabase, prepopulateExerciseDatabase } from '../scripts/databaseHelper'
|
import { deleteAllTables, deleteExerciseProgressTables, prepopulateDatabase, prepopulateExerciseDatabase } from '../scripts/databaseHelper'
|
||||||
|
|
||||||
export const api = Router()
|
export const api = Router()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status check endpoint
|
* @swagger
|
||||||
|
* /api:
|
||||||
|
* get:
|
||||||
|
* summary: Status check endpoint
|
||||||
|
* tags: [Api]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Server is up and running
|
||||||
*/
|
*/
|
||||||
api.get("/", (req: Request, res: Response, next: NextFunction) => {
|
api.get("/", (req: Request, res: Response, next: NextFunction) => {
|
||||||
res.status(200).send()
|
res.status(200).send()
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the whole database to factory state
|
* @swagger
|
||||||
* Doesn't effect ExerciseTable and ExerciseGroupTable
|
* /api/resetdatabase:
|
||||||
|
* get:
|
||||||
|
* summary: Reset the database to factory state
|
||||||
|
* description: Doesn't effect ExerciseTable and ExerciseGroupTable
|
||||||
|
* tags: [Api]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Reset successful
|
||||||
*/
|
*/
|
||||||
api.get("/resetdatabase", async (req: Request, res: Response, next: NextFunction) => {
|
api.get("/resetdatabase", async (req: Request, res: Response, next: NextFunction) => {
|
||||||
// Step 1: Delete all data tables
|
// Step 1: Delete all data tables
|
||||||
@@ -26,7 +46,15 @@ api.get("/resetdatabase", async (req: Request, res: Response, next: NextFunction
|
|||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset ExerciseTable and ExerciseGroupTable to factory state
|
* @swagger
|
||||||
|
* /api/resetExerciseProgress:
|
||||||
|
* get:
|
||||||
|
* summary: Reset exercises to factory state
|
||||||
|
* description: Reset ExerciseTable and ExerciseGroupTable to factory state
|
||||||
|
* tags: [Api]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Reset successful
|
||||||
*/
|
*/
|
||||||
api.get("/resetExerciseProgress", async (req: Request, res: Response, next: NextFunction) => {
|
api.get("/resetExerciseProgress", async (req: Request, res: Response, next: NextFunction) => {
|
||||||
deleteExerciseProgressTables()
|
deleteExerciseProgressTables()
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Bands
|
||||||
|
* description: API to manage the bands
|
||||||
|
*/
|
||||||
import { Member } from "../models/acts/member.model";
|
import { Member } from "../models/acts/member.model";
|
||||||
import { Band } from "../models/acts/band.model";
|
import { Band } from "../models/acts/band.model";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
@@ -13,7 +19,33 @@ import { sequelize } from "../database";
|
|||||||
export const band = Router()
|
export const band = Router()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all bands
|
* @swagger
|
||||||
|
* /bands:
|
||||||
|
* get:
|
||||||
|
* summary: Download all available bands
|
||||||
|
* tags: [Bands]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: sort
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: false
|
||||||
|
* description: Sort bands by number of concerts ascending (asc) or descending (desc)
|
||||||
|
* - in: query
|
||||||
|
* name: count
|
||||||
|
* schema:
|
||||||
|
* type: number
|
||||||
|
* required: false
|
||||||
|
* description: Limit number of results
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: List of band objects
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/band'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
band.get("/", (req: Request, res: Response) => {
|
band.get("/", (req: Request, res: Response) => {
|
||||||
let sort = req.query.sort
|
let sort = req.query.sort
|
||||||
@@ -21,16 +53,14 @@ band.get("/", (req: Request, res: Response) => {
|
|||||||
|
|
||||||
Band.findAll({
|
Band.findAll({
|
||||||
include: [
|
include: [
|
||||||
{
|
|
||||||
model: Rating,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
model: Genre,
|
model: Genre,
|
||||||
attributes: {
|
attributes: {
|
||||||
exclude: [ "id" ]
|
exclude: [ "id" ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Concert
|
Concert,
|
||||||
|
Rating
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.then(bands => {
|
.then(bands => {
|
||||||
@@ -65,6 +95,9 @@ band.get("/", (req: Request, res: Response) => {
|
|||||||
|
|
||||||
res.status(200).json(bands)
|
res.status(200).json(bands)
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,7 +155,7 @@ band.get("/band/:name", (req: Request, res: Response) => {
|
|||||||
|
|
||||||
res.status(200).json(band)
|
res.status(200).json(band)
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(error => {
|
||||||
res.status(404).send()
|
res.status(404).send()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -137,10 +170,13 @@ band.get("/search", async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
// On stacked prompts, execute last prompt
|
// On stacked prompts, execute last prompt
|
||||||
if (prompts.length > 1) {
|
if (prompts.length > 1) {
|
||||||
const [results, metadata] =
|
try {
|
||||||
await sequelize.query(prompts[prompts.length - 2])
|
const [results, metadata] =
|
||||||
|
await sequelize.query(prompts[prompts.length - 2])
|
||||||
res.status(200).json(results)
|
res.status(200).json(results)
|
||||||
|
} catch (e) {
|
||||||
|
res.status(400).send()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Band.findAll({
|
Band.findAll({
|
||||||
where: {
|
where: {
|
||||||
@@ -153,7 +189,7 @@ band.get("/search", async (req: Request, res: Response) => {
|
|||||||
.then(bands => {
|
.then(bands => {
|
||||||
res.status(200).json(bands)
|
res.status(200).json(bands)
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(error => {
|
||||||
res.status(200).send()
|
res.status(200).send()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -172,6 +208,9 @@ band.patch("/", (req: Request, res: Response) => {
|
|||||||
.then(result => {
|
.then(result => {
|
||||||
res.status(200).json(result)
|
res.status(200).json(result)
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -183,6 +222,9 @@ band.post("/", (req: Request, res: Response) => {
|
|||||||
.then(result => {
|
.then(result => {
|
||||||
res.status(200).json(result)
|
res.status(200).json(result)
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,11 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Cities
|
||||||
|
* description: API to manage the cities
|
||||||
|
*/
|
||||||
import { City } from "../models/locations/city.model";
|
import { City } from "../models/locations/city.model";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
|
|
||||||
export const city = Router()
|
export const city = Router()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /cities:
|
||||||
|
* get:
|
||||||
|
* summary: Download all cities
|
||||||
|
* tags: [Cities]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: List of all cities as objects
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/city'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
city.get("/", (req: Request, res: Response) => {
|
city.get("/", (req: Request, res: Response) => {
|
||||||
City.findAll()
|
City.findAll()
|
||||||
.then(cities => {
|
.then(cities => {
|
||||||
res.status(200).json(cities)
|
res.status(200).json(cities)
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Concerts
|
||||||
|
* description: API to manage the concerts
|
||||||
|
*/
|
||||||
import { Location } from "../models/locations/location.model";
|
import { Location } from "../models/locations/location.model";
|
||||||
import { Concert } from "../models/acts/concert.model";
|
import { Concert } from "../models/acts/concert.model";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
@@ -11,18 +17,68 @@ import { Op } from "sequelize";
|
|||||||
|
|
||||||
export const concert = Router()
|
export const concert = Router()
|
||||||
|
|
||||||
|
const concertStructure = [
|
||||||
|
{
|
||||||
|
model: Band
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Location,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: City
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: SeatGroup,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: SeatRow,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Seat,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Ticket
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
attributes: {
|
||||||
|
exclude: [ "cityId" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /concerts:
|
||||||
|
* get:
|
||||||
|
* summary: Get all available concerts
|
||||||
|
* tags: [Concerts]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: count
|
||||||
|
* schema:
|
||||||
|
* type: number
|
||||||
|
* required: false
|
||||||
|
* description: Limit number of results
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/concert'
|
||||||
|
*/
|
||||||
concert.get("/", (req: Request, res: Response) => {
|
concert.get("/", (req: Request, res: Response) => {
|
||||||
let count = req.query.count
|
let count = req.query.count
|
||||||
|
|
||||||
Concert.findAll({
|
Concert.findAll({
|
||||||
include: [
|
include: concertStructure,
|
||||||
{
|
|
||||||
model: Location,
|
|
||||||
include: [ City ]
|
|
||||||
},
|
|
||||||
Band
|
|
||||||
],
|
|
||||||
order: [
|
order: [
|
||||||
[ 'date', 'ASC' ]
|
[ 'date', 'ASC' ]
|
||||||
]
|
]
|
||||||
@@ -35,50 +91,37 @@ concert.get("/", (req: Request, res: Response) => {
|
|||||||
|
|
||||||
res.status(200).json(concerts)
|
res.status(200).json(concerts)
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Get all available data about a band by it's ID
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /concerts/concert/{id}:
|
||||||
|
* get:
|
||||||
|
* summary: Download all available informations about a specific concert
|
||||||
|
* tags: [Concerts]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* schema:
|
||||||
|
* type: number
|
||||||
|
* required: true
|
||||||
|
* description: ID of concert in database
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Single concert object
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/concert'
|
||||||
|
* 404:
|
||||||
|
* description: Not found
|
||||||
|
*/
|
||||||
concert.get("/concert/:id", (req: Request, res: Response) => {
|
concert.get("/concert/:id", (req: Request, res: Response) => {
|
||||||
Concert.findByPk(req.params.id, {
|
Concert.findByPk(req.params.id, { include: concertStructure })
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Band,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: Location,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: City
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: SeatGroup,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: SeatRow,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Seat,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Ticket
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
attributes: {
|
|
||||||
exclude: [ "cityId" ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
attributes: {
|
|
||||||
exclude: [ "locationId", "tourId" ]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(concert => {
|
.then(concert => {
|
||||||
concert.dataValues["capacity"] = 0
|
concert.dataValues["capacity"] = 0
|
||||||
|
|
||||||
@@ -116,7 +159,29 @@ concert.get("/concert/:id", (req: Request, res: Response) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Concert search
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /concerts/search:
|
||||||
|
* get:
|
||||||
|
* summary: Search for concerts
|
||||||
|
* tags: [Concerts]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: value
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: true
|
||||||
|
* description: Search term
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: List of concert objects
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/concert'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
concert.get("/search", (req: Request, res: Response) => {
|
concert.get("/search", (req: Request, res: Response) => {
|
||||||
Concert.findAll({
|
Concert.findAll({
|
||||||
where: {
|
where: {
|
||||||
@@ -154,4 +219,7 @@ concert.get("/search", (req: Request, res: Response) => {
|
|||||||
.then(concerts => {
|
.then(concerts => {
|
||||||
res.status(200).json(concerts)
|
res.status(200).json(concerts)
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Exercises
|
||||||
|
* description: API to manage the exercise progress
|
||||||
|
*/
|
||||||
import { Op } from "sequelize";
|
import { Op } from "sequelize";
|
||||||
import { Exercise } from "../models/exercises/exercise.model";
|
import { Exercise } from "../models/exercises/exercise.model";
|
||||||
import { ExerciseGroup } from "../models/exercises/exerciseGroup.model";
|
import { ExerciseGroup } from "../models/exercises/exerciseGroup.model";
|
||||||
@@ -6,26 +12,75 @@ import { Request, Response, Router } from "express";
|
|||||||
export const exercises = Router()
|
export const exercises = Router()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all Exercises grouped in ExerciseGroups
|
* @swagger
|
||||||
|
* /exercises:
|
||||||
|
* get:
|
||||||
|
* summary: Download all exercises
|
||||||
|
* tags: [Exercises]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Array of all exercises
|
||||||
|
* type: array
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/exercise'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
exercises.get("/", (req: Request, res: Response) => {
|
exercises.get("/", (req: Request, res: Response) => {
|
||||||
Exercise.findAll({
|
Exercise.findAll({
|
||||||
include: [ ExerciseGroup ]
|
include: [ ExerciseGroup ],
|
||||||
}).then(result => {
|
attributes: {
|
||||||
result.sort((a, b) => {
|
exclude: [ "exerciseGroupId" ]
|
||||||
return (a.dataValues.exerciseGroup.dataValues.groupNr * 10 + a.dataValues.exerciseNr) > (b.dataValues.exerciseGroup.dataValues.groupNr * 10 + b.dataValues.exerciseNr) ? 1 : -1
|
}
|
||||||
})
|
|
||||||
|
|
||||||
res.status(200).json(result)
|
|
||||||
})
|
})
|
||||||
|
.then(result => {
|
||||||
|
result.sort((a, b) => {
|
||||||
|
return (a.dataValues.exerciseGroup.dataValues.groupNr * 10 + a.dataValues.exerciseNr) > (b.dataValues.exerciseGroup.dataValues.groupNr * 10 + b.dataValues.exerciseNr) ? 1 : -1
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json(result)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update state of an Exercise
|
* @swagger
|
||||||
*
|
* /exercises/{groupNr}/{exerciseNr}/{state}:
|
||||||
* @param groupNr Number of exercise group (not ID)
|
* post:
|
||||||
* @param exerciseNr Number of exercise (not ID)
|
* summary: Update an exercise solved state
|
||||||
* @param state New state boolean
|
* tags: [Exercises]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: groupNr
|
||||||
|
* schema:
|
||||||
|
* type: number
|
||||||
|
* required: true
|
||||||
|
* description: Number of exercise group (not ID)
|
||||||
|
* - in: path
|
||||||
|
* name: exerciseNr
|
||||||
|
* schema:
|
||||||
|
* type: number
|
||||||
|
* required: true
|
||||||
|
* description: Number of exercise (not ID)
|
||||||
|
* - in: path
|
||||||
|
* name: state
|
||||||
|
* schema:
|
||||||
|
* type: number
|
||||||
|
* required: true
|
||||||
|
* description: 1 = Solved, 0 = Unsolved
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Edited exercise
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/exercise'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
exercises.post("/:groupNr/:exerciseNr/:state", (req: Request, res: Response) => {
|
exercises.post("/:groupNr/:exerciseNr/:state", (req: Request, res: Response) => {
|
||||||
Exercise.findOne({
|
Exercise.findOne({
|
||||||
@@ -39,7 +94,10 @@ exercises.post("/:groupNr/:exerciseNr/:state", (req: Request, res: Response) =>
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
include: [ ExerciseGroup ]
|
include: [ ExerciseGroup ],
|
||||||
|
attributes: {
|
||||||
|
exclude: [ "exerciseGroupId" ]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.then(async exercise => {
|
.then(async exercise => {
|
||||||
let changed = false
|
let changed = false
|
||||||
@@ -54,21 +112,7 @@ exercises.post("/:groupNr/:exerciseNr/:state", (req: Request, res: Response) =>
|
|||||||
changed: changed
|
changed: changed
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
// ExerciseGroup.findOne({
|
})
|
||||||
// where: { groupNr: req.params.groupNr }
|
|
||||||
// })
|
|
||||||
// .then(group => {
|
|
||||||
// Exercise.findOne({
|
|
||||||
// where: {
|
|
||||||
// exerciseNr: req.params.exerciseNr,
|
|
||||||
// exerciseGroupId: group.id
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .then(exercise => {
|
|
||||||
// exercise.update({ solved: req.params.state == "1"})
|
|
||||||
// res.status(200).send()
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
})
|
})
|
||||||
@@ -1,22 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Files
|
||||||
|
* description: API for handling static files
|
||||||
|
*/
|
||||||
import { Request, Response, NextFunction, Router } from 'express'
|
import { Request, Response, NextFunction, Router } from 'express'
|
||||||
import fs, { createReadStream } from "fs"
|
import fs from "fs"
|
||||||
import multer from "multer"
|
import multer from "multer"
|
||||||
const upload = multer({ dest: './backend/images/' })
|
const upload = multer({ dest: './backend/images/' })
|
||||||
import licenses from "../data/licenses.json"
|
import licenses from "../data/licenses.json"
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
export const files = Router()
|
export const files = Router()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all folders
|
* @swagger
|
||||||
|
* /files/folders:
|
||||||
|
* get:
|
||||||
|
* summary: Get all static folders
|
||||||
|
* tags: [Files]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Login successful
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/folder'
|
||||||
*/
|
*/
|
||||||
files.get("/folders", async (req: Request, res: Response) => {
|
files.get("/folders", async (req: Request, res: Response) => {
|
||||||
let dirNames = fs.readdirSync("./backend/images")
|
let dirNames = fs.readdirSync(path.resolve(__dirname, "../images"))
|
||||||
let result = []
|
let result = []
|
||||||
|
|
||||||
dirNames.forEach(dir => {
|
dirNames.forEach(dir => {
|
||||||
result.push({
|
result.push({
|
||||||
name: dir,
|
name: dir,
|
||||||
nrOfItems: fs.readdirSync("./backend/images/" + dir).length
|
nrOfItems: fs.readdirSync(path.resolve(__dirname, "../images/" + dir)).length
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -25,32 +43,52 @@ files.get("/folders", async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all uploaded file names by folder name
|
* @swagger
|
||||||
*
|
* /files/{folder}:
|
||||||
* @param folder Name of folder on server
|
* get:
|
||||||
|
* summary: Get all files in one folder
|
||||||
|
* tags: [Files]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: folder
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: true
|
||||||
|
* description: Name of folder
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Login successful
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/file'
|
||||||
*/
|
*/
|
||||||
files.get("/:folder", async (req: Request, res: Response) => {
|
files.get("/:folder", async (req: Request, res: Response) => {
|
||||||
let result = []
|
let result = []
|
||||||
let fileNames = fs.readdirSync("./backend/images/" + req.params.folder + "/")
|
let fileNames = fs.readdirSync(path.resolve(__dirname, "../images/" + req.params.folder))
|
||||||
|
|
||||||
fileNames.forEach(file => {
|
try {
|
||||||
let resData = ""
|
fileNames.forEach(file => {
|
||||||
let url = "http://localhost:3000/static/" + req.params.folder + "/" + file
|
let resData = ""
|
||||||
|
let url = "http://localhost:3000/static/" + req.params.folder + "/" + file
|
||||||
|
|
||||||
if (file.endsWith("html") || file.endsWith("js")) {
|
if (file.endsWith("html") || file.endsWith("js")) {
|
||||||
resData = fs.readFileSync("./backend/images/" + req.params.folder + "/" + file, "utf8")
|
resData = fs.readFileSync(path.resolve(__dirname, "../images/" + req.params.folder + "/" + file), "utf8")
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push({
|
result.push({
|
||||||
name: file,
|
name: file,
|
||||||
size: fs.statSync("./backend/images/" + req.params.folder + "/" + file).size,
|
size: fs.statSync(path.resolve(__dirname, "../images/" + req.params.folder + "/" + file)).size,
|
||||||
content: resData,
|
content: resData,
|
||||||
url: url,
|
url: url,
|
||||||
copyright: licenses.find(data => data.image == file)
|
copyright: licenses.find(data => data.image == file)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
res.status(200).json(result)
|
res.status(200).json(result)
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).json(error)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -58,7 +96,5 @@ files.get("/:folder", async (req: Request, res: Response) => {
|
|||||||
* Upload a file
|
* Upload a file
|
||||||
*/
|
*/
|
||||||
files.post("/", upload.single("file"), function (req: Request, res: Response, next: NextFunction) {
|
files.post("/", upload.single("file"), function (req: Request, res: Response, next: NextFunction) {
|
||||||
console.log(req.file)
|
|
||||||
|
|
||||||
res.status(200).send()
|
res.status(200).send()
|
||||||
})
|
})
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Genres
|
||||||
|
* description: API to manage the music genres
|
||||||
|
*/
|
||||||
import { Band } from "../models/acts/band.model";
|
import { Band } from "../models/acts/band.model";
|
||||||
import { Genre } from "../models/acts/genre.model";
|
import { Genre } from "../models/acts/genre.model";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
@@ -5,7 +11,20 @@ import { Request, Response, Router } from "express";
|
|||||||
export const genre = Router()
|
export const genre = Router()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all available Genres
|
* @swagger
|
||||||
|
* /genres:
|
||||||
|
* get:
|
||||||
|
* summary: Get all available genres
|
||||||
|
* tags: [Genres]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/genre'
|
||||||
|
* 500:
|
||||||
|
* description: Internal Server Error
|
||||||
*/
|
*/
|
||||||
genre.get("/", (req: Request, res: Response) => {
|
genre.get("/", (req: Request, res: Response) => {
|
||||||
Genre.findAll({
|
Genre.findAll({
|
||||||
@@ -19,8 +38,22 @@ genre.get("/", (req: Request, res: Response) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a Genre entry
|
* @swagger
|
||||||
|
* /genres:
|
||||||
|
* patch:
|
||||||
|
* summary: Update the dataset of a genre
|
||||||
|
* tags: [Genres]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/genre'
|
||||||
|
* 500:
|
||||||
|
* description: Internal Server Error
|
||||||
*/
|
*/
|
||||||
genre.patch("/", (req: Request, res: Response) => {
|
genre.patch("/", (req: Request, res: Response) => {
|
||||||
Genre.update(req.body, {
|
Genre.update(req.body, {
|
||||||
@@ -36,8 +69,22 @@ genre.patch("/", (req: Request, res: Response) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Genre entry
|
* @swagger
|
||||||
|
* /genres:
|
||||||
|
* post:
|
||||||
|
* summary: Add a new dataset of a genre
|
||||||
|
* tags: [Genres]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/genre'
|
||||||
|
* 500:
|
||||||
|
* description: Internal Server Error
|
||||||
*/
|
*/
|
||||||
genre.post("/", (req: Request, res: Response) => {
|
genre.post("/", (req: Request, res: Response) => {
|
||||||
Genre.create(req.body)
|
Genre.create(req.body)
|
||||||
@@ -49,8 +96,22 @@ genre.post("/", (req: Request, res: Response) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a Genre entry
|
* @swagger
|
||||||
|
* /genres:
|
||||||
|
* delete:
|
||||||
|
* summary: Delete the dataset of a genre
|
||||||
|
* tags: [Genres]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/genre'
|
||||||
|
* 500:
|
||||||
|
* description: Internal Server Error
|
||||||
*/
|
*/
|
||||||
genre.delete("/", (req: Request, res: Response) => {
|
genre.delete("/", (req: Request, res: Response) => {
|
||||||
Genre.destroy({
|
Genre.destroy({
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Locations
|
||||||
|
* description: API to manage the event locations
|
||||||
|
*/
|
||||||
import { Concert } from "../models/acts/concert.model";
|
import { Concert } from "../models/acts/concert.model";
|
||||||
import { City } from "../models/locations/city.model";
|
import { City } from "../models/locations/city.model";
|
||||||
import { Location } from "../models/locations/location.model";
|
import { Location } from "../models/locations/location.model";
|
||||||
@@ -10,24 +16,57 @@ import { Op } from "sequelize";
|
|||||||
|
|
||||||
export const location = Router()
|
export const location = Router()
|
||||||
|
|
||||||
|
// Response include rules
|
||||||
|
const locationStructure = [
|
||||||
|
City,
|
||||||
|
{
|
||||||
|
model: Concert,
|
||||||
|
include: [ Band ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: SeatGroup,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: SeatRow,
|
||||||
|
include: [ Seat ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all available Locations
|
* @swagger
|
||||||
*
|
* /locations:
|
||||||
* @query sort Sort results ascending (asc) or descending (desc)
|
* get:
|
||||||
* @query count Limit number of results
|
* summary: Get all available locations
|
||||||
|
* tags: [Locations]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: sort
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: false
|
||||||
|
* description: Sort locations by number of concerts ascending (asc) or descending (desc)
|
||||||
|
* - in: query
|
||||||
|
* name: count
|
||||||
|
* schema:
|
||||||
|
* type: number
|
||||||
|
* required: false
|
||||||
|
* description: Limit number of results
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/location'
|
||||||
*/
|
*/
|
||||||
location.get("/", (req: Request, res: Response) => {
|
location.get("/", (req: Request, res: Response) => {
|
||||||
let sort = req.query.sort
|
let sort = req.query.sort
|
||||||
let count = req.query.count
|
let count = req.query.count
|
||||||
|
|
||||||
Location.findAll({
|
Location.findAll({
|
||||||
include: [
|
include: locationStructure,
|
||||||
City,
|
|
||||||
{
|
|
||||||
model: Concert,
|
|
||||||
include: [ Band ],
|
|
||||||
}
|
|
||||||
],
|
|
||||||
attributes: {
|
attributes: {
|
||||||
exclude: [ "cityId" ]
|
exclude: [ "cityId" ]
|
||||||
}
|
}
|
||||||
@@ -60,29 +99,32 @@ location.get("/", (req: Request, res: Response) => {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all data about a specific location
|
* @swagger
|
||||||
*
|
* /locations/{urlName}:
|
||||||
* @param urlName UrlName of the band (e.g. Red Hot Chili Peppers => red-hot-chili-peppers)
|
* get:
|
||||||
|
* summary: Download all available informations about a specific locations
|
||||||
|
* tags: [Locations]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: urlName
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: true
|
||||||
|
* description: Url name of the location to request for
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Single of location objects
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/location'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
location.get("/location/:urlName", (req: Request, res: Response) => {
|
location.get("/location/:urlName", (req: Request, res: Response) => {
|
||||||
Location.findOne({
|
Location.findOne({
|
||||||
where: { urlName: req.params.urlName },
|
where: { urlName: req.params.urlName },
|
||||||
include: [
|
include: locationStructure,
|
||||||
City,
|
|
||||||
{
|
|
||||||
model: Concert,
|
|
||||||
include: [ Band ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: SeatGroup,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: SeatRow,
|
|
||||||
include: [ Seat ]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
attributes: {
|
attributes: {
|
||||||
exclude: [ "cityId" ]
|
exclude: [ "cityId" ]
|
||||||
}
|
}
|
||||||
@@ -98,16 +140,34 @@ location.get("/location/:urlName", (req: Request, res: Response) => {
|
|||||||
|
|
||||||
res.status(200).json(location)
|
res.status(200).json(location)
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(error => {
|
||||||
res.status(404).send()
|
res.status(404).send()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for Locations
|
* @swagger
|
||||||
*
|
* /locations/search:
|
||||||
* @query value Search term to look for
|
* get:
|
||||||
|
* summary: Search for locations
|
||||||
|
* tags: [Locations]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: value
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: true
|
||||||
|
* description: Search term
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: List of band objects
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/location'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
location.get("/search", (req: Request, res: Response) => {
|
location.get("/search", (req: Request, res: Response) => {
|
||||||
Location.findAll({
|
Location.findAll({
|
||||||
@@ -128,9 +188,12 @@ location.get("/search", (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
include: [ City, Concert ]
|
include: locationStructure
|
||||||
})
|
})
|
||||||
.then(locations => {
|
.then(locations => {
|
||||||
res.status(200).json(locations)
|
res.status(200).json(locations)
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Orders
|
||||||
|
* description: API to manage orders
|
||||||
|
*/
|
||||||
import { Router, Request, Response } from "express";
|
import { Router, Request, Response } from "express";
|
||||||
import { Order } from "../models/ordering/order.model";
|
import { Order } from "../models/ordering/order.model";
|
||||||
import { Concert } from "../models/acts/concert.model";
|
import { Concert } from "../models/acts/concert.model";
|
||||||
@@ -10,17 +16,41 @@ import { City } from "../models/locations/city.model";
|
|||||||
import { Seat } from "../models/locations/seat.model";
|
import { Seat } from "../models/locations/seat.model";
|
||||||
import { SeatRow } from "../models/locations/seatRow.model";
|
import { SeatRow } from "../models/locations/seatRow.model";
|
||||||
import { SeatGroup } from "../models/locations/seatGroup.model";
|
import { SeatGroup } from "../models/locations/seatGroup.model";
|
||||||
|
import { verifyToken } from "../middlewares/auth.middleware";
|
||||||
import { Account } from "../models/user/account.model";
|
import { Account } from "../models/user/account.model";
|
||||||
import { Exercise } from "backend/models/exercises/exercise.model";
|
|
||||||
|
|
||||||
export const order = Router()
|
export const order = Router()
|
||||||
|
|
||||||
// Get all orders
|
/**
|
||||||
order.get("/", (req: Request, res: Response) => {
|
* @swagger
|
||||||
|
* /orders:
|
||||||
|
* get:
|
||||||
|
* summary: Get orders of an account or all available
|
||||||
|
* tags: [Orders]
|
||||||
|
* security:
|
||||||
|
* - JWT: []
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: id
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: false
|
||||||
|
* description: User account id to filter the orders
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/order'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
|
order.get("/", verifyToken, (req: Request, res: Response) => {
|
||||||
|
const accountId = req.query.id
|
||||||
|
|
||||||
Order.findAll({
|
Order.findAll({
|
||||||
include: [
|
include: [
|
||||||
Account,
|
|
||||||
Address,
|
|
||||||
{
|
{
|
||||||
model: Ticket,
|
model: Ticket,
|
||||||
include: [
|
include: [
|
||||||
@@ -35,42 +65,6 @@ order.get("/", (req: Request, res: Response) => {
|
|||||||
include: [ City ]
|
include: [ City ]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.then(orders => {
|
|
||||||
res.status(200).json(orders)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
// Get all orders of one account by it's user id
|
|
||||||
order.get("/:id", (req: Request, res: Response) => {
|
|
||||||
Order.findAll({
|
|
||||||
where: { accountId: req.params.id },
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Ticket,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Concert,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Band
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: Location,
|
|
||||||
include: [ City ]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
attributes: {
|
|
||||||
exclude: [
|
|
||||||
"categoryId",
|
|
||||||
"brandId"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: Seat,
|
model: Seat,
|
||||||
@@ -83,17 +77,58 @@ order.get("/:id", (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
Address,
|
||||||
Payment,
|
Payment,
|
||||||
Address
|
Account,
|
||||||
]
|
],
|
||||||
|
attributes: {
|
||||||
|
exclude: [ "accountId", "addressId", "paymentId" ]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.then(orders => {
|
.then(orders => {
|
||||||
res.status(200).json(orders)
|
if (accountId != undefined) {
|
||||||
|
let filteredOrders = orders.filter(order => {
|
||||||
|
return order.id == accountId
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json(filteredOrders)
|
||||||
|
} else {
|
||||||
|
res.status(200).json(orders)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Place a new order
|
/**
|
||||||
order.post("/", (req: Request, res: Response) => {
|
* @swagger
|
||||||
|
* /orders:
|
||||||
|
* post:
|
||||||
|
* summary: Place a new order
|
||||||
|
* tags: [Orders]
|
||||||
|
* security:
|
||||||
|
* - JWT: []
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: id
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: false
|
||||||
|
* description: User account id to filter the orders
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/order'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
|
order.post("/", verifyToken, (req: Request, res: Response) => {
|
||||||
|
req.body["accountId"] = req["id"]
|
||||||
|
|
||||||
Order.create(req.body)
|
Order.create(req.body)
|
||||||
.then(async order => {
|
.then(async order => {
|
||||||
for (let ticket of req.body.tickets) {
|
for (let ticket of req.body.tickets) {
|
||||||
@@ -116,4 +151,45 @@ order.post("/", (req: Request, res: Response) => {
|
|||||||
// Created
|
// Created
|
||||||
res.status(201).json(order)
|
res.status(201).json(order)
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /orders:
|
||||||
|
* patch:
|
||||||
|
* summary: Update an order
|
||||||
|
* tags: [Orders]
|
||||||
|
* parameters:
|
||||||
|
* - in: body
|
||||||
|
* name: order
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required: true
|
||||||
|
* description: Updated order object
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/order'
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
|
order.patch("/", (req: Request, res: Response) => {
|
||||||
|
Order.update(req.body, {
|
||||||
|
where: {
|
||||||
|
id: req.body.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(affectedCount => {
|
||||||
|
res.status(200).send()
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import cors from 'cors'
|
import cors from 'cors'
|
||||||
import bodyParser from 'body-parser'
|
import bodyParser from 'body-parser'
|
||||||
|
import swaggerJsdoc from "swagger-jsdoc"
|
||||||
|
import swaggerUi from "swagger-ui-express"
|
||||||
import { api } from './routes/api.routes'
|
import { api } from './routes/api.routes'
|
||||||
import { startDatabase } from './database'
|
import { startDatabase } from './database'
|
||||||
import { order } from './routes/order.routes'
|
import { order } from './routes/order.routes'
|
||||||
@@ -12,6 +14,7 @@ import { location } from './routes/location.routes'
|
|||||||
import { city } from './routes/city.routes'
|
import { city } from './routes/city.routes'
|
||||||
import { exercises } from './routes/exercise.routes'
|
import { exercises } from './routes/exercise.routes'
|
||||||
import { files } from './routes/files.routes'
|
import { files } from './routes/files.routes'
|
||||||
|
import swaggerFile from './swagger.json'
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
const port = 3000
|
const port = 3000
|
||||||
@@ -46,6 +49,17 @@ app.use("/accounts", account)
|
|||||||
app.use("/cities", city)
|
app.use("/cities", city)
|
||||||
app.use("/concerts", concert)
|
app.use("/concerts", concert)
|
||||||
|
|
||||||
|
|
||||||
|
// Swagger API documentation
|
||||||
|
const specs = swaggerJsdoc(swaggerFile);
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
"/api-docs",
|
||||||
|
swaggerUi.serve,
|
||||||
|
swaggerUi.setup(specs, { explorer: true })
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
const server = app.listen(port, () => {
|
const server = app.listen(port, () => {
|
||||||
console.log(`Server is running and listening to port ${port}`)
|
console.log(`Server is running and listening to port ${port}`)
|
||||||
|
|||||||
796
backend/swagger.json
Normal file
796
backend/swagger.json
Normal file
@@ -0,0 +1,796 @@
|
|||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"definition": {
|
||||||
|
"openapi": "3.1.0",
|
||||||
|
"info": {
|
||||||
|
"title": "EventMaster API",
|
||||||
|
"version": "0.2.0",
|
||||||
|
"description": "Dokumentation über alle API-Endpunkte des Backends",
|
||||||
|
"license": {
|
||||||
|
"name": "MIT",
|
||||||
|
"url": "https://spdx.org/licenses/MIT.html"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"components": {
|
||||||
|
"securitySchemes": {
|
||||||
|
"JWT": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"in": "header",
|
||||||
|
"name": "Json Web Token"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {
|
||||||
|
"city": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "The auto-generated id"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of the city"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of country of the city"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Hannover",
|
||||||
|
"country": "Germany"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"loginResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"success": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Login successful state"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Individual created access token"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"success": true,
|
||||||
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjI2MiwiaWF0IjoxNzMzNzYwOTY3fQ.I3rR71c-k2Y2WB0dkd1QEgHxsIRGl4s69YprBNuhX7w"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimalAccount": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"username": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Account username"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Encrypted password"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "E-Mail address of user"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"username": "maxmustermann",
|
||||||
|
"password": "supersecret",
|
||||||
|
"email": "tijjji@didjhli.de"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimalAccountResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "The auto-generated id"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Account username"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Encrypted password"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "E-Mail address of user"
|
||||||
|
},
|
||||||
|
"accountRoleId": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "ID of account role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"id": 263,
|
||||||
|
"username": "maxmustermann",
|
||||||
|
"password": "8746fb88adbae61ffa68193ee0bb8050",
|
||||||
|
"email": "tijjji@didjhli.de",
|
||||||
|
"accountRoleId": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"placeOrderBody": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"username": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Account username"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Encrypted password"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "E-Mail address of user"
|
||||||
|
},
|
||||||
|
"accountRoleId": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "ID of account role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"id": 263,
|
||||||
|
"username": "maxmustermann",
|
||||||
|
"password": "8746fb88adbae61ffa68193ee0bb8050",
|
||||||
|
"email": "tijjji@didjhli.de",
|
||||||
|
"accountRoleId": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"genre": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "The auto-generated id"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of the genre"
|
||||||
|
},
|
||||||
|
"bands": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Bands with this genre object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": [
|
||||||
|
{
|
||||||
|
"id": 562,
|
||||||
|
"name": "Funk Rock",
|
||||||
|
"bands": [
|
||||||
|
{
|
||||||
|
"images": [
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-1.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-2.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-3.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-4.jpg"
|
||||||
|
],
|
||||||
|
"id": 265,
|
||||||
|
"name": "Red Hot Chili Peppers",
|
||||||
|
"foundingYear": 1983,
|
||||||
|
"descriptionEn": "The Red Hot Chili Peppers are an American rock band formed in Los Angeles in 1983, comprising vocalist Anthony Kiedis, bassist Flea, drummer Chad Smith, and guitarist John Frusciante. Their music incorporates elements of alternative rock, funk, punk rock, hard rock, hip hop, and psychedelic rock. Their eclectic range has influenced genres such as funk metal, rap metal, rap rock, and nu metal. With over 120 million records sold worldwide, the Red Hot Chili Peppers are one of the top-selling bands of all time.",
|
||||||
|
"descriptionDe": "Red Hot Chili Peppers (Abkürzung: RHCP) ist eine 1983 gegründete US-amerikanische Funk- und Alternative-Rockband. Sie zählt zu den kommerziell erfolgreichsten Vertretern des Crossover. Ihr Album Blood Sugar Sex Magik gilt als eines der bedeutendsten dieses Genres.",
|
||||||
|
"imageMembers": "http://localhost:3000/static/bands/red-hot-chili-peppers-members.jpg",
|
||||||
|
"logo": "http://localhost:3000/static/bands/red-hot-chili-peppers-logo.png",
|
||||||
|
"BandGenre": {
|
||||||
|
"id": 793,
|
||||||
|
"genreId": 562,
|
||||||
|
"bandId": 265
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 563,
|
||||||
|
"name": "Alternative Rock",
|
||||||
|
"bands": [
|
||||||
|
{
|
||||||
|
"images": [
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-1.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-2.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-3.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-4.jpg"
|
||||||
|
],
|
||||||
|
"id": 265,
|
||||||
|
"name": "Red Hot Chili Peppers",
|
||||||
|
"foundingYear": 1983,
|
||||||
|
"descriptionEn": "The Red Hot Chili Peppers are an American rock band formed in Los Angeles in 1983, comprising vocalist Anthony Kiedis, bassist Flea, drummer Chad Smith, and guitarist John Frusciante. Their music incorporates elements of alternative rock, funk, punk rock, hard rock, hip hop, and psychedelic rock. Their eclectic range has influenced genres such as funk metal, rap metal, rap rock, and nu metal. With over 120 million records sold worldwide, the Red Hot Chili Peppers are one of the top-selling bands of all time.",
|
||||||
|
"descriptionDe": "Red Hot Chili Peppers (Abkürzung: RHCP) ist eine 1983 gegründete US-amerikanische Funk- und Alternative-Rockband. Sie zählt zu den kommerziell erfolgreichsten Vertretern des Crossover. Ihr Album Blood Sugar Sex Magik gilt als eines der bedeutendsten dieses Genres.",
|
||||||
|
"imageMembers": "http://localhost:3000/static/bands/red-hot-chili-peppers-members.jpg",
|
||||||
|
"logo": "http://localhost:3000/static/bands/red-hot-chili-peppers-logo.png",
|
||||||
|
"BandGenre": {
|
||||||
|
"id": 794,
|
||||||
|
"genreId": 563,
|
||||||
|
"bandId": 265
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "The auto-generated id"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of the genre"
|
||||||
|
},
|
||||||
|
"bands": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Bands with this genre object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"id": 562,
|
||||||
|
"name": "Funk Rock",
|
||||||
|
"bands": [
|
||||||
|
{
|
||||||
|
"images": [
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-1.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-2.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-3.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-4.jpg"
|
||||||
|
],
|
||||||
|
"id": 265,
|
||||||
|
"name": "Red Hot Chili Peppers",
|
||||||
|
"foundingYear": 1983,
|
||||||
|
"descriptionEn": "The Red Hot Chili Peppers are an American rock band formed in Los Angeles in 1983, comprising vocalist Anthony Kiedis, bassist Flea, drummer Chad Smith, and guitarist John Frusciante. Their music incorporates elements of alternative rock, funk, punk rock, hard rock, hip hop, and psychedelic rock. Their eclectic range has influenced genres such as funk metal, rap metal, rap rock, and nu metal. With over 120 million records sold worldwide, the Red Hot Chili Peppers are one of the top-selling bands of all time.",
|
||||||
|
"descriptionDe": "Red Hot Chili Peppers (Abkürzung: RHCP) ist eine 1983 gegründete US-amerikanische Funk- und Alternative-Rockband. Sie zählt zu den kommerziell erfolgreichsten Vertretern des Crossover. Ihr Album Blood Sugar Sex Magik gilt als eines der bedeutendsten dieses Genres.",
|
||||||
|
"imageMembers": "http://localhost:3000/static/bands/red-hot-chili-peppers-members.jpg",
|
||||||
|
"logo": "http://localhost:3000/static/bands/red-hot-chili-peppers-logo.png",
|
||||||
|
"BandGenre": {
|
||||||
|
"id": 793,
|
||||||
|
"genreId": 562,
|
||||||
|
"bandId": 265
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "The auto-generated id"
|
||||||
|
},
|
||||||
|
"orderedAt": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Timestamp of order"
|
||||||
|
},
|
||||||
|
"tickets": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Array of Ticket objects"
|
||||||
|
},
|
||||||
|
"addresses": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Address object"
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Payment object"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Account object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"id": 112,
|
||||||
|
"orderedAt": "2024-11-29T12:38:36.381Z",
|
||||||
|
"shipped": false,
|
||||||
|
"tickets": [
|
||||||
|
{
|
||||||
|
"id": 144,
|
||||||
|
"orderId": 112,
|
||||||
|
"orderPrice": 184,
|
||||||
|
"concertId": 892,
|
||||||
|
"seatId": 106331,
|
||||||
|
"concert": {
|
||||||
|
"id": 892,
|
||||||
|
"date": "2024-11-30",
|
||||||
|
"name": "Unlimited Love",
|
||||||
|
"price": 92,
|
||||||
|
"image": "http://localhost:3000/static/concerts/unlimited-love-tour.jpg",
|
||||||
|
"inStock": 170,
|
||||||
|
"offered": true,
|
||||||
|
"bandId": 265,
|
||||||
|
"locationId": 834,
|
||||||
|
"band": {
|
||||||
|
"images": [
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-1.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-2.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-3.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-4.jpg"
|
||||||
|
],
|
||||||
|
"id": 265,
|
||||||
|
"name": "Red Hot Chili Peppers",
|
||||||
|
"foundingYear": 1983,
|
||||||
|
"descriptionEn": "The Red Hot Chili Peppers are an American rock band formed in Los Angeles in 1983, comprising vocalist Anthony Kiedis, bassist Flea, drummer Chad Smith, and guitarist John Frusciante. Their music incorporates elements of alternative rock, funk, punk rock, hard rock, hip hop, and psychedelic rock. Their eclectic range has influenced genres such as funk metal, rap metal, rap rock, and nu metal. With over 120 million records sold worldwide, the Red Hot Chili Peppers are one of the top-selling bands of all time.",
|
||||||
|
"descriptionDe": "Red Hot Chili Peppers (Abkürzung: RHCP) ist eine 1983 gegründete US-amerikanische Funk- und Alternative-Rockband. Sie zählt zu den kommerziell erfolgreichsten Vertretern des Crossover. Ihr Album Blood Sugar Sex Magik gilt als eines der bedeutendsten dieses Genres.",
|
||||||
|
"imageMembers": "http://localhost:3000/static/bands/red-hot-chili-peppers-members.jpg",
|
||||||
|
"logo": "http://localhost:3000/static/bands/red-hot-chili-peppers-logo.png"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"id": 834,
|
||||||
|
"urlName": "swiss-life-hall",
|
||||||
|
"name": "Swiss Life Hall",
|
||||||
|
"address": "Ferdinand-Wilhelm-Fricke-Weg 8",
|
||||||
|
"cityId": 246,
|
||||||
|
"imageIndoor": "http://localhost:3000/static/locations/swiss-life-hall-indoor.jpg",
|
||||||
|
"imageOutdoor": "http://localhost:3000/static/locations/swiss-life-hall-outdoor.jpg",
|
||||||
|
"layout": 2,
|
||||||
|
"capacity": 180,
|
||||||
|
"city": {
|
||||||
|
"id": 246,
|
||||||
|
"name": "Hannover",
|
||||||
|
"country": "Germany"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seat": {
|
||||||
|
"id": 106331,
|
||||||
|
"seatNr": 1,
|
||||||
|
"seatRowId": 14701,
|
||||||
|
"seatRow": {
|
||||||
|
"id": 14701,
|
||||||
|
"row": 0,
|
||||||
|
"seatGroupId": 3872,
|
||||||
|
"seatGroup": {
|
||||||
|
"id": 3872,
|
||||||
|
"name": "A",
|
||||||
|
"surcharge": 30,
|
||||||
|
"capacity": 40,
|
||||||
|
"standingArea": true,
|
||||||
|
"locationId": 834
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"address": {
|
||||||
|
"id": 342,
|
||||||
|
"accountId": 255,
|
||||||
|
"street": "Laportestraße",
|
||||||
|
"houseNumber": 22,
|
||||||
|
"postalCode": 30449,
|
||||||
|
"city": "Hannover"
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"id": 247,
|
||||||
|
"accountId": 255,
|
||||||
|
"bankName": "Deutsche Bank",
|
||||||
|
"iban": "DE92500105175721645777"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"id": 255,
|
||||||
|
"username": "hagemeister93",
|
||||||
|
"password": "e1e3981e5b0c009c018c5726a4be5eee",
|
||||||
|
"email": "hagemeister93@gmail.com",
|
||||||
|
"firstName": "Laurin",
|
||||||
|
"lastName": "Hagemeister",
|
||||||
|
"accountRoleId": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"useraccount": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "The auto-generated id"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Account username"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Encrypted password"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "E-Mail address of user"
|
||||||
|
},
|
||||||
|
"firstName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "First name of user"
|
||||||
|
},
|
||||||
|
"lastName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Last name of user"
|
||||||
|
},
|
||||||
|
"addresses": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Array of Address objects"
|
||||||
|
},
|
||||||
|
"accountRole": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Account role object"
|
||||||
|
},
|
||||||
|
"payments": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Array of Payments objects"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"id": 262,
|
||||||
|
"username": "max",
|
||||||
|
"password": "06f7a5f329fed099ad36026f9623e6ce",
|
||||||
|
"email": "titi@didi.de",
|
||||||
|
"firstName": "Max",
|
||||||
|
"lastName": "Mustermann",
|
||||||
|
"accountRoleId": 1,
|
||||||
|
"addresses": [
|
||||||
|
{
|
||||||
|
"id": 352,
|
||||||
|
"accountId": 262,
|
||||||
|
"street": "Musterstraße",
|
||||||
|
"houseNumber": 21,
|
||||||
|
"postalCode": 30167,
|
||||||
|
"city": "Hannover"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accountRole": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "User",
|
||||||
|
"privilegeBuy": true,
|
||||||
|
"privilegeAdminPanel": false
|
||||||
|
},
|
||||||
|
"payments": [
|
||||||
|
{
|
||||||
|
"id": 254,
|
||||||
|
"accountId": 262,
|
||||||
|
"bankName": "Deutsche Bank",
|
||||||
|
"iban": "DE293948484738383829"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exercise": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "The auto-generated id"
|
||||||
|
},
|
||||||
|
"nameDe": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "German exercise name"
|
||||||
|
},
|
||||||
|
"nameEn": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "English exercise name"
|
||||||
|
},
|
||||||
|
"exerciseNr": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Number of exercise in group"
|
||||||
|
},
|
||||||
|
"descriptionDe": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "German description text"
|
||||||
|
},
|
||||||
|
"descriptionEn": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "English description text"
|
||||||
|
},
|
||||||
|
"solved": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "State of solved"
|
||||||
|
},
|
||||||
|
"exerciseGroup": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Exercise group object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"id": 350,
|
||||||
|
"nameDe": "Registrieren",
|
||||||
|
"nameEn": "Register",
|
||||||
|
"exerciseNr": 1,
|
||||||
|
"descriptionDe": "Wir richten uns einen gewöhnlichen Account auf der Plattform ein. Navigiere hierzu auf die Account-Seite und registriere dich.",
|
||||||
|
"descriptionEn": "Create a new account in the online shop",
|
||||||
|
"solved": true,
|
||||||
|
"exerciseGroup": {
|
||||||
|
"id": 113,
|
||||||
|
"nameDe": "Den Shop kennenlernen",
|
||||||
|
"nameEn": "Getting to know the shop",
|
||||||
|
"groupNr": 0,
|
||||||
|
"descriptionDe": "Vor einem Angriff ist es wichtig zu verstehen, wie die Webseite aufgebaut ist. Wie sind die URLs strukturiert? Wo befinden sich Eingabefelder welche im Backend eine SQL Abfrage stellen?",
|
||||||
|
"descriptionEn": "todo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"folder": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of folder"
|
||||||
|
},
|
||||||
|
"nrOrItems": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Number of files in folder"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"name": "artists",
|
||||||
|
"description": 41
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of file"
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "File size in Bytes"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Text content, only for Text/Code files"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Resource URL"
|
||||||
|
},
|
||||||
|
"copyright": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Copyright object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"name": "alex-turner.jpg",
|
||||||
|
"size": 551625,
|
||||||
|
"content": "",
|
||||||
|
"url": "http://localhost:3000/static/artists/alex-turner.jpg",
|
||||||
|
"copyright": {
|
||||||
|
"image": "alex-turner.jpg",
|
||||||
|
"license": "CC BY 2.0",
|
||||||
|
"creator": "Raph_PH",
|
||||||
|
"url": "https://upload.wikimedia.org/wikipedia/commons/9/95/Alex_Turner%2C_Way_Out_West_2018.jpg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"concert": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "The auto-generated id"
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Date of the concert"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of concert"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Lowest price of concert"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Concert image"
|
||||||
|
},
|
||||||
|
"inStock": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Amount of available tickets"
|
||||||
|
},
|
||||||
|
"offered": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Display concert in UI"
|
||||||
|
},
|
||||||
|
"band": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Band object"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Location object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": [
|
||||||
|
{
|
||||||
|
"id": 892,
|
||||||
|
"date": "2024-11-30",
|
||||||
|
"name": "Unlimited Love",
|
||||||
|
"price": 92,
|
||||||
|
"image": "http://localhost:3000/static/concerts/unlimited-love-tour.jpg",
|
||||||
|
"inStock": 169,
|
||||||
|
"offered": true,
|
||||||
|
"bandId": 265,
|
||||||
|
"locationId": 834,
|
||||||
|
"band": {
|
||||||
|
"images": [
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-1.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-2.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-3.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-4.jpg"
|
||||||
|
],
|
||||||
|
"id": 265,
|
||||||
|
"name": "Red Hot Chili Peppers",
|
||||||
|
"foundingYear": 1983,
|
||||||
|
"descriptionEn": "The Red Hot Chili Peppers are an American rock band formed in Los Angeles in 1983, comprising vocalist Anthony Kiedis, bassist Flea, drummer Chad Smith, and guitarist John Frusciante. Their music incorporates elements of alternative rock, funk, punk rock, hard rock, hip hop, and psychedelic rock. Their eclectic range has influenced genres such as funk metal, rap metal, rap rock, and nu metal. With over 120 million records sold worldwide, the Red Hot Chili Peppers are one of the top-selling bands of all time.",
|
||||||
|
"descriptionDe": "Red Hot Chili Peppers (Abkürzung: RHCP) ist eine 1983 gegründete US-amerikanische Funk- und Alternative-Rockband. Sie zählt zu den kommerziell erfolgreichsten Vertretern des Crossover. Ihr Album Blood Sugar Sex Magik gilt als eines der bedeutendsten dieses Genres.",
|
||||||
|
"imageMembers": "http://localhost:3000/static/bands/red-hot-chili-peppers-members.jpg",
|
||||||
|
"logo": "http://localhost:3000/static/bands/red-hot-chili-peppers-logo.png"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"id": 834,
|
||||||
|
"urlName": "swiss-life-hall",
|
||||||
|
"name": "Swiss Life Hall",
|
||||||
|
"address": "Ferdinand-Wilhelm-Fricke-Weg 8",
|
||||||
|
"imageIndoor": "http://localhost:3000/static/locations/swiss-life-hall-indoor.jpg",
|
||||||
|
"imageOutdoor": "http://localhost:3000/static/locations/swiss-life-hall-outdoor.jpg",
|
||||||
|
"layout": 2,
|
||||||
|
"capacity": 180,
|
||||||
|
"city": {
|
||||||
|
"id": 246,
|
||||||
|
"name": "Hannover",
|
||||||
|
"country": "Germany"
|
||||||
|
},
|
||||||
|
"seatGroups": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"band": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "The auto-generated id"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of the band"
|
||||||
|
},
|
||||||
|
"foundingYear": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Founding year of the band"
|
||||||
|
},
|
||||||
|
"descriptionEn": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "English description text"
|
||||||
|
},
|
||||||
|
"descriptionDe": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "German description text"
|
||||||
|
},
|
||||||
|
"imageMembers": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "URL to image of band members"
|
||||||
|
},
|
||||||
|
"logo": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "URL to image of band logo"
|
||||||
|
},
|
||||||
|
"genres": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Array of Genre objects which fits the bands music"
|
||||||
|
},
|
||||||
|
"concerts": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Array of Concert objects"
|
||||||
|
},
|
||||||
|
"nrOfConcerts": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Number of concerts"
|
||||||
|
},
|
||||||
|
"rating": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Average rating of the band"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"images": [
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-1.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-2.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-3.jpg",
|
||||||
|
"http://localhost:3000/static/bands/red-hot-chili-peppers-4.jpg"
|
||||||
|
],
|
||||||
|
"id": 265,
|
||||||
|
"name": "Red Hot Chili Peppers",
|
||||||
|
"foundingYear": 1983,
|
||||||
|
"descriptionEn": "The Red Hot Chili Peppers are an American rock band formed in Los Angeles in 1983, comprising vocalist Anthony Kiedis, bassist Flea, drummer Chad Smith, and guitarist John Frusciante. Their music incorporates elements of alternative rock, funk, punk rock, hard rock, hip hop, and psychedelic rock. Their eclectic range has influenced genres such as funk metal, rap metal, rap rock, and nu metal. With over 120 million records sold worldwide, the Red Hot Chili Peppers are one of the top-selling bands of all time.",
|
||||||
|
"descriptionDe": "Red Hot Chili Peppers (Abkürzung: RHCP) ist eine 1983 gegründete US-amerikanische Funk- und Alternative-Rockband. Sie zählt zu den kommerziell erfolgreichsten Vertretern des Crossover. Ihr Album Blood Sugar Sex Magik gilt als eines der bedeutendsten dieses Genres.",
|
||||||
|
"imageMembers": "http://localhost:3000/static/bands/red-hot-chili-peppers-members.jpg",
|
||||||
|
"logo": "http://localhost:3000/static/bands/red-hot-chili-peppers-logo.png",
|
||||||
|
"genres": [
|
||||||
|
{
|
||||||
|
"name": "Funk Rock"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Alternative Rock"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Crossover"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"concerts": [
|
||||||
|
{
|
||||||
|
"id": 892,
|
||||||
|
"date": "2024-11-30",
|
||||||
|
"name": "Unlimited Love",
|
||||||
|
"price": 92,
|
||||||
|
"image": "http://localhost:3000/static/concerts/unlimited-love-tour.jpg",
|
||||||
|
"inStock": 170,
|
||||||
|
"offered": true,
|
||||||
|
"bandId": 265,
|
||||||
|
"locationId": 834
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 893,
|
||||||
|
"date": "2024-12-07",
|
||||||
|
"name": "Unlimited Love",
|
||||||
|
"price": 92,
|
||||||
|
"image": "http://localhost:3000/static/concerts/unlimited-love-tour.jpg",
|
||||||
|
"inStock": 170,
|
||||||
|
"offered": true,
|
||||||
|
"bandId": 265,
|
||||||
|
"locationId": 834
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 894,
|
||||||
|
"date": "2024-12-11",
|
||||||
|
"name": "Unlimited Love",
|
||||||
|
"price": 119.9,
|
||||||
|
"image": "http://localhost:3000/static/concerts/unlimited-love-tour.jpg",
|
||||||
|
"inStock": 8736,
|
||||||
|
"offered": true,
|
||||||
|
"bandId": 265,
|
||||||
|
"locationId": 838
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 895,
|
||||||
|
"date": "2024-12-18",
|
||||||
|
"name": "Unlimited Love",
|
||||||
|
"price": 114.9,
|
||||||
|
"image": "http://localhost:3000/static/concerts/unlimited-love-tour.jpg",
|
||||||
|
"inStock": 2793,
|
||||||
|
"offered": true,
|
||||||
|
"bandId": 265,
|
||||||
|
"locationId": 842
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 896,
|
||||||
|
"date": "2024-12-30",
|
||||||
|
"name": "Unlimited Love",
|
||||||
|
"price": 124.9,
|
||||||
|
"image": "http://localhost:3000/static/concerts/unlimited-love-tour.jpg",
|
||||||
|
"inStock": 3079,
|
||||||
|
"offered": true,
|
||||||
|
"bandId": 265,
|
||||||
|
"locationId": 845
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nrOfConcerts": 5,
|
||||||
|
"rating": 4.428571428571429
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apis": [
|
||||||
|
"./backend/routes/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
1481
misc/database.drawio
1481
misc/database.drawio
File diff suppressed because it is too large
Load Diff
309
package-lock.json
generated
309
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "eventmaster",
|
"name": "eventmaster",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "eventmaster",
|
"name": "eventmaster",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdi/font": "^7.4.47",
|
"@mdi/font": "^7.4.47",
|
||||||
@@ -29,6 +29,9 @@
|
|||||||
"sequelize": "^6.37.4",
|
"sequelize": "^6.37.4",
|
||||||
"sequelize-typescript": "^2.1.6",
|
"sequelize-typescript": "^2.1.6",
|
||||||
"sqlite3": "^5.1.7",
|
"sqlite3": "^5.1.7",
|
||||||
|
"swagger-autogen": "^2.23.7",
|
||||||
|
"swagger-jsdoc": "^6.2.8",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"vue": "^3.4.29",
|
"vue": "^3.4.29",
|
||||||
"vue-i18n": "^10.0.4",
|
"vue-i18n": "^10.0.4",
|
||||||
"vue-router": "^4.4.5",
|
"vue-router": "^4.4.5",
|
||||||
@@ -44,6 +47,8 @@
|
|||||||
"@types/jsonwebtoken": "^9.0.7",
|
"@types/jsonwebtoken": "^9.0.7",
|
||||||
"@types/multer": "^1.4.12",
|
"@types/multer": "^1.4.12",
|
||||||
"@types/node": "^22.9.0",
|
"@types/node": "^22.9.0",
|
||||||
|
"@types/swagger-jsdoc": "^6.0.4",
|
||||||
|
"@types/swagger-ui-express": "^4.1.7",
|
||||||
"@vitejs/plugin-vue": "^5.1.4",
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
@@ -56,6 +61,50 @@
|
|||||||
"vue-tsc": "^2.1.10"
|
"vue-tsc": "^2.1.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@apidevtools/json-schema-ref-parser": {
|
||||||
|
"version": "9.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
|
||||||
|
"integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jsdevtools/ono": "^7.1.3",
|
||||||
|
"@types/json-schema": "^7.0.6",
|
||||||
|
"call-me-maybe": "^1.0.1",
|
||||||
|
"js-yaml": "^4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@apidevtools/openapi-schemas": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@apidevtools/swagger-methods": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@apidevtools/swagger-parser": {
|
||||||
|
"version": "10.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz",
|
||||||
|
"integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@apidevtools/json-schema-ref-parser": "^9.0.6",
|
||||||
|
"@apidevtools/openapi-schemas": "^2.0.4",
|
||||||
|
"@apidevtools/swagger-methods": "^3.0.2",
|
||||||
|
"@jsdevtools/ono": "^7.1.3",
|
||||||
|
"call-me-maybe": "^1.0.1",
|
||||||
|
"z-schema": "^5.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"openapi-types": ">=7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.25.7",
|
"version": "7.25.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz",
|
||||||
@@ -1546,6 +1595,12 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@jsdevtools/ono": {
|
||||||
|
"version": "7.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
|
||||||
|
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@malept/cross-spawn-promise": {
|
"node_modules/@malept/cross-spawn-promise": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz",
|
||||||
@@ -1933,6 +1988,13 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@scarf/scarf": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/@sideway/address": {
|
"node_modules/@sideway/address": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
|
||||||
@@ -2138,6 +2200,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/json-schema": {
|
||||||
|
"version": "7.0.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||||
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/jsonwebtoken": {
|
"node_modules/@types/jsonwebtoken": {
|
||||||
"version": "9.0.7",
|
"version": "9.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz",
|
||||||
@@ -2256,6 +2324,24 @@
|
|||||||
"@types/send": "*"
|
"@types/send": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/swagger-jsdoc": {
|
||||||
|
"version": "6.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz",
|
||||||
|
"integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/swagger-ui-express": {
|
||||||
|
"version": "4.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.7.tgz",
|
||||||
|
"integrity": "sha512-ovLM9dNincXkzH4YwyYpll75vhzPBlWx6La89wwvYH7mHjVpf0X0K/vR/aUM7SRxmr5tt9z7E5XJcjQ46q+S3g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/serve-static": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/validator": {
|
"node_modules/@types/validator": {
|
||||||
"version": "13.12.2",
|
"version": "13.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz",
|
||||||
@@ -3050,7 +3136,6 @@
|
|||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "Python-2.0"
|
"license": "Python-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/array-flatten": {
|
"node_modules/array-flatten": {
|
||||||
@@ -3635,6 +3720,12 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/call-me-maybe": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/canvg": {
|
"node_modules/canvg": {
|
||||||
"version": "3.0.10",
|
"version": "3.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
|
||||||
@@ -4370,6 +4461,15 @@
|
|||||||
"node": ">=4.0.0"
|
"node": ">=4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/deepmerge": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/defaults": {
|
"node_modules/defaults": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
|
||||||
@@ -4598,6 +4698,18 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/doctrine": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"esutils": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dompurify": {
|
"node_modules/dompurify": {
|
||||||
"version": "2.5.7",
|
"version": "2.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.7.tgz",
|
||||||
@@ -5060,6 +5172,15 @@
|
|||||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/esutils": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/etag": {
|
"node_modules/etag": {
|
||||||
"version": "1.8.1",
|
"version": "1.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||||
@@ -5086,9 +5207,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/exifreader/node_modules/@xmldom/xmldom": {
|
"node_modules/exifreader/node_modules/@xmldom/xmldom": {
|
||||||
"version": "0.9.5",
|
"version": "0.9.6",
|
||||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.6.tgz",
|
||||||
"integrity": "sha512-6g1EwSs8cr8JhP1iBxzyVAWM6BIDvx9Y3FZRIQiMDzgG43Pxi8YkWOZ0nQj2NHgNzgXDZbJewFx/n+YAvMZrfg==",
|
"integrity": "sha512-Su4xcxR0CPGwlDHNmVP09fqET9YxbyDXHaSob6JlBH7L6reTYaeim6zbk9o08UarO0L5GTRo3uzl0D+9lSxmvw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -6210,7 +6331,6 @@
|
|||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
@@ -6252,7 +6372,6 @@
|
|||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"json5": "lib/cli.js"
|
"json5": "lib/cli.js"
|
||||||
@@ -6444,6 +6563,12 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.get": {
|
||||||
|
"version": "4.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||||
|
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.includes": {
|
"node_modules/lodash.includes": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||||
@@ -6456,6 +6581,12 @@
|
|||||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.isequal": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.isinteger": {
|
"node_modules/lodash.isinteger": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||||
@@ -6480,6 +6611,12 @@
|
|||||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.mergewith": {
|
||||||
|
"version": "4.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
|
||||||
|
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.once": {
|
"node_modules/lodash.once": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||||
@@ -7229,6 +7366,13 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/openapi-types": {
|
||||||
|
"version": "12.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
|
||||||
|
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/ora": {
|
"node_modules/ora": {
|
||||||
"version": "5.4.1",
|
"version": "5.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
|
||||||
@@ -8816,6 +8960,116 @@
|
|||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/swagger-autogen": {
|
||||||
|
"version": "2.23.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-autogen/-/swagger-autogen-2.23.7.tgz",
|
||||||
|
"integrity": "sha512-vr7uRmuV0DCxWc0wokLJAwX3GwQFJ0jwN+AWk0hKxre2EZwusnkGSGdVFd82u7fQLgwSTnbWkxUL7HXuz5LTZQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^7.4.1",
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"glob": "^7.1.7",
|
||||||
|
"json5": "^2.2.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/swagger-autogen/node_modules/acorn": {
|
||||||
|
"version": "7.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||||
|
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"acorn": "bin/acorn"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/swagger-jsdoc": {
|
||||||
|
"version": "6.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz",
|
||||||
|
"integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "6.2.0",
|
||||||
|
"doctrine": "3.0.0",
|
||||||
|
"glob": "7.1.6",
|
||||||
|
"lodash.mergewith": "^4.6.2",
|
||||||
|
"swagger-parser": "^10.0.3",
|
||||||
|
"yaml": "2.0.0-1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"swagger-jsdoc": "bin/swagger-jsdoc.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/swagger-jsdoc/node_modules/commander": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/swagger-jsdoc/node_modules/glob": {
|
||||||
|
"version": "7.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||||
|
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||||
|
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"fs.realpath": "^1.0.0",
|
||||||
|
"inflight": "^1.0.4",
|
||||||
|
"inherits": "2",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
|
"once": "^1.3.0",
|
||||||
|
"path-is-absolute": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/swagger-parser": {
|
||||||
|
"version": "10.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz",
|
||||||
|
"integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@apidevtools/swagger-parser": "10.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/swagger-ui-dist": {
|
||||||
|
"version": "5.18.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz",
|
||||||
|
"integrity": "sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@scarf/scarf": "=1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/swagger-ui-express": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"swagger-ui-dist": ">=5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= v0.10.32"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"express": ">=4.0.0 || >=5.0.0-beta"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tar": {
|
"node_modules/tar": {
|
||||||
"version": "6.2.1",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||||
@@ -9642,6 +9896,15 @@
|
|||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/yaml": {
|
||||||
|
"version": "2.0.0-1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",
|
||||||
|
"integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yargs": {
|
"node_modules/yargs": {
|
||||||
"version": "17.7.2",
|
"version": "17.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||||
@@ -9705,6 +9968,36 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/z-schema": {
|
||||||
|
"version": "5.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz",
|
||||||
|
"integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
|
"lodash.isequal": "^4.5.0",
|
||||||
|
"validator": "^13.7.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"z-schema": "bin/z-schema"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"commander": "^9.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/z-schema/node_modules/commander": {
|
||||||
|
"version": "9.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||||
|
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/zip-stream": {
|
"node_modules/zip-stream": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "eventmaster",
|
"name": "eventmaster",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"author": "Tobias Zoghaib",
|
"author": "Tobias Zoghaib",
|
||||||
"description": "Hackable ticket store for educational purposes",
|
"description": "Hackable ticket store for educational purposes",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -53,6 +53,9 @@
|
|||||||
"sequelize": "^6.37.4",
|
"sequelize": "^6.37.4",
|
||||||
"sequelize-typescript": "^2.1.6",
|
"sequelize-typescript": "^2.1.6",
|
||||||
"sqlite3": "^5.1.7",
|
"sqlite3": "^5.1.7",
|
||||||
|
"swagger-autogen": "^2.23.7",
|
||||||
|
"swagger-jsdoc": "^6.2.8",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"vue": "^3.4.29",
|
"vue": "^3.4.29",
|
||||||
"vue-i18n": "^10.0.4",
|
"vue-i18n": "^10.0.4",
|
||||||
"vue-router": "^4.4.5",
|
"vue-router": "^4.4.5",
|
||||||
@@ -68,6 +71,8 @@
|
|||||||
"@types/jsonwebtoken": "^9.0.7",
|
"@types/jsonwebtoken": "^9.0.7",
|
||||||
"@types/multer": "^1.4.12",
|
"@types/multer": "^1.4.12",
|
||||||
"@types/node": "^22.9.0",
|
"@types/node": "^22.9.0",
|
||||||
|
"@types/swagger-jsdoc": "^6.0.4",
|
||||||
|
"@types/swagger-ui-express": "^4.1.7",
|
||||||
"@vitejs/plugin-vue": "^5.1.4",
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ defineProps({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-card variant="outlined" class="my-1 mx-2 px-2">
|
<v-card variant="outlined" class="my-1 px-2">
|
||||||
<v-row class="d-flex justify-center align-center">
|
<v-row class="d-flex justify-center align-center">
|
||||||
<v-col class="text-caption text-left" v-if="descriptionText.length > 0">
|
<v-col class="text-caption text-left" v-if="descriptionText.length > 0">
|
||||||
{{ descriptionText }}
|
{{ descriptionText }}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ defineProps({
|
|||||||
{{ secondLine }}
|
{{ secondLine }}
|
||||||
</v-skeleton-loader>
|
</v-skeleton-loader>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions v-if="!$slots.actions">
|
||||||
<outlined-button
|
<outlined-button
|
||||||
@click="router.push(buttonRoute)"
|
@click="router.push(buttonRoute)"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@@ -45,6 +45,10 @@ defineProps({
|
|||||||
{{ $t('misc.actions.more') }}
|
{{ $t('misc.actions.more') }}
|
||||||
</outlined-button>
|
</outlined-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #actions v-else>
|
||||||
|
<slot name="actions"></slot>
|
||||||
|
</template>
|
||||||
</card-view>
|
</card-view>
|
||||||
</v-col>
|
</v-col>
|
||||||
</template>
|
</template>
|
||||||
@@ -27,7 +27,7 @@ export async function fetchAllAccounts(token: string) {
|
|||||||
* @returns Response from server with token body
|
* @returns Response from server with token body
|
||||||
*/
|
*/
|
||||||
export async function getLogin(username: string, password: string) {
|
export async function getLogin(username: string, password: string) {
|
||||||
return await axios.get(BASE_URL + "/account/login?username=" + username + "&password=" + password)
|
return await axios.get(BASE_URL + "/login?username=" + username + "&password=" + password)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ export async function getLogin(username: string, password: string) {
|
|||||||
* @returns Response from server with account body
|
* @returns Response from server with account body
|
||||||
*/
|
*/
|
||||||
export async function getAccount(token: string) {
|
export async function getAccount(token: string) {
|
||||||
return await axios.get(BASE_URL + "/account/data", {
|
return await axios.get(BASE_URL + "/account", {
|
||||||
headers: {
|
headers: {
|
||||||
"Authorization": token
|
"Authorization": token
|
||||||
}
|
}
|
||||||
@@ -77,9 +77,17 @@ export async function updateAccount(account: AccountModel, token: string) {
|
|||||||
* Delete an account in servers database
|
* Delete an account in servers database
|
||||||
*
|
*
|
||||||
* @param account Account to delete
|
* @param account Account to delete
|
||||||
|
* @param token Validation token
|
||||||
*
|
*
|
||||||
* @returns Response from server
|
* @returns Response from server
|
||||||
*/
|
*/
|
||||||
export async function deleteAccount(account: AccountModel) {
|
export async function deleteAccount(account: AccountModel, token: string) {
|
||||||
return await axios.delete(BASE_URL + "/account/" + account.id)
|
return await axios.delete(BASE_URL + "/account", {
|
||||||
|
headers: {
|
||||||
|
"Authorization": token
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
account: account
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,22 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
import { BasketItemModel } from "../models/ordering/basketItemModel"
|
import { BasketItemModel } from "../models/ordering/basketItemModel"
|
||||||
|
import { OrderApiModel } from "../models/apiEndpoints/orderApiModel"
|
||||||
|
|
||||||
const BASE_URL = "http://localhost:3000/orders"
|
const BASE_URL = "http://localhost:3000/orders"
|
||||||
|
|
||||||
export async function fetchUserOrders(userId: number) {
|
export async function fetchUserOrders(userId: number, token: string) {
|
||||||
return axios.get(BASE_URL + "/" + userId)
|
return axios.get(BASE_URL + "?id=" + userId, {
|
||||||
|
headers: {
|
||||||
|
"Authorization": token
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createOrder(
|
export async function createOrder(
|
||||||
accountId: number,
|
|
||||||
basketItem: Array<BasketItemModel>,
|
basketItem: Array<BasketItemModel>,
|
||||||
paymentId: number,
|
paymentId: number,
|
||||||
addressId: number
|
addressId: number,
|
||||||
|
token: string
|
||||||
) {
|
) {
|
||||||
let tickets = []
|
let tickets = []
|
||||||
|
|
||||||
@@ -25,21 +30,25 @@ export async function createOrder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log({
|
|
||||||
accountId: accountId,
|
|
||||||
tickets: tickets,
|
|
||||||
paymentId: paymentId,
|
|
||||||
addressId: addressId
|
|
||||||
})
|
|
||||||
|
|
||||||
return axios.post(BASE_URL, {
|
return axios.post(BASE_URL, {
|
||||||
accountId: accountId,
|
|
||||||
tickets: tickets,
|
tickets: tickets,
|
||||||
paymentId: paymentId,
|
paymentId: paymentId,
|
||||||
addressId: addressId
|
addressId: addressId,
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
"Authorization": token
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchAllOrders() {
|
export async function fetchAllOrders(token: string) {
|
||||||
return axios.get(BASE_URL)
|
return axios.get(BASE_URL, {
|
||||||
|
headers: {
|
||||||
|
"Authorization": token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function patchOrder(order: OrderApiModel) {
|
||||||
|
return axios.patch(BASE_URL, order)
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
"emailIsNotValid": "Ungültige E-Mail Addresse",
|
"emailIsNotValid": "Ungültige E-Mail Addresse",
|
||||||
"emailRequired": "E-Mail-Adresse benötigt",
|
"emailRequired": "E-Mail-Adresse benötigt",
|
||||||
"accountManagement": "Account verwalten",
|
"accountManagement": "Account verwalten",
|
||||||
"accountManagementDescription": "Persönliche Daten, Adressen, Bezahlmethoden",
|
"accountManagementDescription": "Persönliche Daten, Konto löschen",
|
||||||
"login": {
|
"login": {
|
||||||
"pleaseLoginToOrder": "Bitte anmelden zum bestellen",
|
"pleaseLoginToOrder": "Bitte anmelden zum bestellen",
|
||||||
"backToLogin": "Zurück zum Login",
|
"backToLogin": "Zurück zum Login",
|
||||||
@@ -109,7 +109,16 @@
|
|||||||
"addNewAccount": "Neuen Account hinzufügen",
|
"addNewAccount": "Neuen Account hinzufügen",
|
||||||
"accountRole": "Account Rolle",
|
"accountRole": "Account Rolle",
|
||||||
"noRealPaymentsNeeded": "Keine echten Kontodaten nötig!",
|
"noRealPaymentsNeeded": "Keine echten Kontodaten nötig!",
|
||||||
"administrator": "Administrator | Administratoren"
|
"administrator": "Administrator | Administratoren",
|
||||||
|
"managePaymentsDescription": "Bezahlarten hinzufügen, ändern, löschen",
|
||||||
|
"paymentsManagement": "Bezahlarten verwalten",
|
||||||
|
"payments": {
|
||||||
|
"editPayment": "Bezahlart bearbeiten",
|
||||||
|
"editAddress": "Adresse bearbeiten"
|
||||||
|
},
|
||||||
|
"addressManagementDetails": "Adressen hinzufügen, ändern, löschen",
|
||||||
|
"addressManagement": "Adressen verwalten",
|
||||||
|
"sessionTime": "Session time"
|
||||||
},
|
},
|
||||||
"order": {
|
"order": {
|
||||||
"oclock": "Uhr",
|
"oclock": "Uhr",
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
"emailIsNotValid": "E-Mail not valid",
|
"emailIsNotValid": "E-Mail not valid",
|
||||||
"emailRequired": "E-Mail required",
|
"emailRequired": "E-Mail required",
|
||||||
"accountManagement": "Manage Account",
|
"accountManagement": "Manage Account",
|
||||||
"accountManagementDescription": "Personal data, addresses, payments",
|
"accountManagementDescription": "Personal data, delete account",
|
||||||
"login": {
|
"login": {
|
||||||
"pleaseLoginToOrder": "Please login to order",
|
"pleaseLoginToOrder": "Please login to order",
|
||||||
"backToLogin": "Back to Login",
|
"backToLogin": "Back to Login",
|
||||||
@@ -109,7 +109,16 @@
|
|||||||
"addNewAccount": "Add new account",
|
"addNewAccount": "Add new account",
|
||||||
"accountRole": "Account Role",
|
"accountRole": "Account Role",
|
||||||
"noRealPaymentsNeeded": "No real payment data required!",
|
"noRealPaymentsNeeded": "No real payment data required!",
|
||||||
"administrator": "Administrator"
|
"administrator": "Administrator",
|
||||||
|
"managePaymentsDescription": "Add, change, remove payments",
|
||||||
|
"paymentsManagement": "Manage payments",
|
||||||
|
"payments": {
|
||||||
|
"editPayment": "Edit Payment",
|
||||||
|
"editAddress": "Edit address"
|
||||||
|
},
|
||||||
|
"addressManagementDetails": "Add, change, remove addresses",
|
||||||
|
"addressManagement": "Manage addresses",
|
||||||
|
"sessionTime": "Session time"
|
||||||
},
|
},
|
||||||
"order": {
|
"order": {
|
||||||
"oclock": "o'clock",
|
"oclock": "o'clock",
|
||||||
|
|||||||
79
src/pages/account/accountAddressesPage/addressEditDialog.vue
Normal file
79
src/pages/account/accountAddressesPage/addressEditDialog.vue
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import actionDialog from '@/components/basics/actionDialog.vue';
|
||||||
|
import OutlinedButton from '@/components/basics/outlinedButton.vue';
|
||||||
|
import { getIbanRules, getNumberStartRules, getPostalRules, getStringRules } from '@/scripts/validationRules';
|
||||||
|
import { useAccountStore } from '@/stores/account.store';
|
||||||
|
import cardViewOneLine from '@/components/basics/cardViewOneLine.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const valid = ref(false)
|
||||||
|
|
||||||
|
const accountStore = useAccountStore()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<action-dialog
|
||||||
|
v-model="accountStore.showEditDialog"
|
||||||
|
max-width="800"
|
||||||
|
:title="$t('account.payments.editAddress')"
|
||||||
|
>
|
||||||
|
<v-container>
|
||||||
|
<v-form v-model="valid">
|
||||||
|
<v-row class="pt-5">
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
:label="$t('account.userData.street')"
|
||||||
|
v-model="accountStore.address.street"
|
||||||
|
:rules="getStringRules()"
|
||||||
|
variant="outlined"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
:label="$t('account.userData.houseNumber')"
|
||||||
|
v-model="accountStore.address.houseNumber"
|
||||||
|
:rules="getNumberStartRules()"
|
||||||
|
variant="outlined"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
:label="$t('account.userData.postalCode')"
|
||||||
|
v-model="accountStore.address.postalCode"
|
||||||
|
:rules="getPostalRules()"
|
||||||
|
variant="outlined"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
:label="$t('account.userData.placeOfResidence')"
|
||||||
|
v-model="accountStore.address.city"
|
||||||
|
:rules="getStringRules()"
|
||||||
|
variant="outlined"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-form>
|
||||||
|
|
||||||
|
</v-container>
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<outlined-button
|
||||||
|
color="success"
|
||||||
|
prepend-icon="mdi-content-save"
|
||||||
|
:disabled="!valid"
|
||||||
|
:loading="accountStore.fetchInProgress"
|
||||||
|
@click="accountStore.saveAddress"
|
||||||
|
>
|
||||||
|
{{ $t('misc.actions.save') }}
|
||||||
|
</outlined-button>
|
||||||
|
</template>
|
||||||
|
</action-dialog>
|
||||||
|
</template>
|
||||||
51
src/pages/account/accountAddressesPage/index.vue
Normal file
51
src/pages/account/accountAddressesPage/index.vue
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import dataLayout from '@/layouts/dataLayout.vue';
|
||||||
|
import { useAccountStore } from '@/stores/account.store';
|
||||||
|
import { useFeedbackStore } from '@/stores/feedback.store';
|
||||||
|
import addressEditDialog from './addressEditDialog.vue';
|
||||||
|
|
||||||
|
const accountStore = useAccountStore()
|
||||||
|
const feedbackStore = useFeedbackStore()
|
||||||
|
|
||||||
|
const headers = [
|
||||||
|
{ title: feedbackStore.i18n.t('account.userData.street'), value: "street" },
|
||||||
|
{ title: feedbackStore.i18n.t('account.userData.houseNumber'), value: "houseNumber" },
|
||||||
|
{ title: feedbackStore.i18n.t('account.userData.postalCode'), value: "postalCode" },
|
||||||
|
{ title: feedbackStore.i18n.t('account.userData.placeOfResidence'), value: "city" },
|
||||||
|
{ title: "Aktionen", value: "actions", width: 130 }
|
||||||
|
]
|
||||||
|
|
||||||
|
accountStore.refreshAccount()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<data-layout
|
||||||
|
:add-button-string="$t('misc.actions.add')"
|
||||||
|
:fetch-in-progress="accountStore.fetchInProgress"
|
||||||
|
:on-add-click="() => { accountStore.newAddress() }"
|
||||||
|
>
|
||||||
|
<v-data-table
|
||||||
|
:headers="headers"
|
||||||
|
:items="accountStore.userAccount.addresses"
|
||||||
|
:loading="accountStore.fetchInProgress"
|
||||||
|
>
|
||||||
|
<template #item.actions="{ item }">
|
||||||
|
<v-btn
|
||||||
|
icon="mdi-pencil"
|
||||||
|
variant="plain"
|
||||||
|
color="orange"
|
||||||
|
@click="accountStore.editAddress(item)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<v-btn
|
||||||
|
icon="mdi-delete"
|
||||||
|
variant="plain"
|
||||||
|
color="red"
|
||||||
|
@click="accountStore.removeAddress(item)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</data-layout>
|
||||||
|
|
||||||
|
<address-edit-dialog />
|
||||||
|
</template>
|
||||||
@@ -81,7 +81,6 @@ const stringRules = [
|
|||||||
v-model="accountStore.userAccount.firstName"
|
v-model="accountStore.userAccount.firstName"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
:rules="stringRules"
|
:rules="stringRules"
|
||||||
hide-details
|
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col>
|
<v-col>
|
||||||
@@ -90,7 +89,6 @@ const stringRules = [
|
|||||||
v-model="accountStore.userAccount.lastName"
|
v-model="accountStore.userAccount.lastName"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
:rules="stringRules"
|
:rules="stringRules"
|
||||||
hide-details
|
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import cardView from '@/components/basics/cardView.vue';
|
|
||||||
import { useAccountStore } from '@/stores/account.store';
|
|
||||||
import outlinedButton from '@/components/basics/outlinedButton.vue';
|
|
||||||
import { AddressModel } from '@/data/models/user/addressModel';
|
|
||||||
import { getNumberStartRules, getPostalRules, getStringRules } from '@/scripts/validationRules';
|
|
||||||
|
|
||||||
const accountStore = useAccountStore()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<card-view
|
|
||||||
icon="mdi-home"
|
|
||||||
:title="$t('account.userData.address', 2)"
|
|
||||||
>
|
|
||||||
<v-expansion-panels v-if="accountStore.userAccount.addresses.length > 0">
|
|
||||||
<v-expansion-panel
|
|
||||||
v-for="address in accountStore.userAccount.addresses"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<template #title>
|
|
||||||
<div v-if="address.street != undefined">
|
|
||||||
{{ address.street }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div v-if="address.houseNumber != undefined">
|
|
||||||
{{ address.houseNumber }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #text>
|
|
||||||
<v-row class="pt-5">
|
|
||||||
<v-col>
|
|
||||||
<v-text-field
|
|
||||||
:label="$t('account.userData.street')"
|
|
||||||
v-model="address.street"
|
|
||||||
:rules="getStringRules()"
|
|
||||||
variant="outlined"
|
|
||||||
clearable
|
|
||||||
hide-details
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
<v-col>
|
|
||||||
<v-text-field
|
|
||||||
:label="$t('account.userData.houseNumber')"
|
|
||||||
v-model="address.houseNumber"
|
|
||||||
:rules="getNumberStartRules()"
|
|
||||||
variant="outlined"
|
|
||||||
clearable
|
|
||||||
hide-details
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row>
|
|
||||||
<v-col>
|
|
||||||
<v-text-field
|
|
||||||
:label="$t('account.userData.postalCode')"
|
|
||||||
v-model="address.postalCode"
|
|
||||||
:rules="getPostalRules()"
|
|
||||||
variant="outlined"
|
|
||||||
clearable
|
|
||||||
hide-details
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
<v-col>
|
|
||||||
<v-text-field
|
|
||||||
:label="$t('account.userData.placeOfResidence')"
|
|
||||||
v-model="address.city"
|
|
||||||
:rules="getStringRules()"
|
|
||||||
variant="outlined"
|
|
||||||
clearable
|
|
||||||
hide-details
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row>
|
|
||||||
<v-col class="d-flex justify-center align-center">
|
|
||||||
<outlined-button
|
|
||||||
@click="accountStore.removeAddress(address)"
|
|
||||||
color="error"
|
|
||||||
prepend-icon="mdi-delete"
|
|
||||||
>
|
|
||||||
{{ $t('misc.actions.remove') }}
|
|
||||||
</outlined-button>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</template>
|
|
||||||
</v-expansion-panel>
|
|
||||||
</v-expansion-panels>
|
|
||||||
|
|
||||||
<v-empty-state
|
|
||||||
v-else
|
|
||||||
:title="$t('account.noAddresses')"
|
|
||||||
icon="mdi-home-off"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<template #actions>
|
|
||||||
<outlined-button
|
|
||||||
@click="accountStore.userAccount.addresses.push(new AddressModel())"
|
|
||||||
prepend-icon="mdi-plus"
|
|
||||||
color="success"
|
|
||||||
>
|
|
||||||
{{ $t('misc.actions.add') }}
|
|
||||||
</outlined-button>
|
|
||||||
</template>
|
|
||||||
</card-view>
|
|
||||||
</template>
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import accountDataCard from './accountDataCard.vue';
|
import accountDataCard from './accountDataCard.vue';
|
||||||
import accountManagingCard from './accountManagingCard.vue';
|
import accountManagingCard from './accountManagingCard.vue';
|
||||||
import addressesCard from './addressesCard.vue';
|
|
||||||
import paymentsCard from './paymentsCard.vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import accountSubPageLayout from '@/layouts/accountSubPageLayout.vue';
|
import accountSubPageLayout from '@/layouts/accountSubPageLayout.vue';
|
||||||
|
|
||||||
@@ -17,18 +15,6 @@ const router = useRouter()
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<v-row>
|
|
||||||
<v-col>
|
|
||||||
<addresses-card />
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row>
|
|
||||||
<v-col>
|
|
||||||
<payments-card />
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
<account-managing-card />
|
<account-managing-card />
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import cardView from '@/components/basics/cardView.vue';
|
|
||||||
import { useAccountStore } from '@/stores/account.store';
|
|
||||||
import outlinedButton from '@/components/basics/outlinedButton.vue';
|
|
||||||
import { PaymentModel } from '@/data/models/user/paymentModel';
|
|
||||||
import { getIbanRules, getStringRules } from '@/scripts/validationRules';
|
|
||||||
import cardViewOneLine from '@/components/basics/cardViewOneLine.vue';
|
|
||||||
|
|
||||||
const accountStore = useAccountStore()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<card-view
|
|
||||||
icon="mdi-currency-usd"
|
|
||||||
:title="$t('account.userData.payment', 2)"
|
|
||||||
>
|
|
||||||
<v-row>
|
|
||||||
<v-col>
|
|
||||||
<card-view-one-line
|
|
||||||
color="warning"
|
|
||||||
prepend-icon="mdi-alert"
|
|
||||||
:title="$t('account.noRealPaymentsNeeded')"
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row v-if="accountStore.userAccount.payments.length > 0">
|
|
||||||
<v-col>
|
|
||||||
<v-expansion-panels>
|
|
||||||
<v-expansion-panel
|
|
||||||
v-for="payment in accountStore.userAccount.payments"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<template #title>
|
|
||||||
{{ payment.bankName }}
|
|
||||||
</template>
|
|
||||||
<template #text>
|
|
||||||
<v-row class="pt-5">
|
|
||||||
<v-col>
|
|
||||||
<v-text-field
|
|
||||||
:label="$t('account.userData.bankName')"
|
|
||||||
v-model="payment.bankName"
|
|
||||||
:rules="getStringRules()"
|
|
||||||
variant="outlined"
|
|
||||||
hide-details
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
<v-col>
|
|
||||||
<v-text-field
|
|
||||||
:label="$t('account.userData.iban')"
|
|
||||||
v-model="payment.iban"
|
|
||||||
:rules="getIbanRules()"
|
|
||||||
variant="outlined"
|
|
||||||
hide-details
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row>
|
|
||||||
<v-col class="d-flex justify-center align-center">
|
|
||||||
<outlined-button
|
|
||||||
@click="accountStore.removePayment(payment)"
|
|
||||||
color="error"
|
|
||||||
prepend-icon="mdi-delete"
|
|
||||||
>
|
|
||||||
{{ $t('misc.actions.remove') }}
|
|
||||||
</outlined-button>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</template>
|
|
||||||
</v-expansion-panel>
|
|
||||||
</v-expansion-panels>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row v-else>
|
|
||||||
<v-col>
|
|
||||||
<v-empty-state
|
|
||||||
:title="$t('account.noPayments')"
|
|
||||||
icon="mdi-currency-usd-off"
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<template #actions>
|
|
||||||
<outlined-button
|
|
||||||
@click="accountStore.userAccount.payments.push(new PaymentModel())"
|
|
||||||
prepend-icon="mdi-plus"
|
|
||||||
color="success"
|
|
||||||
>
|
|
||||||
{{ $t('misc.actions.add') }}
|
|
||||||
</outlined-button>
|
|
||||||
</template>
|
|
||||||
</card-view>
|
|
||||||
</template>
|
|
||||||
@@ -1,60 +1,76 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAccountStore } from '@/stores/account.store';
|
import { useAccountStore } from '@/stores/account.store';
|
||||||
import cardView from '@/components/basics/cardView.vue';
|
import dashboardCard from '@/components/pageParts/dashboardCard.vue';
|
||||||
|
import { useOrderStore } from '@/stores/order.store';
|
||||||
|
import OutlinedButton from '@/components/basics/outlinedButton.vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import moment from 'moment';
|
||||||
|
import { millisecondsToHumanReadableString } from '@/scripts/dateTimeScripts';
|
||||||
|
|
||||||
const accountStore = useAccountStore()
|
const accountStore = useAccountStore()
|
||||||
|
const orderStore = useOrderStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
orderStore.getOrdersOfAccount(accountStore.userAccount, accountStore.userAccountToken)
|
||||||
|
accountStore.refreshAccount()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-container max-width="1000">
|
<v-container>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<dashboard-card
|
||||||
<card-view
|
:title="$t('order.order', 2)"
|
||||||
:title="$t('misc.greeting', { msg: accountStore.userAccount.username })"
|
icon="mdi-basket-check"
|
||||||
icon="mdi-hand-wave"
|
:first-line="orderStore.orders.length + ' ' + $t('order.order', 2)"
|
||||||
>
|
:second-line="$t('order.ordersDescription')"
|
||||||
<v-container>
|
button-route="/account/orders"
|
||||||
<v-row>
|
:loading="orderStore.fetchInProgress"
|
||||||
<v-col>
|
/>
|
||||||
<card-view
|
|
||||||
:title="$t('order.order', 2)"
|
|
||||||
icon="mdi-basket-check"
|
|
||||||
@click="router.push('/account/orders')"
|
|
||||||
>
|
|
||||||
{{ $t('order.ordersDescription') }}
|
|
||||||
</card-view>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row>
|
<dashboard-card
|
||||||
<v-col>
|
:title="$t('account.accountManagement')"
|
||||||
<card-view
|
icon="mdi-account"
|
||||||
:title="$t('account.accountManagement')"
|
:first-line="accountStore.userAccount.username"
|
||||||
icon="mdi-account"
|
:second-line="$t('account.accountManagementDescription')"
|
||||||
@click="router.push('/account/data')"
|
:loading="accountStore.fetchInProgress"
|
||||||
>
|
button-route="/account/data"
|
||||||
{{ $t('account.accountManagementDescription') }}
|
/>
|
||||||
</card-view>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row>
|
<dashboard-card
|
||||||
<v-col>
|
:title="$t('account.addressManagement')"
|
||||||
<card-view
|
icon="mdi-city"
|
||||||
:title="$t('account.logout.logout')"
|
:first-line="accountStore.userAccount.addresses?.length + ' ' +
|
||||||
icon="mdi-logout"
|
$t('account.userData.address', accountStore.userAccount.addresses?.length)"
|
||||||
@click="accountStore.logout(); router.push('/account/login')"
|
:second-line="$t('account.addressManagementDetails')"
|
||||||
>
|
:loading="accountStore.fetchInProgress"
|
||||||
{{ $t('account.logout.logoutDescription') }}
|
button-route="/account/addresses"
|
||||||
</card-view>
|
/>
|
||||||
</v-col>
|
|
||||||
</v-row>
|
<dashboard-card
|
||||||
</v-container>
|
:title="$t('account.paymentsManagement', 2)"
|
||||||
</card-view>
|
icon="mdi-currency-eur"
|
||||||
|
:first-line="accountStore.userAccount.payments?.length + ' ' +
|
||||||
</v-col>
|
$t('account.userData.payment', accountStore.userAccount.payments?.length)"
|
||||||
|
:second-line="$t('account.managePaymentsDescription')"
|
||||||
|
:loading="accountStore.fetchInProgress"
|
||||||
|
button-route="/account/payments"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<dashboard-card
|
||||||
|
:title="$t('account.logout.logout')"
|
||||||
|
:first-line="millisecondsToHumanReadableString(moment().diff(moment(accountStore.loggedInTimeStamp))) + ' h ' + $t('account.sessionTime')"
|
||||||
|
:second-line="$t('account.logout.logoutDescription')"
|
||||||
|
icon="mdi-logout"
|
||||||
|
>
|
||||||
|
<template #actions>
|
||||||
|
<outlined-button
|
||||||
|
color="error"
|
||||||
|
@click="accountStore.logout(); router.push('/account/login')"
|
||||||
|
>
|
||||||
|
{{ $t('account.logout.logout') }}
|
||||||
|
</outlined-button>
|
||||||
|
</template>
|
||||||
|
</dashboard-card>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
49
src/pages/account/accountPaymentsPage/index.vue
Normal file
49
src/pages/account/accountPaymentsPage/index.vue
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import dataLayout from '@/layouts/dataLayout.vue';
|
||||||
|
import { useAccountStore } from '@/stores/account.store';
|
||||||
|
import { useFeedbackStore } from '@/stores/feedback.store';
|
||||||
|
import PaymentEditDialog from './paymentEditDialog.vue';
|
||||||
|
|
||||||
|
const accountStore = useAccountStore()
|
||||||
|
const feedbackStore = useFeedbackStore()
|
||||||
|
|
||||||
|
const headers = [
|
||||||
|
{ title: feedbackStore.i18n.t('account.userData.bankName'), value: "bankName" },
|
||||||
|
{ title: feedbackStore.i18n.t('account.userData.iban'), value: "iban" },
|
||||||
|
{ title: "Aktionen", value: "actions", width: 130 }
|
||||||
|
]
|
||||||
|
|
||||||
|
accountStore.refreshAccount()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<data-layout
|
||||||
|
:add-button-string="$t('misc.actions.add')"
|
||||||
|
:fetch-in-progress="accountStore.fetchInProgress"
|
||||||
|
:on-add-click="() => { accountStore.newPayment() }"
|
||||||
|
>
|
||||||
|
<v-data-table
|
||||||
|
:headers="headers"
|
||||||
|
:items="accountStore.userAccount.payments"
|
||||||
|
:loading="accountStore.fetchInProgress"
|
||||||
|
>
|
||||||
|
<template #item.actions="{ item }">
|
||||||
|
<v-btn
|
||||||
|
icon="mdi-pencil"
|
||||||
|
variant="plain"
|
||||||
|
color="orange"
|
||||||
|
@click="accountStore.editPayment(item)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<v-btn
|
||||||
|
icon="mdi-delete"
|
||||||
|
variant="plain"
|
||||||
|
color="red"
|
||||||
|
@click="accountStore.removePayment(item)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</data-layout>
|
||||||
|
|
||||||
|
<payment-edit-dialog />
|
||||||
|
</template>
|
||||||
69
src/pages/account/accountPaymentsPage/paymentEditDialog.vue
Normal file
69
src/pages/account/accountPaymentsPage/paymentEditDialog.vue
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import actionDialog from '@/components/basics/actionDialog.vue';
|
||||||
|
import OutlinedButton from '@/components/basics/outlinedButton.vue';
|
||||||
|
import { getIbanRules, getStringRules } from '@/scripts/validationRules';
|
||||||
|
import { useAccountStore } from '@/stores/account.store';
|
||||||
|
import cardViewOneLine from '@/components/basics/cardViewOneLine.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const valid = ref(false)
|
||||||
|
|
||||||
|
const accountStore = useAccountStore()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<action-dialog
|
||||||
|
v-model="accountStore.showEditDialog"
|
||||||
|
max-width="800"
|
||||||
|
:title="$t('account.payments.editPayment')"
|
||||||
|
>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<card-view-one-line
|
||||||
|
color="warning"
|
||||||
|
prepend-icon="mdi-alert"
|
||||||
|
:title="$t('account.noRealPaymentsNeeded')"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-form v-model="valid">
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
:label="$t('account.userData.bankName')"
|
||||||
|
v-model="accountStore.payment.bankName"
|
||||||
|
:rules="getStringRules(8)"
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
:label="$t('account.userData.iban')"
|
||||||
|
v-model="accountStore.payment.iban"
|
||||||
|
:rules="getIbanRules()"
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-form>
|
||||||
|
|
||||||
|
</v-container>
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<outlined-button
|
||||||
|
color="success"
|
||||||
|
prepend-icon="mdi-content-save"
|
||||||
|
:disabled="!valid"
|
||||||
|
:loading="accountStore.fetchInProgress"
|
||||||
|
@click="accountStore.savePayment"
|
||||||
|
>
|
||||||
|
{{ $t('misc.actions.save') }}
|
||||||
|
</outlined-button>
|
||||||
|
</template>
|
||||||
|
</action-dialog>
|
||||||
|
</template>
|
||||||
@@ -10,6 +10,7 @@ const accountStore = useAccountStore()
|
|||||||
async function registerAccount() {
|
async function registerAccount() {
|
||||||
accountStore.registerAccount()
|
accountStore.registerAccount()
|
||||||
.then(result => {
|
.then(result => {
|
||||||
|
console.log(result)
|
||||||
if (result) {
|
if (result) {
|
||||||
showRegisterCard.value = false
|
showRegisterCard.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { useOrderStore } from '@/stores/order.store';
|
|||||||
const accountStore = useAccountStore()
|
const accountStore = useAccountStore()
|
||||||
const orderStore = useOrderStore()
|
const orderStore = useOrderStore()
|
||||||
|
|
||||||
orderStore.getOrdersOfAccount(accountStore.userAccount)
|
orderStore.getOrdersOfAccount(accountStore.userAccount, accountStore.userAccountToken)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAccountStore } from '@/stores/account.store';
|
import { useAccountStore } from '@/stores/account.store';
|
||||||
import adminDataLayout from '@/layouts/adminDataLayout.vue';
|
import dataLayout from '@/layouts/dataLayout.vue';
|
||||||
import { useFeedbackStore } from '@/stores/feedback.store';
|
import { useFeedbackStore } from '@/stores/feedback.store';
|
||||||
|
|
||||||
const accountStore = useAccountStore()
|
const accountStore = useAccountStore()
|
||||||
@@ -19,7 +19,7 @@ accountStore.getAllAccounts()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<admin-data-layout
|
<data-layout
|
||||||
:add-button-string="$t('account.addNewAccount')"
|
:add-button-string="$t('account.addNewAccount')"
|
||||||
:fetch-in-progress="accountStore.fetchInProgress"
|
:fetch-in-progress="accountStore.fetchInProgress"
|
||||||
>
|
>
|
||||||
@@ -44,5 +44,5 @@ accountStore.getAllAccounts()
|
|||||||
/> -->
|
/> -->
|
||||||
</template>
|
</template>
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</admin-data-layout>
|
</data-layout>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useBandStore } from '@/stores/band.store';
|
import { useBandStore } from '@/stores/band.store';
|
||||||
import bandEditDialog from './bandEditDialog.vue';
|
import bandEditDialog from './bandEditDialog.vue';
|
||||||
import adminDataLayout from '@/layouts/adminDataLayout.vue';
|
import dataLayout from '@/layouts/dataLayout.vue';
|
||||||
import { useFeedbackStore } from '@/stores/feedback.store';
|
import { useFeedbackStore } from '@/stores/feedback.store';
|
||||||
|
|
||||||
const bandStore = useBandStore()
|
const bandStore = useBandStore()
|
||||||
@@ -22,7 +22,7 @@ bandStore.getBands()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<admin-data-layout
|
<data-layout
|
||||||
:add-button-string="$t('band.addNewBand')"
|
:add-button-string="$t('band.addNewBand')"
|
||||||
:fetch-in-progress="bandStore.fetchInProgress"
|
:fetch-in-progress="bandStore.fetchInProgress"
|
||||||
:on-add-click="() => bandStore.newBand()"
|
:on-add-click="() => bandStore.newBand()"
|
||||||
@@ -72,7 +72,7 @@ bandStore.getBands()
|
|||||||
/> -->
|
/> -->
|
||||||
</template>
|
</template>
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</admin-data-layout>
|
</data-layout>
|
||||||
|
|
||||||
<band-edit-dialog />
|
<band-edit-dialog />
|
||||||
</template>
|
</template>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
import { useBandStore } from '@/stores/band.store';
|
import { useBandStore } from '@/stores/band.store';
|
||||||
import { useConcertStore } from '@/stores/concert.store';
|
import { useConcertStore } from '@/stores/concert.store';
|
||||||
import { useFeedbackStore } from '@/stores/feedback.store';
|
import { useFeedbackStore } from '@/stores/feedback.store';
|
||||||
import adminDataLayout from '@/layouts/adminDataLayout.vue';
|
import dataLayout from '@/layouts/dataLayout.vue';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
const concertStore = useConcertStore()
|
const concertStore = useConcertStore()
|
||||||
@@ -25,7 +25,7 @@ concertStore.getConcerts()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<admin-data-layout
|
<data-layout
|
||||||
:add-button-string="$t('concert.addNewConcert')"
|
:add-button-string="$t('concert.addNewConcert')"
|
||||||
:fetch-in-progress="concertStore.fetchInProgress"
|
:fetch-in-progress="concertStore.fetchInProgress"
|
||||||
:on-add-click="() => concertStore.newConcert()"
|
:on-add-click="() => concertStore.newConcert()"
|
||||||
@@ -73,5 +73,5 @@ concertStore.getConcerts()
|
|||||||
/> -->
|
/> -->
|
||||||
</template>
|
</template>
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</admin-data-layout>
|
</data-layout>
|
||||||
</template>
|
</template>
|
||||||
@@ -5,7 +5,7 @@ import { useAccountStore } from '@/stores/account.store';
|
|||||||
import { useLocationStore } from '@/stores/location.store';
|
import { useLocationStore } from '@/stores/location.store';
|
||||||
import { useGenreStore } from '@/stores/genre.store';
|
import { useGenreStore } from '@/stores/genre.store';
|
||||||
import { usePreferencesStore } from '@/stores/preferences.store';
|
import { usePreferencesStore } from '@/stores/preferences.store';
|
||||||
import dashboardCard from './dashboardCard.vue';
|
import dashboardCard from '../../../components/pageParts/dashboardCard.vue';
|
||||||
import { useOrderStore } from '@/stores/order.store';
|
import { useOrderStore } from '@/stores/order.store';
|
||||||
import { useFilesStore } from '@/stores/files.store';
|
import { useFilesStore } from '@/stores/files.store';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import adminDataLayout from '@/layouts/adminDataLayout.vue';
|
import dataLayout from '@/layouts/dataLayout.vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import FileUploadDialog from './fileUploadDialog.vue';
|
import FileUploadDialog from './fileUploadDialog.vue';
|
||||||
import { useFilesStore } from '@/stores/files.store';
|
import { useFilesStore } from '@/stores/files.store';
|
||||||
@@ -12,7 +12,7 @@ filesStore.getStaticFolders()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<admin-data-layout
|
<data-layout
|
||||||
:add-button-string="$t('misc.uploadFile')"
|
:add-button-string="$t('misc.uploadFile')"
|
||||||
:fetch-in-progress="filesStore.fetchInProgress"
|
:fetch-in-progress="filesStore.fetchInProgress"
|
||||||
:on-add-click="() => { filesStore.showFileUploadDialog = true }"
|
:on-add-click="() => { filesStore.showFileUploadDialog = true }"
|
||||||
@@ -112,7 +112,7 @@ filesStore.getStaticFolders()
|
|||||||
</v-row>
|
</v-row>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</admin-data-layout>
|
</data-layout>
|
||||||
|
|
||||||
<file-preview-dialog
|
<file-preview-dialog
|
||||||
v-model:show-dialog="showPreviewDialog"
|
v-model:show-dialog="showPreviewDialog"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import adminDataLayout from '@/layouts/adminDataLayout.vue';
|
import dataLayout from '@/layouts/dataLayout.vue';
|
||||||
import genreEditDialog from './genreEditDialog.vue';
|
import genreEditDialog from './genreEditDialog.vue';
|
||||||
import { useGenreStore } from '@/stores/genre.store';
|
import { useGenreStore } from '@/stores/genre.store';
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ genreStore.getGenres()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<admin-data-layout
|
<data-layout
|
||||||
:add-button-string="$t('band.addNewGenre')"
|
:add-button-string="$t('band.addNewGenre')"
|
||||||
:fetch-in-progress="genreStore.fetchInProgress"
|
:fetch-in-progress="genreStore.fetchInProgress"
|
||||||
:on-add-click="() => { genreStore.newGenre() }"
|
:on-add-click="() => { genreStore.newGenre() }"
|
||||||
@@ -48,7 +48,7 @@ genreStore.getGenres()
|
|||||||
/> -->
|
/> -->
|
||||||
</template>
|
</template>
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</admin-data-layout>
|
</data-layout>
|
||||||
|
|
||||||
<genre-edit-dialog />
|
<genre-edit-dialog />
|
||||||
</template>
|
</template>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import adminDataLayout from '@/layouts/adminDataLayout.vue';
|
import dataLayout from '@/layouts/dataLayout.vue';
|
||||||
import { useFeedbackStore } from '@/stores/feedback.store';
|
import { useFeedbackStore } from '@/stores/feedback.store';
|
||||||
import { useLocationStore } from '@/stores/location.store';
|
import { useLocationStore } from '@/stores/location.store';
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ locationStore.getLocations()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<admin-data-layout
|
<data-layout
|
||||||
:fetch-in-progress="locationStore.fetchInProgress"
|
:fetch-in-progress="locationStore.fetchInProgress"
|
||||||
:add-button-string="$t('location.addLocation')"
|
:add-button-string="$t('location.addLocation')"
|
||||||
:on-add-click="() => { locationStore.newLocation() }"
|
:on-add-click="() => { locationStore.newLocation() }"
|
||||||
@@ -66,5 +66,5 @@ locationStore.getLocations()
|
|||||||
/> -->
|
/> -->
|
||||||
</template>
|
</template>
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</admin-data-layout>
|
</data-layout>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import adminDataLayout from '@/layouts/adminDataLayout.vue';
|
import dataLayout from '@/layouts/dataLayout.vue';
|
||||||
import { useOrderStore } from '@/stores/order.store';
|
import { useOrderStore } from '@/stores/order.store';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import OrderDetailDialog from './orderDetailDialog.vue';
|
import OrderDetailDialog from './orderDetailDialog.vue';
|
||||||
@@ -13,19 +13,21 @@ const headers = [
|
|||||||
{ title: "Adresse", value: "street" },
|
{ title: "Adresse", value: "street" },
|
||||||
{ title: "Stadt", value: "city" },
|
{ title: "Stadt", value: "city" },
|
||||||
{ title: "Versendet", value: "shipped" },
|
{ title: "Versendet", value: "shipped" },
|
||||||
{ title: "", value: "edit", width: 130 }
|
{ title: "Aktionen", value: "edit", width: 130 }
|
||||||
]
|
]
|
||||||
|
|
||||||
orderStore.getAllOrders()
|
orderStore.getAllOrders()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<admin-data-layout
|
<data-layout
|
||||||
:hide-add-button="true"
|
:hide-add-button="true"
|
||||||
>
|
>
|
||||||
<v-data-table
|
<v-data-table
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
:items="orderStore.orders"
|
:items="orderStore.orders"
|
||||||
|
:loading="orderStore.fetchInProgress"
|
||||||
|
:items-per-page="100"
|
||||||
>
|
>
|
||||||
<template #item.account="{ item }">
|
<template #item.account="{ item }">
|
||||||
{{ item.account.firstName }} {{ item.account.lastName }}
|
{{ item.account.firstName }} {{ item.account.lastName }}
|
||||||
@@ -46,27 +48,27 @@ orderStore.getAllOrders()
|
|||||||
<template #item.shipped="{ item }">
|
<template #item.shipped="{ item }">
|
||||||
<v-icon
|
<v-icon
|
||||||
:icon="item.shipped ? 'mdi-check' : 'mdi-close'"
|
:icon="item.shipped ? 'mdi-check' : 'mdi-close'"
|
||||||
:color="item.shipped ? 'green' : 'red'"
|
:color="item.shipped ? 'success' : 'error'"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #item.edit="{ item }">
|
<template #item.edit="{ item }">
|
||||||
<!-- todo <v-btn
|
<v-btn
|
||||||
icon="mdi-eye"
|
icon="mdi-eye"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
@click="orderStore.openDetails(item)"
|
@click="orderStore.openDetails(item)"
|
||||||
/> -->
|
/>
|
||||||
|
|
||||||
<!-- todo <v-btn
|
<v-btn
|
||||||
icon="mdi-delete"
|
:icon="item.shipped ? 'mdi-close-circle-outline' : 'mdi-check-circle-outline'"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
color="red"
|
:color="item.shipped ? 'error' : 'success'"
|
||||||
@click="orderStore.deleteOrder(item)"
|
@click="orderStore.changeOrderShippedState(item, !item.shipped)"
|
||||||
/> -->
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</admin-data-layout>
|
</data-layout>
|
||||||
|
|
||||||
<order-detail-dialog />
|
<order-detail-dialog />
|
||||||
</template>
|
</template>
|
||||||
@@ -12,15 +12,67 @@ const orderStore = useOrderStore()
|
|||||||
v-model="orderStore.showDetailDialog"
|
v-model="orderStore.showDetailDialog"
|
||||||
:title="$t('order.order')"
|
:title="$t('order.order')"
|
||||||
icon="mdi-basket"
|
icon="mdi-basket"
|
||||||
|
max-width="800"
|
||||||
>
|
>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-subheader>
|
<v-list-subheader>
|
||||||
{{ $t('ticket.ticket', 2) }}
|
{{ $t('account.account') }}
|
||||||
</v-list-subheader>
|
</v-list-subheader>
|
||||||
|
|
||||||
<v-list-item v-for="ticket of orderStore.order.tickets">
|
<v-list-item prepend-icon="mdi-account">
|
||||||
{{ moment(ticket.concert.date).format("DD.MM.YYYY") }} -
|
{{ orderStore.order.account.username }}
|
||||||
{{ ticket.concert.band.name }} - {{ ticket.concert.name }}
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item prepend-icon="mdi-card-account-details">
|
||||||
|
{{ orderStore.order.account.firstName }} {{ orderStore.order.account.lastName }}
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item prepend-icon="mdi-home">
|
||||||
|
{{ orderStore.order.address.street }} {{ orderStore.order.address.houseNumber }}
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item prepend-icon="mdi-city">
|
||||||
|
{{ orderStore.order.address.postalCode }} {{ orderStore.order.address.city }}
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-subheader>
|
||||||
|
{{ $t('order.order') }}
|
||||||
|
</v-list-subheader>
|
||||||
|
|
||||||
|
<v-list-item prepend-icon="mdi-calendar">
|
||||||
|
{{ moment(orderStore.order.orderedAt).format("DD.MM.YYYY, HH:mm:ss") }}
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item prepend-icon="mdi-truck">
|
||||||
|
{{ orderStore.order.shipped ? 'Versendet' : 'Nicht versendet' }}
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item>
|
||||||
|
<v-table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ $t('concert.date') }}</th>
|
||||||
|
<th>{{ $t('concert.name') }}</th>
|
||||||
|
<th>{{ $t('band.name') }}</th>
|
||||||
|
<th>{{ $t('location.name') }}</th>
|
||||||
|
<th>{{ $t('location.seat.seatGroup') }}</th>
|
||||||
|
<th>{{ $t('location.seat.seatRow') }}</th>
|
||||||
|
<th>{{ $t('location.seat.seat') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="ticket of orderStore.order.tickets">
|
||||||
|
<td>{{ moment(ticket.concert.date).format("DD.MM.YYYY") }}</td>
|
||||||
|
<td>{{ ticket.concert.name }}</td>
|
||||||
|
<td>{{ ticket.concert.band.name }}</td>
|
||||||
|
<td>{{ ticket.concert.location.name }}</td>
|
||||||
|
<td>{{ ticket.seat.seatRow.seatGroup.name }}</td>
|
||||||
|
<td>{{ ticket.seat.seatRow.row }}</td>
|
||||||
|
<td>{{ ticket.seat.seatNr }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</v-table>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</action-dialog>
|
</action-dialog>
|
||||||
|
|||||||
@@ -19,6 +19,22 @@ function getDotColor(exerciseGroupNr: number) {
|
|||||||
case 3: return "pink"
|
case 3: return "pink"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateExerciseKey() {
|
||||||
|
try {
|
||||||
|
let code = ""
|
||||||
|
|
||||||
|
for (let i = 0; i < 13; i++) {
|
||||||
|
if (exerciseStore.exercises[i].solved) {
|
||||||
|
code += "3"
|
||||||
|
} else {
|
||||||
|
code += "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Number(code) + Number(preferencesStore.registrationNumber)) * 237
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -26,20 +42,7 @@ function getDotColor(exerciseGroupNr: number) {
|
|||||||
<v-row>
|
<v-row>
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
|
|
||||||
<v-col
|
|
||||||
v-if="preferencesStore.studentName.length < 3 || preferencesStore.registrationNumber.length < 7"
|
|
||||||
cols="auto"
|
|
||||||
>
|
|
||||||
<card-view variant="outlined" >
|
|
||||||
{{ $t('misc.fulfillYourPersonalDataFirst') }}
|
|
||||||
</card-view>
|
|
||||||
</v-col>
|
|
||||||
|
|
||||||
<v-col cols="auto">
|
<v-col cols="auto">
|
||||||
<v-tooltip :text="$t('misc.fulfillYourPersonalDataFirst')">
|
|
||||||
<template #activator="{ props }"></template>
|
|
||||||
|
|
||||||
</v-tooltip>
|
|
||||||
<outlined-button
|
<outlined-button
|
||||||
prepend-icon="mdi-file-pdf-box"
|
prepend-icon="mdi-file-pdf-box"
|
||||||
@click="generateResultsPdf()"
|
@click="generateResultsPdf()"
|
||||||
@@ -50,6 +53,17 @@ function getDotColor(exerciseGroupNr: number) {
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col class="text-h5 text-center">
|
||||||
|
<div>
|
||||||
|
Persönlicher Lösungsschlüssel:
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ generateExerciseKey() }}
|
||||||
|
</div>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
<card-view
|
<card-view
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import actionDialog from '@/components/basics/actionDialog.vue';
|
import actionDialog from '@/components/basics/actionDialog.vue';
|
||||||
import outlinedButton from '@/components/basics/outlinedButton.vue';
|
import outlinedButton from '@/components/basics/outlinedButton.vue';
|
||||||
import ServerStateText from '@/components/pageParts/serverStateText.vue';
|
import ServerStateText from '@/components/pageParts/serverStateText.vue';
|
||||||
|
import { getRegisterNumberRules, getStringRules } from '@/scripts/validationRules';
|
||||||
import { useFeedbackStore } from '@/stores/feedback.store';
|
import { useFeedbackStore } from '@/stores/feedback.store';
|
||||||
import { usePreferencesStore } from '@/stores/preferences.store';
|
import { usePreferencesStore } from '@/stores/preferences.store';
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
@@ -135,9 +136,9 @@ watch(() => currentStep.value, () => {
|
|||||||
<v-col>
|
<v-col>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
hide-details
|
|
||||||
:label="$t('misc.yourFullName')"
|
:label="$t('misc.yourFullName')"
|
||||||
v-model="preferencesStore.studentName"
|
v-model="preferencesStore.studentName"
|
||||||
|
:rules="getStringRules(4)"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
@@ -146,9 +147,9 @@ watch(() => currentStep.value, () => {
|
|||||||
<v-col>
|
<v-col>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
hide-details
|
|
||||||
:label="$t('misc.registrationNumber')"
|
:label="$t('misc.registrationNumber')"
|
||||||
v-model="preferencesStore.registrationNumber"
|
v-model="preferencesStore.registrationNumber"
|
||||||
|
:rules="getRegisterNumberRules()"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
@@ -177,8 +178,8 @@ watch(() => currentStep.value, () => {
|
|||||||
<outlined-button
|
<outlined-button
|
||||||
v-else
|
v-else
|
||||||
@click="showDialog = false; preferencesStore.firstStartup = false"
|
@click="showDialog = false; preferencesStore.firstStartup = false"
|
||||||
:disabled="preferencesStore.studentName.length == 0 ||
|
:disabled="preferencesStore.studentName.length < 5 ||
|
||||||
preferencesStore.registrationNumber.length == 0"
|
preferencesStore.registrationNumber.length < 8"
|
||||||
prepend-icon="mdi-check"
|
prepend-icon="mdi-check"
|
||||||
color="success"
|
color="success"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import PreferencesPage from "@/pages/misc/preferencesPage/index.vue";
|
|||||||
import HelpPage from "@/pages/misc/helpPage/index.vue"
|
import HelpPage from "@/pages/misc/helpPage/index.vue"
|
||||||
import ErrorPage from "@/pages/misc/errorPage/index.vue"
|
import ErrorPage from "@/pages/misc/errorPage/index.vue"
|
||||||
import ImageLicensePage from "@/pages/misc/imageLicensePage/index.vue"
|
import ImageLicensePage from "@/pages/misc/imageLicensePage/index.vue"
|
||||||
|
import AccountPaymentsPage from "@/pages/account/accountPaymentsPage/index.vue"
|
||||||
|
import AccountAddressesPage from "@/pages/account/accountAddressesPage/index.vue"
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
// Main page
|
// Main page
|
||||||
@@ -32,6 +34,8 @@ const routes = [
|
|||||||
{ path: '/account/orders', component: OrdersPage },
|
{ path: '/account/orders', component: OrdersPage },
|
||||||
{ path: '/account/data', component: AccountDataPage },
|
{ path: '/account/data', component: AccountDataPage },
|
||||||
{ path: '/account/login', component: LoginPage },
|
{ path: '/account/login', component: LoginPage },
|
||||||
|
{ path: '/account/payments', component: AccountPaymentsPage },
|
||||||
|
{ path: '/account/addresses', component: AccountAddressesPage },
|
||||||
|
|
||||||
// Admin
|
// Admin
|
||||||
...adminRoutes,
|
...adminRoutes,
|
||||||
|
|||||||
@@ -20,4 +20,16 @@ export function dateToHumanReadableString(date: Date) {
|
|||||||
*/
|
*/
|
||||||
export function dateStringToHumanReadableString(string: string) {
|
export function dateStringToHumanReadableString(string: string) {
|
||||||
return dateToHumanReadableString(new Date(string))
|
return dateToHumanReadableString(new Date(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format milliseconds to a readable format
|
||||||
|
*
|
||||||
|
* @param milliseconds Milliseconds to format
|
||||||
|
*
|
||||||
|
* @returns h:mm format
|
||||||
|
*/
|
||||||
|
export function millisecondsToHumanReadableString(milliseconds: number): string {
|
||||||
|
return Math.floor(milliseconds / 1000 / 60 / 60) + ':' +
|
||||||
|
String(Math.floor(milliseconds / 60000)).padStart(2, "0") + ''
|
||||||
}
|
}
|
||||||
@@ -168,4 +168,32 @@ export function getIbanRules() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRegisterNumberRules() {
|
||||||
|
const feedbackStore = useFeedbackStore()
|
||||||
|
|
||||||
|
return [
|
||||||
|
value => {
|
||||||
|
if (value) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return feedbackStore.i18n.t('misc.validation.required')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value => {
|
||||||
|
if (value?.length >= 8) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return feedbackStore.i18n.t('misc.validation.notEnoughChars')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value => {
|
||||||
|
if(!isNaN(value) && !isNaN(parseFloat(value))) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return feedbackStore.i18n.t('misc.validation.onlyDigitsAllowed')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ import { AccountApiModel } from "../data/models/user/accountApiModel";
|
|||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { useExerciseStore } from "./exercise.store";
|
import { useExerciseStore } from "./exercise.store";
|
||||||
|
import moment, { Moment } from "moment";
|
||||||
|
|
||||||
export const useAccountStore = defineStore("accountStore", {
|
export const useAccountStore = defineStore("accountStore", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@@ -17,10 +18,10 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
accounts: ref<Array<AccountApiModel>>([]),
|
accounts: ref<Array<AccountApiModel>>([]),
|
||||||
|
|
||||||
/** Server token of currently logged in account */
|
/** Server token of currently logged in account */
|
||||||
userAccountToken: useLocalStorage("hackmycart/accountStore/userAccountToken", ""),
|
userAccountToken: useLocalStorage("eventMaster/accountStore/userAccountToken", ""),
|
||||||
|
|
||||||
/** Useraccount which is currently logged in */
|
/** Useraccount which is currently logged in */
|
||||||
userAccount: useLocalStorage("hackmycart/accountStore/userAccount", new AccountApiModel()),
|
userAccount: useLocalStorage("eventMaster/accountStore/userAccount", new AccountApiModel()),
|
||||||
|
|
||||||
/** User input on login screen */
|
/** User input on login screen */
|
||||||
loginData: ref<{ username: String, password: String}>(
|
loginData: ref<{ username: String, password: String}>(
|
||||||
@@ -37,7 +38,15 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
adminPanelVisible: ref(false),
|
adminPanelVisible: ref(false),
|
||||||
|
|
||||||
/** Flag to activate buy option on basket page */
|
/** Flag to activate buy option on basket page */
|
||||||
privilegeBuy: ref(false)
|
privilegeBuy: ref(false),
|
||||||
|
|
||||||
|
payment: ref(),
|
||||||
|
|
||||||
|
address: ref(),
|
||||||
|
|
||||||
|
showEditDialog: ref(false),
|
||||||
|
|
||||||
|
loggedInTimeStamp: useLocalStorage<string>("eventMaster/accountStore/loggedInTimeStamp", "")
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
@@ -80,6 +89,7 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
await getLogin(this.loginData.username, this.loginData.password)
|
await getLogin(this.loginData.username, this.loginData.password)
|
||||||
.then(async result => {
|
.then(async result => {
|
||||||
this.userAccountToken = result.data.token
|
this.userAccountToken = result.data.token
|
||||||
|
this.loggedInTimeStamp = moment().format("YYYY-MM-DDTHH:mm:ss.SSS")
|
||||||
|
|
||||||
getAccount(this.userAccountToken)
|
getAccount(this.userAccountToken)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
@@ -91,7 +101,7 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
this.privilegeBuy = true
|
this.privilegeBuy = true
|
||||||
this.adminPanelVisible = response.data.accountRole.privilegeAdminPanel
|
this.adminPanelVisible = response.data.accountRole.privilegeAdminPanel
|
||||||
|
|
||||||
if (response.data.accountRoleId == 3) {
|
if (response.data.accountRoleId == 2) {
|
||||||
exerciseStore.solveExercise(2, 5)
|
exerciseStore.solveExercise(2, 5)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -113,14 +123,16 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
* Reload account information about current logged in user
|
* Reload account information about current logged in user
|
||||||
*/
|
*/
|
||||||
async refreshAccount() {
|
async refreshAccount() {
|
||||||
|
this.fetchInProgress = true
|
||||||
|
|
||||||
getAccount(this.userAccountToken)
|
getAccount(this.userAccountToken)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.userAccount = response.data
|
this.userAccount = response.data
|
||||||
|
|
||||||
this.fetchInProgress = false
|
|
||||||
|
|
||||||
this.privilegeBuy = true
|
this.privilegeBuy = true
|
||||||
this.adminPanelVisible = response.data.accountRole.privilegeAdminPanel
|
this.adminPanelVisible = response.data.accountRole.privilegeAdminPanel
|
||||||
|
|
||||||
|
this.fetchInProgress = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -133,6 +145,7 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
async registerAccount(): Promise<boolean> {
|
async registerAccount(): Promise<boolean> {
|
||||||
const feedbackStore = useFeedbackStore()
|
const feedbackStore = useFeedbackStore()
|
||||||
const exerciseStore = useExerciseStore()
|
const exerciseStore = useExerciseStore()
|
||||||
|
let success = false
|
||||||
this.fetchInProgress = true
|
this.fetchInProgress = true
|
||||||
|
|
||||||
if (this.registerData.username == null || this.registerData.username.length < 4) {
|
if (this.registerData.username == null || this.registerData.username.length < 4) {
|
||||||
@@ -142,7 +155,8 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
} else if (!this.registerData.email.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)) {
|
} else if (!this.registerData.email.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)) {
|
||||||
feedbackStore.addSnackbar(BannerStateEnum.ACCOUNTMAILADDRESSUNVALID)
|
feedbackStore.addSnackbar(BannerStateEnum.ACCOUNTMAILADDRESSUNVALID)
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
await registerAccount(this.registerData)
|
await registerAccount(this.registerData)
|
||||||
.then(async res => {
|
.then(async res => {
|
||||||
if (res.status == 201) {
|
if (res.status == 201) {
|
||||||
@@ -156,6 +170,7 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.fetchInProgress = false
|
this.fetchInProgress = false
|
||||||
|
success = true
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.status == 400) {
|
if (error.status == 400) {
|
||||||
@@ -165,12 +180,11 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.fetchInProgress = false
|
this.fetchInProgress = false
|
||||||
return false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fetchInProgress = false
|
this.fetchInProgress = false
|
||||||
return false
|
return success
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -179,6 +193,7 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
async updateAccount() {
|
async updateAccount() {
|
||||||
const feedbackStore = useFeedbackStore()
|
const feedbackStore = useFeedbackStore()
|
||||||
const exerciseStore = useExerciseStore()
|
const exerciseStore = useExerciseStore()
|
||||||
|
this.fetchInProgress = true
|
||||||
|
|
||||||
// Check for exercise 0.2 completion
|
// Check for exercise 0.2 completion
|
||||||
let accountComplete = this.userAccount.firstName != "" && this.userAccount.lastName != "" &&
|
let accountComplete = this.userAccount.firstName != "" && this.userAccount.lastName != "" &&
|
||||||
@@ -196,6 +211,7 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
feedbackStore.addSnackbar(BannerStateEnum.ACCOUNTUPDATESUCCESSFUL)
|
feedbackStore.addSnackbar(BannerStateEnum.ACCOUNTUPDATESUCCESSFUL)
|
||||||
|
|
||||||
this.userAccount = res.data
|
this.userAccount = res.data
|
||||||
|
this.fetchInProgress = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -222,13 +238,40 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
async refreshOrders() {
|
async refreshOrders() {
|
||||||
this.fetchInProgress = true
|
this.fetchInProgress = true
|
||||||
|
|
||||||
await fetchUserOrders(this.userAccount.id)
|
await fetchUserOrders(this.userAccount.id, this.userAccountToken)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
this.orders = result.data
|
this.orders = result.data
|
||||||
this.fetchInProgress = false
|
this.fetchInProgress = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
newAddress() {
|
||||||
|
this.address = new AddressModel()
|
||||||
|
this.showEditDialog = true
|
||||||
|
},
|
||||||
|
|
||||||
|
editAddress(address: AddressModel) {
|
||||||
|
this.address = address
|
||||||
|
this.showEditDialog = true
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveAddress() {
|
||||||
|
this.fetchInProgress = true
|
||||||
|
|
||||||
|
if (this.address.id == undefined) {
|
||||||
|
this.userAccount.addresses.push(this.address)
|
||||||
|
} else {
|
||||||
|
this.userAccount.addresses = this.userAccount.addresses.filter(address => {
|
||||||
|
return address.id != this.address.id
|
||||||
|
})
|
||||||
|
|
||||||
|
this.userAccount.addresses.push(this.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.updateAccount()
|
||||||
|
this.showEditDialog = false
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an address from the user model
|
* Remove an address from the user model
|
||||||
*
|
*
|
||||||
@@ -238,17 +281,59 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
this.userAccount.addresses = this.userAccount.addresses.filter((addr: AddressModel) =>
|
this.userAccount.addresses = this.userAccount.addresses.filter((addr: AddressModel) =>
|
||||||
addr != address
|
addr != address
|
||||||
)
|
)
|
||||||
|
|
||||||
|
this.updateAccount()
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an payment from the user model
|
* Add a new payment, opens dialog
|
||||||
|
*/
|
||||||
|
newPayment() {
|
||||||
|
this.payment = new PaymentModel()
|
||||||
|
this.showEditDialog = true
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit existing payment, opens dialog
|
||||||
|
*
|
||||||
|
* @param payment Payment dataset to edit
|
||||||
|
*/
|
||||||
|
editPayment(payment: PaymentModel) {
|
||||||
|
this.payment = payment
|
||||||
|
this.showEditDialog = true
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save current edited payment
|
||||||
|
*/
|
||||||
|
async savePayment() {
|
||||||
|
this.fetchInProgress = true
|
||||||
|
|
||||||
|
if (this.payment.id == undefined) {
|
||||||
|
this.userAccount.payments.push(this.payment)
|
||||||
|
} else {
|
||||||
|
this.userAccount.payments = this.userAccount.payments.filter(payment => {
|
||||||
|
return payment.id != this.payment.id
|
||||||
|
})
|
||||||
|
|
||||||
|
this.userAccount.payments.push(this.payment)
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.updateAccount()
|
||||||
|
this.showEditDialog = false
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a payment from the user model
|
||||||
*
|
*
|
||||||
* @param address Payment dataset to remove
|
* @param address Payment dataset to remove
|
||||||
*/
|
*/
|
||||||
removePayment(payment: PaymentModel) {
|
async removePayment(payment: PaymentModel) {
|
||||||
this.userAccount.payments = this.userAccount.payments.filter((paym: PaymentModel) =>
|
this.userAccount.payments = await this.userAccount.payments.filter((paym: PaymentModel) =>
|
||||||
paym != payment
|
paym != payment
|
||||||
)
|
)
|
||||||
|
|
||||||
|
this.updateAccount()
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -259,7 +344,7 @@ export const useAccountStore = defineStore("accountStore", {
|
|||||||
async deleteAccount(account: AccountModel) {
|
async deleteAccount(account: AccountModel) {
|
||||||
this.fetchInProgress = true
|
this.fetchInProgress = true
|
||||||
|
|
||||||
deleteAccount(account)
|
deleteAccount(account, this.userAccountToken)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.fetchInProgress = false
|
this.fetchInProgress = false
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { useExerciseStore } from "./exercise.store";
|
|||||||
export const useBasketStore = defineStore('basketStore', {
|
export const useBasketStore = defineStore('basketStore', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
/** Items in customers basket */
|
/** Items in customers basket */
|
||||||
itemsInBasket: useLocalStorage<Array<BasketItemModel>>("hackmycart/basketStore/itemsInBasket", []),
|
itemsInBasket: useLocalStorage<Array<BasketItemModel>>("eventMaster/basketStore/itemsInBasket", []),
|
||||||
|
|
||||||
/** Address used in the order dialog */
|
/** Address used in the order dialog */
|
||||||
usedAddress: ref<AddressModel>(null),
|
usedAddress: ref<AddressModel>(null),
|
||||||
@@ -100,10 +100,10 @@ export const useBasketStore = defineStore('basketStore', {
|
|||||||
const exerciseStore = useExerciseStore()
|
const exerciseStore = useExerciseStore()
|
||||||
|
|
||||||
await createOrder(
|
await createOrder(
|
||||||
accountStore.userAccount.id,
|
|
||||||
this.itemsInBasket,
|
this.itemsInBasket,
|
||||||
this.usedPayment.id,
|
this.usedPayment.id,
|
||||||
this.usedAddress.id
|
this.usedAddress.id,
|
||||||
|
accountStore.userAccountToken
|
||||||
)
|
)
|
||||||
.then(async result => {
|
.then(async result => {
|
||||||
if (result.status == 201) {
|
if (result.status == 201) {
|
||||||
@@ -119,7 +119,6 @@ export const useBasketStore = defineStore('basketStore', {
|
|||||||
for (let item of this.itemsInBasket) {
|
for (let item of this.itemsInBasket) {
|
||||||
if (!item.concert.offered) {
|
if (!item.concert.offered) {
|
||||||
exerciseStore.solveExercise(1, 2)
|
exerciseStore.solveExercise(1, 2)
|
||||||
feedbackStore.addSnackbar(BannerStateEnum.EXERCISESOLVED12)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,13 +95,5 @@ export const useConcertStore = defineStore("concertStore", {
|
|||||||
this.concert = new ConcertDetailsApiModel()
|
this.concert = new ConcertDetailsApiModel()
|
||||||
this.showEditDialog = true
|
this.showEditDialog = true
|
||||||
},
|
},
|
||||||
|
|
||||||
editConcert(concert: ConcertModel) {
|
|
||||||
// todo
|
|
||||||
},
|
|
||||||
|
|
||||||
async deleteConcert(item: ConcertModel) {
|
|
||||||
// todo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1,16 +1,19 @@
|
|||||||
import { fetchAllOrders, fetchUserOrders } from "@/data/api/orderApi";
|
import { fetchAllOrders, fetchUserOrders, patchOrder } from "@/data/api/orderApi";
|
||||||
import { OrderApiModel } from "@/data/models/apiEndpoints/orderApiModel";
|
import { OrderApiModel } from "@/data/models/apiEndpoints/orderApiModel";
|
||||||
import { AccountModel } from "@/data/models/user/accountModel";
|
import { AccountModel } from "@/data/models/user/accountModel";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
import { useAccountStore } from "./account.store";
|
||||||
|
|
||||||
export const useOrderStore = defineStore("orderStore", {
|
export const useOrderStore = defineStore("orderStore", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
/** All orders of one/all users */
|
/** All orders of one/all users */
|
||||||
orders: ref<Array<OrderApiModel>>([]),
|
orders: ref<Array<OrderApiModel>>([]),
|
||||||
|
|
||||||
|
/** Current selected order */
|
||||||
order: ref<OrderApiModel>(new OrderApiModel),
|
order: ref<OrderApiModel>(new OrderApiModel),
|
||||||
|
|
||||||
|
/** Show detail dialog on admin page */
|
||||||
showDetailDialog: ref<boolean>(false),
|
showDetailDialog: ref<boolean>(false),
|
||||||
|
|
||||||
/** Request to server sent, waiting for data response */
|
/** Request to server sent, waiting for data response */
|
||||||
@@ -22,9 +25,10 @@ export const useOrderStore = defineStore("orderStore", {
|
|||||||
* Get all orders from all accounts from server
|
* Get all orders from all accounts from server
|
||||||
*/
|
*/
|
||||||
async getAllOrders() {
|
async getAllOrders() {
|
||||||
|
const accountStore = useAccountStore()
|
||||||
this.fetchInProgress = true
|
this.fetchInProgress = true
|
||||||
|
|
||||||
fetchAllOrders()
|
fetchAllOrders(accountStore.userAccountToken)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.orders = res.data
|
this.orders = res.data
|
||||||
this.fetchInProgress = false
|
this.fetchInProgress = false
|
||||||
@@ -36,23 +40,41 @@ export const useOrderStore = defineStore("orderStore", {
|
|||||||
*
|
*
|
||||||
* @param user User to request orders from
|
* @param user User to request orders from
|
||||||
*/
|
*/
|
||||||
async getOrdersOfAccount(user: AccountModel) {
|
async getOrdersOfAccount(user: AccountModel, token: string) {
|
||||||
this.fetchInProgress = true
|
this.fetchInProgress = true
|
||||||
|
|
||||||
fetchUserOrders(user.id)
|
fetchUserOrders(user.id, token)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.orders = res.data
|
this.orders = res.data
|
||||||
this.fetchInProgress = false
|
this.fetchInProgress = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open detail dialog
|
||||||
|
*
|
||||||
|
* @param order Order to view
|
||||||
|
*/
|
||||||
openDetails(order: OrderApiModel) {
|
openDetails(order: OrderApiModel) {
|
||||||
this.order = order
|
this.order = order
|
||||||
this.showDetailDialog = true
|
this.showDetailDialog = true
|
||||||
},
|
},
|
||||||
|
|
||||||
async deleteOrder(order: OrderApiModel) {
|
|
||||||
// todo
|
/**
|
||||||
|
*
|
||||||
|
* @param order
|
||||||
|
* @param shipped
|
||||||
|
*/
|
||||||
|
async changeOrderShippedState(order: OrderApiModel, shipped: boolean) {
|
||||||
|
this.fetchInProgress = true
|
||||||
|
|
||||||
|
order.shipped = shipped
|
||||||
|
|
||||||
|
patchOrder(order)
|
||||||
|
.then(res => {
|
||||||
|
this.getAllOrders()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -15,10 +15,10 @@ import { AccountApiModel } from "@/data/models/user/accountApiModel";
|
|||||||
export const usePreferencesStore = defineStore('preferencesStore', {
|
export const usePreferencesStore = defineStore('preferencesStore', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
/** Selected theme by user */
|
/** Selected theme by user */
|
||||||
theme: useLocalStorage<ThemeEnum>("hackmycart/preferencesStore/theme", ThemeEnum.DARK),
|
theme: useLocalStorage<ThemeEnum>("eventMaster/preferencesStore/theme", ThemeEnum.DARK),
|
||||||
|
|
||||||
/** Selected language by user */
|
/** Selected language by user */
|
||||||
language: useLocalStorage<LanguageEnum>("hackmycart/preferencesStore/language", LanguageEnum.GERMAN),
|
language: useLocalStorage<LanguageEnum>("eventMaster/preferencesStore/language", LanguageEnum.GERMAN),
|
||||||
|
|
||||||
/** Request to server sent, waiting for data response */
|
/** Request to server sent, waiting for data response */
|
||||||
fetchInProgress: ref(false),
|
fetchInProgress: ref(false),
|
||||||
@@ -36,13 +36,13 @@ export const usePreferencesStore = defineStore('preferencesStore', {
|
|||||||
showFactoryResetDialog: ref(false),
|
showFactoryResetDialog: ref(false),
|
||||||
|
|
||||||
/** Marks the first run of the app */
|
/** Marks the first run of the app */
|
||||||
firstStartup: useLocalStorage<Boolean>("hackmycart/preferencesStore/firstStartup", true),
|
firstStartup: useLocalStorage<Boolean>("eventMaster/preferencesStore/firstStartup", true),
|
||||||
|
|
||||||
/** Full name of student */
|
/** Full name of student */
|
||||||
studentName: useLocalStorage<string>("hackmycart/preferencesStore/studentName", ""),
|
studentName: useLocalStorage<string>("eventMaster/preferencesStore/studentName", ""),
|
||||||
|
|
||||||
/** Matrikel number */
|
/** Matrikel number */
|
||||||
registrationNumber: useLocalStorage<string>("hackmycart/preferencesStore/registrationNumber", "")
|
registrationNumber: useLocalStorage<string>("eventMaster/preferencesStore/registrationNumber", "")
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export const useSearchStore = defineStore("searchStore", {
|
|||||||
|
|
||||||
|
|
||||||
// Check for exercise solution
|
// Check for exercise solution
|
||||||
if (result.data.length != 0) {
|
if (this.searchTerm.toUpperCase().includes("SELECT")) {
|
||||||
// Exercise 2.1
|
// Exercise 2.1
|
||||||
if (result.data[0].type != undefined && result.data[0].type == "table") {
|
if (result.data[0].type != undefined && result.data[0].type == "table") {
|
||||||
exerciseStore.solveExercise(2, 1)
|
exerciseStore.solveExercise(2, 1)
|
||||||
@@ -68,7 +68,7 @@ export const useSearchStore = defineStore("searchStore", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exercise 2.4
|
// Exercise 2.4
|
||||||
else if (this.searchTerm.includes("UPDATE")) {
|
else if (this.searchTerm.toUpperCase().includes("UPDATE")) {
|
||||||
const accountStore = useAccountStore()
|
const accountStore = useAccountStore()
|
||||||
await accountStore.refreshAccount()
|
await accountStore.refreshAccount()
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ export const useSearchStore = defineStore("searchStore", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exercise 2.6
|
// Exercise 2.6
|
||||||
else if (this.searchTerm.includes("DELETE")) {
|
else if (this.searchTerm.toUpperCase().includes("DELETE")) {
|
||||||
const bandStore = useBandStore()
|
const bandStore = useBandStore()
|
||||||
await bandStore.getBand("muse")
|
await bandStore.getBand("muse")
|
||||||
|
|
||||||
@@ -92,6 +92,7 @@ export const useSearchStore = defineStore("searchStore", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
// Normal behaviour
|
||||||
this.bands = result.data
|
this.bands = result.data
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user