Compare commits
179 Commits
debug/loca
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| 861b592864 | |||
| 04cd85fe59 | |||
| 373b57cec8 | |||
| fb3b0fced5 | |||
| 607cb4fc7d | |||
| 39001b37a3 | |||
| d6becc43ea | |||
| f68e9ee218 | |||
| 18f6d53998 | |||
| 4b8e878735 | |||
| 3f7da82ea6 | |||
| c1e3e8939a | |||
| dc98b1d500 | |||
| a50cd9cc9a | |||
| d06669e943 | |||
| 60baf02299 | |||
| ae2ce859ad | |||
| 44dd6010d7 | |||
| 9116841292 | |||
| b5dd7422f4 | |||
| 63a3ce2f6f | |||
| 8cc3444626 | |||
| 6362f47d43 | |||
| c6954fb222 | |||
| 6d8b86280c | |||
| 2a1570d9f5 | |||
| 14cfb41591 | |||
| 62bd6304c4 | |||
| 7fea4d27b7 | |||
| 03b434b801 | |||
| dbd7347ac9 | |||
| ac15a6c2cf | |||
| c27685df6e | |||
| 6610532c90 | |||
| d180dac600 | |||
| 8b4131332b | |||
| 27b9f46f30 | |||
| c8550431e0 | |||
| a1b807824e | |||
| 189626d61c | |||
| 7b08eafd84 | |||
| 9e1c654826 | |||
| ec925c1eb6 | |||
| d879d8cc5c | |||
| 4885c6a0ff | |||
| 7baa7b0220 | |||
| a3a8ef3b39 | |||
| fd5dbc8b37 | |||
| 6cbc8df5f5 | |||
| bc3d5678ed | |||
| 545910c9b8 | |||
| 9dc4673b3b | |||
| 3d76acb2f0 | |||
| 98c05aed3b | |||
| 98696aee93 | |||
| 7f706dfc51 | |||
| ab12e28d3d | |||
| e9a7e03ebf | |||
| f1c5bd3cd8 | |||
| bb13d74849 | |||
| 55cf17d169 | |||
| ea634a3af2 | |||
| 21471d4d41 | |||
| fce897fae4 | |||
| 64c6607076 | |||
| 6dedc04957 | |||
| 213f7cf58c | |||
| 49a8498bbe | |||
| e84a73465d | |||
| 2d61565c29 | |||
| 753d8a4465 | |||
| 654518e642 | |||
| 7840406688 | |||
| 1f860baa2b | |||
| 5eb1074a79 | |||
| ba8778cc3f | |||
| 6b173495af | |||
| cda3f231a7 | |||
| 91caf74dca | |||
| b36e2c9e05 | |||
| 0c6c3a048d | |||
| 1e6e34df77 | |||
| f7a43ca971 | |||
| e103743d5e | |||
| 710e21e567 | |||
| afe31e504a | |||
| 1fd87edd6e | |||
| a648cc2e71 | |||
| 880a8a2a8d | |||
| f7684902aa | |||
| f218e5f96a | |||
| 4d5d63dbdd | |||
| 622ab6b4a3 | |||
| 47da3ff475 | |||
| 7813203790 | |||
| 331ffcd10c | |||
| 14244e2f48 | |||
| 3e2b9f649c | |||
| 02947ce6e5 | |||
| fc6c6179b8 | |||
| 7548de7609 | |||
| e5d9d051ea | |||
| 50cecc6a9d | |||
| ebb2182c4c | |||
| 023f3357f3 | |||
| dd3f000f84 | |||
| 573ab2d808 | |||
| 9b69e4f50c | |||
| be46e79a67 | |||
| 7d4f202692 | |||
| 44f5d07ed7 | |||
| 941b5e70fb | |||
| 97a9e0bcf7 | |||
| 4acf8d7c29 | |||
| 74b15e4b64 | |||
| e60a623753 | |||
| ddae95b784 | |||
| 184d15554b | |||
| 0d9e4ac026 | |||
| 6bfb0d3e23 | |||
| 25013b4edc | |||
| 3775d6775c | |||
| 9bb847242c | |||
| 2576127b79 | |||
| 08792c5fa7 | |||
| effbf42303 | |||
| b070979723 | |||
| d6e3ae20c1 | |||
| b5a8a3d31c | |||
| be5859424d | |||
| 72d3ad05bf | |||
| 0d7861ec36 | |||
| 4531eda8f1 | |||
| b5b78a9c7e | |||
| f0720b9b1d | |||
| bac3421a64 | |||
| 11098da25b | |||
|
|
fb8b732b1d | ||
| 4a0943c64f | |||
| 2a47dd6534 | |||
| dd5d334e96 | |||
| 34c91497f3 | |||
| e18188cd85 | |||
| 4b1f773c6f | |||
| 1d64a83d32 | |||
| 0eaea46409 | |||
| f3c5111265 | |||
| d7919922fc | |||
| 90d32a26f1 | |||
| ed6f5ab648 | |||
| 12c1fc59b1 | |||
| a06ec0eabb | |||
| de94d63a41 | |||
| 3b3601baeb | |||
|
|
7abf0e26e2 | ||
|
|
cc29320c87 | ||
| 402c9807c9 | |||
| 6215449bc8 | |||
| 80ad3e8e5a | |||
| 948684455d | |||
| 0e7493366c | |||
| 775fa3a7e2 | |||
| 5ce866936d | |||
| a68a768277 | |||
| 489dfc2ed6 | |||
| c796be2892 | |||
| 6a6ffa38f9 | |||
| a2c56e9696 | |||
| cc17e6c33a | |||
| 5625cbac49 | |||
| 79ed86937c | |||
| 76995a84e4 | |||
| 759532733c | |||
| 6cfd311bbb | |||
| 8b4c9e2590 | |||
|
|
ff060edcfa | ||
| de7a9a05f2 | |||
| bbc705cf63 | |||
| 9b038b3571 |
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@ -12,7 +12,8 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"FLASK_APP": "src/server/BreCal",
|
"FLASK_APP": "src/server/BreCal",
|
||||||
"FLASK_DEBUG": "1",
|
"FLASK_DEBUG": "1",
|
||||||
"SECRET_KEY" : "zdiTz8P3jXOc7jztIQAoelK4zztyuCpJ" // https://randomkeygen.com/
|
"SECRET_KEY" : "zdiTz8P3jXOc7jztIQAoelK4zztyuCpJ", // https://randomkeygen.com/
|
||||||
|
"FLASK_RUN_PORT": "5000"
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
"run",
|
"run",
|
||||||
|
|||||||
1347
misc/BreCalApi.cs
1347
misc/BreCalApi.cs
File diff suppressed because it is too large
Load Diff
537
misc/BreCalApi.md
Normal file
537
misc/BreCalApi.md
Normal file
@ -0,0 +1,537 @@
|
|||||||
|
# Bremen calling API
|
||||||
|
Version: _1.7.0_
|
||||||
|
Last change: _Nov 14, 2025_
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
This API allows users to interact with "Bremen calling" without an UI. Apart vom querying data via _GET_ endpoints users may create and update shipcalls, assign participants and update participant times for shipcalls.
|
||||||
|
|
||||||
|
Creating and updating times and shipcalls depend on the participant roles a user is assigned to. For example, if a participant has the role "AGENCY" they may change assignments _and_ create and update agency times. A participant with the role "PILOT" on the other hand may not change the assigments and only create/update times for the pilot.
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
- **ApiKey**: API key in `header` header named `Authorization`. This is a JWT Token that the caller receives upon login.
|
||||||
|
|
||||||
|
### Notes on this version
|
||||||
|
|
||||||
|
This version refers to _1.7_ whereas the public client currently has version _1.6_. This means that there is some functionality available in the API that cannot be accessed through the UI yet, specifically notifications.
|
||||||
|
|
||||||
|
There is no documentation for the structures returned by _GET_ requests but these can easily be determined via a single query.
|
||||||
|
|
||||||
|
## Ship Endpoints
|
||||||
|
|
||||||
|
### `DELETE /ships`
|
||||||
|
**Summary:** Delete a ship (logically).
|
||||||
|
A ship can only be logically deleted, since it is possible to have been used in previous shipcalls. On logical delete, the ship can no longer be selected in a new ship call.
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | In | Type | Required | Description |
|
||||||
|
|------|----|------|----------|-------------|
|
||||||
|
| id | query | integer | Yes | **Id of ship**. *Example: 42*. Id of ship to be deleted. |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /ships`
|
||||||
|
**Summary:** gets a list of ships
|
||||||
|
Gets a list of ships including logically deleted ships to be used with shipcalls
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**: list of ships
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `POST /ships`
|
||||||
|
**Summary:** create a new ship entry
|
||||||
|
adds a new non-existing ship to the database. The ships IMO number is the unique identifier.
|
||||||
|
|
||||||
|
#### Request Body
|
||||||
|
Ship details. **Do not** provide id parameter.
|
||||||
|
|
||||||
|
**JSON Schema**
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| id | integer | No | |
|
||||||
|
| name | string | No | |
|
||||||
|
| imo | integer | No | |
|
||||||
|
| callsign | string | No | |
|
||||||
|
| participant_id | integer | No | Optional reference to participant (tug role) |
|
||||||
|
| length | number | No | |
|
||||||
|
| width | number | No | |
|
||||||
|
| is_tug | boolean | No | |
|
||||||
|
| bollard_pull | integer | No | |
|
||||||
|
| eni | integer | No | BSMD internal use |
|
||||||
|
| created | string | No | Readonly field set by the database when ship was created |
|
||||||
|
| modified | string | No | Readonly field set by the database when ship was last modified |
|
||||||
|
| deleted | boolean | No | marks the ship as logically deleted |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **201**
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `PUT /ships`
|
||||||
|
**Summary:** Update a ship entry
|
||||||
|
Updating a ship entry. Please do not modify the IMO number. In that case please add a new entry.
|
||||||
|
|
||||||
|
#### Request Body
|
||||||
|
Updated ship entry. The id parameter is **required**.
|
||||||
|
|
||||||
|
**JSON Schema**
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| id | integer | No | |
|
||||||
|
| name | string | No | |
|
||||||
|
| imo | integer | No | |
|
||||||
|
| callsign | string | No | |
|
||||||
|
| participant_id | integer | No | Optional reference to participant (tug role) |
|
||||||
|
| length | number | No | |
|
||||||
|
| width | number | No | |
|
||||||
|
| is_tug | boolean | No | |
|
||||||
|
| bollard_pull | integer | No | |
|
||||||
|
| eni | integer | No | BSMD internal use |
|
||||||
|
| created | string | No | Readonly field set by the database when ship was created |
|
||||||
|
| modified | string | No | Readonly field set by the database when ship was last modified |
|
||||||
|
| deleted | boolean | No | marks the ship as logically deleted |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
## Shipcall Endpoints
|
||||||
|
|
||||||
|
### `GET /shipcalls`
|
||||||
|
**Summary:** Gets a list of ship calls
|
||||||
|
Get current ship calls
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | In | Type | Required | Description |
|
||||||
|
|------|----|------|----------|-------------|
|
||||||
|
| past_days | query | integer | No | number of days in the past to include in the result. *Example: 7*. |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**: ship call list
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `POST /shipcalls`
|
||||||
|
**Summary:** Create a new ship call
|
||||||
|
A new shipcall is created without times at this point. This is ususally done by the BSMD or a participant with that particular role.
|
||||||
|
|
||||||
|
#### Request Body
|
||||||
|
Creates a new ship call. **Do not** provide id parameter.
|
||||||
|
|
||||||
|
**JSON Schema**
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| id | integer | No | |
|
||||||
|
| ship_id | integer | Yes | |
|
||||||
|
| port_id | integer | No | |
|
||||||
|
| type | string | Yes | Type of ship call |
|
||||||
|
| eta | string | No | |
|
||||||
|
| voyage | string | No | |
|
||||||
|
| etd | string | No | |
|
||||||
|
| arrival_berth_id | integer | No | |
|
||||||
|
| departure_berth_id | integer | No | |
|
||||||
|
| tug_required | boolean | No | |
|
||||||
|
| pilot_required | boolean | No | |
|
||||||
|
| flags | integer | No | |
|
||||||
|
| pier_side | boolean | No | |
|
||||||
|
| bunkering | boolean | No | |
|
||||||
|
| replenishing_terminal | boolean | No | |
|
||||||
|
| replenishing_lock | boolean | No | |
|
||||||
|
| draft | number | No | |
|
||||||
|
| tidal_window_from | string | No | |
|
||||||
|
| tidal_window_to | string | No | |
|
||||||
|
| rain_sensitive_cargo | boolean | No | |
|
||||||
|
| recommended_tugs | integer | No | |
|
||||||
|
| anchored | boolean | No | |
|
||||||
|
| moored_lock | boolean | No | |
|
||||||
|
| canceled | boolean | No | |
|
||||||
|
| evaluation | string | No | Evaluation of the ship call |
|
||||||
|
| evaluation_message | string | No | |
|
||||||
|
| time_ref_point | integer | No | Physical reference point for all times given in shipcall and depending times entries |
|
||||||
|
| participants | array<object> | No | |
|
||||||
|
| created | string | No | Readonly field set by the database when shipcall was created |
|
||||||
|
| modified | string | No | Readonly field set by the database when shipcall was last modified |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **201**
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `PUT /shipcalls`
|
||||||
|
**Summary:** Updates a ship call
|
||||||
|
Updates a shipcall. Usually done if the participant assignments change.
|
||||||
|
|
||||||
|
#### Request Body
|
||||||
|
Creates a new ship call. The id parameter is **required**.
|
||||||
|
|
||||||
|
**JSON Schema**
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| id | integer | No | |
|
||||||
|
| ship_id | integer | Yes | |
|
||||||
|
| port_id | integer | No | |
|
||||||
|
| type | string | Yes | Type of ship call |
|
||||||
|
| eta | string | No | |
|
||||||
|
| voyage | string | No | |
|
||||||
|
| etd | string | No | |
|
||||||
|
| arrival_berth_id | integer | No | |
|
||||||
|
| departure_berth_id | integer | No | |
|
||||||
|
| tug_required | boolean | No | |
|
||||||
|
| pilot_required | boolean | No | |
|
||||||
|
| flags | integer | No | |
|
||||||
|
| pier_side | boolean | No | |
|
||||||
|
| bunkering | boolean | No | |
|
||||||
|
| replenishing_terminal | boolean | No | |
|
||||||
|
| replenishing_lock | boolean | No | |
|
||||||
|
| draft | number | No | |
|
||||||
|
| tidal_window_from | string | No | |
|
||||||
|
| tidal_window_to | string | No | |
|
||||||
|
| rain_sensitive_cargo | boolean | No | |
|
||||||
|
| recommended_tugs | integer | No | |
|
||||||
|
| anchored | boolean | No | |
|
||||||
|
| moored_lock | boolean | No | |
|
||||||
|
| canceled | boolean | No | |
|
||||||
|
| evaluation | string | No | Evaluation of the ship call |
|
||||||
|
| evaluation_message | string | No | |
|
||||||
|
| time_ref_point | integer | No | Physical reference point for all times given in shipcall and depending times entries |
|
||||||
|
| participants | array<object> | No | |
|
||||||
|
| created | string | No | Readonly field set by the database when shipcall was created |
|
||||||
|
| modified | string | No | Readonly field set by the database when shipcall was last modified |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
## Static Endpoints
|
||||||
|
|
||||||
|
### `GET /berths`
|
||||||
|
**Summary:** Gets a list of all berths registered
|
||||||
|
Returns a list of berths, including berths that are (logically) deleted
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**: list of berths
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /history`
|
||||||
|
**Summary:** History data
|
||||||
|
This endpoint returns a list of changes made to the specific shipcall
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | In | Type | Required | Description |
|
||||||
|
|------|----|------|----------|-------------|
|
||||||
|
| shipcall_id | query | integer | Yes | **Id of ship call**. *Example: 3*. Id given in ship call list |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**: list of history entries
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /notifications`
|
||||||
|
**Summary:** Gets a list of notifications pursuant to a specified participant and ship call
|
||||||
|
List of notifications (tbd)
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | In | Type | Required | Description |
|
||||||
|
|------|----|------|----------|-------------|
|
||||||
|
| shipcall_id | query | integer | No | **Id of ship call**. *Example: 52*. Id given in ship call list |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**: notification list
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /participants`
|
||||||
|
**Summary:** gets one or all participants
|
||||||
|
If no parameter is given, all participants are returned. The list can be used to display participant information in the context of ship calls.
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | In | Type | Required | Description |
|
||||||
|
|------|----|------|----------|-------------|
|
||||||
|
| user_id | query | integer | No | **Id of user**. *Example: 2*. User id returned by verify call. |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**: one or all participants as list
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **404**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /ports`
|
||||||
|
**Summary:** Your GET endpoint
|
||||||
|
Returns a list of ports
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**: list of ports
|
||||||
|
- **401**
|
||||||
|
- **403**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
## Times Endpoints
|
||||||
|
|
||||||
|
### `DELETE /times`
|
||||||
|
**Summary:** Delete a times entry for a ship call.
|
||||||
|
A times entry is typically deleted if the agent for example changes or removes the participant assignment for a particular role.
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | In | Type | Required | Description |
|
||||||
|
|------|----|------|----------|-------------|
|
||||||
|
| id | query | integer | Yes | **Id of times**. *Example: 42*. Id of times entry to be deleted. |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /times`
|
||||||
|
**Summary:** Gets list of times
|
||||||
|
Get all times assigned to a shipcall. These might not be complete.
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | In | Type | Required | Description |
|
||||||
|
|------|----|------|----------|-------------|
|
||||||
|
| shipcall_id | query | integer | No | **Id**. *Example: 42*. Id of referenced ship call. |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**: list of recorded times
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `POST /times`
|
||||||
|
**Summary:** Create a new times entry for a ship call
|
||||||
|
The times entry for a shipcall is created with reference to a participant. For each participant type there should be only one times data record.
|
||||||
|
|
||||||
|
#### Request Body
|
||||||
|
Times entry that will be added to the ship call. **Do not** provide id parameter.
|
||||||
|
|
||||||
|
**JSON Schema**
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| id | integer | No | |
|
||||||
|
| eta_berth | string | No | Arrival time at berth |
|
||||||
|
| eta_berth_fixed | boolean | No | If true, the eta is fixed and cannot be changed |
|
||||||
|
| etd_berth | string | No | departure time from berth |
|
||||||
|
| etd_berth_fixed | boolean | No | If true, the etd is fixed and cannot be changed |
|
||||||
|
| lock_time | string | No | arrival time at lock |
|
||||||
|
| lock_time_fixed | boolean | No | If true, the lock time is fixed and cannot be changed |
|
||||||
|
| zone_entry | string | No | Expected time of entry into the zone |
|
||||||
|
| zone_entry_fixed | boolean | No | If true, the zone entry time is fixed and cannot be changed |
|
||||||
|
| operations_start | string | No | Start time for terminal operations |
|
||||||
|
| operations_end | string | No | End time for terminal operations |
|
||||||
|
| remarks | string | No | Additional remarks |
|
||||||
|
| shipcall_id | integer | Yes | Reference to a shipcall id |
|
||||||
|
| participant_id | integer | Yes | Reference to a participant id |
|
||||||
|
| berth_id | integer | No | Reference to a berth id |
|
||||||
|
| berth_info | string | No | Additional info text for berth |
|
||||||
|
| pier_side | boolean | No | true if ship is rotated, false otherwise |
|
||||||
|
| participant_type | integer | No | |
|
||||||
|
| ata | string | No | ata can be set by mooring if actual times are different from planned |
|
||||||
|
| atd | string | No | atd can be set by mooring if actual times are different from planned |
|
||||||
|
| eta_interval_end | string | No | Optional end of the interval for the times eta entry |
|
||||||
|
| etd_interval_end | string | No | Optional end of the interval for the times etd entry |
|
||||||
|
| created | string | No | Readonly field set by the database when times record was created |
|
||||||
|
| modified | string | No | Readonly field set by the database when times record was last modified |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **201**
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
### `PUT /times`
|
||||||
|
**Summary:** Update a times entry for a ship call
|
||||||
|
Updating a times entry for a ship for a particular participant. The times entries are required for a shipcall to pass the validation rules.
|
||||||
|
|
||||||
|
#### Request Body
|
||||||
|
Times entry that will be added to the ship call. The id parameter is **required**.
|
||||||
|
|
||||||
|
**JSON Schema**
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| id | integer | No | |
|
||||||
|
| eta_berth | string | No | Arrival time at berth |
|
||||||
|
| eta_berth_fixed | boolean | No | If true, the eta is fixed and cannot be changed |
|
||||||
|
| etd_berth | string | No | departure time from berth |
|
||||||
|
| etd_berth_fixed | boolean | No | If true, the etd is fixed and cannot be changed |
|
||||||
|
| lock_time | string | No | arrival time at lock |
|
||||||
|
| lock_time_fixed | boolean | No | If true, the lock time is fixed and cannot be changed |
|
||||||
|
| zone_entry | string | No | Expected time of entry into the zone |
|
||||||
|
| zone_entry_fixed | boolean | No | If true, the zone entry time is fixed and cannot be changed |
|
||||||
|
| operations_start | string | No | Start time for terminal operations |
|
||||||
|
| operations_end | string | No | End time for terminal operations |
|
||||||
|
| remarks | string | No | Additional remarks |
|
||||||
|
| shipcall_id | integer | Yes | Reference to a shipcall id |
|
||||||
|
| participant_id | integer | Yes | Reference to a participant id |
|
||||||
|
| berth_id | integer | No | Reference to a berth id |
|
||||||
|
| berth_info | string | No | Additional info text for berth |
|
||||||
|
| pier_side | boolean | No | true if ship is rotated, false otherwise |
|
||||||
|
| participant_type | integer | No | |
|
||||||
|
| ata | string | No | ata can be set by mooring if actual times are different from planned |
|
||||||
|
| atd | string | No | atd can be set by mooring if actual times are different from planned |
|
||||||
|
| eta_interval_end | string | No | Optional end of the interval for the times eta entry |
|
||||||
|
| etd_interval_end | string | No | Optional end of the interval for the times etd entry |
|
||||||
|
| created | string | No | Readonly field set by the database when times record was created |
|
||||||
|
| modified | string | No | Readonly field set by the database when times record was last modified |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
|
|
||||||
|
## User Endpoints
|
||||||
|
|
||||||
|
### `POST /login`
|
||||||
|
**Summary:** Returns a JWT session token and user data if successful
|
||||||
|
Perform login
|
||||||
|
|
||||||
|
#### Request Body
|
||||||
|
Login credentials
|
||||||
|
|
||||||
|
**JSON Schema**
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| username | string | Yes | |
|
||||||
|
| password | string | Yes | |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**: Successful response
|
||||||
|
- **400**
|
||||||
|
- **403**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
|
||||||
|
**Response 200 JSON Schema**
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| id | integer | No | |
|
||||||
|
| participant_id | integer | No | |
|
||||||
|
| first_name | string | No | |
|
||||||
|
| last_name | string | No | |
|
||||||
|
| user_name | string | No | |
|
||||||
|
| user_phone | string | No | |
|
||||||
|
| user_email | string | No | |
|
||||||
|
| notify_email | boolean | No | |
|
||||||
|
| notify_whatsapp | boolean | No | |
|
||||||
|
| notify_signal | boolean | No | |
|
||||||
|
| notify_popup | boolean | No | |
|
||||||
|
| exp | number | No | |
|
||||||
|
| token | string | No | |
|
||||||
|
| notify_on | array<string> | No | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `PUT /user`
|
||||||
|
**Summary:** Update user details (first/last name, phone, password)
|
||||||
|
Update user information
|
||||||
|
|
||||||
|
#### Request Body
|
||||||
|
User details
|
||||||
|
|
||||||
|
**JSON Schema**
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| id | integer | No | |
|
||||||
|
| old_password | string | No | |
|
||||||
|
| new_password | string | No | |
|
||||||
|
| first_name | string | No | |
|
||||||
|
| last_name | string | No | |
|
||||||
|
| user_phone | string | No | |
|
||||||
|
| user_email | string | No | |
|
||||||
|
| notify_email | boolean | No | |
|
||||||
|
| notify_popup | boolean | No | |
|
||||||
|
| notify_whatsapp | boolean | No | |
|
||||||
|
| notify_signal | boolean | No | |
|
||||||
|
| notify_on | array<string> | No | |
|
||||||
|
|
||||||
|
#### Responses
|
||||||
|
|
||||||
|
- **200**
|
||||||
|
- **400**
|
||||||
|
- **401**
|
||||||
|
- **500**
|
||||||
|
- **503**
|
||||||
|
---
|
||||||
1093
misc/BreCalApi.yaml
1093
misc/BreCalApi.yaml
File diff suppressed because it is too large
Load Diff
153
misc/Readme.md
153
misc/Readme.md
@ -48,3 +48,156 @@ DROP TABLE IF EXISTS `shipcall`;
|
|||||||
SET FOREIGN_KEY_CHECKS = 1;
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
participant {
|
||||||
|
INT id PK
|
||||||
|
VARCHAR name
|
||||||
|
VARCHAR street
|
||||||
|
VARCHAR postal_code
|
||||||
|
VARCHAR city
|
||||||
|
INT type
|
||||||
|
INT flags
|
||||||
|
}
|
||||||
|
port {
|
||||||
|
INT id PK
|
||||||
|
VARCHAR name
|
||||||
|
CHAR locode
|
||||||
|
}
|
||||||
|
berth {
|
||||||
|
INT id PK
|
||||||
|
VARCHAR name
|
||||||
|
BIT lock
|
||||||
|
INT owner_id FK
|
||||||
|
INT authority_id FK
|
||||||
|
INT port_id FK
|
||||||
|
BIT deleted
|
||||||
|
}
|
||||||
|
ship {
|
||||||
|
INT id PK
|
||||||
|
VARCHAR name
|
||||||
|
INT imo
|
||||||
|
VARCHAR callsign
|
||||||
|
INT participant_id FK
|
||||||
|
FLOAT length
|
||||||
|
FLOAT width
|
||||||
|
BIT is_tug
|
||||||
|
INT bollard_pull
|
||||||
|
INT eni
|
||||||
|
BIT deleted
|
||||||
|
}
|
||||||
|
shipcall {
|
||||||
|
INT id PK
|
||||||
|
INT ship_id FK
|
||||||
|
TINYINT type
|
||||||
|
DATETIME eta
|
||||||
|
DATETIME etd
|
||||||
|
INT arrival_berth_id FK
|
||||||
|
INT departure_berth_id FK
|
||||||
|
INT port_id FK
|
||||||
|
INT flags
|
||||||
|
BIT tug_required
|
||||||
|
BIT pilot_required
|
||||||
|
}
|
||||||
|
times {
|
||||||
|
INT id PK
|
||||||
|
INT shipcall_id FK
|
||||||
|
INT participant_id FK
|
||||||
|
INT berth_id FK
|
||||||
|
INT participant_type
|
||||||
|
DATETIME eta_berth
|
||||||
|
DATETIME etd_berth
|
||||||
|
DATETIME lock_time
|
||||||
|
DATETIME zone_entry
|
||||||
|
}
|
||||||
|
notification {
|
||||||
|
INT id PK
|
||||||
|
INT shipcall_id FK
|
||||||
|
INT participant_id FK
|
||||||
|
TINYINT level
|
||||||
|
TINYINT type
|
||||||
|
}
|
||||||
|
history {
|
||||||
|
INT id PK
|
||||||
|
INT participant_id FK
|
||||||
|
INT user_id FK
|
||||||
|
INT shipcall_id FK
|
||||||
|
DATETIME timestamp
|
||||||
|
DATETIME eta
|
||||||
|
INT type
|
||||||
|
INT operation
|
||||||
|
}
|
||||||
|
shipcall_participant_map {
|
||||||
|
INT id PK
|
||||||
|
INT shipcall_id FK
|
||||||
|
INT participant_id FK
|
||||||
|
INT type
|
||||||
|
}
|
||||||
|
shipcall_tug_map {
|
||||||
|
INT id PK
|
||||||
|
INT shipcall_id FK
|
||||||
|
INT ship_id FK
|
||||||
|
}
|
||||||
|
participant_port_map {
|
||||||
|
INT id PK
|
||||||
|
INT participant_id FK
|
||||||
|
INT port_id FK
|
||||||
|
}
|
||||||
|
user {
|
||||||
|
INT id PK
|
||||||
|
INT participant_id FK
|
||||||
|
VARCHAR first_name
|
||||||
|
VARCHAR last_name
|
||||||
|
VARCHAR user_name
|
||||||
|
VARCHAR user_email
|
||||||
|
}
|
||||||
|
role {
|
||||||
|
INT id PK
|
||||||
|
VARCHAR name
|
||||||
|
VARCHAR description
|
||||||
|
}
|
||||||
|
securable {
|
||||||
|
INT id PK
|
||||||
|
VARCHAR name
|
||||||
|
}
|
||||||
|
role_securable_map {
|
||||||
|
INT id PK
|
||||||
|
INT role_id FK
|
||||||
|
INT securable_id FK
|
||||||
|
}
|
||||||
|
user_role_map {
|
||||||
|
INT id PK
|
||||||
|
INT user_id FK
|
||||||
|
INT role_id FK
|
||||||
|
}
|
||||||
|
|
||||||
|
participant ||--o{ berth : owner_id
|
||||||
|
participant ||--o{ berth : authority_id
|
||||||
|
port ||--o{ berth : port_id
|
||||||
|
participant ||--o{ ship : participant_id
|
||||||
|
ship ||--o{ shipcall : ship_id
|
||||||
|
berth ||--o{ shipcall : arrival_berth_id
|
||||||
|
berth ||--o{ shipcall : departure_berth_id
|
||||||
|
port ||--o{ shipcall : port_id
|
||||||
|
shipcall ||--|| times : shipcall_id
|
||||||
|
participant ||--|| times : participant_id
|
||||||
|
berth ||--o{ times : berth_id
|
||||||
|
shipcall ||--o{ notification : shipcall_id
|
||||||
|
participant ||--o{ notification : participant_id
|
||||||
|
participant ||--o{ history : participant_id
|
||||||
|
user ||--o{ history : user_id
|
||||||
|
shipcall ||--o{ history : shipcall_id
|
||||||
|
shipcall ||--o{ shipcall_participant_map : shipcall_id
|
||||||
|
participant ||--o{ shipcall_participant_map : participant_id
|
||||||
|
shipcall ||--o{ shipcall_tug_map : shipcall_id
|
||||||
|
ship ||--o{ shipcall_tug_map : ship_id
|
||||||
|
participant ||--o{ participant_port_map : participant_id
|
||||||
|
port ||--o{ participant_port_map : port_id
|
||||||
|
participant ||--o{ user : participant_id
|
||||||
|
user ||--o{ user_role_map : user_id
|
||||||
|
role ||--o{ user_role_map : role_id
|
||||||
|
role ||--o{ role_securable_map : role_id
|
||||||
|
securable ||--o{ role_securable_map : securable_id
|
||||||
|
```
|
||||||
|
|||||||
21
misc/Readme_test.md
Normal file
21
misc/Readme_test.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Tests
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## schemathesis
|
||||||
|
|
||||||
|
Unter dem Verzeichnis ./src/server/tests befinden sich die Test-Cases, die Max bei der ersten Implementierung der Validierung angelegt hat.
|
||||||
|
Diese sind derzeit nicht "aktiv", bzw. noch nicht bereinigt.
|
||||||
|
|
||||||
|
Ich möchte gern ein automatisches Framework verwenden, das aber nur "manuell" betrieben wird. Änderungen an der API sind selten.
|
||||||
|
|
||||||
|
Aktueller Stand (7.1.26):
|
||||||
|
|
||||||
|
Im Verzeichnis ./src/server/tests kann folgendes ausgeführt werden:
|
||||||
|
|
||||||
|
```pytest -q --maxfail=1 contract/test_openapi_fuzz.py```
|
||||||
|
|
||||||
|
Das Ganze funktioniert nur, wenn auch schemathesis und hypothesis in den passenden(!) Versionen im lokalen _venv_ installiert sind.
|
||||||
|
Aktuell habe ich schemathesis ("latest") und hypothesis 6.120.0:
|
||||||
|
```pip install "hypothesis==6.120.0"```
|
||||||
|
Das muss wegen dependencies so blöd gepinnt werden.
|
||||||
@ -17,3 +17,11 @@ public bool ShouldSerializeEvaluation()
|
|||||||
```
|
```
|
||||||
|
|
||||||
Witziger(!)weise funktioniert es für das Property EvaluationMessage korrekt.
|
Witziger(!)weise funktioniert es für das Property EvaluationMessage korrekt.
|
||||||
|
|
||||||
|
### Vacuum Yaml Linter
|
||||||
|
|
||||||
|
Example Usage:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vacuum lint -d .\misc\BreCalApi.yaml --fail-severity warn
|
||||||
|
```
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
# Versionshistorie
|
||||||
|
|
||||||
|
## 1.7
|
||||||
|
|
||||||
|
### YAML / API
|
||||||
|
|
||||||
|
1. Notifications GET: Der Parameter "shipcall_id" ist jetzt optional für den Abruf von Benachrichtigungen.
|
||||||
|
|
||||||
|
2. Notification: Enthält jetzt ein neues Feld "participant_id". Ist dieses gesetzt, richtet sich die Benachrichtigung an diesen Teilnehmer. Ist das Feld nicht vorhanden, richtet sich die Benachrichtigung an alle Beteiligten des shipcall
|
||||||
|
|
||||||
|
3. Die Benutzerdaten (login_result) enthalten jetzt die Felder (Flags) der Zuordnung für die verschiedenen Benachrichtigungs-Wege, aktuell implementiert ist notify_email und notify_popup. Diese können auch über user_details analog zu Telefonnummer, Name etc. gesetzt werden.
|
||||||
|
|
||||||
|
4. Die Enumeration NotificationType enthält jetzt nicht mehr den Benachrichtigungsweg, sondern den Typ des Ereignisses, das die Benachrichtigung ausgelöst hat. Aktuell werden 7 Ereignisse unterschieden.
|
||||||
|
|
||||||
|
5. Die Benutzerdaten enthalten eine Liste NotifyOn vom Typ NotificationType. In dieser Aufzählung sind die Ereignisse enthalten, über die der Benutzer benachrichtigt werden will. Wenn diese Liste leer oder nicht vorhanden ist erhält der Benutzer keine Nachrichten, auch wenn er einen Benachrichtigungsweg ausgewählt hat.
|
||||||
|
|
||||||
46
misc/check_clear_double_times_entries.sql
Normal file
46
misc/check_clear_double_times_entries.sql
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
-- Inspect duplicates first
|
||||||
|
WITH duplicate_participants AS (
|
||||||
|
SELECT
|
||||||
|
shipcall_id,
|
||||||
|
participant_type,
|
||||||
|
COUNT(*) AS cnt
|
||||||
|
FROM times
|
||||||
|
GROUP BY shipcall_id, participant_type
|
||||||
|
HAVING COUNT(*) > 1
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
t.*
|
||||||
|
FROM times AS t
|
||||||
|
JOIN duplicate_participants AS d
|
||||||
|
ON d.shipcall_id = t.shipcall_id
|
||||||
|
AND (d.participant_type <=> t.participant_type)
|
||||||
|
ORDER BY t.shipcall_id, t.participant_type, t.id;
|
||||||
|
|
||||||
|
-- Delete all but the highest-id entry per (shipcall_id, participant_type)
|
||||||
|
WITH ordered_times AS (
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
ROW_NUMBER() OVER (
|
||||||
|
PARTITION BY shipcall_id, participant_type
|
||||||
|
ORDER BY id DESC
|
||||||
|
) AS rn
|
||||||
|
FROM times
|
||||||
|
)
|
||||||
|
DELETE FROM times
|
||||||
|
WHERE id IN (
|
||||||
|
SELECT id
|
||||||
|
FROM ordered_times
|
||||||
|
WHERE rn > 1
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Optional: re-check that no duplicates remain
|
||||||
|
WITH duplicate_participants AS (
|
||||||
|
SELECT
|
||||||
|
shipcall_id,
|
||||||
|
participant_type,
|
||||||
|
COUNT(*) AS cnt
|
||||||
|
FROM times
|
||||||
|
GROUP BY shipcall_id, participant_type
|
||||||
|
HAVING COUNT(*) > 1
|
||||||
|
)
|
||||||
|
SELECT COUNT(*) AS remaining_duplicates FROM duplicate_participants;
|
||||||
37
misc/clear_data.sql
Normal file
37
misc/clear_data.sql
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
-- This script clears all data from the database tables related to the port management system.
|
||||||
|
|
||||||
|
DELETE FROM notification WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM history WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM notification WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM shipcall_participant_map WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM participant_port_map WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM shipcall_tug_map WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM times WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM shipcall WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM user_role_map WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM role_securable_map WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM user_role_map WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM securable WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM role WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM user WHERE id > 0;
|
||||||
|
|
||||||
|
delete FROM ship WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM berth WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM participant WHERE id > 0;
|
||||||
|
|
||||||
|
DELETE FROM port WHERE id > 0;
|
||||||
23
misc/clear_entries_for_participant.sql
Normal file
23
misc/clear_entries_for_participant.sql
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
DELETE FROM times WHERE
|
||||||
|
times.shipcall_id IN
|
||||||
|
(
|
||||||
|
SELECT s.id FROM shipcall s
|
||||||
|
JOIN shipcall_participant_map spm ON s.id = spm.shipcall_id
|
||||||
|
JOIN participant p ON spm.participant_id = p.id
|
||||||
|
WHERE p.id = 10
|
||||||
|
);
|
||||||
|
|
||||||
|
DELETE `history` FROM `history`
|
||||||
|
JOIN shipcall s on `history`.shipcall_id = s.id
|
||||||
|
JOIN shipcall_participant_map spm ON s.id = spm.shipcall_id
|
||||||
|
WHERE spm.participant_id = 10;
|
||||||
|
|
||||||
|
-- damit das hier funktioniert muss der FK in shipcall_participant_map von "RESTRICT" auf "SET NULL"
|
||||||
|
-- geändert werden
|
||||||
|
|
||||||
|
DELETE shipcall FROM shipcall
|
||||||
|
INNER JOIN shipcall_participant_map spm ON shipcall.id = spm.shipcall_id
|
||||||
|
JOIN participant p ON spm.participant_id = p.id
|
||||||
|
WHERE p.id = 10;
|
||||||
|
|
||||||
|
DELETE FROM shipcall_participant_map WHERE participant_id = 10;
|
||||||
@ -1,8 +1,8 @@
|
|||||||
-- MySQL dump 10.13 Distrib 8.0.33, for Win64 (x86_64)
|
-- MySQL dump 10.13 Distrib 8.0.43, for Win64 (x86_64)
|
||||||
--
|
--
|
||||||
-- Host: localhost Database: bremen_calling_test
|
-- Host: localhost Database: bremen_calling_test
|
||||||
-- ------------------------------------------------------
|
-- ------------------------------------------------------
|
||||||
-- Server version 8.0.34-0ubuntu0.22.04.1
|
-- Server version 8.0.42-0ubuntu0.24.10.1
|
||||||
|
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
@ -28,17 +28,65 @@ CREATE TABLE `berth` (
|
|||||||
`lock` bit(1) DEFAULT NULL COMMENT 'The lock must be used',
|
`lock` bit(1) DEFAULT NULL COMMENT 'The lock must be used',
|
||||||
`owner_id` int unsigned DEFAULT NULL,
|
`owner_id` int unsigned DEFAULT NULL,
|
||||||
`authority_id` int unsigned DEFAULT NULL,
|
`authority_id` int unsigned DEFAULT NULL,
|
||||||
|
`port_id` int unsigned DEFAULT NULL,
|
||||||
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
`deleted` bit(1) DEFAULT b'0',
|
`deleted` bit(1) DEFAULT b'0',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `FK_OWNER_PART_idx` (`owner_id`),
|
KEY `FK_OWNER_PART_idx` (`owner_id`),
|
||||||
KEY `FK_AUTHORITY_PART_idx` (`authority_id`),
|
KEY `FK_AUTHORITY_PART_idx` (`authority_id`) /*!80000 INVISIBLE */,
|
||||||
|
KEY `FK_PORT_PART_idx` (`port_id`),
|
||||||
CONSTRAINT `FK_AUTHORITY_PART` FOREIGN KEY (`authority_id`) REFERENCES `participant` (`id`),
|
CONSTRAINT `FK_AUTHORITY_PART` FOREIGN KEY (`authority_id`) REFERENCES `participant` (`id`),
|
||||||
CONSTRAINT `FK_OWNER_PART` FOREIGN KEY (`owner_id`) REFERENCES `participant` (`id`)
|
CONSTRAINT `FK_OWNER_PART` FOREIGN KEY (`owner_id`) REFERENCES `participant` (`id`),
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=195 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Berth of ship for a ship call';
|
CONSTRAINT `FK_PORT` FOREIGN KEY (`port_id`) REFERENCES `port` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=205 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Berth of ship for a ship call';
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `history`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `history`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `history` (
|
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`participant_id` int unsigned NOT NULL,
|
||||||
|
`user_id` int unsigned DEFAULT NULL,
|
||||||
|
`shipcall_id` int unsigned NOT NULL,
|
||||||
|
`timestamp` datetime NOT NULL COMMENT 'Time of saving',
|
||||||
|
`eta` datetime DEFAULT NULL COMMENT 'Current ETA / ETD value (depends if shipcall or times were saved)',
|
||||||
|
`type` int NOT NULL COMMENT 'shipcall or times',
|
||||||
|
`operation` int NOT NULL COMMENT 'insert, update or delete',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `FK_HISTORY_PARTICIPANT_idx` (`participant_id`),
|
||||||
|
KEY `FK_HISTORY_SHIPCALL_idx` (`shipcall_id`),
|
||||||
|
KEY `FK_HISTORY_USER` (`user_id`),
|
||||||
|
CONSTRAINT `FK_HISTORY_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`),
|
||||||
|
CONSTRAINT `FK_HISTORY_SHIPCALL` FOREIGN KEY (`shipcall_id`) REFERENCES `shipcall` (`id`),
|
||||||
|
CONSTRAINT `FK_HISTORY_USER` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=23537 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='This table stores a history of changes made to shipcalls so that everyone can see who changed what and when';
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
CREATE TABLE `history` (
|
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`participant_id` int unsigned NOT NULL,
|
||||||
|
`user_id` int unsigned DEFAULT NULL,
|
||||||
|
`shipcall_id` int unsigned NOT NULL,
|
||||||
|
`timestamp` datetime NOT NULL COMMENT 'Time of saving',
|
||||||
|
`eta` datetime DEFAULT NULL COMMENT 'Current ETA / ETD value (depends if shipcall or times were saved)',
|
||||||
|
`type` int NOT NULL COMMENT 'shipcall or times',
|
||||||
|
`operation` int NOT NULL COMMENT 'insert, update or delete',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `FK_HISTORY_PARTICIPANT_idx` (`participant_id`),
|
||||||
|
KEY `FK_HISTORY_SHIPCALL_idx` (`shipcall_id`),
|
||||||
|
KEY `FK_HISTORY_USER` (`user_id`),
|
||||||
|
CONSTRAINT `FK_HISTORY_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`),
|
||||||
|
CONSTRAINT `FK_HISTORY_SHIPCALL` FOREIGN KEY (`shipcall_id`) REFERENCES `shipcall` (`id`),
|
||||||
|
CONSTRAINT `FK_HISTORY_USER` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=29292 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='This table stores a history of changes made to shipcalls so that everyone can see who changed what and when';
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `notification`
|
-- Table structure for table `notification`
|
||||||
--
|
--
|
||||||
@ -48,20 +96,19 @@ DROP TABLE IF EXISTS `notification`;
|
|||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `notification` (
|
CREATE TABLE `notification` (
|
||||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`times_id` int unsigned NOT NULL COMMENT 'times record that caused the notification',
|
`shipcall_id` int unsigned DEFAULT NULL,
|
||||||
`participant_id` int unsigned NOT NULL COMMENT 'participant ref',
|
`participant_id` int unsigned DEFAULT NULL,
|
||||||
`acknowledged` bit(1) DEFAULT b'0' COMMENT 'true if UI acknowledged',
|
|
||||||
`level` tinyint DEFAULT NULL COMMENT 'severity of the notification',
|
`level` tinyint DEFAULT NULL COMMENT 'severity of the notification',
|
||||||
`type` tinyint DEFAULT NULL COMMENT 'Email/UI/Other',
|
`type` tinyint DEFAULT NULL COMMENT 'Email/UI/Other',
|
||||||
`message` varchar(256) DEFAULT NULL COMMENT 'individual message',
|
`message` varchar(512) DEFAULT NULL COMMENT 'individual message',
|
||||||
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `FK_NOT_TIMES` (`times_id`),
|
KEY `FK_NOTIFICATION_SHIPCALL_idx` (`shipcall_id`),
|
||||||
KEY `FK_NOT_PART` (`participant_id`),
|
KEY `FK_NOTIFICATION_PARTICIPANT_idx` (`participant_id`),
|
||||||
CONSTRAINT `FK_NOT_PART` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`),
|
CONSTRAINT `FK_NOTIFICATION_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||||
CONSTRAINT `FK_NOT_TIMES` FOREIGN KEY (`times_id`) REFERENCES `times` (`id`)
|
CONSTRAINT `FK_NOTIFICATION_SHIPCALL` FOREIGN KEY (`shipcall_id`) REFERENCES `shipcall` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='An entry corresponds to an alarm given by a violated rule during times update';
|
) ENGINE=InnoDB AUTO_INCREMENT=10398 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='An entry corresponds to an alarm given by a violated rule during times update';
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -83,7 +130,46 @@ CREATE TABLE `participant` (
|
|||||||
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
`deleted` bit(1) DEFAULT b'0',
|
`deleted` bit(1) DEFAULT b'0',
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=137 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='An organization taking part';
|
) ENGINE=InnoDB AUTO_INCREMENT=160 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='An organization taking part';
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `participant_port_map`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `participant_port_map`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `participant_port_map` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
|
`participant_id` int unsigned NOT NULL COMMENT 'Ref to participant',
|
||||||
|
`port_id` int unsigned NOT NULL COMMENT 'Ref to port',
|
||||||
|
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `FK_PP_PARTICIPANT` (`participant_id`),
|
||||||
|
KEY `FK_PP_PORT` (`port_id`),
|
||||||
|
CONSTRAINT `FK_PP_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`),
|
||||||
|
CONSTRAINT `FK_PP_PORT` FOREIGN KEY (`port_id`) REFERENCES `port` (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=86 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Mapping table that assigns participants to a port';
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `port`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `port`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `port` (
|
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(128) NOT NULL COMMENT 'Name of port',
|
||||||
|
`locode` char(5) DEFAULT NULL COMMENT 'UNECE locode',
|
||||||
|
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
`deleted` bit(1) DEFAULT b'0',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Port as reference for shipcalls and berths';
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -166,7 +252,7 @@ CREATE TABLE `ship` (
|
|||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `FK_SHIP_PARTICIPANT` (`participant_id`),
|
KEY `FK_SHIP_PARTICIPANT` (`participant_id`),
|
||||||
CONSTRAINT `FK_SHIP_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
|
CONSTRAINT `FK_SHIP_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=485 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -202,16 +288,25 @@ CREATE TABLE `shipcall` (
|
|||||||
`canceled` bit(1) DEFAULT NULL,
|
`canceled` bit(1) DEFAULT NULL,
|
||||||
`evaluation` int unsigned DEFAULT NULL,
|
`evaluation` int unsigned DEFAULT NULL,
|
||||||
`evaluation_message` varchar(512) DEFAULT NULL,
|
`evaluation_message` varchar(512) DEFAULT NULL,
|
||||||
|
`evaluation_time` datetime DEFAULT NULL,
|
||||||
|
`evaluation_notifications_sent` bit(1) DEFAULT NULL,
|
||||||
|
`port_id` int unsigned NOT NULL DEFAULT '1' COMMENT 'Selected port for this shipcall',
|
||||||
|
`time_ref_point` int DEFAULT '0' COMMENT 'Index of a location which is the reference point for all time value entries, e.g. berth or Geeste',
|
||||||
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `FK_SHIPCALL_SHIP` (`ship_id`),
|
KEY `FK_SHIPCALL_SHIP` (`ship_id`),
|
||||||
KEY `FK_SHIPCALL_BERTH_ARRIVAL` (`arrival_berth_id`),
|
KEY `FK_SHIPCALL_BERTH_ARRIVAL` (`arrival_berth_id`),
|
||||||
KEY `FK_SHIPCALL_BERTH_DEPARTURE` (`departure_berth_id`),
|
KEY `FK_SHIPCALL_BERTH_DEPARTURE` (`departure_berth_id`),
|
||||||
|
KEY `idx_shipcall_type` (`type`),
|
||||||
|
KEY `idx_shipcall_eta` (`eta`),
|
||||||
|
KEY `idx_shipcall_etd` (`etd`),
|
||||||
|
KEY `FK_SHIPCALL_PORT_idx` (`port_id`),
|
||||||
CONSTRAINT `FK_SHIPCALL_BERTH_ARRIVAL` FOREIGN KEY (`arrival_berth_id`) REFERENCES `berth` (`id`),
|
CONSTRAINT `FK_SHIPCALL_BERTH_ARRIVAL` FOREIGN KEY (`arrival_berth_id`) REFERENCES `berth` (`id`),
|
||||||
CONSTRAINT `FK_SHIPCALL_BERTH_DEPARTURE` FOREIGN KEY (`departure_berth_id`) REFERENCES `berth` (`id`),
|
CONSTRAINT `FK_SHIPCALL_BERTH_DEPARTURE` FOREIGN KEY (`departure_berth_id`) REFERENCES `berth` (`id`),
|
||||||
|
CONSTRAINT `FK_SHIPCALL_PORT` FOREIGN KEY (`port_id`) REFERENCES `port` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||||
CONSTRAINT `FK_SHIPCALL_SHIP` FOREIGN KEY (`ship_id`) REFERENCES `ship` (`id`)
|
CONSTRAINT `FK_SHIPCALL_SHIP` FOREIGN KEY (`ship_id`) REFERENCES `ship` (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Incoming, outgoing or moving to another berth';
|
) ENGINE=InnoDB AUTO_INCREMENT=2789 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Incoming, outgoing or moving to another berth';
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -225,15 +320,15 @@ CREATE TABLE `shipcall_participant_map` (
|
|||||||
`id` int NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`shipcall_id` int unsigned DEFAULT NULL,
|
`shipcall_id` int unsigned DEFAULT NULL,
|
||||||
`participant_id` int unsigned DEFAULT NULL,
|
`participant_id` int unsigned DEFAULT NULL,
|
||||||
`type` int unsigned DEFAULT NULL COMMENT 'Type of participant role',
|
`type` int unsigned DEFAULT NULL,
|
||||||
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `FK_MAP_PARTICIPANT_SHIPCALL` (`shipcall_id`),
|
KEY `FK_MAP_PARTICIPANT_SHIPCALL` (`shipcall_id`),
|
||||||
KEY `FK_MAP_SHIPCALL_PARTICIPANT` (`participant_id`),
|
KEY `FK_MAP_SHIPCALL_PARTICIPANT` (`participant_id`),
|
||||||
CONSTRAINT `FK_MAP_PARTICIPANT_SHIPCALL` FOREIGN KEY (`shipcall_id`) REFERENCES `shipcall` (`id`),
|
CONSTRAINT `FK_MAP_PARTICIPANT_SHIPCALL` FOREIGN KEY (`shipcall_id`) REFERENCES `shipcall` (`id`) ON DELETE SET NULL,
|
||||||
CONSTRAINT `FK_MAP_SHIPCALL_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
|
CONSTRAINT `FK_MAP_SHIPCALL_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=128 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Associates a participant with a shipcall';
|
) ENGINE=InnoDB AUTO_INCREMENT=8933 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Associates a participant with a shipcall';
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -285,13 +380,20 @@ CREATE TABLE `times` (
|
|||||||
`berth_info` varchar(512) DEFAULT NULL,
|
`berth_info` varchar(512) DEFAULT NULL,
|
||||||
`pier_side` bit(1) DEFAULT NULL,
|
`pier_side` bit(1) DEFAULT NULL,
|
||||||
`participant_type` int unsigned DEFAULT NULL,
|
`participant_type` int unsigned DEFAULT NULL,
|
||||||
|
`ata` datetime DEFAULT NULL COMMENT 'Relevant only for mooring, this field can be used to record actual ATA',
|
||||||
|
`atd` datetime DEFAULT NULL COMMENT 'Relevant only for mooring, this field can be used to record actual ATD',
|
||||||
|
`eta_interval_end` datetime DEFAULT NULL COMMENT 'If this value is set the times are given as interval instead of a single point in time. The start time value depends on the participant type.',
|
||||||
|
`etd_interval_end` datetime DEFAULT NULL COMMENT 'If this value is set the times are given as interval instead of a single point in time. The start time value depends on the participant type.',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uniq_shipcall_participant` (`shipcall_id`,`participant_type`),
|
||||||
KEY `FK_TIME_SHIPCALL` (`shipcall_id`),
|
KEY `FK_TIME_SHIPCALL` (`shipcall_id`),
|
||||||
KEY `FK_TIME_PART` (`participant_id`) /*!80000 INVISIBLE */,
|
KEY `FK_TIME_PART` (`participant_id`) /*!80000 INVISIBLE */,
|
||||||
KEY `FK_TIME_BERTH` (`berth_id`) /*!80000 INVISIBLE */,
|
KEY `FK_TIME_BERTH` (`berth_id`) /*!80000 INVISIBLE */,
|
||||||
|
KEY `idx_times_eta_berth` (`eta_berth`),
|
||||||
|
KEY `idx_times_etd_berth` (`etd_berth`),
|
||||||
CONSTRAINT `FK_TIME_BERTH` FOREIGN KEY (`berth_id`) REFERENCES `berth` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
CONSTRAINT `FK_TIME_BERTH` FOREIGN KEY (`berth_id`) REFERENCES `berth` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||||
CONSTRAINT `FK_TIME_PART` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
|
CONSTRAINT `FK_TIME_PART` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='the planned time for the participants work';
|
) ENGINE=InnoDB AUTO_INCREMENT=7863 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='the planned time for the participants work';
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -303,7 +405,7 @@ DROP TABLE IF EXISTS `user`;
|
|||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `user` (
|
CREATE TABLE `user` (
|
||||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`participant_id` int unsigned DEFAULT NULL,
|
`participant_id` int unsigned NOT NULL,
|
||||||
`first_name` varchar(45) DEFAULT NULL,
|
`first_name` varchar(45) DEFAULT NULL,
|
||||||
`last_name` varchar(45) DEFAULT NULL,
|
`last_name` varchar(45) DEFAULT NULL,
|
||||||
`user_name` varchar(45) DEFAULT NULL,
|
`user_name` varchar(45) DEFAULT NULL,
|
||||||
@ -311,12 +413,17 @@ CREATE TABLE `user` (
|
|||||||
`user_phone` varchar(128) DEFAULT NULL,
|
`user_phone` varchar(128) DEFAULT NULL,
|
||||||
`password_hash` varchar(128) DEFAULT NULL,
|
`password_hash` varchar(128) DEFAULT NULL,
|
||||||
`api_key` varchar(256) DEFAULT NULL,
|
`api_key` varchar(256) DEFAULT NULL,
|
||||||
|
`notify_email` bit(1) DEFAULT NULL,
|
||||||
|
`notify_whatsapp` bit(1) DEFAULT NULL,
|
||||||
|
`notify_signal` bit(1) DEFAULT NULL,
|
||||||
|
`notify_popup` bit(1) DEFAULT NULL,
|
||||||
|
`notify_event` int DEFAULT NULL COMMENT 'Bitflag of selected notification event types that the user wants to be notified of',
|
||||||
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `FK_USER_PART` (`participant_id`),
|
KEY `FK_USER_PART` (`participant_id`),
|
||||||
CONSTRAINT `FK_USER_PART` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
|
CONSTRAINT `FK_USER_PART` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='member of a participant';
|
) ENGINE=InnoDB AUTO_INCREMENT=55 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='member of a participant';
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -339,6 +446,57 @@ CREATE TABLE `user_role_map` (
|
|||||||
CONSTRAINT `FK_USER_ROLE` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
|
CONSTRAINT `FK_USER_ROLE` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Assigns a user to a role';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Assigns a user to a role';
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping routines for database 'bremen_calling_test'
|
||||||
|
--
|
||||||
|
/*!50003 DROP PROCEDURE IF EXISTS `delete_data` */;
|
||||||
|
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
||||||
|
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
|
||||||
|
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
|
||||||
|
/*!50003 SET character_set_client = utf8mb4 */ ;
|
||||||
|
/*!50003 SET character_set_results = utf8mb4 */ ;
|
||||||
|
/*!50003 SET collation_connection = utf8mb4_0900_ai_ci */ ;
|
||||||
|
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||||
|
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION' */ ;
|
||||||
|
DELIMITER ;;
|
||||||
|
CREATE DEFINER=`ds`@`localhost` PROCEDURE `delete_data`()
|
||||||
|
BEGIN
|
||||||
|
DECLARE shipcall_id_var int;
|
||||||
|
DECLARE done INT DEFAULT FALSE;
|
||||||
|
|
||||||
|
DECLARE shipcall_iter CURSOR FOR
|
||||||
|
SELECT shipcall.id FROM shipcall
|
||||||
|
LEFT JOIN times ON
|
||||||
|
times.shipcall_id = shipcall.id AND times.participant_type = 8
|
||||||
|
WHERE
|
||||||
|
-- ARRIVAL
|
||||||
|
(type = 1 AND GREATEST(shipcall.eta, COALESCE(times.eta_berth, 0)) <= CURRENT_DATE() - INTERVAL 1 MONTH) OR
|
||||||
|
-- DEPARTURE / SHIFTING
|
||||||
|
(type != 1 AND GREATEST(shipcall.etd, COALESCE(times.etd_berth, 0)) <= CURRENT_DATE() - INTERVAL 1 MONTH);
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
||||||
|
|
||||||
|
OPEN shipcall_iter;
|
||||||
|
|
||||||
|
delete_loop: LOOP
|
||||||
|
FETCH shipcall_iter INTO shipcall_id_var;
|
||||||
|
IF done THEN
|
||||||
|
LEAVE delete_loop;
|
||||||
|
END IF;
|
||||||
|
DELETE FROM shipcall_participant_map WHERE shipcall_id = shipcall_id_var;
|
||||||
|
DELETE FROM shipcall_tug_map WHERE shipcall_id = shipcall_id_var;
|
||||||
|
DELETE FROM times WHERE shipcall_id = shipcall_id_var;
|
||||||
|
DELETE FROM history WHERE shipcall_id = shipcall_id_var;
|
||||||
|
DELETE FROM shipcall WHERE id = shipcall_id_var;
|
||||||
|
END LOOP;
|
||||||
|
CLOSE shipcall_iter;
|
||||||
|
END ;;
|
||||||
|
DELIMITER ;
|
||||||
|
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||||
|
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
||||||
|
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
||||||
|
/*!50003 SET collation_connection = @saved_col_connection */ ;
|
||||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||||
|
|
||||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||||
@ -349,4 +507,4 @@ CREATE TABLE `user_role_map` (
|
|||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
-- Dump completed on 2023-10-06 14:52:04
|
-- Dump completed on 2025-11-17 8:26:36
|
||||||
|
|||||||
BIN
misc/favicon.ico
Normal file
BIN
misc/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
11
misc/index.html
Normal file
11
misc/index.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Bremen Calling</title>
|
||||||
|
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
misc/logo_bremen_calling_small.png
Normal file
BIN
misc/logo_bremen_calling_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
113
misc/notifications.md
Normal file
113
misc/notifications.md
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
# Benachrichtigungen
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## Benachrichtigungs-Typen (Auslöser)
|
||||||
|
|
||||||
|
### 1. Teilnehmer wird zugeordnet
|
||||||
|
|
||||||
|
Ein Teilnehmer wird über die Anwendung einem Anlauf zugeordnet. Dies ist entweder die Agentur (durch BSMD zugeordnet) oder ein weiterer Teilnehmer außer dem Hafenamt, der durch die Agentur zugeordnet wird. Die Zuordnung des Hafenamts erfolgt automatisch bei Anlage des Anlaufs.
|
||||||
|
|
||||||
|
### 2. Morgenrunde ist relevant
|
||||||
|
|
||||||
|
Ein Teilnehmer ist einem Anlauf zugeordnet. Dieser Anlauf findet in den nächsten 24 Stunden statt und ist daher für die "Morgenrunde" relevant. Der Teilnehmer erhält dazu eine Benachrichtigung.
|
||||||
|
|
||||||
|
### 3. Zeitlicher Konflikt ("Ampel")
|
||||||
|
|
||||||
|
Durch unterschiedliche Zeitangaben der Teilnehmer wird die Ampel ausgelöst und stellt eine entsprechende Fehlermeldung dar. Die Benachrichtigung wird ausgelöst bei folgenden Ampel-Wechseln:
|
||||||
|
|
||||||
|
* grün -> gelb
|
||||||
|
* grün -> rot
|
||||||
|
* gelb -> rot
|
||||||
|
|
||||||
|
### 4. Auflösung zeitl. Konflikt
|
||||||
|
|
||||||
|
* rot -> gelb
|
||||||
|
* rot -> grün
|
||||||
|
* gelb -> grün
|
||||||
|
|
||||||
|
### 5. Abwählen eines Teilnehmer
|
||||||
|
|
||||||
|
Der Teilnehmer ist nicht mehr länger dem Anlauf zugeordnet.
|
||||||
|
|
||||||
|
### 6. Fehlende Daten
|
||||||
|
|
||||||
|
Dienstleister, die 16 Stunden vor ETA/ETD und Agenturen, die 20 Stunden vor ETA/ETD keine Angaben gemacht haben.
|
||||||
|
|
||||||
|
### 7. Storno
|
||||||
|
|
||||||
|
Wird ein Anlauf storniert erhalten alle bis dahin zugeordneten Teilnehmer eine Benachrichtigung.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
NotificationType:
|
||||||
|
type: string
|
||||||
|
description: Type of notification
|
||||||
|
enum:
|
||||||
|
- assignment
|
||||||
|
- next24h
|
||||||
|
- time_conflict
|
||||||
|
- time_conflict_resolved
|
||||||
|
- unassigned
|
||||||
|
- missing_data
|
||||||
|
- cancelled
|
||||||
|
```
|
||||||
|
|
||||||
|
## Entfernen von Benachrichtigungen
|
||||||
|
|
||||||
|
Unter den folgenden Voraussetzungen werden Benachrichtigungen wieder aus dem System entfernt:
|
||||||
|
|
||||||
|
* Die Benachrichtigung ist älter als 3 Tage (n.B.: Zeitraum definieren)
|
||||||
|
* Ein Teilnehmer wird wieder abgewählt
|
||||||
|
* Ein zeitlicher Konflikt wird aufgelöst
|
||||||
|
|
||||||
|
## Ablauf der Benachrichtigungen
|
||||||
|
|
||||||
|
Eine Benachrichtung enthält folgende Informationen:
|
||||||
|
|
||||||
|
* Verweis auf den Anlauf (shipcall)
|
||||||
|
* ein Erstell- und Änderungsdatum
|
||||||
|
* einen Benachrichtigungs-Typ
|
||||||
|
* einen Zustand ("level")
|
||||||
|
|
||||||
|
Der Zustand steuert den Ablauf, wenn die Prüfungsfunktion die Anläufe durchsucht oder ein Anlauf gespeichert wird.
|
||||||
|
|
||||||
|
Wird einer der Zustände 1-3 erkannt wird geprüft, ob bereits eine Benachrichtigung vorhanden ist. Ist dies nicht der Fall, wird eine Benachrichtigung neu erstellt im Zustand "0".
|
||||||
|
|
||||||
|
Die Prüfungsfunktion durchläuft alle Benachrichtigungen. Abhängig vom Zustand (0-2) werden folgende Aktionen ausgeführt:
|
||||||
|
|
||||||
|
* Ist die Benachrichtigung um Zustand "0" und sind mind. 10 Minuten vergangen, wird die Benachrichtigung in den Zustand "1" versetzt.
|
||||||
|
|
||||||
|
* Ist die Benachrichtigung im Zustand "1" wird versucht, allen dafür eingetragenenen Benutzern eine E-Mail zu senden. Ist dies erfolgreich, wechselt die Benachrichtigung in den Zustand "2".
|
||||||
|
|
||||||
|
* Ist die Benachrichtigung im Zustand "2" und sind mind. 3 Tage vergangen wird die Benachrichtigung gelöscht.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
---
|
||||||
|
title: Ablauf
|
||||||
|
---
|
||||||
|
stateDiagram-v2
|
||||||
|
state "Level 0" as lvl0
|
||||||
|
state "Level 1" as lvl1
|
||||||
|
state "Level 2" as lvl2
|
||||||
|
[*] --> lvl0: Zustand 1-3 erkannt
|
||||||
|
lvl0 --> lvl1: +10 min.
|
||||||
|
lvl1 --> lvl2: E-Mail Versand erfolgt
|
||||||
|
lvl2 --> [*]: +3 Tage ODER Zustand 1-3 nicht mehr relevant
|
||||||
|
|
||||||
|
|
||||||
|
lvl0 --> [*]: Zustand 1-3 nicht mehr relevant
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bemerkungen
|
||||||
|
|
||||||
|
Für die Zukunft sind ggf. auch Benachrichtigungen via Whatsapp/Signal geplant. Diese verhalten sich analog zu den E-Mail Benachrichtigungen und werden nur einmal versendet. Die Anzahl der Zustände wird dabei erhöht bzw. der Wechsel in den Endzustand ensprechend angepasst.
|
||||||
|
|
||||||
|
## Benachrichtigungstext
|
||||||
|
|
||||||
|
... TBD
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
37
misc/requirements.txt
Normal file
37
misc/requirements.txt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
bcrypt==4.2.0
|
||||||
|
blinker==1.8.2
|
||||||
|
cached-property==1.5.2
|
||||||
|
click==8.1.7
|
||||||
|
coro-context-manager==0.2.0
|
||||||
|
coverage==7.6.1
|
||||||
|
dsnparse==0.1.15
|
||||||
|
Flask==3.0.3
|
||||||
|
Flask-JWT-Extended==4.6.0
|
||||||
|
iniconfig==2.0.0
|
||||||
|
itsdangerous==2.2.0
|
||||||
|
Jinja2==3.1.4
|
||||||
|
MarkupSafe==2.1.5
|
||||||
|
marshmallow==3.22.0
|
||||||
|
marshmallow-enum==1.5.1
|
||||||
|
marshmallow_dataclass==8.7.1
|
||||||
|
mypy-extensions==1.0.0
|
||||||
|
mysql-connector-python==9.0.0
|
||||||
|
numpy==2.1.1
|
||||||
|
packaging==24.1
|
||||||
|
pandas==2.2.3
|
||||||
|
pluggy==1.5.0
|
||||||
|
pydapper==0.10.0
|
||||||
|
PyJWT==2.9.0
|
||||||
|
pytest==8.3.3
|
||||||
|
pytest-cov==5.0.0
|
||||||
|
python-dateutil==2.9.0.post0
|
||||||
|
pytz==2024.2
|
||||||
|
schedule==1.2.2
|
||||||
|
six==1.16.0
|
||||||
|
tqdm==4.66.5
|
||||||
|
typeguard==4.3.0
|
||||||
|
typing-inspect==0.9.0
|
||||||
|
typing_extensions==4.12.2
|
||||||
|
tzdata==2024.1
|
||||||
|
webargs==8.6.0
|
||||||
|
Werkzeug==3.0.4
|
||||||
57
misc/update_1.5_to_1.6.sql
Normal file
57
misc/update_1.5_to_1.6.sql
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
CREATE TABLE `port` (
|
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(128) NOT NULL COMMENT 'Name of port',
|
||||||
|
`locode` char(5) DEFAULT NULL COMMENT 'UNECE locode',
|
||||||
|
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
`deleted` bit(1) DEFAULT b'0',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Port as reference for shipcalls and berths';
|
||||||
|
|
||||||
|
-- Add default port to table
|
||||||
|
INSERT INTO port (id, name, locode) VALUES (1, 'Bremen', 'DEBRE');
|
||||||
|
|
||||||
|
-- Adding new ref column to berth
|
||||||
|
ALTER TABLE `berth`
|
||||||
|
ADD COLUMN `port_id` INT UNSIGNED DEFAULT NULL AFTER `authority_id`;
|
||||||
|
ALTER TABLE `berth` ALTER INDEX `FK_AUTHORITY_PART_idx` INVISIBLE;
|
||||||
|
|
||||||
|
-- adding a foreign key berth.port_id -> port.id
|
||||||
|
ALTER TABLE `berth`
|
||||||
|
ADD INDEX `FK_PORT_PART_idx` (`port_id` ASC) VISIBLE;
|
||||||
|
|
||||||
|
ALTER TABLE `berth`
|
||||||
|
ADD CONSTRAINT `FK_PORT`
|
||||||
|
FOREIGN KEY (`port_id`)
|
||||||
|
REFERENCES `port` (`id`)
|
||||||
|
ON DELETE RESTRICT
|
||||||
|
ON UPDATE RESTRICT;
|
||||||
|
|
||||||
|
-- adding new ref column to shipcall incl. foreign key
|
||||||
|
ALTER TABLE `shipcall`
|
||||||
|
ADD COLUMN `port_id` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Selected port for this shipcall' AFTER `evaluation_notifications_sent`,
|
||||||
|
CHANGE COLUMN `time_ref_point` `time_ref_point` INT NULL DEFAULT '0' COMMENT 'Index of a location which is the reference point for all time value entries, e.g. berth or Geeste' AFTER `port_id`,
|
||||||
|
ADD INDEX `FK_SHIPCALL_PORT_idx` (`port_id` ASC) VISIBLE;
|
||||||
|
;
|
||||||
|
ALTER TABLE `shipcall`
|
||||||
|
ADD CONSTRAINT `FK_SHIPCALL_PORT`
|
||||||
|
FOREIGN KEY (`port_id`)
|
||||||
|
REFERENCES `port` (`id`)
|
||||||
|
ON DELETE RESTRICT
|
||||||
|
ON UPDATE RESTRICT;
|
||||||
|
|
||||||
|
CREATE TABLE `participant_port_map` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
|
`participant_id` int unsigned NOT NULL COMMENT 'Ref to participant',
|
||||||
|
`port_id` int unsigned NOT NULL COMMENT 'Ref to port',
|
||||||
|
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `FK_PP_PARTICIPANT` (`participant_id`),
|
||||||
|
KEY `FK_PP_PORT` (`port_id`),
|
||||||
|
CONSTRAINT `FK_PP_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`),
|
||||||
|
CONSTRAINT `FK_PP_PORT` FOREIGN KEY (`port_id`) REFERENCES `port` (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Mapping table that assigns participants to a port';
|
||||||
|
|
||||||
|
-- all existing berths shall default to "bremen"
|
||||||
|
UPDATE berth SET port_id = 1 where port_id is null;
|
||||||
13
misc/update_1.6_to_1.7.sql
Normal file
13
misc/update_1.6_to_1.7.sql
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
ALTER TABLE `notification`
|
||||||
|
ADD COLUMN `participant_id` INT UNSIGNED NULL DEFAULT NULL AFTER `shipcall_id`,
|
||||||
|
ADD INDEX `FK_NOTIFICATION_PARTICIPANT_idx` (`participant_id` ASC) VISIBLE;
|
||||||
|
;
|
||||||
|
ALTER TABLE `notification`
|
||||||
|
ADD CONSTRAINT `FK_NOTIFICATION_PARTICIPANT`
|
||||||
|
FOREIGN KEY (`participant_id`)
|
||||||
|
REFERENCES `participant` (`id`)
|
||||||
|
ON DELETE RESTRICT
|
||||||
|
ON UPDATE RESTRICT;
|
||||||
|
|
||||||
|
ALTER TABLE `user`
|
||||||
|
ADD COLUMN `notify_event` INT NULL COMMENT 'Bitflag of selected notification event types that the user wants to be notified of' AFTER `notify_popup`;
|
||||||
@ -1 +1 @@
|
|||||||
1.4.1.0
|
1.8.0.0
|
||||||
|
|||||||
10
misc/weserport.md
Normal file
10
misc/weserport.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Schnittstelle Weserport Anforderungen
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
|
Automatische Zuordnung:
|
||||||
|
|
||||||
|
* Hafenamt
|
||||||
|
* Festmacher
|
||||||
|
* Lotsen (>120m l 13m br)
|
||||||
|
|
||||||
@ -7,11 +7,12 @@
|
|||||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||||
xmlns:p = "clr-namespace:BreCalClient.Resources"
|
xmlns:p = "clr-namespace:BreCalClient.Resources"
|
||||||
mc:Ignorable="d" Left="{local:SettingBinding W1Left}" Top="{local:SettingBinding W1Top}"
|
mc:Ignorable="d" Left="{local:SettingBinding W1Left}" Top="{local:SettingBinding W1Top}"
|
||||||
Title="Help" Height="374" Width="500" Loaded="Window_Loaded">
|
Title="Help" Height="512" Width="800" Loaded="Window_Loaded">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="180" />
|
<ColumnDefinition Width="180" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width=".5*" />
|
||||||
|
<ColumnDefinition Width=".5*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
@ -25,6 +26,13 @@
|
|||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="10" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="10" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
|
|
||||||
@ -42,21 +50,33 @@
|
|||||||
Informatikbüro Daniel Schick
|
Informatikbüro Daniel Schick
|
||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
<Border BorderThickness="0 0 0 2" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" BorderBrush="Gray" />
|
||||||
<Label FontWeight="DemiBold" Grid.Row="3" Grid.Column="0" Content="{x:Static p:Resources.textChangeContactInfo}" HorizontalContentAlignment="Right"/>
|
<Label FontWeight="DemiBold" Grid.Row="3" Grid.Column="0" Content="{x:Static p:Resources.textChangeContactInfo}" HorizontalContentAlignment="Right"/>
|
||||||
<Label Grid.Row="4" Grid.Column="0" Content="{x:Static p:Resources.textEmail}" HorizontalContentAlignment="Right" />
|
<Label Grid.Row="4" Grid.Column="0" Content="{x:Static p:Resources.textEmail}" HorizontalContentAlignment="Right" />
|
||||||
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static p:Resources.textPhone}" HorizontalContentAlignment="Right" />
|
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static p:Resources.textPhone}" HorizontalContentAlignment="Right" />
|
||||||
<TextBox Name="textBoxUserEmail" Grid.Column="1" Grid.Row="4" Margin="2" VerticalContentAlignment="Center" />
|
<TextBox Name="textBoxUserEmail" Grid.Column="1" Grid.Row="4" Margin="2" VerticalContentAlignment="Center" />
|
||||||
<TextBox Name="textBoxUserPhone" Grid.Column="1" Grid.Row="5" Margin="2" VerticalContentAlignment="Center" />
|
<TextBox Name="textBoxUserPhone" Grid.Column="1" Grid.Row="5" Margin="2" VerticalContentAlignment="Center" />
|
||||||
|
|
||||||
<Label FontWeight="DemiBold" Grid.Row="7" Grid.Column="0" Content="{x:Static p:Resources.textChangePassword}" HorizontalContentAlignment="Right"/>
|
<Label FontWeight="DemiBold" Grid.Row="7" Grid.Column="0" Content="{x:Static p:Resources.textNotifications}" HorizontalContentAlignment="Right"/>
|
||||||
|
<CheckBox HorizontalAlignment="Right" Margin="2" Grid.Column="0" Grid.Row="8" VerticalAlignment="Center" x:Name="checkboxEMailNotify" />
|
||||||
<xctk:WatermarkPasswordBox Watermark="{x:Static p:Resources.textOldPassword}" Grid.Column="1" Grid.Row="7" Margin="2" x:Name="wpBoxOldPassword" TextChanged="wpBoxOldPassword_TextChanged"/>
|
<Label Grid.Row="8" Grid.Column="1" Content="{x:Static p:Resources.textNotifyEmail}" />
|
||||||
<xctk:WatermarkPasswordBox Watermark="{x:Static p:Resources.textNewPassword}" Grid.Column="1" Grid.Row="8" Margin="2" x:Name="wpBoxNewPassword" TextChanged="wpBoxOldPassword_TextChanged"/>
|
<CheckBox HorizontalAlignment="Right" Margin="2" Grid.Column="0" Grid.Row="9" VerticalAlignment="Center" x:Name="checkboxPushNotify" />
|
||||||
<xctk:WatermarkPasswordBox Watermark="{x:Static p:Resources.textRepeatNewPassword}" Grid.Column="1" Grid.Row="9" Margin="2" x:Name="wpBoxNewPasswordRepeat" TextChanged="wpBoxOldPassword_TextChanged"/>
|
<Label Grid.Row="9" Grid.Column="1" Content="{x:Static p:Resources.textNotifyPush}" />
|
||||||
<Button x:Name="buttonChangePassword" Click="buttonChangePassword_Click" Grid.Column="1" Grid.Row="10" Margin="2" Content="{x:Static p:Resources.textChange}" Width="80" HorizontalAlignment="Left" IsEnabled="True" />
|
<Label Grid.Row="7" Grid.Column="2" Content="{x:Static p:Resources.textNotifyOn}" />
|
||||||
|
<xctk:CheckListBox Grid.Column="2" Grid.Row="8" Grid.RowSpan="3" x:Name="checkListBoxEventSelection" Margin="2" />
|
||||||
|
<Button x:Name="buttonChangeUserFields" Click="buttonChangeUserFields_Click" Grid.Column="2" Grid.Row="11" Margin="2" Content="{x:Static p:Resources.textChange}" Width="80" HorizontalAlignment="Right" IsEnabled="True" />
|
||||||
|
|
||||||
<Button x:Name="buttonClose" Click="buttonClose_Click" Content="{x:Static p:Resources.textClose}" Width="80" Margin="2" Grid.Column="1" Grid.Row="12" HorizontalAlignment="Right" />
|
<Border BorderThickness="0 0 0 2" Grid.Row="12" Grid.Column="0" Grid.ColumnSpan="3" BorderBrush="Gray" />
|
||||||
|
<Label FontWeight="DemiBold" Grid.Row="13" Grid.Column="0" Content="{x:Static p:Resources.textChangePassword}" HorizontalContentAlignment="Right"/>
|
||||||
|
|
||||||
|
<xctk:WatermarkPasswordBox Watermark="{x:Static p:Resources.textOldPassword}" Grid.Column="1" Grid.Row="13" Margin="2" x:Name="wpBoxOldPassword" TextChanged="wpBoxOldPassword_TextChanged"/>
|
||||||
|
<xctk:WatermarkPasswordBox Watermark="{x:Static p:Resources.textNewPassword}" Grid.Column="1" Grid.Row="14" Margin="2" x:Name="wpBoxNewPassword" TextChanged="wpBoxOldPassword_TextChanged"/>
|
||||||
|
<xctk:WatermarkPasswordBox Watermark="{x:Static p:Resources.textRepeatNewPassword}" Grid.Column="1" Grid.Row="15" Margin="2" x:Name="wpBoxNewPasswordRepeat" TextChanged="wpBoxOldPassword_TextChanged"/>
|
||||||
|
<Button x:Name="buttonChangePassword" Click="buttonChangePassword_Click" Grid.Column="1" Grid.Row="16" Margin="2" Content="{x:Static p:Resources.textChangePassword}" Width="120" HorizontalAlignment="Right" IsEnabled="False" />
|
||||||
|
<Border BorderThickness="0 0 0 2" Grid.Row="17" Grid.Column="0" Grid.ColumnSpan="3" BorderBrush="Gray" />
|
||||||
|
|
||||||
|
|
||||||
|
<Button x:Name="buttonClose" Click="buttonClose_Click" Content="{x:Static p:Resources.textClose}" Width="80" Margin="2" Grid.Column="2" Grid.Row="19" HorizontalAlignment="Right" />
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@ -34,6 +34,7 @@ namespace BreCalClient
|
|||||||
#region events
|
#region events
|
||||||
|
|
||||||
public event Action<string, string>? ChangePasswordRequested;
|
public event Action<string, string>? ChangePasswordRequested;
|
||||||
|
public event Action? ChangeUserSettingsRequested;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -45,14 +46,25 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void buttonChangePassword_Click(object sender, RoutedEventArgs e)
|
private void buttonChangePassword_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.ChangePasswordRequested?.Invoke(this.wpBoxOldPassword.Password, this.wpBoxNewPassword.Password);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buttonChangeUserFields_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (this.LoginResult != null)
|
if (this.LoginResult != null)
|
||||||
{
|
{
|
||||||
this.LoginResult.UserPhone = this.textBoxUserPhone.Text.Trim();
|
this.LoginResult.UserPhone = this.textBoxUserPhone.Text.Trim();
|
||||||
this.LoginResult.UserEmail = this.textBoxUserEmail.Text.Trim();
|
this.LoginResult.UserEmail = this.textBoxUserEmail.Text.Trim();
|
||||||
|
this.LoginResult.NotifyEmail = this.checkboxEMailNotify.IsChecked ?? false;
|
||||||
|
this.LoginResult.NotifyPopup = this.checkboxPushNotify.IsChecked ?? false;
|
||||||
|
if ((this.checkListBoxEventSelection.SelectedItems.Count > 0) && (this.LoginResult.NotifyOn == null))
|
||||||
|
this.LoginResult.NotifyOn = new();
|
||||||
|
this.LoginResult.NotifyOn.Clear();
|
||||||
|
foreach (NotificationType nt in this.checkListBoxEventSelection.SelectedItems)
|
||||||
|
this.LoginResult.NotifyOn.Add(nt);
|
||||||
|
this.ChangeUserSettingsRequested?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ChangePasswordRequested?.Invoke(this.wpBoxOldPassword.Password, this.wpBoxNewPassword.Password);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
|
private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
|
||||||
@ -73,13 +85,23 @@ namespace BreCalClient
|
|||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
this.checkListBoxEventSelection.ItemsSource = Enum.GetValues(typeof(BreCalClient.misc.Model.NotificationType));
|
||||||
|
|
||||||
if(LoginResult != null)
|
if(LoginResult != null)
|
||||||
{
|
{
|
||||||
this.textBoxUserEmail.Text = LoginResult.UserEmail;
|
this.textBoxUserEmail.Text = LoginResult.UserEmail;
|
||||||
this.textBoxUserPhone.Text = LoginResult.UserPhone;
|
this.textBoxUserPhone.Text = LoginResult.UserPhone;
|
||||||
|
this.checkboxEMailNotify.IsChecked = LoginResult.NotifyEmail;
|
||||||
|
this.checkboxPushNotify.IsChecked = LoginResult.NotifyPopup;
|
||||||
|
if (LoginResult.NotifyOn != null)
|
||||||
|
{
|
||||||
|
foreach (NotificationType nt in LoginResult.NotifyOn)
|
||||||
|
this.checkListBoxEventSelection.SelectedItems.Add(nt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,13 +32,13 @@
|
|||||||
<value>#751D1F</value>
|
<value>#751D1F</value>
|
||||||
</setting>
|
</setting>
|
||||||
<setting name="APP_TITLE" serializeAs="String">
|
<setting name="APP_TITLE" serializeAs="String">
|
||||||
<value>!!Bremen calling Testversion!!</value>
|
<value>!!Bremen calling Entwicklungsversion!!</value>
|
||||||
</setting>
|
</setting>
|
||||||
<setting name="LOGO_IMAGE_URL" serializeAs="String">
|
<setting name="LOGO_IMAGE_URL" serializeAs="String">
|
||||||
<value>https://www.textbausteine.net/</value>
|
<value>https://www.textbausteine.net/</value>
|
||||||
</setting>
|
</setting>
|
||||||
<setting name="API_URL" serializeAs="String">
|
<setting name="API_URL" serializeAs="String">
|
||||||
<value>http://127.0.0.1:5000</value>
|
<value>https://brecaltest.bsmd-emswe.eu</value>
|
||||||
</setting>
|
</setting>
|
||||||
</BreCalClient.Properties.Settings>
|
</BreCalClient.Properties.Settings>
|
||||||
</applicationSettings>
|
</applicationSettings>
|
||||||
@ -86,6 +86,12 @@
|
|||||||
<setting name="FilterCriteriaMap" serializeAs="String">
|
<setting name="FilterCriteriaMap" serializeAs="String">
|
||||||
<value />
|
<value />
|
||||||
</setting>
|
</setting>
|
||||||
|
<setting name="W5Top" serializeAs="String">
|
||||||
|
<value>0</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="W5Left" serializeAs="String">
|
||||||
|
<value>0</value>
|
||||||
|
</setting>
|
||||||
</BreCalClient.Properties.Settings>
|
</BreCalClient.Properties.Settings>
|
||||||
</userSettings>
|
</userSettings>
|
||||||
</configuration>
|
</configuration>
|
||||||
@ -3,6 +3,7 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="clr-namespace:BreCalClient"
|
xmlns:local="clr-namespace:BreCalClient"
|
||||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
|
||||||
StartupUri="MainWindow.xaml" Exit="Application_Exit" Startup="Application_Startup" >
|
StartupUri="MainWindow.xaml" Exit="Application_Exit" Startup="Application_Startup" >
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
|
||||||
@ -14,6 +15,95 @@
|
|||||||
<sys:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">10</sys:Double>
|
<sys:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">10</sys:Double>
|
||||||
<sys:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">10</sys:Double>
|
<sys:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">10</sys:Double>
|
||||||
|
|
||||||
|
<Color x:Key="InformationColor">#147ec9</Color>
|
||||||
|
<SolidColorBrush x:Key="InformationColorBrush" Color="{StaticResource InformationColor}" options:Freeze="True" />
|
||||||
|
|
||||||
|
<Color x:Key="SuccessColor">#11ad45</Color>
|
||||||
|
<SolidColorBrush x:Key="SuccessColorBrush" Color="{StaticResource SuccessColor}" options:Freeze="True" />
|
||||||
|
|
||||||
|
<Color x:Key="ErrorColor">#e60914</Color>
|
||||||
|
<SolidColorBrush x:Key="ErrorColorBrush" Color="{StaticResource ErrorColor}" options:Freeze="True" />
|
||||||
|
|
||||||
|
<Color x:Key="WarningColor">#f5a300</Color>
|
||||||
|
<SolidColorBrush x:Key="WarningColorBrush" Color="{StaticResource WarningColor}" options:Freeze="True" />
|
||||||
|
|
||||||
|
<Canvas x:Key="InformationIcon" Width="24" Height="24">
|
||||||
|
<Path Data="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z" Fill="White" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
<Canvas x:Key="SuccessIcon" Width="24" Height="24">
|
||||||
|
<Path Data="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" Fill="White" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
<Canvas x:Key="ErrorIcon" Width="24" Height="24">
|
||||||
|
<Path Data="M11,15H13V17H11V15M11,7H13V13H11V7M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20Z" Fill="White" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
<Canvas x:Key="WarningIcon" Width="24" Height="24">
|
||||||
|
<Path Data="M12,2L1,21H23M12,6L19.53,19H4.47M11,10V14H13V10M11,16V18H13V16" Fill="White" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
<Canvas x:Key="CloseIcon" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
|
||||||
|
<Path Width="31.6666" Height="31.6667" Canvas.Left="22.1666" Canvas.Top="22.1667" Stretch="Fill" Fill="#FF000000" Data="F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z "/>
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
<Style TargetType="Border" x:Key="NotificationBorder">
|
||||||
|
<Setter Property="Padding" Value="5" />
|
||||||
|
<Setter Property="Effect">
|
||||||
|
<Setter.Value>
|
||||||
|
<DropShadowEffect Opacity="0.5" ShadowDepth="1" BlurRadius="2" />
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style TargetType="Rectangle" x:Key="NotificationIcon">
|
||||||
|
<Setter Property="Width" Value="24"/>
|
||||||
|
<Setter Property="Height" Value="24"/>
|
||||||
|
<Setter Property="Margin" Value="0,5,5,5" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
<Setter Property="Fill" Value="White"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style TargetType="TextBlock" x:Key="NotificationText">
|
||||||
|
<Setter Property="Foreground" Value="White" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||||
|
<Setter Property="TextWrapping" Value="Wrap" />
|
||||||
|
<Setter Property="Margin" Value="5,0,0,0" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style TargetType="{x:Type Button}" x:Key="NotificationCloseButton">
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
<Setter Property="Foreground" Value="#FFF" />
|
||||||
|
<Setter Property="FontSize" Value="15" />
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Top" />
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
|
<Border Background="{TemplateBinding Background}">
|
||||||
|
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" />
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="#33000000" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter Property="Background" Value="#77000000" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style TargetType="Rectangle" x:Key="CloseButtonIcon">
|
||||||
|
<Setter Property="Width" Value="10"/>
|
||||||
|
<Setter Property="Height" Value="10"/>
|
||||||
|
<Setter Property="Fill" Value="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
|
|||||||
207
src/BreCalClient/AppNotification.cs
Normal file
207
src/BreCalClient/AppNotification.cs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
// Copyright (c) 2024- schick Informatik
|
||||||
|
// Description: Helper (static) class to handle polled API notifications
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using ToastNotifications.Core;
|
||||||
|
using BreCalClient.misc.Model;
|
||||||
|
|
||||||
|
namespace BreCalClient
|
||||||
|
{
|
||||||
|
internal class AppNotification(int id)
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<int, AppNotification> _notifications = [];
|
||||||
|
private static readonly ObservableCollection<AppNotification> _notificationsCollection = [];
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public int Id { get { return id; } }
|
||||||
|
|
||||||
|
public string? NotificationType
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? NotificationDisplay
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? NotificationDate
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Ship
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? ShipcallType
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Berth
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? ETA
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Message
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ObservableCollection<AppNotification> AppNotifications { get { return _notificationsCollection; } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region internal statics
|
||||||
|
|
||||||
|
internal static void LoadFromSettings()
|
||||||
|
{
|
||||||
|
_notifications.Clear();
|
||||||
|
|
||||||
|
if (Properties.Settings.Default.Notifications != null)
|
||||||
|
{
|
||||||
|
// load notification ids that have been processed
|
||||||
|
foreach (string? notification_id in Properties.Settings.Default.Notifications)
|
||||||
|
{
|
||||||
|
if (Int32.TryParse(notification_id, out int result))
|
||||||
|
_notifications.Add(result, new AppNotification(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Clear()
|
||||||
|
{
|
||||||
|
_notifications.Clear();
|
||||||
|
SaveNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool UpdateNotifications(List<Notification> notifications, System.Collections.Concurrent.ConcurrentDictionary<int, ShipcallControlModel> currentShipcalls, ToastViewModel vm, LoginResult loginResult)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
foreach (Notification notification in notifications)
|
||||||
|
{
|
||||||
|
if (notification.ParticipantId.HasValue && notification.ParticipantId.Value != App.Participant.Id) // not meant for us
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!currentShipcalls.ContainsKey(notification.ShipcallId)) // not one of our shipcalls (maybe for another port or filtered)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// filter out notifications for shipcalls where we are not nomiated/assigned
|
||||||
|
if (!notification.ParticipantId.HasValue)
|
||||||
|
{
|
||||||
|
bool iAmAssigned = false;
|
||||||
|
foreach (ParticipantAssignment p in currentShipcalls[notification.ShipcallId].AssignedParticipants.Values)
|
||||||
|
{
|
||||||
|
if (p.ParticipantId.Equals(App.Participant.Id))
|
||||||
|
{
|
||||||
|
iAmAssigned = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!iAmAssigned) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter out notifications the user is not interested in
|
||||||
|
if((notification.Type != null) && !loginResult.NotifyOn.Contains(notification.Type.Value))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!_notificationsCollection.Where(x => x.Id == notification.Id).Any())
|
||||||
|
{
|
||||||
|
List<AppNotification> newList = new(_notificationsCollection);
|
||||||
|
|
||||||
|
AppNotification ap = new(notification.Id)
|
||||||
|
{
|
||||||
|
NotificationType = notification.Type.ToString(),
|
||||||
|
NotificationDate = notification.Created.ToString(),
|
||||||
|
Ship = currentShipcalls[notification.ShipcallId]?.Ship?.Name,
|
||||||
|
ShipcallType = currentShipcalls[notification.ShipcallId]?.Shipcall?.Type.ToString(),
|
||||||
|
ETA = currentShipcalls[notification.ShipcallId]?.GetETAETD(true)
|
||||||
|
};
|
||||||
|
Times? agencyTimes = currentShipcalls[notification.ShipcallId]?.GetTimesForParticipantType(Extensions.ParticipantType.AGENCY);
|
||||||
|
ap.Berth = currentShipcalls[notification.ShipcallId]?.GetBerthText(agencyTimes);
|
||||||
|
ap.Message = notification.Message;
|
||||||
|
|
||||||
|
System.Diagnostics.Trace.WriteLine($"Notification {notification.Id} Type {notification.Type}");
|
||||||
|
MessageOptions options = new()
|
||||||
|
{
|
||||||
|
FontSize = 14,
|
||||||
|
ShowCloseButton = true,
|
||||||
|
Tag = ap
|
||||||
|
};
|
||||||
|
|
||||||
|
newList.Add(ap);
|
||||||
|
newList.Sort((a, b) => (a.NotificationDate ?? "").CompareTo(b.NotificationDate));
|
||||||
|
_notificationsCollection.Clear();
|
||||||
|
foreach(AppNotification newAp in newList)
|
||||||
|
_notificationsCollection.Add(newAp);
|
||||||
|
|
||||||
|
ap.NotificationDisplay = string.Empty;
|
||||||
|
switch(notification.Type)
|
||||||
|
{
|
||||||
|
case misc.Model.NotificationType.Assignment:
|
||||||
|
ap.NotificationDisplay = Resources.Resources.textAssignment; break;
|
||||||
|
case misc.Model.NotificationType.Next24h:
|
||||||
|
ap.NotificationDisplay = Resources.Resources.textNext24h; break;
|
||||||
|
case misc.Model.NotificationType.TimeConflict:
|
||||||
|
ap.NotificationDisplay = Resources.Resources.textTimeConflict; break;
|
||||||
|
case misc.Model.NotificationType.TimeConflictResolved:
|
||||||
|
ap.NotificationDisplay = Resources.Resources.textTimeConflictResolved; break;
|
||||||
|
case misc.Model.NotificationType.MissingData:
|
||||||
|
ap.NotificationDisplay = Resources.Resources.textMissingData; break;
|
||||||
|
case misc.Model.NotificationType.Cancelled:
|
||||||
|
ap.NotificationDisplay = Resources.Resources.textCancelled; break;
|
||||||
|
case misc.Model.NotificationType.Unassigned:
|
||||||
|
ap.NotificationDisplay = Resources.Resources.textUnassigned; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string toastText = ap.NotificationDisplay + "\n";
|
||||||
|
|
||||||
|
toastText += $"{ap.Ship} ({ap.ShipcallType}) - {ap.ETA} - {ap.Berth}";
|
||||||
|
if (!string.IsNullOrEmpty(ap.Message))
|
||||||
|
toastText += $" \n{ap.Message}";
|
||||||
|
|
||||||
|
if (_notifications.TryAdd(notification.Id, ap))
|
||||||
|
{
|
||||||
|
App.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
vm.ShowAppNotification(toastText, options);
|
||||||
|
});
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
SaveNotifications(); // store notification ids in config array on change
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void SaveNotifications()
|
||||||
|
{
|
||||||
|
if (Properties.Settings.Default.Notifications == null)
|
||||||
|
Properties.Settings.Default.Notifications = [];
|
||||||
|
else
|
||||||
|
Properties.Settings.Default.Notifications.Clear();
|
||||||
|
foreach (int notification_id in _notifications.Keys)
|
||||||
|
{
|
||||||
|
Properties.Settings.Default.Notifications.Add(notification_id.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/BreCalClient/AppNotificationExtension.cs
Normal file
23
src/BreCalClient/AppNotificationExtension.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2024- schick Informatik
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
|
||||||
|
using ToastNotifications;
|
||||||
|
using ToastNotifications.Core;
|
||||||
|
|
||||||
|
namespace BreCalClient
|
||||||
|
{
|
||||||
|
public static class AppNotificationExtension
|
||||||
|
{
|
||||||
|
public static void ShowAppNotification(this Notifier notifier, string message)
|
||||||
|
{
|
||||||
|
notifier.Notify(() => new AppNotificationMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ShowAppNotification(this Notifier notifier, string message, MessageOptions displayOptions)
|
||||||
|
{
|
||||||
|
notifier.Notify(() => new AppNotificationMessage(message, displayOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/BreCalClient/AppNotificationMessage.cs
Normal file
30
src/BreCalClient/AppNotificationMessage.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using ToastNotifications.Core;
|
||||||
|
using ToastNotifications.Messages.Core;
|
||||||
|
|
||||||
|
namespace BreCalClient
|
||||||
|
{
|
||||||
|
public class AppNotificationMessage : MessageBase<AppNotificationPart>
|
||||||
|
{
|
||||||
|
public AppNotificationMessage(string message) : this(message, new MessageOptions())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppNotificationMessage(string message, MessageOptions options) : base(message, options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override AppNotificationPart CreateDisplayPart()
|
||||||
|
{
|
||||||
|
return new AppNotificationPart(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateDisplayOptions(AppNotificationPart displayPart, MessageOptions options)
|
||||||
|
{
|
||||||
|
// if (options.FontSize != null)
|
||||||
|
// displayPart.Text.FontSize = options.FontSize.Value;
|
||||||
|
|
||||||
|
// displayPart.CloseButton.Visibility = options.ShowCloseButton ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/BreCalClient/AppNotificationPart.xaml
Normal file
31
src/BreCalClient/AppNotificationPart.xaml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<core:NotificationDisplayPart x:Class="BreCalClient.AppNotificationPart"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:core="clr-namespace:ToastNotifications.Core;assembly=ToastNotifications"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="250" >
|
||||||
|
<Border x:Name="ContentWrapper" Style="{DynamicResource NotificationBorder}" Background="{DynamicResource ErrorColorBrush}">
|
||||||
|
<Grid x:Name="ContentContainer">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="25" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Rectangle x:Name="Icon" Width="24" Height="24">
|
||||||
|
<Rectangle.Fill>
|
||||||
|
<VisualBrush Visual="{StaticResource ErrorIcon}" />
|
||||||
|
</Rectangle.Fill>
|
||||||
|
</Rectangle>
|
||||||
|
|
||||||
|
<TextBlock x:Name="Text" Text="{Binding Message, Mode=OneTime}" Style="{StaticResource NotificationText}" Grid.Column="1" />
|
||||||
|
<Button x:Name="CloseButton" Style="{StaticResource NotificationCloseButton}" Padding="1" Grid.Column="2" Click="OnClose" Visibility="Hidden">
|
||||||
|
<Rectangle Style="{StaticResource CloseButtonIcon}" Margin="2">
|
||||||
|
<Rectangle.OpacityMask>
|
||||||
|
<VisualBrush Stretch="Fill" Visual="{StaticResource CloseIcon}" />
|
||||||
|
</Rectangle.OpacityMask>
|
||||||
|
</Rectangle>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</core:NotificationDisplayPart>
|
||||||
57
src/BreCalClient/AppNotificationPart.xaml.cs
Normal file
57
src/BreCalClient/AppNotificationPart.xaml.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using BreCalClient.misc.Model;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using ToastNotifications.Core;
|
||||||
|
|
||||||
|
namespace BreCalClient
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for NotificationPart.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class AppNotificationPart : NotificationDisplayPart
|
||||||
|
{
|
||||||
|
public AppNotificationPart(AppNotificationMessage appNotification)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
Bind(appNotification);
|
||||||
|
|
||||||
|
if (appNotification.Options.Tag is AppNotification ap)
|
||||||
|
{
|
||||||
|
switch (ap.NotificationType)
|
||||||
|
{
|
||||||
|
case "TimeConflict":
|
||||||
|
this.ContentWrapper.Background = Brushes.Red;
|
||||||
|
break;
|
||||||
|
case "TimeConflictResolved":
|
||||||
|
this.ContentWrapper.Background = Brushes.Green;
|
||||||
|
break;
|
||||||
|
case "Assignment":
|
||||||
|
this.ContentWrapper.Background = Brushes.Blue;
|
||||||
|
break;
|
||||||
|
case "Next24h":
|
||||||
|
this.ContentWrapper.Background = Brushes.DarkOrange;
|
||||||
|
break;
|
||||||
|
case "Unassigned":
|
||||||
|
this.ContentWrapper.Background = Brushes.Gray;
|
||||||
|
break;
|
||||||
|
case "MissingData":
|
||||||
|
this.ContentWrapper.Background = Brushes.DarkKhaki;
|
||||||
|
break;
|
||||||
|
case "Cancelled":
|
||||||
|
this.ContentWrapper.Background = Brushes.DarkGray;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClose(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Notification.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<SignAssembly>True</SignAssembly>
|
<SignAssembly>True</SignAssembly>
|
||||||
<StartupObject>BreCalClient.App</StartupObject>
|
<StartupObject>BreCalClient.App</StartupObject>
|
||||||
<AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile>
|
||||||
<AssemblyVersion>1.5.0.10</AssemblyVersion>
|
<AssemblyVersion>1.8.0.0</AssemblyVersion>
|
||||||
<FileVersion>1.5.0.10</FileVersion>
|
<FileVersion>1.8.0.0</FileVersion>
|
||||||
<Title>Bremen calling client</Title>
|
<Title>Bremen calling client</Title>
|
||||||
<Description>A Windows WPF client for the Bremen calling API.</Description>
|
<Description>A Windows WPF client for the Bremen calling API.</Description>
|
||||||
<ApplicationIcon>containership.ico</ApplicationIcon>
|
<ApplicationIcon>containership.ico</ApplicationIcon>
|
||||||
@ -26,6 +26,7 @@
|
|||||||
<None Remove="Resources\arrow_up_blue.png" />
|
<None Remove="Resources\arrow_up_blue.png" />
|
||||||
<None Remove="Resources\arrow_up_green.png" />
|
<None Remove="Resources\arrow_up_green.png" />
|
||||||
<None Remove="Resources\arrow_up_red.png" />
|
<None Remove="Resources\arrow_up_red.png" />
|
||||||
|
<None Remove="Resources\bell3.png" />
|
||||||
<None Remove="Resources\check.png" />
|
<None Remove="Resources\check.png" />
|
||||||
<None Remove="Resources\clipboard.png" />
|
<None Remove="Resources\clipboard.png" />
|
||||||
<None Remove="Resources\clock.png" />
|
<None Remove="Resources\clock.png" />
|
||||||
@ -84,6 +85,7 @@
|
|||||||
<Resource Include="Resources\arrow_up_blue.png" />
|
<Resource Include="Resources\arrow_up_blue.png" />
|
||||||
<Resource Include="Resources\arrow_up_green.png" />
|
<Resource Include="Resources\arrow_up_green.png" />
|
||||||
<Resource Include="Resources\arrow_up_red.png" />
|
<Resource Include="Resources\arrow_up_red.png" />
|
||||||
|
<Resource Include="Resources\bell3.png" />
|
||||||
<Resource Include="Resources\check.png" />
|
<Resource Include="Resources\check.png" />
|
||||||
<Resource Include="Resources\clipboard.png" />
|
<Resource Include="Resources\clipboard.png" />
|
||||||
<Resource Include="Resources\clock.png" />
|
<Resource Include="Resources\clock.png" />
|
||||||
@ -118,10 +120,12 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.6.1" />
|
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.6.1" />
|
||||||
<PackageReference Include="JsonSubTypes" Version="2.0.1" />
|
<PackageReference Include="JsonSubTypes" Version="2.0.1" />
|
||||||
<PackageReference Include="log4net" Version="2.0.17" />
|
<PackageReference Include="log4net" Version="3.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Polly" Version="8.4.1" />
|
<PackageReference Include="Polly" Version="8.5.1" />
|
||||||
<PackageReference Include="RestSharp" Version="112.0.0" />
|
<PackageReference Include="RestSharp" Version="112.0.0" />
|
||||||
|
<PackageReference Include="ToastNotifications" Version="2.5.1" />
|
||||||
|
<PackageReference Include="ToastNotifications.Messages" Version="2.5.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -25,16 +25,19 @@ namespace BreCalClient
|
|||||||
private static List<Participant> _participants = new();
|
private static List<Participant> _participants = new();
|
||||||
private static readonly List<ShipModel> _ships = new();
|
private static readonly List<ShipModel> _ships = new();
|
||||||
private static readonly List<ShipModel> _allShips = new();
|
private static readonly List<ShipModel> _allShips = new();
|
||||||
|
private static readonly List<Port> _ports = new();
|
||||||
|
private static readonly List<Port> _allPorts = new();
|
||||||
|
|
||||||
private readonly static ConcurrentDictionary<int, ShipModel> _shipLookupDict = new();
|
private readonly static ConcurrentDictionary<int, ShipModel> _shipLookupDict = new();
|
||||||
private readonly static ConcurrentDictionary<int, Berth> _berthLookupDict = new();
|
private readonly static ConcurrentDictionary<int, Berth> _berthLookupDict = new();
|
||||||
private readonly static Dictionary<int, Participant> _participantLookupDict = new();
|
private readonly static Dictionary<int, Participant> _participantLookupDict = new();
|
||||||
|
private readonly static ConcurrentDictionary<int, Port> _portLookupDict = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of TimeRef points
|
/// List of TimeRef points
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// TODO: To make this portable the list of texts should come from a configuration file
|
// TODO: To make this portable the list of texts should come from a configuration file
|
||||||
private readonly static List<string> _timeRefs = new List<string>
|
private readonly static List<string> _timeRefs = new()
|
||||||
{
|
{
|
||||||
"ETB",
|
"ETB",
|
||||||
"Geeste",
|
"Geeste",
|
||||||
@ -45,12 +48,26 @@ namespace BreCalClient
|
|||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// fast ship lookup
|
||||||
|
/// </summary>
|
||||||
public static ConcurrentDictionary<int, ShipModel> ShipLookupDict { get { return _shipLookupDict; } }
|
public static ConcurrentDictionary<int, ShipModel> ShipLookupDict { get { return _shipLookupDict; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// fast port lookup
|
||||||
|
/// </summary>
|
||||||
public static ConcurrentDictionary<int, Berth> BerthLookupDict { get { return _berthLookupDict; } }
|
public static ConcurrentDictionary<int, Berth> BerthLookupDict { get { return _berthLookupDict; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// fast participant lookup
|
||||||
|
/// </summary>
|
||||||
public static Dictionary<int, Participant> ParticipantLookupDict { get { return _participantLookupDict; } }
|
public static Dictionary<int, Participant> ParticipantLookupDict { get { return _participantLookupDict; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// fast port lookup
|
||||||
|
/// </summary>
|
||||||
|
public static ConcurrentDictionary<int, Port> PortLookupDict { get { return _portLookupDict; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Participants that are agents
|
/// Participants that are agents
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -91,6 +108,16 @@ namespace BreCalClient
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static List<Berth> AllBerths { get { return _allBerths; } }
|
public static List<Berth> AllBerths { get { return _allBerths; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All active ports
|
||||||
|
/// </summary>
|
||||||
|
public static List<Port> Ports { get { return _ports; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All ports including deleted ports
|
||||||
|
/// </summary>
|
||||||
|
public static List<Port> AllPorts { get { return _allPorts; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All active ships
|
/// All active ships
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -108,7 +135,33 @@ namespace BreCalClient
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region methods
|
#region public static methods
|
||||||
|
|
||||||
|
public static List<Berth> GetBerthsByPort(int port)
|
||||||
|
{
|
||||||
|
List<Berth> berths = new();
|
||||||
|
foreach(Berth berth in _berths)
|
||||||
|
{
|
||||||
|
if(berth.PortId == port)
|
||||||
|
berths.Add(berth);
|
||||||
|
}
|
||||||
|
return berths;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Participant> GetParticipants(int port, Extensions.ParticipantType type)
|
||||||
|
{
|
||||||
|
List<Participant> participants = new();
|
||||||
|
foreach(Participant participant in _participants)
|
||||||
|
{
|
||||||
|
if(participant.IsTypeFlagSet(type) && participant.Ports.Contains(port))
|
||||||
|
participants.Add(participant);
|
||||||
|
}
|
||||||
|
return participants;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Internal initializer methods
|
||||||
|
|
||||||
internal static void InitializeParticipants(List<Participant> participants)
|
internal static void InitializeParticipants(List<Participant> participants)
|
||||||
{
|
{
|
||||||
@ -157,6 +210,17 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void InitializePorts(List<Port> ports)
|
||||||
|
{
|
||||||
|
foreach(var port in ports)
|
||||||
|
{
|
||||||
|
_portLookupDict[port.Id] = port;
|
||||||
|
if(!port.Deleted)
|
||||||
|
_ports.Add(port);
|
||||||
|
_allPorts.Add(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,9 @@
|
|||||||
<xctk:DoubleUpDown x:Name="doubleUpDownWidth" Margin="2" Grid.Column="1" Grid.Row="4" FormatString="N2" IsReadOnly="True" IsEnabled="False" ShowButtonSpinner="False"/>
|
<xctk:DoubleUpDown x:Name="doubleUpDownWidth" Margin="2" Grid.Column="1" Grid.Row="4" FormatString="N2" IsReadOnly="True" IsEnabled="False" ShowButtonSpinner="False"/>
|
||||||
<Label Content="{x:Static p:Resources.textCancelled}" Grid.Column="0" Grid.Row="5" HorizontalContentAlignment="Right" />
|
<Label Content="{x:Static p:Resources.textCancelled}" Grid.Column="0" Grid.Row="5" HorizontalContentAlignment="Right" />
|
||||||
<CheckBox x:Name="checkBoxCancelled" Grid.Column="1" Grid.Row="5" Margin="2" VerticalContentAlignment="Center" />
|
<CheckBox x:Name="checkBoxCancelled" Grid.Column="1" Grid.Row="5" Margin="2" VerticalContentAlignment="Center" />
|
||||||
<Button x:Name="buttonEditShips" Grid.Column="1" Grid.Row="6" Margin="2" Content="{x:Static p:Resources.textEditShips}" Click="buttonEditShips_Click" Visibility="Hidden" />
|
<Label Content="{x:Static p:Resources.textHarbour}" Grid.Column="0" Grid.Row="6" HorizontalContentAlignment="Right" />
|
||||||
|
<ComboBox x:Name="comboBoxHarbour" Grid.Column="1" Margin="2" Grid.Row="6" DisplayMemberPath="Name" SelectedValuePath="Id" />
|
||||||
|
<Button x:Name="buttonEditShips" Grid.Column="1" Grid.Row="7" Margin="2" Content="{x:Static p:Resources.textEditShips}" Click="buttonEditShips_Click" Visibility="Hidden" />
|
||||||
|
|
||||||
<Label Content="{x:Static p:Resources.textType}" Grid.Column="2" Grid.Row="0" HorizontalContentAlignment="Right" />
|
<Label Content="{x:Static p:Resources.textType}" Grid.Column="2" Grid.Row="0" HorizontalContentAlignment="Right" />
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ using BreCalClient.misc.Api;
|
|||||||
using BreCalClient.misc.Model;
|
using BreCalClient.misc.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using static BreCalClient.Extensions;
|
using static BreCalClient.Extensions;
|
||||||
@ -41,13 +42,14 @@ namespace BreCalClient
|
|||||||
|
|
||||||
public ShipApi? ShipApi { get; set; }
|
public ShipApi? ShipApi { get; set; }
|
||||||
|
|
||||||
|
public bool IsCreate { get; set; } = false;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Event handler
|
#region Event handler
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.comboBoxAgency.ItemsSource = BreCalLists.Participants_Agent;
|
|
||||||
|
|
||||||
this.comboBoxShip.ItemsSource = BreCalLists.Ships;
|
this.comboBoxShip.ItemsSource = BreCalLists.Ships;
|
||||||
Array types = Enum.GetValues(typeof(ShipcallType));
|
Array types = Enum.GetValues(typeof(ShipcallType));
|
||||||
@ -59,10 +61,8 @@ namespace BreCalClient
|
|||||||
else first = false;
|
else first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
|
|
||||||
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
|
|
||||||
|
|
||||||
this.comboBoxTimeRef.ItemsSource = BreCalLists.TimeRefs;
|
this.comboBoxTimeRef.ItemsSource = BreCalLists.TimeRefs;
|
||||||
|
this.comboBoxHarbour.ItemsSource = BreCalLists.Ports.Where(x => App.Participant.Ports.Contains(x.Id));
|
||||||
|
|
||||||
this.integerUpDownShiftingCount.Value = this.ShipcallModel.ShiftSequence;
|
this.integerUpDownShiftingCount.Value = this.ShipcallModel.ShiftSequence;
|
||||||
|
|
||||||
@ -86,21 +86,21 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void comboBoxShip_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void comboBoxShip_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (this.comboBoxShip.SelectedItem != null)
|
if (this.comboBoxShip.SelectedItem != null)
|
||||||
{
|
{
|
||||||
ShipModel? ship = this.comboBoxShip.SelectedItem as ShipModel;
|
ShipModel? ship = this.comboBoxShip.SelectedItem as ShipModel;
|
||||||
this.integerUpDownIMO.Value = ship?.Ship.Imo;
|
this.integerUpDownIMO.Value = ship?.Ship.Imo;
|
||||||
this.textBoxCallsign.Text = ship?.Ship.Callsign;
|
this.textBoxCallsign.Text = ship?.Ship.Callsign;
|
||||||
this.doubleUpDownLength.Value = ship?.Ship.Length;
|
this.doubleUpDownLength.Value = ship?.Ship.Length;
|
||||||
this.doubleUpDownWidth.Value = ship?.Ship.Width;
|
this.doubleUpDownWidth.Value = ship?.Ship.Width;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.integerUpDownIMO.Value = null;
|
this.integerUpDownIMO.Value = null;
|
||||||
this.textBoxCallsign.Text = string.Empty;
|
this.textBoxCallsign.Text = string.Empty;
|
||||||
this.doubleUpDownLength.Value = null;
|
this.doubleUpDownLength.Value = null;
|
||||||
this.doubleUpDownWidth.Value = null;
|
this.doubleUpDownWidth.Value = null;
|
||||||
}
|
}
|
||||||
this.CheckForCompletion();
|
this.CheckForCompletion();
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ShipcallType.Arrival:
|
case ShipcallType.Arrival:
|
||||||
this.datePickerETD.Visibility = Visibility.Hidden;
|
this.datePickerETD.Visibility = Visibility.Hidden;
|
||||||
this.labelETD.Visibility = Visibility.Hidden;
|
this.labelETD.Visibility = Visibility.Hidden;
|
||||||
this.datePickerETA.Visibility = Visibility.Visible;
|
this.datePickerETA.Visibility = Visibility.Visible;
|
||||||
@ -175,7 +175,7 @@ namespace BreCalClient
|
|||||||
this.comboBoxAgency.SelectedIndex = -1;
|
this.comboBoxAgency.SelectedIndex = -1;
|
||||||
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.AGENCY);
|
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.AGENCY);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region private methods
|
#region private methods
|
||||||
@ -188,10 +188,13 @@ namespace BreCalClient
|
|||||||
|
|
||||||
void CheckForCompletion()
|
void CheckForCompletion()
|
||||||
{
|
{
|
||||||
|
if (this.ShipcallModel.Shipcall?.Canceled ?? false) return; // Cancelled shipcall never clicks ok
|
||||||
|
|
||||||
bool isEnabled = true;
|
bool isEnabled = true;
|
||||||
|
|
||||||
isEnabled &= this.comboBoxShip.SelectedItem != null;
|
isEnabled &= this.comboBoxShip.SelectedItem != null;
|
||||||
isEnabled &= this.comboBoxCategories.SelectedItem != null;
|
isEnabled &= this.comboBoxCategories.SelectedItem != null;
|
||||||
|
isEnabled &= this.comboBoxHarbour.SelectedItem != null;
|
||||||
|
|
||||||
if (comboBoxCategories.SelectedItem == null)
|
if (comboBoxCategories.SelectedItem == null)
|
||||||
{
|
{
|
||||||
@ -207,7 +210,7 @@ namespace BreCalClient
|
|||||||
isEnabled &= this.datePickerETD.Value.HasValue;
|
isEnabled &= this.datePickerETD.Value.HasValue;
|
||||||
isEnabled &= !(this.datePickerETD.Value.IsTooOld() && this.datePickerETD.Value != this.ShipcallModel.Shipcall?.Etd);
|
isEnabled &= !(this.datePickerETD.Value.IsTooOld() && this.datePickerETD.Value != this.ShipcallModel.Shipcall?.Etd);
|
||||||
isEnabled &= !this.datePickerETD.Value.IsTooFar();
|
isEnabled &= !this.datePickerETD.Value.IsTooFar();
|
||||||
break;
|
break;
|
||||||
case ShipcallType.Arrival:
|
case ShipcallType.Arrival:
|
||||||
isEnabled &= this.comboBoxArrivalBerth.SelectedItem != null;
|
isEnabled &= this.comboBoxArrivalBerth.SelectedItem != null;
|
||||||
isEnabled &= this.datePickerETA.Value.HasValue;
|
isEnabled &= this.datePickerETA.Value.HasValue;
|
||||||
@ -227,7 +230,7 @@ namespace BreCalClient
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnabled &= this.comboBoxAgency.SelectedItem != null;
|
isEnabled &= this.comboBoxAgency.SelectedItem != null;
|
||||||
|
|
||||||
this.buttonOK.IsEnabled = isEnabled;
|
this.buttonOK.IsEnabled = isEnabled;
|
||||||
@ -249,7 +252,7 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
this.ShipcallModel.Shipcall.ArrivalBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
|
this.ShipcallModel.Shipcall.ArrivalBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
|
||||||
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxDepartureBerth.SelectedItem != null) ? ((Berth)this.comboBoxDepartureBerth.SelectedItem).Id : null;
|
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxDepartureBerth.SelectedItem != null) ? ((Berth)this.comboBoxDepartureBerth.SelectedItem).Id : null;
|
||||||
}
|
}
|
||||||
else // shifting
|
else // shifting
|
||||||
{
|
{
|
||||||
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
|
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
|
||||||
@ -264,11 +267,11 @@ namespace BreCalClient
|
|||||||
ParticipantAssignment pa = new()
|
ParticipantAssignment pa = new()
|
||||||
{
|
{
|
||||||
ParticipantId = participant.Id,
|
ParticipantId = participant.Id,
|
||||||
|
|
||||||
Type = (int)Extensions.ParticipantType.AGENCY
|
Type = (int)Extensions.ParticipantType.AGENCY
|
||||||
};
|
};
|
||||||
this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.AGENCY] = pa;
|
this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.AGENCY] = pa;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// AGENCY was set before and now is set to nothing
|
// AGENCY was set before and now is set to nothing
|
||||||
@ -309,7 +312,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
// set the time reference value (which point do all times refer to?)
|
// set the time reference value (which point do all times refer to?)
|
||||||
this.ShipcallModel.Shipcall.TimeRefPoint = this.comboBoxTimeRef.SelectedIndex;
|
this.ShipcallModel.Shipcall.TimeRefPoint = this.comboBoxTimeRef.SelectedIndex;
|
||||||
|
this.ShipcallModel.Shipcall.PortId = ((Port) this.comboBoxHarbour.SelectedItem).Id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,8 +324,8 @@ namespace BreCalClient
|
|||||||
this.comboBoxTimeRef.SelectedIndex = this.ShipcallModel.Shipcall.TimeRefPoint ?? 1;
|
this.comboBoxTimeRef.SelectedIndex = this.ShipcallModel.Shipcall.TimeRefPoint ?? 1;
|
||||||
this.comboBoxCategories.SelectedItem = new EnumToStringConverter().Convert(this.ShipcallModel.Shipcall.Type, typeof(ShipcallType), new object(), System.Globalization.CultureInfo.CurrentCulture);
|
this.comboBoxCategories.SelectedItem = new EnumToStringConverter().Convert(this.ShipcallModel.Shipcall.Type, typeof(ShipcallType), new object(), System.Globalization.CultureInfo.CurrentCulture);
|
||||||
if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
|
if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
|
||||||
this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
|
this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
|
||||||
// this.textBoxVoyage.Text = this.ShipcallModel.Shipcall.Voyage;
|
|
||||||
this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
|
this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
|
||||||
if (BreCalLists.Ships.Find(x => x.Ship.Id == this.ShipcallModel.Shipcall.ShipId) != null)
|
if (BreCalLists.Ships.Find(x => x.Ship.Id == this.ShipcallModel.Shipcall.ShipId) != null)
|
||||||
{
|
{
|
||||||
@ -333,6 +336,16 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
this.checkBoxCancelled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
this.checkBoxCancelled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
||||||
|
|
||||||
|
if (BreCalLists.PortLookupDict.ContainsKey(this.ShipcallModel.Shipcall.PortId))
|
||||||
|
this.comboBoxHarbour.SelectedValue = this.ShipcallModel.Shipcall.PortId;
|
||||||
|
List<Berth> availableBerths = BreCalLists.GetBerthsByPort(this.ShipcallModel.Shipcall.PortId);
|
||||||
|
this.comboBoxArrivalBerth.ItemsSource = availableBerths;
|
||||||
|
this.comboBoxDepartureBerth.ItemsSource = availableBerths;
|
||||||
|
|
||||||
|
// Filter agency combobox by port
|
||||||
|
List<Participant> availableAgencies = BreCalLists.GetParticipants(this.ShipcallModel.Shipcall.PortId, ParticipantType.AGENCY);
|
||||||
|
this.comboBoxAgency.ItemsSource = availableAgencies;
|
||||||
|
|
||||||
if (this.ShipcallModel.Shipcall.Type != ShipcallType.Shifting) // incoming, outgoing
|
if (this.ShipcallModel.Shipcall.Type != ShipcallType.Shifting) // incoming, outgoing
|
||||||
{
|
{
|
||||||
this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
|
this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
|
||||||
@ -345,14 +358,18 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.ShipcallModel.Shipcall.Participants == null) this.ShipcallModel.Shipcall.Participants = new();
|
if (this.ShipcallModel.Shipcall.Participants == null) this.ShipcallModel.Shipcall.Participants = new();
|
||||||
|
|
||||||
if(this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
if(this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||||
{
|
{
|
||||||
if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId))
|
if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId))
|
||||||
{
|
{
|
||||||
this.comboBoxAgency.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId;
|
this.comboBoxAgency.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.comboBoxHarbour.SelectionChanged += this.comboBoxHarbour_SelectionChanged;
|
||||||
|
|
||||||
|
this.comboBoxHarbour.IsEnabled = this.ShipcallModel.AllowPortChange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,6 +380,8 @@ namespace BreCalClient
|
|||||||
|
|
||||||
bool editRightGrantedForBSMD = false;
|
bool editRightGrantedForBSMD = false;
|
||||||
|
|
||||||
|
if (this.ShipcallModel.Shipcall?.Canceled ?? false) return; // do not allow edit on canceled shipcall
|
||||||
|
|
||||||
// Special case: Selected Agency allows BSMD to edit their fields
|
// Special case: Selected Agency allows BSMD to edit their fields
|
||||||
if (this.comboBoxAgency.SelectedIndex >= 0)
|
if (this.comboBoxAgency.SelectedIndex >= 0)
|
||||||
{
|
{
|
||||||
@ -386,6 +405,7 @@ namespace BreCalClient
|
|||||||
this.datePickerETD.IsEnabled = isAgency || isBsmd;
|
this.datePickerETD.IsEnabled = isAgency || isBsmd;
|
||||||
|
|
||||||
this.labelBSMDGranted.Visibility = editRightGrantedForBSMD ? Visibility.Visible : Visibility.Hidden;
|
this.labelBSMDGranted.Visibility = editRightGrantedForBSMD ? Visibility.Visible : Visibility.Hidden;
|
||||||
|
this.comboBoxHarbour.IsEnabled = this.IsCreate && this.ShipcallModel.AllowPortChange;
|
||||||
|
|
||||||
this.comboBoxCategories_SelectionChanged(null, null);
|
this.comboBoxCategories_SelectionChanged(null, null);
|
||||||
}
|
}
|
||||||
@ -412,7 +432,7 @@ namespace BreCalClient
|
|||||||
private void comboBoxDepartureBerth_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void comboBoxDepartureBerth_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
this.CheckForCompletion();
|
this.CheckForCompletion();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buttonEditShips_Click(object sender, RoutedEventArgs e)
|
private void buttonEditShips_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@ -420,7 +440,7 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
ShipApi = this.ShipApi
|
ShipApi = this.ShipApi
|
||||||
};
|
};
|
||||||
|
|
||||||
shipListDialog.ShowDialog();
|
shipListDialog.ShowDialog();
|
||||||
|
|
||||||
// reload combobox
|
// reload combobox
|
||||||
@ -428,6 +448,24 @@ namespace BreCalClient
|
|||||||
this.comboBoxShip.ItemsSource = BreCalLists.Ships;
|
this.comboBoxShip.ItemsSource = BreCalLists.Ships;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void comboBoxHarbour_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
Port port = (Port)this.comboBoxHarbour.SelectedItem;
|
||||||
|
if (port == null) return;
|
||||||
|
|
||||||
|
// Filter berth selection combobox by port
|
||||||
|
List<Berth> availableBerths = BreCalLists.GetBerthsByPort(port.Id);
|
||||||
|
this.comboBoxArrivalBerth.ItemsSource = null;
|
||||||
|
this.comboBoxArrivalBerth.ItemsSource = availableBerths;
|
||||||
|
this.comboBoxDepartureBerth.ItemsSource = null;
|
||||||
|
this.comboBoxDepartureBerth.ItemsSource = availableBerths;
|
||||||
|
|
||||||
|
// Filter agency combobox by port
|
||||||
|
List<Participant> availableAgencies = BreCalLists.GetParticipants(port.Id, ParticipantType.AGENCY);
|
||||||
|
this.comboBoxAgency.ItemsSource = null;
|
||||||
|
this.comboBoxAgency.ItemsSource = availableAgencies;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// Copyright (c) 2023 schick Informatik
|
// Copyright (c) 2023 schick Informatik
|
||||||
// Description: Input control for incoming shipcalls
|
// Description: Input control for incoming shipcalls
|
||||||
//
|
//
|
||||||
|
|
||||||
using BreCalClient.misc.Model;
|
using BreCalClient.misc.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using static BreCalClient.Extensions;
|
using static BreCalClient.Extensions;
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
public ShipcallControlModel ShipcallModel { get; set; } = new();
|
public ShipcallControlModel ShipcallModel { get; set; } = new();
|
||||||
|
|
||||||
public Times Times { get; set; } = new();
|
public Times Times { get; set; } = new();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -42,19 +41,27 @@ namespace BreCalClient
|
|||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.comboBoxMooring.ItemsSource = BreCalLists.Participants_Mooring;
|
|
||||||
this.comboBoxPilot.ItemsSource = BreCalLists.Participants_Pilot;
|
|
||||||
this.comboBoxTug.ItemsSource = BreCalLists.Participants_Tug;
|
|
||||||
this.comboBoxTerminal.ItemsSource = BreCalLists.Participants_Terminal;
|
|
||||||
|
|
||||||
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
|
if ((this.ShipcallModel != null) && (this.ShipcallModel.Shipcall != null))
|
||||||
|
{
|
||||||
|
int portId = this.ShipcallModel.Shipcall.PortId;
|
||||||
|
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.GetBerthsByPort(portId);
|
||||||
|
this.comboBoxMooring.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.MOORING);
|
||||||
|
this.comboBoxPilot.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.PILOT);
|
||||||
|
this.comboBoxTug.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TUG);
|
||||||
|
this.comboBoxTerminal.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TERMINAL);
|
||||||
|
}
|
||||||
|
|
||||||
this.CopyToControls();
|
this.CopyToControls();
|
||||||
|
|
||||||
this.Title = this.ShipcallModel.Title;
|
this.Title = this.ShipcallModel?.Title;
|
||||||
|
|
||||||
Participant? p = null;
|
Participant? p = null;
|
||||||
if(this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
if (this.ShipcallModel != null)
|
||||||
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
{
|
||||||
|
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||||
|
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
||||||
|
}
|
||||||
|
|
||||||
bool allowBSMD = false;
|
bool allowBSMD = false;
|
||||||
if (p != null)
|
if (p != null)
|
||||||
@ -66,7 +73,7 @@ namespace BreCalClient
|
|||||||
(App.Participant.IsTypeFlagSet(ParticipantType.BSMD) && allowBSMD);
|
(App.Participant.IsTypeFlagSet(ParticipantType.BSMD) && allowBSMD);
|
||||||
|
|
||||||
this.EnableControls();
|
this.EnableControls();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buttonOK_Click(object sender, RoutedEventArgs e)
|
private void buttonOK_Click(object sender, RoutedEventArgs e)
|
||||||
@ -94,49 +101,43 @@ namespace BreCalClient
|
|||||||
#region private methods
|
#region private methods
|
||||||
|
|
||||||
private bool CheckValues(out string message)
|
private bool CheckValues(out string message)
|
||||||
{
|
{
|
||||||
message = "";
|
message = "";
|
||||||
|
|
||||||
if (this.datePickerETA.Value.IsTooOld() && (this.datePickerETA.Value != this.Times.EtaBerth))
|
if ((this.datePickerETA.Value != this.Times.EtaBerth) || (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd)) // something has changed
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textETAInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.datePickerETA_End.Value.IsTooOld() && (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd))
|
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textETAInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
|
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
|
if (datePickerETA.Value.IsTooOld() || datePickerETA_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
|
message = BreCalClient.Resources.Resources.textETAInThePast;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
|
||||||
|
{
|
||||||
|
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerTidalWindowFrom.Value.IsTooOld() && (this.datePickerTidalWindowTo.Value == null) && (this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom))
|
if((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo)) // something has changed
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
if(datePickerTidalWindowTo.Value.IsTooOld() || this.datePickerTidalWindowFrom.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.datePickerTidalWindowTo.Value.IsTooOld() && (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo))
|
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
if ((this.datePickerTidalWindowFrom.Value.HasValue && !this.datePickerTidalWindowTo.Value.HasValue) || (!this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
|
message = BreCalClient.Resources.Resources.textTidalBothValues;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((this.datePickerTidalWindowFrom.Value.HasValue && !this.datePickerTidalWindowTo.Value.HasValue) || (!this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue))
|
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textTidalBothValues;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.datePickerETA.Value.IsTooFar() || this.datePickerETA_End.Value.IsTooFar() || this.datePickerTidalWindowFrom.Value.IsTooFar() || this.datePickerTidalWindowTo.Value.IsTooFar())
|
if(this.datePickerETA.Value.IsTooFar() || this.datePickerETA_End.Value.IsTooFar() || this.datePickerTidalWindowFrom.Value.IsTooFar() || this.datePickerTidalWindowTo.Value.IsTooFar())
|
||||||
@ -161,7 +162,7 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
this.Times.EtaBerth = this.datePickerETA.Value;
|
this.Times.EtaBerth = this.datePickerETA.Value;
|
||||||
this.Times.EtaIntervalEnd = this.datePickerETA_End.Value;
|
this.Times.EtaIntervalEnd = this.datePickerETA_End.Value;
|
||||||
|
|
||||||
if (this.comboBoxPierside.SelectedIndex >= 0)
|
if (this.comboBoxPierside.SelectedIndex >= 0)
|
||||||
{
|
{
|
||||||
this.ShipcallModel.Shipcall.PierSide = (this.comboBoxPierside.SelectedIndex == 0);
|
this.ShipcallModel.Shipcall.PierSide = (this.comboBoxPierside.SelectedIndex == 0);
|
||||||
@ -171,8 +172,8 @@ namespace BreCalClient
|
|||||||
this.ShipcallModel.Shipcall.PierSide = null;
|
this.ShipcallModel.Shipcall.PierSide = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Times.BerthInfo = this.textBoxBerthRemarks.Text.Trim();
|
this.Times.BerthInfo = this.textBoxBerthRemarks.Text.Trim();
|
||||||
this.Times.BerthId = (int?)this.comboBoxArrivalBerth.SelectedValue;
|
this.Times.BerthId = (int?)this.comboBoxArrivalBerth.SelectedValue;
|
||||||
|
|
||||||
this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
|
this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
|
||||||
this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
|
this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
|
||||||
@ -180,9 +181,9 @@ namespace BreCalClient
|
|||||||
this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
|
this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
|
||||||
|
|
||||||
this.ShipcallModel.Shipcall.Anchored = this.checkBoxAnchored.IsChecked;
|
this.ShipcallModel.Shipcall.Anchored = this.checkBoxAnchored.IsChecked;
|
||||||
|
|
||||||
this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
|
this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
|
||||||
|
|
||||||
this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
|
this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
|
||||||
this.ShipcallModel.Shipcall.Bunkering = this.checkBoxBunkering.IsChecked;
|
this.ShipcallModel.Shipcall.Bunkering = this.checkBoxBunkering.IsChecked;
|
||||||
this.ShipcallModel.Shipcall.ReplenishingTerminal = this.checkBoxReplenishingTerminal.IsChecked;
|
this.ShipcallModel.Shipcall.ReplenishingTerminal = this.checkBoxReplenishingTerminal.IsChecked;
|
||||||
@ -194,7 +195,7 @@ namespace BreCalClient
|
|||||||
Participant? participant = (Participant?)this.comboBoxMooring.SelectedItem;
|
Participant? participant = (Participant?)this.comboBoxMooring.SelectedItem;
|
||||||
if (participant != null)
|
if (participant != null)
|
||||||
{
|
{
|
||||||
ParticipantAssignment participantAssignment = new() {
|
ParticipantAssignment participantAssignment = new() {
|
||||||
ParticipantId = participant.Id,
|
ParticipantId = participant.Id,
|
||||||
Type = (int)Extensions.ParticipantType.MOORING
|
Type = (int)Extensions.ParticipantType.MOORING
|
||||||
};
|
};
|
||||||
@ -242,14 +243,14 @@ namespace BreCalClient
|
|||||||
if(this.Times.EtaBerth.HasValue)
|
if(this.Times.EtaBerth.HasValue)
|
||||||
{
|
{
|
||||||
this.datePickerETA.Value = this.Times.EtaBerth.Value;
|
this.datePickerETA.Value = this.Times.EtaBerth.Value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if not set through times use value of BSMD entry
|
// if not set through times use value of BSMD entry
|
||||||
if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
|
if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
|
||||||
this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
|
this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.datePickerETA_End.Value = this.Times.EtaIntervalEnd;
|
this.datePickerETA_End.Value = this.Times.EtaIntervalEnd;
|
||||||
|
|
||||||
if (Times.BerthId.HasValue)
|
if (Times.BerthId.HasValue)
|
||||||
@ -269,12 +270,12 @@ namespace BreCalClient
|
|||||||
this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
||||||
|
|
||||||
this.checkBoxAnchored.IsChecked = this.ShipcallModel.Shipcall.Anchored ?? false;
|
this.checkBoxAnchored.IsChecked = this.ShipcallModel.Shipcall.Anchored ?? false;
|
||||||
|
|
||||||
this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
|
this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
|
||||||
|
|
||||||
|
|
||||||
this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock ?? false;
|
this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock ?? false;
|
||||||
|
|
||||||
this.checkBoxBunkering.IsChecked = this.ShipcallModel.Shipcall.Bunkering ?? false;
|
this.checkBoxBunkering.IsChecked = this.ShipcallModel.Shipcall.Bunkering ?? false;
|
||||||
this.checkBoxReplenishingLock.IsChecked = this.ShipcallModel.Shipcall.ReplenishingLock ?? false;
|
this.checkBoxReplenishingLock.IsChecked = this.ShipcallModel.Shipcall.ReplenishingLock ?? false;
|
||||||
this.checkBoxReplenishingTerminal.IsChecked = this.ShipcallModel.Shipcall.ReplenishingTerminal ?? false;
|
this.checkBoxReplenishingTerminal.IsChecked = this.ShipcallModel.Shipcall.ReplenishingTerminal ?? false;
|
||||||
@ -284,7 +285,7 @@ namespace BreCalClient
|
|||||||
else
|
else
|
||||||
this.labelETA.Content = string.Format("ETA {0}", BreCalLists.TimeRefs[this.ShipcallModel.Shipcall.TimeRefPoint ?? 0]);
|
this.labelETA.Content = string.Format("ETA {0}", BreCalLists.TimeRefs[this.ShipcallModel.Shipcall.TimeRefPoint ?? 0]);
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(this.Times.Remarks))
|
if(!string.IsNullOrEmpty(this.Times.Remarks))
|
||||||
this.textBoxRemarks.Text = this.Times.Remarks;
|
this.textBoxRemarks.Text = this.Times.Remarks;
|
||||||
|
|
||||||
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.MOORING))
|
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.MOORING))
|
||||||
@ -317,8 +318,8 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
this.comboBoxTug.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.TUG].ParticipantId;
|
this.comboBoxTug.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.TUG].ParticipantId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,10 +336,10 @@ namespace BreCalClient
|
|||||||
this.checkBoxCanceled.IsEnabled = _editing;
|
this.checkBoxCanceled.IsEnabled = _editing;
|
||||||
|
|
||||||
this.checkBoxAnchored.IsEnabled = _editing;
|
this.checkBoxAnchored.IsEnabled = _editing;
|
||||||
|
|
||||||
this.comboBoxTug.IsEnabled = _editing;
|
this.comboBoxTug.IsEnabled = _editing;
|
||||||
this.integerUpDownRecommendedTugs.IsEnabled = _editing;
|
this.integerUpDownRecommendedTugs.IsEnabled = _editing;
|
||||||
|
|
||||||
this.comboBoxPilot.IsEnabled = _editing;
|
this.comboBoxPilot.IsEnabled = _editing;
|
||||||
this.comboBoxMooring.IsEnabled = _editing;
|
this.comboBoxMooring.IsEnabled = _editing;
|
||||||
this.checkBoxMooredLock.IsEnabled = _editing;
|
this.checkBoxMooredLock.IsEnabled = _editing;
|
||||||
@ -365,7 +366,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
private void CheckOKButton()
|
private void CheckOKButton()
|
||||||
{
|
{
|
||||||
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet();
|
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet() && !(this.ShipcallModel.Shipcall?.Canceled ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -400,17 +401,17 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
this.comboBoxTerminal.SelectedIndex = -1;
|
this.comboBoxTerminal.SelectedIndex = -1;
|
||||||
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
|
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contextMenuItemClearPierside_Click(object sender, RoutedEventArgs e)
|
private void contextMenuItemClearPierside_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.comboBoxPierside.SelectedIndex = -1;
|
this.comboBoxPierside.SelectedIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doubleUpDownDraft_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
private void doubleUpDownDraft_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||||
{
|
{
|
||||||
this.CheckOKButton();
|
this.CheckOKButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void datePickerETA_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
private void datePickerETA_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||||
{
|
{
|
||||||
@ -420,7 +421,7 @@ namespace BreCalClient
|
|||||||
private void comboBoxArrivalBerth_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private void comboBoxArrivalBerth_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
this.CheckOKButton();
|
this.CheckOKButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void datePickerETA_End_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
private void datePickerETA_End_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,18 +1,11 @@
|
|||||||
// Copyright (c) 2023 schick Informatik
|
// Copyright (c) 2023 schick Informatik
|
||||||
// Description: Input control for outgoing shipcalls
|
// Description: Input control for outgoing shipcalls
|
||||||
//
|
//
|
||||||
|
|
||||||
using BreCalClient.misc.Model;
|
using BreCalClient.misc.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls.Primitives;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using Xceed.Wpf.Toolkit;
|
|
||||||
using static BreCalClient.Extensions;
|
using static BreCalClient.Extensions;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace BreCalClient
|
namespace BreCalClient
|
||||||
{
|
{
|
||||||
@ -41,7 +34,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
public ShipcallControlModel ShipcallModel { get; set; } = new();
|
public ShipcallControlModel ShipcallModel { get; set; } = new();
|
||||||
|
|
||||||
public Times Times { get; set; } = new();
|
public Times Times { get; set; } = new();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -49,20 +42,27 @@ namespace BreCalClient
|
|||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.comboBoxMooring.ItemsSource = BreCalLists.Participants_Mooring;
|
|
||||||
this.comboBoxPilot.ItemsSource = BreCalLists.Participants_Pilot;
|
|
||||||
this.comboBoxTug.ItemsSource = BreCalLists.Participants_Tug;
|
|
||||||
this.comboBoxTerminal.ItemsSource = BreCalLists.Participants_Terminal;
|
|
||||||
|
|
||||||
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
|
if ((this.ShipcallModel != null) && (this.ShipcallModel.Shipcall != null))
|
||||||
|
{
|
||||||
|
int portId = this.ShipcallModel.Shipcall.PortId;
|
||||||
|
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.GetBerthsByPort(portId);
|
||||||
|
this.comboBoxMooring.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.MOORING);
|
||||||
|
this.comboBoxPilot.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.PILOT);
|
||||||
|
this.comboBoxTug.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TUG);
|
||||||
|
this.comboBoxTerminal.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TERMINAL);
|
||||||
|
}
|
||||||
|
|
||||||
this.CopyToControls();
|
this.CopyToControls();
|
||||||
|
|
||||||
this.Title = this.ShipcallModel.Title;
|
this.Title = this.ShipcallModel?.Title;
|
||||||
|
|
||||||
Participant? p = null;
|
Participant? p = null;
|
||||||
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
if (this.ShipcallModel != null)
|
||||||
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
{
|
||||||
|
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||||
|
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
||||||
|
}
|
||||||
bool allowBSMD = false;
|
bool allowBSMD = false;
|
||||||
if (p != null)
|
if (p != null)
|
||||||
{
|
{
|
||||||
@ -73,10 +73,10 @@ namespace BreCalClient
|
|||||||
(App.Participant.IsTypeFlagSet(ParticipantType.BSMD) && allowBSMD);
|
(App.Participant.IsTypeFlagSet(ParticipantType.BSMD) && allowBSMD);
|
||||||
|
|
||||||
this.EnableControls();
|
this.EnableControls();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void buttonOK_Click(object sender, RoutedEventArgs e)
|
private void buttonOK_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@ -107,16 +107,13 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
message = "";
|
message = "";
|
||||||
|
|
||||||
if (this.datePickerETD.Value.IsTooOld() && (this.datePickerETD.Value != this.Times.EtdBerth))
|
if((this.datePickerETD.Value != this.Times.EtdBerth) || (this.datePickerETD_End.Value != this.Times.EtdIntervalEnd))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textETDInThePast;
|
if (datePickerETD.Value.IsTooOld() || datePickerETD_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textETDInThePast;
|
||||||
|
return false;
|
||||||
if (this.datePickerETD_End.Value.IsTooOld() && (this.datePickerETD_End.Value != this.Times.EtdIntervalEnd))
|
}
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textETDInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
|
if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
|
||||||
@ -125,16 +122,13 @@ namespace BreCalClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerTidalWindowFrom.Value.IsTooOld() && (this.datePickerTidalWindowTo.Value == null) && (this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom))
|
if((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
if (this.datePickerTidalWindowTo.Value.IsTooOld() || this.datePickerTidalWindowFrom.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
||||||
|
return false;
|
||||||
if (this.datePickerTidalWindowTo.Value.IsTooOld() && (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo))
|
}
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
||||||
@ -182,16 +176,16 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.Times.BerthId = (int?)this.comboBoxDepartureBerth.SelectedValue;
|
this.Times.BerthId = (int?)this.comboBoxDepartureBerth.SelectedValue;
|
||||||
|
|
||||||
this.Times.BerthInfo = this.textBoxBerthRemarks.Text.Trim();
|
this.Times.BerthInfo = this.textBoxBerthRemarks.Text.Trim();
|
||||||
this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
|
this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
|
||||||
this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
|
this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
|
||||||
this.ShipcallModel.Shipcall.TidalWindowTo = this.datePickerTidalWindowTo.Value;
|
this.ShipcallModel.Shipcall.TidalWindowTo = this.datePickerTidalWindowTo.Value;
|
||||||
this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
|
this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
|
||||||
|
|
||||||
|
|
||||||
this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
|
this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
|
||||||
|
|
||||||
this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
|
this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
|
||||||
this.ShipcallModel.Shipcall.RainSensitiveCargo = this.checkBoxRainsensitiveCargo.IsChecked;
|
this.ShipcallModel.Shipcall.RainSensitiveCargo = this.checkBoxRainsensitiveCargo.IsChecked;
|
||||||
if(!string.IsNullOrEmpty(this.textBoxRemarks.Text.Trim()))
|
if(!string.IsNullOrEmpty(this.textBoxRemarks.Text.Trim()))
|
||||||
@ -255,7 +249,7 @@ namespace BreCalClient
|
|||||||
if (this.ShipcallModel.Shipcall.Etd != DateTime.MinValue)
|
if (this.ShipcallModel.Shipcall.Etd != DateTime.MinValue)
|
||||||
this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
|
this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.datePickerETD_End.Value = this.Times.EtdIntervalEnd;
|
this.datePickerETD_End.Value = this.Times.EtdIntervalEnd;
|
||||||
|
|
||||||
if (this.Times.BerthId.HasValue)
|
if (this.Times.BerthId.HasValue)
|
||||||
@ -273,10 +267,10 @@ namespace BreCalClient
|
|||||||
this.datePickerTidalWindowFrom.Value = this.ShipcallModel.Shipcall.TidalWindowFrom;
|
this.datePickerTidalWindowFrom.Value = this.ShipcallModel.Shipcall.TidalWindowFrom;
|
||||||
this.datePickerTidalWindowTo.Value = this.ShipcallModel.Shipcall.TidalWindowTo;
|
this.datePickerTidalWindowTo.Value = this.ShipcallModel.Shipcall.TidalWindowTo;
|
||||||
this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
||||||
|
|
||||||
|
|
||||||
this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
|
this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
|
||||||
|
|
||||||
|
|
||||||
this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock ?? false;
|
this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock ?? false;
|
||||||
this.checkBoxRainsensitiveCargo.IsChecked = this.ShipcallModel.Shipcall.RainSensitiveCargo ?? false;
|
this.checkBoxRainsensitiveCargo.IsChecked = this.ShipcallModel.Shipcall.RainSensitiveCargo ?? false;
|
||||||
@ -284,7 +278,7 @@ namespace BreCalClient
|
|||||||
if ((this.ShipcallModel.Shipcall.TimeRefPoint ?? 0) == 0)
|
if ((this.ShipcallModel.Shipcall.TimeRefPoint ?? 0) == 0)
|
||||||
this.labelETD.Content = BreCalClient.Resources.Resources.textETDBerth;
|
this.labelETD.Content = BreCalClient.Resources.Resources.textETDBerth;
|
||||||
else
|
else
|
||||||
this.labelETD.Content = string.Format("ETD {0}", BreCalLists.TimeRefs[this.ShipcallModel.Shipcall.TimeRefPoint ?? 0]);
|
this.labelETD.Content = string.Format("ETD {0}", BreCalLists.TimeRefs[this.ShipcallModel.Shipcall.TimeRefPoint ?? 0]);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(this.Times.Remarks))
|
if (!string.IsNullOrEmpty(this.Times.Remarks))
|
||||||
this.textBoxRemarks.Text = this.Times.Remarks;
|
this.textBoxRemarks.Text = this.Times.Remarks;
|
||||||
@ -335,9 +329,9 @@ namespace BreCalClient
|
|||||||
this.datePickerTidalWindowTo.IsEnabled = _editing;
|
this.datePickerTidalWindowTo.IsEnabled = _editing;
|
||||||
this.checkBoxCanceled.IsEnabled = _editing;
|
this.checkBoxCanceled.IsEnabled = _editing;
|
||||||
|
|
||||||
|
|
||||||
this.comboBoxTug.IsEnabled = _editing;
|
this.comboBoxTug.IsEnabled = _editing;
|
||||||
this.integerUpDownRecommendedTugs.IsEnabled = _editing;
|
this.integerUpDownRecommendedTugs.IsEnabled = _editing;
|
||||||
this.comboBoxPilot.IsEnabled = _editing;
|
this.comboBoxPilot.IsEnabled = _editing;
|
||||||
this.comboBoxMooring.IsEnabled = _editing;
|
this.comboBoxMooring.IsEnabled = _editing;
|
||||||
this.checkBoxMooredLock.IsEnabled = _editing;
|
this.checkBoxMooredLock.IsEnabled = _editing;
|
||||||
@ -362,7 +356,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
private void CheckOKButton()
|
private void CheckOKButton()
|
||||||
{
|
{
|
||||||
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet();
|
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet() && !(this.ShipcallModel.Shipcall?.Canceled ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -397,12 +391,12 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
this.comboBoxTerminal.SelectedIndex = -1;
|
this.comboBoxTerminal.SelectedIndex = -1;
|
||||||
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
|
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contextMenuItemClearPierside_Click(object sender, RoutedEventArgs e)
|
private void contextMenuItemClearPierside_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.comboBoxPierside.SelectedIndex = -1;
|
this.comboBoxPierside.SelectedIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void datePickerETD_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
private void datePickerETD_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||||
{
|
{
|
||||||
@ -419,7 +413,7 @@ namespace BreCalClient
|
|||||||
CheckOKButton();
|
CheckOKButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
using BreCalClient.misc.Model;
|
using BreCalClient.misc.Model;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Documents;
|
||||||
using static BreCalClient.Extensions;
|
using static BreCalClient.Extensions;
|
||||||
|
|
||||||
namespace BreCalClient
|
namespace BreCalClient
|
||||||
@ -40,21 +42,30 @@ namespace BreCalClient
|
|||||||
#region event handler
|
#region event handler
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.comboBoxMooring.ItemsSource = BreCalLists.Participants_Mooring;
|
|
||||||
this.comboBoxPilot.ItemsSource = BreCalLists.Participants_Pilot;
|
|
||||||
this.comboBoxTug.ItemsSource = BreCalLists.Participants_Tug;
|
|
||||||
this.comboBoxTerminal.ItemsSource = BreCalLists.Participants_Terminal;
|
|
||||||
|
|
||||||
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
|
if ((this.ShipcallModel != null) && (this.ShipcallModel.Shipcall != null))
|
||||||
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
|
{
|
||||||
|
int portId = this.ShipcallModel.Shipcall.PortId;
|
||||||
|
List<Berth> availableBerths = BreCalLists.GetBerthsByPort(portId);
|
||||||
|
this.comboBoxArrivalBerth.ItemsSource = availableBerths;
|
||||||
|
this.comboBoxDepartureBerth.ItemsSource = availableBerths;
|
||||||
|
this.comboBoxMooring.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.MOORING);
|
||||||
|
this.comboBoxPilot.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.PILOT);
|
||||||
|
this.comboBoxTug.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TUG);
|
||||||
|
this.comboBoxTerminal.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TERMINAL);
|
||||||
|
}
|
||||||
|
|
||||||
this.CopyToControls();
|
this.CopyToControls();
|
||||||
|
|
||||||
this.Title = this.ShipcallModel.Title;
|
|
||||||
|
|
||||||
Participant? p = null;
|
Participant? p = null;
|
||||||
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
|
||||||
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
if (this.ShipcallModel != null)
|
||||||
|
{
|
||||||
|
this.Title = this.ShipcallModel.Title;
|
||||||
|
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||||
|
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
||||||
|
}
|
||||||
|
|
||||||
bool allowBSMD = false;
|
bool allowBSMD = false;
|
||||||
if (p != null)
|
if (p != null)
|
||||||
@ -97,17 +108,15 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
message = "";
|
message = "";
|
||||||
|
|
||||||
if (this.datePickerETA.Value.IsTooOld() && (this.datePickerETA.Value != this.Times.EtaBerth))
|
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textETAInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.datePickerETA_End.Value.IsTooOld() && (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd))
|
if((this.datePickerETA.Value != this.Times.EtaBerth) || (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textETAInThePast;
|
if (this.datePickerETA.Value.IsTooOld() && this.datePickerETA_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textETAInThePast;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
|
if (this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
|
||||||
{
|
{
|
||||||
@ -115,17 +124,14 @@ namespace BreCalClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerETD.Value.IsTooOld() && (this.datePickerETD.Value != this.Times.EtdBerth))
|
if((this.datePickerETD.Value != this.Times.EtdBerth) || (this.datePickerETD_End.Value != this.Times.EtdIntervalEnd))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textETDInThePast;
|
if (this.datePickerETD.Value.IsTooOld() || this.datePickerETD_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textETDInThePast;
|
||||||
|
return false;
|
||||||
if (this.datePickerETD_End.Value.IsTooOld() && (this.datePickerETD_End.Value != this.Times.EtdIntervalEnd))
|
}
|
||||||
{
|
}
|
||||||
message = BreCalClient.Resources.Resources.textETDInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
|
if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
|
||||||
{
|
{
|
||||||
@ -133,17 +139,14 @@ namespace BreCalClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerTidalWindowFrom.Value.IsTooOld() && (this.datePickerTidalWindowTo.Value == null) && (this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom))
|
if((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
if (this.datePickerTidalWindowFrom.Value.IsTooOld() && this.datePickerTidalWindowTo.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
||||||
|
return false;
|
||||||
if (this.datePickerTidalWindowTo.Value.IsTooOld() && (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo))
|
}
|
||||||
{
|
}
|
||||||
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
||||||
{
|
{
|
||||||
@ -391,7 +394,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
private void CheckOKButton()
|
private void CheckOKButton()
|
||||||
{
|
{
|
||||||
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet();
|
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet() && !(this.ShipcallModel.Shipcall?.Canceled ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
xmlns:p = "clr-namespace:BreCalClient.Resources"
|
xmlns:p = "clr-namespace:BreCalClient.Resources"
|
||||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||||
mc:Ignorable="d" Left="{local:SettingBinding W1Left}" Top="{local:SettingBinding W1Top}"
|
mc:Ignorable="d" Left="{local:SettingBinding W1Left}" Top="{local:SettingBinding W1Top}"
|
||||||
Title="{x:Static p:Resources.textEditTimes}" Height="331" Width="500" Loaded="Window_Loaded" ResizeMode="CanResizeWithGrip" Icon="Resources/containership.ico">
|
Title="{x:Static p:Resources.textEditTimes}" Height="415" Width="500" Loaded="Window_Loaded" ResizeMode="CanResizeWithGrip" Icon="Resources/containership.ico">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width=".20*" />
|
<ColumnDefinition Width=".20*" />
|
||||||
@ -22,6 +22,9 @@
|
|||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="28" x:Name="rowt1" />
|
||||||
|
<RowDefinition Height="28" x:Name="rowt2" />
|
||||||
|
<RowDefinition Height="28" x:Name="rowt3" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
@ -35,8 +38,10 @@
|
|||||||
<Label Grid.Row="4" Grid.Column="0" Content="ATD" HorizontalContentAlignment="Right" x:Name="labelATD" />
|
<Label Grid.Row="4" Grid.Column="0" Content="ATD" HorizontalContentAlignment="Right" x:Name="labelATD" />
|
||||||
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static p:Resources.textLockTime}" HorizontalContentAlignment="Right" />
|
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static p:Resources.textLockTime}" HorizontalContentAlignment="Right" />
|
||||||
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static p:Resources.textZoneEntryTime}" HorizontalContentAlignment="Right" />
|
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static p:Resources.textZoneEntryTime}" HorizontalContentAlignment="Right" />
|
||||||
|
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static p:Resources.textTidalWindow}" HorizontalContentAlignment="Right" />
|
||||||
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static p:Resources.textRemarks}" HorizontalContentAlignment="Right" />
|
<Label Grid.Row="8" Grid.Column="0" Content="{x:Static p:Resources.textFrom}" HorizontalContentAlignment="Right" />
|
||||||
|
<Label Grid.Row="9" Grid.Column="0" Content="{x:Static p:Resources.textTo}" HorizontalContentAlignment="Right" />
|
||||||
|
<Label Grid.Row="10" Grid.Column="0" Content="{x:Static p:Resources.textRemarks}" HorizontalContentAlignment="Right" />
|
||||||
|
|
||||||
<Grid Grid.Row="1" Grid.Column="1">
|
<Grid Grid.Row="1" Grid.Column="1">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -137,7 +142,7 @@
|
|||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</xctk:DateTimePicker.ContextMenu>
|
</xctk:DateTimePicker.ContextMenu>
|
||||||
</local:DateTimePickerExt>
|
</local:DateTimePickerExt>
|
||||||
<!--CheckBox IsEnabled="False" Grid.Row="3" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxLockTimeFixed" VerticalAlignment="Center" /-->
|
|
||||||
<local:DateTimePickerExt IsEnabled="False" Grid.Row="6" Grid.Column="1" Margin="2" x:Name="datePickerZoneEntry" Format="Custom" FormatString="dd.MM. yyyy HH:mm">
|
<local:DateTimePickerExt IsEnabled="False" Grid.Row="6" Grid.Column="1" Margin="2" x:Name="datePickerZoneEntry" Format="Custom" FormatString="dd.MM. yyyy HH:mm">
|
||||||
<xctk:DateTimePicker.ContextMenu>
|
<xctk:DateTimePicker.ContextMenu>
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
@ -149,10 +154,12 @@
|
|||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</xctk:DateTimePicker.ContextMenu>
|
</xctk:DateTimePicker.ContextMenu>
|
||||||
</local:DateTimePickerExt>
|
</local:DateTimePickerExt>
|
||||||
<!--CheckBox IsEnabled="False" Grid.Row="4" Grid.Column="2" Margin="4,0,0,0" Name="checkBoxZoneEntryFixed" VerticalAlignment="Center" /-->
|
|
||||||
|
<xctk:DateTimePicker Name="datePickerTidalWindowFrom" Grid.Column="1" Grid.Row="8" Margin="2" IsEnabled="False" Format="Custom" FormatString="dd.MM. yyyy HH:mm"/>
|
||||||
|
<xctk:DateTimePicker Name="datePickerTidalWindowTo" Grid.Column="1" Grid.Row="9" Margin="2" IsEnabled="False" Format="Custom" FormatString="dd.MM. yyyy HH:mm"/>
|
||||||
|
|
||||||
<TextBox Grid.Row="7" Grid.Column="1" Margin="2" Name="textBoxRemarks" TextWrapping="Wrap" AcceptsReturn="True" SpellCheck.IsEnabled="True" AcceptsTab="False" IsReadOnly="True" MaxLength="512"/>
|
<TextBox Grid.Row="10" Grid.Column="1" Margin="2" Name="textBoxRemarks" TextWrapping="Wrap" AcceptsReturn="True" SpellCheck.IsEnabled="True" AcceptsTab="False" IsReadOnly="True" MaxLength="512"/>
|
||||||
<StackPanel Grid.Row="8" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right">
|
<StackPanel Grid.Row="11" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
<Button Width= "80" Margin="2" Content="{x:Static p:Resources.textOK}" x:Name="buttonOK" Click="buttonOK_Click" />
|
<Button Width= "80" Margin="2" Content="{x:Static p:Resources.textOK}" x:Name="buttonOK" Click="buttonOK_Click" />
|
||||||
<Button Width="80" Margin="2" Content="{x:Static p:Resources.textCancel}" x:Name="buttonCancel" Click="buttonCancel_Click"/>
|
<Button Width="80" Margin="2" Content="{x:Static p:Resources.textCancel}" x:Name="buttonCancel" Click="buttonCancel_Click"/>
|
||||||
<Button Width="28" x:Name="buttonClearAll" Click="buttonClearAll_Click" Margin="2" IsEnabled="False">
|
<Button Width="28" x:Name="buttonClearAll" Click="buttonClearAll_Click" Margin="2" IsEnabled="False">
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
using BreCalClient.misc.Model;
|
using BreCalClient.misc.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using Xceed.Wpf.Toolkit;
|
using Xceed.Wpf.Toolkit;
|
||||||
@ -49,7 +48,7 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
if (!CheckValues(out string message))
|
if (!CheckValues(out string message))
|
||||||
{
|
{
|
||||||
System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning,
|
System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning,
|
||||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -87,6 +86,8 @@ namespace BreCalClient
|
|||||||
this.datePickerLockTime.Value = null;
|
this.datePickerLockTime.Value = null;
|
||||||
this.datePickerZoneEntry.Value = null;
|
this.datePickerZoneEntry.Value = null;
|
||||||
this.textBoxRemarks.Text = null;
|
this.textBoxRemarks.Text = null;
|
||||||
|
this.datePickerTidalWindowFrom.Value = null;
|
||||||
|
this.datePickerTidalWindowTo.Value = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,16 +100,13 @@ namespace BreCalClient
|
|||||||
|
|
||||||
message = "";
|
message = "";
|
||||||
|
|
||||||
if (this.datePickerETABerth.Value.IsTooOld() && (this.datePickerETABerth_End.Value == null) && (this.datePickerETABerth.Value != this.Times.EtaBerth))
|
if ((this.datePickerETABerth.Value != this.Times.EtaBerth) || (this.datePickerETABerth_End.Value != this.Times.EtaIntervalEnd))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textETAInThePast;
|
if (this.datePickerETABerth.Value.IsTooOld() || this.datePickerETABerth_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textETAInThePast;
|
||||||
|
return false;
|
||||||
if (this.datePickerETABerth_End.Value.IsTooOld() && this.datePickerETABerth_End.Value != this.Times.EtaIntervalEnd)
|
}
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textETAInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerETABerth.Value.HasValue && this.datePickerETABerth_End.Value.HasValue && this.datePickerETABerth.Value > this.datePickerETABerth_End.Value)
|
if (this.datePickerETABerth.Value.HasValue && this.datePickerETABerth_End.Value.HasValue && this.datePickerETABerth.Value > this.datePickerETABerth_End.Value)
|
||||||
@ -117,16 +115,13 @@ namespace BreCalClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerETDBerth.Value.IsTooOld() && (this.datePickerETDBerth_End.Value == null) && (this.datePickerETDBerth.Value != this.Times.EtdBerth))
|
if((this.datePickerETDBerth.Value != this.Times.EtdBerth) || (this.datePickerETDBerth_End.Value != this.Times.EtdIntervalEnd))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textETDInThePast;
|
if(this.datePickerETDBerth.Value.IsTooOld() || this.datePickerETDBerth_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textETDInThePast;
|
||||||
|
return false;
|
||||||
if (this.datePickerETDBerth_End.Value.IsTooOld() && this.datePickerETDBerth_End.Value != this.Times.EtdIntervalEnd)
|
}
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textETDInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerETDBerth.Value.HasValue && this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth.Value > this.datePickerETDBerth_End.Value)
|
if (this.datePickerETDBerth.Value.HasValue && this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth.Value > this.datePickerETDBerth_End.Value)
|
||||||
@ -154,13 +149,36 @@ namespace BreCalClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((this.datePickerETABerth_End.Value.HasValue && !this.datePickerETABerth.Value.HasValue) ||
|
if((this.datePickerETABerth_End.Value.HasValue && !this.datePickerETABerth.Value.HasValue) || (this.datePickerETDBerth_End.Value.HasValue && !this.datePickerETDBerth.Value.HasValue))
|
||||||
(this.datePickerETDBerth_End.Value.HasValue && !this.datePickerETDBerth.Value.HasValue))
|
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((Extensions.ParticipantType)this.Times.ParticipantType == Extensions.ParticipantType.PILOT)
|
||||||
|
{
|
||||||
|
if ((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo)) // something has changed
|
||||||
|
{
|
||||||
|
if (datePickerTidalWindowTo.Value.IsTooOld() || this.datePickerTidalWindowFrom.Value.IsTooOld())
|
||||||
|
{
|
||||||
|
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
||||||
|
{
|
||||||
|
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((this.datePickerTidalWindowFrom.Value.HasValue && !this.datePickerTidalWindowTo.Value.HasValue) || (!this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue))
|
||||||
|
{
|
||||||
|
message = BreCalClient.Resources.Resources.textTidalBothValues;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,19 +193,26 @@ namespace BreCalClient
|
|||||||
this.Times.ZoneEntry = this.datePickerZoneEntry.Value;
|
this.Times.ZoneEntry = this.datePickerZoneEntry.Value;
|
||||||
this.Times.Ata = this.datePickerATA.Value;
|
this.Times.Ata = this.datePickerATA.Value;
|
||||||
this.Times.Atd = this.datePickerATD.Value;
|
this.Times.Atd = this.datePickerATD.Value;
|
||||||
|
|
||||||
|
Extensions.ParticipantType pType = (Extensions.ParticipantType)this.Times.ParticipantType;
|
||||||
|
if ((pType == Extensions.ParticipantType.PILOT) && this.ShipcallModel.Shipcall != null)
|
||||||
|
{
|
||||||
|
this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
|
||||||
|
this.ShipcallModel.Shipcall.TidalWindowTo = this.datePickerTidalWindowTo.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyToControls()
|
private void CopyToControls()
|
||||||
{
|
{
|
||||||
this.textBoxRemarks.Text = this.Times.Remarks;
|
this.textBoxRemarks.Text = this.Times.Remarks;
|
||||||
this.datePickerETABerth.Value = this.Times.EtaBerth;
|
this.datePickerETABerth.Value = this.Times.EtaBerth;
|
||||||
if(this.datePickerETABerth.IsEnabled && (this.Times.EtaBerth == null) && (this.AgencyTimes?.EtaBerth != null) && (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival))
|
if(this.datePickerETABerth.IsEnabled && (this.Times.EtaBerth == null) && (this.AgencyTimes?.EtaBerth != null) && (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival) && (this.AgencyTimes?.EtaBerth > DateTime.Now))
|
||||||
{
|
{
|
||||||
this.datePickerETABerth.Value = this.AgencyTimes.EtaBerth;
|
this.datePickerETABerth.Value = this.AgencyTimes.EtaBerth;
|
||||||
if (this.datePickerETABerth.Template.FindName("PART_TextBox", this.datePickerETABerth) is WatermarkTextBox tb) { tb.Focus(); tb.SelectAll(); }
|
if (this.datePickerETABerth.Template.FindName("PART_TextBox", this.datePickerETABerth) is WatermarkTextBox tb) { tb.Focus(); tb.SelectAll(); }
|
||||||
}
|
}
|
||||||
this.datePickerETDBerth.Value = this.Times.EtdBerth;
|
this.datePickerETDBerth.Value = this.Times.EtdBerth;
|
||||||
if(this.datePickerETDBerth.IsEnabled && (this.Times.EtdBerth == null) && (this.AgencyTimes?.EtdBerth != null) && ((ShipcallModel.Shipcall?.Type == ShipcallType.Departure) || (ShipcallModel.Shipcall?.Type == ShipcallType.Shifting)))
|
if(this.datePickerETDBerth.IsEnabled && (this.Times.EtdBerth == null) && (this.AgencyTimes?.EtdBerth != null) && ((ShipcallModel.Shipcall?.Type == ShipcallType.Departure) || (ShipcallModel.Shipcall?.Type == ShipcallType.Shifting)) && (this.AgencyTimes?.EtdBerth > DateTime.Now))
|
||||||
{
|
{
|
||||||
this.datePickerETDBerth.Value = this.AgencyTimes.EtdBerth;
|
this.datePickerETDBerth.Value = this.AgencyTimes.EtdBerth;
|
||||||
if (this.datePickerETDBerth.Template.FindName("PART_TextBox", this.datePickerETDBerth) is WatermarkTextBox tb) tb.SelectAll();
|
if (this.datePickerETDBerth.Template.FindName("PART_TextBox", this.datePickerETDBerth) is WatermarkTextBox tb) tb.SelectAll();
|
||||||
@ -226,6 +251,19 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Extensions.ParticipantType pType = (Extensions.ParticipantType)this.Times.ParticipantType;
|
||||||
|
if ((pType == Extensions.ParticipantType.PILOT) && this.ShipcallModel.Shipcall != null)
|
||||||
|
{
|
||||||
|
this.datePickerTidalWindowFrom.Value = this.ShipcallModel.Shipcall.TidalWindowFrom;
|
||||||
|
this.datePickerTidalWindowTo.Value = this.ShipcallModel.Shipcall.TidalWindowTo;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.rowt1.Height = new(0);
|
||||||
|
this.rowt2.Height = new(0);
|
||||||
|
this.rowt3.Height = new(0);
|
||||||
|
}
|
||||||
|
|
||||||
this.SetLockButton(this.Times.EtaBerthFixed ?? false);
|
this.SetLockButton(this.Times.EtaBerthFixed ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +305,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
// setting en/dis-abled
|
// setting en/dis-abled
|
||||||
|
|
||||||
if (this.Times.ParticipantId != App.Participant.Id)
|
if ((this.Times.ParticipantId != App.Participant.Id) || (this.ShipcallModel.Shipcall?.Canceled ?? false))
|
||||||
{
|
{
|
||||||
this.buttonFixedOrder.IsEnabled = false;
|
this.buttonFixedOrder.IsEnabled = false;
|
||||||
this.buttonOK.IsEnabled = false;
|
this.buttonOK.IsEnabled = false;
|
||||||
@ -291,8 +329,12 @@ namespace BreCalClient
|
|||||||
this.datePickerLockTime.IsEnabled = true;
|
this.datePickerLockTime.IsEnabled = true;
|
||||||
break;
|
break;
|
||||||
case Extensions.ParticipantType.TUG:
|
case Extensions.ParticipantType.TUG:
|
||||||
|
this.datePickerZoneEntry.IsEnabled = (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival);
|
||||||
|
break;
|
||||||
case Extensions.ParticipantType.PILOT:
|
case Extensions.ParticipantType.PILOT:
|
||||||
this.datePickerZoneEntry.IsEnabled = (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival);
|
this.datePickerZoneEntry.IsEnabled = (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival);
|
||||||
|
this.datePickerTidalWindowFrom.IsEnabled = true;
|
||||||
|
this.datePickerTidalWindowTo.IsEnabled = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// Copyright (c) 2023 schick Informatik
|
// Copyright (c) 2023 schick Informatik
|
||||||
// Description: Terminals have all different fields so a different dialog
|
// Description: Terminals have all different fields so a different dialog
|
||||||
//
|
//
|
||||||
|
|
||||||
using BreCalClient.misc.Model;
|
using BreCalClient.misc.Model;
|
||||||
using System;
|
using System;
|
||||||
@ -30,7 +30,10 @@ namespace BreCalClient
|
|||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.comboBoxBerth.ItemsSource = BreCalLists.Berths;
|
if ((this.ShipcallModel != null) && (this.ShipcallModel.Shipcall != null))
|
||||||
|
this.comboBoxBerth.ItemsSource = BreCalLists.GetBerthsByPort(this.ShipcallModel.Shipcall.PortId);
|
||||||
|
else
|
||||||
|
this.comboBoxBerth.ItemsSource = BreCalLists.Berths;
|
||||||
this.CopyToControls();
|
this.CopyToControls();
|
||||||
this.EnableControls();
|
this.EnableControls();
|
||||||
}
|
}
|
||||||
@ -108,16 +111,13 @@ namespace BreCalClient
|
|||||||
|
|
||||||
message = "";
|
message = "";
|
||||||
|
|
||||||
if (this.datePickerOperationStart.Value.IsTooOld() && (this.datePickerOperationStart_End.Value == null) && (this.datePickerOperationStart.Value != this.Times.OperationsStart))
|
if((this.datePickerOperationStart.Value != this.Times.OperationsStart) || (this.datePickerOperationStart_End.Value != this.Times.EtaIntervalEnd))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textOperationStartInThePast;
|
if(this.datePickerOperationStart.Value.IsTooOld() || this.datePickerOperationStart_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textOperationStartInThePast;
|
||||||
|
return false;
|
||||||
if (this.datePickerOperationStart_End.Value.IsTooOld() && (this.datePickerOperationStart_End.Value != this.Times.EtaIntervalEnd))
|
}
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textOperationStartInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerOperationStart.Value.HasValue && this.datePickerOperationStart_End.Value.HasValue && this.datePickerOperationStart.Value > this.datePickerOperationStart_End.Value)
|
if (this.datePickerOperationStart.Value.HasValue && this.datePickerOperationStart_End.Value.HasValue && this.datePickerOperationStart.Value > this.datePickerOperationStart_End.Value)
|
||||||
@ -126,16 +126,13 @@ namespace BreCalClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerOperationEnd.Value.IsTooOld() && (this.datePickerOperationEnd_End.Value == null) && (this.datePickerOperationEnd.Value != this.Times.OperationsEnd))
|
if ((this.datePickerOperationEnd.Value != this.Times.OperationsEnd) || (this.datePickerOperationEnd_End.Value != this.Times.EtdIntervalEnd))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textOperationEndInThePast;
|
if(this.datePickerOperationEnd.Value.IsTooOld() || this.datePickerOperationEnd_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textOperationEndInThePast;
|
||||||
|
return false;
|
||||||
if (this.datePickerOperationEnd_End.Value.IsTooOld() && (this.datePickerOperationEnd_End.Value != this.Times.EtdIntervalEnd))
|
}
|
||||||
{
|
|
||||||
message = BreCalClient.Resources.Resources.textOperationEndInThePast;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerOperationEnd.Value.HasValue && this.datePickerOperationEnd_End.Value.HasValue && this.datePickerOperationEnd.Value > this.datePickerOperationEnd_End.Value)
|
if (this.datePickerOperationEnd.Value.HasValue && this.datePickerOperationEnd_End.Value.HasValue && this.datePickerOperationEnd.Value > this.datePickerOperationEnd_End.Value)
|
||||||
@ -150,8 +147,7 @@ namespace BreCalClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((this.datePickerOperationEnd_End.Value.HasValue && !this.datePickerOperationEnd.Value.HasValue) ||
|
if((this.datePickerOperationEnd_End.Value.HasValue && !this.datePickerOperationEnd.Value.HasValue) || (this.datePickerOperationStart_End.Value.HasValue && !this.datePickerOperationStart.Value.HasValue))
|
||||||
(this.datePickerOperationStart_End.Value.HasValue && !this.datePickerOperationStart.Value.HasValue))
|
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
||||||
return false;
|
return false;
|
||||||
@ -194,7 +190,7 @@ namespace BreCalClient
|
|||||||
case ShipcallType.Arrival:
|
case ShipcallType.Arrival:
|
||||||
this.labelEnd.Visibility = Visibility.Hidden;
|
this.labelEnd.Visibility = Visibility.Hidden;
|
||||||
this.datePickerOperationEnd.Visibility = Visibility.Hidden;
|
this.datePickerOperationEnd.Visibility = Visibility.Hidden;
|
||||||
this.datePickerOperationEnd_End.Visibility = Visibility.Hidden;
|
this.datePickerOperationEnd_End.Visibility = Visibility.Hidden;
|
||||||
this.rowEnd.Height = new(0);
|
this.rowEnd.Height = new(0);
|
||||||
break;
|
break;
|
||||||
case ShipcallType.Departure:
|
case ShipcallType.Departure:
|
||||||
@ -207,7 +203,7 @@ namespace BreCalClient
|
|||||||
this.textBoxBerthRemarks.Visibility = Visibility.Hidden;
|
this.textBoxBerthRemarks.Visibility = Visibility.Hidden;
|
||||||
break;
|
break;
|
||||||
case ShipcallType.Shifting:
|
case ShipcallType.Shifting:
|
||||||
this.rowStart.Height = new(0);
|
this.rowStart.Height = new(0);
|
||||||
this.labelBerth.Visibility = Visibility.Hidden;
|
this.labelBerth.Visibility = Visibility.Hidden;
|
||||||
this.comboBoxBerth.Visibility = Visibility.Hidden;
|
this.comboBoxBerth.Visibility = Visibility.Hidden;
|
||||||
this.labelPierside.Visibility = Visibility.Hidden;
|
this.labelPierside.Visibility = Visibility.Hidden;
|
||||||
@ -221,7 +217,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
private void EnableControls()
|
private void EnableControls()
|
||||||
{
|
{
|
||||||
if (this.Times.ParticipantId != App.Participant.Id)
|
if ((this.Times.ParticipantId != App.Participant.Id) || (this.ShipcallModel.Shipcall?.Canceled ?? false))
|
||||||
{
|
{
|
||||||
this.buttonOK.IsEnabled = false;
|
this.buttonOK.IsEnabled = false;
|
||||||
return;
|
return;
|
||||||
@ -236,10 +232,10 @@ namespace BreCalClient
|
|||||||
this.textBoxBerthRemarks.IsReadOnly = ShipcallModel.Shipcall?.Type != ShipcallType.Arrival;
|
this.textBoxBerthRemarks.IsReadOnly = ShipcallModel.Shipcall?.Type != ShipcallType.Arrival;
|
||||||
this.textBoxRemarks.IsReadOnly = false;
|
this.textBoxRemarks.IsReadOnly = false;
|
||||||
this.buttonClearAll.IsEnabled = true;
|
this.buttonClearAll.IsEnabled = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2024- schick Informatik
|
// Copyright (c) 2024- schick Informatik
|
||||||
// Description: Window to show (complete) list of current shipcall histories
|
// Description:
|
||||||
//
|
//
|
||||||
|
|
||||||
using BreCalClient.misc.Api;
|
using BreCalClient.misc.Api;
|
||||||
|
|||||||
@ -73,9 +73,19 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Button Margin="2" Grid.Column="0" Content="{x:Static p:Resources.textNewDots}" x:Name="buttonNew" Visibility="Hidden" Click="buttonNew_Click" Background="Transparent"/>
|
<Button Margin="2" Grid.Column="0" Content="{x:Static p:Resources.textNewDots}" x:Name="buttonNew" Visibility="Hidden" Click="buttonNew_Click" Background="Transparent"/>
|
||||||
<Label Content="{x:Static p:Resources.textSortOrder}" Grid.Column="1" HorizontalContentAlignment="Right"/>
|
<Label Content="{x:Static p:Resources.textSortOrder}" Grid.Column="1" HorizontalContentAlignment="Right"/>
|
||||||
<ComboBox x:Name="comboBoxSortOrder" Margin="2" Grid.Column="2" SelectionChanged="comboBoxSortOrder_SelectionChanged" />
|
<Grid Grid.Column="2" Grid.Row="1">
|
||||||
<CheckBox x:Name="checkboxShowCancelledCalls" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Checked="checkboxShowCancelledCalls_Checked" Unchecked="checkboxShowCancelledCalls_Checked" />
|
<Grid.ColumnDefinitions>
|
||||||
<Label Content="{x:Static p:Resources.textShowCancelledShipcalls}" Grid.Column="4" />
|
<ColumnDefinition Width=".5*" />
|
||||||
|
<ColumnDefinition Width="30" />
|
||||||
|
<ColumnDefinition Width=".5*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ComboBox x:Name="comboBoxSortOrder" Margin="2" Grid.Column="0" SelectionChanged="comboBoxSortOrder_SelectionChanged" />
|
||||||
|
<CheckBox x:Name="checkboxShowCancelledCalls" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Checked="checkboxShowCancelledCalls_Checked" Unchecked="checkboxShowCancelledCalls_Checked" />
|
||||||
|
<Label Content="{x:Static p:Resources.textShowCancelledShipcalls}" Grid.Column="2" />
|
||||||
|
</Grid>
|
||||||
|
<Label Content="{x:Static p:Resources.textHarbour}" Grid.Column="3" HorizontalAlignment="Right" />
|
||||||
|
<xctk:CheckComboBox x:Name="comboBoxPorts" Margin="2" Grid.Column="4" ItemSelectionChanged="comboBoxPorts_ItemSelectionChanged" DisplayMemberPath="Name" />
|
||||||
|
|
||||||
<Button Margin="2" Grid.Column="6" Content="{x:Static p:Resources.textClearFilters}" x:Name="buttonClearFilter" Click="buttonClearFilter_Click" Background="Transparent" />
|
<Button Margin="2" Grid.Column="6" Content="{x:Static p:Resources.textClearFilters}" x:Name="buttonClearFilter" Click="buttonClearFilter_Click" Background="Transparent" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid Grid.Row="2">
|
<Grid Grid.Row="2">
|
||||||
@ -114,6 +124,8 @@
|
|||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="26" />
|
<ColumnDefinition Width="26" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="26" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="26" />
|
<ColumnDefinition Width="26" />
|
||||||
@ -147,19 +159,25 @@
|
|||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
<Separator Grid.Column="9"/>
|
<Separator Grid.Column="9"/>
|
||||||
<StatusBarItem Grid.Column="10">
|
<StatusBarItem Grid.Column="10">
|
||||||
|
<Button x:Name="buttonNotifications" Click="buttonNotifications_Click" Width="20" ToolTip="{x:Static p:Resources.textShowNotifications}">
|
||||||
|
<Image Source="./Resources/bell3.png"/>
|
||||||
|
</Button>
|
||||||
|
</StatusBarItem>
|
||||||
|
<Separator Grid.Column="9"/>
|
||||||
|
<StatusBarItem Grid.Column="12">
|
||||||
<TextBlock Name="labelStatusBar"></TextBlock>
|
<TextBlock Name="labelStatusBar"></TextBlock>
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
<Separator Grid.Column="11"/>
|
<Separator Grid.Column="13"/>
|
||||||
<StatusBarItem Grid.Column="12">
|
<StatusBarItem Grid.Column="14">
|
||||||
<Button x:Name="buttonManualRefresh" Width="20" Click="buttonManualRefresh_Click" ToolTip="{x:Static p:Resources.textTriggerManualRefresh}">
|
<Button x:Name="buttonManualRefresh" Width="20" Click="buttonManualRefresh_Click" ToolTip="{x:Static p:Resources.textTriggerManualRefresh}">
|
||||||
<Image Source="./Resources/nav_refresh_green.png"/>
|
<Image Source="./Resources/nav_refresh_green.png"/>
|
||||||
</Button>
|
</Button>
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
<StatusBarItem Grid.Column="13">
|
<StatusBarItem Grid.Column="15">
|
||||||
<TextBlock x:Name="labelLatestUpdate" />
|
<TextBlock x:Name="labelLatestUpdate" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
<Separator Grid.Column="14"/>
|
<Separator Grid.Column="16"/>
|
||||||
<StatusBarItem Grid.Column="15">
|
<StatusBarItem Grid.Column="17">
|
||||||
<ProgressBar Name="generalProgressStatus" Width="90" Height="16" Foreground="LightGray"/>
|
<ProgressBar Name="generalProgressStatus" Width="90" Height="16" Foreground="LightGray"/>
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
</StatusBar>
|
</StatusBar>
|
||||||
|
|||||||
@ -25,6 +25,7 @@ using System.Net;
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
|
||||||
namespace BreCalClient
|
namespace BreCalClient
|
||||||
@ -35,8 +36,11 @@ namespace BreCalClient
|
|||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
private readonly ILog _log = LogManager.GetLogger(typeof(MainWindow));
|
private readonly ILog _log = LogManager.GetLogger(typeof(MainWindow));
|
||||||
|
private readonly ToastViewModel _vm;
|
||||||
|
|
||||||
private const int SHIPCALL_UPDATE_INTERVAL_SECONDS = 30;
|
private const int SHIPCALL_UPDATE_INTERVAL_SECONDS = 30;
|
||||||
private const int SHIPS_UPDATE_INTERVAL_SECONDS = 120;
|
private const int SHIPS_UPDATE_INTERVAL_SECONDS = 120;
|
||||||
|
private const int CHECK_NOTIFICATIONS_INTERVAL_SECONDS = 5;
|
||||||
private const int PROGRESS_STEPS = 50;
|
private const int PROGRESS_STEPS = 50;
|
||||||
|
|
||||||
#region Fields
|
#region Fields
|
||||||
@ -48,7 +52,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
private readonly ConcurrentDictionary<int, ShipcallControlModel> _allShipcallsDict = new();
|
private readonly ConcurrentDictionary<int, ShipcallControlModel> _allShipcallsDict = new();
|
||||||
private readonly ConcurrentDictionary<int, ShipcallControl> _allShipCallsControlDict = new();
|
private readonly ConcurrentDictionary<int, ShipcallControl> _allShipCallsControlDict = new();
|
||||||
private readonly List<ShipcallControlModel> _visibleControlModels = new();
|
private readonly List<ShipcallControlModel> _visibleControlModels = [];
|
||||||
|
|
||||||
private readonly ShipcallApi _shipcallApi;
|
private readonly ShipcallApi _shipcallApi;
|
||||||
private readonly UserApi _userApi;
|
private readonly UserApi _userApi;
|
||||||
@ -67,6 +71,7 @@ namespace BreCalClient
|
|||||||
// private bool _filterChanged = false;
|
// private bool _filterChanged = false;
|
||||||
// private bool _sequenceChanged = false;
|
// private bool _sequenceChanged = false;
|
||||||
private HistoryDialog? _historyDialog;
|
private HistoryDialog? _historyDialog;
|
||||||
|
private NotificationDialog? _notificationDialog;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -121,6 +126,13 @@ namespace BreCalClient
|
|||||||
RetryConfiguration.AsyncRetryPolicy = retryPolicy;
|
RetryConfiguration.AsyncRetryPolicy = retryPolicy;
|
||||||
|
|
||||||
this.generalProgressStatus.Maximum = PROGRESS_STEPS;
|
this.generalProgressStatus.Maximum = PROGRESS_STEPS;
|
||||||
|
_vm = new ToastViewModel();
|
||||||
|
this.Unloaded += MainWindow_Unloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainWindow_Unloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_vm.OnUnloaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -140,6 +152,7 @@ namespace BreCalClient
|
|||||||
};
|
};
|
||||||
this.comboBoxSortOrder.ItemsSource = Enum.GetValues(typeof(Extensions.SortOrder));
|
this.comboBoxSortOrder.ItemsSource = Enum.GetValues(typeof(Extensions.SortOrder));
|
||||||
this.comboBoxSortOrder.SelectedIndex = (int)_sortOrder;
|
this.comboBoxSortOrder.SelectedIndex = (int)_sortOrder;
|
||||||
|
AppNotification.LoadFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||||
@ -182,12 +195,12 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
catch (ApiException ex)
|
catch (ApiException ex)
|
||||||
{
|
{
|
||||||
if ((ex.ErrorContent != null && ((string)ex.ErrorContent).StartsWith("{"))) {
|
if ((ex.ErrorContent != null && ((string)ex.ErrorContent).StartsWith('{'))) {
|
||||||
Error? anError = JsonConvert.DeserializeObject<Error>((string)ex.ErrorContent);
|
Error? anError = JsonConvert.DeserializeObject<Error>((string)ex.ErrorContent);
|
||||||
if ((anError != null) && anError.Message.Equals("invalid credentials"))
|
if ((anError != null) && anError.ErrorField.Equals("invalid credentials"))
|
||||||
this.labelLoginResult.Content = BreCalClient.Resources.Resources.textWrongCredentials;
|
this.labelLoginResult.Content = BreCalClient.Resources.Resources.textWrongCredentials;
|
||||||
else
|
else
|
||||||
this.labelLoginResult.Content = anError?.Message ?? ex.Message;
|
this.labelLoginResult.Content = anError?.ErrorField ?? ex.Message;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.labelLoginResult.Content = ex.Message;
|
this.labelLoginResult.Content = ex.Message;
|
||||||
@ -246,7 +259,8 @@ namespace BreCalClient
|
|||||||
EditShipcallControl esc = new()
|
EditShipcallControl esc = new()
|
||||||
{
|
{
|
||||||
ShipEditingEnabled = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD),
|
ShipEditingEnabled = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD),
|
||||||
ShipApi = _shipApi
|
ShipApi = _shipApi,
|
||||||
|
IsCreate = true
|
||||||
};
|
};
|
||||||
if (model != null)
|
if (model != null)
|
||||||
esc.ShipcallModel = model;
|
esc.ShipcallModel = model;
|
||||||
@ -287,13 +301,15 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
scmOut.Shipcall.ShipId = esc.ShipcallModel.Shipcall.ShipId;
|
scmOut.Shipcall.ShipId = esc.ShipcallModel.Shipcall.ShipId;
|
||||||
|
scmOut.Shipcall.PortId = esc.ShipcallModel.Shipcall.PortId;
|
||||||
scmOut.Ship = esc.ShipcallModel.Ship;
|
scmOut.Ship = esc.ShipcallModel.Ship;
|
||||||
|
scmOut.AllowPortChange = false;
|
||||||
DateTime eta = esc.ShipcallModel.Shipcall?.Eta ?? DateTime.Now;
|
DateTime eta = esc.ShipcallModel.Shipcall?.Eta ?? DateTime.Now;
|
||||||
scmOut.Shipcall.Etd = eta.AddDays(2);
|
scmOut.Shipcall.Etd = eta.AddDays(2);
|
||||||
scmOut.Shipcall.DepartureBerthId = esc.ShipcallModel.Shipcall?.ArrivalBerthId;
|
scmOut.Shipcall.DepartureBerthId = esc.ShipcallModel.Shipcall?.ArrivalBerthId;
|
||||||
if (esc.ShipcallModel.Shipcall != null)
|
if (esc.ShipcallModel.Shipcall != null)
|
||||||
{
|
{
|
||||||
scmOut.Shipcall.Participants = new();
|
scmOut.Shipcall.Participants = [];
|
||||||
scmOut.Shipcall.Participants.AddRange(esc.ShipcallModel.Shipcall.Participants);
|
scmOut.Shipcall.Participants.AddRange(esc.ShipcallModel.Shipcall.Participants);
|
||||||
foreach(ParticipantType pType in esc.ShipcallModel.AssignedParticipants.Keys)
|
foreach(ParticipantType pType in esc.ShipcallModel.AssignedParticipants.Keys)
|
||||||
scmOut.AssignedParticipants[pType] = esc.ShipcallModel.AssignedParticipants[pType];
|
scmOut.AssignedParticipants[pType] = esc.ShipcallModel.AssignedParticipants[pType];
|
||||||
@ -320,11 +336,7 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
UserDetails ud = new()
|
UserDetails ud = new()
|
||||||
{
|
{
|
||||||
Id = _loginResult.Id,
|
Id = _loginResult.Id,
|
||||||
FirstName = _loginResult.FirstName,
|
|
||||||
LastName = _loginResult.LastName,
|
|
||||||
UserPhone = _loginResult.UserPhone,
|
|
||||||
UserEmail = _loginResult.UserEmail,
|
|
||||||
OldPassword = oldPw,
|
OldPassword = oldPw,
|
||||||
NewPassword = newPw
|
NewPassword = newPw
|
||||||
};
|
};
|
||||||
@ -342,6 +354,41 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
ad.ChangeUserSettingsRequested += async () =>
|
||||||
|
{
|
||||||
|
if (_loginResult != null)
|
||||||
|
{
|
||||||
|
UserDetails ud = new()
|
||||||
|
{
|
||||||
|
Id = _loginResult.Id,
|
||||||
|
FirstName = _loginResult.FirstName,
|
||||||
|
LastName = _loginResult.LastName,
|
||||||
|
UserPhone = _loginResult.UserPhone,
|
||||||
|
UserEmail = _loginResult.UserEmail,
|
||||||
|
NotifyEmail = _loginResult.NotifyEmail,
|
||||||
|
NotifyPopup = _loginResult.NotifyPopup,
|
||||||
|
NotifySignal = _loginResult.NotifySignal,
|
||||||
|
NotifyWhatsapp = _loginResult.NotifyWhatsapp,
|
||||||
|
};
|
||||||
|
if (_loginResult.NotifyOn != null)
|
||||||
|
{
|
||||||
|
ud.NotifyOn = new(_loginResult.NotifyOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _userApi.UserUpdateAsync(ud);
|
||||||
|
MessageBox.Show(BreCalClient.Resources.Resources.textInformationUpdated, BreCalClient.Resources.Resources.textConfirmation, MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.Dispatcher.Invoke(new Action(() =>
|
||||||
|
{
|
||||||
|
ShowErrorDialog(ex.Message, "Error saving user information");
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
ad.ShowDialog();
|
ad.ShowDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,6 +396,7 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
this.searchFilterControl.ClearFilters();
|
this.searchFilterControl.ClearFilters();
|
||||||
this.checkboxShowCancelledCalls.IsChecked = false;
|
this.checkboxShowCancelledCalls.IsChecked = false;
|
||||||
|
this.comboBoxPorts.UnSelectAll();
|
||||||
this.FilterShipcalls();
|
this.FilterShipcalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,6 +414,24 @@ namespace BreCalClient
|
|||||||
this.SearchFilterControl_SearchFilterChanged();
|
this.SearchFilterControl_SearchFilterChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void comboBoxPorts_ItemSelectionChanged(object sender, Xceed.Wpf.Toolkit.Primitives.ItemSelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
this.searchFilterControl.SearchFilter.Ports.Clear();
|
||||||
|
|
||||||
|
List<Berth> berths = [];
|
||||||
|
foreach (Port port in comboBoxPorts.SelectedItems)
|
||||||
|
{
|
||||||
|
this.searchFilterControl.SearchFilter.Ports.Add(port.Id);
|
||||||
|
berths.AddRange(BreCalLists.GetBerthsByPort(port.Id));
|
||||||
|
}
|
||||||
|
// create list of berths from selected port(s) or return all berths
|
||||||
|
if (berths.Count == 0)
|
||||||
|
berths = BreCalLists.AllBerths;
|
||||||
|
this.searchFilterControl.SetBerths(berths);
|
||||||
|
|
||||||
|
this.SearchFilterControl_SearchFilterChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private async void comboBoxSortOrder_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private async void comboBoxSortOrder_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
_sortOrder = (Extensions.SortOrder) this.comboBoxSortOrder.SelectedIndex;
|
_sortOrder = (Extensions.SortOrder) this.comboBoxSortOrder.SelectedIndex;
|
||||||
@ -383,8 +449,8 @@ namespace BreCalClient
|
|||||||
_historyDialog.Closed += (sender, e) => { this._historyDialog = null; };
|
_historyDialog.Closed += (sender, e) => { this._historyDialog = null; };
|
||||||
_historyDialog.HistoryItemSelected += (x) =>
|
_historyDialog.HistoryItemSelected += (x) =>
|
||||||
{
|
{
|
||||||
if(_allShipCallsControlDict.ContainsKey(x))
|
if(_allShipCallsControlDict.TryGetValue(x, out ShipcallControl? value))
|
||||||
_allShipCallsControlDict[x].BringIntoView();
|
value.BringIntoView();
|
||||||
};
|
};
|
||||||
_historyDialog.Show();
|
_historyDialog.Show();
|
||||||
}
|
}
|
||||||
@ -394,6 +460,21 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void buttonNotifications_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_notificationDialog == null)
|
||||||
|
{
|
||||||
|
_notificationDialog = new NotificationDialog();
|
||||||
|
_notificationDialog.AppNotifications = AppNotification.AppNotifications;
|
||||||
|
_notificationDialog.Closed += (sender, e) => { this._notificationDialog = null; };
|
||||||
|
_notificationDialog.Show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_notificationDialog.Activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void buttonManualRefresh_Click(object sender, RoutedEventArgs e)
|
private void buttonManualRefresh_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_refreshImmediately = true; // set flag to avoid timer loop termination
|
_refreshImmediately = true; // set flag to avoid timer loop termination
|
||||||
@ -409,11 +490,12 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
if (_loginResult == null) return;
|
if (_loginResult == null) return;
|
||||||
|
|
||||||
|
BreCalLists.InitializePorts(await _staticApi.GetPortsAsync());
|
||||||
BreCalLists.InitializeBerths(await _staticApi.BerthsGetAsync());
|
BreCalLists.InitializeBerths(await _staticApi.BerthsGetAsync());
|
||||||
BreCalLists.InitializeShips(await _shipApi.ShipsGetAsync());
|
BreCalLists.InitializeShips(await _shipApi.ShipsGetAsync());
|
||||||
BreCalLists.InitializeParticipants(await _staticApi.ParticipantsGetAsync());
|
BreCalLists.InitializeParticipants(await _staticApi.ParticipantsGetAsync());
|
||||||
|
|
||||||
this.searchFilterControl.SetBerths(BreCalLists.Berths);
|
this.searchFilterControl.SetBerths(BreCalLists.Berths);
|
||||||
|
|
||||||
foreach (Participant participant in BreCalLists.Participants)
|
foreach (Participant participant in BreCalLists.Participants)
|
||||||
{
|
{
|
||||||
@ -432,14 +514,14 @@ namespace BreCalClient
|
|||||||
SearchFilterModel? currentFilter = null;
|
SearchFilterModel? currentFilter = null;
|
||||||
if (SearchFilterModel.filterMap != null)
|
if (SearchFilterModel.filterMap != null)
|
||||||
{
|
{
|
||||||
if((_loginResult != null) && SearchFilterModel.filterMap.ContainsKey(_loginResult.Id))
|
if((_loginResult != null) && SearchFilterModel.filterMap.TryGetValue(_loginResult.Id, out SearchFilterModel? value))
|
||||||
{
|
{
|
||||||
currentFilter = SearchFilterModel.filterMap[_loginResult.Id];
|
currentFilter = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SearchFilterModel.filterMap = new();
|
SearchFilterModel.filterMap = [];
|
||||||
}
|
}
|
||||||
if (currentFilter == null)
|
if (currentFilter == null)
|
||||||
{
|
{
|
||||||
@ -448,10 +530,19 @@ namespace BreCalClient
|
|||||||
SearchFilterModel.filterMap[_loginResult.Id] = currentFilter;
|
SearchFilterModel.filterMap[_loginResult.Id] = currentFilter;
|
||||||
}
|
}
|
||||||
this.searchFilterControl.SetFilterFromModel(currentFilter);
|
this.searchFilterControl.SetFilterFromModel(currentFilter);
|
||||||
|
|
||||||
|
if (currentFilter.Ports != null)
|
||||||
|
{
|
||||||
|
foreach (Port p in this.comboBoxPorts.ItemsSource)
|
||||||
|
{
|
||||||
|
if (currentFilter.Ports.Contains(p.Id)) this.comboBoxPorts.SelectedItems.Add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = Task.Run(() => RefreshShipcalls());
|
_ = Task.Run(() => RefreshShipcalls());
|
||||||
_ = Task.Run(() => RefreshShips());
|
_ = Task.Run(() => RefreshShips());
|
||||||
|
_ = Task.Run(() => CheckNotifications());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,7 +607,7 @@ namespace BreCalClient
|
|||||||
// load times for each shipcall
|
// load times for each shipcall
|
||||||
List<Times> currentTimes = await _timesApi.TimesGetAsync(shipcall.Id);
|
List<Times> currentTimes = await _timesApi.TimesGetAsync(shipcall.Id);
|
||||||
|
|
||||||
if (!_allShipcallsDict.ContainsKey(shipcall.Id))
|
if (!_allShipcallsDict.TryGetValue(shipcall.Id, out ShipcallControlModel? value))
|
||||||
{
|
{
|
||||||
// add entry
|
// add entry
|
||||||
ShipcallControlModel scm = new()
|
ShipcallControlModel scm = new()
|
||||||
@ -528,10 +619,9 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// update entry
|
value.Shipcall = shipcall;
|
||||||
_allShipcallsDict[shipcall.Id].Shipcall = shipcall;
|
value.Times = currentTimes;
|
||||||
_allShipcallsDict[shipcall.Id].Times = currentTimes;
|
UpdateShipcall(value);
|
||||||
UpdateShipcall(_allShipcallsDict[shipcall.Id]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,6 +665,19 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task CheckNotifications()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Thread.Sleep(CHECK_NOTIFICATIONS_INTERVAL_SECONDS * 1000);
|
||||||
|
if (_loginResult?.NotifyPopup ?? false)
|
||||||
|
{
|
||||||
|
List<Notification> notifications = await _staticApi.NotificationsGetAsync();
|
||||||
|
AppNotification.UpdateNotifications(notifications, _allShipcallsDict, _vm, _loginResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region basic operations
|
#region basic operations
|
||||||
@ -585,8 +688,8 @@ namespace BreCalClient
|
|||||||
_allShipcallsDict[scm.Shipcall.Id] = scm;
|
_allShipcallsDict[scm.Shipcall.Id] = scm;
|
||||||
|
|
||||||
Shipcall shipcall = scm.Shipcall;
|
Shipcall shipcall = scm.Shipcall;
|
||||||
if (BreCalLists.ShipLookupDict.ContainsKey(shipcall.ShipId))
|
if (BreCalLists.ShipLookupDict.TryGetValue(shipcall.ShipId, out ShipModel? value))
|
||||||
scm.Ship = BreCalLists.ShipLookupDict[shipcall.ShipId].Ship;
|
scm.Ship = value.Ship;
|
||||||
|
|
||||||
if (shipcall.Type == ShipcallType.Arrival)
|
if (shipcall.Type == ShipcallType.Arrival)
|
||||||
{
|
{
|
||||||
@ -604,7 +707,7 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
ShipcallControl sc = new()
|
ShipcallControl sc = new()
|
||||||
{
|
{
|
||||||
Height = 135,
|
Height = 145,
|
||||||
ShipcallControlModel = scm
|
ShipcallControlModel = scm
|
||||||
};
|
};
|
||||||
sc.EditTimesRequested += Sc_EditTimesRequested;
|
sc.EditTimesRequested += Sc_EditTimesRequested;
|
||||||
@ -619,8 +722,8 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
if(scm.Shipcall == null) return;
|
if(scm.Shipcall == null) return;
|
||||||
Shipcall shipcall = scm.Shipcall;
|
Shipcall shipcall = scm.Shipcall;
|
||||||
if (BreCalLists.ShipLookupDict.ContainsKey(shipcall.ShipId))
|
if (BreCalLists.ShipLookupDict.TryGetValue(shipcall.ShipId, out ShipModel? value))
|
||||||
scm.Ship = BreCalLists.ShipLookupDict[shipcall.ShipId].Ship;
|
scm.Ship = value.Ship;
|
||||||
|
|
||||||
if (shipcall.Type == ShipcallType.Arrival)
|
if (shipcall.Type == ShipcallType.Arrival)
|
||||||
{
|
{
|
||||||
@ -700,6 +803,11 @@ namespace BreCalClient
|
|||||||
_ = this._visibleControlModels.RemoveAll(x => { if (x.Shipcall == null) return false; else return !sfm.Categories.Contains(x.Shipcall.Type); });
|
_ = this._visibleControlModels.RemoveAll(x => { if (x.Shipcall == null) return false; else return !sfm.Categories.Contains(x.Shipcall.Type); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(sfm.Ports.Count > 0 )
|
||||||
|
{
|
||||||
|
_ = this._visibleControlModels.RemoveAll(x => { if(x.Shipcall == null) return false; else return !sfm.Ports.Contains(x.Shipcall.PortId); });
|
||||||
|
}
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(sfm.SearchString))
|
if(!string.IsNullOrEmpty(sfm.SearchString))
|
||||||
{
|
{
|
||||||
_ = this._visibleControlModels.RemoveAll(x => !(x.ContainsRemarkText(sfm.SearchString) || (x.Ship?.Name.Contains(sfm.SearchString, StringComparison.InvariantCultureIgnoreCase) ?? false)));
|
_ = this._visibleControlModels.RemoveAll(x => !(x.ContainsRemarkText(sfm.SearchString) || (x.Ship?.Name.Contains(sfm.SearchString, StringComparison.InvariantCultureIgnoreCase) ?? false)));
|
||||||
@ -860,10 +968,10 @@ namespace BreCalClient
|
|||||||
foreach (ShipcallControlModel visibleModel in this._visibleControlModels)
|
foreach (ShipcallControlModel visibleModel in this._visibleControlModels)
|
||||||
{
|
{
|
||||||
if (visibleModel.Shipcall == null) continue; // should not happen
|
if (visibleModel.Shipcall == null) continue; // should not happen
|
||||||
if (this._allShipCallsControlDict.ContainsKey(visibleModel.Shipcall.Id))
|
if (this._allShipCallsControlDict.TryGetValue(visibleModel.Shipcall.Id, out ShipcallControl? value))
|
||||||
{
|
{
|
||||||
this._allShipCallsControlDict[visibleModel.Shipcall.Id].RefreshData();
|
value.RefreshData();
|
||||||
this.stackPanel.Children.Add(this._allShipCallsControlDict[visibleModel.Shipcall.Id]);
|
this.stackPanel.Children.Add(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -899,19 +1007,16 @@ namespace BreCalClient
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
obj.ShipcallControlModel.Shipcall?.Participants.Clear();
|
obj.ShipcallControlModel.Shipcall?.Participants.Clear();
|
||||||
if (!await obj.ShipcallControlModel.UpdateTimesAssignments(this._timesApi))
|
if(! await obj.ShipcallControlModel.UpdateTimesAssignments(this._timesApi))
|
||||||
{
|
{
|
||||||
ShowErrorDialog(obj.ShipcallControlModel.LastErrorMessage, "Update assignments error");
|
ShowErrorDialog(obj.ShipcallControlModel.LastErrorMessage, "Update assignments error");
|
||||||
}
|
}
|
||||||
else
|
foreach(ParticipantAssignment pa in obj.ShipcallControlModel.AssignedParticipants.Values)
|
||||||
{
|
obj.ShipcallControlModel.Shipcall?.Participants.Add(pa);
|
||||||
foreach (ParticipantAssignment pa in obj.ShipcallControlModel.AssignedParticipants.Values)
|
await _shipcallApi.ShipcallUpdateAsync(obj.ShipcallControlModel.Shipcall);
|
||||||
obj.ShipcallControlModel.Shipcall?.Participants.Add(pa);
|
obj.RefreshData();
|
||||||
await _shipcallApi.ShipcallUpdateAsync(obj.ShipcallControlModel.Shipcall);
|
_refreshImmediately = true;
|
||||||
obj.RefreshData();
|
_tokenSource.Cancel();
|
||||||
_refreshImmediately = true;
|
|
||||||
_tokenSource.Cancel();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -972,6 +1077,13 @@ namespace BreCalClient
|
|||||||
etc.Times.Id = apiResultId.VarId;
|
etc.Times.Id = apiResultId.VarId;
|
||||||
obj.ShipcallControlModel?.Times.Add(etc.Times);
|
obj.ShipcallControlModel?.Times.Add(etc.Times);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a pilot may have changed the tidal window so we update the shipcall too in this case
|
||||||
|
if(((Extensions.ParticipantType)etc.Times.ParticipantType) == ParticipantType.PILOT)
|
||||||
|
{
|
||||||
|
await _shipcallApi.ShipcallUpdateAsync(obj.ShipcallControlModel?.Shipcall);
|
||||||
|
}
|
||||||
|
|
||||||
_refreshImmediately = true;
|
_refreshImmediately = true;
|
||||||
_tokenSource.Cancel();
|
_tokenSource.Cancel();
|
||||||
}
|
}
|
||||||
@ -1009,8 +1121,8 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(editControl.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
if(editControl.ShipcallModel.AssignedParticipants.TryGetValue(ParticipantType.AGENCY, out ParticipantAssignment? value))
|
||||||
editControl.Times.ParticipantId = editControl.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId;
|
editControl.Times.ParticipantId = value.ParticipantId;
|
||||||
}
|
}
|
||||||
editControl.Times.ParticipantType = (int)ParticipantType.AGENCY;
|
editControl.Times.ParticipantType = (int)ParticipantType.AGENCY;
|
||||||
if(editControl.ShowDialog() ?? false)
|
if(editControl.ShowDialog() ?? false)
|
||||||
@ -1026,9 +1138,9 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
// always try to be the agent, even if we are BSMD
|
// always try to be the agent, even if we are BSMD
|
||||||
if (editControl.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
if (editControl.ShipcallModel.AssignedParticipants.TryGetValue(ParticipantType.AGENCY, out ParticipantAssignment? value))
|
||||||
{
|
{
|
||||||
editControl.Times.ParticipantId = editControl.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId;
|
editControl.Times.ParticipantId = value.ParticipantId;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1077,7 +1189,7 @@ namespace BreCalClient
|
|||||||
// (if the special-flag is enabled). Assigned Agency: ShipcallParticipantMap(id=628, shipcall_id=115, participant_id=10,
|
// (if the special-flag is enabled). Assigned Agency: ShipcallParticipantMap(id=628, shipcall_id=115, participant_id=10,
|
||||||
// type=8, created=datetime.datetime(2024, 8, 28, 15, 13, 14), modified=None) with Flags: 42\"}
|
// type=8, created=datetime.datetime(2024, 8, 28, 15, 13, 14), modified=None) with Flags: 42\"}
|
||||||
|
|
||||||
Match m = Regex.Match(message, "\\{(.*)\\}");
|
Match m = ErrorRegex().Match(message);
|
||||||
if ((m != null) && m.Success)
|
if ((m != null) && m.Success)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -1112,6 +1224,8 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD))
|
if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD))
|
||||||
this.buttonNew.Visibility = Visibility.Visible;
|
this.buttonNew.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
this.comboBoxPorts.ItemsSource = BreCalLists.AllPorts.Where(x => App.Participant.Ports.Contains(x.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
|
private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
|
||||||
@ -1120,6 +1234,9 @@ namespace BreCalClient
|
|||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[GeneratedRegex("\\{(.*)\\}")]
|
||||||
|
private static partial Regex ErrorRegex();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
68
src/BreCalClient/NotificationDialog.xaml
Normal file
68
src/BreCalClient/NotificationDialog.xaml
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<Window x:Class="BreCalClient.NotificationDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:BreCalClient"
|
||||||
|
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||||
|
xmlns:p = "clr-namespace:BreCalClient.Resources"
|
||||||
|
mc:Ignorable="d" Left="{local:SettingBinding W5Left}" Top="{local:SettingBinding W5Top}"
|
||||||
|
Title="{x:Static p:Resources.textNotifications}" Height="450" Width="800" Loaded="Window_Loaded">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<local:ENIDataGrid x:Name="dataGridNotifications" Grid.Row="0" SelectionMode="Single" IsReadOnly="True" AutoGenerateColumns="False"
|
||||||
|
CanUserAddRows="False" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
|
||||||
|
<local:ENIDataGrid.RowStyle>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding NotificationType}" Value="Assignment">
|
||||||
|
<Setter Property="Foreground" Value="Blue"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding NotificationType}" Value="Next24h">
|
||||||
|
<Setter Property="Foreground" Value="DarkOrange"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding NotificationType}" Value="TimeConflict">
|
||||||
|
<Setter Property="Background" Value="Red"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding NotificationType}" Value="TimeConflictResolved">
|
||||||
|
<Setter Property="Foreground" Value="Green"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding NotificationType}" Value="Unassigned">
|
||||||
|
<Setter Property="Foreground" Value="DarkGray"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding NotificationType}" Value="MissingData">
|
||||||
|
<Setter Property="Foreground" Value="Yellow" />
|
||||||
|
<Setter Property="Background" Value="DarkGray" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding NotificationType}" Value="Cancelled">
|
||||||
|
<Setter Property="Background" Value="LightGray" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</local:ENIDataGrid.RowStyle>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Id" Binding="{Binding Path=Id}" IsReadOnly="True"/>
|
||||||
|
<DataGridTextColumn Header="{x:Static p:Resources.textType}" Binding="{Binding Path=NotificationDisplay}" IsReadOnly="True"/>
|
||||||
|
<DataGridTextColumn Header="{x:Static p:Resources.textDate}" Binding="{Binding Path=NotificationDate}" IsReadOnly="True"/>
|
||||||
|
<DataGridTextColumn Header="{x:Static p:Resources.textShip}" Binding="{Binding Path=Ship}" IsReadOnly="True"/>
|
||||||
|
<DataGridTextColumn Header="{x:Static p:Resources.textShipcall}" Binding="{Binding Path=ShipcallType}" IsReadOnly="True"/>
|
||||||
|
<DataGridTextColumn Header="ETA/ETD" Binding="{Binding Path=ETA}" IsReadOnly="True"/>
|
||||||
|
<DataGridTextColumn Header="{x:Static p:Resources.textBerth}" Binding="{Binding Path=Berth}" IsReadOnly="True"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</local:ENIDataGrid>
|
||||||
|
<Grid Grid.Row="1" Grid.Column="0" >
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="22" />
|
||||||
|
<ColumnDefinition Width="80" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width=".2*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button x:Name="buttonClose" Click="buttonClose_Click" Content="{x:Static p:Resources.textClose}" Width="80" Margin="2" Grid.Row="0" Grid.Column="3" HorizontalAlignment="Right" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
44
src/BreCalClient/NotificationDialog.xaml.cs
Normal file
44
src/BreCalClient/NotificationDialog.xaml.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) 2024- schick Informatik
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace BreCalClient
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for NotificationDialog.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class NotificationDialog : Window
|
||||||
|
{
|
||||||
|
public NotificationDialog()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ObservableCollection<AppNotification>? AppNotifications { get; set; }
|
||||||
|
|
||||||
|
private void buttonClose_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.dataGridNotifications.ItemsSource = AppNotifications;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,8 +4,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
-->
|
-->
|
||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ApplicationRevision>1</ApplicationRevision>
|
<ApplicationRevision>0</ApplicationRevision>
|
||||||
<ApplicationVersion>1.4.1.0</ApplicationVersion>
|
<ApplicationVersion>1.8.0.0</ApplicationVersion>
|
||||||
<BootstrapperEnabled>True</BootstrapperEnabled>
|
<BootstrapperEnabled>True</BootstrapperEnabled>
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
||||||
@ -21,7 +21,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<OpenBrowserOnPublish>False</OpenBrowserOnPublish>
|
<OpenBrowserOnPublish>False</OpenBrowserOnPublish>
|
||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<ProductName>Bremen calling development client</ProductName>
|
<ProductName>Bremen calling development client</ProductName>
|
||||||
<PublishDir>bin\Debug\net6.0-windows\win-x64\app.publish\</PublishDir>
|
<PublishDir>bin\Debug\net8.0-windows7.0\win-x64\app.publish\</PublishDir>
|
||||||
<PublishUrl>bin\publish.devel\</PublishUrl>
|
<PublishUrl>bin\publish.devel\</PublishUrl>
|
||||||
<PublisherName>Informatikbüro Daniel Schick</PublisherName>
|
<PublisherName>Informatikbüro Daniel Schick</PublisherName>
|
||||||
<PublishProtocol>ClickOnce</PublishProtocol>
|
<PublishProtocol>ClickOnce</PublishProtocol>
|
||||||
@ -33,11 +33,13 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<SignManifests>False</SignManifests>
|
<SignManifests>False</SignManifests>
|
||||||
<SuiteName>Bremen calling</SuiteName>
|
<SuiteName>Bremen calling</SuiteName>
|
||||||
<SupportUrl>https://www.textbausteine.net/</SupportUrl>
|
<SupportUrl>https://www.textbausteine.net/</SupportUrl>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<UpdateEnabled>True</UpdateEnabled>
|
<UpdateEnabled>True</UpdateEnabled>
|
||||||
<UpdateMode>Foreground</UpdateMode>
|
<UpdateMode>Foreground</UpdateMode>
|
||||||
<UpdateRequired>False</UpdateRequired>
|
<UpdateRequired>True</UpdateRequired>
|
||||||
<WebPageFileName>Publish.html</WebPageFileName>
|
<WebPageFileName>Publish.html</WebPageFileName>
|
||||||
|
<MinimumRequiredVersion>1.8.0.0</MinimumRequiredVersion>
|
||||||
|
<SkipPublishVerification>false</SkipPublishVerification>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PublishFile Include="containership.ico">
|
<PublishFile Include="containership.ico">
|
||||||
|
|||||||
@ -4,8 +4,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
-->
|
-->
|
||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ApplicationRevision>0</ApplicationRevision>
|
<ApplicationRevision>5</ApplicationRevision>
|
||||||
<ApplicationVersion>1.5.0.10</ApplicationVersion>
|
<ApplicationVersion>1.7.0.7</ApplicationVersion>
|
||||||
<BootstrapperEnabled>True</BootstrapperEnabled>
|
<BootstrapperEnabled>True</BootstrapperEnabled>
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
||||||
@ -27,10 +27,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<SelfContained>True</SelfContained>
|
<SelfContained>True</SelfContained>
|
||||||
<SignatureAlgorithm>(none)</SignatureAlgorithm>
|
<SignatureAlgorithm>(none)</SignatureAlgorithm>
|
||||||
<SignManifests>False</SignManifests>
|
<SignManifests>False</SignManifests>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<UpdateEnabled>True</UpdateEnabled>
|
<UpdateEnabled>True</UpdateEnabled>
|
||||||
<UpdateMode>Foreground</UpdateMode>
|
<UpdateMode>Foreground</UpdateMode>
|
||||||
<UpdateRequired>False</UpdateRequired>
|
<UpdateRequired>True</UpdateRequired>
|
||||||
<WebPageFileName>Publish.html</WebPageFileName>
|
<WebPageFileName>Publish.html</WebPageFileName>
|
||||||
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
||||||
<ErrorReportUrl>https://www.bsmd-emswe.eu/</ErrorReportUrl>
|
<ErrorReportUrl>https://www.bsmd-emswe.eu/</ErrorReportUrl>
|
||||||
@ -38,8 +38,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<PublisherName>Informatikbüro Daniel Schick</PublisherName>
|
<PublisherName>Informatikbüro Daniel Schick</PublisherName>
|
||||||
<SuiteName>Bremen Calling</SuiteName>
|
<SuiteName>Bremen Calling</SuiteName>
|
||||||
<SupportUrl>http://www.textbausteine.net/</SupportUrl>
|
<SupportUrl>http://www.textbausteine.net/</SupportUrl>
|
||||||
<PublishDir>bin\Debug\net6.0-windows\win-x64\app.publish\</PublishDir>
|
<PublishDir>bin\Debug\net8.0-windows7.0\win-x64\app.publish\</PublishDir>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
<SkipPublishVerification>false</SkipPublishVerification>
|
||||||
|
<MinimumRequiredVersion>1.7.0.7</MinimumRequiredVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PublishFile Include="containership.ico">
|
<PublishFile Include="containership.ico">
|
||||||
|
|||||||
41
src/BreCalClient/Properties/Settings.Designer.cs
generated
41
src/BreCalClient/Properties/Settings.Designer.cs
generated
@ -12,7 +12,7 @@ namespace BreCalClient.Properties {
|
|||||||
|
|
||||||
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.10.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.12.0.0")]
|
||||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
@ -34,7 +34,7 @@ namespace BreCalClient.Properties {
|
|||||||
|
|
||||||
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Configuration.DefaultSettingValueAttribute("!!Bremen calling Testversion!!")]
|
[global::System.Configuration.DefaultSettingValueAttribute("!!Bremen calling Entwicklungsversion!!")]
|
||||||
public string APP_TITLE {
|
public string APP_TITLE {
|
||||||
get {
|
get {
|
||||||
return ((string)(this["APP_TITLE"]));
|
return ((string)(this["APP_TITLE"]));
|
||||||
@ -64,7 +64,7 @@ namespace BreCalClient.Properties {
|
|||||||
|
|
||||||
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Configuration.DefaultSettingValueAttribute("http://127.0.0.1:5000")]
|
[global::System.Configuration.DefaultSettingValueAttribute("https://brecaltest.bsmd-emswe.eu")]
|
||||||
public string API_URL {
|
public string API_URL {
|
||||||
get {
|
get {
|
||||||
return ((string)(this["API_URL"]));
|
return ((string)(this["API_URL"]));
|
||||||
@ -226,5 +226,40 @@ namespace BreCalClient.Properties {
|
|||||||
this["FilterCriteriaMap"] = value;
|
this["FilterCriteriaMap"] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
public global::System.Collections.Specialized.StringCollection Notifications {
|
||||||
|
get {
|
||||||
|
return ((global::System.Collections.Specialized.StringCollection)(this["Notifications"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["Notifications"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("0")]
|
||||||
|
public double W5Top {
|
||||||
|
get {
|
||||||
|
return ((double)(this["W5Top"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["W5Top"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("0")]
|
||||||
|
public double W5Left {
|
||||||
|
get {
|
||||||
|
return ((double)(this["W5Left"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["W5Left"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<Value Profile="(Default)">#751D1F</Value>
|
<Value Profile="(Default)">#751D1F</Value>
|
||||||
</Setting>
|
</Setting>
|
||||||
<Setting Name="APP_TITLE" Type="System.String" Scope="Application">
|
<Setting Name="APP_TITLE" Type="System.String" Scope="Application">
|
||||||
<Value Profile="(Default)">!!Bremen calling Testversion!!</Value>
|
<Value Profile="(Default)">!!Bremen calling Entwicklungsversion!!</Value>
|
||||||
</Setting>
|
</Setting>
|
||||||
<Setting Name="LOGO_IMAGE_URL" Type="System.String" Scope="Application">
|
<Setting Name="LOGO_IMAGE_URL" Type="System.String" Scope="Application">
|
||||||
<Value Profile="(Default)">https://www.textbausteine.net/</Value>
|
<Value Profile="(Default)">https://www.textbausteine.net/</Value>
|
||||||
@ -15,7 +15,7 @@
|
|||||||
<Value Profile="(Default)" />
|
<Value Profile="(Default)" />
|
||||||
</Setting>
|
</Setting>
|
||||||
<Setting Name="API_URL" Type="System.String" Scope="Application">
|
<Setting Name="API_URL" Type="System.String" Scope="Application">
|
||||||
<Value Profile="(Default)">http://127.0.0.1:5000</Value>
|
<Value Profile="(Default)">https://brecaltest.bsmd-emswe.eu</Value>
|
||||||
</Setting>
|
</Setting>
|
||||||
<Setting Name="Width" Type="System.Double" Scope="User">
|
<Setting Name="Width" Type="System.Double" Scope="User">
|
||||||
<Value Profile="(Default)">800</Value>
|
<Value Profile="(Default)">800</Value>
|
||||||
@ -56,5 +56,14 @@
|
|||||||
<Setting Name="FilterCriteriaMap" Type="System.String" Scope="User">
|
<Setting Name="FilterCriteriaMap" Type="System.String" Scope="User">
|
||||||
<Value Profile="(Default)" />
|
<Value Profile="(Default)" />
|
||||||
</Setting>
|
</Setting>
|
||||||
|
<Setting Name="Notifications" Type="System.Collections.Specialized.StringCollection" Scope="User">
|
||||||
|
<Value Profile="(Default)" />
|
||||||
|
</Setting>
|
||||||
|
<Setting Name="W5Top" Type="System.Double" Scope="User">
|
||||||
|
<Value Profile="(Default)">0</Value>
|
||||||
|
</Setting>
|
||||||
|
<Setting Name="W5Left" Type="System.Double" Scope="User">
|
||||||
|
<Value Profile="(Default)">0</Value>
|
||||||
|
</Setting>
|
||||||
</Settings>
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
||||||
172
src/BreCalClient/Resources/Resources.Designer.cs
generated
172
src/BreCalClient/Resources/Resources.Designer.cs
generated
@ -167,6 +167,16 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
|
/// </summary>
|
||||||
|
public static byte[] bell3 {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("bell3", resourceCulture);
|
||||||
|
return ((byte[])(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Byte[].
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -380,6 +390,15 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Participant assigned to shipcall.
|
||||||
|
/// </summary>
|
||||||
|
public static string textAssignment {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textAssignment", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Berth.
|
/// Looks up a localized string similar to Berth.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -560,6 +579,15 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Date.
|
||||||
|
/// </summary>
|
||||||
|
public static string textDate {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textDate", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Delete.
|
/// Looks up a localized string similar to Delete.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -596,6 +624,15 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Draft.
|
||||||
|
/// </summary>
|
||||||
|
public static string textDraftNoUnit {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textDraftNoUnit", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Edit.
|
/// Looks up a localized string similar to Edit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -749,6 +786,15 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Harbour.
|
||||||
|
/// </summary>
|
||||||
|
public static string textHarbour {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textHarbour", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Incoming.
|
/// Looks up a localized string similar to Incoming.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -767,6 +813,15 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Information successfully updated.
|
||||||
|
/// </summary>
|
||||||
|
public static string textInformationUpdated {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textInformationUpdated", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Interval.
|
/// Looks up a localized string similar to Interval.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -830,6 +885,15 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The participant has not provided any info.
|
||||||
|
/// </summary>
|
||||||
|
public static string textMissingData {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textMissingData", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Moored in lock.
|
/// Looks up a localized string similar to Moored in lock.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -866,6 +930,51 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Relevant next 24hrs.
|
||||||
|
/// </summary>
|
||||||
|
public static string textNext24h {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textNext24h", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Notifications.
|
||||||
|
/// </summary>
|
||||||
|
public static string textNotifications {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textNotifications", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Notify by e-mail.
|
||||||
|
/// </summary>
|
||||||
|
public static string textNotifyEmail {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textNotifyEmail", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Notify on.
|
||||||
|
/// </summary>
|
||||||
|
public static string textNotifyOn {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textNotifyOn", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Notify by push notification in app.
|
||||||
|
/// </summary>
|
||||||
|
public static string textNotifyPush {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textNotifyPush", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Not rotated.
|
/// Looks up a localized string similar to Not rotated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1046,6 +1155,15 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Position.
|
||||||
|
/// </summary>
|
||||||
|
public static string textPosition {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textPosition", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Rain sensitive cargo.
|
/// Looks up a localized string similar to Rain sensitive cargo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1163,6 +1281,24 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Shipcall.
|
||||||
|
/// </summary>
|
||||||
|
public static string textShipcall {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textShipcall", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The shipcall was cancelled.
|
||||||
|
/// </summary>
|
||||||
|
public static string textShipcallCancelled {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textShipcallCancelled", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Ship length.
|
/// Looks up a localized string similar to Ship length.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1199,6 +1335,15 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Show notificiations.
|
||||||
|
/// </summary>
|
||||||
|
public static string textShowNotifications {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textShowNotifications", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Sort order.
|
/// Looks up a localized string similar to Sort order.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1262,6 +1407,24 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Participants disagree on times.
|
||||||
|
/// </summary>
|
||||||
|
public static string textTimeConflict {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textTimeConflict", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Times conflict resolved.
|
||||||
|
/// </summary>
|
||||||
|
public static string textTimeConflictResolved {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textTimeConflictResolved", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Timestamp.
|
/// Looks up a localized string similar to Timestamp.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1352,6 +1515,15 @@ namespace BreCalClient.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Participant unassigned from shipcall.
|
||||||
|
/// </summary>
|
||||||
|
public static string textUnassigned {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("textUnassigned", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to User login.
|
/// Looks up a localized string similar to User login.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -235,6 +235,9 @@
|
|||||||
<data name="textDraft" xml:space="preserve">
|
<data name="textDraft" xml:space="preserve">
|
||||||
<value>Tiefgang (m)</value>
|
<value>Tiefgang (m)</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="textDraftNoUnit" xml:space="preserve">
|
||||||
|
<value>Tiefgang</value>
|
||||||
|
</data>
|
||||||
<data name="textEdit" xml:space="preserve">
|
<data name="textEdit" xml:space="preserve">
|
||||||
<value>Bearbeiten</value>
|
<value>Bearbeiten</value>
|
||||||
</data>
|
</data>
|
||||||
@ -286,6 +289,9 @@
|
|||||||
<data name="textFrom" xml:space="preserve">
|
<data name="textFrom" xml:space="preserve">
|
||||||
<value>von</value>
|
<value>von</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="textHarbour" xml:space="preserve">
|
||||||
|
<value>Hafen</value>
|
||||||
|
</data>
|
||||||
<data name="textIncoming" xml:space="preserve">
|
<data name="textIncoming" xml:space="preserve">
|
||||||
<value>Einkommend</value>
|
<value>Einkommend</value>
|
||||||
</data>
|
</data>
|
||||||
@ -550,4 +556,49 @@
|
|||||||
<data name="textStartTimeMissing" xml:space="preserve">
|
<data name="textStartTimeMissing" xml:space="preserve">
|
||||||
<value>Wenn eine Ende-Zeit angegeben wird, muss auch eine Start-Zeit angegeben werden</value>
|
<value>Wenn eine Ende-Zeit angegeben wird, muss auch eine Start-Zeit angegeben werden</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="textInformationUpdated" xml:space="preserve">
|
||||||
|
<value>Einstellungen erfolgreich aktualisiert</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNotifications" xml:space="preserve">
|
||||||
|
<value>Benachrichtigungen</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNotifyEmail" xml:space="preserve">
|
||||||
|
<value>E-Mail Benachrichtigung</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNotifyPush" xml:space="preserve">
|
||||||
|
<value>Banner / Push Benachrichtigung in App</value>
|
||||||
|
</data>
|
||||||
|
<data name="textAssignment" xml:space="preserve">
|
||||||
|
<value>Teilnehmer wurde nominiert</value>
|
||||||
|
</data>
|
||||||
|
<data name="textDate" xml:space="preserve">
|
||||||
|
<value>Datum</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNext24h" xml:space="preserve">
|
||||||
|
<value>Relevant für Morgenrunde (24hrs)</value>
|
||||||
|
</data>
|
||||||
|
<data name="textShipcall" xml:space="preserve">
|
||||||
|
<value>Anlauf</value>
|
||||||
|
</data>
|
||||||
|
<data name="textShowNotifications" xml:space="preserve">
|
||||||
|
<value>Benachrichtigungen anzeigen</value>
|
||||||
|
</data>
|
||||||
|
<data name="textTimeConflict" xml:space="preserve">
|
||||||
|
<value>"Ampel"-Regel(n) wurde verletzt</value>
|
||||||
|
</data>
|
||||||
|
<data name="textTimeConflictResolved" xml:space="preserve">
|
||||||
|
<value>Zeitliche Konflikte aufgelöst</value>
|
||||||
|
</data>
|
||||||
|
<data name="textUnassigned" xml:space="preserve">
|
||||||
|
<value>Nominierung des Teilnehmer entfernt</value>
|
||||||
|
</data>
|
||||||
|
<data name="textMissingData" xml:space="preserve">
|
||||||
|
<value>Der Teilnehmer hat keine Daten eingetragen</value>
|
||||||
|
</data>
|
||||||
|
<data name="textShipcallCancelled" xml:space="preserve">
|
||||||
|
<value>Der Anlauf wurde storniert</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNotifyOn" xml:space="preserve">
|
||||||
|
<value>Benachrichtigung bei</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@ -328,6 +328,9 @@
|
|||||||
<data name="textFrom" xml:space="preserve">
|
<data name="textFrom" xml:space="preserve">
|
||||||
<value>from</value>
|
<value>from</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="textHarbour" xml:space="preserve">
|
||||||
|
<value>Harbour</value>
|
||||||
|
</data>
|
||||||
<data name="textIncoming" xml:space="preserve">
|
<data name="textIncoming" xml:space="preserve">
|
||||||
<value>Incoming</value>
|
<value>Incoming</value>
|
||||||
</data>
|
</data>
|
||||||
@ -598,4 +601,58 @@
|
|||||||
<data name="textStartTimeMissing" xml:space="preserve">
|
<data name="textStartTimeMissing" xml:space="preserve">
|
||||||
<value>If an end time is set, a start time is also required</value>
|
<value>If an end time is set, a start time is also required</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="textInformationUpdated" xml:space="preserve">
|
||||||
|
<value>Information successfully updated</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNotifications" xml:space="preserve">
|
||||||
|
<value>Notifications</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNotifyEmail" xml:space="preserve">
|
||||||
|
<value>Notify by e-mail</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNotifyPush" xml:space="preserve">
|
||||||
|
<value>Notify by push notification in app</value>
|
||||||
|
</data>
|
||||||
|
<data name="bell3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>bell3.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name="textAssignment" xml:space="preserve">
|
||||||
|
<value>Participant assigned to shipcall</value>
|
||||||
|
</data>
|
||||||
|
<data name="textDate" xml:space="preserve">
|
||||||
|
<value>Date</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNext24h" xml:space="preserve">
|
||||||
|
<value>Relevant next 24hrs</value>
|
||||||
|
</data>
|
||||||
|
<data name="textShipcall" xml:space="preserve">
|
||||||
|
<value>Shipcall</value>
|
||||||
|
</data>
|
||||||
|
<data name="textShowNotifications" xml:space="preserve">
|
||||||
|
<value>Show notificiations</value>
|
||||||
|
</data>
|
||||||
|
<data name="textTimeConflict" xml:space="preserve">
|
||||||
|
<value>Participants disagree on times</value>
|
||||||
|
</data>
|
||||||
|
<data name="textTimeConflictResolved" xml:space="preserve">
|
||||||
|
<value>Times conflict resolved</value>
|
||||||
|
</data>
|
||||||
|
<data name="textUnassigned" xml:space="preserve">
|
||||||
|
<value>Participant unassigned from shipcall</value>
|
||||||
|
</data>
|
||||||
|
<data name="textMissingData" xml:space="preserve">
|
||||||
|
<value>The participant has not provided any info</value>
|
||||||
|
</data>
|
||||||
|
<data name="textShipcallCancelled" xml:space="preserve">
|
||||||
|
<value>The shipcall was cancelled</value>
|
||||||
|
</data>
|
||||||
|
<data name="textNotifyOn" xml:space="preserve">
|
||||||
|
<value>Notify on</value>
|
||||||
|
</data>
|
||||||
|
<data name="textPosition" xml:space="preserve">
|
||||||
|
<value>Position</value>
|
||||||
|
</data>
|
||||||
|
<data name="textDraftNoUnit" xml:space="preserve">
|
||||||
|
<value>Draft</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
BIN
src/BreCalClient/Resources/bell3.png
Normal file
BIN
src/BreCalClient/Resources/bell3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@ -25,6 +25,8 @@ namespace BreCalClient
|
|||||||
|
|
||||||
public List<int> Berths { get; set; } = new();
|
public List<int> Berths { get; set; } = new();
|
||||||
|
|
||||||
|
public List<int> Ports { get; set; } = new();
|
||||||
|
|
||||||
public string? SearchString { get; set; }
|
public string? SearchString { get; set; }
|
||||||
|
|
||||||
public double? ShipLengthFrom { get; set; }
|
public double? ShipLengthFrom { get; set; }
|
||||||
|
|||||||
@ -98,7 +98,7 @@ namespace BreCalClient
|
|||||||
private async void DataGridShips_CreateRequested()
|
private async void DataGridShips_CreateRequested()
|
||||||
{
|
{
|
||||||
|
|
||||||
ShipModel shipModel = new((ShipModel.LastEditShip != null) ? ShipModel.LastEditShip : new Ship());
|
ShipModel shipModel = new(ShipModel.LastEditShip ?? new Ship());
|
||||||
|
|
||||||
EditShipDialog esd = new()
|
EditShipDialog esd = new()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -20,16 +20,15 @@
|
|||||||
<ColumnDefinition Width=".15*" />
|
<ColumnDefinition Width=".15*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="32" />
|
<RowDefinition Height="42" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" >
|
<Grid Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" >
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="32"/>
|
<RowDefinition Height="42"/>
|
||||||
<RowDefinition Height=".125*"/>
|
<RowDefinition Height=".125*"/>
|
||||||
<RowDefinition Height=".125*"/>
|
<RowDefinition Height=".125*"/>
|
||||||
<RowDefinition Height=".125*"/>
|
<RowDefinition Height=".125*"/>
|
||||||
|
|
||||||
<RowDefinition Height=".125*"/>
|
<RowDefinition Height=".125*"/>
|
||||||
<RowDefinition Height=".125*"/>
|
<RowDefinition Height=".125*"/>
|
||||||
<RowDefinition Height=".125*"/>
|
<RowDefinition Height=".125*"/>
|
||||||
@ -64,52 +63,88 @@
|
|||||||
<TextBlock x:Name="textBlockIMO" Padding="0" FontWeight="DemiBold" />
|
<TextBlock x:Name="textBlockIMO" Padding="0" FontWeight="DemiBold" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left">
|
<Viewbox Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left">
|
||||||
<TextBlock Text="{x:Static p:Resources.textCallsign}" />
|
|
||||||
</Viewbox>
|
|
||||||
<Viewbox Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left">
|
|
||||||
<TextBlock x:Name="textBlockCallsign" Padding="0"/>
|
|
||||||
</Viewbox>
|
|
||||||
<Viewbox Grid.Row="3" Grid.Column="0" HorizontalAlignment="Left">
|
|
||||||
<TextBlock Text="{x:Static p:Resources.textLengthWidth}" Padding="0" />
|
<TextBlock Text="{x:Static p:Resources.textLengthWidth}" Padding="0" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left">
|
<Viewbox Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left">
|
||||||
<TextBlock x:Name="textBlockLengthWidth" Padding="0"/>
|
<TextBlock x:Name="textBlockLengthWidth" Padding="0"/>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox Grid.Row="4" Grid.Column="0" HorizontalAlignment="Left">
|
<Viewbox Grid.Row="3" Grid.Column="0" HorizontalAlignment="Left">
|
||||||
<TextBlock Text="{x:Static p:Resources.textDraft}" Padding="0" />
|
<TextBlock Text="{x:Static p:Resources.textDraftNoUnit}" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left">
|
<Viewbox Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left">
|
||||||
<TextBlock x:Name="textBlockDraft" Padding="0"/>
|
<TextBlock x:Name="textBlockDraft" Padding="0"/>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left">
|
<Viewbox Grid.Row="4" Grid.Column="0" HorizontalAlignment="Left">
|
||||||
<TextBlock Text="ETA" x:Name="labelETA"/>
|
<TextBlock Text="ETA" x:Name="labelETA"/>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox Grid.Row="5" Grid.Column="1" HorizontalAlignment="Left">
|
<Viewbox Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left">
|
||||||
<TextBlock x:Name="textBlockETA" Padding="0" FontWeight="DemiBold"/>
|
<TextBlock x:Name="textBlockETA" Padding="0" FontWeight="DemiBold"/>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox Grid.Row="6" Grid.Column="0" HorizontalAlignment="Left">
|
<Viewbox Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left">
|
||||||
<TextBlock Text="{x:Static p:Resources.textBerth}"/>
|
<TextBlock Text="{x:Static p:Resources.textBerth}"/>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox Grid.Row="6" Grid.Column="1" HorizontalAlignment="Left">
|
<Viewbox Grid.Row="5" Grid.Column="1" HorizontalAlignment="Left">
|
||||||
<TextBlock x:Name="textBlockBerth" Padding="0" FontWeight="DemiBold" />
|
<TextBlock x:Name="textBlockBerth" Padding="0" FontWeight="DemiBold" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
|
<Viewbox Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Left">
|
||||||
|
<TextBlock x:Name="textBlockHarbour" Padding="0" FontWeight="DemiBold" />
|
||||||
|
</Viewbox>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid Grid.Row="0" Grid.Column="1">
|
||||||
<Label Grid.Row="0" Grid.Column="1" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="14" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelAgent" PreviewMouseUp="labelAgent_PreviewMouseUp"/>
|
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelAgent" PreviewMouseUp="labelAgent_PreviewMouseUp"/>
|
||||||
<Label Grid.Row="0" Grid.Column="2" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
<Label Name="labelLastChangeAgency" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelMooring" PreviewMouseUp="labelMooring_PreviewMouseUp"/>
|
</Grid>
|
||||||
<Label Grid.Row="0" Grid.Column="3" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
<Grid Grid.Row="0" Grid.Column="2">
|
||||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPortAuthority" PreviewMouseUp="labelPortAuthority_PreviewMouseUp" />
|
<Grid.RowDefinitions>
|
||||||
<Label Grid.Row="0" Grid.Column="4" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
<RowDefinition Height="*" />
|
||||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPilot" PreviewMouseUp="labelPilot_PreviewMouseUp"/>
|
<RowDefinition Height="14" />
|
||||||
<Label Grid.Row="0" Grid.Column="5" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
</Grid.RowDefinitions>
|
||||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTug" PreviewMouseUp="labelTug_PreviewMouseUp"/>
|
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||||
<Label Grid.Row="0" Grid.Column="6" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelMooring" PreviewMouseUp="labelMooring_PreviewMouseUp"/>
|
||||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTerminal" PreviewMouseUp="labelTerminal_PreviewMouseUp" />
|
<Label Name="labelLastChangeMooring" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="0" Grid.Column="3">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="14" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||||
|
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPortAuthority" PreviewMouseUp="labelPortAuthority_PreviewMouseUp"/>
|
||||||
|
<Label Name="labelLastChangePortAuthority" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="0" Grid.Column="4">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="14" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||||
|
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPilot" PreviewMouseUp="labelPilot_PreviewMouseUp"/>
|
||||||
|
<Label Name="labelLastChangePilot" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="0" Grid.Column="5">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="14" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||||
|
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTug" PreviewMouseUp="labelTug_PreviewMouseUp"/>
|
||||||
|
<Label Name="labelLastChangeTug" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="0" Grid.Column="6">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="14" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||||
|
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTerminal" PreviewMouseUp="labelTerminal_PreviewMouseUp"/>
|
||||||
|
<Label Name="labelLastChangeTerminal" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<!-- AGENCY -->
|
<!-- AGENCY -->
|
||||||
<Border Grid.Row="2" Grid.Column="1" BorderThickness="1, 0, 0, 0" BorderBrush="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" Padding="3,0,0,0">
|
<Border Grid.Row="2" Grid.Column="1" BorderThickness="1, 0, 0, 0" BorderBrush="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" Padding="3,0,0,0">
|
||||||
<Grid Grid.Row="2" Grid.Column="1">
|
<Grid Grid.Row="2" Grid.Column="1">
|
||||||
|
|||||||
@ -72,7 +72,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
string agentName = "";
|
string agentName = "";
|
||||||
string? name;
|
string? name;
|
||||||
_agency = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.AGENCY);
|
_agency = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.AGENCY);
|
||||||
name = _agency?.Name;
|
name = _agency?.Name;
|
||||||
if (name != null) agentName = name;
|
if (name != null) agentName = name;
|
||||||
this.labelAgent.Content = name ?? "- / -";
|
this.labelAgent.Content = name ?? "- / -";
|
||||||
@ -82,11 +82,10 @@ namespace BreCalClient
|
|||||||
this.labelAgencyBerth.Content = "";
|
this.labelAgencyBerth.Content = "";
|
||||||
this.labelAgencyETAETDValue.Content = "";
|
this.labelAgencyETAETDValue.Content = "";
|
||||||
this.textBlockAgencyRemarks.Text = "";
|
this.textBlockAgencyRemarks.Text = "";
|
||||||
this.textBlockAgencyBerthRemarks.Text = "";
|
this.textBlockAgencyBerthRemarks.Text = "";
|
||||||
this.textBlockDraft.Text = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_mooring = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.MOORING);
|
_mooring = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.MOORING);
|
||||||
name = _mooring?.Name;
|
name = _mooring?.Name;
|
||||||
this.labelMooring.Content = name ?? "- / -";
|
this.labelMooring.Content = name ?? "- / -";
|
||||||
if(_mooring == null)
|
if(_mooring == null)
|
||||||
@ -95,7 +94,7 @@ namespace BreCalClient
|
|||||||
this.textBlockMooringRemarks.Text = "";
|
this.textBlockMooringRemarks.Text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
_pilot = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.PILOT);
|
_pilot = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.PILOT);
|
||||||
name = _pilot?.Name;
|
name = _pilot?.Name;
|
||||||
this.labelPilot.Content = name ?? "- / - ";
|
this.labelPilot.Content = name ?? "- / - ";
|
||||||
if(_pilot == null)
|
if(_pilot == null)
|
||||||
@ -104,7 +103,7 @@ namespace BreCalClient
|
|||||||
this.textBlockPilotRemarks.Text = "";
|
this.textBlockPilotRemarks.Text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
_tug = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.TUG);
|
_tug = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.TUG);
|
||||||
name = _tug?.Name;
|
name = _tug?.Name;
|
||||||
this.labelTug.Content = name ?? "- / - ";
|
this.labelTug.Content = name ?? "- / - ";
|
||||||
if(_tug == null)
|
if(_tug == null)
|
||||||
@ -113,7 +112,7 @@ namespace BreCalClient
|
|||||||
this.textBlockTugRemarks.Text = "";
|
this.textBlockTugRemarks.Text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
_port_administration = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.PORT_ADMINISTRATION);
|
_port_administration = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.PORT_ADMINISTRATION);
|
||||||
name = _port_administration?.Name;
|
name = _port_administration?.Name;
|
||||||
this.labelPortAuthority.Content = name ?? "- / - ";
|
this.labelPortAuthority.Content = name ?? "- / - ";
|
||||||
if(_port_administration == null)
|
if(_port_administration == null)
|
||||||
@ -122,7 +121,7 @@ namespace BreCalClient
|
|||||||
this.textBlockPortAuthorityRemarks.Text = "";
|
this.textBlockPortAuthorityRemarks.Text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
_terminal = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.TERMINAL);
|
_terminal = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.TERMINAL);
|
||||||
name = _terminal?.Name;
|
name = _terminal?.Name;
|
||||||
this.labelTerminal.Content = name ?? "- / - ";
|
this.labelTerminal.Content = name ?? "- / - ";
|
||||||
if(_terminal == null)
|
if(_terminal == null)
|
||||||
@ -269,22 +268,9 @@ namespace BreCalClient
|
|||||||
else
|
else
|
||||||
this.imageEvaluation.ToolTip = null;
|
this.imageEvaluation.ToolTip = null;
|
||||||
|
|
||||||
//Times? bsmdTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.BSMD);
|
this.textBlockBerth.Text = this.ShipcallControlModel?.GetBerthText(null);
|
||||||
//if (bsmdTimes != null)
|
this.textBlockDraft.Text = (this.ShipcallControlModel?.Shipcall?.Draft != null) ? $"{this.ShipcallControlModel?.Shipcall?.Draft.Value.ToString("N2")} m" : "-";
|
||||||
this.textBlockBerth.Text = this.ShipcallControlModel?.GetBerthText(null);
|
this.textBlockETA.Text = this.ShipcallControlModel?.GetETAETD(true);
|
||||||
//else
|
|
||||||
// this.textBlockBerth.Text = this.ShipcallControlModel?.Berth;
|
|
||||||
|
|
||||||
this.textBlockCallsign.Text = this.ShipcallControlModel?.Ship?.Callsign;
|
|
||||||
if (this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival)
|
|
||||||
{
|
|
||||||
this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Eta?.ToString("dd.MM. HH:mm");
|
|
||||||
}
|
|
||||||
if ((this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Departure) || (this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Shifting))
|
|
||||||
{
|
|
||||||
this.labelETA.Text = "ETD";
|
|
||||||
this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Etd?.ToString("dd.MM. HH:mm");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.textBlockIMO.Text = this.ShipcallControlModel?.Ship?.Imo.ToString();
|
this.textBlockIMO.Text = this.ShipcallControlModel?.Ship?.Imo.ToString();
|
||||||
this.textBlockLengthWidth.Text = $"{this.ShipcallControlModel?.Ship?.Length} / {this.ShipcallControlModel?.Ship?.Width}";
|
this.textBlockLengthWidth.Text = $"{this.ShipcallControlModel?.Ship?.Length} / {this.ShipcallControlModel?.Ship?.Width}";
|
||||||
@ -294,6 +280,7 @@ namespace BreCalClient
|
|||||||
|
|
||||||
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
||||||
{
|
{
|
||||||
|
this.labelETA.Text = "ETD";
|
||||||
this.labelETAETDAgent.Content = "ETD";
|
this.labelETAETDAgent.Content = "ETD";
|
||||||
this.labelETAETDMooring.Content = "ETD";
|
this.labelETAETDMooring.Content = "ETD";
|
||||||
this.labelETAETDPilot.Content = "ETD";
|
this.labelETAETDPilot.Content = "ETD";
|
||||||
@ -315,6 +302,9 @@ namespace BreCalClient
|
|||||||
|
|
||||||
if (this.ShipcallControlModel != null)
|
if (this.ShipcallControlModel != null)
|
||||||
{
|
{
|
||||||
|
this.textBlockHarbour.Text = ((ShipcallControlModel != null) && (ShipcallControlModel.Shipcall != null) && BreCalLists.PortLookupDict.ContainsKey(ShipcallControlModel.Shipcall.PortId)) ?
|
||||||
|
BreCalLists.PortLookupDict[ShipcallControlModel.Shipcall.PortId].Name : "";
|
||||||
|
Extensions.ParticipantType? lastToUpdate = this.ShipcallControlModel?.LastParticipantTypeToUpdate();
|
||||||
|
|
||||||
Times? agencyTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.AGENCY);
|
Times? agencyTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.AGENCY);
|
||||||
if (agencyTimes != null)
|
if (agencyTimes != null)
|
||||||
@ -323,7 +313,19 @@ namespace BreCalClient
|
|||||||
this.labelAgencyETAETDValue.Content = agencyTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
this.labelAgencyETAETDValue.Content = agencyTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
||||||
this.textBlockAgencyRemarks.Text = agencyTimes.Remarks.TruncateDots(50);
|
this.textBlockAgencyRemarks.Text = agencyTimes.Remarks.TruncateDots(50);
|
||||||
this.textBlockAgencyBerthRemarks.Text = agencyTimes.BerthInfo.TruncateDots(50);
|
this.textBlockAgencyBerthRemarks.Text = agencyTimes.BerthInfo.TruncateDots(50);
|
||||||
this.textBlockDraft.Text = ShipcallControlModel?.Shipcall?.Draft?.ToString("N2");
|
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.AGENCY);
|
||||||
|
this.labelLastChangeAgency.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||||
|
Grid.SetRowSpan(this.labelAgent, 1);
|
||||||
|
if(lastToUpdate == Extensions.ParticipantType.AGENCY)
|
||||||
|
{
|
||||||
|
this.labelLastChangeAgency.Foreground = Brushes.White;
|
||||||
|
this.labelLastChangeAgency.FontWeight = FontWeights.DemiBold;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.labelLastChangeAgency.Foreground = Brushes.LightGray;
|
||||||
|
this.labelLastChangeAgency.FontWeight = FontWeights.Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -332,7 +334,7 @@ namespace BreCalClient
|
|||||||
this.labelAgencyETAETDValue.Content = "- / -";
|
this.labelAgencyETAETDValue.Content = "- / -";
|
||||||
this.textBlockAgencyRemarks.Text = "";
|
this.textBlockAgencyRemarks.Text = "";
|
||||||
this.textBlockAgencyBerthRemarks.Text = "";
|
this.textBlockAgencyBerthRemarks.Text = "";
|
||||||
this.textBlockDraft.Text = "";
|
Grid.SetRowSpan(this.labelAgent, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Times? mooringTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.MOORING);
|
Times? mooringTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.MOORING);
|
||||||
@ -356,12 +358,26 @@ namespace BreCalClient
|
|||||||
labelTimesMooringATD.Content = mooringTimes.Atd.Value.ToString("dd.MM.yyyy HH:mm");
|
labelTimesMooringATD.Content = mooringTimes.Atd.Value.ToString("dd.MM.yyyy HH:mm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.MOORING);
|
||||||
|
this.labelLastChangeMooring.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||||
|
Grid.SetRowSpan(this.labelMooring, 1);
|
||||||
|
if (lastToUpdate == Extensions.ParticipantType.MOORING)
|
||||||
|
{
|
||||||
|
this.labelLastChangeMooring.Foreground = Brushes.White;
|
||||||
|
this.labelLastChangeMooring.FontWeight = FontWeights.DemiBold;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.labelLastChangeMooring.Foreground = Brushes.LightGray;
|
||||||
|
this.labelLastChangeMooring.FontWeight = FontWeights.Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.labelMooringETAETDValue.Content = "- / ";
|
this.labelMooringETAETDValue.Content = "- / ";
|
||||||
this.textBlockMooringRemarks.Text = "";
|
this.textBlockMooringRemarks.Text = "";
|
||||||
this.imageMooringLocked.Visibility = Visibility.Hidden;
|
this.imageMooringLocked.Visibility = Visibility.Hidden;
|
||||||
|
Grid.SetRowSpan(this.labelMooring, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Times? portAuthorityTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PORT_ADMINISTRATION);
|
Times? portAuthorityTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PORT_ADMINISTRATION);
|
||||||
@ -375,12 +391,27 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
labelPortAuthorityLockTime.Content = portAuthorityTimes.LockTime.Value.ToString("dd.MM.yyyy HH:mm");
|
labelPortAuthorityLockTime.Content = portAuthorityTimes.LockTime.Value.ToString("dd.MM.yyyy HH:mm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.PORT_ADMINISTRATION);
|
||||||
|
this.labelLastChangePortAuthority.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||||
|
Grid.SetRowSpan(this.labelPortAuthority, 1);
|
||||||
|
if (lastToUpdate == Extensions.ParticipantType.PORT_ADMINISTRATION)
|
||||||
|
{
|
||||||
|
this.labelLastChangePortAuthority.Foreground = Brushes.White;
|
||||||
|
this.labelLastChangePortAuthority.FontWeight = FontWeights.DemiBold;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.labelLastChangePortAuthority.Foreground = Brushes.LightGray;
|
||||||
|
this.labelLastChangePortAuthority.FontWeight = FontWeights.Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.labelPortAuthorityETAETDValue.Content = "- / -";
|
this.labelPortAuthorityETAETDValue.Content = "- / -";
|
||||||
this.textBlockPortAuthorityRemarks.Text = "";
|
this.textBlockPortAuthorityRemarks.Text = "";
|
||||||
this.imagePortAuthorityLocked.Visibility = Visibility.Hidden;
|
this.imagePortAuthorityLocked.Visibility = Visibility.Hidden;
|
||||||
|
Grid.SetRowSpan(this.labelPortAuthority, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Times? pilotTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PILOT);
|
Times? pilotTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PILOT);
|
||||||
@ -389,12 +420,27 @@ namespace BreCalClient
|
|||||||
this.labelPilotETAETDValue.Content = pilotTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
this.labelPilotETAETDValue.Content = pilotTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
||||||
this.textBlockPilotRemarks.Text = pilotTimes.Remarks.TruncateDots(50);
|
this.textBlockPilotRemarks.Text = pilotTimes.Remarks.TruncateDots(50);
|
||||||
this.imagePilotLocked.Visibility = (pilotTimes.EtaBerthFixed ?? false) ? Visibility.Visible : Visibility.Hidden;
|
this.imagePilotLocked.Visibility = (pilotTimes.EtaBerthFixed ?? false) ? Visibility.Visible : Visibility.Hidden;
|
||||||
|
|
||||||
|
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.PILOT);
|
||||||
|
this.labelLastChangePilot.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||||
|
Grid.SetRowSpan(this.labelPilot, 1);
|
||||||
|
if (lastToUpdate == Extensions.ParticipantType.PILOT)
|
||||||
|
{
|
||||||
|
this.labelLastChangePilot.Foreground = Brushes.White;
|
||||||
|
this.labelLastChangePilot.FontWeight = FontWeights.DemiBold;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.labelLastChangePilot.Foreground = Brushes.LightGray;
|
||||||
|
this.labelLastChangePilot.FontWeight = FontWeights.Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.labelPilotETAETDValue.Content = "- / -";
|
this.labelPilotETAETDValue.Content = "- / -";
|
||||||
this.textBlockPilotRemarks.Text = "";
|
this.textBlockPilotRemarks.Text = "";
|
||||||
this.imagePilotLocked.Visibility = Visibility.Hidden;
|
this.imagePilotLocked.Visibility = Visibility.Hidden;
|
||||||
|
Grid.SetRowSpan(this.labelPilot, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Times? tugTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.TUG);
|
Times? tugTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.TUG);
|
||||||
@ -403,12 +449,27 @@ namespace BreCalClient
|
|||||||
this.labelTugETAETDValue.Content = tugTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
this.labelTugETAETDValue.Content = tugTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
||||||
this.textBlockTugRemarks.Text = tugTimes.Remarks.TruncateDots(50);
|
this.textBlockTugRemarks.Text = tugTimes.Remarks.TruncateDots(50);
|
||||||
this.imageTugLocked.Visibility = (tugTimes.EtaBerthFixed ?? false) ? Visibility.Visible : Visibility.Hidden;
|
this.imageTugLocked.Visibility = (tugTimes.EtaBerthFixed ?? false) ? Visibility.Visible : Visibility.Hidden;
|
||||||
|
|
||||||
|
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.TUG);
|
||||||
|
this.labelLastChangeTug.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||||
|
Grid.SetRowSpan(this.labelTug, 1);
|
||||||
|
if (lastToUpdate == Extensions.ParticipantType.TUG)
|
||||||
|
{
|
||||||
|
this.labelLastChangeTug.Foreground = Brushes.White;
|
||||||
|
this.labelLastChangeTug.FontWeight = FontWeights.DemiBold;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.labelLastChangeTug.Foreground = Brushes.LightGray;
|
||||||
|
this.labelLastChangeTug.FontWeight = FontWeights.Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.labelTugETAETDValue.Content = "- / -";
|
this.labelTugETAETDValue.Content = "- / -";
|
||||||
this.textBlockTugRemarks.Text = "";
|
this.textBlockTugRemarks.Text = "";
|
||||||
this.imageTugLocked.Visibility = Visibility.Hidden;
|
this.imageTugLocked.Visibility = Visibility.Hidden;
|
||||||
|
Grid.SetRowSpan(this.labelTug, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rowDefinitionTerminalBerth.Height = (this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival) ? new(14) : new(0);
|
this.rowDefinitionTerminalBerth.Height = (this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival) ? new(14) : new(0);
|
||||||
@ -422,6 +483,19 @@ namespace BreCalClient
|
|||||||
this.labelOperationsStart.Content = terminalTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
this.labelOperationsStart.Content = terminalTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
||||||
this.textBlockTerminalRemarks.Text = terminalTimes.Remarks.TruncateDots(40);
|
this.textBlockTerminalRemarks.Text = terminalTimes.Remarks.TruncateDots(40);
|
||||||
this.textBlockTerminalBerthRemarks.Text = terminalTimes.BerthInfo.TruncateDots(40);
|
this.textBlockTerminalBerthRemarks.Text = terminalTimes.BerthInfo.TruncateDots(40);
|
||||||
|
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.TERMINAL);
|
||||||
|
this.labelLastChangeTerminal.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||||
|
Grid.SetRowSpan(this.labelTerminal, 1);
|
||||||
|
if (lastToUpdate == Extensions.ParticipantType.TERMINAL)
|
||||||
|
{
|
||||||
|
this.labelLastChangeTerminal.Foreground = Brushes.White;
|
||||||
|
this.labelLastChangeTerminal.FontWeight = FontWeights.DemiBold;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.labelLastChangeTerminal.Foreground = Brushes.LightGray;
|
||||||
|
this.labelLastChangeTerminal.FontWeight = FontWeights.Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -429,6 +503,7 @@ namespace BreCalClient
|
|||||||
this.labelOperationsStart.Content = "";
|
this.labelOperationsStart.Content = "";
|
||||||
this.textBlockTerminalRemarks.Text = "";
|
this.textBlockTerminalRemarks.Text = "";
|
||||||
this.textBlockTerminalBerthRemarks.Text = "";
|
this.textBlockTerminalBerthRemarks.Text = "";
|
||||||
|
Grid.SetRowSpan(this.labelTerminal, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,6 +118,8 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AllowPortChange { get; set; } = true;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region public methods
|
#region public methods
|
||||||
@ -217,7 +219,7 @@ namespace BreCalClient
|
|||||||
return berthText;
|
return berthText;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetETAETD()
|
public string GetETAETD(bool useShortVersion = false)
|
||||||
{
|
{
|
||||||
DateTime theDate = DateTime.Now;
|
DateTime theDate = DateTime.Now;
|
||||||
if(this.Shipcall != null)
|
if(this.Shipcall != null)
|
||||||
@ -241,6 +243,8 @@ namespace BreCalClient
|
|||||||
theDate = agentTimes.EtdBerth.Value;
|
theDate = agentTimes.EtdBerth.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(useShortVersion)
|
||||||
|
return theDate.ToString("dd.MM. HH:mm");
|
||||||
return theDate.ToString();
|
return theDate.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,6 +313,42 @@ namespace BreCalClient
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DateTime? GetLastChangeForType(Extensions.ParticipantType type)
|
||||||
|
{
|
||||||
|
DateTime? lastChange = null;
|
||||||
|
Times? times = GetTimesForParticipantType(type);
|
||||||
|
if(times != null)
|
||||||
|
{
|
||||||
|
if (times.Modified.HasValue) lastChange = times.Modified.Value;
|
||||||
|
else lastChange = times.Created;
|
||||||
|
}
|
||||||
|
return lastChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Extensions.ParticipantType? LastParticipantTypeToUpdate()
|
||||||
|
{
|
||||||
|
Extensions.ParticipantType? last = null;
|
||||||
|
DateTime min = DateTime.MinValue;
|
||||||
|
foreach(Times times in this.Times)
|
||||||
|
{
|
||||||
|
if (times.Modified.HasValue)
|
||||||
|
{
|
||||||
|
if (times.Modified.Value > min)
|
||||||
|
{
|
||||||
|
min = times.Modified.Value;
|
||||||
|
last = (Extensions.ParticipantType)times.ParticipantType;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(times.Created > min)
|
||||||
|
{
|
||||||
|
min = times.Created;
|
||||||
|
last = (Extensions.ParticipantType)times.ParticipantType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region helper
|
#region helper
|
||||||
|
|||||||
73
src/BreCalClient/ToastViewModel.cs
Normal file
73
src/BreCalClient/ToastViewModel.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// Copyright (c) 2024- schick Informatik
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
using ToastNotifications;
|
||||||
|
using ToastNotifications.Core;
|
||||||
|
using ToastNotifications.Lifetime;
|
||||||
|
using ToastNotifications.Lifetime.Clear;
|
||||||
|
using ToastNotifications.Messages;
|
||||||
|
using ToastNotifications.Position;
|
||||||
|
|
||||||
|
namespace BreCalClient
|
||||||
|
{
|
||||||
|
internal class ToastViewModel : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private readonly Notifier _notifier;
|
||||||
|
|
||||||
|
public ToastViewModel()
|
||||||
|
{
|
||||||
|
_notifier = new Notifier(cfg =>
|
||||||
|
{
|
||||||
|
cfg.PositionProvider = new WindowPositionProvider(
|
||||||
|
parentWindow: Application.Current.MainWindow,
|
||||||
|
corner: Corner.BottomRight,
|
||||||
|
offsetX: 25,
|
||||||
|
offsetY: 100);
|
||||||
|
|
||||||
|
cfg.LifetimeSupervisor = new TimeAndCountBasedLifetimeSupervisor(
|
||||||
|
notificationLifetime: TimeSpan.FromSeconds(30),
|
||||||
|
maximumNotificationCount: MaximumNotificationCount.FromCount(6));
|
||||||
|
|
||||||
|
cfg.Dispatcher = Application.Current.Dispatcher;
|
||||||
|
|
||||||
|
cfg.DisplayOptions.TopMost = false;
|
||||||
|
cfg.DisplayOptions.Width = 250;
|
||||||
|
});
|
||||||
|
|
||||||
|
_notifier.ClearMessages(new ClearAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUnloaded()
|
||||||
|
{
|
||||||
|
_notifier.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowAppNotification(string message, MessageOptions options)
|
||||||
|
{
|
||||||
|
_notifier?.ShowAppNotification(message, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowAppNotification(string message)
|
||||||
|
{
|
||||||
|
_notifier?.ShowAppNotification(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
|
protected virtual void OnPropertyChanged(string? propertyName = null)
|
||||||
|
{
|
||||||
|
var handler = PropertyChanged;
|
||||||
|
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearAll()
|
||||||
|
{
|
||||||
|
_notifier.ClearMessages(new ClearAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@
|
|||||||
<applicationSettings>
|
<applicationSettings>
|
||||||
<RoleEditor.Properties.Settings>
|
<RoleEditor.Properties.Settings>
|
||||||
<setting name="ConnectionString" serializeAs="String">
|
<setting name="ConnectionString" serializeAs="String">
|
||||||
<value>Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling_test;Port=33306</value>
|
<value>Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling_test;Port=33307</value>
|
||||||
</setting>
|
</setting>
|
||||||
</RoleEditor.Properties.Settings>
|
</RoleEditor.Properties.Settings>
|
||||||
</applicationSettings>
|
</applicationSettings>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:RoleEditor"
|
xmlns:local="clr-namespace:RoleEditor"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Edit berth" Height="188" Width="450" Loaded="Window_Loaded">
|
Title="Edit berth" Height="216" Width="450" Loaded="Window_Loaded">
|
||||||
<Grid x:Name="berthGrid">
|
<Grid x:Name="berthGrid">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width=".3*" />
|
<ColumnDefinition Width=".3*" />
|
||||||
@ -16,6 +16,7 @@
|
|||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
@ -45,7 +46,9 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Label Content="Uses lock" HorizontalAlignment="Right" Grid.Row="3" />
|
<Label Content="Uses lock" HorizontalAlignment="Right" Grid.Row="3" />
|
||||||
<CheckBox x:Name="checkBoxLock" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" Margin="2" IsChecked="{Binding Path=Lock, Mode=OneWay}"/>
|
<CheckBox x:Name="checkBoxLock" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" Margin="2" IsChecked="{Binding Path=Lock, Mode=OneWay}"/>
|
||||||
<StackPanel Grid.Column="1" Grid.Row="5" Orientation="Horizontal" FlowDirection="RightToLeft">
|
<Label Content="Port" HorizontalAlignment="Right" Grid.Row="4" />
|
||||||
|
<ComboBox Name="comboBoxPorts" Margin="2" Grid.Column="1" Grid.Row="4" SelectedItem="{Binding Port, Mode=OneWay}" />
|
||||||
|
<StackPanel Grid.Column="1" Grid.Row="6" Orientation="Horizontal" FlowDirection="RightToLeft">
|
||||||
<Button x:Name="buttonCancel" Width="80" Content="Cancel" Margin="2" Click="buttonCancel_Click" />
|
<Button x:Name="buttonCancel" Width="80" Content="Cancel" Margin="2" Click="buttonCancel_Click" />
|
||||||
<Button x:Name="buttonOK" Width="80" Content="OK" Margin="2" Click="buttonOK_Click"/>
|
<Button x:Name="buttonOK" Width="80" Content="OK" Margin="2" Click="buttonOK_Click"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@ -20,6 +20,8 @@ namespace RoleEditor
|
|||||||
|
|
||||||
public List<Participant> Authorities { get; } = new List<Participant>();
|
public List<Participant> Authorities { get; } = new List<Participant>();
|
||||||
|
|
||||||
|
public List<Port> Ports { get; } = new List<Port>();
|
||||||
|
|
||||||
private void buttonCancel_Click(object sender, RoutedEventArgs e)
|
private void buttonCancel_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.DialogResult = false;
|
this.DialogResult = false;
|
||||||
@ -43,6 +45,12 @@ namespace RoleEditor
|
|||||||
else
|
else
|
||||||
this.Berth.Authority_Id = null;
|
this.Berth.Authority_Id = null;
|
||||||
|
|
||||||
|
this.Berth.Port = this.comboBoxPorts.SelectedItem as Port;
|
||||||
|
if (this.Berth.Port != null)
|
||||||
|
this.Berth.Port_Id = this.Berth.Port.Id;
|
||||||
|
else
|
||||||
|
this.Berth.Port_Id = null;
|
||||||
|
|
||||||
this.DialogResult = true;
|
this.DialogResult = true;
|
||||||
this.Close();
|
this.Close();
|
||||||
}
|
}
|
||||||
@ -52,6 +60,7 @@ namespace RoleEditor
|
|||||||
this.DataContext = this.Berth;
|
this.DataContext = this.Berth;
|
||||||
this.comboBoxParticipants.ItemsSource = this.Owners;
|
this.comboBoxParticipants.ItemsSource = this.Owners;
|
||||||
this.comboBoxAuthorities.ItemsSource = this.Authorities;
|
this.comboBoxAuthorities.ItemsSource = this.Authorities;
|
||||||
|
this.comboBoxPorts.ItemsSource = this.Ports;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buttonResetParticipant_Click(object sender, RoutedEventArgs e)
|
private void buttonResetParticipant_Click(object sender, RoutedEventArgs e)
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
xmlns:local="clr-namespace:RoleEditor"
|
xmlns:local="clr-namespace:RoleEditor"
|
||||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Bremen calling admin editor" Height="670" Width="800" Icon="Resources/lock_preferences.ico" Loaded="Window_Loaded">
|
Title="Bremen calling admin editor" Height="670" Width="1024" Icon="Resources/lock_preferences.ico" Loaded="Window_Loaded">
|
||||||
<Grid>
|
<Grid>
|
||||||
<TabControl>
|
<TabControl>
|
||||||
<TabItem Header="Participant, users and roles">
|
<TabItem Header="Participant, users and roles">
|
||||||
@ -16,8 +16,9 @@
|
|||||||
<RowDefinition Height=".5*" />
|
<RowDefinition Height=".5*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width=".5*" />
|
<ColumnDefinition Width=".4*" />
|
||||||
<ColumnDefinition Width=".5*" />
|
<ColumnDefinition Width=".3*" />
|
||||||
|
<ColumnDefinition Width=".3*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<GroupBox Header="Participant" Margin="2">
|
<GroupBox Header="Participant" Margin="2">
|
||||||
<Grid>
|
<Grid>
|
||||||
@ -58,7 +59,7 @@
|
|||||||
<Label Content="Street" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right"/>
|
<Label Content="Street" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right"/>
|
||||||
<Label Content="Postal code" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Right"/>
|
<Label Content="Postal code" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Right"/>
|
||||||
<Label Content="City" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Right"/>
|
<Label Content="City" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Right"/>
|
||||||
<Label Content="Active" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right"/>
|
<Label Content="Deleted" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right"/>
|
||||||
<Label Content="Type" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Right"/>
|
<Label Content="Type" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Right"/>
|
||||||
<Label Content="Created" Grid.Row="6" Grid.Column="1" HorizontalAlignment="Right"/>
|
<Label Content="Created" Grid.Row="6" Grid.Column="1" HorizontalAlignment="Right"/>
|
||||||
<Label Content="Modified" Grid.Row="7" Grid.Column="1" HorizontalAlignment="Right"/>
|
<Label Content="Modified" Grid.Row="7" Grid.Column="1" HorizontalAlignment="Right"/>
|
||||||
@ -66,7 +67,7 @@
|
|||||||
<TextBox x:Name="textBoxParticipantStreet" Grid.Row="1" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
|
<TextBox x:Name="textBoxParticipantStreet" Grid.Row="1" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
|
||||||
<TextBox x:Name="textBoxParticipantPostalCode" Grid.Row="2" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
|
<TextBox x:Name="textBoxParticipantPostalCode" Grid.Row="2" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
|
||||||
<TextBox x:Name="textBoxParticipantCity" Grid.Row="3" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
|
<TextBox x:Name="textBoxParticipantCity" Grid.Row="3" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
|
||||||
<CheckBox x:Name="checkboxParticipantActive" Grid.Row="4" Grid.Column="2" VerticalAlignment="Center" />
|
<CheckBox x:Name="checkboxParticipantDeleted" Grid.Row="4" Grid.Column="2" VerticalAlignment="Center" IsEnabled="False" />
|
||||||
<xctk:CheckComboBox x:Name="comboBoxParticipantType" Grid.Row="5" Grid.Column="2" Margin="2" SelectedValue="Key" DisplayMemberPath="Value" />
|
<xctk:CheckComboBox x:Name="comboBoxParticipantType" Grid.Row="5" Grid.Column="2" Margin="2" SelectedValue="Key" DisplayMemberPath="Value" />
|
||||||
<TextBox x:Name="textBoxParticipantCreated" Grid.Row="6" IsReadOnly="True" IsEnabled="False" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
|
<TextBox x:Name="textBoxParticipantCreated" Grid.Row="6" IsReadOnly="True" IsEnabled="False" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
|
||||||
<StackPanel Orientation="Horizontal" Grid.Row="7" Grid.Column="0">
|
<StackPanel Orientation="Horizontal" Grid.Row="7" Grid.Column="0">
|
||||||
@ -82,6 +83,69 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
<GroupBox Header="Port Assignment" Margin="2" Grid.Row="0" Grid.Column="1">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="60" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ListBox x:Name="listBoxPortAssignment" Margin="2" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" />
|
||||||
|
<Button x:Name="buttonAddPortAssignment" Margin="2" Grid.Row="0" Grid.Column="1" Click="buttonAddPortAssignment_Click">
|
||||||
|
<Image Source="./Resources/arrow_left_green.png"/>
|
||||||
|
</Button>
|
||||||
|
<Button x:Name="buttonRemovePortAssignment" Margin="2" Grid.Row="1" Grid.Column="1" Click="buttonRemovePortAssignment_Click">
|
||||||
|
<Image Source="./Resources/delete2.png"/>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
|
<GroupBox Header="Ports" Margin="2" Grid.Row="0" Grid.Column="2">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="28"/>
|
||||||
|
<RowDefinition Height="28"/>
|
||||||
|
<RowDefinition Height="28"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="160" />
|
||||||
|
<ColumnDefinition Width=".38*" />
|
||||||
|
<ColumnDefinition Width=".62*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ListBox x:Name="listBoxPort" Margin="2" Grid.RowSpan="4" SelectionChanged="listBoxPort_SelectionChanged">
|
||||||
|
<ListBox.ContextMenu>
|
||||||
|
<ContextMenu>
|
||||||
|
<MenuItem x:Name="menuItemNewPort" Header="New.." Click="menuItemNewPort_Click">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<Image Source="Resources/add.png" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem x:Name="menuItemDeletePort" Header="Delete" Click="menuItemDeletePort_Click">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<Image Source="Resources/delete2.png" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
</ContextMenu>
|
||||||
|
</ListBox.ContextMenu>
|
||||||
|
</ListBox>
|
||||||
|
<Label Grid.Row="0" Grid.Column="1" Content="Name" HorizontalAlignment="Right"/>
|
||||||
|
<Label Grid.Row="1" Grid.Column="1" Content="Locode" HorizontalAlignment="Right"/>
|
||||||
|
<TextBox x:Name="textBoxPortName" Grid.Row="0" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" MaxLength="128"/>
|
||||||
|
<TextBox x:Name="textBoxPortLocode" Grid.Row="1" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" MaxLength="5" />
|
||||||
|
|
||||||
|
<Button x:Name="buttonPortSave" Grid.Row="2" Grid.Column="2" Click="buttonPortSave_Click" Margin="2">
|
||||||
|
<DockPanel>
|
||||||
|
<Image Source="./Resources/disk_blue.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="16"/>
|
||||||
|
<TextBlock Text="Save" VerticalAlignment="Center" DockPanel.Dock="Right"/>
|
||||||
|
</DockPanel>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</GroupBox>
|
||||||
<GroupBox Header="User" Margin="2" Grid.Row="1">
|
<GroupBox Header="User" Margin="2" Grid.Row="1">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
@ -103,7 +167,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<ListBox x:Name="listBoxUser" Margin="2" Grid.RowSpan="9" SelectionChanged="listBoxUser_SelectionChanged">
|
<ListBox x:Name="listBoxUser" Margin="2" Grid.RowSpan="9" SelectionChanged="listBoxUser_SelectionChanged">
|
||||||
<ListBox.ContextMenu>
|
<ListBox.ContextMenu>
|
||||||
<ContextMenu>
|
<ContextMenu Name="contextMenuUser">
|
||||||
<MenuItem x:Name="menuItemNewUser" Header="New.." Click="menuItemNewUser_Click">
|
<MenuItem x:Name="menuItemNewUser" Header="New.." Click="menuItemNewUser_Click">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Image Source="Resources/add.png" />
|
<Image Source="Resources/add.png" />
|
||||||
@ -145,7 +209,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
<GroupBox Header="Role" Margin="2" Grid.Column="1">
|
<GroupBox Header="Role" Margin="2" Grid.Column="1" Grid.Row="1">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="28"/>
|
<RowDefinition Height="28"/>
|
||||||
@ -199,7 +263,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
<GroupBox Header="Securable" Margin="2" Grid.Row="1" Grid.Column="1">
|
<GroupBox Header="Securable" Margin="2" Grid.Row="1" Grid.Column="2">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="28"/>
|
<RowDefinition Height="28"/>
|
||||||
@ -276,6 +340,7 @@
|
|||||||
<DataGridCheckBoxColumn Header="Lock" Binding="{Binding Path=Lock}" IsReadOnly="True"/>
|
<DataGridCheckBoxColumn Header="Lock" Binding="{Binding Path=Lock}" IsReadOnly="True"/>
|
||||||
<DataGridTextColumn Header="Terminal" Binding="{Binding Path=Terminal, Mode=OneWay}" IsReadOnly="True"/>
|
<DataGridTextColumn Header="Terminal" Binding="{Binding Path=Terminal, Mode=OneWay}" IsReadOnly="True"/>
|
||||||
<DataGridTextColumn Header="Authority" Binding="{Binding Path=Authority_Text, Mode=OneWay}" IsReadOnly="True" />
|
<DataGridTextColumn Header="Authority" Binding="{Binding Path=Authority_Text, Mode=OneWay}" IsReadOnly="True" />
|
||||||
|
<DataGridTextColumn Header="Port" Binding="{Binding Path=Port}" IsReadOnly="True" />
|
||||||
<DataGridTextColumn Header="Deleted" Binding="{Binding Path=Deleted, Mode=OneWay}" IsReadOnly="True" />
|
<DataGridTextColumn Header="Deleted" Binding="{Binding Path=Deleted, Mode=OneWay}" IsReadOnly="True" />
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</local:ENIDataGrid>
|
</local:ENIDataGrid>
|
||||||
|
|||||||
@ -38,6 +38,8 @@ namespace RoleEditor
|
|||||||
private readonly ObservableCollection<SecurableAssignment> _assignedSecurables = new ObservableCollection<SecurableAssignment>();
|
private readonly ObservableCollection<SecurableAssignment> _assignedSecurables = new ObservableCollection<SecurableAssignment>();
|
||||||
private readonly ObservableCollection<Berth> _berths = new ObservableCollection<Berth>();
|
private readonly ObservableCollection<Berth> _berths = new ObservableCollection<Berth>();
|
||||||
private readonly ObservableCollection<Ship> _ships = new ObservableCollection<Ship>();
|
private readonly ObservableCollection<Ship> _ships = new ObservableCollection<Ship>();
|
||||||
|
private readonly ObservableCollection<Port> _ports = new ObservableCollection<Port>();
|
||||||
|
private readonly ObservableCollection<PortAssignment> _assignedPorts = new ObservableCollection<PortAssignment>();
|
||||||
private DBManager _dbManager;
|
private DBManager _dbManager;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -59,6 +61,8 @@ namespace RoleEditor
|
|||||||
|
|
||||||
// load all participants
|
// load all participants
|
||||||
List<Participant> participants = await Participant.LoadAll(_dbManager);
|
List<Participant> participants = await Participant.LoadAll(_dbManager);
|
||||||
|
participants.Sort((x, y) => string.Compare(x.Name, y.Name));
|
||||||
|
|
||||||
foreach (Participant p in participants)
|
foreach (Participant p in participants)
|
||||||
{
|
{
|
||||||
_participants.Add(p);
|
_participants.Add(p);
|
||||||
@ -77,6 +81,10 @@ namespace RoleEditor
|
|||||||
_securables.Add(s);
|
_securables.Add(s);
|
||||||
this.listBoxSecurables.ItemsSource = _securables;
|
this.listBoxSecurables.ItemsSource = _securables;
|
||||||
|
|
||||||
|
// load all ports
|
||||||
|
foreach (Port port in await Port.LoadAll(_dbManager)) _ports.Add(port);
|
||||||
|
this.listBoxPort.ItemsSource = _ports;
|
||||||
|
|
||||||
// load all berths
|
// load all berths
|
||||||
foreach (Berth b in await Berth.LoadAll(_dbManager))
|
foreach (Berth b in await Berth.LoadAll(_dbManager))
|
||||||
{
|
{
|
||||||
@ -89,6 +97,10 @@ namespace RoleEditor
|
|||||||
{
|
{
|
||||||
b.Authority = participants.Where(p => p.Id == b.Authority_Id).FirstOrDefault();
|
b.Authority = participants.Where(p => p.Id == b.Authority_Id).FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
if (b.Port_Id != null)
|
||||||
|
{
|
||||||
|
b.Port = _ports.Where(p => p.Id == b.Port_Id).FirstOrDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.dataGridBerths.Initialize();
|
this.dataGridBerths.Initialize();
|
||||||
this.dataGridBerths.ItemsSource = _berths;
|
this.dataGridBerths.ItemsSource = _berths;
|
||||||
@ -112,12 +124,14 @@ namespace RoleEditor
|
|||||||
|
|
||||||
this.dataGridShips.CreateRequested += DataGridShips_CreateRequested;
|
this.dataGridShips.CreateRequested += DataGridShips_CreateRequested;
|
||||||
this.dataGridShips.EditRequested += DataGridShips_EditRequested;
|
this.dataGridShips.EditRequested += DataGridShips_EditRequested;
|
||||||
this.dataGridShips.DeleteRequested += DataGridShips_DeleteRequested;
|
this.dataGridShips.DeleteRequested += DataGridShips_DeleteRequested;
|
||||||
|
|
||||||
|
|
||||||
// set other item sources (filled later after selection)
|
// set other item sources (filled later after selection)
|
||||||
this.listBoxUser.ItemsSource = _users;
|
this.listBoxUser.ItemsSource = _users;
|
||||||
this.listBoxRoleSecurables.ItemsSource = _assignedSecurables;
|
this.listBoxRoleSecurables.ItemsSource = _assignedSecurables;
|
||||||
this.listBoxUserRoles.ItemsSource = _assignedRoles;
|
this.listBoxUserRoles.ItemsSource = _assignedRoles;
|
||||||
|
this.listBoxPortAssignment.ItemsSource = _assignedPorts;
|
||||||
|
|
||||||
this.comboBoxParticipantType.ItemsSource = EnumHelper.GetAllValuesAndDescription(typeof(Participant.ParticipantType));
|
this.comboBoxParticipantType.ItemsSource = EnumHelper.GetAllValuesAndDescription(typeof(Participant.ParticipantType));
|
||||||
|
|
||||||
@ -192,6 +206,7 @@ namespace RoleEditor
|
|||||||
ebd.Berth = b;
|
ebd.Berth = b;
|
||||||
ebd.Owners.AddRange(this._terminals);
|
ebd.Owners.AddRange(this._terminals);
|
||||||
ebd.Authorities.AddRange(this._authorities);
|
ebd.Authorities.AddRange(this._authorities);
|
||||||
|
ebd.Ports.AddRange(this._ports.Where(p => !p.IsDeleted));
|
||||||
if (ebd.ShowDialog() ?? false)
|
if (ebd.ShowDialog() ?? false)
|
||||||
{
|
{
|
||||||
await b.Save(_dbManager);
|
await b.Save(_dbManager);
|
||||||
@ -208,6 +223,7 @@ namespace RoleEditor
|
|||||||
ebd.Berth = b;
|
ebd.Berth = b;
|
||||||
ebd.Owners.AddRange(this._terminals);
|
ebd.Owners.AddRange(this._terminals);
|
||||||
ebd.Authorities.AddRange(this._authorities);
|
ebd.Authorities.AddRange(this._authorities);
|
||||||
|
ebd.Ports.AddRange(_ports.Where(p => !p.IsDeleted));
|
||||||
if (ebd.ShowDialog() ?? false)
|
if (ebd.ShowDialog() ?? false)
|
||||||
{
|
{
|
||||||
_berths.Add(b);
|
_berths.Add(b);
|
||||||
@ -386,6 +402,59 @@ namespace RoleEditor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void buttonPortSave_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Port? p = this.listBoxPort.SelectedItem as Port;
|
||||||
|
if (p != null)
|
||||||
|
{
|
||||||
|
p.Name = this.textBoxPortName.Text.Trim();
|
||||||
|
p.Locode = this.textBoxPortLocode.Text.Trim();
|
||||||
|
await p.Save(_dbManager);
|
||||||
|
this.listBoxPort.ItemsSource = null;
|
||||||
|
this.listBoxPort.ItemsSource = _ports;
|
||||||
|
this.listBoxPort.SelectedItem = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void buttonAddPortAssignment_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if ((this.listBoxPort.SelectedItem is Port p) && (this.listBoxParticipant.SelectedItem is Participant pa))
|
||||||
|
{
|
||||||
|
// test if assignment is already present
|
||||||
|
bool foundMatchingAssignment = false;
|
||||||
|
foreach (PortAssignment portAssignment in _assignedPorts)
|
||||||
|
{
|
||||||
|
if ((portAssignment.PortId == p.Id) && (portAssignment.ParticipantId == pa.Id))
|
||||||
|
{
|
||||||
|
foundMatchingAssignment = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundMatchingAssignment)
|
||||||
|
{
|
||||||
|
PortAssignment portAssignment = new PortAssignment();
|
||||||
|
portAssignment.PortId = (int)p.Id;
|
||||||
|
portAssignment.ParticipantId = (int)pa.Id;
|
||||||
|
portAssignment.AssignedParticipant = pa;
|
||||||
|
portAssignment.AssignedPort = p;
|
||||||
|
await portAssignment.Save(_dbManager);
|
||||||
|
_assignedPorts.Add(portAssignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void buttonRemovePortAssignment_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
PortAssignment? pa = this.listBoxPortAssignment.SelectedItem as PortAssignment;
|
||||||
|
if (pa != null)
|
||||||
|
{
|
||||||
|
await pa.Delete(_dbManager);
|
||||||
|
if (_assignedPorts.Contains(pa))
|
||||||
|
_assignedPorts.Remove(pa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region listbox selection callbacks
|
#region listbox selection callbacks
|
||||||
@ -397,9 +466,9 @@ namespace RoleEditor
|
|||||||
this.textBoxParticipantName.Text = (p != null) ? p.Name : string.Empty;
|
this.textBoxParticipantName.Text = (p != null) ? p.Name : string.Empty;
|
||||||
this.textBoxParticipantStreet.Text = (p != null) ? p.Street : string.Empty;
|
this.textBoxParticipantStreet.Text = (p != null) ? p.Street : string.Empty;
|
||||||
this.textBoxParticipantPostalCode.Text = (p != null) ? p.PostalCode : string.Empty;
|
this.textBoxParticipantPostalCode.Text = (p != null) ? p.PostalCode : string.Empty;
|
||||||
this.textBoxParticipantCity.Text = (p != null) ? p.City : string.Empty;
|
this.textBoxParticipantCity.Text = (p != null) ? p.City : string.Empty;
|
||||||
// this.checkboxParticipantActive.Checked = (p != null) ? p.
|
|
||||||
this.textBoxParticipantCreated.Text = (p != null) ? p.Created.ToString() : string.Empty;
|
this.textBoxParticipantCreated.Text = (p != null) ? p.Created.ToString() : string.Empty;
|
||||||
|
this.checkboxParticipantDeleted.IsChecked = (p != null) ? p.Deleted : null;
|
||||||
this.textBoxParticipantModified.Text = (p != null) ? p.Modified.ToString() : string.Empty;
|
this.textBoxParticipantModified.Text = (p != null) ? p.Modified.ToString() : string.Empty;
|
||||||
this.checkBoxParticipantAllowBSMD.IsChecked = (p != null) ? p.IsFlagSet(Participant.ParticipantFlags.ALLOW_BSMD) : null;
|
this.checkBoxParticipantAllowBSMD.IsChecked = (p != null) ? p.IsFlagSet(Participant.ParticipantFlags.ALLOW_BSMD) : null;
|
||||||
this.comboBoxParticipantType.SelectedItems.Clear();
|
this.comboBoxParticipantType.SelectedItems.Clear();
|
||||||
@ -430,6 +499,24 @@ namespace RoleEditor
|
|||||||
foreach (User u in await User.LoadForParticipant(p, _dbManager))
|
foreach (User u in await User.LoadForParticipant(p, _dbManager))
|
||||||
_users.Add(u);
|
_users.Add(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -> load port assignments for this participant selection
|
||||||
|
this._assignedPorts.Clear();
|
||||||
|
if(p != null)
|
||||||
|
{
|
||||||
|
foreach (PortAssignment pa in await PortAssignment.LoadForParticipant(p, this._dbManager))
|
||||||
|
{
|
||||||
|
foreach (Port port in this._ports)
|
||||||
|
if (pa.PortId == port.Id)
|
||||||
|
pa.AssignedPort = port;
|
||||||
|
_assignedPorts.Add(pa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.contextMenuUser.IsEnabled = !p.Deleted;
|
||||||
|
this.buttonAddPortAssignment.IsEnabled = !p.Deleted;
|
||||||
|
this.buttonRemovePortAssignment.IsEnabled = !p.Deleted;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void listBoxRoles_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private async void listBoxRoles_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
@ -496,6 +583,13 @@ namespace RoleEditor
|
|||||||
this.textBoxSecurableName.Text = (s != null) ? s.Name : string.Empty;
|
this.textBoxSecurableName.Text = (s != null) ? s.Name : string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void listBoxPort_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
Port? p = this.listBoxPort.SelectedItem as Port;
|
||||||
|
this.textBoxPortName.Text = (p != null) ? p.Name : string.Empty;
|
||||||
|
this.textBoxPortLocode.Text = (p != null) ? p.Locode : string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region menuitem callbacks
|
#region menuitem callbacks
|
||||||
@ -507,7 +601,7 @@ namespace RoleEditor
|
|||||||
if(this.listBoxParticipant.SelectedItem is Participant p)
|
if(this.listBoxParticipant.SelectedItem is Participant p)
|
||||||
{
|
{
|
||||||
await p.Delete(_dbManager);
|
await p.Delete(_dbManager);
|
||||||
this._participants.Remove(p);
|
p.Deleted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -541,6 +635,7 @@ namespace RoleEditor
|
|||||||
{
|
{
|
||||||
if (this.listBoxUser.SelectedItem is User u)
|
if (this.listBoxUser.SelectedItem is User u)
|
||||||
{
|
{
|
||||||
|
await u.ExecuteNonQuery(_dbManager); // extra history delete happens here
|
||||||
await u.Delete(_dbManager);
|
await u.Delete(_dbManager);
|
||||||
this._users.Remove(u);
|
this._users.Remove(u);
|
||||||
}
|
}
|
||||||
@ -597,6 +692,29 @@ namespace RoleEditor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void menuItemNewPort_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Port p = new();
|
||||||
|
this._ports.Add(p);
|
||||||
|
this.listBoxPort.SelectedItem = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void menuItemDeletePort_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (this.listBoxPort.SelectedItem is Port p)
|
||||||
|
{
|
||||||
|
await p.Delete(_dbManager);
|
||||||
|
this._ports.Remove(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Excel import
|
#region Excel import
|
||||||
@ -634,7 +752,7 @@ namespace RoleEditor
|
|||||||
{
|
{
|
||||||
if (reader.FieldCount < 2)
|
if (reader.FieldCount < 2)
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("Sheet must have at least 2 Columns of data");
|
throw new InvalidDataException("Sheet must have at least 3 Columns of data");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reader.IsDBNull(0) && reader.IsDBNull(1)) continue;
|
if (reader.IsDBNull(0) && reader.IsDBNull(1)) continue;
|
||||||
@ -649,8 +767,20 @@ namespace RoleEditor
|
|||||||
if (_berths.Any(predicate: x => (x.Name != null) && x.Name.Equals(berth_name, StringComparison.OrdinalIgnoreCase)))
|
if (_berths.Any(predicate: x => (x.Name != null) && x.Name.Equals(berth_name, StringComparison.OrdinalIgnoreCase)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
string port_name = "";
|
||||||
|
if (!reader.IsDBNull(2)) port_name = reader.GetString(2);
|
||||||
|
|
||||||
|
// find port in list
|
||||||
|
if(!_ports.Any(x => (x.Name != null) && x.Name.Equals(port_name, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Port port = _ports.First(x => (x.Name != null) && x.Name.Equals(port_name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
Berth b = new Berth();
|
Berth b = new Berth();
|
||||||
b.Name = berth_name;
|
b.Name = berth_name;
|
||||||
|
b.Port = port;
|
||||||
|
b.Port_Id = port.Id;
|
||||||
|
|
||||||
bool found_participant = false;
|
bool found_participant = false;
|
||||||
|
|
||||||
foreach(Participant p in this._participants)
|
foreach(Participant p in this._participants)
|
||||||
@ -801,6 +931,6 @@ namespace RoleEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/RoleEditor/Properties/Settings.Designer.cs
generated
16
src/RoleEditor/Properties/Settings.Designer.cs
generated
@ -9,24 +9,24 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace RoleEditor.Properties {
|
namespace RoleEditor.Properties {
|
||||||
|
|
||||||
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.10.0.0")]
|
||||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
public static Settings Default {
|
public static Settings Default {
|
||||||
get {
|
get {
|
||||||
return defaultInstance;
|
return defaultInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Configuration.DefaultSettingValueAttribute("Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling;" +
|
[global::System.Configuration.DefaultSettingValueAttribute("Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling_" +
|
||||||
"Port=33306")]
|
"test;Port=33306")]
|
||||||
public string ConnectionString {
|
public string ConnectionString {
|
||||||
get {
|
get {
|
||||||
return ((string)(this["ConnectionString"]));
|
return ((string)(this["ConnectionString"]));
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<Profiles />
|
<Profiles />
|
||||||
<Settings>
|
<Settings>
|
||||||
<Setting Name="ConnectionString" Type="System.String" Scope="Application">
|
<Setting Name="ConnectionString" Type="System.String" Scope="Application">
|
||||||
<Value Profile="(Default)">Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling;Port=33306</Value>
|
<Value Profile="(Default)">Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling_test;Port=33306</Value>
|
||||||
</Setting>
|
</Setting>
|
||||||
</Settings>
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
||||||
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<ApplicationIcon>Resources\lock_preferences.ico</ApplicationIcon>
|
<ApplicationIcon>Resources\lock_preferences.ico</ApplicationIcon>
|
||||||
|
<FileVersion>1.8.0.0</FileVersion>
|
||||||
|
<AssemblyVersion>1.8.0.0</AssemblyVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -28,8 +30,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
<PackageReference Include="ExcelDataReader" Version="3.7.0-develop00385" />
|
<PackageReference Include="ExcelDataReader" Version="3.8.0" />
|
||||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.0" />
|
<PackageReference Include="Extended.Wpf.Toolkit" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -13,6 +13,12 @@
|
|||||||
"SccProvider" = "8:"
|
"SccProvider" = "8:"
|
||||||
"Hierarchy"
|
"Hierarchy"
|
||||||
{
|
{
|
||||||
|
"Entry"
|
||||||
|
{
|
||||||
|
"MsmKey" = "8:_1E7663DCE02A4D848349229A724E961A"
|
||||||
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
}
|
||||||
"Entry"
|
"Entry"
|
||||||
{
|
{
|
||||||
"MsmKey" = "8:_3E48B6E716164CC1826E094025517B3F"
|
"MsmKey" = "8:_3E48B6E716164CC1826E094025517B3F"
|
||||||
@ -25,6 +31,24 @@
|
|||||||
"OwnerKey" = "8:_UNDEFINED"
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
"MsmSig" = "8:_UNDEFINED"
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
}
|
}
|
||||||
|
"Entry"
|
||||||
|
{
|
||||||
|
"MsmKey" = "8:_CD20A468610C42B89F66B4D3367A5A6A"
|
||||||
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
}
|
||||||
|
"Entry"
|
||||||
|
{
|
||||||
|
"MsmKey" = "8:_UNDEFINED"
|
||||||
|
"OwnerKey" = "8:_CD20A468610C42B89F66B4D3367A5A6A"
|
||||||
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
}
|
||||||
|
"Entry"
|
||||||
|
{
|
||||||
|
"MsmKey" = "8:_UNDEFINED"
|
||||||
|
"OwnerKey" = "8:_1E7663DCE02A4D848349229A724E961A"
|
||||||
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"Configurations"
|
"Configurations"
|
||||||
{
|
{
|
||||||
@ -76,6 +100,14 @@
|
|||||||
{
|
{
|
||||||
"LaunchCondition"
|
"LaunchCondition"
|
||||||
{
|
{
|
||||||
|
"{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_3415D375792A4611BF998D78F56CD22C"
|
||||||
|
{
|
||||||
|
"Name" = "8:.NET Framework"
|
||||||
|
"Message" = "8:[VSDNETMSG]"
|
||||||
|
"FrameworkVersion" = "8:.NETFramework,Version=v4.7.2"
|
||||||
|
"AllowLaterVersions" = "11:FALSE"
|
||||||
|
"InstallUrl" = "8:http://go.microsoft.com/fwlink/?LinkId=863262"
|
||||||
|
}
|
||||||
"{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_7C5ED856EDF94532A041DBACD5D5C09E"
|
"{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_7C5ED856EDF94532A041DBACD5D5C09E"
|
||||||
{
|
{
|
||||||
"Name" = "8:.NET Core"
|
"Name" = "8:.NET Core"
|
||||||
@ -90,6 +122,37 @@
|
|||||||
}
|
}
|
||||||
"File"
|
"File"
|
||||||
{
|
{
|
||||||
|
"{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_1E7663DCE02A4D848349229A724E961A"
|
||||||
|
{
|
||||||
|
"AssemblyRegister" = "3:1"
|
||||||
|
"AssemblyIsInGAC" = "11:FALSE"
|
||||||
|
"AssemblyAsmDisplayName" = "8:Xceed.Wpf.AvalonDock.resources, Version=4.6.0.0, Culture=de, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL"
|
||||||
|
"ScatterAssemblies"
|
||||||
|
{
|
||||||
|
"_1E7663DCE02A4D848349229A724E961A"
|
||||||
|
{
|
||||||
|
"Name" = "8:Xceed.Wpf.AvalonDock.resources.dll"
|
||||||
|
"Attributes" = "3:512"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"SourcePath" = "8:..\\BreCalClient\\bin\\Debug\\net6.0-windows\\de\\Xceed.Wpf.AvalonDock.resources.dll"
|
||||||
|
"TargetName" = "8:"
|
||||||
|
"Tag" = "8:"
|
||||||
|
"Folder" = "8:_F64284776BC0480CBF6C33B1FE00C374"
|
||||||
|
"Condition" = "8:"
|
||||||
|
"Transitive" = "11:FALSE"
|
||||||
|
"Vital" = "11:TRUE"
|
||||||
|
"ReadOnly" = "11:FALSE"
|
||||||
|
"Hidden" = "11:FALSE"
|
||||||
|
"System" = "11:FALSE"
|
||||||
|
"Permanent" = "11:FALSE"
|
||||||
|
"SharedLegacy" = "11:FALSE"
|
||||||
|
"PackageAs" = "3:1"
|
||||||
|
"Register" = "3:1"
|
||||||
|
"Exclude" = "11:FALSE"
|
||||||
|
"IsDependency" = "11:FALSE"
|
||||||
|
"IsolateTo" = "8:"
|
||||||
|
}
|
||||||
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4EE484EAA4A246CBBB283030A6054BC0"
|
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4EE484EAA4A246CBBB283030A6054BC0"
|
||||||
{
|
{
|
||||||
"SourcePath" = "8:..\\BreCalClient\\Resources\\containership.ico"
|
"SourcePath" = "8:..\\BreCalClient\\Resources\\containership.ico"
|
||||||
@ -110,6 +173,37 @@
|
|||||||
"IsDependency" = "11:FALSE"
|
"IsDependency" = "11:FALSE"
|
||||||
"IsolateTo" = "8:"
|
"IsolateTo" = "8:"
|
||||||
}
|
}
|
||||||
|
"{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_CD20A468610C42B89F66B4D3367A5A6A"
|
||||||
|
{
|
||||||
|
"AssemblyRegister" = "3:1"
|
||||||
|
"AssemblyIsInGAC" = "11:FALSE"
|
||||||
|
"AssemblyAsmDisplayName" = "8:BreCalClient.resources, Version=1.6.2.0, Culture=de, PublicKeyToken=9ce7b6b354e08ac9, processorArchitecture=MSIL"
|
||||||
|
"ScatterAssemblies"
|
||||||
|
{
|
||||||
|
"_CD20A468610C42B89F66B4D3367A5A6A"
|
||||||
|
{
|
||||||
|
"Name" = "8:BreCalClient.resources.dll"
|
||||||
|
"Attributes" = "3:512"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"SourcePath" = "8:..\\BreCalClient\\bin\\Debug\\net6.0-windows\\de\\BreCalClient.resources.dll"
|
||||||
|
"TargetName" = "8:"
|
||||||
|
"Tag" = "8:"
|
||||||
|
"Folder" = "8:_F64284776BC0480CBF6C33B1FE00C374"
|
||||||
|
"Condition" = "8:"
|
||||||
|
"Transitive" = "11:FALSE"
|
||||||
|
"Vital" = "11:TRUE"
|
||||||
|
"ReadOnly" = "11:FALSE"
|
||||||
|
"Hidden" = "11:FALSE"
|
||||||
|
"System" = "11:FALSE"
|
||||||
|
"Permanent" = "11:FALSE"
|
||||||
|
"SharedLegacy" = "11:FALSE"
|
||||||
|
"PackageAs" = "3:1"
|
||||||
|
"Register" = "3:1"
|
||||||
|
"Exclude" = "11:FALSE"
|
||||||
|
"IsDependency" = "11:FALSE"
|
||||||
|
"IsolateTo" = "8:"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"FileType"
|
"FileType"
|
||||||
{
|
{
|
||||||
@ -137,6 +231,17 @@
|
|||||||
"Property" = "8:TARGETDIR"
|
"Property" = "8:TARGETDIR"
|
||||||
"Folders"
|
"Folders"
|
||||||
{
|
{
|
||||||
|
"{9EF0B969-E518-4E46-987F-47570745A589}:_F64284776BC0480CBF6C33B1FE00C374"
|
||||||
|
{
|
||||||
|
"Name" = "8:de"
|
||||||
|
"AlwaysCreate" = "11:FALSE"
|
||||||
|
"Condition" = "8:"
|
||||||
|
"Transitive" = "11:FALSE"
|
||||||
|
"Property" = "8:_319F0FD8E72443BFA3AE5E1F3F42523B"
|
||||||
|
"Folders"
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"{1525181F-901A-416C-8A58-119130FE478E}:_8BBC7FE2F38E4B41A71D26CCED7D0BCB"
|
"{1525181F-901A-416C-8A58-119130FE478E}:_8BBC7FE2F38E4B41A71D26CCED7D0BCB"
|
||||||
|
|||||||
@ -1,12 +1,7 @@
|
|||||||
// Copyright (c) 2023- schick Informatik
|
// Copyright (c) 2023- schick Informatik
|
||||||
// Description: Model class for berth entity
|
// Description: Model class for berth entity
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace brecal.model
|
namespace brecal.model
|
||||||
{
|
{
|
||||||
@ -23,10 +18,14 @@ namespace brecal.model
|
|||||||
|
|
||||||
public uint? Authority_Id { get; set; }
|
public uint? Authority_Id { get; set; }
|
||||||
|
|
||||||
|
public uint? Port_Id { get; set; }
|
||||||
|
|
||||||
public Participant? Owner { get; set; }
|
public Participant? Owner { get; set; }
|
||||||
|
|
||||||
public Participant? Authority { get; set; }
|
public Participant? Authority { get; set; }
|
||||||
|
|
||||||
|
public Port? Port { get; set; }
|
||||||
|
|
||||||
public string? Terminal { get { if (Owner != null) return Owner.Name; else return "n/a"; } }
|
public string? Terminal { get { if (Owner != null) return Owner.Name; else return "n/a"; } }
|
||||||
|
|
||||||
public string? Authority_Text { get { if (Authority != null) return Authority.Name; else return "n/a"; } }
|
public string? Authority_Text { get { if (Authority != null) return Authority.Name; else return "n/a"; } }
|
||||||
@ -48,12 +47,12 @@ namespace brecal.model
|
|||||||
|
|
||||||
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
|
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
|
||||||
{
|
{
|
||||||
cmd.CommandText = "SELECT id, name, owner_id, authority_id, `lock`, created, modified, deleted FROM berth";
|
cmd.CommandText = "SELECT id, name, owner_id, authority_id, port_id, `lock`, created, modified, deleted FROM berth";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<DbEntity> LoadElems(IDataReader reader)
|
public static List<DbEntity> LoadElems(IDataReader reader)
|
||||||
{
|
{
|
||||||
List<DbEntity> result = new List<DbEntity>();
|
List<DbEntity> result = new();
|
||||||
while (reader.Read())
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
Berth b = new();
|
Berth b = new();
|
||||||
@ -61,10 +60,11 @@ namespace brecal.model
|
|||||||
if (!reader.IsDBNull(1)) b.Name = reader.GetString(1);
|
if (!reader.IsDBNull(1)) b.Name = reader.GetString(1);
|
||||||
if (!reader.IsDBNull(2)) b.Owner_Id = (uint) reader.GetInt32(2);
|
if (!reader.IsDBNull(2)) b.Owner_Id = (uint) reader.GetInt32(2);
|
||||||
if (!reader.IsDBNull(3)) b.Authority_Id = (uint) reader.GetInt32(3);
|
if (!reader.IsDBNull(3)) b.Authority_Id = (uint) reader.GetInt32(3);
|
||||||
if (!reader.IsDBNull(4)) b.Lock = reader.GetBoolean(4);
|
if (!reader.IsDBNull(4)) b.Port_Id = (uint) reader.GetInt32(4);
|
||||||
if (!reader.IsDBNull(5)) b.Created = reader.GetDateTime(5);
|
if (!reader.IsDBNull(5)) b.Lock = reader.GetBoolean(5);
|
||||||
if (!reader.IsDBNull(6)) b.Modified = reader.GetDateTime(6);
|
if (!reader.IsDBNull(6)) b.Created = reader.GetDateTime(6);
|
||||||
if (!reader.IsDBNull(7)) b.Deleted = reader.GetInt16(7);
|
if (!reader.IsDBNull(7)) b.Modified = reader.GetDateTime(7);
|
||||||
|
if (!reader.IsDBNull(8)) b.Deleted = reader.GetInt16(8);
|
||||||
result.Add(b);
|
result.Add(b);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -76,7 +76,7 @@ namespace brecal.model
|
|||||||
|
|
||||||
public override void SetCreate(IDbCommand cmd)
|
public override void SetCreate(IDbCommand cmd)
|
||||||
{
|
{
|
||||||
cmd.CommandText = "INSERT INTO berth (owner_id, authority_id, name, `lock`) VALUES ( @PID, @AID, @NAME, @LOCK)";
|
cmd.CommandText = "INSERT INTO berth (owner_id, authority_id, port_id, name, `lock`) VALUES ( @PID, @AID, @PO_ID, @NAME, @LOCK)";
|
||||||
this.SetParameters(cmd);
|
this.SetParameters(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ namespace brecal.model
|
|||||||
|
|
||||||
public override void SetUpdate(IDbCommand cmd)
|
public override void SetUpdate(IDbCommand cmd)
|
||||||
{
|
{
|
||||||
cmd.CommandText = "UPDATE berth SET name = @NAME, owner_id = @PID, authority_id = @AID, `lock` = @LOCK WHERE id = @ID";
|
cmd.CommandText = "UPDATE berth SET name = @NAME, owner_id = @PID, authority_id = @AID, port_id = @PO_ID, `lock` = @LOCK WHERE id = @ID";
|
||||||
this.SetParameters(cmd);
|
this.SetParameters(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,14 +109,19 @@ namespace brecal.model
|
|||||||
|
|
||||||
IDbDataParameter pid = cmd.CreateParameter();
|
IDbDataParameter pid = cmd.CreateParameter();
|
||||||
pid.ParameterName = "PID";
|
pid.ParameterName = "PID";
|
||||||
pid.Value = this.Owner_Id;
|
pid.Value = this.Owner_Id.HasValue ? this.Owner_Id.Value : DBNull.Value;
|
||||||
cmd.Parameters.Add(pid);
|
cmd.Parameters.Add(pid);
|
||||||
|
|
||||||
IDbDataParameter aid = cmd.CreateParameter();
|
IDbDataParameter aid = cmd.CreateParameter();
|
||||||
aid.ParameterName = "AID";
|
aid.ParameterName = "AID";
|
||||||
aid.Value = this.Authority_Id;
|
aid.Value = this.Authority_Id.HasValue ? this.Authority_Id.Value : DBNull.Value;
|
||||||
cmd.Parameters.Add(aid);
|
cmd.Parameters.Add(aid);
|
||||||
|
|
||||||
|
IDbDataParameter poid = cmd.CreateParameter();
|
||||||
|
poid.ParameterName = "PO_ID";
|
||||||
|
poid.Value = this.Port_Id.HasValue ? this.Port_Id.Value : DBNull.Value;
|
||||||
|
cmd.Parameters.Add(poid);
|
||||||
|
|
||||||
IDbDataParameter name = cmd.CreateParameter();
|
IDbDataParameter name = cmd.CreateParameter();
|
||||||
name.ParameterName = "NAME";
|
name.ParameterName = "NAME";
|
||||||
name.Value = this.Name;
|
name.Value = this.Name;
|
||||||
|
|||||||
@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System.Data;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace brecal.model
|
namespace brecal.model
|
||||||
@ -42,6 +38,11 @@ namespace brecal.model
|
|||||||
/// <param name="cmd">CMD created by DB manager</param>
|
/// <param name="cmd">CMD created by DB manager</param>
|
||||||
public abstract void SetDelete(IDbCommand cmd);
|
public abstract void SetDelete(IDbCommand cmd);
|
||||||
|
|
||||||
|
public virtual void SetNonQuery(IDbCommand cmd)
|
||||||
|
{
|
||||||
|
// default: do nothing
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Each database entity must be able to save itself to the database
|
/// Each database entity must be able to save itself to the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -61,9 +62,14 @@ namespace brecal.model
|
|||||||
/// Each entity must be able to delete itself
|
/// Each entity must be able to delete itself
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task Delete(IDBManager manager)
|
public async Task Delete(IDBManager manager)
|
||||||
{
|
{
|
||||||
await manager.ExecuteNonQuery(this.SetDelete);
|
await manager.ExecuteNonQuery(this.SetDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ExecuteNonQuery(IDBManager manager)
|
||||||
|
{
|
||||||
|
await manager.ExecuteNonQuery(this.SetNonQuery);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,6 +55,8 @@ namespace brecal.model
|
|||||||
|
|
||||||
public uint Flags { get; set; }
|
public uint Flags { get; set; }
|
||||||
|
|
||||||
|
public bool Deleted { get; set; } = false;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region public static methods
|
#region public static methods
|
||||||
@ -70,7 +72,7 @@ namespace brecal.model
|
|||||||
|
|
||||||
public static List<DbEntity> LoadElems(IDataReader reader)
|
public static List<DbEntity> LoadElems(IDataReader reader)
|
||||||
{
|
{
|
||||||
List<DbEntity> result = new List<DbEntity>();
|
List<DbEntity> result = new();
|
||||||
while (reader.Read())
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
Participant p = new();
|
Participant p = new();
|
||||||
@ -83,6 +85,7 @@ namespace brecal.model
|
|||||||
if (!reader.IsDBNull(6)) p.Flags = (uint)reader.GetInt32(6);
|
if (!reader.IsDBNull(6)) p.Flags = (uint)reader.GetInt32(6);
|
||||||
if (!reader.IsDBNull(7)) p.Created = reader.GetDateTime(7);
|
if (!reader.IsDBNull(7)) p.Created = reader.GetDateTime(7);
|
||||||
if (!reader.IsDBNull(8)) p.Modified = reader.GetDateTime(8);
|
if (!reader.IsDBNull(8)) p.Modified = reader.GetDateTime(8);
|
||||||
|
if (!reader.IsDBNull(9)) p.Deleted = reader.GetBoolean(9);
|
||||||
result.Add(p);
|
result.Add(p);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -90,7 +93,7 @@ namespace brecal.model
|
|||||||
|
|
||||||
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
|
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
|
||||||
{
|
{
|
||||||
cmd.CommandText = "SELECT id, name, street, postal_code, city, type, flags, created, modified FROM participant";
|
cmd.CommandText = "SELECT id, name, street, postal_code, city, type, flags, created, modified, deleted FROM participant";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -111,13 +114,13 @@ namespace brecal.model
|
|||||||
|
|
||||||
public override void SetDelete(IDbCommand cmd)
|
public override void SetDelete(IDbCommand cmd)
|
||||||
{
|
{
|
||||||
cmd.CommandText = "DELETE FROM participant WHERE id = @ID";
|
cmd.CommandText = "UPDATE participant SET deleted = 1 WHERE id = @ID";
|
||||||
|
|
||||||
IDataParameter idParam = cmd.CreateParameter();
|
IDataParameter idParam = cmd.CreateParameter();
|
||||||
idParam.ParameterName = "ID";
|
idParam.ParameterName = "ID";
|
||||||
idParam.Value = this.Id;
|
idParam.Value = this.Id;
|
||||||
cmd.Parameters.Add(idParam);
|
cmd.Parameters.Add(idParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
115
src/brecal.model/Port.cs
Normal file
115
src/brecal.model/Port.cs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (c) 2023- schick Informatik
|
||||||
|
// Description: Port entity
|
||||||
|
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace brecal.model
|
||||||
|
{
|
||||||
|
public class Port : DbEntity
|
||||||
|
{
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public string? Locode { get; set; }
|
||||||
|
|
||||||
|
public bool IsDeleted { get; set; } = false;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region overrides
|
||||||
|
|
||||||
|
public override void SetCreate(IDbCommand cmd)
|
||||||
|
{
|
||||||
|
cmd.CommandText = "INSERT INTO port (name, locode) VALUES ( @NAME, @LOCODE)";
|
||||||
|
this.SetParameters(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDelete(IDbCommand cmd)
|
||||||
|
{
|
||||||
|
cmd.CommandText = "UPDATE port SET deleted = 1 WHERE id = @ID";
|
||||||
|
IDataParameter idParam = cmd.CreateParameter();
|
||||||
|
idParam.ParameterName = "ID";
|
||||||
|
idParam.Value = this.Id;
|
||||||
|
cmd.Parameters.Add(idParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetUpdate(IDbCommand cmd)
|
||||||
|
{
|
||||||
|
cmd.CommandText = "UPDATE port set name = @NAME, locode = @LOCODE WHERE id = @ID";
|
||||||
|
this.SetParameters(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public static methods
|
||||||
|
|
||||||
|
public static async Task<List<Port>> LoadAll(IDBManager manager)
|
||||||
|
{
|
||||||
|
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems);
|
||||||
|
List<Port> result = new();
|
||||||
|
foreach (Port p in loadResultList.Cast<Port>())
|
||||||
|
result.Add(p);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
|
||||||
|
{
|
||||||
|
cmd.CommandText = "SELECT id, name, locode, created, modified, deleted FROM port WHERE deleted = 0";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<DbEntity> LoadElems(IDataReader reader)
|
||||||
|
{
|
||||||
|
List<DbEntity> result = new();
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Port p = new();
|
||||||
|
p.Id = (uint)reader.GetInt32(0);
|
||||||
|
if (!reader.IsDBNull(1)) p.Name = reader.GetString(1);
|
||||||
|
if (!reader.IsDBNull(2)) p.Locode = reader.GetString(2);
|
||||||
|
if (!reader.IsDBNull(3)) p.Created = reader.GetDateTime(3);
|
||||||
|
if (!reader.IsDBNull(4)) p.Modified = reader.GetDateTime(4);
|
||||||
|
if (!reader.IsDBNull(5)) p.IsDeleted = reader.GetBoolean(5);
|
||||||
|
result.Add(p);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region private methods
|
||||||
|
|
||||||
|
private void SetParameters(IDbCommand cmd)
|
||||||
|
{
|
||||||
|
IDbDataParameter name = cmd.CreateParameter();
|
||||||
|
name.ParameterName = "NAME";
|
||||||
|
name.Value = this.Name;
|
||||||
|
cmd.Parameters.Add(name);
|
||||||
|
|
||||||
|
IDbDataParameter desc = cmd.CreateParameter();
|
||||||
|
desc.ParameterName = "LOCODE";
|
||||||
|
desc.Value = this.Locode;
|
||||||
|
cmd.Parameters.Add(desc);
|
||||||
|
|
||||||
|
IDataParameter idParam = cmd.CreateParameter();
|
||||||
|
idParam.ParameterName = "ID";
|
||||||
|
idParam.Value = this.Id;
|
||||||
|
cmd.Parameters.Add(idParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region overrides
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Name} ({Locode})";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
111
src/brecal.model/PortAssignment.cs
Normal file
111
src/brecal.model/PortAssignment.cs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
// Copyright (c) 2023- schick Informatik
|
||||||
|
// Description: Participant Port Map Entity
|
||||||
|
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace brecal.model
|
||||||
|
{
|
||||||
|
public class PortAssignment : DbEntity
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public int? ParticipantId { get; set; }
|
||||||
|
|
||||||
|
public int? PortId { get; set; }
|
||||||
|
|
||||||
|
public Participant? AssignedParticipant { get; set; }
|
||||||
|
|
||||||
|
public Port? AssignedPort { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public static methods
|
||||||
|
|
||||||
|
public static async Task<List<PortAssignment>> LoadForParticipant(Participant? p, IDBManager manager)
|
||||||
|
{
|
||||||
|
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems, args: p);
|
||||||
|
List<PortAssignment> result = new();
|
||||||
|
foreach (PortAssignment pa in loadResultList.Cast<PortAssignment>())
|
||||||
|
{
|
||||||
|
pa.AssignedParticipant = p;
|
||||||
|
result.Add(pa);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetLoadQuery(IDbCommand cmd, params object?[] args)
|
||||||
|
{
|
||||||
|
cmd.CommandText = "SELECT id, participant_id, port_id FROM participant_port_map WHERE participant_id = @PID";
|
||||||
|
if (args.Length != 1 || args[0] is not Participant)
|
||||||
|
throw new ArgumentException("loader needs single participant as argument");
|
||||||
|
IDataParameter pid = cmd.CreateParameter();
|
||||||
|
pid.ParameterName = "PID";
|
||||||
|
if (args[0] is Participant p)
|
||||||
|
pid.Value = p.Id;
|
||||||
|
cmd.Parameters.Add(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<DbEntity> LoadElems(IDataReader reader)
|
||||||
|
{
|
||||||
|
List<DbEntity> result = new();
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
PortAssignment ra = new();
|
||||||
|
ra.Id = (uint)reader.GetInt32(0);
|
||||||
|
if (!reader.IsDBNull(1)) ra.ParticipantId = reader.GetInt32(1);
|
||||||
|
if (!reader.IsDBNull(2)) ra.PortId = reader.GetInt32(2);
|
||||||
|
result.Add(ra);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region overrides
|
||||||
|
|
||||||
|
public override void SetUpdate(IDbCommand cmd)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetCreate(IDbCommand cmd)
|
||||||
|
{
|
||||||
|
cmd.CommandText = "INSERT INTO participant_port_map (participant_id, port_id) VALUES (@PID, @PORTID)";
|
||||||
|
|
||||||
|
IDbDataParameter participantId = cmd.CreateParameter();
|
||||||
|
participantId.ParameterName = "pID";
|
||||||
|
participantId.Value = this.ParticipantId;
|
||||||
|
cmd.Parameters.Add(participantId);
|
||||||
|
|
||||||
|
IDbDataParameter portId = cmd.CreateParameter();
|
||||||
|
portId.ParameterName = "PORTID";
|
||||||
|
portId.Value = this.PortId;
|
||||||
|
cmd.Parameters.Add(portId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDelete(IDbCommand cmd)
|
||||||
|
{
|
||||||
|
cmd.CommandText = "DELETE FROM participant_port_map WHERE id = @ID";
|
||||||
|
|
||||||
|
IDataParameter idParam = cmd.CreateParameter();
|
||||||
|
idParam.ParameterName = "ID";
|
||||||
|
idParam.Value = this.Id;
|
||||||
|
cmd.Parameters.Add(idParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (this.AssignedPort == null)
|
||||||
|
{
|
||||||
|
return $"{Id}: <defunct port>";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return AssignedPort.Name ?? AssignedPort.Id.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,7 @@
|
|||||||
using System;
|
// Copyright (c) 2023- schick Informatik
|
||||||
using System.Collections.Generic;
|
// Description: Role Entity
|
||||||
|
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace brecal.model
|
namespace brecal.model
|
||||||
{
|
{
|
||||||
|
|||||||
@ -101,6 +101,16 @@ namespace brecal.model
|
|||||||
return this.Username ?? $"{base.Id} - {this.GetType().Name}";
|
return this.Username ?? $"{base.Id} - {this.GetType().Name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetNonQuery(IDbCommand cmd)
|
||||||
|
{
|
||||||
|
cmd.CommandText = "UPDATE history set user_id = NULL WHERE user_id = @ID";
|
||||||
|
|
||||||
|
IDataParameter idParam = cmd.CreateParameter();
|
||||||
|
idParam.ParameterName = "ID";
|
||||||
|
idParam.Value = this.Id;
|
||||||
|
cmd.Parameters.Add(idParam);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region private methods
|
#region private methods
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@ -17,7 +17,7 @@ namespace brecal.mysql
|
|||||||
|
|
||||||
public async Task<List<DbEntity>> Load(QueryFunc prepareAction, LoadFunc<IDataReader> loadAction, params object?[] args)
|
public async Task<List<DbEntity>> Load(QueryFunc prepareAction, LoadFunc<IDataReader> loadAction, params object?[] args)
|
||||||
{
|
{
|
||||||
await using MySqlConnection connection = new MySqlConnection(_connectionString);
|
await using MySqlConnection connection = new(_connectionString);
|
||||||
await connection.OpenAsync();
|
await connection.OpenAsync();
|
||||||
|
|
||||||
using MySqlCommand cmd = new();
|
using MySqlCommand cmd = new();
|
||||||
@ -31,7 +31,7 @@ namespace brecal.mysql
|
|||||||
|
|
||||||
public async Task<object?> ExecuteScalar(Action<IDbCommand> prepareAction)
|
public async Task<object?> ExecuteScalar(Action<IDbCommand> prepareAction)
|
||||||
{
|
{
|
||||||
await using MySqlConnection connection = new MySqlConnection(_connectionString);
|
await using MySqlConnection connection = new(_connectionString);
|
||||||
await connection.OpenAsync();
|
await connection.OpenAsync();
|
||||||
|
|
||||||
using MySqlCommand cmd = new();
|
using MySqlCommand cmd = new();
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MySqlConnector" Version="2.3.0-beta.1" />
|
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import logging
|
import logging
|
||||||
from . import local_db
|
from . import local_db
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ from .api import ships
|
|||||||
from .api import login
|
from .api import login
|
||||||
from .api import user
|
from .api import user
|
||||||
from .api import history
|
from .api import history
|
||||||
|
from .api import ports
|
||||||
|
|
||||||
from BreCal.brecal_utils.file_handling import get_project_root, ensure_path
|
from BreCal.brecal_utils.file_handling import get_project_root, ensure_path
|
||||||
from BreCal.brecal_utils.test_handling import execute_test_with_pytest, execute_coverage_test
|
from BreCal.brecal_utils.test_handling import execute_test_with_pytest, execute_coverage_test
|
||||||
@ -35,7 +37,6 @@ from BreCal.stubs.df_times import get_df_times
|
|||||||
from BreCal.services.schedule_routines import setup_schedule, run_schedule_permanently_in_background
|
from BreCal.services.schedule_routines import setup_schedule, run_schedule_permanently_in_background
|
||||||
|
|
||||||
def create_app(test_config=None, instance_path=None):
|
def create_app(test_config=None, instance_path=None):
|
||||||
|
|
||||||
app = Flask(__name__, instance_relative_config=True)
|
app = Flask(__name__, instance_relative_config=True)
|
||||||
app.config.from_mapping(
|
app.config.from_mapping(
|
||||||
SECRET_KEY='dev'
|
SECRET_KEY='dev'
|
||||||
@ -47,6 +48,8 @@ def create_app(test_config=None, instance_path=None):
|
|||||||
|
|
||||||
if instance_path is not None:
|
if instance_path is not None:
|
||||||
app.instance_path = instance_path
|
app.instance_path = instance_path
|
||||||
|
elif app.config.get("INSTANCE_PATH"):
|
||||||
|
app.instance_path = app.config["INSTANCE_PATH"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import os
|
import os
|
||||||
@ -66,14 +69,25 @@ def create_app(test_config=None, instance_path=None):
|
|||||||
app.register_blueprint(login.bp)
|
app.register_blueprint(login.bp)
|
||||||
app.register_blueprint(user.bp)
|
app.register_blueprint(user.bp)
|
||||||
app.register_blueprint(history.bp)
|
app.register_blueprint(history.bp)
|
||||||
|
app.register_blueprint(ports.bp)
|
||||||
|
|
||||||
logging.basicConfig(filename='brecaltest.log', level=logging.DEBUG, format='%(asctime)s | %(name)s | %(levelname)s | %(message)s')
|
log_level = getattr(logging, app.config.get("LOG_LEVEL", "DEBUG"))
|
||||||
local_db.initPool(os.path.dirname(app.instance_path))
|
log_kwargs = {"format": "%(asctime)s | %(name)s | %(levelname)s | %(message)s"}
|
||||||
|
if app.config.get("LOG_TO_STDERR"):
|
||||||
|
log_kwargs["stream"] = sys.stderr
|
||||||
|
else:
|
||||||
|
log_kwargs["filename"] = app.config.get("LOG_FILE", "brecaltest.log")
|
||||||
|
logging.basicConfig(level=log_level, **log_kwargs)
|
||||||
|
|
||||||
|
if app.config.get("SECRET_KEY"):
|
||||||
|
os.environ["SECRET_KEY"] = app.config["SECRET_KEY"]
|
||||||
|
|
||||||
|
local_db.initPool(os.path.dirname(app.instance_path), config=app.config)
|
||||||
logging.info('App started')
|
logging.info('App started')
|
||||||
|
|
||||||
# Setup Routine jobs (e.g., reevaluation of shipcalls)
|
# Setup Routine jobs (e.g., reevaluation of shipcalls)
|
||||||
setup_schedule(update_shipcalls_interval_in_minutes=60)
|
setup_schedule(update_shipcalls_interval_in_minutes=app.config.get("SCHEDULE_UPDATE_SHIPCALLS_MINUTES", 60))
|
||||||
run_schedule_permanently_in_background(latency=30)
|
run_schedule_permanently_in_background(latency=app.config.get("SCHEDULE_BACKGROUND_LATENCY_SECONDS", 30))
|
||||||
logging.info('Routine Jobs are defined.')
|
logging.info('Routine Jobs are defined.')
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|||||||
@ -3,6 +3,7 @@ from flask import Blueprint, request
|
|||||||
from webargs.flaskparser import parser
|
from webargs.flaskparser import parser
|
||||||
from .. import impl
|
from .. import impl
|
||||||
from ..services.auth_guard import auth_guard
|
from ..services.auth_guard import auth_guard
|
||||||
|
from ..services.jwt_handler import decode_jwt
|
||||||
import json
|
import json
|
||||||
from BreCal.validators.validation_error import create_dynamic_exception_response
|
from BreCal.validators.validation_error import create_dynamic_exception_response
|
||||||
|
|
||||||
@ -15,8 +16,11 @@ def GetBerths():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if 'Authorization' in request.headers:
|
if 'Authorization' in request.headers:
|
||||||
token = request.headers.get('Authorization')
|
token = request.headers.get('Authorization')
|
||||||
return impl.berths.GetBerths(token)
|
payload = decode_jwt(token.split("Bearer ")[-1])
|
||||||
|
options = {}
|
||||||
|
options["participant_id"] = payload["participant_id"]
|
||||||
|
return impl.berths.GetBerths(options)
|
||||||
else:
|
else:
|
||||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||||
|
|
||||||
|
|||||||
@ -12,12 +12,18 @@ bp = Blueprint('notifications', __name__)
|
|||||||
@auth_guard() # no restriction by role
|
@auth_guard() # no restriction by role
|
||||||
def GetNotifications():
|
def GetNotifications():
|
||||||
try:
|
try:
|
||||||
if 'shipcall_id' in request.args:
|
if 'Authorization' in request.headers:
|
||||||
options = {}
|
token = request.headers.get('Authorization')
|
||||||
options["shipcall_id"] = request.args.get("shipcall_id")
|
participant_id = None
|
||||||
return impl.notifications.GetNotifications(options)
|
if 'participant_id' in request.args:
|
||||||
|
try:
|
||||||
|
participant_id = int(request.args.get('participant_id'))
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return create_dynamic_exception_response(ex=None, status_code=400, message="participant_id must be an integer")
|
||||||
|
|
||||||
|
return impl.notifications.GetNotifications(token, participant_id=participant_id)
|
||||||
else:
|
else:
|
||||||
return create_dynamic_exception_response(ex=None, status_code=400, message="missing argument: shipcall_id")
|
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import logging
|
|||||||
from flask import Blueprint, request
|
from flask import Blueprint, request
|
||||||
from .. import impl
|
from .. import impl
|
||||||
from ..services.auth_guard import auth_guard
|
from ..services.auth_guard import auth_guard
|
||||||
|
from ..services.jwt_handler import decode_jwt
|
||||||
import json
|
import json
|
||||||
from BreCal.validators.validation_error import create_dynamic_exception_response
|
from BreCal.validators.validation_error import create_dynamic_exception_response
|
||||||
|
|
||||||
@ -12,10 +13,15 @@ bp = Blueprint('participants', __name__)
|
|||||||
def GetParticipant():
|
def GetParticipant():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if 'Authorization' in request.headers:
|
if 'Authorization' in request.headers:
|
||||||
token = request.headers.get('Authorization')
|
payload = decode_jwt(request.headers.get("Authorization").split("Bearer ")[-1])
|
||||||
options = {}
|
options = {}
|
||||||
options["user_id"] = request.args.get("user_id")
|
options["user_id"] = request.args.get("user_id")
|
||||||
|
if "participant_id" in payload:
|
||||||
|
options["participant_id"] = payload["participant_id"]
|
||||||
|
else:
|
||||||
|
return create_dynamic_exception_response(ex=None, status_code=403, message="not authorized")
|
||||||
|
|
||||||
return impl.participant.GetParticipant(options)
|
return impl.participant.GetParticipant(options)
|
||||||
else:
|
else:
|
||||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||||
|
|||||||
24
src/server/BreCal/api/ports.py
Normal file
24
src/server/BreCal/api/ports.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import logging
|
||||||
|
from flask import Blueprint, request
|
||||||
|
from webargs.flaskparser import parser
|
||||||
|
from .. import impl
|
||||||
|
from ..services.auth_guard import auth_guard
|
||||||
|
import json
|
||||||
|
from BreCal.validators.validation_error import create_dynamic_exception_response
|
||||||
|
|
||||||
|
bp = Blueprint('ports', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/ports', methods=['get'])
|
||||||
|
@auth_guard() # no restriction by role
|
||||||
|
def GetPorts():
|
||||||
|
|
||||||
|
try:
|
||||||
|
if 'Authorization' in request.headers:
|
||||||
|
token = request.headers.get('Authorization')
|
||||||
|
return impl.ports.GetPorts(token)
|
||||||
|
else:
|
||||||
|
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||||
@ -7,6 +7,7 @@ from ..services.auth_guard import auth_guard, check_jwt
|
|||||||
from BreCal.validators.input_validation import validate_posted_shipcall_data, check_if_user_is_bsmd_type
|
from BreCal.validators.input_validation import validate_posted_shipcall_data, check_if_user_is_bsmd_type
|
||||||
from BreCal.validators.input_validation_shipcall import InputValidationShipcall
|
from BreCal.validators.input_validation_shipcall import InputValidationShipcall
|
||||||
from BreCal.database.sql_handler import execute_sql_query_standalone
|
from BreCal.database.sql_handler import execute_sql_query_standalone
|
||||||
|
from BreCal.services.jwt_handler import decode_jwt
|
||||||
from BreCal.validators.validation_error import create_validation_error_response, create_werkzeug_error_response, create_dynamic_exception_response
|
from BreCal.validators.validation_error import create_validation_error_response, create_werkzeug_error_response, create_dynamic_exception_response
|
||||||
from . import verify_if_request_is_json
|
from . import verify_if_request_is_json
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ bp = Blueprint('shipcalls', __name__)
|
|||||||
def GetShipcalls():
|
def GetShipcalls():
|
||||||
try:
|
try:
|
||||||
if 'Authorization' in request.headers:
|
if 'Authorization' in request.headers:
|
||||||
token = request.headers.get('Authorization') # see impl/login to see the token encoding, which is a JWT token.
|
token = request.headers.get('Authorization') # see impl/login to see the token encoding, which is a JWT token.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from BreCal.services.jwt_handler import decode_jwt
|
from BreCal.services.jwt_handler import decode_jwt
|
||||||
@ -32,14 +33,15 @@ def GetShipcalls():
|
|||||||
# oneline:
|
# oneline:
|
||||||
payload = decode_jwt(request.headers.get("Authorization").split("Bearer ")[-1])
|
payload = decode_jwt(request.headers.get("Authorization").split("Bearer ")[-1])
|
||||||
"""
|
"""
|
||||||
|
payload = decode_jwt(request.headers.get("Authorization").split("Bearer ")[-1])
|
||||||
options = {}
|
options = {}
|
||||||
options["participant_id"] = request.args.get("participant_id")
|
|
||||||
options["past_days"] = request.args.get("past_days", default=1, type=int)
|
options["past_days"] = request.args.get("past_days", default=1, type=int)
|
||||||
|
options["participant_id"] = payload["participant_id"]
|
||||||
|
|
||||||
return impl.shipcalls.GetShipcalls(options)
|
return impl.shipcalls.GetShipcalls(options)
|
||||||
else:
|
else:
|
||||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
@ -60,10 +62,10 @@ def PostShipcalls():
|
|||||||
# validate the posted shipcall data & the user's authority
|
# validate the posted shipcall data & the user's authority
|
||||||
InputValidationShipcall.evaluate_post_data(user_data, loadedModel, content)
|
InputValidationShipcall.evaluate_post_data(user_data, loadedModel, content)
|
||||||
return impl.shipcalls.PostShipcalls(loadedModel)
|
return impl.shipcalls.PostShipcalls(loadedModel)
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
return create_validation_error_response(ex=ex, status_code=400)
|
return create_validation_error_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
return create_dynamic_exception_response(ex=ex, status_code=400, message="bad format")
|
return create_dynamic_exception_response(ex=ex, status_code=400, message="bad format")
|
||||||
@ -75,23 +77,26 @@ def PutShipcalls():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
verify_if_request_is_json(request)
|
verify_if_request_is_json(request)
|
||||||
|
|
||||||
content = request.get_json(force=True)
|
content = request.get_json(force=True)
|
||||||
loadedModel = model.ShipcallSchema().load(data=content, many=False, partial=True)
|
loadedModel = model.ShipcallSchema().load(data=content, many=False, partial=True)
|
||||||
|
|
||||||
# read the user data from the JWT token (set when login is performed)
|
# read the user data from the JWT token (set when login is performed)
|
||||||
user_data = check_jwt()
|
user_data = check_jwt()
|
||||||
|
|
||||||
|
if not InputValidationShipcall.exists_shipcall_by_id(loadedModel.get("id")):
|
||||||
|
return create_dynamic_exception_response(ex=None, status_code=404, message="no shipcall found with the provided id")
|
||||||
|
|
||||||
# validate the PUT shipcall data and the user's authority
|
# validate the PUT shipcall data and the user's authority
|
||||||
InputValidationShipcall.evaluate_put_data(user_data, loadedModel, content)
|
InputValidationShipcall.evaluate_put_data(user_data, loadedModel, content)
|
||||||
return impl.shipcalls.PutShipcalls(loadedModel)
|
return impl.shipcalls.PutShipcalls(loadedModel, content)
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
return create_validation_error_response(ex=ex, status_code=400)
|
return create_validation_error_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
except werkzeug.exceptions.Forbidden as ex:
|
except werkzeug.exceptions.Forbidden as ex:
|
||||||
return create_werkzeug_error_response(ex=ex, status_code=403)
|
return create_werkzeug_error_response(ex=ex, status_code=403)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
return create_dynamic_exception_response(ex=None, status_code=400, message="bad format")
|
return create_dynamic_exception_response(ex=None, status_code=400, message="bad format")
|
||||||
|
|||||||
@ -23,7 +23,7 @@ def GetShips():
|
|||||||
return impl.ships.GetShips(token)
|
return impl.ships.GetShips(token)
|
||||||
else:
|
else:
|
||||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ def PostShip():
|
|||||||
is_bsmd = check_if_user_is_bsmd_type(user_data)
|
is_bsmd = check_if_user_is_bsmd_type(user_data)
|
||||||
if not is_bsmd:
|
if not is_bsmd:
|
||||||
raise ValidationError({"participant_type":f"current user does not belong to BSMD. Cannot post shipcalls. Found user data: {user_data}"})
|
raise ValidationError({"participant_type":f"current user does not belong to BSMD. Cannot post shipcalls. Found user data: {user_data}"})
|
||||||
|
|
||||||
content = request.get_json(force=True)
|
content = request.get_json(force=True)
|
||||||
loadedModel = model.ShipSchema().load(data=content, many=False, partial=True)
|
loadedModel = model.ShipSchema().load(data=content, many=False, partial=True)
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ def PostShip():
|
|||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
return create_validation_error_response(ex=ex, status_code=400)
|
return create_validation_error_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return create_dynamic_exception_response(ex=ex, status_code=400, message=None)
|
return create_dynamic_exception_response(ex=ex, status_code=400, message=None)
|
||||||
|
|
||||||
@ -71,13 +71,16 @@ def PutShip():
|
|||||||
content = request.get_json(force=True)
|
content = request.get_json(force=True)
|
||||||
loadedModel = model.ShipSchema().load(data=content, many=False, partial=True, unknown=EXCLUDE)
|
loadedModel = model.ShipSchema().load(data=content, many=False, partial=True, unknown=EXCLUDE)
|
||||||
|
|
||||||
|
if not InputValidationShip.exists_ship_by_dict(model=loadedModel):
|
||||||
|
return create_dynamic_exception_response(ex=None, status_code=404, message="no ship found with the provided id")
|
||||||
|
|
||||||
# validate the request data & user permissions
|
# validate the request data & user permissions
|
||||||
InputValidationShip.evaluate_put_data(user_data, loadedModel, content)
|
InputValidationShip.evaluate_put_data(user_data, loadedModel, content)
|
||||||
return impl.ships.PutShip(loadedModel)
|
return impl.ships.PutShip(loadedModel)
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
return create_validation_error_response(ex=ex, status_code=400)
|
return create_validation_error_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
@ -88,10 +91,10 @@ def DeleteShip():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
verify_if_request_is_json(request)
|
verify_if_request_is_json(request)
|
||||||
|
|
||||||
# read the user data from the JWT token (set when login is performed)
|
# read the user data from the JWT token (set when login is performed)
|
||||||
user_data = check_jwt()
|
user_data = check_jwt()
|
||||||
|
|
||||||
if 'id' in request.args:
|
if 'id' in request.args:
|
||||||
options = {}
|
options = {}
|
||||||
options["id"] = request.args.get("id")
|
options["id"] = request.args.get("id")
|
||||||
@ -100,12 +103,16 @@ def DeleteShip():
|
|||||||
|
|
||||||
# validate the request data & user permissions
|
# validate the request data & user permissions
|
||||||
ship_id = request.args.get("id")
|
ship_id = request.args.get("id")
|
||||||
|
|
||||||
|
if not InputValidationShip.exists_ship_by_id(id=ship_id):
|
||||||
|
return create_dynamic_exception_response(ex=None, status_code=404, message="no ship found with the provided id")
|
||||||
|
|
||||||
InputValidationShip.evaluate_delete_data(user_data, ship_id)
|
InputValidationShip.evaluate_delete_data(user_data, ship_id)
|
||||||
return impl.ships.DeleteShip(options)
|
return impl.ships.DeleteShip(options)
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
return create_validation_error_response(ex=ex, status_code=400)
|
return create_validation_error_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ def GetTimes():
|
|||||||
options = {}
|
options = {}
|
||||||
options["shipcall_id"] = request.args.get("shipcall_id")
|
options["shipcall_id"] = request.args.get("shipcall_id")
|
||||||
return impl.times.GetTimes(options)
|
return impl.times.GetTimes(options)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
@ -60,16 +60,19 @@ def PutTimes():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
verify_if_request_is_json(request)
|
verify_if_request_is_json(request)
|
||||||
|
|
||||||
content = request.get_json(force=True)
|
content = request.get_json(force=True)
|
||||||
loadedModel = model.TimesSchema().load(data=content, many=False, partial=True)
|
loadedModel = model.TimesSchema().load(data=content, many=False, partial=True)
|
||||||
|
|
||||||
# read the user data from the JWT token (set when login is performed)
|
# read the user data from the JWT token (set when login is performed)
|
||||||
user_data = check_jwt()
|
user_data = check_jwt()
|
||||||
|
|
||||||
|
if not InputValidationTimes.exists_times_by_id(loadedModel.get("id")):
|
||||||
|
return create_dynamic_exception_response(ex=None, status_code=404, message="no times found with the provided id")
|
||||||
|
|
||||||
# validate the request
|
# validate the request
|
||||||
InputValidationTimes.evaluate_put_data(user_data, loadedModel, content)
|
InputValidationTimes.evaluate_put_data(user_data, loadedModel, content)
|
||||||
return impl.times.PutTimes(loadedModel)
|
return impl.times.PutTimes(loadedModel, content)
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
return create_validation_error_response(ex=ex, status_code=400)
|
return create_validation_error_response(ex=ex, status_code=400)
|
||||||
@ -91,13 +94,16 @@ def DeleteTimes():
|
|||||||
# read the user data from the JWT token (set when login is performed)
|
# read the user data from the JWT token (set when login is performed)
|
||||||
user_data = check_jwt()
|
user_data = check_jwt()
|
||||||
|
|
||||||
|
if not InputValidationTimes.exists_times_by_id(options["id"]):
|
||||||
|
return create_dynamic_exception_response(ex=None, status_code=404, message="no times found with the provided id")
|
||||||
|
|
||||||
# validate the request
|
# validate the request
|
||||||
InputValidationTimes.evaluate_delete_data(user_data, times_id = request.args.get("id"))
|
InputValidationTimes.evaluate_delete_data(user_data, times_id = request.args.get("id"))
|
||||||
|
|
||||||
return impl.times.DeleteTimes(options)
|
return impl.times.DeleteTimes(options)
|
||||||
else:
|
else:
|
||||||
return create_dynamic_exception_response(ex=None, status_code=400, message="Times delete missing argument: id")
|
return create_dynamic_exception_response(ex=None, status_code=400, message="Times delete missing argument: id")
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
return create_validation_error_response(ex=ex, status_code=400)
|
return create_validation_error_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
|
|||||||
@ -2,29 +2,35 @@ from flask import Blueprint, request
|
|||||||
from ..schemas import model
|
from ..schemas import model
|
||||||
from .. import impl
|
from .. import impl
|
||||||
from ..services.auth_guard import auth_guard
|
from ..services.auth_guard import auth_guard
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
from marshmallow import ValidationError
|
from marshmallow import ValidationError
|
||||||
from . import verify_if_request_is_json
|
from . import verify_if_request_is_json
|
||||||
from BreCal.validators.validation_error import create_dynamic_exception_response, create_validation_error_response
|
from BreCal.validators.validation_error import create_dynamic_exception_response, create_validation_error_response
|
||||||
|
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
bp = Blueprint('user', __name__)
|
bp = Blueprint('user', __name__)
|
||||||
|
|
||||||
@bp.route('/user', methods=['put'])
|
@bp.route('/user', methods=['put'])
|
||||||
@auth_guard() # no restriction by role
|
@auth_guard() # no restriction by role
|
||||||
def PutUser():
|
def PutUser():
|
||||||
|
|
||||||
|
content = None
|
||||||
try:
|
try:
|
||||||
verify_if_request_is_json(request)
|
verify_if_request_is_json(request)
|
||||||
|
|
||||||
content = request.get_json(force=True)
|
content = request.get_json(force=True)
|
||||||
loadedModel = model.UserSchema().load(data=content, many=False, partial=True)
|
loadedModel = model.UserSchema().load(data=content, many=False, partial=True)
|
||||||
return impl.user.PutUser(loadedModel)
|
return impl.user.PutUser(loadedModel)
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
|
logging.warning("UserSchema validation failed. Payload=%s", json.dumps(content, default=str))
|
||||||
return create_validation_error_response(ex=ex, status_code=400)
|
return create_validation_error_response(ex=ex, status_code=400)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
logging.error("UserSchema load failed. Payload=%s\n%s", json.dumps(content, default=str), traceback.format_exc())
|
||||||
return create_dynamic_exception_response(ex=None, status_code=400, message="bad format")
|
return create_dynamic_exception_response(ex=None, status_code=400, message="bad format")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -22,15 +22,15 @@ def get_request_code(code_id):
|
|||||||
class RequestStatusCode(ABC):
|
class RequestStatusCode(ABC):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __call__(self, data):
|
def __call__(self, data):
|
||||||
raise NotImplementedError("any default status code object must be callable")
|
raise NotImplementedError("any default status code object must be callable")
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def status_code(self):
|
def status_code(self):
|
||||||
raise NotImplementedError("any default status code object should return an integer")
|
raise NotImplementedError("any default status code object should return an integer")
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def response(self, data):
|
def response(self, data):
|
||||||
raise NotImplementedError("the response method should return a binary json object. typically, json.dumps is used")
|
raise NotImplementedError("the response method should return a binary json object. typically, json.dumps is used")
|
||||||
@ -38,7 +38,7 @@ class RequestStatusCode(ABC):
|
|||||||
|
|
||||||
def headers(self):
|
def headers(self):
|
||||||
return {'Content-Type': 'application/json; charset=utf-8'}
|
return {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
|
|
||||||
class RequestCode_HTTP_200_OK(RequestStatusCode):
|
class RequestCode_HTTP_200_OK(RequestStatusCode):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
@ -46,13 +46,13 @@ class RequestCode_HTTP_200_OK(RequestStatusCode):
|
|||||||
|
|
||||||
def __call__(self, data):
|
def __call__(self, data):
|
||||||
return (self.response(data), self.status_code(), self.headers())
|
return (self.response(data), self.status_code(), self.headers())
|
||||||
|
|
||||||
def status_code(self):
|
def status_code(self):
|
||||||
return 200
|
return 200
|
||||||
|
|
||||||
def response(self, data):
|
def response(self, data):
|
||||||
return json.dumps(data, default=obj_dict)
|
return json.dumps(data, default=obj_dict)
|
||||||
|
|
||||||
|
|
||||||
class RequestCode_HTTP_201_CREATED(RequestStatusCode):
|
class RequestCode_HTTP_201_CREATED(RequestStatusCode):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
@ -60,10 +60,10 @@ class RequestCode_HTTP_201_CREATED(RequestStatusCode):
|
|||||||
|
|
||||||
def __call__(self, data):
|
def __call__(self, data):
|
||||||
return (self.response(data), self.status_code(), self.headers())
|
return (self.response(data), self.status_code(), self.headers())
|
||||||
|
|
||||||
def status_code(self):
|
def status_code(self):
|
||||||
return 201
|
return 201
|
||||||
|
|
||||||
def response(self, new_id):
|
def response(self, new_id):
|
||||||
return json.dumps({"id":new_id})
|
return json.dumps({"id":new_id})
|
||||||
|
|
||||||
@ -74,10 +74,10 @@ class RequestCode_HTTP_400_BAD_REQUEST(RequestStatusCode):
|
|||||||
|
|
||||||
def __call__(self, data):
|
def __call__(self, data):
|
||||||
return (self.response(data), self.status_code(), self.headers())
|
return (self.response(data), self.status_code(), self.headers())
|
||||||
|
|
||||||
def status_code(self):
|
def status_code(self):
|
||||||
return 400
|
return 400
|
||||||
|
|
||||||
def response(self, data):
|
def response(self, data):
|
||||||
return json.dumps(data)
|
return json.dumps(data)
|
||||||
|
|
||||||
@ -88,15 +88,15 @@ class RequestCode_HTTP_403_FORBIDDEN(RequestStatusCode):
|
|||||||
|
|
||||||
def __call__(self, data):
|
def __call__(self, data):
|
||||||
return (self.response(data), self.status_code(), self.headers())
|
return (self.response(data), self.status_code(), self.headers())
|
||||||
|
|
||||||
def status_code(self):
|
def status_code(self):
|
||||||
return 403
|
return 403
|
||||||
|
|
||||||
def response(self, message="invalid credentials"):
|
def response(self, message="invalid credentials"):
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = message
|
result["error_field"] = message
|
||||||
return json.dumps(result)
|
return json.dumps(result)
|
||||||
|
|
||||||
|
|
||||||
class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode):
|
class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
@ -104,13 +104,13 @@ class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode):
|
|||||||
|
|
||||||
def __call__(self, data):
|
def __call__(self, data):
|
||||||
return (self.response(data), self.status_code(), self.headers())
|
return (self.response(data), self.status_code(), self.headers())
|
||||||
|
|
||||||
def status_code(self):
|
def status_code(self):
|
||||||
return 404
|
return 404
|
||||||
|
|
||||||
def response(self, message="no such record"):
|
def response(self, message="no such record"):
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = message
|
result["error_field"] = message
|
||||||
return json.dumps(result)
|
return json.dumps(result)
|
||||||
|
|
||||||
|
|
||||||
@ -120,12 +120,12 @@ class RequestCode_HTTP_500_INTERNAL_SERVER_ERROR(RequestStatusCode):
|
|||||||
|
|
||||||
def __call__(self, data):
|
def __call__(self, data):
|
||||||
return (self.response(data), self.status_code(), self.headers())
|
return (self.response(data), self.status_code(), self.headers())
|
||||||
|
|
||||||
def status_code(self):
|
def status_code(self):
|
||||||
return 500
|
return 500
|
||||||
|
|
||||||
def response(self, message="credential lookup mismatch"):
|
def response(self, message="credential lookup mismatch"):
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = message
|
result["error_field"] = message
|
||||||
return json.dumps(result)
|
return json.dumps(result)
|
||||||
|
|
||||||
|
|||||||
@ -47,17 +47,10 @@ class PierSide(IntEnum):
|
|||||||
"""These enumerators determine the pier side of a shipcall."""
|
"""These enumerators determine the pier side of a shipcall."""
|
||||||
PORTSIDE = 0 # Port/Backbord
|
PORTSIDE = 0 # Port/Backbord
|
||||||
STARBOARD_SIDE = 1 # Starboard / Steuerbord
|
STARBOARD_SIDE = 1 # Starboard / Steuerbord
|
||||||
|
|
||||||
class NotificationType(IntFlag):
|
|
||||||
"""determines the method by which a notification is distributed to users. Flagging allows selecting multiple notification types."""
|
|
||||||
UNDEFINED = 0
|
|
||||||
EMAIL = 1
|
|
||||||
POPUP = 2
|
|
||||||
MESSENGER = 4
|
|
||||||
|
|
||||||
class ParticipantFlag(IntFlag):
|
class ParticipantFlag(IntFlag):
|
||||||
"""
|
"""
|
||||||
| 1 | If this flag is set on a shipcall record with participant type Agency (8),
|
| 1 | If this flag is set on a shipcall record with participant type Agency (8),
|
||||||
all participants of type BSMD (1) may edit the record.
|
all participants of type BSMD (1) may edit the record.
|
||||||
"""
|
"""
|
||||||
undefined = 0
|
undefined = 0
|
||||||
|
|||||||
@ -8,22 +8,40 @@ def create_sql_query_shipcall_get(options:dict)->str:
|
|||||||
|
|
||||||
args:
|
args:
|
||||||
options : dict. A dictionary, which must contains the 'past_days' key (int). Determines the range
|
options : dict. A dictionary, which must contains the 'past_days' key (int). Determines the range
|
||||||
by which shipcalls are filtered.
|
by which shipcalls are filtered.
|
||||||
"""
|
"""
|
||||||
query = ("SELECT s.id as id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
|
if "participant_id" not in options: # if no participant_id is given, all shipcalls are selected
|
||||||
"flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
|
query = ("SELECT s.id as id, ship_id, port_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
|
||||||
"tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
|
"flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
|
||||||
"evaluation_message, evaluation_time, evaluation_notifications_sent, s.created as created, s.modified as modified, time_ref_point " +
|
"tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
|
||||||
"FROM shipcall s " +
|
"evaluation_message, evaluation_time, evaluation_notifications_sent, s.created as created, s.modified as modified, time_ref_point " +
|
||||||
"LEFT JOIN times t ON t.shipcall_id = s.id AND t.participant_type = 8 " +
|
"FROM shipcall s " +
|
||||||
"WHERE " +
|
"LEFT JOIN times t ON t.shipcall_id = s.id AND t.participant_type = 8 " +
|
||||||
"(type = 1 AND " +
|
"WHERE " +
|
||||||
"((t.id IS NOT NULL AND t.eta_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
"(type = 1 AND " +
|
||||||
"(eta >= DATE(NOW() - INTERVAL %d DAY)))) OR " +
|
"((t.id IS NOT NULL AND t.eta_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||||
"((type = 2 OR type = 3) AND " +
|
"(eta >= DATE(NOW() - INTERVAL %d DAY)))) OR " +
|
||||||
"((t.id IS NOT NULL AND t.etd_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
"((type = 2 OR type = 3) AND " +
|
||||||
"(etd >= DATE(NOW() - INTERVAL %d DAY)))) " +
|
"((t.id IS NOT NULL AND t.etd_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||||
"ORDER BY eta") % (options["past_days"], options["past_days"], options["past_days"], options["past_days"])
|
"(etd >= DATE(NOW() - INTERVAL %d DAY)))) " +
|
||||||
|
"ORDER BY eta") % (options["past_days"], options["past_days"], options["past_days"], options["past_days"])
|
||||||
|
else:
|
||||||
|
query = ("SELECT s.id as id, ship_id, port_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
|
||||||
|
"flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
|
||||||
|
"tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
|
||||||
|
"evaluation_message, evaluation_time, evaluation_notifications_sent, s.created as created, s.modified as modified, time_ref_point " +
|
||||||
|
"FROM shipcall s " +
|
||||||
|
"LEFT JOIN times t ON t.shipcall_id = s.id AND t.participant_type = 8 " +
|
||||||
|
"WHERE " +
|
||||||
|
"port_id in (SELECT port_id FROM participant_port_map WHERE participant_id = %d)" +
|
||||||
|
" AND (" +
|
||||||
|
"(type = 1 AND " +
|
||||||
|
"((t.id IS NOT NULL AND t.eta_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||||
|
"(eta >= DATE(NOW() - INTERVAL %d DAY)))) OR " +
|
||||||
|
"((type = 2 OR type = 3) AND " +
|
||||||
|
"((t.id IS NOT NULL AND t.etd_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||||
|
"(etd >= DATE(NOW() - INTERVAL %d DAY))))) " +
|
||||||
|
"ORDER BY eta") % (options["participant_id"], options["past_days"], options["past_days"], options["past_days"], options["past_days"])
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@ -43,9 +61,9 @@ def create_sql_query_shipcall_post(schemaModel:dict)->str:
|
|||||||
if key == "evaluation":
|
if key == "evaluation":
|
||||||
continue
|
continue
|
||||||
if key == "evaluation_message":
|
if key == "evaluation_message":
|
||||||
continue
|
continue
|
||||||
if key == "type_value":
|
if key == "type_value":
|
||||||
continue
|
continue
|
||||||
if key == "evaluation_value":
|
if key == "evaluation_value":
|
||||||
continue
|
continue
|
||||||
if isNotFirst:
|
if isNotFirst:
|
||||||
@ -196,12 +214,12 @@ def create_sql_query_ship_put(schemaModel:dict):
|
|||||||
class SQLQuery():
|
class SQLQuery():
|
||||||
"""
|
"""
|
||||||
This class provides quick access to different SQL query functions, which creates default queries for the BreCal package.
|
This class provides quick access to different SQL query functions, which creates default queries for the BreCal package.
|
||||||
Each method is callable without initializing the SQLQuery object.
|
Each method is callable without initializing the SQLQuery object.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
SQLQuery.get_berths()
|
SQLQuery.get_berths()
|
||||||
|
|
||||||
When the data violates one of the rules, a marshmallow.ValidationError is raised, which details the issues.
|
When the data violates one of the rules, a marshmallow.ValidationError is raised, which details the issues.
|
||||||
"""
|
"""
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
pass
|
pass
|
||||||
@ -215,30 +233,30 @@ class SQLQuery():
|
|||||||
def get_history()->str:
|
def get_history()->str:
|
||||||
query = "SELECT id, participant_id, shipcall_id, timestamp, eta, type, operation FROM history WHERE shipcall_id = ?shipcallid?"
|
query = "SELECT id, participant_id, shipcall_id, timestamp, eta, type, operation FROM history WHERE shipcall_id = ?shipcallid?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user()->str:
|
def get_user()->str:
|
||||||
query = "SELECT id, participant_id, first_name, last_name, user_name, user_email, user_phone, password_hash, " +\
|
query = "SELECT id, participant_id, first_name, last_name, user_name, user_email, user_phone, password_hash, " +\
|
||||||
"api_key, notify_email, notify_whatsapp, notify_signal, notify_popup, created, modified FROM user " +\
|
"api_key, notify_email, notify_whatsapp, notify_signal, notify_popup, notify_event, created, modified FROM user " +\
|
||||||
"WHERE user_name = ?username? OR user_email = ?username?"
|
"WHERE user_name = ?username? OR user_email = ?username?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_notifications()->str:
|
def get_notifications()->str:
|
||||||
query = "SELECT id, shipcall_id, level, type, message, created, modified FROM notification " + \
|
query = "SELECT id, shipcall_id, level, type, message, created, modified FROM notification " + \
|
||||||
"WHERE shipcall_id = ?scid?"
|
"WHERE shipcall_id = ?scid?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_participant_by_user_id()->str:
|
def get_participant_by_user_id()->str:
|
||||||
query = "SELECT p.id as id, p.name as name, p.street as street, p.postal_code as postal_code, p.city as city, p.type as type, p.flags as flags, p.created as created, p.modified as modified, p.deleted as deleted FROM participant p INNER JOIN user u WHERE u.participant_id = p.id and u.id = ?userid?"
|
query = "SELECT p.id as id, p.name as name, p.street as street, p.postal_code as postal_code, p.city as city, p.type as type, p.flags as flags, p.created as created, p.modified as modified, p.deleted as deleted FROM participant p INNER JOIN user u WHERE u.participant_id = p.id and u.id = ?userid?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_participants()->str:
|
def get_participants()->str:
|
||||||
query = "SELECT id, name, street, postal_code, city, type, flags, created, modified, deleted FROM participant p ORDER BY p.name"
|
query = "SELECT id, name, street, postal_code, city, type, flags, created, modified, deleted FROM participant p ORDER BY p.name"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_shipcalls(options:dict={'past_days':3})->str:
|
def get_shipcalls(options:dict={'past_days':3})->str:
|
||||||
# a pytest proves this method to be identical to create_sql_query_shipcall_get(options)
|
# a pytest proves this method to be identical to create_sql_query_shipcall_get(options)
|
||||||
@ -260,17 +278,24 @@ class SQLQuery():
|
|||||||
f"(etd >= DATE(NOW() - INTERVAL {past_days} DAY)))) " + \
|
f"(etd >= DATE(NOW() - INTERVAL {past_days} DAY)))) " + \
|
||||||
"ORDER BY eta")
|
"ORDER BY eta")
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
def get_next24hrs_shipcalls()->str:
|
||||||
|
query = ("SELECT s.id as id, ship.name as name FROM shipcall s INNER JOIN ship ON s.ship_id = ship.id LEFT JOIN times t on t.shipcall_id = s.id AND t.participant_type = 8 " + \
|
||||||
|
"WHERE (type = 1 AND (COALESCE(t.eta_berth, eta) >= NOW() AND COALESCE(t.eta_berth, eta) < (NOW() + INTERVAL 1 DAY)))" + \
|
||||||
|
"OR ((type = 2 OR type = 3) AND (COALESCE(t.etd_berth, etd) >= NOW() AND COALESCE(t.etd_berth, etd) < (NOW() + INTERVAL 1 DAY)))"
|
||||||
|
"AND s.canceled = 0")
|
||||||
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_ships()->str:
|
def get_ships()->str:
|
||||||
query = "SELECT id, name, imo, callsign, participant_id, length, width, is_tug, bollard_pull, eni, created, modified, deleted FROM ship ORDER BY name"
|
query = "SELECT id, name, imo, callsign, participant_id, length, width, is_tug, bollard_pull, eni, created, modified, deleted FROM ship ORDER BY name"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_ship_by_id()->str:
|
def get_ship_by_id()->str:
|
||||||
query = "SELECT * FROM ship where id = ?id?"
|
query = "SELECT * FROM ship where id = ?id?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_times()->str:
|
def get_times()->str:
|
||||||
query = "SELECT id, eta_berth, eta_berth_fixed, etd_berth, etd_berth_fixed, lock_time, lock_time_fixed, " + \
|
query = "SELECT id, eta_berth, eta_berth_fixed, etd_berth, etd_berth_fixed, lock_time, lock_time_fixed, " + \
|
||||||
@ -278,12 +303,12 @@ class SQLQuery():
|
|||||||
"berth_id, berth_info, pier_side, participant_type, created, modified, ata, atd, eta_interval_end, etd_interval_end FROM times " + \
|
"berth_id, berth_info, pier_side, participant_type, created, modified, ata, atd, eta_interval_end, etd_interval_end FROM times " + \
|
||||||
"WHERE times.shipcall_id = ?scid?"
|
"WHERE times.shipcall_id = ?scid?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user_by_id():
|
def get_user_by_id():
|
||||||
query = "SELECT * FROM user where id = ?id?"
|
query = "SELECT * FROM user where id = ?id?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user_put(schemaModel:dict):
|
def get_user_put(schemaModel:dict):
|
||||||
# a pytest proves this method to be identical to create_sql_query_user_put(schemaModel)
|
# a pytest proves this method to be identical to create_sql_query_user_put(schemaModel)
|
||||||
@ -308,7 +333,7 @@ class SQLQuery():
|
|||||||
def get_participant_from_id()->str:
|
def get_participant_from_id()->str:
|
||||||
query = "SELECT id, type, flags FROM participant WHERE id=?participant_id?"
|
query = "SELECT id, type, flags FROM participant WHERE id=?participant_id?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_shipcall_post(schemaModel:dict)->str:
|
def get_shipcall_post(schemaModel:dict)->str:
|
||||||
# a pytest proves this method to be identical to create_sql_query_shipcall_post(schemaModel)
|
# a pytest proves this method to be identical to create_sql_query_shipcall_post(schemaModel)
|
||||||
@ -331,28 +356,28 @@ class SQLQuery():
|
|||||||
def get_last_insert_id()->str:
|
def get_last_insert_id()->str:
|
||||||
query = "select last_insert_id()"
|
query = "select last_insert_id()"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_shipcall_post_last_insert_id()->str:
|
def get_shipcall_post_last_insert_id()->str:
|
||||||
"""alias function. May be deleted soon"""
|
"""alias function. May be deleted soon"""
|
||||||
query = SQLQuery.get_last_insert_id()
|
query = SQLQuery.get_last_insert_id()
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_shipcall_post_update_shipcall_participant_map()->str:
|
def get_shipcall_post_update_shipcall_participant_map()->str:
|
||||||
query = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
query = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_sql_query_history_post()->str:
|
def create_sql_query_history_post()->str:
|
||||||
query = create_sql_query_history_post()
|
query = create_sql_query_history_post()
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_shipcall_by_id()->str:
|
def get_shipcall_by_id()->str:
|
||||||
query = "SELECT * FROM shipcall where id = ?id?"
|
query = "SELECT * FROM shipcall where id = ?id?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_shipcall_put(schemaModel:dict)->str:
|
def get_shipcall_put(schemaModel:dict)->str:
|
||||||
# a pytest proves this method to be identical to create_sql_query_shipcall_put(schemaModel)
|
# a pytest proves this method to be identical to create_sql_query_shipcall_put(schemaModel)
|
||||||
@ -366,12 +391,12 @@ class SQLQuery():
|
|||||||
|
|
||||||
query = prefix + body + suffix
|
query = prefix + body + suffix
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_shipcall_participant_map_by_shipcall_id()->str:
|
def get_shipcall_participant_map_by_shipcall_id()->str:
|
||||||
query = "SELECT id, participant_id, type FROM shipcall_participant_map where shipcall_id = ?id?"
|
query = "SELECT id, participant_id, type FROM shipcall_participant_map where shipcall_id = ?id?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_shipcall_participant_map_by_shipcall_id_and_type()->str:
|
def get_shipcall_participant_map_by_shipcall_id_and_type()->str:
|
||||||
query = "SELECT id, participant_id FROM shipcall_participant_map where (shipcall_id = ?id? AND type=?type?)"
|
query = "SELECT id, participant_id FROM shipcall_participant_map where (shipcall_id = ?id? AND type=?type?)"
|
||||||
@ -414,14 +439,14 @@ class SQLQuery():
|
|||||||
def get_ship_delete_by_id()->str:
|
def get_ship_delete_by_id()->str:
|
||||||
query = "UPDATE ship SET deleted = 1 WHERE id = ?id?"
|
query = "UPDATE ship SET deleted = 1 WHERE id = ?id?"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_notification_post()->str:
|
def get_notification_post()->str:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
# #TODO: this query is wrong and just a proxy for a POST request
|
# #TODO: this query is wrong and just a proxy for a POST request
|
||||||
query = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
query = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_shipcall_put_notification_state()->str:
|
def get_shipcall_put_notification_state()->str:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|||||||
@ -1,22 +1,43 @@
|
|||||||
from BreCal.database.sql_handler import execute_sql_query_standalone
|
from BreCal.database.sql_handler import execute_sql_query_standalone
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
def get_user_data_for_id(user_id:int, expiration_time:int=90):
|
def get_user_data_for_id(user_id:int, expiration_time:int=90):
|
||||||
"""debugging function, which is useful to pull user_data from the database, which may be used to create stub data and unit tests"""
|
"""debugging function, which is useful to pull user_data from the database, which may be used to create stub data and unit tests"""
|
||||||
query = "SELECT * FROM user where id = ?id?"
|
query = "SELECT * FROM user where id = ?id?"
|
||||||
pdata = execute_sql_query_standalone(query=query, param={"id":user_id})
|
pdata = execute_sql_query_standalone(query=query, param={"id":user_id}, command_type="single_or_none")
|
||||||
pdata = pdata[0] if len(pdata)>0 else None
|
|
||||||
assert pdata is not None, f"could not find user with id {user_id}"
|
assert pdata is not None, f"could not find user with id {user_id}"
|
||||||
|
|
||||||
user_data = {k:v for k,v in pdata.items() if k in ['id','participant_id','first_name','last_name','user_name','user_phone','user_email']}
|
user_data = {k:v for k,v in pdata.items() if k in ['id','participant_id','first_name','last_name','user_name','user_phone','user_email']}
|
||||||
user_data["exp"] = (datetime.datetime.now()+datetime.timedelta(minutes=expiration_time)).timestamp()
|
user_data["exp"] = (datetime.datetime.now()+datetime.timedelta(minutes=expiration_time)).timestamp()
|
||||||
return user_data
|
return user_data
|
||||||
|
|
||||||
|
|
||||||
def get_times_data_for_id(times_id:int):
|
def get_times_data_for_id(times_id:int):
|
||||||
"""helper function to load previous times data from the database"""
|
"""helper function to load previous times data from the database"""
|
||||||
query = "SELECT * FROM times where id = ?id?"
|
query = "SELECT * FROM times where id = ?id?"
|
||||||
pdata = execute_sql_query_standalone(query=query, param={"id":times_id})
|
pdata = execute_sql_query_standalone(query=query, param={"id":times_id}, command_type="single_or_none")
|
||||||
pdata = pdata[0] if len(pdata)>0 else None
|
return pdata
|
||||||
assert pdata is not None, f"could not find times with id {times_id}"
|
|
||||||
|
def get_ship_data_for_id(ship_id:int):
|
||||||
|
"""helper function to load previous ship data from the database"""
|
||||||
|
query = "SELECT * FROM ship where id = ?id?"
|
||||||
|
pdata = execute_sql_query_standalone(query=query, param={"id":ship_id}, command_type="single_or_none")
|
||||||
|
return pdata
|
||||||
|
|
||||||
|
def get_shipcall_data_for_id(shipcall_id:int):
|
||||||
|
"""helper function to load previous shipcall data from the database"""
|
||||||
|
query = "SELECT * FROM shipcall where id = ?id?"
|
||||||
|
pdata = execute_sql_query_standalone(query=query, param={"id":shipcall_id}, command_type="single_or_none")
|
||||||
|
return pdata
|
||||||
|
|
||||||
|
def get_port_ids_for_participant_id(participant_id:int):
|
||||||
|
"""helper function to load all port ids for a participant"""
|
||||||
|
query = "SELECT port_id FROM participant_port_map where participant_id = ?participant_id?"
|
||||||
|
pdata = execute_sql_query_standalone(query=query, param={"participant_id":participant_id})
|
||||||
|
return pdata
|
||||||
|
|
||||||
|
def get_notification_for_shipcall_and_type(shipcall_id:int, notification_type:int):
|
||||||
|
"""helper function to load a notification for a shipcall and a specific type"""
|
||||||
|
query = "SELECT * FROM notification where shipcall_id = ?shipcall_id? and type = ?type?"
|
||||||
|
pdata = execute_sql_query_standalone(query=query, param={"shipcall_id":shipcall_id, "type":notification_type}, command_type="query")
|
||||||
return pdata
|
return pdata
|
||||||
@ -6,4 +6,5 @@ from . import times
|
|||||||
from . import ships
|
from . import ships
|
||||||
from . import login
|
from . import login
|
||||||
from . import user
|
from . import user
|
||||||
from . import history
|
from . import history
|
||||||
|
from . import ports
|
||||||
@ -4,26 +4,35 @@ import pydapper
|
|||||||
|
|
||||||
from ..schemas import model
|
from ..schemas import model
|
||||||
from .. import local_db
|
from .. import local_db
|
||||||
from BreCal.database.sql_queries import SQLQuery
|
|
||||||
|
|
||||||
def GetBerths(token):
|
def GetBerths(options):
|
||||||
"""
|
"""
|
||||||
No parameters, gets all entries
|
No parameters, gets all entries
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
# query = SQLQuery.get_berth()
|
|
||||||
# data = commands.query(query, model=model.Berth)
|
# only load berths to ports that the participant is assigned to
|
||||||
data = commands.query("SELECT id, name, `lock`, owner_id, authority_id, created, modified, deleted FROM berth WHERE deleted = 0 ORDER BY name", model=model.Berth)
|
if "participant_id" in options:
|
||||||
|
query = ("SELECT id, name, `lock`, owner_id, port_id, authority_id, created, modified, deleted FROM berth WHERE " +
|
||||||
|
"deleted = 0 AND + "
|
||||||
|
"port_id IN (SELECT port_id FROM participant_port_map WHERE participant_id = %d) " +
|
||||||
|
"ORDER BY name") % (options["participant_id"])
|
||||||
|
else:
|
||||||
|
query = ("SELECT id, name, `lock`, owner_id, port_id, authority_id, created, modified, deleted FROM berth WHERE " +
|
||||||
|
"deleted = 0 ORDER BY name")
|
||||||
|
|
||||||
|
data = commands.query(query, model=model.Berth)
|
||||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps(result), 500
|
return json.dumps(result), 500
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@ -16,6 +16,8 @@ def GetHistory(options):
|
|||||||
options["shipcall_id"]: **Id of shipcall**.
|
options["shipcall_id"]: **Id of shipcall**.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pooledConnection = None
|
||||||
|
data = []
|
||||||
try:
|
try:
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
@ -26,17 +28,16 @@ def GetHistory(options):
|
|||||||
data = commands.query("SELECT id, participant_id, shipcall_id, timestamp, eta, type, operation FROM history WHERE shipcall_id = ?shipcallid?",
|
data = commands.query("SELECT id, participant_id, shipcall_id, timestamp, eta, type, operation FROM history WHERE shipcall_id = ?shipcallid?",
|
||||||
model=History.from_query_row,
|
model=History.from_query_row,
|
||||||
param={"shipcallid" : options["shipcall_id"]})
|
param={"shipcallid" : options["shipcall_id"]})
|
||||||
|
|
||||||
|
|
||||||
pooledConnection.close()
|
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
pdb.pm()
|
pdb.pm()
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps("call failed"), 500
|
return json.dumps("call failed"), 500
|
||||||
|
finally:
|
||||||
|
if pooledConnection is not None:
|
||||||
|
pooledConnection.close()
|
||||||
|
|
||||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
|
|||||||
@ -6,22 +6,25 @@ import bcrypt
|
|||||||
from ..schemas import model
|
from ..schemas import model
|
||||||
from .. import local_db
|
from .. import local_db
|
||||||
from ..services import jwt_handler
|
from ..services import jwt_handler
|
||||||
from BreCal.database.sql_queries import SQLQuery
|
|
||||||
|
|
||||||
|
|
||||||
def GetUser(options):
|
def GetUser(options):
|
||||||
|
|
||||||
|
pooledConnection = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if "password" in options and "username" in options:
|
if "password" in options and "username" in options:
|
||||||
hash = bcrypt.hashpw(options["password"].encode('utf-8'), bcrypt.gensalt( 12 )).decode('utf8')
|
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
# query = SQLQuery.get_user()
|
# query = SQLQuery.get_user()
|
||||||
# data = commands.query(query, model=model.User, param={"username" : options["username"]})
|
# data = commands.query(query, model=model.User, param={"username" : options["username"]})
|
||||||
data = commands.query("SELECT id, participant_id, first_name, last_name, user_name, user_email, user_phone, password_hash, " +
|
data = commands.query("SELECT id, participant_id, first_name, last_name, user_name, user_email, user_phone, password_hash, " +
|
||||||
"api_key, notify_email, notify_whatsapp, notify_signal, notify_popup, created, modified FROM user " +
|
"api_key, notify_email, notify_whatsapp, notify_signal, notify_popup, notify_event, created, modified FROM user " +
|
||||||
"WHERE user_name = ?username? OR user_email = ?username?",
|
"WHERE user_name = ?username? OR user_email = ?username?",
|
||||||
model=model.User, param={"username" : options["username"]})
|
model=model.User, param={"username" : options["username"]})
|
||||||
|
|
||||||
if len(data) == 1:
|
if len(data) == 1:
|
||||||
if bcrypt.checkpw(options["password"].encode("utf-8"), bytes(data[0].password_hash, "utf-8")):
|
if bcrypt.checkpw(options["password"].encode("utf-8"), bytes(data[0].password_hash, "utf-8")):
|
||||||
result = {
|
result = {
|
||||||
@ -31,7 +34,12 @@ def GetUser(options):
|
|||||||
"last_name": data[0].last_name,
|
"last_name": data[0].last_name,
|
||||||
"user_name": data[0].user_name,
|
"user_name": data[0].user_name,
|
||||||
"user_phone": data[0].user_phone,
|
"user_phone": data[0].user_phone,
|
||||||
"user_email": data[0].user_email
|
"user_email": data[0].user_email,
|
||||||
|
"notify_email": data[0].notify_email,
|
||||||
|
"notify_whatsapp": data[0].notify_whatsapp,
|
||||||
|
"notify_signal": data[0].notify_signal,
|
||||||
|
"notify_popup": data[0].notify_popup,
|
||||||
|
"notify_on": model.notification_types_to_names(model.bitflag_to_list(data[0].notify_event))
|
||||||
}
|
}
|
||||||
token = jwt_handler.generate_jwt(payload=result, lifetime=120) # generate token valid 60 mins
|
token = jwt_handler.generate_jwt(payload=result, lifetime=120) # generate token valid 60 mins
|
||||||
result["token"] = token # add token to user data
|
result["token"] = token # add token to user data
|
||||||
@ -39,24 +47,21 @@ def GetUser(options):
|
|||||||
|
|
||||||
if len(data) > 1:
|
if len(data) > 1:
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "credential lookup mismatch"
|
result["error_field"] = "credential lookup mismatch"
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "invalid credentials"
|
result["error_field"] = "invalid credentials"
|
||||||
return json.dumps(result), 403, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 403, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed: " + str(ex)
|
result["error_field"] = "call failed"
|
||||||
|
result["error_description"] = str(ex)
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
if pooledConnection is not None:
|
if pooledConnection is not None:
|
||||||
pooledConnection.close()
|
pooledConnection.close()
|
||||||
|
|
||||||
# $2b$12$uWLE0r32IrtCV30WkMbVwOdltgeibymZyYAf4ZnQb2Bip8hrkGGwG
|
|
||||||
# $2b$12$.vEapj9xU8z0RK0IpIGeYuRIl0ktdMt4XdJQBhVn.3K2hmvm7qD3y
|
|
||||||
# $2b$12$yL3PiseU70ciwEuMVM4OtuMwR6tNuIT9vvBiBG/uyMrPxa16E2Zqu
|
|
||||||
@ -6,29 +6,32 @@ from ..schemas import model
|
|||||||
from .. import local_db
|
from .. import local_db
|
||||||
from BreCal.database.sql_queries import SQLQuery
|
from BreCal.database.sql_queries import SQLQuery
|
||||||
|
|
||||||
def GetNotifications(options):
|
def GetNotifications(token, participant_id=None):
|
||||||
"""
|
"""
|
||||||
:param options: A dictionary containing all the paramters for the Operations
|
Optional filtering by participant_id. Returns delivered (level=2) notifications.
|
||||||
options["shipcall_id"]: **Id**. *Example: 42*. Id of referenced ship call.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
|
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
# query = SQLQuery.get_notifications()
|
query = "SELECT id, shipcall_id, participant_id, level, type, message, created, modified FROM notification WHERE level = 2"
|
||||||
# data = commands.query(query, model=model.Notification.from_query_row, param={"scid" : options["shipcall_id"]})
|
params = {}
|
||||||
data = commands.query("SELECT id, shipcall_id, level, type, message, created, modified FROM notification " +
|
if participant_id is not None:
|
||||||
"WHERE shipcall_id = ?scid?", model=model.Notification.from_query_row, param={"scid" : options["shipcall_id"]})
|
query += " AND participant_id = ?participant_id?"
|
||||||
pooledConnection.close()
|
params["participant_id"] = participant_id
|
||||||
|
|
||||||
|
data = commands.query(query, model=model.Notification.from_query_row, param=params if params else None)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
finally:
|
||||||
|
if pooledConnection is not None:
|
||||||
|
pooledConnection.close()
|
||||||
|
|
||||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
|
|||||||
@ -10,18 +10,47 @@ def GetParticipant(options):
|
|||||||
"""
|
"""
|
||||||
:param options: A dictionary containing all the paramters for the Operations
|
:param options: A dictionary containing all the paramters for the Operations
|
||||||
options["user_id"]: **Id of user**. *Example: 2*. User id returned by login call.
|
options["user_id"]: **Id of user**. *Example: 2*. User id returned by login call.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
if "user_id" in options and options["user_id"]:
|
if "user_id" in options and options["user_id"]:
|
||||||
# query = SQLQuery.get_participant_by_user_id()
|
# query = SQLQuery.get_participant_by_user_id()
|
||||||
data = commands.query("SELECT p.id as id, p.name as name, p.street as street, p.postal_code as postal_code, p.city as city, p.type as type, p.flags as flags, p.created as created, p.modified as modified, p.deleted as deleted FROM participant p INNER JOIN user u WHERE u.participant_id = p.id and u.id = ?userid?", model=model.Participant, param={"userid" : options["user_id"]})
|
query = ("SELECT p.id as id, p.name as name, p.street as street, p.postal_code as postal_code, p.city as city, p.type as type, p.flags as flags, " +
|
||||||
|
"p.created as created, p.modified as modified, p.deleted as deleted FROM participant p " +
|
||||||
|
"INNER JOIN user u WHERE u.participant_id = p.id and u.id = %s") % options["user_id"]
|
||||||
|
data = commands.query(query, model=model.Participant)
|
||||||
|
for participant in data:
|
||||||
|
port_query = "SELECT port_id FROM participant_port_map WHERE participant_id=?id?"
|
||||||
|
for record in commands.query(port_query, model=model.Port_Assignment, param={"id" : participant.id}, buffered=False):
|
||||||
|
pa = model.Port_Assignment(record.port_id)
|
||||||
|
participant.ports.append(pa.port_id)
|
||||||
else:
|
else:
|
||||||
# query = SQLQuery.get_participants()
|
# query = SQLQuery.get_participants()
|
||||||
data = commands.query("SELECT id, name, street, postal_code, city, type, flags, created, modified, deleted FROM participant p ORDER BY p.name", model=model.Participant)
|
if "participant_id" in options:
|
||||||
|
# list only participants that are assigned to the same ports than participant of caller
|
||||||
|
query = ("SELECT p.id as id, name, street, postal_code, city, type, flags, p.created, p.modified, p.deleted " +
|
||||||
|
"FROM participant p " +
|
||||||
|
"JOIN participant_port_map ON p.id = participant_port_map.participant_id " +
|
||||||
|
"WHERE participant_port_map.port_id IN " +
|
||||||
|
"(SELECT port_id FROM participant_port_map where participant_id = %s) " +
|
||||||
|
"GROUP BY id " +
|
||||||
|
"ORDER BY p.name") % options["participant_id"]
|
||||||
|
else:
|
||||||
|
query = ("SELECT p.id as id, name, street, postal_code, city, type, flags, p.created, p.modified, p.deleted " +
|
||||||
|
"FROM participant p " +
|
||||||
|
"JOIN participant_port_map ON p.id = participant_port_map.participant_id " +
|
||||||
|
"GROUP BY id " +
|
||||||
|
"ORDER BY p.name")
|
||||||
|
|
||||||
|
data = commands.query(query, model=model.Participant)
|
||||||
|
for participant in data:
|
||||||
|
port_query = "SELECT port_id FROM participant_port_map WHERE participant_id=?id?"
|
||||||
|
for record in commands.query(port_query, model=model.Port_Assignment, param={"id" : participant.id}, buffered=False):
|
||||||
|
pa = model.Port_Assignment(record.port_id)
|
||||||
|
participant.ports.append(pa.port_id)
|
||||||
|
|
||||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
@ -29,7 +58,7 @@ def GetParticipant(options):
|
|||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps("call failed"), 500
|
return json.dumps("call failed"), 500
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
34
src/server/BreCal/impl/ports.py
Normal file
34
src/server/BreCal/impl/ports.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import pydapper
|
||||||
|
|
||||||
|
from ..schemas import model
|
||||||
|
from .. import local_db
|
||||||
|
from BreCal.database.sql_queries import SQLQuery
|
||||||
|
|
||||||
|
def GetPorts(token):
|
||||||
|
"""
|
||||||
|
No parameters, gets all entries
|
||||||
|
"""
|
||||||
|
|
||||||
|
pooledConnection = None
|
||||||
|
try:
|
||||||
|
pooledConnection = local_db.getPoolConnection()
|
||||||
|
commands = pydapper.using(pooledConnection)
|
||||||
|
data = commands.query("SELECT id, name, locode, created, modified, deleted FROM port ORDER BY name", model=model.Port)
|
||||||
|
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
logging.error(ex)
|
||||||
|
print(ex)
|
||||||
|
result = {}
|
||||||
|
result["error_field"] = "call failed"
|
||||||
|
return json.dumps(result), 500
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if pooledConnection is not None:
|
||||||
|
pooledConnection.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -8,7 +8,8 @@ from .. import local_db
|
|||||||
from ..services.auth_guard import check_jwt
|
from ..services.auth_guard import check_jwt
|
||||||
|
|
||||||
from BreCal.database.update_database import evaluate_shipcall_state
|
from BreCal.database.update_database import evaluate_shipcall_state
|
||||||
from BreCal.database.sql_queries import create_sql_query_shipcall_get, create_sql_query_shipcall_post, create_sql_query_shipcall_put, create_sql_query_history_post, create_sql_query_history_put, SQLQuery
|
from BreCal.database.sql_utils import get_notification_for_shipcall_and_type, get_ship_data_for_id
|
||||||
|
from BreCal.database.sql_queries import create_sql_query_shipcall_get
|
||||||
from marshmallow import Schema, fields, ValidationError
|
from marshmallow import Schema, fields, ValidationError
|
||||||
from BreCal.validators.validation_error import create_validation_error_response
|
from BreCal.validators.validation_error import create_validation_error_response
|
||||||
|
|
||||||
@ -17,8 +18,8 @@ def GetShipcalls(options):
|
|||||||
No parameters, gets all entries
|
No parameters, gets all entries
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
|
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
# query = SQLQuery.get_shipcalls(options)
|
# query = SQLQuery.get_shipcalls(options)
|
||||||
@ -42,7 +43,7 @@ def GetShipcalls(options):
|
|||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -52,8 +53,8 @@ def GetShipcalls(options):
|
|||||||
|
|
||||||
def PostShipcalls(schemaModel):
|
def PostShipcalls(schemaModel):
|
||||||
"""
|
"""
|
||||||
This function *executes* a post-request for shipcalls. The function is accessible as part of an API route.
|
This function *executes* a post-request for shipcalls. The function is accessible as part of an API route.
|
||||||
|
|
||||||
The common sequence is:
|
The common sequence is:
|
||||||
a) issue a request to the Flask API
|
a) issue a request to the Flask API
|
||||||
b) BreCal.api.shipcalls.PostShipcalls, to verify the incoming request (which includes an authentification guard)
|
b) BreCal.api.shipcalls.PostShipcalls, to verify the incoming request (which includes an authentification guard)
|
||||||
@ -62,19 +63,20 @@ def PostShipcalls(schemaModel):
|
|||||||
:param schemaModel: The deserialized dict of the request
|
:param schemaModel: The deserialized dict of the request
|
||||||
e.g.,
|
e.g.,
|
||||||
{
|
{
|
||||||
'ship_id': 1, 'type': 1, 'eta': datetime.datetime(2023, 7, 23, 7, 18, 19),
|
'ship_id': 1, 'type': 1, 'eta': datetime.datetime(2023, 7, 23, 7, 18, 19),
|
||||||
'voyage': '43B', 'tug_required': False, 'pilot_required': True, 'flags': 0,
|
'voyage': '43B', 'tug_required': False, 'pilot_required': True, 'flags': 0,
|
||||||
'pier_side': False, 'bunkering': True, 'recommended_tugs': 2, 'type_value': 1, 'evaluation_value': 0}
|
'pier_side': False, 'bunkering': True, 'recommended_tugs': 2, 'type_value': 1, 'evaluation_value': 0}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This creates a *new* entry
|
# This creates a *new* entry
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
|
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
|
|
||||||
# query = SQLQuery.get_shipcall_post(schemaModel) # create_sql_query_shipcall_post(schemaModel)
|
# query = SQLQuery.get_shipcall_post(schemaModel) # create_sql_query_shipcall_post(schemaModel)
|
||||||
|
|
||||||
query = "INSERT INTO shipcall ("
|
query = "INSERT INTO shipcall ("
|
||||||
isNotFirst = False
|
isNotFirst = False
|
||||||
for key in schemaModel.keys():
|
for key in schemaModel.keys():
|
||||||
@ -89,9 +91,9 @@ def PostShipcalls(schemaModel):
|
|||||||
if key == "evaluation":
|
if key == "evaluation":
|
||||||
continue
|
continue
|
||||||
if key == "evaluation_message":
|
if key == "evaluation_message":
|
||||||
continue
|
continue
|
||||||
if key == "type_value":
|
if key == "type_value":
|
||||||
continue
|
continue
|
||||||
if key == "evaluation_value":
|
if key == "evaluation_value":
|
||||||
continue
|
continue
|
||||||
if isNotFirst:
|
if isNotFirst:
|
||||||
@ -133,12 +135,27 @@ def PostShipcalls(schemaModel):
|
|||||||
# new_id = commands.execute_scalar(lquery)
|
# new_id = commands.execute_scalar(lquery)
|
||||||
new_id = commands.execute_scalar("select last_insert_id()")
|
new_id = commands.execute_scalar("select last_insert_id()")
|
||||||
|
|
||||||
|
shipdata = get_ship_data_for_id(schemaModel["ship_id"])
|
||||||
|
message = "The participant has been assigned to the shipcall."
|
||||||
|
if "type_value" in schemaModel:
|
||||||
|
match schemaModel["type_value"]:
|
||||||
|
case 1:
|
||||||
|
message += " [ARRIVAL]"
|
||||||
|
case 2:
|
||||||
|
message += " [DEPARTURE]"
|
||||||
|
case 3:
|
||||||
|
message += " [SHIFTING]"
|
||||||
|
|
||||||
|
|
||||||
# add participant assignments if we have a list of participants
|
# add participant assignments if we have a list of participants
|
||||||
if 'participants' in schemaModel:
|
if 'participants' in schemaModel:
|
||||||
# pquery = SQLQuery.get_shipcall_post_update_shipcall_participant_map()
|
# pquery = SQLQuery.get_shipcall_post_update_shipcall_participant_map()
|
||||||
pquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
pquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
||||||
|
nquery = "INSERT INTO notification (shipcall_id, participant_id, level, type, message) VALUES (?shipcall_id?, ?participant_id?, 0, 1, ?message?)" # type = 1 is assignment
|
||||||
|
|
||||||
for participant_assignment in schemaModel["participants"]:
|
for participant_assignment in schemaModel["participants"]:
|
||||||
commands.execute(pquery, param={"shipcall_id" : new_id, "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]})
|
commands.execute(pquery, param={"shipcall_id" : new_id, "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]})
|
||||||
|
commands.execute(nquery, param={"shipcall_id" : new_id, "participant_id" : participant_assignment["participant_id"], "message" : message})
|
||||||
|
|
||||||
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database
|
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database
|
||||||
# evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=new_id) # new_id (last insert id) refers to the shipcall id
|
# evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=new_id) # new_id (last insert id) refers to the shipcall id
|
||||||
@ -151,7 +168,7 @@ def PostShipcalls(schemaModel):
|
|||||||
commands.execute(query, {"scid" : new_id, "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
commands.execute(query, {"scid" : new_id, "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||||
|
|
||||||
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
return create_validation_error_response(ex, status_code=400, create_log=True)
|
return create_validation_error_response(ex, status_code=400, create_log=True)
|
||||||
|
|
||||||
@ -160,7 +177,7 @@ def PostShipcalls(schemaModel):
|
|||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -168,15 +185,15 @@ def PostShipcalls(schemaModel):
|
|||||||
pooledConnection.close()
|
pooledConnection.close()
|
||||||
|
|
||||||
|
|
||||||
def PutShipcalls(schemaModel):
|
def PutShipcalls(schemaModel, original_payload=None):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
:param schemaModel: The deserialized dict of the request
|
:param schemaModel: The deserialized dict of the request
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This updates an *existing* entry
|
# This updates an *existing* entry
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
|
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
|
|
||||||
@ -185,17 +202,19 @@ def PutShipcalls(schemaModel):
|
|||||||
# test if object to update is found
|
# test if object to update is found
|
||||||
|
|
||||||
sentinel = object()
|
sentinel = object()
|
||||||
# query = SQLQuery.get_shipcall_by_id()
|
|
||||||
# theshipcall = commands.query_single_or_default(query, sentinel, param={"id" : schemaModel["id"]})
|
|
||||||
theshipcall = commands.query_single_or_default("SELECT * FROM shipcall where id = ?id?", sentinel, param={"id" : schemaModel["id"]})
|
theshipcall = commands.query_single_or_default("SELECT * FROM shipcall where id = ?id?", sentinel, param={"id" : schemaModel["id"]})
|
||||||
if theshipcall is sentinel:
|
if theshipcall is sentinel:
|
||||||
pooledConnection.close()
|
|
||||||
return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
# query = SQLQuery.get_shipcall_put(schemaModel)
|
was_canceled = theshipcall["canceled"]
|
||||||
query = "UPDATE shipcall SET "
|
|
||||||
isNotFirst = False
|
provided_keys = set(original_payload.keys()) if isinstance(original_payload, dict) else None
|
||||||
|
|
||||||
|
update_clauses = []
|
||||||
for key in schemaModel.keys():
|
for key in schemaModel.keys():
|
||||||
|
if provided_keys is not None and key not in provided_keys:
|
||||||
|
continue
|
||||||
param_key = key
|
param_key = key
|
||||||
if key == "id":
|
if key == "id":
|
||||||
continue
|
continue
|
||||||
@ -217,21 +236,23 @@ def PutShipcalls(schemaModel):
|
|||||||
param_key = "evaluation_value"
|
param_key = "evaluation_value"
|
||||||
if key == "evaluation_value":
|
if key == "evaluation_value":
|
||||||
continue
|
continue
|
||||||
if isNotFirst:
|
update_clauses.append(f"{key} = ?{param_key}?")
|
||||||
query += ", "
|
|
||||||
isNotFirst = True
|
|
||||||
query += key + " = ?" + param_key + "? "
|
|
||||||
|
|
||||||
query += "WHERE id = ?id?"
|
if update_clauses:
|
||||||
|
query = "UPDATE shipcall SET " + ", ".join(update_clauses) + " WHERE id = ?id?"
|
||||||
affected_rows = commands.execute(query, param=schemaModel)
|
commands.execute(query, param=schemaModel)
|
||||||
|
|
||||||
# pquery = SQLQuery.get_shipcall_participant_map_by_shipcall_id()
|
# pquery = SQLQuery.get_shipcall_participant_map_by_shipcall_id()
|
||||||
pquery = "SELECT id, participant_id, type FROM shipcall_participant_map where shipcall_id = ?id?"
|
pquery = "SELECT id, participant_id, type FROM shipcall_participant_map where shipcall_id = ?id?"
|
||||||
pdata = commands.query(pquery,param={"id" : schemaModel["id"]}) # existing list of assignments
|
pdata = commands.query(pquery,param={"id" : schemaModel["id"]}) # existing list of assignments
|
||||||
|
|
||||||
|
if schemaModel.get("participants") is None:
|
||||||
|
schemaModel["participants"] = []
|
||||||
|
|
||||||
# loop across passed participant ids, creating entries for those not present in pdata
|
# loop across passed participant ids, creating entries for those not present in pdata
|
||||||
|
|
||||||
|
existing_notifications = get_notification_for_shipcall_and_type(schemaModel["id"], 1) # type = 1 is assignment
|
||||||
|
|
||||||
for participant_assignment in schemaModel["participants"]:
|
for participant_assignment in schemaModel["participants"]:
|
||||||
found_participant = False
|
found_participant = False
|
||||||
for elem in pdata:
|
for elem in pdata:
|
||||||
@ -239,9 +260,20 @@ def PutShipcalls(schemaModel):
|
|||||||
found_participant = True
|
found_participant = True
|
||||||
break
|
break
|
||||||
if not found_participant:
|
if not found_participant:
|
||||||
|
message = "The participant has been assigned to the shipcall."
|
||||||
# nquery = SQLQuery.get_shipcall_post_update_shipcall_participant_map()
|
# nquery = SQLQuery.get_shipcall_post_update_shipcall_participant_map()
|
||||||
nquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
spquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
||||||
commands.execute(nquery, param={"shipcall_id" : schemaModel["id"], "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]})
|
commands.execute(spquery, param={"shipcall_id" : schemaModel["id"], "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]})
|
||||||
|
|
||||||
|
# create a notification but only if there is no existing notification in level 0
|
||||||
|
found_notification = False
|
||||||
|
for existing_notification in existing_notifications:
|
||||||
|
if existing_notification["participant_id"] == participant_assignment["participant_id"] and existing_notification["level"] == 1:
|
||||||
|
found_notification = True
|
||||||
|
break
|
||||||
|
if not found_notification:
|
||||||
|
nquery = "INSERT INTO notification (shipcall_id, participant_id, level, type, message) VALUES (?shipcall_id?, ?participant_id?, 0, 1, ?message?)" # type = 1 is assignment
|
||||||
|
commands.execute(nquery, param={"shipcall_id" : schemaModel["id"], "participant_id" : participant_assignment["participant_id"], "message" : message})
|
||||||
|
|
||||||
# loop across existing pdata entries, deleting those not present in participant list
|
# loop across existing pdata entries, deleting those not present in participant list
|
||||||
for elem in pdata:
|
for elem in pdata:
|
||||||
@ -254,6 +286,27 @@ def PutShipcalls(schemaModel):
|
|||||||
# dquery = SQLQuery.get_shipcall_participant_map_delete_by_id()
|
# dquery = SQLQuery.get_shipcall_participant_map_delete_by_id()
|
||||||
dquery = "DELETE FROM shipcall_participant_map WHERE id = ?existing_id?"
|
dquery = "DELETE FROM shipcall_participant_map WHERE id = ?existing_id?"
|
||||||
commands.execute(dquery, param={"existing_id" : elem["id"]})
|
commands.execute(dquery, param={"existing_id" : elem["id"]})
|
||||||
|
# TODO: Create un-assignment notification but only if level > 0 else delete existing notification
|
||||||
|
for existing_notification in existing_notifications:
|
||||||
|
if existing_notification["participant_id"] == elem["participant_id"]:
|
||||||
|
if existing_notification["level"] == 0:
|
||||||
|
nquery = "DELETE FROM notification WHERE id = ?nid?"
|
||||||
|
commands.execute(nquery, param={"nid" : existing_notification["id"]})
|
||||||
|
else:
|
||||||
|
# create un-assignment notification
|
||||||
|
message = "The participant has been unassigned from the shipcall."
|
||||||
|
nquery = "INSERT INTO notification (shipcall_id, participant_id, level, type, message) VALUES (?shipcall_id?, ?participant_id?, 0, 5, ?message?)"
|
||||||
|
commands.execute(nquery, param={"shipcall_id" : schemaModel["id"], "participant_id" : elem["participant_id"], "message" : message})
|
||||||
|
break
|
||||||
|
|
||||||
|
canceled_value = schemaModel.get("canceled")
|
||||||
|
if canceled_value is not None:
|
||||||
|
if canceled_value and not was_canceled:
|
||||||
|
message = "The shipcall has been canceled."
|
||||||
|
# create a canceled notification for all currently assigned participants
|
||||||
|
stornoNotificationQuery = "INSERT INTO notification (shipcall_id, participant_id, level, type, message) VALUES (?shipcall_id?, ?participant_id?, 0, 7, ?message?)"
|
||||||
|
for participant_assignment in schemaModel["participants"]:
|
||||||
|
commands.execute(stornoNotificationQuery, param={"shipcall_id" : schemaModel["id"], "participant_id" : participant_assignment["participant_id"], "message" : message})
|
||||||
|
|
||||||
# save history data
|
# save history data
|
||||||
# TODO: set ETA properly
|
# TODO: set ETA properly
|
||||||
@ -262,7 +315,7 @@ def PutShipcalls(schemaModel):
|
|||||||
commands.execute(query, {"scid" : schemaModel["id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
commands.execute(query, {"scid" : schemaModel["id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||||
|
|
||||||
return json.dumps({"id" : schemaModel["id"]}), 200
|
return json.dumps({"id" : schemaModel["id"]}), 200
|
||||||
|
|
||||||
except ValidationError as ex:
|
except ValidationError as ex:
|
||||||
return create_validation_error_response(ex, status_code=400, create_log=True)
|
return create_validation_error_response(ex, status_code=400, create_log=True)
|
||||||
|
|
||||||
@ -271,7 +324,7 @@ def PutShipcalls(schemaModel):
|
|||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@ -11,8 +11,8 @@ def GetShips(token):
|
|||||||
No parameters, gets all entries
|
No parameters, gets all entries
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
|
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
# query = SQLQuery.get_ships()
|
# query = SQLQuery.get_ships()
|
||||||
@ -25,7 +25,7 @@ def GetShips(token):
|
|||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -44,8 +44,8 @@ def PostShip(schemaModel):
|
|||||||
# TODO: Validate the incoming data
|
# TODO: Validate the incoming data
|
||||||
|
|
||||||
# This creates a *new* entry
|
# This creates a *new* entry
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
|
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
|
|
||||||
@ -83,16 +83,17 @@ def PostShip(schemaModel):
|
|||||||
# new_id = commands.execute_scalar(nquery)
|
# new_id = commands.execute_scalar(nquery)
|
||||||
new_id = commands.execute_scalar("select last_insert_id()")
|
new_id = commands.execute_scalar("select last_insert_id()")
|
||||||
|
|
||||||
pooledConnection.close()
|
|
||||||
|
|
||||||
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
finally:
|
||||||
|
if pooledConnection is not None:
|
||||||
|
pooledConnection.close()
|
||||||
|
|
||||||
|
|
||||||
def PutShip(schemaModel):
|
def PutShip(schemaModel):
|
||||||
@ -101,8 +102,8 @@ def PutShip(schemaModel):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# This updates an *existing* entry
|
# This updates an *existing* entry
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
|
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
|
|
||||||
@ -125,16 +126,17 @@ def PutShip(schemaModel):
|
|||||||
|
|
||||||
affected_rows = commands.execute(query, param=schemaModel)
|
affected_rows = commands.execute(query, param=schemaModel)
|
||||||
|
|
||||||
pooledConnection.close()
|
|
||||||
|
|
||||||
return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
finally:
|
||||||
|
if pooledConnection is not None:
|
||||||
|
pooledConnection.close()
|
||||||
|
|
||||||
|
|
||||||
def DeleteShip(options):
|
def DeleteShip(options):
|
||||||
@ -143,26 +145,27 @@ def DeleteShip(options):
|
|||||||
options["id"]
|
options["id"]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
pooledConnection = None
|
||||||
try:
|
try:
|
||||||
|
|
||||||
pooledConnection = local_db.getPoolConnection()
|
pooledConnection = local_db.getPoolConnection()
|
||||||
commands = pydapper.using(pooledConnection)
|
commands = pydapper.using(pooledConnection)
|
||||||
# query = SQLQuery.get_ship_delete_by_id()
|
# query = SQLQuery.get_ship_delete_by_id()
|
||||||
# affected_rows = commands.execute(query, param={"id" : options["id"]})
|
# affected_rows = commands.execute(query, param={"id" : options["id"]})
|
||||||
affected_rows = commands.execute("UPDATE ship SET deleted = 1 WHERE id = ?id?", param={"id" : options["id"]})
|
affected_rows = commands.execute("UPDATE ship SET deleted = 1 WHERE id = ?id?", param={"id" : options["id"]})
|
||||||
|
|
||||||
pooledConnection.close()
|
|
||||||
|
|
||||||
if affected_rows == 1:
|
if affected_rows == 1:
|
||||||
return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "no such record"
|
result["error_field"] = "no such record"
|
||||||
return json.dumps(result), 404, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 404, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.error(ex)
|
logging.error(ex)
|
||||||
print(ex)
|
print(ex)
|
||||||
result = {}
|
result = {}
|
||||||
result["message"] = "call failed"
|
result["error_field"] = "call failed"
|
||||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||||
|
finally:
|
||||||
|
if pooledConnection is not None:
|
||||||
|
pooledConnection.close()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user