Compare commits

..

94 Commits

Author SHA1 Message Date
7dce3a434f Merge pull request 'issue-117' (#119) from issue-117 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m9s
Java CI with Maven / build-and-push-backend (push) Successful in 1m13s
Reviewed-on: #119
2024-04-19 10:19:13 +02:00
Sebastian Böckelmann
952dddff2e Assign cloned schedule to cloned task and not to root task
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-19 10:14:23 +02:00
Sebastian Böckelmann
dd58ec6520 Repare indecing (duplicate 00): Call RepeatTask with itemIndex 1, as the root task gets itemIndex 0
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 9s
2024-04-19 09:59:43 +02:00
Sebastian Böckelmann
57be3393c9 Distribute cloned tasks on weeks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-04-19 09:51:14 +02:00
bc239f9b86 Merge pull request 'Fix way to long schedule after registering forgotten task' (#116) from issue-111 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m48s
Java CI with Maven / build-and-push-backend (push) Successful in 1m51s
Reviewed-on: #116
2024-04-18 20:34:36 +02:00
Sebastian Böckelmann
a8fb54f337 Fix way to long schedule after registering forgotten task
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 6s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-04-18 20:30:36 +02:00
2bc3b3ab63 Merge pull request 'issue-112' (#115) from issue-112 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m56s
Java CI with Maven / build-and-push-backend (push) Successful in 1m39s
Reviewed-on: #115
2024-04-18 20:20:22 +02:00
Sebastian Böckelmann
d537fd5d57 Added Reschedule Redirection for Planned Schedules
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-18 20:19:05 +02:00
Sebastian Böckelmann
f0a596ff0c Added Links in Schedules planned for today
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-18 20:14:35 +02:00
Sebastian Böckelmann
ba5faeed6a Added Link from TaskgroupPathElement to Taskgroup-Overview in active-schedule
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-18 20:11:04 +02:00
Sebastian Böckelmann
cd98423f6b Added Link from active schedule to task detail-overview
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-18 20:09:06 +02:00
Sebastian Böckelmann
8dffb6f9ad Activate Finishing from active task schedule dashboard
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 10s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-18 19:56:25 +02:00
Sebastian Böckelmann
7cd1d68739 Implement Delete Button in Task Detail Overview
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-17 20:55:50 +02:00
Sebastian Böckelmann
6417b7afb9 Navigation Link Tree in Register Forgotten Task Schedule
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-04-17 20:37:27 +02:00
0d3ba5d7d7 Merge pull request 'issue-113: Fix all Delete Operations' (#114) from issue-113 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m19s
Java CI with Maven / build-and-push-backend (push) Successful in 1m14s
Reviewed-on: #114
2024-04-17 20:25:39 +02:00
Sebastian Böckelmann
79f1eba26b Formatting TaskSerie and Fix Deleting of TaskSerie
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-17 20:19:38 +02:00
Sebastian Böckelmann
aa6eb9bfb2 Fix deleting Subtasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-17 18:20:04 +02:00
Sebastian Böckelmann
8342d1ef2c Fix deleting Tasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 9s
2024-04-17 18:19:04 +02:00
Sebastian Böckelmann
583cb0aca0 Fix Deleting Taskgroup when Taskgroup has parent
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-04-17 18:16:07 +02:00
d1527e6d9c Merge pull request 'fix-statistics' (#110) from fix-statistics into master
Some checks failed
Java CI with Maven / build-and-push-frontend (push) Failing after 31s
Java CI with Maven / build-and-push-backend (push) Successful in 1m12s
Reviewed-on: #110
2024-03-18 15:25:19 +01:00
Sebastian Böckelmann
28f390f88a Document additional endpoint to get taskgroup specific activity info
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 11s
Java CI with Maven / build-and-push-backend (push) Successful in 12s
2024-03-18 15:24:10 +01:00
Sebastian Böckelmann
bbdeaabd1e Activity of Taskgroups 2024-03-18 15:23:40 +01:00
Sebastian Böckelmann
183030611b Select top taskgroups by default in Activity Statistic
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 13s
Java CI with Maven / build-and-push-backend (push) Successful in 13s
2024-03-18 14:45:25 +01:00
Sebastian Böckelmann
e1f69b340d Adapt Statistic Endpoint for Statistics independent of Taskgroup
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 21s
Java CI with Maven / build-and-push-backend (push) Successful in 11s
2024-03-18 09:42:56 +01:00
Sebastian Böckelmann
985aa5f83b Partial Correct heatMap implementation
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 14s
Java CI with Maven / build-and-push-backend (push) Successful in 10s
2024-03-17 16:01:48 +01:00
Sebastian Böckelmann
e53a1797fe Display only statistics until today
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 11s
2024-03-17 13:28:49 +01:00
1133d2123c Merge pull request 'issue-92' (#109) from issue-92 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m20s
Java CI with Maven / build-and-push-backend (push) Successful in 1m14s
Reviewed-on: #109
2024-03-17 13:21:28 +01:00
Sebastian Böckelmann
514a5650bf Include CalendarHeader for all CalendarViews
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 14s
2024-03-17 13:16:05 +01:00
Sebastian Böckelmann
88d285bef7 Calendar Header for upcoming deadlines
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 10s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-17 12:28:07 +01:00
Sebastian Böckelmann
9d20335c59 Visualize Upcoming Deadlines (use default view)
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 11s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-17 12:04:59 +01:00
Sebastian Böckelmann
f921d1d222 Visualize Upcoming Deadlines
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 11s
2024-03-17 11:50:47 +01:00
2215fe2ff8 Merge pull request 'issue-93' (#108) from issue-93 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m8s
Java CI with Maven / build-and-push-backend (push) Successful in 1m18s
Reviewed-on: #108
2024-03-17 09:34:13 +01:00
Sebastian Böckelmann
b4a82c745d Only send ntfy-msg when ntfy-data is specified
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-17 09:33:49 +01:00
Sebastian Böckelmann
f5607f8023 Delete Schedules in ScheduleHistory
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 6s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-17 09:33:20 +01:00
4b6a90b085 Merge pull request 'issue-106' (#107) from issue-106 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m8s
Java CI with Maven / build-and-push-backend (push) Successful in 1m10s
Reviewed-on: #107
2024-03-17 09:17:10 +01:00
Sebastian Böckelmann
0a60b8b27e Clear subtasks in UI
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-17 09:16:37 +01:00
Sebastian Böckelmann
4059500fa4 Clear Subtasks and fix indexing only when non subtask is deleted
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-17 09:16:20 +01:00
Sebastian Böckelmann
56d75fead9 Fix Repair Indexing to consider subtasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-17 08:42:58 +01:00
Sebastian Böckelmann
7336daddb1 Add root(sub)tasks to taskserie
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-17 08:32:33 +01:00
Sebastian Böckelmann
63418cb99a Fix unshifted Schedules
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-17 08:28:02 +01:00
Sebastian Böckelmann
f080c6db52 Adjust Frontend to removed DeadlineStrategy
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-17 08:21:56 +01:00
Sebastian Böckelmann
9b995baa75 Remove DeadlineStrategy as it is not longer necessary
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-17 08:01:48 +01:00
Sebastian Böckelmann
fea17c3fb9 Refactor Code for Repeating Weekly
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-17 07:48:06 +01:00
Sebastian Böckelmann
f0d50a280e Adapt weekly repeating algorithm to consider subtasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-17 07:30:49 +01:00
Sebastian Böckelmann
dcdba67f22 Delete Tasks by Taskgroup and Fix NullpointerException in TaskEntityInfo Constructor
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-16 14:28:25 +01:00
Sebastian Böckelmann
125ab10a00 Deliver Task only if it is no subtask to TaskOverview
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-16 14:18:43 +01:00
Sebastian Böckelmann
dfe12e6102 Take subtasks in Dashboard into account (TaskOverview)
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-16 14:18:23 +01:00
Sebastian Böckelmann
8487a573a1 Hide copy function for subtasks (daily)
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-16 14:04:57 +01:00
Sebastian Böckelmann
7526b6c134 Hide copy function for subtasks (weekly)
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-16 14:01:10 +01:00
Sebastian Böckelmann
6047f4097c Display Subtasks in TaskDetail Component
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 10s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-16 11:29:55 +01:00
Sebastian Böckelmann
682d88e183 Remove Subtasks from TaskDashboard
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-16 11:10:29 +01:00
Sebastian Böckelmann
d7b2683ffc Ui Support for Creating Subtasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-16 10:57:50 +01:00
Sebastian Böckelmann
160c379116 Adapt Task to consider subtasks and implement service to create Subtasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-16 10:33:35 +01:00
f7d844fd51 Merge pull request 'issue-77' (#105) from issue-77 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m4s
Java CI with Maven / build-and-push-backend (push) Successful in 1m22s
Reviewed-on: #105
2024-03-16 10:12:35 +01:00
Sebastian Böckelmann
3e3fba9b2d Delete Tasks that do not belong to any series
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-16 10:09:52 +01:00
Sebastian Böckelmann
e58e6addb9 Clone Schedules when Repeating Tasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-16 10:09:38 +01:00
Sebastian Böckelmann
e7283c030d Disable weekly task repetition when task is already part of a series
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-16 09:39:13 +01:00
Sebastian Böckelmann
f3c491826b Disable daily task repetition when task is already part of a series
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-16 09:37:42 +01:00
Sebastian Böckelmann
9e5a1337d9 Avoid weekly task repeatition with no selected tasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-16 09:34:17 +01:00
Sebastian Böckelmann
49119b2549 Newly files in frontend for generating weekly repeating tasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-16 09:31:17 +01:00
Sebastian Böckelmann
aafb5886db Frontend Form for generating repeating tasks weekly
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-16 09:30:48 +01:00
Sebastian Böckelmann
7d24ed1229 Implement Generating Repeating Task on Weekly Basis
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 10s
2024-03-15 18:07:40 +01:00
Sebastian Böckelmann
015d82587c Repair Indexing after Deleting Tasks of Taskserie
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-15 16:58:51 +01:00
Sebastian Böckelmann
ec4a1cfbc7 Delete Unreferenced TaskSeries
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-15 16:49:31 +01:00
Sebastian Böckelmann
717e8d4e45 Fix storing multiple TaskSerieItems for RootTask
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-15 15:32:31 +01:00
Sebastian Böckelmann
e102b91a1f Fix Deleting Tasks with TaskSerieItem: Foreign Key Constraint failed
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-15 15:16:31 +01:00
Sebastian Böckelmann
c093720a07 Deleting of Tasks, Taskseries and TaskSerieItems
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-15 15:08:24 +01:00
Sebastian Böckelmann
59ee88b5fe Replace index placeholder for root-task
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-15 09:45:54 +01:00
Sebastian Böckelmann
4b9dd4d17c Frontend Components for Creating Daily Repeating Tasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-15 09:43:38 +01:00
Sebastian Böckelmann
a3723e3459 Frontend Components for Creating Daily Repeating Tasks
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-15 09:43:23 +01:00
Sebastian Böckelmann
3f58fe3600 Implement Backend Components for Creating Daily Taskseries
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 7s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-15 08:57:54 +01:00
13df4ac6fa Merge pull request 'issue-96: Fix TaskStatus' (#104) from issue-96 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m13s
Java CI with Maven / build-and-push-backend (push) Successful in 1m9s
Reviewed-on: #104
2024-03-15 07:22:53 +01:00
Sebastian Böckelmann
56a7047bad Use TaskStatus Service for Status Determination in Detail Overview of Task
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 12s
Java CI with Maven / build-and-push-backend (push) Successful in 9s
2024-03-15 07:22:03 +01:00
Sebastian Böckelmann
313d329636 Use TaskStatus Service instead of duplicate implementation in TaskDashboard
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 29s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-15 07:19:43 +01:00
fcbf8b0a17 Merge pull request 'Consider updated Date Selection in Schedule History' (#103) from issue-94 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m22s
Java CI with Maven / build-and-push-backend (push) Successful in 1m13s
Reviewed-on: #103
2024-03-14 15:03:36 +01:00
Sebastian Böckelmann
d68794236e Consider updated Date Selection in Schedule History
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-14 15:02:50 +01:00
574c86af7e Merge pull request 'issue-86' (#102) from issue-86 into master
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 2m45s
Java CI with Maven / build-and-push-backend (push) Successful in 1m31s
Reviewed-on: #102
2024-03-14 14:57:43 +01:00
Sebastian Böckelmann
19075b2b1d Send ntf-msg when schedule is started
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 17s
Java CI with Maven / build-and-push-backend (push) Successful in 15s
2024-03-14 14:56:02 +01:00
Sebastian Böckelmann
526c57a362 Do not ntfy on already performed scheduled or missed schedules
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 12s
Java CI with Maven / build-and-push-backend (push) Successful in 9s
2024-03-14 14:46:59 +01:00
Sebastian Böckelmann
4155af45f5 Frontend to update ntfy data
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 13s
Java CI with Maven / build-and-push-backend (push) Successful in 9s
2024-03-14 14:44:06 +01:00
Sebastian Böckelmann
4653ab9866 Use user dependent ntfy data
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 19s
Java CI with Maven / build-and-push-backend (push) Successful in 18s
2024-03-14 14:43:45 +01:00
Sebastian Böckelmann
f2823ad21e Schedule notifcations for all todays schedules and stop notification when schedule is activated
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 25s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-14 12:22:24 +01:00
Sebastian Böckelmann
6c8f216fa5 Remove Testing code (interfers with commandlinerunner)
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 14s
Java CI with Maven / build-and-push-backend (push) Successful in 10s
2024-03-14 11:25:11 +01:00
Sebastian Böckelmann
14aabc483f Load basic ntfy values from environment
Some checks failed
Java CI with Maven / test (push) Failing after 50s
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-14 10:32:29 +01:00
Sebastian Böckelmann
871751b5d4 Define Starting Reminder Notification
All checks were successful
Java CI with Maven / test (push) Successful in 39s
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-14 10:04:58 +01:00
Sebastian Böckelmann
248717cb45 Implement single scheduler and send simple msg to ntfy
All checks were successful
Java CI with Maven / test (push) Successful in 1m4s
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-14 09:34:26 +01:00
Sebastian Böckelmann
2b0f9ef186 Implement a small example dynamic schedule
All checks were successful
Java CI with Maven / test (push) Successful in 34s
Java CI with Maven / build-and-push-frontend (push) Successful in 6s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-14 08:08:04 +01:00
5366dcc0e3 Merge pull request 'issue-95' (#101) from issue-95 into master
All checks were successful
Java CI with Maven / test (push) Successful in 38s
Java CI with Maven / build-and-push-frontend (push) Successful in 2m9s
Java CI with Maven / build-and-push-backend (push) Successful in 1m21s
Reviewed-on: #101
2024-03-14 07:29:48 +01:00
Sebastian Böckelmann
a78be70a5d Use buttons instead of links to react already to first click
All checks were successful
Java CI with Maven / test (push) Successful in 37s
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 10s
2024-03-14 07:26:04 +01:00
Sebastian Böckelmann
635b03ecac Implement Aborting and setting Manual Stop Time on Task-Schedules
All checks were successful
Java CI with Maven / test (push) Successful in 38s
Java CI with Maven / build-and-push-frontend (push) Successful in 9s
Java CI with Maven / build-and-push-backend (push) Successful in 8s
2024-03-14 07:23:44 +01:00
Sebastian Böckelmann
fc742a3526 Abort Schedules
All checks were successful
Java CI with Maven / test (push) Successful in 41s
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-13 23:17:22 +01:00
Sebastian Böckelmann
376b5395f1 Design UI functionality
All checks were successful
Java CI with Maven / test (push) Successful in 36s
Java CI with Maven / build-and-push-frontend (push) Successful in 8s
Java CI with Maven / build-and-push-backend (push) Successful in 7s
2024-03-13 23:05:28 +01:00
Sebastian Böckelmann
8e41085008 Fix issue-100
All checks were successful
Java CI with Maven / test (push) Successful in 1m5s
Java CI with Maven / build-and-push-frontend (push) Successful in 2m21s
Java CI with Maven / build-and-push-backend (push) Successful in 1m22s
2024-03-13 19:00:30 +01:00
Sebastian Böckelmann
a66a72eb68 Fix taskgroup and task deletion (issue-99)
All checks were successful
Java CI with Maven / test (push) Successful in 5m41s
Java CI with Maven / build-and-push-frontend (push) Successful in 9m0s
Java CI with Maven / build-and-push-backend (push) Successful in 1m32s
2024-03-13 18:26:47 +01:00
146 changed files with 4319 additions and 1761 deletions

View File

@ -3,25 +3,6 @@ run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
on: [push] on: [push]
jobs: jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Set up Maven
uses: stCarolas/setup-maven@v4.5
with:
maven-version: 3.8.2
- name: Build with Maven
run: mvn -B package --file backend/pom.xml
build-and-push-frontend: build-and-push-frontend:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@ -21,6 +21,11 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId> <artifactId>spring-boot-starter-security</artifactId>

View File

@ -2,15 +2,25 @@ package core;
import core.entities.RoleEntity; import core.entities.RoleEntity;
import core.entities.UserRole; import core.entities.UserRole;
import core.entities.timemanager.AdvancedTaskSchedule;
import core.repositories.RoleRepository; import core.repositories.RoleRepository;
import core.repositories.UserRepository; import core.repositories.UserRepository;
import core.services.PropertyService; import core.services.PropertyService;
import core.services.TaskScheduleService;
import core.services.ntfy.TaskSchedulingService;
import org.springframework.boot.CommandLineRunner; import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@SpringBootApplication @SpringBootApplication
@EnableScheduling
public class DemoApplication{ public class DemoApplication{
public static void main(String[] args) { public static void main(String[] args) {
@ -18,19 +28,12 @@ public class DemoApplication{
} }
/*@Bean @Bean
public CommandLineRunner init(RoleRepository roleRepository, UserRepository userRepository, PropertyService propertyService) { public CommandLineRunner init(TaskSchedulingService taskSchedulingService) {
return args -> { return args -> {
for (UserRole userRole : UserRole.values()) { taskSchedulingService.scheduleStartReminders();
if(!roleRepository.existsByName(userRole)) {
roleRepository.save(new RoleEntity(userRole));
}
}
propertyService.init();
FirstUserObserver observer = new FirstUserObserver(userRepository);
observer.start();
}; };
}*/ }
} }

View File

@ -0,0 +1,55 @@
package core.api.controller;
import core.api.models.auth.SimpleStatusResponse;
import core.api.models.users.NtfyInformation;
import core.entities.User;
import core.repositories.UserRepository;
import core.services.UserService;
import core.services.ntfy.TaskSchedulingService;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.Optional;
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api")
public class NtfyController {
@Autowired private UserRepository userRepository;
@Autowired private UserService userService;
@Autowired private TaskSchedulingService taskSchedulingService;
@GetMapping("/ntfy")
public ResponseEntity<?> getNtfyInformation() {
String username = SecurityContextHolder.getContext().getAuthentication().getName();
Optional<User> userOptional = userRepository.findByUsername(username);
if(userOptional.isPresent()) {
return ResponseEntity.ok(new NtfyInformation(userOptional.get()));
} else {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
}
@PostMapping("/ntfy")
public ResponseEntity<?> editNtfyInformation(@Valid @RequestBody NtfyInformation ntfyInformation) {
String username = SecurityContextHolder.getContext().getAuthentication().getName();
Optional<User> user = userRepository.findByUsername(username);
if(user.isPresent()) {
userService.editNtfyInformation(user.get(), ntfyInformation);
try {
taskSchedulingService.scheduleStartReminders();
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
return ResponseEntity.ok(new SimpleStatusResponse("success"));
} else {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
}
}

View File

@ -9,6 +9,8 @@ import core.entities.timemanager.AdvancedTaskSchedule;
import core.entities.timemanager.BasicTaskSchedule; import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.services.*; import core.services.*;
import core.services.ntfy.TaskSchedulingService;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
@ -27,6 +29,7 @@ public class ScheduleController {
@Autowired private TaskScheduleService taskScheduleService; @Autowired private TaskScheduleService taskScheduleService;
@Autowired private TaskService taskService; @Autowired private TaskService taskService;
@Autowired private TaskSchedulingService taskSchedulingService;
@GetMapping("/schedules") @GetMapping("/schedules")
public ResponseEntity<?> loadAllSchedulesOfUser() { public ResponseEntity<?> loadAllSchedulesOfUser() {
String username = SecurityContextHolder.getContext().getAuthentication().getName(); String username = SecurityContextHolder.getContext().getAuthentication().getName();
@ -38,7 +41,7 @@ public class ScheduleController {
@GetMapping("/schedules/{taskID}") @GetMapping("/schedules/{taskID}")
public ResponseEntity<?> loadAllSchedulesOfTask(@PathVariable long taskID) { public ResponseEntity<?> loadAllSchedulesOfTask(@PathVariable long taskID) {
PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -69,7 +72,7 @@ public class ScheduleController {
private ResponseEntity<?> createAbstractSchedule(long taskID, ScheduleFieldInfo scheduleFieldInfo) { private ResponseEntity<?> createAbstractSchedule(long taskID, ScheduleFieldInfo scheduleFieldInfo) {
PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -108,7 +111,7 @@ public class ScheduleController {
private ResponseEntity<?> editAbstractSchedule(long scheduleID, ScheduleFieldInfo scheduleFieldInfo) { private ResponseEntity<?> editAbstractSchedule(long scheduleID, ScheduleFieldInfo scheduleFieldInfo) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -138,7 +141,7 @@ public class ScheduleController {
@DeleteMapping("/schedules/{scheduleID}") @DeleteMapping("/schedules/{scheduleID}")
public ResponseEntity<?> deleteSchedule(@PathVariable long scheduleID) { public ResponseEntity<?> deleteSchedule(@PathVariable long scheduleID) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -160,7 +163,7 @@ public class ScheduleController {
@PostMapping("/schedules/{taskID}/now") @PostMapping("/schedules/{taskID}/now")
public ResponseEntity<?> scheduleNow(@PathVariable long taskID) { public ResponseEntity<?> scheduleNow(@PathVariable long taskID) {
PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -172,6 +175,7 @@ public class ScheduleController {
if(scheduleResult.getExitCode() == ServiceExitCode.ENTITY_ALREADY_EXIST) { if(scheduleResult.getExitCode() == ServiceExitCode.ENTITY_ALREADY_EXIST) {
return ResponseEntity.status(409).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(409).body(new SimpleStatusResponse("failed"));
} else { } else {
taskSchedulingService.sendRunningTaskNotification(scheduleResult.getResult());
return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo()); return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo());
} }
} }
@ -189,7 +193,7 @@ public class ScheduleController {
@PostMapping("/schedules/{scheduleID}/activate") @PostMapping("/schedules/{scheduleID}/activate")
public ResponseEntity<?> activateSchedule(@PathVariable long scheduleID) { public ResponseEntity<?> activateSchedule(@PathVariable long scheduleID) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -198,13 +202,22 @@ public class ScheduleController {
} }
ServiceResult<AbstractSchedule> serviceResult = taskScheduleService.activateSchedule(permissionResult.getResult()); ServiceResult<AbstractSchedule> serviceResult = taskScheduleService.activateSchedule(permissionResult.getResult());
if(serviceResult.getResult() instanceof AdvancedTaskSchedule) {
try {
taskSchedulingService.stopStartReminderNotification((AdvancedTaskSchedule) serviceResult.getResult());
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
taskSchedulingService.sendRunningTaskNotification(serviceResult.getResult());
return ResponseEntity.ok(new ScheduleActivateResponse(serviceResult.getResult().getStartTime())); return ResponseEntity.ok(new ScheduleActivateResponse(serviceResult.getResult().getStartTime()));
} }
@PostMapping("/schedules/{scheduleID}/stop/{finish}") @PostMapping("/schedules/{scheduleID}/stop/{finish}")
public ResponseEntity<?> stopSchedule(@PathVariable long scheduleID, @PathVariable boolean finish) { public ResponseEntity<?> stopSchedule(@PathVariable long scheduleID, @PathVariable boolean finish) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -219,7 +232,7 @@ public class ScheduleController {
@PostMapping("/schedules/{taskID}/forgotten") @PostMapping("/schedules/{taskID}/forgotten")
public ResponseEntity<?> registerForgottenSchedule(@PathVariable long taskID, @RequestBody @Valid ForgottenScheduleInfo forgottenScheduleInfo) { public ResponseEntity<?> registerForgottenSchedule(@PathVariable long taskID, @RequestBody @Valid ForgottenScheduleInfo forgottenScheduleInfo) {
PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -246,7 +259,7 @@ public class ScheduleController {
List<PermissionResult<AbstractSchedule>> permissionResults = new ArrayList<>(); List<PermissionResult<AbstractSchedule>> permissionResults = new ArrayList<>();
for(long scheduleID: scheduleIDs) { for(long scheduleID: scheduleIDs) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -265,7 +278,7 @@ public class ScheduleController {
@GetMapping("/schedules/{scheduleID}/details") @GetMapping("/schedules/{scheduleID}/details")
public ResponseEntity<?> loadScheduleDetails(@PathVariable long scheduleID) { public ResponseEntity<?> loadScheduleDetails(@PathVariable long scheduleID) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) { if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -275,4 +288,20 @@ public class ScheduleController {
return ResponseEntity.ok(permissionResult.getResult().toScheduleInfo()); return ResponseEntity.ok(permissionResult.getResult().toScheduleInfo());
} }
@PostMapping("/schedules/{scheduleID}/stopManual")
public ResponseEntity<?> stopManual(@PathVariable long scheduleID, @Valid @RequestBody ManualScheduleStopInfo manualScheduleStopInfo) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
taskScheduleService.finishScheduleManual(permissionResult.getResult(), manualScheduleStopInfo);
return ResponseEntity.ok(new SimpleStatusResponse("success"));
}
} }

View File

@ -3,23 +3,16 @@ package core.api.controller;
import core.api.models.auth.SimpleStatusResponse; import core.api.models.auth.SimpleStatusResponse;
import core.api.models.timemanager.history.TaskgroupActivityInfo; import core.api.models.timemanager.history.TaskgroupActivityInfo;
import core.api.models.timemanager.history.WorkingStatus; import core.api.models.timemanager.history.WorkingStatus;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.entities.timemanager.AbstractSchedule; import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup; import core.entities.timemanager.Taskgroup;
import core.services.PermissionResult; import core.services.*;
import core.services.ServiceExitCode;
import core.services.TaskScheduleService;
import core.services.TaskgroupService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.parameters.P;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.time.*; import java.time.*;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*; import java.util.*;
@CrossOrigin(origins = "*", maxAge = 3600) @CrossOrigin(origins = "*", maxAge = 3600)
@ -28,6 +21,7 @@ import java.util.*;
public class StatisticController { public class StatisticController {
@Autowired private TaskScheduleService taskScheduleService; @Autowired private TaskScheduleService taskScheduleService;
@Autowired private StatisticService statisticService;
@Autowired private TaskgroupService taskgroupService; @Autowired private TaskgroupService taskgroupService;
@GetMapping("/history/workingStatus") @GetMapping("/history/workingStatus")
@ -46,24 +40,29 @@ public class StatisticController {
return ResponseEntity.ok(new WorkingStatus(missedSchedules, activeTime)); return ResponseEntity.ok(new WorkingStatus(missedSchedules, activeTime));
} }
@GetMapping("/statistics/taskgroup-activity/{taskgroupID}/{startingDate}/{endingDate}/{includeSubTaskgroups}") @GetMapping("/statistics/{startingDate}/{endingDate}")
public ResponseEntity<?> getTaskgroupActivity(@PathVariable long taskgroupID, @PathVariable String startingDate, @PathVariable String endingDate, @PathVariable boolean includeSubTaskgroups){ public ResponseEntity<?> getTaskgroupActivity(@PathVariable String startingDate, @PathVariable String endingDate){
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName()); LocalDate starting = LocalDate.parse(startingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
if(!taskgroupPermissionResult.isHasPermissions()) { LocalDate ending = LocalDate.parse(endingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} else if(taskgroupPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) { var taskgroupActivityInfos = statisticService.calcActivityByUser(null, SecurityContextHolder.getContext().getAuthentication().getName(), starting, ending);
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); List<TaskgroupActivityInfo> outgoingResult = StatisticService.convertInternActivityInfo(taskgroupActivityInfos);
return ResponseEntity.ok(outgoingResult);
}
@GetMapping("/statistics/{taskgroupID}/{startingDate}/{endingDate}")
public ResponseEntity<?> getTaskgroupActivity(@PathVariable long taskgroupID, @PathVariable String startingDate, @PathVariable String endingDate){
LocalDate starting = LocalDate.parse(startingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDate ending = LocalDate.parse(endingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
String username = SecurityContextHolder.getContext().getAuthentication().getName();
var permissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, username);
if(permissionResult.hasIssue()) {
return permissionResult.mapToResponseEntity();
} }
List<TaskgroupActivityInfo> activityInfos = taskgroupPermissionResult.getResult().calcActivityInfo(includeSubTaskgroups, var taskgroupActivityInfos = statisticService.calcActivityByUser(permissionResult.getResult(), username, starting, ending);
LocalDate.parse(startingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), LocalDate.parse(endingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"))); List<TaskgroupActivityInfo> outgoingResult = StatisticService.convertInternActivityInfo(taskgroupActivityInfos);
activityInfos.sort(new Comparator<TaskgroupActivityInfo>() { return ResponseEntity.ok(outgoingResult);
@Override
public int compare(TaskgroupActivityInfo o1, TaskgroupActivityInfo o2) {
return o1.getDate().compareTo(o2.getDate());
}
});
return ResponseEntity.ok(activityInfos);
} }
@GetMapping("/history/schedules/{date}") @GetMapping("/history/schedules/{date}")

View File

@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
@CrossOrigin(origins = "*", maxAge = 3600) @CrossOrigin(origins = "*", maxAge = 3600)
@ -64,7 +65,7 @@ public class TaskController {
@GetMapping("/tasks/{taskgroupID}/{status}") @GetMapping("/tasks/{taskgroupID}/{status}")
public ResponseEntity<?> listTasksOfTaskgroup(@PathVariable long taskgroupID, @PathVariable String status) { public ResponseEntity<?> listTasksOfTaskgroup(@PathVariable long taskgroupID, @PathVariable String status) {
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!taskgroupPermissionResult.isHasPermissions()) { if(taskgroupPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -72,13 +73,17 @@ public class TaskController {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
} }
return ResponseEntity.ok(taskgroupPermissionResult.getResult().getTasks().stream().map(TaskEntityInfo::new)); List<Task> tasks = new ArrayList<>();
for(Task task : taskgroupPermissionResult.getResult().getTasks()) {
if(task.getParent() == null) tasks.add(task);
}
return ResponseEntity.ok(tasks.stream().map(TaskEntityInfo::new));
} }
@PutMapping("/tasks/{taskgroupID}") @PutMapping("/tasks/{taskgroupID}")
public ResponseEntity<?> createTask(@PathVariable long taskgroupID, @RequestBody @Valid TaskFieldInfo taskFieldInfo) { public ResponseEntity<?> createTask(@PathVariable long taskgroupID, @RequestBody @Valid TaskFieldInfo taskFieldInfo) {
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!taskgroupPermissionResult.isHasPermissions()) { if(taskgroupPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -101,7 +106,7 @@ public class TaskController {
@PostMapping("/tasks/{taskID}") @PostMapping("/tasks/{taskID}")
public ResponseEntity<?> editTask(@PathVariable long taskID, @RequestBody @Valid TaskFieldInfo taskFieldInfo) { public ResponseEntity<?> editTask(@PathVariable long taskID, @RequestBody @Valid TaskFieldInfo taskFieldInfo) {
PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if (!taskPermissionResult.isHasPermissions()) { if (taskPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -124,7 +129,7 @@ public class TaskController {
@DeleteMapping("/tasks/{taskID}") @DeleteMapping("/tasks/{taskID}")
public ResponseEntity<?> deleteTask(@PathVariable long taskID) { public ResponseEntity<?> deleteTask(@PathVariable long taskID) {
PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if (!taskPermissionResult.isHasPermissions()) { if (taskPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -139,7 +144,7 @@ public class TaskController {
@GetMapping("/tasks/{taskID}") @GetMapping("/tasks/{taskID}")
public ResponseEntity<?> loadTaskDetails(@PathVariable long taskID) { public ResponseEntity<?> loadTaskDetails(@PathVariable long taskID) {
PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if (!taskPermissionResult.isHasPermissions()) { if (taskPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -153,7 +158,7 @@ public class TaskController {
@PostMapping("/tasks/{taskID}/finish") @PostMapping("/tasks/{taskID}/finish")
public ResponseEntity<?> finishTask(@PathVariable long taskID) { public ResponseEntity<?> finishTask(@PathVariable long taskID) {
PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if (!taskPermissionResult.isHasPermissions()) { if (taskPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -164,4 +169,42 @@ public class TaskController {
taskService.finishTask(taskPermissionResult.getResult()); taskService.finishTask(taskPermissionResult.getResult());
return ResponseEntity.ok(new SimpleStatusResponse("success")); return ResponseEntity.ok(new SimpleStatusResponse("success"));
} }
@PutMapping("/tasks/{taskID}/subtasks")
public ResponseEntity<?> onCreateSubTask(@PathVariable long taskID, @Valid @RequestBody TaskFieldInfo taskFieldInfo) {
var taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(taskPermissionResult.hasIssue()) {
return taskPermissionResult.mapToResponseEntity();
}
var serviceResult = taskService.createSubTask(taskPermissionResult.getResult(), taskFieldInfo);
if(serviceResult.hasIssue()) {
return serviceResult.mapToResponseEntity();
} else {
return ResponseEntity.ok(new TaskEntityInfo(serviceResult.getResult()));
}
}
@GetMapping("/tasks/{taskID}/subtasks")
public ResponseEntity<?> onListSubtasks(@PathVariable long taskID) {
var taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(taskPermissionResult.hasIssue()) {
return taskPermissionResult.mapToResponseEntity();
}
Collection<Task> subtasks = taskPermissionResult.getResult().getSubtasks();
return ResponseEntity.ok(subtasks.stream().map(TaskEntityInfo::new).toList());
}
@DeleteMapping("/tasks/{taskID}/subtasks")
public ResponseEntity<?> onClearSubtasks(@PathVariable long taskID) {
var taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(taskPermissionResult.hasIssue()) {
return taskPermissionResult.mapToResponseEntity();
}
ServiceExitCode result = taskService.clearSubTasks(taskPermissionResult.getResult());
return result.mapToResponseEntity();
}
} }

View File

@ -0,0 +1,40 @@
package core.api.controller;
import core.api.models.timemanager.tasks.repeatinginfo.TaskRepeatDayInfo;
import core.api.models.timemanager.tasks.repeatinginfo.TaskRepeatWeekInfo;
import core.services.ServiceExitCode;
import core.services.ServiceResult;
import core.services.TaskSeriesService;
import core.services.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api")
public class TaskSeriesController {
@Autowired private TaskService taskService;
@Autowired private TaskSeriesService taskSeriesService;
@PostMapping("/tasks/taskseries/weekly")
public ResponseEntity<?> onCreateTaskSeries(@Valid @RequestBody TaskRepeatWeekInfo taskRepeatWeekInfo) {
ServiceExitCode serviceExitCode = taskSeriesService.createTaskSeries(taskRepeatWeekInfo);
return serviceExitCode.mapToResponseEntity();
}
@PostMapping("/tasks/{taskID}/taskseries/daily")
public ResponseEntity<?> onCreateTaskSeries(@PathVariable long taskID, @Valid @RequestBody TaskRepeatDayInfo taskRepeatDayInfo) {
var taskPermission = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(taskPermission.hasIssue()) {
return taskPermission.mapToResponseEntity();
} else {
ServiceExitCode serviceExitCode = taskSeriesService.createTaskSeries(taskPermission.getResult(), taskRepeatDayInfo);
return serviceExitCode.mapToResponseEntity();
}
}
}

View File

@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Set;
@CrossOrigin(origins = "*", maxAge = 3600) @CrossOrigin(origins = "*", maxAge = 3600)
@RestController @RestController
@ -40,7 +39,7 @@ public class TaskgroupController {
@PostMapping("/taskgroups/{taskgroupID}") @PostMapping("/taskgroups/{taskgroupID}")
public ResponseEntity<?> editTaskgroup(@PathVariable long taskgroupID, @Valid @RequestBody TaskgroupFieldInfo taskgroupFieldInfo) { public ResponseEntity<?> editTaskgroup(@PathVariable long taskgroupID, @Valid @RequestBody TaskgroupFieldInfo taskgroupFieldInfo) {
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!taskgroupPermissionResult.isHasPermissions()) { if(taskgroupPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -59,7 +58,7 @@ public class TaskgroupController {
@DeleteMapping("/taskgroups/{taskgroupID}") @DeleteMapping("/taskgroups/{taskgroupID}")
public ResponseEntity<?> deleteTaskgroup(@PathVariable long taskgroupID) { public ResponseEntity<?> deleteTaskgroup(@PathVariable long taskgroupID) {
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
if (!taskgroupPermissionResult.isHasPermissions()) { if (taskgroupPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -88,7 +87,7 @@ public class TaskgroupController {
@GetMapping("/taskgroups/{taskgroupID}") @GetMapping("/taskgroups/{taskgroupID}")
public ResponseEntity<?> getDetails(@PathVariable long taskgroupID) { public ResponseEntity<?> getDetails(@PathVariable long taskgroupID) {
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!taskgroupPermissionResult.isHasPermissions()) { if(taskgroupPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -102,7 +101,7 @@ public class TaskgroupController {
@DeleteMapping("/taskgroups/{taskgroupID}/clear") @DeleteMapping("/taskgroups/{taskgroupID}/clear")
public ResponseEntity<?> clearTasks(@PathVariable long taskgroupID) { public ResponseEntity<?> clearTasks(@PathVariable long taskgroupID) {
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
if (!taskgroupPermissionResult.isHasPermissions()) { if (taskgroupPermissionResult.isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }

View File

@ -0,0 +1,30 @@
package core.api.models.timemanager.history;
import java.time.LocalDate;
public class ActivityInfo {
private LocalDate scheduleDate;
private int activeMinutes;
public ActivityInfo(LocalDate scheduleDate, int workedMinutes) {
this.scheduleDate = scheduleDate;
this.activeMinutes = workedMinutes;
}
public LocalDate getScheduleDate() {
return scheduleDate;
}
public void setScheduleDate(LocalDate scheduleDate) {
this.scheduleDate = scheduleDate;
}
public int getActiveMinutes() {
return activeMinutes;
}
public void setActiveMinutes(int activeMinutes) {
this.activeMinutes = activeMinutes;
}
}

View File

@ -4,25 +4,23 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List;
public class TaskgroupActivityInfo { public class TaskgroupActivityInfo {
@JsonProperty private TaskgroupEntityInfo taskgroup;
private LocalDate date; private List<ActivityInfo> activityInfos;
@JsonProperty public TaskgroupActivityInfo(TaskgroupEntityInfo taskgroup, List<ActivityInfo> activityInfos) {
private int activeMinutes; this.taskgroup = taskgroup;
this.activityInfos = activityInfos;
public TaskgroupActivityInfo(int activeMinutes, LocalDate localDate) {
this.date = localDate;
this.activeMinutes = activeMinutes;
} }
public LocalDate getDate() { public TaskgroupEntityInfo getTaskgroup() {
return date; return taskgroup;
} }
public int getActiveMinutes() { public List<ActivityInfo> getActivityInfos() {
return activeMinutes; return activityInfos;
} }
} }

View File

@ -0,0 +1,15 @@
package core.api.models.timemanager.taskSchedule;
import com.fasterxml.jackson.annotation.JsonFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
public class ManualScheduleStopInfo {
@NotNull
private long duration;
public long getDuration() {
return duration;
}
}

View File

@ -31,10 +31,13 @@ public class RecursiveTaskgroupInfo {
} }
for(Task task : taskgroup.getActiveTasks()) { for(Task task : taskgroup.getActiveTasks()) {
this.activeTasks.add(new TaskOverviewInfo(task)); if(task.getParent() == null) {
if(task.getDeadline() != null && task.getDeadline().isBefore(LocalDate.now())) { this.activeTasks.add(new TaskOverviewInfo(task));
this.hasOverdueTask = true; if(task.getDeadline() != null && task.getDeadline().isBefore(LocalDate.now())) {
this.hasOverdueTask = true;
}
} }
} }
this.amountActiveTasks = taskgroup.getAmountOfActiveTasks(); this.amountActiveTasks = taskgroup.getAmountOfActiveTasks();
} }

View File

@ -2,6 +2,7 @@ package core.api.models.timemanager.tasks;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.services.TaskSeriesService;
import java.time.LocalDate; import java.time.LocalDate;
@ -27,10 +28,17 @@ public class TaskEntityInfo {
private boolean hasActiveSchedules; private boolean hasActiveSchedules;
private boolean hasPlannedSchedules; private boolean hasPlannedSchedules;
private boolean hasTaskSerie;
private boolean hasSubtasks;
private boolean hasParent;
public TaskEntityInfo(Task task) { public TaskEntityInfo(Task task) {
this.taskID = task.getTaskID(); this.taskID = task.getTaskID();
this.taskName = task.getTaskName(); if(task.getTaskSerieItem() != null) {
this.taskName = TaskSeriesService.insertNameIndex(task.getTaskSerieItem().getSeriesIndex(), task.getTaskName());
} else {
this.taskName = task.getTaskName();
}
this.eta = task.getEta(); this.eta = task.getEta();
this.startDate = task.getStartDate(); this.startDate = task.getStartDate();
this.deadline = task.getDeadline(); this.deadline = task.getDeadline();
@ -42,6 +50,9 @@ public class TaskEntityInfo {
this.finishable = task.isFinishable(); this.finishable = task.isFinishable();
this.hasActiveSchedules = task.hasActiveSchedule(); this.hasActiveSchedules = task.hasActiveSchedule();
this.hasPlannedSchedules = task.hasPlannedSchedules(); this.hasPlannedSchedules = task.hasPlannedSchedules();
this.hasTaskSerie = task.getTaskSerieItem() != null;
this.hasSubtasks = task.getSubtasks() != null && !task.getSubtasks().isEmpty();
this.hasParent = task.getParent() != null;
} }
public long getTaskID() { public long getTaskID() {
@ -131,4 +142,28 @@ public class TaskEntityInfo {
public void setHasPlannedSchedules(boolean hasPlannedSchedules) { public void setHasPlannedSchedules(boolean hasPlannedSchedules) {
this.hasPlannedSchedules = hasPlannedSchedules; this.hasPlannedSchedules = hasPlannedSchedules;
} }
public boolean isHasTaskSerie() {
return hasTaskSerie;
}
public void setHasTaskSerie(boolean hasTaskSerie) {
this.hasTaskSerie = hasTaskSerie;
}
public boolean isHasSubtasks() {
return hasSubtasks;
}
public void setHasSubtasks(boolean hasSubtasks) {
this.hasSubtasks = hasSubtasks;
}
public boolean isHasParent() {
return hasParent;
}
public void setHasParent(boolean hasParent) {
this.hasParent = hasParent;
}
} }

View File

@ -3,6 +3,7 @@ package core.api.models.timemanager.tasks;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup; import core.entities.timemanager.Taskgroup;
import core.services.TaskSeriesService;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
@ -17,10 +18,15 @@ public class TaskOverviewInfo {
private boolean overdue; private boolean overdue;
private boolean finishable; private boolean finishable;
private boolean hasSubtasks;
public TaskOverviewInfo(Task task) { public TaskOverviewInfo(Task task) {
this.taskID = task.getTaskID(); this.taskID = task.getTaskID();
this.taskName = task.getTaskName(); if(task.getTaskSerieItem() != null) {
this.taskName = TaskSeriesService.insertNameIndex(task.getTaskSerieItem().getSeriesIndex(), task.getTaskName());
} else {
this.taskName = task.getTaskName();
}
this.activeMinutes = task.getWorkTime(); this.activeMinutes = task.getWorkTime();
this.eta = task.getEta(); this.eta = task.getEta();
this.limit = task.getDeadline(); this.limit = task.getDeadline();
@ -28,6 +34,7 @@ public class TaskOverviewInfo {
this.overdue = LocalDate.now().isAfter(task.getDeadline()); this.overdue = LocalDate.now().isAfter(task.getDeadline());
} }
this.finishable = task.isFinishable(); this.finishable = task.isFinishable();
this.hasSubtasks = !task.getSubtasks().isEmpty();
} }
public long getTaskID() { public long getTaskID() {
@ -85,4 +92,12 @@ public class TaskOverviewInfo {
public void setFinishable(boolean finishable) { public void setFinishable(boolean finishable) {
this.finishable = finishable; this.finishable = finishable;
} }
public boolean isHasSubtasks() {
return hasSubtasks;
}
public void setHasSubtasks(boolean hasSubtasks) {
this.hasSubtasks = hasSubtasks;
}
} }

View File

@ -1,6 +1,7 @@
package core.api.models.timemanager.tasks; package core.api.models.timemanager.tasks;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.services.TaskSeriesService;
public class TaskShortInfo { public class TaskShortInfo {
@ -11,7 +12,12 @@ public class TaskShortInfo {
public TaskShortInfo(Task task) { public TaskShortInfo(Task task) {
this.taskID = task.getTaskID(); this.taskID = task.getTaskID();
this.taskName = task.getTaskName(); if(task.getTaskSerieItem() != null) {
this.taskName = TaskSeriesService.insertNameIndex(task.getTaskSerieItem().getSeriesIndex(), task.getTaskName());
} else {
this.taskName = task.getTaskName();
}
this.finishable = task.isFinishable(); this.finishable = task.isFinishable();
} }

View File

@ -3,6 +3,7 @@ package core.api.models.timemanager.tasks;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup; import core.entities.timemanager.Taskgroup;
import core.services.TaskSeriesService;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
@ -31,7 +32,11 @@ public class TaskTaskgroupInfo {
public TaskTaskgroupInfo(Task task) { public TaskTaskgroupInfo(Task task) {
this.taskID = task.getTaskID(); this.taskID = task.getTaskID();
this.taskName = task.getTaskName(); if(task.getTaskSerieItem() != null) {
this.taskName = TaskSeriesService.insertNameIndex(task.getTaskSerieItem().getSeriesIndex(), task.getTaskName());
} else {
this.taskName = task.getTaskName();
}
this.eta = task.getEta(); this.eta = task.getEta();
this.startDate = task.getStartDate(); this.startDate = task.getStartDate();
this.deadline = task.getDeadline(); this.deadline = task.getDeadline();

View File

@ -0,0 +1,8 @@
package core.api.models.timemanager.tasks.repeatinginfo;
public enum DeadlineStrategy {
FIX_DEADLINE,
DEADLINE_EQUAL_START,
DEADLINE_FIT_START
}

View File

@ -0,0 +1,29 @@
package core.api.models.timemanager.tasks.repeatinginfo;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDate;
public class TaskRepeatDayInfo {
private int offset;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
private LocalDate endingDate;
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public LocalDate getEndingDate() {
return endingDate;
}
public void setEndingDate(LocalDate endingDate) {
this.endingDate = endingDate;
}
}

View File

@ -0,0 +1,36 @@
package core.api.models.timemanager.tasks.repeatinginfo;
import core.api.models.timemanager.tasks.TaskEntityInfo;
import core.entities.timemanager.Task;
import java.time.DayOfWeek;
public class TaskRepeatWeekDayInfo {
private int offset;
private long taskID;
private DayOfWeek dayOfWeek;
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public long getTaskID() {
return taskID;
}
public void setTaskID(long taskID) {
this.taskID = taskID;
}
public DayOfWeek getDayOfWeek() {
return dayOfWeek;
}
public void setDayOfWeek(DayOfWeek dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}
}

View File

@ -0,0 +1,35 @@
package core.api.models.timemanager.tasks.repeatinginfo;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.hibernate.validator.constraints.Length;
import util.Tupel;
import javax.validation.constraints.Size;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
public class TaskRepeatWeekInfo {
@Size(min = 1, max = 7)
private List<TaskRepeatWeekDayInfo> weekDayInfos;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
private LocalDate endDate;
public List<TaskRepeatWeekDayInfo> getWeekDayInfos() {
return weekDayInfos;
}
public void setWeekDayInfos(List<TaskRepeatWeekDayInfo> weekDayInfos) {
this.weekDayInfos = weekDayInfos;
}
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}
}

View File

@ -0,0 +1,53 @@
package core.api.models.users;
import core.entities.User;
public class NtfyInformation {
private String ntfy_host;
private String ntfy_topic;
private String ntfy_user;
private String ntfy_token;
public NtfyInformation(User user) {
this.ntfy_host = user.getNtfy_host();
this.ntfy_topic = user.getNtfy_topic();
this.ntfy_user = "****";
this.ntfy_token = "****";
}
public NtfyInformation() {
}
public String getNtfy_host() {
return ntfy_host;
}
public void setNtfy_host(String ntfy_host) {
this.ntfy_host = ntfy_host;
}
public String getNtfy_topic() {
return ntfy_topic;
}
public void setNtfy_topic(String ntfy_topic) {
this.ntfy_topic = ntfy_topic;
}
public String getNtfy_user() {
return ntfy_user;
}
public void setNtfy_user(String ntfy_user) {
this.ntfy_user = ntfy_user;
}
public String getNtfy_token() {
return ntfy_token;
}
public void setNtfy_token(String ntfy_token) {
this.ntfy_token = ntfy_token;
}
}

View File

@ -42,6 +42,11 @@ public class User {
inverseJoinColumns = @JoinColumn(name = "role_id")) inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<RoleEntity> roles = new HashSet<>(); private Set<RoleEntity> roles = new HashSet<>();
private String ntfy_host;
private String ntfy_topic;
private String ntfy_username;
private String ntfy_token;
public User() { public User() {
} }
@ -98,6 +103,38 @@ public class User {
this.roles = roles; this.roles = roles;
} }
public String getNtfy_host() {
return ntfy_host;
}
public void setNtfy_host(String ntfy_host) {
this.ntfy_host = ntfy_host;
}
public String getNtfy_topic() {
return ntfy_topic;
}
public void setNtfy_topic(String ntfy_topic) {
this.ntfy_topic = ntfy_topic;
}
public String getNtfy_username() {
return ntfy_username;
}
public void setNtfy_username(String ntfy_username) {
this.ntfy_username = ntfy_username;
}
public String getNtfy_token() {
return ntfy_token;
}
public void setNtfy_token(String ntfy_token) {
this.ntfy_token = ntfy_token;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;

View File

@ -124,4 +124,8 @@ public abstract class AbstractSchedule {
return (int) duration.toMinutes(); return (int) duration.toMinutes();
} }
} }
public abstract AbstractSchedule cloneSchedule();
public abstract void shiftSchedule(long numberDays);
} }

View File

@ -71,4 +71,15 @@ public class AdvancedTaskSchedule extends AbstractSchedule {
public boolean isMissed(LocalDateTime timeReference) { public boolean isMissed(LocalDateTime timeReference) {
return startTime == null && scheduleEnd.toLocalDate().isBefore(timeReference.toLocalDate()); return startTime == null && scheduleEnd.toLocalDate().isBefore(timeReference.toLocalDate());
} }
@Override
public AbstractSchedule cloneSchedule() {
return new AdvancedTaskSchedule(this.task, this.scheduleStart, this.scheduleEnd);
}
@Override
public void shiftSchedule(long numberDays) {
this.scheduleStart = this.scheduleStart.plusDays(numberDays);
this.scheduleEnd = this.scheduleEnd.plusDays(numberDays);
}
} }

View File

@ -52,4 +52,14 @@ public class BasicTaskSchedule extends AbstractSchedule{
public boolean isMissed(LocalDateTime timeReference) { public boolean isMissed(LocalDateTime timeReference) {
return startTime == null && scheduleDate.isBefore(timeReference.toLocalDate()); return startTime == null && scheduleDate.isBefore(timeReference.toLocalDate());
} }
@Override
public AbstractSchedule cloneSchedule() {
return new BasicTaskSchedule(this.task, this.scheduleDate);
}
@Override
public void shiftSchedule(long numberDays) {
this.scheduleDate = this.scheduleDate.plusDays(numberDays);
}
} }

View File

@ -1,14 +1,15 @@
package core.entities.timemanager; package core.entities.timemanager;
import core.api.models.timemanager.tasks.TaskFieldInfo; import core.api.models.timemanager.tasks.TaskFieldInfo;
import core.api.models.timemanager.tasks.repeatinginfo.DeadlineStrategy;
import util.Tripel;
import util.Tupel;
import javax.persistence.*; import javax.persistence.*;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.time.temporal.ChronoUnit;
import java.util.List; import java.util.*;
import java.util.Objects;
import java.util.Set;
@Entity @Entity
@Table(name = "tasks") @Table(name = "tasks")
@ -22,21 +23,23 @@ public class Task {
@JoinColumn(name = "taskgroup_id") @JoinColumn(name = "taskgroup_id")
private Taskgroup taskgroup; private Taskgroup taskgroup;
private String taskName; private String taskName;
private LocalDate startDate; private LocalDate startDate;
private LocalDate deadline; private LocalDate deadline;
private int eta; private int eta;
private boolean finished; private boolean finished;
private boolean finishable; private boolean finishable;
@OneToMany(mappedBy = "task", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@OneToMany(mappedBy = "task", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<AbstractSchedule> basicTaskSchedules; private List<AbstractSchedule> basicTaskSchedules;
private int workTime; private int workTime;
@OneToOne(mappedBy = "task", cascade = CascadeType.ALL, orphanRemoval = true)
private TaskSerieItem taskSerieItem;
@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.EAGER)
private Set<Task> subtasks;
@ManyToOne
@JoinColumn(name = "parent")
private Task parent;
public Task() { public Task() {
this.basicTaskSchedules = new ArrayList<>(); this.basicTaskSchedules = new ArrayList<>();
@ -52,6 +55,57 @@ public class Task {
this.finishable = taskFieldInfo.isFinishable(); this.finishable = taskFieldInfo.isFinishable();
} }
public Tripel<Task, Collection<Task>, Collection<AbstractSchedule>> cloneTask() {
Collection<Task> clonedTasks = new ArrayList<>();
Collection<AbstractSchedule> clonedSchedules = new ArrayList<>();
Task clonedTask = new Task();
clonedTasks.add(clonedTask);
clonedTask.setTaskgroup(this.getTaskgroup());
clonedTask.setTaskName(this.taskName);
clonedTask.setEta(this.eta);
clonedTask.setFinished(this.finished);
clonedTask.setFinishable(this.finishable);
clonedTask.setStartDate(this.startDate);
clonedTask.setDeadline(this.deadline);
for(AbstractSchedule abstractSchedule : this.basicTaskSchedules) {
AbstractSchedule clonedSchedule = abstractSchedule.cloneSchedule();
clonedSchedules.add(clonedSchedule);
clonedTask.getBasicTaskSchedules().clear();
clonedTask.getBasicTaskSchedules().add(clonedSchedule);
clonedSchedule.setTask(clonedTask);
}
Set<Task> clonedSubtasks = new HashSet<>();
for(Task task : this.subtasks) {
Tripel<Task, Collection<Task>, Collection<AbstractSchedule>> clonedSubtask = task.cloneTask();
clonedSubtask.getValue00().setParent(clonedTask);
clonedSubtasks.add(clonedSubtask.getValue00());
clonedTasks.addAll(clonedSubtask.getValue01());
clonedSchedules.addAll(clonedSubtask.getValue02());
}
clonedTask.setSubtasks(clonedSubtasks);
return new Tripel<>(clonedTask, clonedTasks, clonedSchedules);
}
public void shiftTask(long offset) {
this.setStartDate(this.getStartDate().plusDays(offset));
this.setDeadline(this.getDeadline().plusDays(offset));
for(AbstractSchedule abstractSchedule : this.basicTaskSchedules) {
abstractSchedule.shiftSchedule(offset);
}
for(Task subtask: this.subtasks) {
subtask.shiftTask(offset);
}
}
public long getTaskID() { public long getTaskID() {
return taskID; return taskID;
} }
@ -124,6 +178,14 @@ public class Task {
this.taskID = taskID; this.taskID = taskID;
} }
public TaskSerieItem getTaskSerieItem() {
return taskSerieItem;
}
public void setTaskSerieItem(TaskSerieItem taskSerieItem) {
this.taskSerieItem = taskSerieItem;
}
public List<AbstractSchedule> getBasicTaskSchedules() { public List<AbstractSchedule> getBasicTaskSchedules() {
if(basicTaskSchedules == null) { if(basicTaskSchedules == null) {
return new ArrayList<>(); return new ArrayList<>();
@ -135,12 +197,33 @@ public class Task {
this.basicTaskSchedules = basicTaskSchedules; this.basicTaskSchedules = basicTaskSchedules;
} }
public void addSubtask(Task subtask) {
subtask.setParent(this);
this.subtasks.add(subtask);
}
public Set<Task> getSubtasks() {
return subtasks;
}
public void setSubtasks(Set<Task> subtasks) {
this.subtasks = subtasks;
}
public Task getParent() {
return parent;
}
public void setParent(Task parent) {
this.parent = parent;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Task task = (Task) o; Task task = (Task) o;
return taskID == task.taskID && eta == task.eta && finished == task.finished && workTime == task.workTime && Objects.equals(taskgroup, task.taskgroup) && Objects.equals(taskName, task.taskName) && Objects.equals(startDate, task.startDate) && Objects.equals(deadline, task.deadline); return taskID == task.taskID;
} }
@Override @Override

View File

@ -0,0 +1,44 @@
package core.entities.timemanager;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "task_series")
public class TaskSerie {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long taskSerieID;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "taskSerie", orphanRemoval = true)
List<TaskSerieItem> tasks = new ArrayList<>();
public long getTaskSerieID() {
return taskSerieID;
}
public void setTaskSerieID(long taskSerieID) {
this.taskSerieID = taskSerieID;
}
public List<TaskSerieItem> getTasks() {
return tasks;
}
public void setTasks(List<TaskSerieItem> tasks) {
this.tasks = tasks;
}
public TaskSerieItem addTask(Task task) {
TaskSerieItem taskSerieItem = new TaskSerieItem(this, task, this.tasks.size()+1);
this.tasks.add(taskSerieItem);
return taskSerieItem;
}
public void addItem(TaskSerieItem taskSerieItem) {
this.tasks.add(taskSerieItem);
taskSerieItem.setTaskSerie(this);
}
}

View File

@ -0,0 +1,84 @@
package core.entities.timemanager;
import javax.persistence.*;
import java.util.Objects;
@Entity
@Table(name = "task_series_items")
public class TaskSerieItem {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long itemID;
@ManyToOne
@JoinColumn(referencedColumnName = "taskSerieID")
private TaskSerie taskSerie;
@OneToOne
@JoinColumn(name = "task_id")
private Task task;
private int seriesIndex;
public TaskSerieItem(TaskSerie taskSerie, Task task, int index) {
this.taskSerie = taskSerie;
this.seriesIndex = index;
this.task = task;
}
public TaskSerieItem() {
}
public TaskSerieItem(Task task, int itemIndex) {
this.taskSerie = null;
this.seriesIndex = itemIndex;
this.task = task;
}
public long getItemID() {
return itemID;
}
public void setItemID(long itemID) {
this.itemID = itemID;
}
public TaskSerie getTaskSerie() {
return taskSerie;
}
public void setTaskSerie(TaskSerie taskSerie) {
this.taskSerie = taskSerie;
}
public int getSeriesIndex() {
return seriesIndex;
}
public void setSeriesIndex(int seriesIndex) {
this.seriesIndex = seriesIndex;
}
public Task getTask() {
return task;
}
public void setTask(Task task) {
this.task = task;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TaskSerieItem that = (TaskSerieItem) o;
return itemID == that.itemID;
}
@Override
public int hashCode() {
return Objects.hash(itemID);
}
}

View File

@ -25,7 +25,7 @@ public class Taskgroup {
@JoinColumn(name = "taskgroupuser", nullable = false) @JoinColumn(name = "taskgroupuser", nullable = false)
private User user; private User user;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER) @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<Taskgroup> children; private Set<Taskgroup> children;
@ManyToOne @ManyToOne
@ -33,7 +33,7 @@ public class Taskgroup {
private Taskgroup parent; private Taskgroup parent;
@OneToMany(mappedBy = "taskgroup", cascade = CascadeType.ALL, fetch = FetchType.EAGER) @OneToMany(mappedBy = "taskgroup", cascade = CascadeType.REMOVE, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<Task> tasks; private Set<Task> tasks;
public Taskgroup(String taskgroupName, User user) { public Taskgroup(String taskgroupName, User user) {
@ -136,54 +136,5 @@ public class Taskgroup {
return Objects.hash(taskgroupID); return Objects.hash(taskgroupID);
} }
public List<TaskgroupActivityInfo> calcActivityInfo(boolean includeChildTasks, LocalDate start, LocalDate end) {
HashMap<LocalDate, Integer> activityInfos = new HashMap<>();
if(includeChildTasks) {
Queue<Taskgroup> queue = new LinkedList<>(children);
while(!queue.isEmpty()) {
Taskgroup childTraskgroup = queue.poll();
LocalDate currentDate = start;
while(!currentDate.isAfter(end)) {
int activeMinutes = 0;
for(Task task : childTraskgroup.getTasks()) {
activeMinutes += task.calcOverallActivityInfo(currentDate);
}
if(activityInfos.containsKey(currentDate)) {
activityInfos.put(currentDate, activityInfos.get(currentDate) + activeMinutes);
} else {
activityInfos.put(currentDate, activeMinutes);
}
currentDate = currentDate.plusDays(1);
}
queue.addAll(childTraskgroup.getChildren());
}
}
LocalDate currentDate = start;
while(!currentDate.isAfter(end)) {
int activeMinutes = 0;
for(Task task : tasks) {
activeMinutes += task.calcOverallActivityInfo(currentDate);
}
if(activityInfos.containsKey(currentDate)) {
activityInfos.put(currentDate, activityInfos.get(currentDate) + activeMinutes);
} else {
activityInfos.put(currentDate, activeMinutes);
}
currentDate = currentDate.plusDays(1);
}
List<TaskgroupActivityInfo> taskgroupActivityInfos = new ArrayList<>();
for(Map.Entry<LocalDate, Integer> entry : activityInfos.entrySet()) {
taskgroupActivityInfos.add(new TaskgroupActivityInfo(entry.getValue(), entry.getKey()));
}
return taskgroupActivityInfos;
}
} }

View File

@ -0,0 +1,15 @@
package core.repositories.timemanager;
import core.entities.timemanager.AdvancedTaskSchedule;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.List;
@Repository
public interface AdvancedScheduleRepository extends CrudRepository<AdvancedTaskSchedule, Long> {
}

View File

@ -2,10 +2,12 @@ package core.repositories.timemanager;
import core.entities.timemanager.AbstractSchedule; import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.Taskgroup; import core.entities.timemanager.Taskgroup;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -19,4 +21,13 @@ public interface ScheduleRepository extends CrudRepository<AbstractSchedule, Lon
@Query(value = "SELECT s FROM AbstractSchedule s WHERE s.task.taskgroup.user.username = ?1 AND s.startTime is NOT NULL and s.stopTime is NULL") @Query(value = "SELECT s FROM AbstractSchedule s WHERE s.task.taskgroup.user.username = ?1 AND s.startTime is NOT NULL and s.stopTime is NULL")
Optional<AbstractSchedule> getActiveScheduleOfUser(String username); Optional<AbstractSchedule> getActiveScheduleOfUser(String username);
@Modifying
@Transactional
@Query(value = "DELETE FROM AbstractSchedule a WHERE a.task IN (SELECT t FROM Task t WHERE t.taskgroup = ?1)")
void deleteByTaskgroup(Taskgroup taskgroup);
@Query(value = "SELECT s FROM AbstractSchedule s WHERE s.task.taskgroup.user.username = ?1 AND s.startTime is NOT NULL AND s.stopTime IS NOT NULL")
List<AbstractSchedule> getAllFinishedSchedulesByUser(String username);
} }

View File

@ -20,10 +20,12 @@ public interface TaskRepository extends CrudRepository<Task, Long> {
@Modifying @Modifying
@Transactional @Transactional
@Query(value = "DELETE FROM Task t WHERE t.taskgroup = ?1")
void deleteAllByTaskgroup(Taskgroup taskgroup); void deleteAllByTaskgroup(Taskgroup taskgroup);
@Transactional @Transactional
@Modifying @Modifying
@Query(value = "DELETE FROM Task t WHERE t.taskID = ?1")
void deleteByTaskID(long taskID); void deleteByTaskID(long taskID);
@Query(value = "SELECT t FROM Task t WHERE t.taskgroup.user.username = ?1 AND t.deadline is NOT NULL AND t.deadline < ?2 AND t.finished = FALSE") @Query(value = "SELECT t FROM Task t WHERE t.taskgroup.user.username = ?1 AND t.deadline is NOT NULL AND t.deadline < ?2 AND t.finished = FALSE")
@ -34,4 +36,17 @@ public interface TaskRepository extends CrudRepository<Task, Long> {
@Query(value = "SELECT t FROM Task t WHERE t.taskgroup.user.username = ?1 AND (t.startDate IS NULL OR t.startDate <= ?2) AND t.finished = FALSE") @Query(value = "SELECT t FROM Task t WHERE t.taskgroup.user.username = ?1 AND (t.startDate IS NULL OR t.startDate <= ?2) AND t.finished = FALSE")
List<Task> findAllActive(String username, LocalDate now); List<Task> findAllActive(String username, LocalDate now);
@Query(value = "SELECT t FROM Task t WHERE t.taskgroup = ?1")
List<Task> findAllByTaskgroup(Taskgroup taskgroup);
@Modifying
@Transactional
@Query(value = "UPDATE Task t SET t.parent = null WHERE t.taskgroup = ?1")
void deleteTaskHierarchyWhereTaskgroup(Taskgroup taskgroup);
@Modifying
@Transactional
@Query(value = "DELETE Task t WHERE t.parent = ?1")
void deleteTasksByParent(Task parentTask);
} }

View File

@ -0,0 +1,19 @@
package core.repositories.timemanager;
import core.entities.timemanager.TaskSerieItem;
import core.entities.timemanager.Taskgroup;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
@Repository
public interface TaskSerieItemRepository extends CrudRepository<TaskSerieItem, Long> {
@Query(value = "DELETE FROM TaskSerieItem tsi WHERE tsi.task IN (SELECT t FROM Task t WHERE t.taskgroup = ?1)")
@Modifying
@Transactional
void deleteByTaskgroup(Taskgroup taskgroup);
}

View File

@ -0,0 +1,23 @@
package core.repositories.timemanager;
import core.entities.timemanager.TaskSerie;
import core.entities.timemanager.Taskgroup;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
import java.util.List;
@Repository
public interface TaskSeriesRepository extends CrudRepository<TaskSerie, Long> {
@Query("SELECT DISTINCT ts FROM TaskSerie ts JOIN ts.tasks tsi JOIN tsi.task t WHERE t.taskgroup = :taskgroup")
List<TaskSerie> findByTaskgroup(@Param("taskgroup")Taskgroup taskgroup);
@Modifying
@Transactional
@Query(value = "DELETE FROM TaskSerie ts WHERE ts.tasks.size = 0")
void deleteUnreferenced();
}

View File

@ -1,5 +1,8 @@
package core.services; package core.services;
import core.api.models.auth.SimpleStatusResponse;
import org.springframework.http.ResponseEntity;
public class PermissionResult <T> extends ServiceResult<T> { public class PermissionResult <T> extends ServiceResult<T> {
private boolean hasPermissions; private boolean hasPermissions;
@ -30,11 +33,25 @@ public class PermissionResult <T> extends ServiceResult<T> {
this.hasPermissions = hasPermissions; this.hasPermissions = hasPermissions;
} }
public boolean isHasPermissions() { public boolean isNoPermissions() {
return hasPermissions; return !hasPermissions;
} }
public void setHasPermissions(boolean hasPermissions) { public void setHasPermissions(boolean hasPermissions) {
this.hasPermissions = hasPermissions; this.hasPermissions = hasPermissions;
} }
@Override
public ResponseEntity<?> mapToResponseEntity() {
if(isNoPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} else {
return super.mapToResponseEntity();
}
}
@Override
public boolean hasIssue() {
return super.hasIssue() || isNoPermissions();
}
} }

View File

@ -1,5 +1,8 @@
package core.services; package core.services;
import core.api.models.auth.SimpleStatusResponse;
import org.springframework.http.ResponseEntity;
public enum ServiceExitCode { public enum ServiceExitCode {
OK, OK,
@ -7,4 +10,13 @@ public enum ServiceExitCode {
MISSING_ENTITY, MISSING_ENTITY,
INVALID_OPERATION, INVALID_OPERATION,
INVALID_PARAMETER; INVALID_PARAMETER;
public ResponseEntity<SimpleStatusResponse> mapToResponseEntity() {
return switch (this) {
case OK -> ResponseEntity.ok(new SimpleStatusResponse("success"));
case MISSING_ENTITY -> ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
case ENTITY_ALREADY_EXIST -> ResponseEntity.status(409).body(new SimpleStatusResponse("failed"));
case INVALID_OPERATION, INVALID_PARAMETER -> ResponseEntity.status(400).body(new SimpleStatusResponse("failed"));
};
}
} }

View File

@ -1,5 +1,8 @@
package core.services; package core.services;
import core.api.models.auth.SimpleStatusResponse;
import org.springframework.http.ResponseEntity;
public class ServiceResult <T> { public class ServiceResult <T> {
private ServiceExitCode exitCode; private ServiceExitCode exitCode;
@ -34,4 +37,12 @@ public class ServiceResult <T> {
public void setResult(T result) { public void setResult(T result) {
this.result = result; this.result = result;
} }
public boolean hasIssue() {
return exitCode != ServiceExitCode.OK;
}
public ResponseEntity<?> mapToResponseEntity() {
return exitCode.mapToResponseEntity();
}
} }

View File

@ -0,0 +1,113 @@
package core.services;
import core.api.models.timemanager.history.ActivityInfo;
import core.api.models.timemanager.history.TaskgroupActivityInfo;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.Taskgroup;
import core.repositories.timemanager.ScheduleRepository;
import core.repositories.timemanager.TaskgroupRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
@Service
public class StatisticService {
@Autowired private ScheduleRepository scheduleRepository;
public HashMap<Taskgroup, HashMap<LocalDate, Integer>> calcActivityByUser(Taskgroup taskgroup, String username, LocalDate startinDate, LocalDate endingDate) {
HashMap<Taskgroup, HashMap<LocalDate, Integer>> taskgroupActivityInfos = new HashMap<>();
List<AbstractSchedule> startedSchedules = scheduleRepository.getAllFinishedSchedulesByUser(username);
for(AbstractSchedule schedule : startedSchedules) {
if(schedule.getStartTime().toLocalDate().isAfter(endingDate) || schedule.getStopTime().toLocalDate().isBefore(startinDate)) {
continue;
}
Taskgroup topTaskgroup;
if(taskgroup == null) {
topTaskgroup = findTopTaskgroup(schedule.getTask().getTaskgroup());
} else {
topTaskgroup = findTaskgroupOfLayer(taskgroup, schedule.getTask().getTaskgroup());
if(topTaskgroup == null) {
continue;
}
}
HashMap<LocalDate, Integer> taskgroupActivity;
if(taskgroupActivityInfos.containsKey(topTaskgroup)) {
taskgroupActivity = taskgroupActivityInfos.get(topTaskgroup);
} else {
taskgroupActivity = new HashMap<>();
taskgroupActivityInfos.put(topTaskgroup, taskgroupActivity);
}
if(schedule.getStartTime().toLocalDate().isEqual(schedule.getStopTime().toLocalDate())) {
insertActivity(taskgroupActivity, schedule.getStartTime().toLocalDate(), schedule.getActiveTime());
} else {
//Starting Date
LocalDateTime startingDayEnd = schedule.getStartTime().toLocalDate().atTime(LocalTime.MAX);
Duration startingActivity = Duration.between(schedule.getStartTime(), startingDayEnd);
insertActivity(taskgroupActivity, schedule.getStartTime().toLocalDate(), (int) startingActivity.toMinutes());
//Ending Date
LocalDateTime endingDayStart = schedule.getStopTime().toLocalDate().atStartOfDay();
Duration endingActivity = Duration.between(endingDayStart, schedule.getStopTime());
insertActivity(taskgroupActivity, schedule.getStopTime().toLocalDate(), (int) endingActivity.toMinutes());
}
}
return taskgroupActivityInfos;
}
public static List<TaskgroupActivityInfo> convertInternActivityInfo(HashMap<Taskgroup, HashMap<LocalDate, Integer>> taskgroupActivity) {
List<TaskgroupActivityInfo> taskgroupActivityInfos = new ArrayList<>();
for(Map.Entry<Taskgroup, HashMap<LocalDate, Integer>> entry: taskgroupActivity.entrySet()) {
List<ActivityInfo> activityInfos = new ArrayList<>();
for(Map.Entry<LocalDate, Integer> dateActivity : entry.getValue().entrySet()) {
activityInfos.add(new ActivityInfo(dateActivity.getKey(), dateActivity.getValue()));
}
taskgroupActivityInfos.add(new TaskgroupActivityInfo(new TaskgroupEntityInfo(entry.getKey()), activityInfos));
}
return taskgroupActivityInfos;
}
private static void insertActivity(HashMap<LocalDate, Integer> activityInfo, LocalDate date, int deltaActivity) {
if(activityInfo.containsKey(date)) {
int activity = activityInfo.get(date);
activity += deltaActivity;
activityInfo.put(date, activity);
} else {
activityInfo.put(date, deltaActivity);
}
}
private Taskgroup findTopTaskgroup(Taskgroup taskgroup) {
Taskgroup currentTaskgroup = taskgroup;
while(currentTaskgroup.getParent() != null) {
currentTaskgroup = currentTaskgroup.getParent();
}
return currentTaskgroup;
}
private Taskgroup findTaskgroupOfLayer(Taskgroup targetLayer, Taskgroup childTaskgroup) {
if(targetLayer.getTaskgroupID() == childTaskgroup.getTaskgroupID()) {
return childTaskgroup;
}
Taskgroup currentTaskgroup = childTaskgroup;
while (currentTaskgroup.getParent() != null && currentTaskgroup.getParent().getTaskgroupID() != targetLayer.getTaskgroupID()) {
currentTaskgroup = currentTaskgroup.getParent();
}
if(currentTaskgroup.getParent() == null) {
return null;
}
return currentTaskgroup;
}
}

View File

@ -1,16 +1,15 @@
package core.services; package core.services;
import core.api.models.timemanager.history.PastScheduleInfo; import core.api.models.timemanager.history.PastScheduleInfo;
import core.api.models.timemanager.taskSchedule.ManualScheduleStopInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleFieldInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.BasicScheduleFieldInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.BasicScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.ForgottenScheduleInfo; import core.api.models.timemanager.taskSchedule.ForgottenScheduleInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.ScheduleInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.ScheduleInfo;
import core.entities.timemanager.AbstractSchedule; import core.entities.timemanager.*;
import core.entities.timemanager.AdvancedTaskSchedule;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task;
import core.repositories.UserRepository; import core.repositories.UserRepository;
import core.repositories.timemanager.AdvancedScheduleRepository;
import core.repositories.timemanager.ScheduleRepository; import core.repositories.timemanager.ScheduleRepository;
import core.repositories.timemanager.TaskRepository; import core.repositories.timemanager.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -21,6 +20,7 @@ import java.time.Duration;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.*; import java.util.*;
@Service @Service
@ -30,6 +30,7 @@ public class TaskScheduleService {
@Autowired private UserRepository userRepository; @Autowired private UserRepository userRepository;
@Autowired @Autowired
private TaskRepository taskRepository; private TaskRepository taskRepository;
@Autowired private AdvancedScheduleRepository advancedScheduleRepository;
public List<AbstractSchedule> getAllSchedulesOfUser(String username) { public List<AbstractSchedule> getAllSchedulesOfUser(String username) {
return scheduleRepository.findAllByUsername(username); return scheduleRepository.findAllByUsername(username);
@ -223,6 +224,19 @@ public class TaskScheduleService {
return findScheduleByDate(allSchedules, date); return findScheduleByDate(allSchedules, date);
} }
public List<AdvancedTaskSchedule> findSchedulesByDate(LocalDate date) {
Iterable<AdvancedTaskSchedule> allSchedules = advancedScheduleRepository.findAll();
List<AdvancedTaskSchedule> schedulesToday = new ArrayList<>();
for(AdvancedTaskSchedule advancedTaskSchedule : allSchedules) {
if(advancedTaskSchedule.getScheduleStart().toLocalDate().equals(date) && advancedTaskSchedule.getStartTime() == null &&
advancedTaskSchedule.getScheduleStart().isBefore(LocalDateTime.now())) {
schedulesToday.add(advancedTaskSchedule);
}
}
return schedulesToday;
}
private List<AbstractSchedule> findScheduleByDate(List<AbstractSchedule> schedules, LocalDate date) { private List<AbstractSchedule> findScheduleByDate(List<AbstractSchedule> schedules, LocalDate date) {
List<AbstractSchedule> filteredSchedules = new ArrayList<>(); List<AbstractSchedule> filteredSchedules = new ArrayList<>();
for(AbstractSchedule schedule : schedules) { for(AbstractSchedule schedule : schedules) {
@ -237,4 +251,13 @@ public class TaskScheduleService {
} }
return filteredSchedules; return filteredSchedules;
} }
public void finishScheduleManual(AbstractSchedule schedule, ManualScheduleStopInfo manualScheduleStopInfo) {
schedule.setStopTime(schedule.getStartTime().plusMinutes(manualScheduleStopInfo.getDuration()));
scheduleRepository.save(schedule);
}
public void deleteSchedulesByTaskgroup(Taskgroup taskgroup) {
scheduleRepository.deleteByTaskgroup(taskgroup);
}
} }

View File

@ -0,0 +1,176 @@
package core.services;
import core.api.models.timemanager.tasks.repeatinginfo.DeadlineStrategy;
import core.api.models.timemanager.tasks.repeatinginfo.TaskRepeatDayInfo;
import core.api.models.timemanager.tasks.repeatinginfo.TaskRepeatWeekDayInfo;
import core.api.models.timemanager.tasks.repeatinginfo.TaskRepeatWeekInfo;
import core.entities.timemanager.*;
import core.repositories.timemanager.ScheduleRepository;
import core.repositories.timemanager.TaskRepository;
import core.repositories.timemanager.TaskSerieItemRepository;
import core.repositories.timemanager.TaskSeriesRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import util.Tupel;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
@Service
public class TaskSeriesService {
@Autowired private TaskRepository taskRepository;
@Autowired private TaskSeriesRepository taskSeriesRepository;
@Autowired private TaskSerieItemRepository taskSerieItemRepository;
@Autowired private ScheduleRepository scheduleRepository;
public ServiceExitCode createTaskSeries(TaskRepeatWeekInfo taskRepeatInfo) {
HashMap<Task, Integer> offsetMap = calcWeeklyOffsetMap(taskRepeatInfo);
TaskSerie taskSerie = new TaskSerie();
List<Task> clonedTasks = new ArrayList<>();
List<AbstractSchedule> clonedSchedules = new ArrayList<>();
int weekDayIndex = 0;
for(Map.Entry<Task, Integer> repeatingTaskInfo: offsetMap.entrySet()) {
Task rootTask = repeatingTaskInfo.getKey();
addRootSubTasksToTaskSerie(taskSerie, rootTask, weekDayIndex);
int itemIndex = weekDayIndex +1;
Tupel<Collection<Task>, Collection<AbstractSchedule>> repeatingResult = repeatTask(rootTask, taskRepeatInfo.getEndDate(), offsetMap, taskSerie, itemIndex);
clonedTasks.addAll(repeatingResult.getValue00());
clonedSchedules.addAll(repeatingResult.getValue01());
weekDayIndex++;
}
taskSeriesRepository.save(taskSerie);
taskRepository.saveAll(clonedTasks);
taskSerieItemRepository.saveAll(taskSerie.getTasks());
scheduleRepository.saveAll(clonedSchedules);
return ServiceExitCode.OK;
}
private Tupel<Collection<Task>, Collection<AbstractSchedule>> repeatTask(Task rootTask, LocalDate endingDate, HashMap<Task, Integer> offsetMap,TaskSerie taskSerie, int itemIndex) {
List<Task> clonedTasks = new ArrayList<>();
List<AbstractSchedule> clonedSchedules = new ArrayList<>();
LocalDate currentDate = rootTask.getStartDate().plusDays(offsetMap.get(rootTask));
long index = 1;
while(currentDate.isBefore(endingDate)) {
var cloneResult = rootTask.cloneTask();
Task clonedRootTask = cloneResult.getValue00();
clonedTasks.addAll(cloneResult.getValue01());
clonedSchedules.addAll(cloneResult.getValue02());
for(Task clonedTask : cloneResult.getValue01()) {
TaskSerieItem item = new TaskSerieItem(clonedTask, itemIndex);
taskSerie.addItem(item);
}
clonedRootTask.shiftTask(index * offsetMap.get(rootTask));
currentDate = currentDate.plusDays(offsetMap.get(rootTask));
itemIndex += offsetMap.size();
index++;
}
return new Tupel<>(clonedTasks, clonedSchedules);
}
private HashMap<Task, Integer> calcWeeklyOffsetMap(TaskRepeatWeekInfo weekInfo) throws NoSuchElementException {
HashMap<Task,Integer> offsetMap = new HashMap<>();
weekInfo.getWeekDayInfos().sort(Comparator.comparing(TaskRepeatWeekDayInfo::getDayOfWeek));
for(int i=0; i<weekInfo.getWeekDayInfos().size(); i++) {
Optional<Task> requestedTask = taskRepository.findById(weekInfo.getWeekDayInfos().get(i).getTaskID());
if(requestedTask.isEmpty()) {
throw new NoSuchElementException();
} else {
int offset = weekInfo.getWeekDayInfos().get(i).getOffset()-1;
offsetMap.put(requestedTask.get(), offset);
}
}
return offsetMap;
}
public ServiceExitCode createTaskSeries(Task rootTask, TaskRepeatDayInfo taskRepeatInfo) {
TaskSerie taskSerie = new TaskSerie();
addRootSubTasksToTaskSerie(taskSerie, rootTask, 0);
HashMap<Task, Integer> offsetMap = new HashMap<>();
offsetMap.put(rootTask, taskRepeatInfo.getOffset());
var repeatingResult = repeatTask(rootTask, taskRepeatInfo.getEndingDate(), offsetMap, taskSerie, 1);
List<Task> clonedTasks = new ArrayList<>(repeatingResult.getValue00());
List<AbstractSchedule> clonedSchedules = new ArrayList<>(repeatingResult.getValue01());
taskSeriesRepository.save(taskSerie);
taskRepository.saveAll(clonedTasks);
taskSerieItemRepository.saveAll(taskSerie.getTasks());
scheduleRepository.saveAll(clonedSchedules);
return ServiceExitCode.OK;
}
private void addRootSubTasksToTaskSerie(TaskSerie taskSerie, Task rootTask, int index) {
Queue<Task> taskQueue = new LinkedList<>(Collections.singletonList(rootTask));
while(!taskQueue.isEmpty()) {
Task currentTask = taskQueue.poll();
TaskSerieItem taskSerieItem = new TaskSerieItem(currentTask, index);
taskSerie.addItem(taskSerieItem);
}
}
public void deleteTaskSeriesItem(Task task) {
TaskSerieItem item = task.getTaskSerieItem();
TaskSerie taskSerie = task.getTaskSerieItem().getTaskSerie();
taskSerie.getTasks().remove(item);
task.setTaskSerieItem(null);
taskSerieItemRepository.delete(item);
if(taskSerie.getTasks().isEmpty()) {
taskSeriesRepository.deleteUnreferenced();
} else if(task.getParent() == null){
repearIndexing(taskSerie, item.getSeriesIndex());
}
}
private void repearIndexing(TaskSerie taskSerie, int deletedIndex) {
taskSerie.getTasks().sort(Comparator.comparingInt(TaskSerieItem::getSeriesIndex));
List<TaskSerieItem> updatedItems = new ArrayList<>();
for(TaskSerieItem taskSerieItem : taskSerie.getTasks()) {
if(taskSerieItem.getSeriesIndex() > deletedIndex) {
taskSerieItem.setSeriesIndex(taskSerieItem.getSeriesIndex() -1);
updatedItems.add(taskSerieItem);
}
}
taskSerieItemRepository.saveAll(updatedItems);
}
public void deleteTaskSerieByTaskgroup(Taskgroup taskgroup) {
taskSerieItemRepository.deleteByTaskgroup(taskgroup);
taskSeriesRepository.deleteUnreferenced();
}
public static String convertIndexToString(int index) {
if(index < 10) {
return "0" + index;
} else {
return String.valueOf(index);
}
}
public static String insertNameIndex(int seriesIndex, String taskName) {
return taskName.replaceAll("\\$\\{i}", convertIndexToString(seriesIndex));
}
}

View File

@ -6,6 +6,8 @@ import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup; import core.entities.timemanager.Taskgroup;
import core.repositories.timemanager.TaskRepository; import core.repositories.timemanager.TaskRepository;
import core.repositories.timemanager.TaskSerieItemRepository;
import core.repositories.timemanager.TaskSeriesRepository;
import core.repositories.timemanager.TaskgroupRepository; import core.repositories.timemanager.TaskgroupRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -20,20 +22,20 @@ public class TaskService {
private final TaskScheduleService taskScheduleService; private final TaskScheduleService taskScheduleService;
private final TaskgroupRepository taskgroupRepository; private final TaskgroupRepository taskgroupRepository;
private final TaskSeriesService taskSeriesService;
public TaskService(@Autowired TaskRepository taskRepository, public TaskService(@Autowired TaskRepository taskRepository,
@Autowired TaskScheduleService taskScheduleService, @Autowired TaskScheduleService taskScheduleService,
TaskgroupRepository taskgroupRepository) { @Autowired TaskgroupRepository taskgroupRepository,
@Autowired TaskSeriesService taskSeriesService) {
this.taskRepository = taskRepository; this.taskRepository = taskRepository;
this.taskScheduleService = taskScheduleService; this.taskScheduleService = taskScheduleService;
this.taskgroupRepository = taskgroupRepository; this.taskgroupRepository = taskgroupRepository;
this.taskSeriesService = taskSeriesService;
} }
public ServiceResult<Task> createTask(Taskgroup taskgroup, TaskFieldInfo taskFieldInfo) { public ServiceResult<Task> createTask(Taskgroup taskgroup, TaskFieldInfo taskFieldInfo) {
if(existTaskByName(taskgroup.getTasks(), taskFieldInfo.getTaskName())) {
return new ServiceResult<>(ServiceExitCode.ENTITY_ALREADY_EXIST);
}
//Check for invalid date (deadline before start //Check for invalid date (deadline before start
if(taskFieldInfo.getStartDate() != null && taskFieldInfo.getDeadline() != null && if(taskFieldInfo.getStartDate() != null && taskFieldInfo.getDeadline() != null &&
taskFieldInfo.getDeadline().isBefore(taskFieldInfo.getStartDate())) { taskFieldInfo.getDeadline().isBefore(taskFieldInfo.getStartDate())) {
@ -47,6 +49,21 @@ public class TaskService {
return new ServiceResult<>(task); return new ServiceResult<>(task);
} }
public ServiceResult<Task> createSubTask(Task parentTask, TaskFieldInfo taskFieldInfo) {
if(taskFieldInfo.getStartDate().isBefore(parentTask.getStartDate()) ||
taskFieldInfo.getDeadline().isAfter(parentTask.getDeadline()) ||
taskFieldInfo.getDeadline().isBefore(taskFieldInfo.getStartDate())) {
return new ServiceResult<>(ServiceExitCode.INVALID_PARAMETER);
}
Task task = new Task(parentTask.getTaskgroup(), taskFieldInfo);
parentTask.getTaskgroup().getTasks().add(task);
parentTask.addSubtask(task);
taskRepository.save(task);
return new ServiceResult<>(task);
}
private boolean existTaskByName(Collection<Task> tasks, String name) { private boolean existTaskByName(Collection<Task> tasks, String name) {
for(Task task : tasks) { for(Task task : tasks) {
if(task.getTaskName().equals(name)) { if(task.getTaskName().equals(name)) {
@ -86,16 +103,18 @@ public class TaskService {
} }
public void deleteTask(Task task) { public void deleteTask(Task task) {
//taskScheduleService.deleteScheduleByTask(task);
System.err.println(task.getTaskID());
task.getTaskgroup().getTasks().remove(task); task.getTaskgroup().getTasks().remove(task);
taskgroupRepository.save(task.getTaskgroup()); taskgroupRepository.save(task.getTaskgroup());
task.setTaskgroup(null); if(task.getTaskSerieItem() != null) {
taskRepository.save(task); taskSeriesService.deleteTaskSeriesItem(task);
}
taskRepository.delete(task); taskRepository.delete(task);
} }
public void clearTasks(Taskgroup taskgroup) { public void clearTasks(Taskgroup taskgroup) {
taskSeriesService.deleteTaskSerieByTaskgroup(taskgroup);
taskScheduleService.deleteSchedulesByTaskgroup(taskgroup);
taskRepository.deleteTaskHierarchyWhereTaskgroup(taskgroup);
taskRepository.deleteAllByTaskgroup(taskgroup); taskRepository.deleteAllByTaskgroup(taskgroup);
} }
@ -140,4 +159,9 @@ public class TaskService {
} }
} }
public ServiceExitCode clearSubTasks(Task parentTask) {
taskRepository.deleteTasksByParent(parentTask);
return ServiceExitCode.OK;
}
} }

View File

@ -21,10 +21,12 @@ public class TaskgroupService {
private final TaskgroupRepository taskgroupRepository; private final TaskgroupRepository taskgroupRepository;
private final UserRepository userRepository; private final UserRepository userRepository;
private final TaskService taskService;
public TaskgroupService(@Autowired TaskgroupRepository taskgroupRepository, public TaskgroupService(@Autowired TaskgroupRepository taskgroupRepository,
@Autowired UserRepository userRepository) { @Autowired UserRepository userRepository, @Autowired TaskService taskService) {
this.taskgroupRepository = taskgroupRepository; this.taskgroupRepository = taskgroupRepository;
this.userRepository = userRepository; this.userRepository = userRepository;
this.taskService = taskService;
} }
public PermissionResult<Taskgroup> getTaskgroupByIDAndUsername(long taskgroupID, String username) { public PermissionResult<Taskgroup> getTaskgroupByIDAndUsername(long taskgroupID, String username) {
@ -97,6 +99,7 @@ public class TaskgroupService {
} }
public void deleteTaskgroup(Taskgroup taskgroup) { public void deleteTaskgroup(Taskgroup taskgroup) {
taskService.clearTasks(taskgroup);
taskgroupRepository.delete(taskgroup); taskgroupRepository.delete(taskgroup);
} }

View File

@ -3,6 +3,7 @@ package core.services;
import core.api.models.account.AccountDeleteRequest; import core.api.models.account.AccountDeleteRequest;
import core.api.models.account.EmailChangeRequest; import core.api.models.account.EmailChangeRequest;
import core.api.models.account.PasswordChangeRequest; import core.api.models.account.PasswordChangeRequest;
import core.api.models.users.NtfyInformation;
import core.api.models.users.UserAddInfo; import core.api.models.users.UserAddInfo;
import core.api.models.users.UserInfo; import core.api.models.users.UserInfo;
import core.api.models.users.UserUpdateInfo; import core.api.models.users.UserUpdateInfo;
@ -152,4 +153,13 @@ public class UserService {
userRepository.deleteByUsername(username); userRepository.deleteByUsername(username);
return 0; return 0;
} }
public void editNtfyInformation(User user, NtfyInformation ntfyInformation) {
user.setNtfy_host(ntfyInformation.getNtfy_host());
user.setNtfy_topic(ntfyInformation.getNtfy_topic());
user.setNtfy_username(ntfyInformation.getNtfy_user());
user.setNtfy_token(ntfyInformation.getNtfy_token());
userRepository.save(user);
}
} }

View File

@ -0,0 +1,29 @@
package core.services.ntfy;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.io.IOException;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class NtfyTask implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
HttpClient httpClient = HttpClient.newHttpClient();
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://localhost:4280/Test"))
.POST(HttpRequest.BodyPublishers.ofString(jobExecutionContext.getMergedJobDataMap().getString("data")))
.build();
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,39 @@
package core.services.ntfy;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class NtfyTaskStartNotification implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
HttpClient httpClient = HttpClient.newHttpClient();
String msg = "Task " + jobExecutionContext.getMergedJobDataMap().getString("task") + " should have been started by now!";
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(jobExecutionContext.getMergedJobDataMap().getString("ntfy_host") + "/Test"))
.POST(HttpRequest.BodyPublishers.ofString(msg))
.header("Tags", "warning")
.header("Title", "Task Starting Reminder")
.header("Actions", "view, Open TimeScheduler, "+jobExecutionContext.getMergedJobDataMap().getString("frontend_domain")+", clear=true")
.build();
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,93 @@
package core.services.ntfy;
import core.entities.User;
import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.AdvancedTaskSchedule;
import core.repositories.timemanager.ScheduleRepository;
import core.repositories.timemanager.TaskRepository;
import core.services.TaskScheduleService;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
@Service
public class TaskSchedulingService {
@Value("${frontend.domain}")
private String frontend_domain;
@Autowired private TaskScheduleService taskScheduleService;
private Scheduler scheduler;
public void scheduleStartingTask(AdvancedTaskSchedule advancedTaskSchedule) throws SchedulerException {
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail job = JobBuilder.newJob(NtfyTaskStartNotification.class)
.withIdentity(String.valueOf(advancedTaskSchedule.getScheduleID()))
.build();
job.getJobDataMap().put("task", advancedTaskSchedule.getTask().getTaskName());
job.getJobDataMap().put("ntfy_host", advancedTaskSchedule.getTask().getTaskgroup().getUser().getNtfy_host());
job.getJobDataMap().put("ntfy_topic", advancedTaskSchedule.getTask().getTaskgroup().getUser().getNtfy_topic());
job.getJobDataMap().put("frontend_domain", frontend_domain);
Trigger trigger = TriggerBuilder.newTrigger().startAt(calculateDelayInMillis(advancedTaskSchedule.getScheduleStart())).build();
scheduler.scheduleJob(job, trigger);
}
public void sendRunningTaskNotification(AbstractSchedule abstractSchedule) {
HttpClient httpClient = HttpClient.newHttpClient();
User user = abstractSchedule.getTask().getTaskgroup().getUser();
if(user.getNtfy_host() != null && user.getNtfy_topic() != null) {
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(user.getNtfy_host()+ "/" + user.getNtfy_topic()))
.POST(HttpRequest.BodyPublishers.ofString("Running Task " + abstractSchedule.getTask().getTaskName()))
.header("Tags", "heavy_check_mark")
.header("Title", "Task Running")
.header("Actions", "view, Open TimeScheduler, "+frontend_domain+", clear=true")
.build();
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}
private static Date calculateDelayInMillis(LocalDateTime executionTime) {
return Date.from(executionTime.atZone(ZoneId.systemDefault()).toInstant());
}
@Scheduled(cron = "0 0 0 * * *")
public void scheduleStartReminders() throws SchedulerException {
List<AdvancedTaskSchedule> advancedTaskSchedules = taskScheduleService.findSchedulesByDate(LocalDate.now());
for(AdvancedTaskSchedule advancedTaskSchedule : advancedTaskSchedules) {
if(advancedTaskSchedule.getTask().getTaskgroup().getUser().getNtfy_host() != null) {
scheduleStartingTask(advancedTaskSchedule);
}
}
}
public void stopStartReminderNotification(AdvancedTaskSchedule schedule) throws SchedulerException {
scheduler.deleteJob(JobKey.jobKey(String.valueOf(schedule.getScheduleID())));
}
}

View File

@ -0,0 +1,15 @@
package util;
public class Tripel<A,B,C> extends Tupel<A, B> {
private final C value02;
public Tripel(A value00, B value01, C value02) {
super(value00, value01);
this.value02 = value02;
}
public C getValue02() {
return value02;
}
}

View File

@ -0,0 +1,20 @@
package util;
public class Tupel <A, B>{
private final A value00;
private final B value01;
public Tupel(A value00, B value01) {
this.value00 = value00;
this.value01 = value01;
}
public A getValue00() {
return value00;
}
public B getValue01() {
return value01;
}
}

View File

@ -27,6 +27,7 @@ spring.jpa.open-in-view=false
# Spring Data Rest Setup # Spring Data Rest Setup
spring.data.rest.base-path=/api spring.data.rest.base-path=/api
@ -42,4 +43,8 @@ spring.servlet.multipart.max-request-size=4196KB
demo.webapp.jwtSecret=demoWebappSecretKey demo.webapp.jwtSecret=demoWebappSecretKey
demo.webapp.jwtExpirationMS=86400000 demo.webapp.jwtExpirationMS=86400000
spring.jackson.time-zone=UTC spring.jackson.time-zone=UTC
server.servlet.session.cookie.samesite=None server.servlet.session.cookie.samesite=None
ntfy.host=http://localhost:4280
ntfy.topic=Test
frontend.domain=http://localhost:4200

View File

@ -1,13 +0,0 @@
package core;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/*@SpringBootTest*/
class DemoApplicationTests {
/*@Test
void contextLoads() {
}*/
}

View File

@ -1,57 +0,0 @@
package core.schedules;
import core.entities.User;
import core.entities.timemanager.AbstractSchedule;
import core.repositories.timemanager.ScheduleRepository;
import core.services.ServiceResult;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlGroup;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(SpringExtension.class)
@DataJpaTest
public class ScheduleRepositoryTest {
@Autowired private ScheduleRepository scheduleRepository;
@Autowired private TestEntityManager entityManager;
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void getAllSchedulesOfUser() {
User referenceUser_1 = entityManager.find(User.class, 1L);
User referenceUser_2 = entityManager.find(User.class, 2L);
assertEquals(0, scheduleRepository.findAllByUsername(referenceUser_2.getUsername()).size());
assertEquals(5, scheduleRepository.findAllByUsername(referenceUser_1.getUsername()).size());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void getActiveScheduleOfUser() {
User referenceUser_1 = entityManager.find(User.class, 1L);
User referenceUser_2 = entityManager.find(User.class, 2L);
Optional<AbstractSchedule> result_1 = scheduleRepository.getActiveScheduleOfUser(referenceUser_2.getUsername());
assertTrue(result_1.isEmpty());
Optional<AbstractSchedule> result_2 = scheduleRepository.getActiveScheduleOfUser(referenceUser_1.getUsername());
assertTrue(result_2.isPresent());
}
}

View File

@ -1,321 +0,0 @@
package core.schedules;
import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.BasicScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.ForgottenScheduleInfo;
import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.AdvancedTaskSchedule;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task;
import core.services.ServiceExitCode;
import core.services.ServiceResult;
import core.services.TaskScheduleService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlGroup;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
@Transactional
public class ScheduleServiceTest {
@Autowired
private EntityManager entityManager;
@Autowired private TaskScheduleService taskScheduleService;
private static final String username = "Testuser1";
private static final String username2 = "Testuser2";
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void getAllSchedulesOfUser() {
assertEquals(0, taskScheduleService.getAllSchedulesOfUser(username2).size());
List<AbstractSchedule> result_1 = taskScheduleService.getAllSchedulesOfUser(username);
assertEquals(5, result_1.size());
assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 1L)));
assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 2L)));
assertTrue(result_1.contains(entityManager.find(AbstractSchedule.class, 3L)));
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void scheduleBasic() {
//Situation 1: Schedule finished Task
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.scheduleBasic(entityManager.find(Task.class, 2L), new BasicScheduleFieldInfo(LocalDate.now()));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode());
//Situation 2: Schedule before today
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.scheduleBasic(entityManager.find(Task.class, 1L), new BasicScheduleFieldInfo(LocalDate.of(2010, 3, 14)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode());
//Situation 3: Valid schedule
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.scheduleBasic(entityManager.find(Task.class, 1L), new BasicScheduleFieldInfo(LocalDate.now()));
assertEquals(ServiceExitCode.OK, result_3.getExitCode());
assertThat(entityManager.find(BasicTaskSchedule.class, result_3.getResult().getScheduleID())).isNotNull();
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void editBasicSchedule() {
//Situation 1: Reschedule finished task
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 2L), new BasicScheduleFieldInfo(LocalDate.now()));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode());
//Situation 2: Reschedule unfinished task with invalid reschedule date
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 1L), new BasicScheduleFieldInfo(LocalDate.of(2011, 3, 4)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode());
//Situation 3: Reschedule unfinished task with valid reschedule date
LocalDate oldDate = entityManager.find(BasicTaskSchedule.class, 1L).getScheduleDate();
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 1L), new BasicScheduleFieldInfo(LocalDate.now()));
assertEquals(ServiceExitCode.OK, result_3.getExitCode());
assertNotEquals(((BasicTaskSchedule) result_3.getResult()).getScheduleDate(), oldDate);
//Situation 4: Reschedule already running schedule
ServiceResult<AbstractSchedule> result_4 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 4L),
new BasicScheduleFieldInfo(LocalDate.now()));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_4.getExitCode());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void deleteSchedule() {
for(long i=1; i<=2; i++) {
taskScheduleService.deleteSchedule(entityManager.find(BasicTaskSchedule.class, i));
assertThat(entityManager.find(BasicTaskSchedule.class, i)).isNull();
}
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void getFilteredScheduledOfUser() {
//Invalid user
assertEquals(0, taskScheduleService.getFilteredScheduledOfUser(LocalDate.now(), false, "Quatsch").size());
assertEquals(0, taskScheduleService.getFilteredScheduledOfUser(LocalDate.now(), true, "Quatsch").size());
//User with no tasks/schedules
assertEquals(0, taskScheduleService.getFilteredScheduledOfUser(LocalDate.now(), false, username2).size());
assertEquals(0, taskScheduleService.getFilteredScheduledOfUser(LocalDate.now(), true, username2).size());
//user with tasks and schedules
List<AbstractSchedule> result_1 = taskScheduleService.getFilteredScheduledOfUser(LocalDate.of(2024,11,11), false, username);
assertEquals(3, result_1.size());
assertTrue(result_1.contains(entityManager.find(BasicTaskSchedule.class, 3L)));
assertTrue(result_1.contains(entityManager.find(BasicTaskSchedule.class, 4L)));
assertTrue(result_1.contains(entityManager.find(BasicTaskSchedule.class, 5L)));
List<AbstractSchedule> result_2 = taskScheduleService.getFilteredScheduledOfUser(LocalDate.of(2024,11,11), true, username);
assertEquals(1, result_2.size());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void scheduleNow() {
//Situation 1: Task has already an active schedule
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 3L));
assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, result_1.getExitCode());
//Situation 2: Task is already finished
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 2L));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode());
//Situation 3: Task can be scheduled and started
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 5L));
assertEquals(ServiceExitCode.OK, result_3.getExitCode());
assertThat(entityManager.find(BasicTaskSchedule.class, result_3.getResult().getScheduleID())).isNotNull();
//Situation 4: Running Advanced Schedule
ServiceResult<AbstractSchedule> result_4 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 17L));
assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, result_4.getExitCode());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void activateSchedule() {
//Activate already running schedule
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.activateSchedule(entityManager.find(BasicTaskSchedule.class, 4L));
assertNotNull(result_1.getResult().getStartTime());
assertNull(result_1.getResult().getStopTime());
entityManager.remove(entityManager.find(BasicTaskSchedule.class, 4L));
assertThat(entityManager.find(BasicTaskSchedule.class, 4L)).isNull();
//Activate not running schedule
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.activateSchedule(entityManager.find(BasicTaskSchedule.class, 5L));
assertNotNull(result_2.getResult().getStartTime());
assertNull(result_2.getResult().getStopTime());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void stopSchedule() {
//Stop schedule that is not running 4
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.stopSchedule(entityManager.find(BasicTaskSchedule.class, 5L), false);
assertNull(result_1.getResult().getStartTime());
assertNull(result_1.getResult().getStopTime());
//Stop schedule (without finishing)
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.stopSchedule(entityManager.find(BasicTaskSchedule.class, 4L), false);
assertNotNull(result_2.getResult().getStartTime());
assertNotNull(result_2.getResult().getStopTime());
//Stop schedule with finishing
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.stopSchedule(entityManager.find(BasicTaskSchedule.class, 7L), true);
assertNotNull(result_3.getResult().getStartTime());
assertNotNull(result_3.getResult().getStopTime());
assertTrue(result_3.getResult().getTask().isFinished());
assertFalse(result_3.getResult().isStartable());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void registerForgottenSchedule() {
//Register task schedule for task that is already finished
LocalDateTime startTime = LocalDateTime.now().minusMinutes(10L);
LocalDateTime finishTime = LocalDateTime.now();
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.registerForgottenSchedule(entityManager.find(Task.class, 2L), new ForgottenScheduleInfo(startTime, finishTime));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode());
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.registerForgottenSchedule(entityManager.find(Task.class, 5L), new ForgottenScheduleInfo(startTime, finishTime));
assertEquals(ServiceExitCode.OK, result_2.getExitCode());
assertEquals(startTime, result_2.getResult().getStartTime());
assertEquals(finishTime, result_2.getResult().getStopTime());
assertThat(entityManager.find(BasicTaskSchedule.class, result_2.getResult().getScheduleID())).isNotNull();
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void getAllMissedSchedulesOfUser() {
assertEquals(1, taskScheduleService.getAllMissedSchedulesOfUser(username).size());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void scheduleAdvanced() {
//Situation 1: Schedule finished Task
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 18L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(1L), LocalDateTime.now().plusHours(2L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode());
//Situation 2: Schedule Start is before today
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(1L), LocalDateTime.now().plusHours(2L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode());
//Situation 3: Schedule End is before today
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(2L), LocalDateTime.now().minusDays(1L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_3.getExitCode());
//Situation 4: Start after stop
ServiceResult<AbstractSchedule> result_4 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(2L), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.INVALID_PARAMETER, result_4.getExitCode());
//Situation 5: Valid schedule
ServiceResult<AbstractSchedule> result_5 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L),
new AdvancedScheduleFieldInfo(LocalDateTime.now(), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.OK, result_5.getExitCode());
assertThat(entityManager.find(AdvancedTaskSchedule.class, result_5.getResult().getScheduleID())).isNotNull();
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void editscheduleAdvanced() {
//Situation 1: Schedule finished Task
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 12L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(1L), LocalDateTime.now().plusHours(2L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode());
//Situation 2: Schedule Start is before today
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(1L), LocalDateTime.now().plusHours(2L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode());
//Situation 3: Schedule End is before today
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(2L), LocalDateTime.now().minusDays(1L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_3.getExitCode());
//Situation 4: Start after stop
ServiceResult<AbstractSchedule> result_4 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(2L), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.INVALID_PARAMETER, result_4.getExitCode());
//Situation 5: Valid schedule
ServiceResult<AbstractSchedule> result_5 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L),
new AdvancedScheduleFieldInfo(LocalDateTime.now(), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.OK, result_5.getExitCode());
assertThat(entityManager.find(AdvancedTaskSchedule.class, result_5.getResult().getScheduleID())).isNotNull();
//Situation 6: reschedule already running schedule
ServiceResult<AbstractSchedule> result_6 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 9L),
new AdvancedScheduleFieldInfo(LocalDateTime.now(), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_6.getExitCode());
}
}

View File

@ -1,93 +0,0 @@
package core.taskgroups;
import core.entities.User;
import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup;
import core.repositories.timemanager.TaskgroupRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
@ExtendWith(SpringExtension.class)
@DataJpaTest
public class TaskgroupRepsitoryTest {
@Autowired private TaskgroupRepository taskgroupRepository;
@Autowired private TestEntityManager testEntityManager;
@Test
@Sql("classpath:taskgroupRepositoryTestEntries.sql")
void findAllByUser() {
User testUser1 = testEntityManager.find(User.class, 1L);
User testUser2 = testEntityManager.find(User.class, 2L);
List<Taskgroup> result_user2 = taskgroupRepository.findAllByUser(testUser2.getUsername());
assertEquals(0, result_user2.size());
List<Taskgroup> result_user1 = taskgroupRepository.findAllByUser(testUser1.getUsername());
assertEquals(8, result_user1.size());
}
@Test
@Sql("classpath:taskgroupRepositoryTestEntries.sql")
void findAllTopTaskgroupsByUser() {
User testUser1 = testEntityManager.find(User.class, 1L);
User testUser2 = testEntityManager.find(User.class, 2L);
//Situation 1: Empty user, no taskgroups
assertEquals(0, taskgroupRepository.findAllTopTaskgroupsByUser(testUser2.getUsername()).size());
//Situation 2: Only top taskgroups are returned
List<Taskgroup> topgroups_user1 = taskgroupRepository.findAllTopTaskgroupsByUser(testUser1.getUsername());
assertEquals(3, topgroups_user1.size());
assertTrue(topgroups_user1.contains(testEntityManager.find(Taskgroup.class, 1L)));
assertTrue(topgroups_user1.contains(testEntityManager.find(Taskgroup.class, 2L)));
assertTrue(topgroups_user1.contains(testEntityManager.find(Taskgroup.class, 5L)));
//Situation 3: User with username does not exist
assertEquals(0, taskgroupRepository.findAllTopTaskgroupsByUser("Rotzbakke").size());
}
@Test
@Sql("classpath:taskgroupRepositoryTestEntries.sql")
void deleteAllByUser() {
User testUser1 = testEntityManager.find(User.class, 1L);
User testUser2 = testEntityManager.find(User.class, 2L);
taskgroupRepository.deleteAllByUser(testUser2);
for(long i=1; i<=8; i++) {
assertThat(testEntityManager.find(Taskgroup.class, i)).isNotNull();
}
taskgroupRepository.deleteAllByUser(testUser1);
for(long i=1; i<=8; i++) {
assertThat(testEntityManager.find(Taskgroup.class, i)).isNull();
}
}
@Test
@Sql("classpath:taskgroupRepositoryTestEntries.sql")
void delete() {
Taskgroup no_children = testEntityManager.find(Taskgroup.class, 1L);
Taskgroup taskgroup_with_children = testEntityManager.find(Taskgroup.class, 5L);
taskgroupRepository.delete(no_children);
assertThat(testEntityManager.find(Taskgroup.class, 1L)).isNull();
for(long i=2; i<=8; i++) {
assertThat(testEntityManager.find(Taskgroup.class, i)).isNotNull();
}
taskgroupRepository.delete(taskgroup_with_children);
for(long i=5; i<=8; i++) {
assertThat(testEntityManager.find(Taskgroup.class, i)).isNull();
}
}
}

View File

@ -1,202 +0,0 @@
package core.taskgroups;
import core.api.models.timemanager.taskgroup.TaskgroupFieldInfo;
import core.entities.User;
import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup;
import core.repositories.UserRepository;
import core.repositories.timemanager.TaskgroupRepository;
import core.services.PermissionResult;
import core.services.ServiceExitCode;
import core.services.ServiceResult;
import core.services.TaskgroupService;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlGroup;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit4.SpringRunner;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
@Transactional
public class TaskgroupServiceTest {
@Autowired
private TaskgroupRepository taskgroupRepository;
@Autowired
private TaskgroupService taskgroupService;
@Autowired
private EntityManager entityManager;
private static final String username = "Testuser1";
private static final String username2 = "Testuser2";
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void getTaskgroupByIDAndUsername() {
//Situation 1: correct taskgroup and username
assertFalse(taskgroupRepository.findById(1L).isEmpty());
PermissionResult<Taskgroup> permissionResult = taskgroupService.getTaskgroupByIDAndUsername(1L, username);
assertThat(permissionResult).isNotNull();
assertTrue(permissionResult.isHasPermissions());
assertEquals(ServiceExitCode.OK, permissionResult.getExitCode());
assertEquals(taskgroupRepository.findById(1L).get(), permissionResult.getResult());
//Situation 2: invalid taskgroup
PermissionResult<Taskgroup> invalid_group = taskgroupService.getTaskgroupByIDAndUsername(-1L, username);
assertThat(invalid_group).isNotNull();
assertEquals(ServiceExitCode.MISSING_ENTITY, invalid_group.getExitCode());
assertFalse(invalid_group.isHasPermissions());
//Situation 3: invalid user
PermissionResult<Taskgroup> invalid_user = taskgroupService.getTaskgroupByIDAndUsername(1L, "Rotzbakke");
assertThat(invalid_user).isNotNull();
assertEquals(ServiceExitCode.OK, invalid_user.getExitCode());
assertFalse(invalid_user.isHasPermissions());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void addTaskgroup() {
TaskgroupFieldInfo taskgroupFieldInfo = new TaskgroupFieldInfo("Taskgroup", -1);
//Situation 1: No such user
assertThrows(NoSuchElementException.class, () -> taskgroupService.addTaskgroup(taskgroupFieldInfo, "Rotzbakke"));
//Situation 2: Taskgroup already exists
Taskgroup taskgroup = taskgroupRepository.findById(1L).get();
ServiceResult<Taskgroup> creationResult = taskgroupService.addTaskgroup(new TaskgroupFieldInfo(taskgroup.getTaskgroupName(), -1), username);
assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, creationResult.getExitCode());
assertThat(creationResult.getResult()).isNull();
//Situation 3: Taskgroup does not exist, no parent
ServiceResult<Taskgroup> creationResult_3 = taskgroupService.addTaskgroup(taskgroupFieldInfo, username);
assertEquals(ServiceExitCode.OK, creationResult_3.getExitCode());
assertTrue(taskgroupRepository.existsById(creationResult_3.getResult().getTaskgroupID()));
//Situation 4: Taskgroup does not exist, with parent; invalid parent (no existent)
ServiceResult<Taskgroup> creationResult_4 = taskgroupService.addTaskgroup(new TaskgroupFieldInfo("Situation 4", 100L), username);
assertEquals(ServiceExitCode.MISSING_ENTITY, creationResult_4.getExitCode());
//Situation 5: Taskgroup does not exist, parent exist
ServiceResult<Taskgroup> creationResult_5 = taskgroupService.addTaskgroup(new TaskgroupFieldInfo("Situation 5", 2L), username);
assertEquals(ServiceExitCode.OK, creationResult_5.getExitCode());
assertTrue(taskgroupRepository.existsById(creationResult_5.getResult().getTaskgroupID()));
//Situation 6: taskgroup exist on another user
ServiceResult<Taskgroup> creationResult_6 = taskgroupService.addTaskgroup(new TaskgroupFieldInfo(taskgroup.getTaskgroupName(), -1), username2);
assertEquals(ServiceExitCode.OK, creationResult_6.getExitCode());
assertTrue(taskgroupRepository.existsById(creationResult_6.getResult().getTaskgroupID()));
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void editTaskgroup() {
Taskgroup taskgroup = taskgroupRepository.findById(1L).get();
//Situation 1: Nothing changed
ServiceExitCode exitCode_1 = taskgroupService.editTaskgroup(taskgroup, new TaskgroupFieldInfo(taskgroup.getTaskgroupName(),-1));
assertEquals(ServiceExitCode.OK, exitCode_1);
//Situation 2: Name is already taken
ServiceExitCode exitCode_2 = taskgroupService.editTaskgroup(taskgroup, new TaskgroupFieldInfo("Taskgroup 1", -1));
assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, exitCode_2);
//Situation 3: All fine
ServiceExitCode exitCode_3 = taskgroupService.editTaskgroup(taskgroup, new TaskgroupFieldInfo("Situation 3", -1));
assertEquals(ServiceExitCode.OK, exitCode_3);
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void deleteTaskgroup() {
taskgroupService.deleteTaskgroup(entityManager.find(Taskgroup.class, 1L));
assertThat(entityManager.find(Taskgroup.class, 1L)).isNull();
taskgroupService.deleteTaskgroup(entityManager.find(Taskgroup.class, 2L));
assertThat(entityManager.find(Taskgroup.class, 2L)).isNull();
assertThat(entityManager.find(Taskgroup.class, 3L)).isNull();
for(long i=1; i<=14; i++) {
assertThat(entityManager.find(Task.class, i)).isNull();
}
taskgroupService.deleteTaskgroup(entityManager.find(Taskgroup.class, 5L));
assertThat(entityManager.find(Taskgroup.class, 5L)).isNull();
assertThat(entityManager.find(Taskgroup.class, 6L)).isNull();
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void getTopTaskgroupsByUser() {
//Situation 1: User without taskgroups
List<Taskgroup> taskgroups_user2 = taskgroupService.getTopTaskgroupsByUser(username2);
assertEquals(0, taskgroups_user2.size());
//Situation 2: user with taskgroups
List<Taskgroup> taskgroups_user1 = taskgroupService.getTopTaskgroupsByUser(username);
assertEquals(3, taskgroups_user1.size());
assertTrue(taskgroups_user1.contains(entityManager.find(Taskgroup.class, 1L)));
assertTrue(taskgroups_user1.contains(entityManager.find(Taskgroup.class, 2L)));
assertTrue(taskgroups_user1.contains(entityManager.find(Taskgroup.class, 5L)));
//Situation 3: No existent username
assertEquals(0, taskgroupService.getTopTaskgroupsByUser("Rotzbakke").size());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void deleteTaskgroupByUser() {
User referenceUser1 = entityManager.find(User.class, 1L);
User referenceUser2 = entityManager.find(User.class, 2L);
taskgroupService.deleteTaskgroupByUser(referenceUser2);
for(long i=1; i<=8; i++) {
assertThat(entityManager.find(Taskgroup.class, i)).isNotNull();
}
taskgroupService.deleteTaskgroupByUser(referenceUser1);
for(long i=1; i<=8; i++) {
assertThat(entityManager.find(Taskgroup.class, i)).isNull();
}
for(long i=1; i<=14; i++) {
assertThat(entityManager.find(Task.class, i)).isNull();
}
}
}

View File

@ -1,160 +0,0 @@
package core.tasks;
import core.entities.User;
import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup;
import core.repositories.timemanager.TaskRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlGroup;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.time.LocalDate;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(SpringExtension.class)
@DataJpaTest
public class TaskRepositoryTest {
@Autowired private TaskRepository taskRepository;
@Autowired private TestEntityManager testEntityManager;
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void findAllByUser() {
User testUser1 = testEntityManager.find(User.class, 1L);
User testUser2 = testEntityManager.find(User.class, 2L);
//Situation 1: Non existent user
assertEquals(0, taskRepository.findAllByUser("Rotzbakke", true).size());
assertEquals(0, taskRepository.findAllByUser("Rotzbakke", false).size());
//Situation 2: User with no tasks at all
assertEquals(0, taskRepository.findAllByUser(testUser2.getUsername(), false).size());
assertEquals(0, taskRepository.findAllByUser(testUser2.getUsername(), true).size());
//Situation 3: User with finished and unfinished tasks
List<Task> tasks_user1_false = taskRepository.findAllByUser(testUser1.getUsername(), false);
List<Task> tasks_user1_true = taskRepository.findAllByUser(testUser1.getUsername(), true);
assertEquals(7, tasks_user1_true.size());
assertEquals(8, tasks_user1_false.size());
assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 1L)));
assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 3L)));
assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 5L)));
assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 7L)));
assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 9L)));
assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 11L)));
assertTrue(tasks_user1_false.contains(testEntityManager.find(Task.class, 12L)));
assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 2L)));
assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 4L)));
assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 6L)));
assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 8L)));
assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 10L)));
assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 13L)));
assertTrue(tasks_user1_true.contains(testEntityManager.find(Task.class, 14L)));
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void deleteAllByTaskgroup() {
Taskgroup taskgroup_no_tasks = testEntityManager.find(Taskgroup.class, 1L);
taskRepository.deleteAllByTaskgroup(taskgroup_no_tasks);
for(long i=1; i<=14; i++) {
assertThat(testEntityManager.find(Task.class, i)).isNotNull();
}
Taskgroup taskgroup_with_task = testEntityManager.find(Taskgroup.class, 2L);
taskRepository.deleteAllByTaskgroup(taskgroup_with_task);
for(long i=1; i<=14; i++) {
Task task = testEntityManager.find(Task.class, i);
assertThat(task).isNull();
}
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void deleteByTaskID() {
taskRepository.deleteByTaskID(-1);
for(long i=1; i<=14; i++) {
assertThat(testEntityManager.find(Task.class, i)).isNotNull();
}
taskRepository.deleteByTaskID(1);
assertThat(testEntityManager.find(Task.class, 1L)).isNull();
for(long i=2; i<=14; i++) {
assertThat(testEntityManager.find(Task.class, i)).isNotNull();
}
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void findAllOverdue() {
User testuser1 = testEntityManager.find(User.class, 1L);
LocalDate referenceDate = LocalDate.of(2023, 10, 11);
List<Task> overdue = taskRepository.findAllOverdue(testuser1.getUsername(), referenceDate);
assertEquals(2, overdue.size());
assertTrue(overdue.contains(testEntityManager.find(Task.class, 3L)));
assertTrue(overdue.contains(testEntityManager.find(Task.class, 5L)));
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void findAllUpcoming() {
User testuser1 = testEntityManager.find(User.class, 1L);
LocalDate referenceDate = LocalDate.of(2023, 10, 11);
List<Task> upcoming = taskRepository.findAllUpcoming(testuser1.getUsername(), referenceDate);
assertEquals(2, upcoming.size());
assertTrue(upcoming.contains(testEntityManager.find(Task.class, 7L)));
assertTrue(upcoming.contains(testEntityManager.find(Task.class, 9L)));
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql")
})
void findAllActive() {
User testuser1 = testEntityManager.find(User.class, 1L);
LocalDate referenceDate = LocalDate.of(2023, 10, 11);
List<Task> active = taskRepository.findAllActive(testuser1.getUsername(), referenceDate);
//1,3,5,11,12
assertEquals(6, active.size());
assertTrue(active.contains(testEntityManager.find(Task.class, 1L)));
assertTrue(active.contains(testEntityManager.find(Task.class, 3L)));
assertTrue(active.contains(testEntityManager.find(Task.class, 5L)));
assertTrue(active.contains(testEntityManager.find(Task.class, 11L)));
assertTrue(active.contains(testEntityManager.find(Task.class, 12L)));
}
}

View File

@ -1,287 +0,0 @@
package core.tasks;
import core.api.models.timemanager.tasks.TaskFieldInfo;
import core.api.models.timemanager.tasks.TaskScope;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup;
import core.repositories.timemanager.TaskRepository;
import core.repositories.timemanager.TaskgroupRepository;
import core.services.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlGroup;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.time.LocalDate;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
@Transactional
public class TaskServiceTest {
@Autowired
private TaskService taskService;
@Autowired
private EntityManager entityManager;
private static final String username = "Testuser1";
private static final String username2 = "Testuser2";
@Autowired
private TaskRepository taskRepository;
@Autowired
private TaskgroupRepository taskgroupRepository;
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void createTask() {
//Situation 1: Task with that name already exists in a taskgroup
TaskFieldInfo taskFieldInfo_1 = new TaskFieldInfo(entityManager.find(Task.class, 1L).getTaskName(), 0, null, null);
ServiceResult<Task> situation_1 = taskService.createTask(entityManager.find(Taskgroup.class, 2L), taskFieldInfo_1);
assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, situation_1.getExitCode());
//Situation 2: Task with that name exists in another taskgroup
TaskFieldInfo taskFieldInfo_2 = new TaskFieldInfo(entityManager.find(Task.class, 1L).getTaskName(), 0, null, null);
ServiceResult<Task> result_2 = taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_2);
assertEquals(ServiceExitCode.OK, result_2.getExitCode());
assertThat(entityManager.find(Task.class, result_2.getResult().getTaskID())).isNotNull();
//Situation 3: Normal, everything fine
TaskFieldInfo taskFieldInfo_3 = new TaskFieldInfo("Situation 3", 0, null, null);
ServiceResult<Task> result_3 = taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_3);
assertEquals(ServiceExitCode.OK, result_3.getExitCode());
assertThat(entityManager.find(Task.class, result_3.getResult().getTaskID())).isNotNull();
//Robustness - Test for invalid dates
//Situation 4: Deadline, no start
TaskFieldInfo taskFieldInfo_4 = new TaskFieldInfo("Situation 4", 0, null, LocalDate.now());
ServiceResult<Task> result_4 = taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_4);
assertEquals(ServiceExitCode.OK, result_4.getExitCode());
assertThat(entityManager.find(Task.class, result_4.getResult().getTaskID())).isNotNull();
//Situation 5: Start but no deadline
TaskFieldInfo taskFieldInfo_5 = new TaskFieldInfo("Situation 5", 0, LocalDate.now(),null);
ServiceResult<Task> result_5 = taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_5);
assertEquals(ServiceExitCode.OK, result_5.getExitCode());
assertThat(entityManager.find(Task.class, result_5.getResult().getTaskID())).isNotNull();
//Situation 6: Deadline before start (invalid)
TaskFieldInfo taskFieldInfo_6 = new TaskFieldInfo("Situation 6", 0, LocalDate.now(),LocalDate.of(2010, 3, 20));
ServiceResult<Task> result_6= taskService.createTask(entityManager.find(Taskgroup.class, 1L), taskFieldInfo_6);
assertEquals(ServiceExitCode.INVALID_PARAMETER, result_6.getExitCode());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void getTaskPermissions() {
//Situation 1: correct task and username
PermissionResult<Task> permissionResult_1 = taskService.getTaskPermissions(1L, username);
assertEquals(ServiceExitCode.OK, permissionResult_1.getExitCode());
assertTrue(permissionResult_1.isHasPermissions());
assertEquals(entityManager.find(Task.class, 1L), permissionResult_1.getResult());
//Situation 2: invalid taskgroup
PermissionResult<Task> permissionResult_2 = taskService.getTaskPermissions(200L, username);
assertEquals(ServiceExitCode.MISSING_ENTITY, permissionResult_2.getExitCode());
assertFalse(permissionResult_2.isHasPermissions());
assertThat(permissionResult_2.getResult()).isNull();
//Situation 3: invalid user
PermissionResult<Task> permissionResult_3 = taskService.getTaskPermissions(1L, username2);
assertEquals(ServiceExitCode.OK, permissionResult_3.getExitCode());
assertFalse(permissionResult_2.isHasPermissions());
assertEquals(entityManager.find(Task.class, 1L), permissionResult_3.getResult());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void editTask() {
//Situation 1: Nothing is updated
Task task_1 = entityManager.find(Task.class, 1L);
TaskFieldInfo taskFieldInfo_1 = new TaskFieldInfo(entityManager.find(Task.class, 1L).getTaskName(), 0, null, null);
ServiceResult<Task> result_1 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_1);
assertEquals(ServiceExitCode.OK, result_1.getExitCode());
assertEquals(task_1, result_1.getResult());
//Situation 2: Name is updated to name that already exists within the taskgroup
Task task_2 = entityManager.find(Task.class, 1L);
TaskFieldInfo taskFieldInfo_2 = new TaskFieldInfo(entityManager.find(Task.class, 2L).getTaskName(), 0, null, null);
ServiceResult<Task> result_2 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_2);
task_2.setTaskName(entityManager.find(Task.class, 2L).getTaskName());
assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, result_2.getExitCode());
assertNotEquals(task_2, result_2.getResult());
//Situation 3: Name is updated to nonexistend Name
Task task_3 = entityManager.find(Task.class, 1L);
TaskFieldInfo taskFieldInfo_3 = new TaskFieldInfo("Situation 3", 0, null, null);
ServiceResult<Task> result_3 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_3);
task_3.setTaskName("Situation 3");
assertEquals(ServiceExitCode.OK, result_3.getExitCode());
assertEquals(task_3, result_3.getResult());
//Situation 4: eta is updated
Task task_4 = entityManager.find(Task.class, 1L);
TaskFieldInfo taskFieldInfo_4 = new TaskFieldInfo(task_4.getTaskName(), 90, null, null);
ServiceResult<Task> result_4 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_4);
task_4.setEta(90);
assertEquals(ServiceExitCode.OK, result_4.getExitCode());
assertEquals(task_4, result_4.getResult());
//Situation 5: deadline and start is updated in a valid way
Task task_5 = entityManager.find(Task.class, 1L);
TaskFieldInfo taskFieldInfo_5 = new TaskFieldInfo(task_5.getTaskName(), task_5.getEta(), LocalDate.of(2023, 4, 9), LocalDate.of(2023,5,9));
ServiceResult<Task> result_5 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_5);
task_5.setStartDate(LocalDate.of(2023,4,9));
task_5.setDeadline(LocalDate.of(2023,5,9));
assertEquals(ServiceExitCode.OK, result_5.getExitCode());
assertEquals(task_5, result_5.getResult());
//Situation 6: Deadline and start are updated in a not valid way
Task task_6 = entityManager.find(Task.class, 1L);
TaskFieldInfo taskFieldInfo_6 = new TaskFieldInfo(task_5.getTaskName(), task_5.getEta(), LocalDate.of(2023, 5, 9), LocalDate.of(2023,4,9));
ServiceResult<Task> result_6 = taskService.editTask(entityManager.find(Task.class, 1L), taskFieldInfo_6);
task_6.setStartDate(LocalDate.of(2023,5,9));
task_6.setDeadline(LocalDate.of(2023,4,9));
assertEquals(ServiceExitCode.INVALID_PARAMETER, result_6.getExitCode());
assertNotEquals(task_6, result_6.getResult());
//Situation 10 Startdate = null;
Task task_10 = entityManager.find(Task.class, 5L);
TaskFieldInfo taskFieldInfo_10 = new TaskFieldInfo(task_10.getTaskName(), task_10.getEta(),null, task_10.getDeadline());
ServiceResult<Task> result_10 = taskService.editTask(entityManager.find(Task.class, 5L), taskFieldInfo_10);
task_10.setStartDate(null);
assertEquals(ServiceExitCode.OK, result_10.getExitCode());
assertEquals(task_10, result_10.getResult());
//Situation 11 Deadline = null
Task task_11 = entityManager.find(Task.class, 5L);
TaskFieldInfo taskFieldInfo_11 = new TaskFieldInfo(task_11.getTaskName(), task_11.getEta(),task_11.getStartDate(), null);
ServiceResult<Task> result_11 = taskService.editTask(entityManager.find(Task.class, 5L), taskFieldInfo_11);
task_11.setDeadline(null);
assertEquals(ServiceExitCode.OK, result_11.getExitCode());
assertEquals(task_11, result_11.getResult());
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void deleteTask() {
for(long i=1; i<=15; i++) {
taskService.deleteTask(entityManager.find(Task.class, i));
assertThat(entityManager.find(Task.class, i)).isNull();
}
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void clearTasks() {
//Situation 1: Delete from taskgroup with no tasks
taskService.clearTasks(entityManager.find(Taskgroup.class, 1L));
for(long i=1; i<=15; i++) {
assertThat(entityManager.find(Task.class, i)).isNotNull();
}
//Situation 2: Delete from taskgroup with tasks
taskService.clearTasks(entityManager.find(Taskgroup.class, 2L));
for(long i=1; i<=15; i++) {
assertThat(entityManager.find(Task.class, i)).isNull();
}
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void finishTask() {
taskService.finishTask(entityManager.find(Task.class, 1L));
assertTrue(entityManager.find(Task.class, 1L).isFinished());
taskService.finishTask(entityManager.find(Task.class, 2L));
assertTrue(entityManager.find(Task.class, 1L).isFinished());
assertThat(entityManager.find(BasicTaskSchedule.class, 2L)).isNull();
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void loadAllTasks() {
//Situation 1: No tasks existing
List<Task> result_1 = taskService.loadAllTasks(username2, TaskScope.UNFINISHED);
assertEquals(0, result_1.size());
//Situation 2: Tasks existing, Unfinished#
List<Task> result_2 = taskService.loadAllTasks(username, TaskScope.UNFINISHED);
assertEquals(8, result_2.size());
assertTrue(result_2.contains(entityManager.find(Task.class, 1L)));
assertTrue(result_2.contains(entityManager.find(Task.class, 3L)));
assertTrue(result_2.contains(entityManager.find(Task.class, 5L)));
assertTrue(result_2.contains(entityManager.find(Task.class, 7L)));
assertTrue(result_2.contains(entityManager.find(Task.class, 9L)));
assertTrue(result_2.contains(entityManager.find(Task.class, 11L)));
assertTrue(result_2.contains(entityManager.find(Task.class, 12L)));
//Situation 3: Finished tasks
List<Task> result_3 = taskService.loadAllTasks(username, TaskScope.FINISHED);
assertEquals(7, result_3.size());
assertTrue(result_3.contains(entityManager.find(Task.class, 2L)));
assertTrue(result_3.contains(entityManager.find(Task.class, 4L)));
assertTrue(result_3.contains(entityManager.find(Task.class, 6L)));
assertTrue(result_3.contains(entityManager.find(Task.class, 8L)));
assertTrue(result_3.contains(entityManager.find(Task.class, 10L)));
assertTrue(result_3.contains(entityManager.find(Task.class, 13L)));
assertTrue(result_3.contains(entityManager.find(Task.class, 14L)));
//overdue
List<Task> result_4 = taskService.loadAllTasks(username, TaskScope.OVERDUE);
assertEquals(2, result_4.size());
assertTrue(result_4.contains(entityManager.find(Task.class, 3L)));
assertTrue(result_4.contains(entityManager.find(Task.class, 5L)));
//upcoming
List<Task> result_5 = taskService.loadAllTasks(username, TaskScope.UPCOMING);
assertEquals(2, result_5.size());
assertTrue(result_5.contains(entityManager.find(Task.class, 7L)));
assertTrue(result_5.contains(entityManager.find(Task.class, 9L)));
//Active
List<Task> result_6 = taskService.loadAllTasks(username, TaskScope.ACTIVE);
assertEquals(6, result_6.size());
assertTrue(result_6.contains(entityManager.find(Task.class, 1L)));
assertTrue(result_6.contains(entityManager.find(Task.class, 3L)));
assertTrue(result_6.contains(entityManager.find(Task.class, 5L)));
assertTrue(result_6.contains(entityManager.find(Task.class, 11L)));
assertTrue(result_6.contains(entityManager.find(Task.class, 12L)));
}
}

View File

@ -1,87 +0,0 @@
package core.users;
import core.entities.User;
import core.repositories.UserRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.Optional;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
@DataJpaTest
@ExtendWith(SpringExtension.class)
public class UserRepositoryTests {
@Autowired
private UserRepository userRepository;
@Autowired
private TestEntityManager testEntityManager;
@Test
@Sql("classpath:userRepisotoryTestEntries.sql")
void test_findByUsername() {
//Situation 1: User with name "FawKes100" is present
User referenceUser = testEntityManager.find(User.class, 1L);
Optional<User> findResult = userRepository.findByUsername(referenceUser.getUsername());
assertTrue(findResult.isPresent());
assertEquals(referenceUser,findResult.get());
//Situation 2: No user with the required name is present
findResult = userRepository.findByUsername("fawkes1001");
assertFalse(findResult.isPresent());
}
@Test
@Sql("classpath:userRepisotoryTestEntries.sql")
void test_existsByMail() {
User referenceUser = testEntityManager.find(User.class, 1L);
//Situation 1: invalid email format should not matter
assertFalse(userRepository.existsByEmail("FawKes100"));
//Situation 2: No user exists with such a mail
assertFalse(userRepository.existsByEmail("mail@fawkes100.de"));
//Situation 3: User with this mail exists
assertTrue(userRepository.existsByEmail(referenceUser.getEmail()));
}
@Test
@Sql("classpath:userRepisotoryTestEntries.sql")
void test_existsByUsername() {
User referenceUser = testEntityManager.find(User.class, 1L);
//Situation 1: No such user
assertFalse(userRepository.existsByUsername("FawKes100"));
//Situation 3: User with this name exists
assertTrue(userRepository.existsByUsername(referenceUser.getUsername()));
}
@Test
@Sql("classpath:userRepisotoryTestEntries.sql")
void test_deleteUserByName() {
User referenceUser1 = testEntityManager.find(User.class, 1L);
User referenceUser2 = testEntityManager.find(User.class, 2L);
userRepository.deleteByUsername(referenceUser2.getUsername());
assertThat(testEntityManager.find(User.class, referenceUser2.getId())).isNull();
assertThat(testEntityManager.find(User.class, referenceUser1.getId())).isNotNull();
}
@Test
@Sql("classpath:userRepisotoryTestEntries.sql")
void test_countUsers() {
assertEquals(2, userRepository.countUsers());
}
}

View File

@ -7220,9 +7220,9 @@
"dev": true "dev": true
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.3", "version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -8103,9 +8103,9 @@
} }
}, },
"node_modules/ip": { "node_modules/ip": {
"version": "2.0.0", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==",
"dev": true "dev": true
}, },
"node_modules/ipaddr.js": { "node_modules/ipaddr.js": {

View File

@ -5,16 +5,19 @@ api/account.service.ts
api/api.ts api/api.ts
api/history.service.ts api/history.service.ts
api/login.service.ts api/login.service.ts
api/ntfy.service.ts
api/properties.service.ts api/properties.service.ts
api/schedule.service.ts api/schedule.service.ts
api/task.service.ts api/task.service.ts
api/taskgroup.service.ts api/taskgroup.service.ts
api/taskseries.service.ts
api/users.service.ts api/users.service.ts
configuration.ts configuration.ts
encoder.ts encoder.ts
git_push.sh git_push.sh
index.ts index.ts
model/accountDeleteRequest.ts model/accountDeleteRequest.ts
model/activityInfo.ts
model/advancedScheduleFieldInfo.ts model/advancedScheduleFieldInfo.ts
model/advancedScheduleInfo.ts model/advancedScheduleInfo.ts
model/advancedScheduleInfoAllOf.ts model/advancedScheduleInfoAllOf.ts
@ -30,7 +33,9 @@ model/inlineResponse403.ts
model/inlineResponse409.ts model/inlineResponse409.ts
model/loginRequest.ts model/loginRequest.ts
model/loginResponse.ts model/loginResponse.ts
model/manualScheduleStopInfo.ts
model/models.ts model/models.ts
model/ntfyInformation.ts
model/passwordChangeRequest.ts model/passwordChangeRequest.ts
model/propertiesInfo.ts model/propertiesInfo.ts
model/propertyInfo.ts model/propertyInfo.ts
@ -44,6 +49,9 @@ model/simpleStatusResponse.ts
model/taskEntityInfo.ts model/taskEntityInfo.ts
model/taskFieldInfo.ts model/taskFieldInfo.ts
model/taskOverviewInfo.ts model/taskOverviewInfo.ts
model/taskRepeatDayInfo.ts
model/taskRepeatWeekDayInfo.ts
model/taskRepeatWeekInfo.ts
model/taskScheduleStopResponse.ts model/taskScheduleStopResponse.ts
model/taskShortInfo.ts model/taskShortInfo.ts
model/taskTaskgroupInfo.ts model/taskTaskgroupInfo.ts

View File

@ -5,10 +5,12 @@ import { HttpClient } from '@angular/common/http';
import { AccountService } from './api/account.service'; import { AccountService } from './api/account.service';
import { HistoryService } from './api/history.service'; import { HistoryService } from './api/history.service';
import { LoginService } from './api/login.service'; import { LoginService } from './api/login.service';
import { NtfyService } from './api/ntfy.service';
import { PropertiesService } from './api/properties.service'; import { PropertiesService } from './api/properties.service';
import { ScheduleService } from './api/schedule.service'; import { ScheduleService } from './api/schedule.service';
import { TaskService } from './api/task.service'; import { TaskService } from './api/task.service';
import { TaskgroupService } from './api/taskgroup.service'; import { TaskgroupService } from './api/taskgroup.service';
import { TaskseriesService } from './api/taskseries.service';
import { UsersService } from './api/users.service'; import { UsersService } from './api/users.service';
@NgModule({ @NgModule({

View File

@ -4,6 +4,8 @@ export * from './history.service';
import { HistoryService } from './history.service'; import { HistoryService } from './history.service';
export * from './login.service'; export * from './login.service';
import { LoginService } from './login.service'; import { LoginService } from './login.service';
export * from './ntfy.service';
import { NtfyService } from './ntfy.service';
export * from './properties.service'; export * from './properties.service';
import { PropertiesService } from './properties.service'; import { PropertiesService } from './properties.service';
export * from './schedule.service'; export * from './schedule.service';
@ -12,6 +14,8 @@ export * from './task.service';
import { TaskService } from './task.service'; import { TaskService } from './task.service';
export * from './taskgroup.service'; export * from './taskgroup.service';
import { TaskgroupService } from './taskgroup.service'; import { TaskgroupService } from './taskgroup.service';
export * from './taskseries.service';
import { TaskseriesService } from './taskseries.service';
export * from './users.service'; export * from './users.service';
import { UsersService } from './users.service'; import { UsersService } from './users.service';
export const APIS = [AccountService, HistoryService, LoginService, PropertiesService, ScheduleService, TaskService, TaskgroupService, UsersService]; export const APIS = [AccountService, HistoryService, LoginService, NtfyService, PropertiesService, ScheduleService, TaskService, TaskgroupService, TaskseriesService, UsersService];

View File

@ -203,28 +203,20 @@ export class HistoryService {
} }
/** /**
* @param taskgroupID internal id of taskgroup
* @param startingDate starting date * @param startingDate starting date
* @param endingDate starting date * @param endingDate starting date
* @param includeSubTaskgroups determines whether to include subtaskgroups or not
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress. * @param reportProgress flag to report request and response progress.
*/ */
public statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet(taskgroupID: number, startingDate: string, endingDate: string, includeSubTaskgroups: boolean, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<TaskgroupActivityInfo>>; public statisticsStartingDateEndingDateGet(startingDate: string, endingDate: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<TaskgroupActivityInfo>>;
public statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet(taskgroupID: number, startingDate: string, endingDate: string, includeSubTaskgroups: boolean, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<TaskgroupActivityInfo>>>; public statisticsStartingDateEndingDateGet(startingDate: string, endingDate: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<TaskgroupActivityInfo>>>;
public statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet(taskgroupID: number, startingDate: string, endingDate: string, includeSubTaskgroups: boolean, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<TaskgroupActivityInfo>>>; public statisticsStartingDateEndingDateGet(startingDate: string, endingDate: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<TaskgroupActivityInfo>>>;
public statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet(taskgroupID: number, startingDate: string, endingDate: string, includeSubTaskgroups: boolean, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> { public statisticsStartingDateEndingDateGet(startingDate: string, endingDate: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (taskgroupID === null || taskgroupID === undefined) {
throw new Error('Required parameter taskgroupID was null or undefined when calling statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet.');
}
if (startingDate === null || startingDate === undefined) { if (startingDate === null || startingDate === undefined) {
throw new Error('Required parameter startingDate was null or undefined when calling statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet.'); throw new Error('Required parameter startingDate was null or undefined when calling statisticsStartingDateEndingDateGet.');
} }
if (endingDate === null || endingDate === undefined) { if (endingDate === null || endingDate === undefined) {
throw new Error('Required parameter endingDate was null or undefined when calling statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet.'); throw new Error('Required parameter endingDate was null or undefined when calling statisticsStartingDateEndingDateGet.');
}
if (includeSubTaskgroups === null || includeSubTaskgroups === undefined) {
throw new Error('Required parameter includeSubTaskgroups was null or undefined when calling statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet.');
} }
let localVarHeaders = this.defaultHeaders; let localVarHeaders = this.defaultHeaders;
@ -259,7 +251,72 @@ export class HistoryService {
responseType_ = 'text'; responseType_ = 'text';
} }
return this.httpClient.get<Array<TaskgroupActivityInfo>>(`${this.configuration.basePath}/statistics/taskgroup-activity/${encodeURIComponent(String(taskgroupID))}/${encodeURIComponent(String(startingDate))}/${encodeURIComponent(String(endingDate))}/${encodeURIComponent(String(includeSubTaskgroups))}`, return this.httpClient.get<Array<TaskgroupActivityInfo>>(`${this.configuration.basePath}/statistics/${encodeURIComponent(String(startingDate))}/${encodeURIComponent(String(endingDate))}`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* @param taskgroupID internal id of taskgroup
* @param startingDate starting date
* @param endingDate starting date
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public statisticsTaskgroupIDStartingDateEndingDateGet(taskgroupID: number, startingDate: string, endingDate: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<TaskgroupActivityInfo>>;
public statisticsTaskgroupIDStartingDateEndingDateGet(taskgroupID: number, startingDate: string, endingDate: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<TaskgroupActivityInfo>>>;
public statisticsTaskgroupIDStartingDateEndingDateGet(taskgroupID: number, startingDate: string, endingDate: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<TaskgroupActivityInfo>>>;
public statisticsTaskgroupIDStartingDateEndingDateGet(taskgroupID: number, startingDate: string, endingDate: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (taskgroupID === null || taskgroupID === undefined) {
throw new Error('Required parameter taskgroupID was null or undefined when calling statisticsTaskgroupIDStartingDateEndingDateGet.');
}
if (startingDate === null || startingDate === undefined) {
throw new Error('Required parameter startingDate was null or undefined when calling statisticsTaskgroupIDStartingDateEndingDateGet.');
}
if (endingDate === null || endingDate === undefined) {
throw new Error('Required parameter endingDate was null or undefined when calling statisticsTaskgroupIDStartingDateEndingDateGet.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<Array<TaskgroupActivityInfo>>(`${this.configuration.basePath}/statistics/${encodeURIComponent(String(taskgroupID))}/${encodeURIComponent(String(startingDate))}/${encodeURIComponent(String(endingDate))}`,
{ {
context: localVarHttpContext, context: localVarHttpContext,
responseType: <any>responseType_, responseType: <any>responseType_,

View File

@ -0,0 +1,210 @@
/**
* API Title
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/* tslint:disable:no-unused-variable member-ordering */
import { Inject, Injectable, Optional } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
HttpResponse, HttpEvent, HttpParameterCodec, HttpContext
} from '@angular/common/http';
import { CustomHttpParameterCodec } from '../encoder';
import { Observable } from 'rxjs';
import { NtfyInformation } from '../model/models';
import { SimpleStatusResponse } from '../model/models';
import { BASE_PATH, COLLECTION_FORMATS } from '../variables';
import { Configuration } from '../configuration';
@Injectable({
providedIn: 'root'
})
export class NtfyService {
protected basePath = 'http://127.0.0.1:8080/api';
public defaultHeaders = new HttpHeaders();
public configuration = new Configuration();
public encoder: HttpParameterCodec;
constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
if (configuration) {
this.configuration = configuration;
}
if (typeof this.configuration.basePath !== 'string') {
if (typeof basePath !== 'string') {
basePath = this.basePath;
}
this.configuration.basePath = basePath;
}
this.encoder = this.configuration.encoder || new CustomHttpParameterCodec();
}
private addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
if (typeof value === "object" && value instanceof Date === false) {
httpParams = this.addToHttpParamsRecursive(httpParams, value);
} else {
httpParams = this.addToHttpParamsRecursive(httpParams, value, key);
}
return httpParams;
}
private addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
if (value == null) {
return httpParams;
}
if (typeof value === "object") {
if (Array.isArray(value)) {
(value as any[]).forEach( elem => httpParams = this.addToHttpParamsRecursive(httpParams, elem, key));
} else if (value instanceof Date) {
if (key != null) {
httpParams = httpParams.append(key,
(value as Date).toISOString().substr(0, 10));
} else {
throw Error("key may not be null if value is Date");
}
} else {
Object.keys(value).forEach( k => httpParams = this.addToHttpParamsRecursive(
httpParams, value[k], key != null ? `${key}.${k}` : k));
}
} else if (key != null) {
httpParams = httpParams.append(key, value);
} else {
throw Error("key may not be null if value is not object or array");
}
return httpParams;
}
/**
* Get ntfy information
* Get ntfy information
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public ntfyGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<NtfyInformation>;
public ntfyGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<NtfyInformation>>;
public ntfyGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<NtfyInformation>>;
public ntfyGet(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<NtfyInformation>(`${this.configuration.basePath}/ntfy`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* Edit ntfy information
* Edit ntfy information
* @param ntfyInformation
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public ntfyPost(ntfyInformation?: NtfyInformation, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<SimpleStatusResponse>;
public ntfyPost(ntfyInformation?: NtfyInformation, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<SimpleStatusResponse>>;
public ntfyPost(ntfyInformation?: NtfyInformation, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<SimpleStatusResponse>>;
public ntfyPost(ntfyInformation?: NtfyInformation, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<SimpleStatusResponse>(`${this.configuration.basePath}/ntfy`,
ntfyInformation,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
}

View File

@ -21,6 +21,7 @@ import { Observable } from 'rxjs';
import { AdvancedScheduleFieldInfo } from '../model/models'; import { AdvancedScheduleFieldInfo } from '../model/models';
import { BasicScheduleFieldInfo } from '../model/models'; import { BasicScheduleFieldInfo } from '../model/models';
import { ForgottenActivityRequest } from '../model/models'; import { ForgottenActivityRequest } from '../model/models';
import { ManualScheduleStopInfo } from '../model/models';
import { ScheduleActivateInfo } from '../model/models'; import { ScheduleActivateInfo } from '../model/models';
import { ScheduleInfo } from '../model/models'; import { ScheduleInfo } from '../model/models';
import { SimpleStatusResponse } from '../model/models'; import { SimpleStatusResponse } from '../model/models';
@ -699,6 +700,76 @@ export class ScheduleService {
); );
} }
/**
* load schedule
* gets details of schedule
* @param scheduleID internal id of schedule
* @param manualScheduleStopInfo
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public schedulesScheduleIDStopManualPost(scheduleID: number, manualScheduleStopInfo?: ManualScheduleStopInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>;
public schedulesScheduleIDStopManualPost(scheduleID: number, manualScheduleStopInfo?: ManualScheduleStopInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>;
public schedulesScheduleIDStopManualPost(scheduleID: number, manualScheduleStopInfo?: ManualScheduleStopInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>;
public schedulesScheduleIDStopManualPost(scheduleID: number, manualScheduleStopInfo?: ManualScheduleStopInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (scheduleID === null || scheduleID === undefined) {
throw new Error('Required parameter scheduleID was null or undefined when calling schedulesScheduleIDStopManualPost.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<ScheduleInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}/stopManual`,
manualScheduleStopInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/** /**
* deletes multiple schedules * deletes multiple schedules
* deletes multiple schedules at once * deletes multiple schedules at once

View File

@ -401,6 +401,190 @@ export class TaskService {
); );
} }
/**
* @param taskID internal id of task
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public tasksTaskIDSubtasksDelete(taskID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<SimpleStatusResponse>;
public tasksTaskIDSubtasksDelete(taskID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<SimpleStatusResponse>>;
public tasksTaskIDSubtasksDelete(taskID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<SimpleStatusResponse>>;
public tasksTaskIDSubtasksDelete(taskID: number, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (taskID === null || taskID === undefined) {
throw new Error('Required parameter taskID was null or undefined when calling tasksTaskIDSubtasksDelete.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.delete<SimpleStatusResponse>(`${this.configuration.basePath}/tasks/${encodeURIComponent(String(taskID))}/subtasks`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* @param taskID internal id of task
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public tasksTaskIDSubtasksGet(taskID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<TaskEntityInfo>>;
public tasksTaskIDSubtasksGet(taskID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<TaskEntityInfo>>>;
public tasksTaskIDSubtasksGet(taskID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<TaskEntityInfo>>>;
public tasksTaskIDSubtasksGet(taskID: number, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (taskID === null || taskID === undefined) {
throw new Error('Required parameter taskID was null or undefined when calling tasksTaskIDSubtasksGet.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<Array<TaskEntityInfo>>(`${this.configuration.basePath}/tasks/${encodeURIComponent(String(taskID))}/subtasks`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* Creates Subtask
* Create Subtask
* @param taskID internal id of task
* @param taskFieldInfo
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public tasksTaskIDSubtasksPut(taskID: number, taskFieldInfo?: TaskFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<TaskEntityInfo>;
public tasksTaskIDSubtasksPut(taskID: number, taskFieldInfo?: TaskFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<TaskEntityInfo>>;
public tasksTaskIDSubtasksPut(taskID: number, taskFieldInfo?: TaskFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<TaskEntityInfo>>;
public tasksTaskIDSubtasksPut(taskID: number, taskFieldInfo?: TaskFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (taskID === null || taskID === undefined) {
throw new Error('Required parameter taskID was null or undefined when calling tasksTaskIDSubtasksPut.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.put<TaskEntityInfo>(`${this.configuration.basePath}/tasks/${encodeURIComponent(String(taskID))}/subtasks`,
taskFieldInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/** /**
* creates a new task * creates a new task
* creates tasks * creates tasks

View File

@ -0,0 +1,226 @@
/**
* API Title
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/* tslint:disable:no-unused-variable member-ordering */
import { Inject, Injectable, Optional } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
HttpResponse, HttpEvent, HttpParameterCodec, HttpContext
} from '@angular/common/http';
import { CustomHttpParameterCodec } from '../encoder';
import { Observable } from 'rxjs';
import { SimpleStatusResponse } from '../model/models';
import { TaskRepeatDayInfo } from '../model/models';
import { TaskRepeatWeekInfo } from '../model/models';
import { BASE_PATH, COLLECTION_FORMATS } from '../variables';
import { Configuration } from '../configuration';
@Injectable({
providedIn: 'root'
})
export class TaskseriesService {
protected basePath = 'http://127.0.0.1:8080/api';
public defaultHeaders = new HttpHeaders();
public configuration = new Configuration();
public encoder: HttpParameterCodec;
constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
if (configuration) {
this.configuration = configuration;
}
if (typeof this.configuration.basePath !== 'string') {
if (typeof basePath !== 'string') {
basePath = this.basePath;
}
this.configuration.basePath = basePath;
}
this.encoder = this.configuration.encoder || new CustomHttpParameterCodec();
}
private addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
if (typeof value === "object" && value instanceof Date === false) {
httpParams = this.addToHttpParamsRecursive(httpParams, value);
} else {
httpParams = this.addToHttpParamsRecursive(httpParams, value, key);
}
return httpParams;
}
private addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
if (value == null) {
return httpParams;
}
if (typeof value === "object") {
if (Array.isArray(value)) {
(value as any[]).forEach( elem => httpParams = this.addToHttpParamsRecursive(httpParams, elem, key));
} else if (value instanceof Date) {
if (key != null) {
httpParams = httpParams.append(key,
(value as Date).toISOString().substr(0, 10));
} else {
throw Error("key may not be null if value is Date");
}
} else {
Object.keys(value).forEach( k => httpParams = this.addToHttpParamsRecursive(
httpParams, value[k], key != null ? `${key}.${k}` : k));
}
} else if (key != null) {
httpParams = httpParams.append(key, value);
} else {
throw Error("key may not be null if value is not object or array");
}
return httpParams;
}
/**
* daily repeating task creation
* Creates a daily repeating task
* @param taskID internal id of taskgroup
* @param taskRepeatDayInfo
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public tasksTaskIDTaskseriesDailyPost(taskID: number, taskRepeatDayInfo?: TaskRepeatDayInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<SimpleStatusResponse>;
public tasksTaskIDTaskseriesDailyPost(taskID: number, taskRepeatDayInfo?: TaskRepeatDayInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<SimpleStatusResponse>>;
public tasksTaskIDTaskseriesDailyPost(taskID: number, taskRepeatDayInfo?: TaskRepeatDayInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<SimpleStatusResponse>>;
public tasksTaskIDTaskseriesDailyPost(taskID: number, taskRepeatDayInfo?: TaskRepeatDayInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (taskID === null || taskID === undefined) {
throw new Error('Required parameter taskID was null or undefined when calling tasksTaskIDTaskseriesDailyPost.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<SimpleStatusResponse>(`${this.configuration.basePath}/tasks/${encodeURIComponent(String(taskID))}/taskseries/daily`,
taskRepeatDayInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* daily repeating task creation
* Creates a daily repeating task
* @param taskRepeatWeekInfo
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public tasksTaskseriesWeeklyPost(taskRepeatWeekInfo?: TaskRepeatWeekInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<SimpleStatusResponse>;
public tasksTaskseriesWeeklyPost(taskRepeatWeekInfo?: TaskRepeatWeekInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<SimpleStatusResponse>>;
public tasksTaskseriesWeeklyPost(taskRepeatWeekInfo?: TaskRepeatWeekInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<SimpleStatusResponse>>;
public tasksTaskseriesWeeklyPost(taskRepeatWeekInfo?: TaskRepeatWeekInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<SimpleStatusResponse>(`${this.configuration.basePath}/tasks/taskseries/weekly`,
taskRepeatWeekInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
}

View File

@ -0,0 +1,21 @@
/**
* API Title
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface ActivityInfo {
date: string;
/**
* Number of minutes the task was active
*/
activeMinutes: number;
}

View File

@ -0,0 +1,20 @@
/**
* API Title
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface ManualScheduleStopInfo {
/**
* duration in minutes
*/
duration: number;
}

View File

@ -1,4 +1,5 @@
export * from './accountDeleteRequest'; export * from './accountDeleteRequest';
export * from './activityInfo';
export * from './advancedScheduleFieldInfo'; export * from './advancedScheduleFieldInfo';
export * from './advancedScheduleInfo'; export * from './advancedScheduleInfo';
export * from './advancedScheduleInfoAllOf'; export * from './advancedScheduleInfoAllOf';
@ -14,6 +15,8 @@ export * from './inlineResponse403';
export * from './inlineResponse409'; export * from './inlineResponse409';
export * from './loginRequest'; export * from './loginRequest';
export * from './loginResponse'; export * from './loginResponse';
export * from './manualScheduleStopInfo';
export * from './ntfyInformation';
export * from './passwordChangeRequest'; export * from './passwordChangeRequest';
export * from './propertiesInfo'; export * from './propertiesInfo';
export * from './propertyInfo'; export * from './propertyInfo';
@ -27,6 +30,9 @@ export * from './simpleStatusResponse';
export * from './taskEntityInfo'; export * from './taskEntityInfo';
export * from './taskFieldInfo'; export * from './taskFieldInfo';
export * from './taskOverviewInfo'; export * from './taskOverviewInfo';
export * from './taskRepeatDayInfo';
export * from './taskRepeatWeekDayInfo';
export * from './taskRepeatWeekInfo';
export * from './taskScheduleStopResponse'; export * from './taskScheduleStopResponse';
export * from './taskShortInfo'; export * from './taskShortInfo';
export * from './taskTaskgroupInfo'; export * from './taskTaskgroupInfo';

View File

@ -0,0 +1,32 @@
/**
* API Title
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface NtfyInformation {
/**
* host of ntfy service
*/
ntfy_host: string;
/**
* topic of ntfy service
*/
ntfy_topic: string;
/**
* username of ntfy account for publishing news
*/
ntfy_user?: string;
/**
* token to ntfy useraccount
*/
ntfy_token?: string;
}

View File

@ -56,5 +56,17 @@ export interface TaskEntityInfo {
* determines whether the task has schedules that can be started * determines whether the task has schedules that can be started
*/ */
hasPlannedSchedules: boolean; hasPlannedSchedules: boolean;
/**
* determines whether the task is associated with a taskserie
*/
hasTaskSerie: boolean;
/**
* determines whether a task has subtasks
*/
hasSubtasks: boolean;
/**
* determines whether a task is a top task or Not
*/
hasParent: boolean;
} }

View File

@ -42,5 +42,9 @@ export interface TaskOverviewInfo {
* determines whether the task can be finished * determines whether the task can be finished
*/ */
finishable: boolean; finishable: boolean;
/**
* determines whether the task has subtasks
*/
hasSubtasks: boolean;
} }

View File

@ -0,0 +1,24 @@
/**
* API Title
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface TaskRepeatDayInfo {
/**
* number repeating days
*/
offset: number;
/**
* Date until the tasks repeat
*/
endingDate: string;
}

View File

@ -0,0 +1,41 @@
/**
* API Title
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface TaskRepeatWeekDayInfo {
/**
* number repeating days
*/
offset: number;
/**
* internal identifier of task
*/
taskID: number;
/**
* day of week
*/
dayOfWeek: TaskRepeatWeekDayInfo.DayOfWeekEnum;
}
export namespace TaskRepeatWeekDayInfo {
export type DayOfWeekEnum = 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY' | 'SUNDAY';
export const DayOfWeekEnum = {
Monday: 'MONDAY' as DayOfWeekEnum,
Tuesday: 'TUESDAY' as DayOfWeekEnum,
Wednesday: 'WEDNESDAY' as DayOfWeekEnum,
Thursday: 'THURSDAY' as DayOfWeekEnum,
Friday: 'FRIDAY' as DayOfWeekEnum,
Saturday: 'SATURDAY' as DayOfWeekEnum,
Sunday: 'SUNDAY' as DayOfWeekEnum
};
}

View File

@ -0,0 +1,22 @@
/**
* API Title
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { TaskRepeatWeekDayInfo } from './taskRepeatWeekDayInfo';
export interface TaskRepeatWeekInfo {
/**
* Date until the tasks repeat
*/
endDate: string;
weekDayInfos: Array<TaskRepeatWeekDayInfo>;
}

View File

@ -9,13 +9,12 @@
* https://openapi-generator.tech * https://openapi-generator.tech
* Do not edit the class manually. * Do not edit the class manually.
*/ */
import { ActivityInfo } from './activityInfo';
import { TaskgroupEntityInfo } from './taskgroupEntityInfo';
export interface TaskgroupActivityInfo { export interface TaskgroupActivityInfo {
date: string; taskgroup: TaskgroupEntityInfo;
/** activityInfos: Array<ActivityInfo>;
* Number of minutes the task was active
*/
activeMinutes: number;
} }

View File

@ -93,7 +93,8 @@ export class ActiveTaskOverviewComponent implements OnInit{
editTask(editedTask: TaskTaskgroupInfo) { editTask(editedTask: TaskTaskgroupInfo) {
const taskEditorInfo: TaskEditorData = { const taskEditorInfo: TaskEditorData = {
task: editedTask, task: editedTask,
taskgroupID: editedTask.taskgroups[editedTask.taskgroups.length-1].taskgroupID taskgroupID: editedTask.taskgroups[editedTask.taskgroups.length-1].taskgroupID,
parentTask: undefined
}; };
this.dialog.open(TaskEditorComponent, {data: taskEditorInfo, width: "600px"}) this.dialog.open(TaskEditorComponent, {data: taskEditorInfo, width: "600px"})
} }

View File

@ -17,6 +17,7 @@ import {
} from "./dashboard/forgotten-task-start-dialog/forgotten-task-start-dialog.component"; } from "./dashboard/forgotten-task-start-dialog/forgotten-task-start-dialog.component";
import {TaskgroupActivityComponent} from "./statistics/taskgroup-activity/taskgroup-activity.component"; import {TaskgroupActivityComponent} from "./statistics/taskgroup-activity/taskgroup-activity.component";
import {ScheduleHistoryComponent} from "./statistics/schedule-history/schedule-history.component"; import {ScheduleHistoryComponent} from "./statistics/schedule-history/schedule-history.component";
import {UpcomingDeadlinesOverviewComponent} from "./upcoming-deadlines-overview/upcoming-deadlines-overview.component";
const routes: Routes = [ const routes: Routes = [
{path: '', component: MainComponent}, {path: '', component: MainComponent},
@ -35,6 +36,7 @@ const routes: Routes = [
{path: 'forgotten', component: ForgottenTaskStartDialogComponent}, {path: 'forgotten', component: ForgottenTaskStartDialogComponent},
{path: 'statistics/taskgroup-activity', component: TaskgroupActivityComponent}, {path: 'statistics/taskgroup-activity', component: TaskgroupActivityComponent},
{path: 'statistics/schedule-history', component: ScheduleHistoryComponent}, {path: 'statistics/schedule-history', component: ScheduleHistoryComponent},
{path: 'deadlines', component: UpcomingDeadlinesOverviewComponent}
]; ];
@NgModule({ @NgModule({

View File

@ -6,10 +6,13 @@
<mat-menu #organizeMenu=matMenu> <mat-menu #organizeMenu=matMenu>
<button mat-menu-item routerLink="taskgroups/" aria-label="Task groups">Taskgroups</button> <button mat-menu-item routerLink="taskgroups/" aria-label="Task groups">Taskgroups</button>
<button mat-menu-item routerLink="scheduler/" aria-label="Task groups">Scheduler</button> <button mat-menu-item routerLink="scheduler/" aria-label="Task groups">Scheduler</button>
<mat-divider></mat-divider>
<button mat-menu-item routerLink="active/" aria-label="Missed Schedules">Active Tasks</button> <button mat-menu-item routerLink="active/" aria-label="Missed Schedules">Active Tasks</button>
<button mat-menu-item routerLink="upcoming/" aria-label="Upcoming Tasks">Upcoming Tasks</button> <button mat-menu-item routerLink="upcoming/" aria-label="Upcoming Tasks">Upcoming Tasks</button>
<button mat-menu-item routerLink="overdue/" aria-label="Overdue Tasks">Overdue Tasks</button> <button mat-menu-item routerLink="overdue/" aria-label="Overdue Tasks">Overdue Tasks</button>
<button mat-menu-item routerLink="reschedule/" aria-label="Missed Schedules">Missed Schedules</button> <button mat-menu-item routerLink="reschedule/" aria-label="Missed Schedules">Missed Schedules</button>
<mat-divider></mat-divider>
<button mat-menu-item routerLink="deadlines" aria-label="Upcoming Deadlines">Deadlines</button>
</mat-menu> </mat-menu>
<mat-menu #statisticsMenu=matMenu> <mat-menu #statisticsMenu=matMenu>

View File

@ -86,6 +86,16 @@ import {NgApexchartsModule} from "ng-apexcharts";
import { SimpleActivityDiagramComponent } from './statistics/taskgroup-activity/simple-activity-diagram/simple-activity-diagram.component'; import { SimpleActivityDiagramComponent } from './statistics/taskgroup-activity/simple-activity-diagram/simple-activity-diagram.component';
import { HeatmapActivityComponent } from './statistics/taskgroup-activity/heatmap-activity/heatmap-activity.component'; import { HeatmapActivityComponent } from './statistics/taskgroup-activity/heatmap-activity/heatmap-activity.component';
import { ScheduleHistoryComponent } from './statistics/schedule-history/schedule-history.component'; import { ScheduleHistoryComponent } from './statistics/schedule-history/schedule-history.component';
import {MatButtonToggleModule} from "@angular/material/button-toggle";
import {MatGridListModule} from "@angular/material/grid-list";
import { StopScheduleManuallyComponent } from './dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component';
import { ConnectionSettingsComponent } from './user-settings/connection-settings/connection-settings.component';
import { NtfySettingsComponent } from './user-settings/connection-settings/ntfy-settings/ntfy-settings.component';
import { TaskSeriesCreatorComponent } from './tasks/task-series-creator/task-series-creator.component';
import {MatStepperModule} from "@angular/material/stepper";
import { TaskWeeklySeriesCreatorComponent } from './tasks/task-weekly-series-creator/task-weekly-series-creator.component';
import { UpcomingDeadlinesOverviewComponent } from './upcoming-deadlines-overview/upcoming-deadlines-overview.component';
import {CommonModule} from "@angular/common";
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
@ -130,6 +140,12 @@ import { ScheduleHistoryComponent } from './statistics/schedule-history/schedule
SimpleActivityDiagramComponent, SimpleActivityDiagramComponent,
HeatmapActivityComponent, HeatmapActivityComponent,
ScheduleHistoryComponent, ScheduleHistoryComponent,
StopScheduleManuallyComponent,
ConnectionSettingsComponent,
NtfySettingsComponent,
TaskSeriesCreatorComponent,
TaskWeeklySeriesCreatorComponent,
UpcomingDeadlinesOverviewComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@ -171,6 +187,9 @@ import { ScheduleHistoryComponent } from './statistics/schedule-history/schedule
MatSliderModule, MatSliderModule,
NgxSliderModule, NgxSliderModule,
NgApexchartsModule, NgApexchartsModule,
MatButtonToggleModule,
MatGridListModule,
MatStepperModule
], ],
providers: [ providers: [
HttpClientModule, HttpClientModule,

View File

@ -139,3 +139,26 @@
color: white; color: white;
border-radius: 0; border-radius: 0;
} }
::ng-deep mat-button-toggle.drop-down-button {
margin-left: 0;
}
.parent-container {
display: flex;
justify-content: space-between;
width: 100%;
}
.right-container {
margin-top: -5px;
}
::ng-deep .small-button {
padding: 6px; /* Adjust padding as needed */
font-size: 10px; /* Adjust font size as needed */
}
.btn {
border-radius: 0;
}

View File

@ -6,14 +6,28 @@
</mat-card> </mat-card>
<mat-card *ngIf="activeSchedule != undefined"> <mat-card *ngIf="activeSchedule != undefined">
<mat-card-header> <mat-card-header>
<mat-card-title><a routerLink="/" class="link-no-deco">{{activeSchedule!.task.taskName}}</a></mat-card-title> <mat-card-title><a [routerLink]="['/taskgroups', taskgroupID, 'tasks', activeSchedule!.task.taskID]" class="link-no-deco">{{activeSchedule!.task.taskName}}</a></mat-card-title>
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<span *ngFor="let taskgroupPath of activeSchedule!.taskgroupPath">{{taskgroupPath.taskgroupName}} /</span> <span *ngFor="let taskgroupPath of activeSchedule!.taskgroupPath">
<a class="link-no-deco" [routerLink]="['/taskgroups', taskgroupPath.taskgroupID]"> {{taskgroupPath.taskgroupName}} </a>/
</span>
<p class="gray-text">Running for {{displayTime}}</p> <p class="gray-text">Running for {{displayTime}}</p>
</mat-card-content> </mat-card-content>
<mat-card-actions> <mat-card-actions>
<button mat-raised-button class="grayBtn" (click)="stopTask(false)">Stop</button> <button class="btn btn-secondary" (click)="stopTask(false)">Stop</button>
<button mat-raised-button class="greenBtn" *ngIf="activeSchedule!.task.finishable" (click)="stopTask(true)">Finish</button> <div class="btn-group">
<button type="button" class="btn btn-success" (click)="finishSchedule()">Finish</button>
<button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><button class="dropdown-item" (click)="abortSchedule()">Abort</button></li>
<li><button class="dropdown-item" (click)="finishManual()">Set manually stop time</button></li>
</ul>
</div>
</mat-card-actions> </mat-card-actions>
</mat-card> </mat-card>

View File

@ -1,9 +1,16 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {ScheduleInfo, ScheduleService, TaskOverviewInfo, TaskScheduleStopResponse} from "../../../api"; import {
ScheduleInfo,
ScheduleService,
TaskgroupEntityInfo,
TaskOverviewInfo,
TaskScheduleStopResponse
} from "../../../api";
import {StopActiveScheduleInfo} from "./StopActiveScheduleInfo"; import {StopActiveScheduleInfo} from "./StopActiveScheduleInfo";
import {TaskOverviewComponent} from "../task-overview/task-overview.component"; import {TaskOverviewComponent} from "../task-overview/task-overview.component";
import {MatDialog} from "@angular/material/dialog"; import {MatDialog} from "@angular/material/dialog";
import {ForgottenTaskStartDialogComponent} from "../forgotten-task-start-dialog/forgotten-task-start-dialog.component"; import {ForgottenTaskStartDialogComponent} from "../forgotten-task-start-dialog/forgotten-task-start-dialog.component";
import {StopScheduleManuallyComponent} from "./stop-schedule-manually/stop-schedule-manually.component";
export interface StopActiveScheduleEmitterInfo { export interface StopActiveScheduleEmitterInfo {
stopactiveScheduleResponse: StopActiveScheduleInfo, stopactiveScheduleResponse: StopActiveScheduleInfo,
@ -18,6 +25,7 @@ export interface StopActiveScheduleEmitterInfo {
}) })
export class ActiveScheduleComponent implements OnInit{ export class ActiveScheduleComponent implements OnInit{
activeSchedule: ScheduleInfo | undefined activeSchedule: ScheduleInfo | undefined
taskgroupID: number | undefined
startTime: number = 0; startTime: number = 0;
currentTime: number = 0; currentTime: number = 0;
@ -55,11 +63,15 @@ export class ActiveScheduleComponent implements OnInit{
next: resp => { next: resp => {
if(resp.scheduleID >= 0) { if(resp.scheduleID >= 0) {
this.activateSchedule(resp); this.activateSchedule(resp);
this.taskgroupID = resp.taskgroupPath[resp.taskgroupPath.length-1].taskgroupID
console.log(this.taskgroupID)
} }
}, },
}) })
} }
stopTask(finish: boolean) { stopTask(finish: boolean) {
@ -89,6 +101,43 @@ export class ActiveScheduleComponent implements OnInit{
this.activeSchedule = undefined this.activeSchedule = undefined
} }
abortSchedule() {
this.scheduleService.schedulesScheduleIDDelete(this.activeSchedule!.scheduleID).subscribe({
next: resp => {
this.activeSchedule = undefined;
}
})
}
finishSchedule() {
this.scheduleService.schedulesScheduleIDStopFinishPost(this.activeSchedule!.scheduleID, true).subscribe({
next: resp => {
this.activeSchedule = undefined;
}
})
}
finishManual() {
const dialogRef = this.dialog.open(StopScheduleManuallyComponent, {
data: this.activeSchedule,
minWidth: "400px"})
dialogRef.afterClosed().subscribe(res => {
if(res != undefined) {
this.scheduleStopEmitter.emit({
finish: false,
taskID: this.activeSchedule!.scheduleID,
stopactiveScheduleResponse: {
schedule: this.activeSchedule!,
workedMinutes: res
}
})
this.activeSchedule = undefined;
}
})
}
openForgettedActivityDialog() { openForgettedActivityDialog() {
const dialogRef = this.dialog.open(ForgottenTaskStartDialogComponent, {width: "400px"}) const dialogRef = this.dialog.open(ForgottenTaskStartDialogComponent, {width: "400px"})
dialogRef.afterClosed().subscribe(res => { dialogRef.afterClosed().subscribe(res => {
@ -97,4 +146,6 @@ export class ActiveScheduleComponent implements OnInit{
} }
}) })
} }
} }

View File

@ -0,0 +1,4 @@
.dialog-padding {
padding-left: 5px;
padding-right: 5px;
}

View File

@ -0,0 +1,11 @@
<h1 mat-dialog-title>Set Stoptime Manually</h1>
<mat-dialog-content>
<mat-form-field appearance="outline" class="long-form dialog-padding">
<mat-label>Spent Minutes</mat-label>
<input matInput type="number" [formControl]="formControl">
</mat-form-field>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-raised-button (click)="cancel()">Cancel</button>
<button mat-raised-button color="primary" (click)="save()" [disabled]="formControl.invalid">Confirm</button>
</mat-dialog-actions>

View File

@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StopScheduleManuallyComponent } from './stop-schedule-manually.component';
describe('StopScheduleManuallyComponent', () => {
let component: StopScheduleManuallyComponent;
let fixture: ComponentFixture<StopScheduleManuallyComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [StopScheduleManuallyComponent]
});
fixture = TestBed.createComponent(StopScheduleManuallyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,34 @@
import {Component, Inject} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {ScheduleInfo, ScheduleService} from "../../../../api";
import {FormControl, Validators} from "@angular/forms";
@Component({
selector: 'app-stop-schedule-manually',
templateUrl: './stop-schedule-manually.component.html',
styleUrls: ['./stop-schedule-manually.component.css']
})
export class StopScheduleManuallyComponent {
formControl: FormControl = new FormControl('', [Validators.required])
constructor(@Inject(MAT_DIALOG_DATA) public schedule: ScheduleInfo,
private scheduleService: ScheduleService,
private dialogRef: MatDialogRef<StopScheduleManuallyComponent>) {
}
cancel() {
this.dialogRef.close();
}
save() {
console.log(this.schedule.scheduleID)
this.scheduleService.schedulesScheduleIDStopManualPost(this.schedule.scheduleID, {
duration: this.formControl.value
}).subscribe({
next: resp => {
this.dialogRef.close(Number(this.formControl.value))
}
})
}
}

View File

@ -23,16 +23,18 @@
<mat-card *ngFor="let schedule of schedules"> <mat-card *ngFor="let schedule of schedules">
<mat-card-header> <mat-card-header>
<mat-card-title> <mat-card-title>
<a routerLink="/" class="link-no-deco">{{schedule.task.taskName}}</a> <a [routerLink]="['/taskgroups', schedule.taskgroupPath[schedule.taskgroupPath.length-1].taskgroupID, 'tasks', schedule.task.taskID]" class="link-no-deco">{{schedule.task.taskName}}</a>
</mat-card-title> </mat-card-title>
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<span *ngFor="let taskgroupPath of schedule.taskgroupPath">{{taskgroupPath.taskgroupName}} /</span> <span *ngFor="let taskgroupPath of schedule.taskgroupPath">
<a class="link-no-deco" [routerLink]="['/taskgroups', taskgroupPath.taskgroupID]"> {{taskgroupPath.taskgroupName}} /</a>
</span>
<p class="gray-text" *ngIf="schedule.scheduleType==='BASIC'">To be done sometime today</p> <p class="gray-text" *ngIf="schedule.scheduleType==='BASIC'">To be done sometime today</p>
</mat-card-content> </mat-card-content>
<mat-card-actions> <mat-card-actions>
<button mat-raised-button color="primary" class="primaryBtn" (click)="startSchedule(schedule)" [disabled]="activeScheduleComponent!.activeSchedule != undefined">Start now</button> <button mat-raised-button color="primary" class="primaryBtn" (click)="startSchedule(schedule)" [disabled]="activeScheduleComponent!.activeSchedule != undefined">Start now</button>
<button mat-raised-button class="yellowBtn">Reschedule</button> <button mat-raised-button class="yellowBtn" [routerLink]="['/taskgroups', schedule.taskgroupPath[schedule.taskgroupPath.length-1].taskgroupID, 'tasks', schedule.task.taskID, 'schedule', schedule.scheduleID]">Reschedule</button>
</mat-card-actions> </mat-card-actions>
</mat-card> </mat-card>
</div> </div>

View File

@ -5,6 +5,11 @@
justify-content: space-between; justify-content: space-between;
} }
.navi-link-container {
margin: 20px auto;
width: 80%;
}
.spacer { .spacer {
margin-bottom: 2.5%; margin-bottom: 2.5%;
} }

View File

@ -1,4 +1,8 @@
<div class="navi-link-container">
<app-navigation-link-list [navigationLinks]="defaultNavigationLinks"></app-navigation-link-list>
</div>
<div class="container"> <div class="container">
<div class="calendar-container"> <div class="calendar-container">
<h1 mat-dialog-title>Register forgotten activity</h1> <h1 mat-dialog-title>Register forgotten activity</h1>
<mwl-calendar-day-view <mwl-calendar-day-view

View File

@ -17,6 +17,7 @@ import * as moment from "moment/moment";
import {EventColor} from "calendar-utils"; import {EventColor} from "calendar-utils";
import {TaskOverviewData} from "../taskgroup-overview/taskgroup-overview.component"; import {TaskOverviewData} from "../taskgroup-overview/taskgroup-overview.component";
import {Router} from "@angular/router"; import {Router} from "@angular/router";
import {NavigationLink} from "../../navigation-link-list/navigation-link-list.component";
const colors: Record<string, EventColor> = { const colors: Record<string, EventColor> = {
@ -65,6 +66,16 @@ export class ForgottenTaskStartDialogComponent implements OnInit{
}, },
}, },
]; ];
defaultNavigationLinks: NavigationLink[] = [
{
linkText: "Dashboard",
routerLink: ['/']
},
{
linkText: "Register Forgotten Activity",
routerLink: ["/forgotten"]
}
];
constructor(private router: Router, constructor(private router: Router,
@ -124,6 +135,8 @@ export class ForgottenTaskStartDialogComponent implements OnInit{
event.start = newStart; event.start = newStart;
if (newEnd) { if (newEnd) {
event.end = newEnd; event.end = newEnd;
} else {
event.end = moment(event.start).add( 30, "minutes").toDate()
} }
this.events = [...this.events]; this.events = [...this.events];
} }
@ -169,9 +182,11 @@ export class ForgottenTaskStartDialogComponent implements OnInit{
} }
register() { register() {
this.scheduleService.schedulesTaskIDForgottenPost(this.events[0].meta.taskID, { console.log(this.events[this.events.length-1].start)
startTime: moment(this.events[0].start).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), console.log(this.events[this.events.length-1].end)
endTime: moment(this.events[0].end).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), this.scheduleService.schedulesTaskIDForgottenPost(this.events[this.events.length-1].meta.taskID, {
startTime: moment(this.events[this.events.length-1].start).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
endTime: moment(this.events[this.events.length-1].end).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
}).subscribe({ }).subscribe({
next: resp => { next: resp => {
this.router.navigateByUrl("/"); this.router.navigateByUrl("/");

View File

@ -31,3 +31,13 @@
text-decoration: none; text-decoration: none;
color: black; color: black;
} }
.task-title {
display: flex;
justify-content: space-between;
}
.subtask-link {
color: #00bc8c;
text-decoration: none;
}

View File

@ -2,7 +2,10 @@
<button mat-raised-button class="greenBtn long-btn"(click)="openTaskCreation()">Add</button> <button mat-raised-button class="greenBtn long-btn"(click)="openTaskCreation()">Add</button>
<mat-card *ngFor="let task of tasks"> <mat-card *ngFor="let task of tasks">
<mat-card-content> <mat-card-content>
<h3><a class="task-link" [routerLink]="['/taskgroups', taskgroupID!, 'tasks', task.taskID]">{{task.taskName}}</a></h3> <h3 class="task-title">
<a class="task-link" [routerLink]="['/taskgroups', taskgroupID!, 'tasks', task.taskID]">{{task.taskName}}</a>
<button mat-button class="subtask-link" *ngIf="task.hasSubtasks" [routerLink]="['/taskgroups', taskgroupID!, 'tasks', task.taskID]">has Subtasks</button>
</h3>
<mat-progress-bar mode="determinate" value="{{task.activeTime}}" class="progress"></mat-progress-bar> <mat-progress-bar mode="determinate" value="{{task.activeTime}}" class="progress"></mat-progress-bar>
<p class="task-info"><i>ETA: </i>{{task.activeTime}} / {{task.eta}}</p> <p class="task-info"><i>ETA: </i>{{task.activeTime}} / {{task.eta}}</p>
<p class="task-info"><i>Limit: </i>{{task.limit}}</p> <p class="task-info"><i>Limit: </i>{{task.limit}}</p>

View File

@ -75,7 +75,8 @@ export class TaskOverviewComponent {
openTaskCreation() { openTaskCreation() {
const editorData: TaskEditorData = { const editorData: TaskEditorData = {
task: undefined, task: undefined,
taskgroupID: this.taskgroupID! taskgroupID: this.taskgroupID!,
parentTask: undefined
} }
const dialogRef = this.dialog.open(TaskEditorComponent, {data: editorData, width: "600px"}) const dialogRef = this.dialog.open(TaskEditorComponent, {data: editorData, width: "600px"})
dialogRef.afterClosed().subscribe(res => { dialogRef.afterClosed().subscribe(res => {
@ -88,6 +89,7 @@ export class TaskOverviewComponent {
activeTime: 0, activeTime: 0,
overdue: res.overdue, overdue: res.overdue,
taskgroupPath: [], taskgroupPath: [],
hasSubtasks: false,
finishable: res.finishable finishable: res.finishable
} }
this.creationEmitter.emit({ this.creationEmitter.emit({

View File

@ -3,7 +3,14 @@
<app-navigation-link-list #navLinkList [navigationLinks]="defaultNavigationLinkPath"></app-navigation-link-list> <app-navigation-link-list #navLinkList [navigationLinks]="defaultNavigationLinkPath"></app-navigation-link-list>
<div class="schedule-header"> <div class="schedule-header">
<h1>Monday, {{ viewDate | calendarDate:(view + 'ViewTitle'):'en':1 }}</h1> <div class="calendar-control">
<button mat-flat-button color="primary" mwlCalendarPreviousView [view]="'week'" [(viewDate)]="viewDate">Previous</button>
<button mat-flat-button mwlCalendarToday (click)="resetCalendarToToday()">Today</button>
<button mat-flat-button color="primary" mwlCalendarNextView [view]="'week'" [(viewDate)]="viewDate">Next</button>
</div>
<div class="calendar-date-title">
<h1>Monday, {{ viewDate | calendarDate:(view + 'ViewTitle'):'en':1 }}</h1>
</div>
<mat-form-field style="float:right;"> <mat-form-field style="float:right;">
<mat-label>Schedule Strategy</mat-label> <mat-label>Schedule Strategy</mat-label>
<mat-select [(ngModel)]="scheduleStrategy"> <mat-select [(ngModel)]="scheduleStrategy">
@ -13,11 +20,13 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>
<p>TZest</p>
<div style="display: flex; justify-content: space-between;"> <div style="display: flex; justify-content: space-between;">
<div style="width: 75%"> <div style="width: 75%">
<mwl-calendar-week-view [viewDate]="viewDate" [daysInWeek]="daysInWeek" [dayStartHour]="7" [dayEndHour]="21" [refresh]="refresh" <mwl-calendar-week-view [viewDate]="viewDate" [daysInWeek]="7" [dayStartHour]="7" [dayEndHour]="21" [refresh]="refresh"
[snapDraggedEvents]="false" [snapDraggedEvents]="false"
(eventTimesChanged)="eventDropped($event)" [events]="events" (eventClicked)="eventClicked('Click', $event.event)" (eventTimesChanged)="eventDropped($event)" [events]="events" (eventClicked)="eventClicked('Click', $event.event)"
[weekStartsOn]="1"
> >
</mwl-calendar-week-view> </mwl-calendar-week-view>
</div> </div>

View File

@ -1,4 +1,4 @@
import {Component, ViewChild} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {NavigationLink, NavigationLinkListComponent} from "../../navigation-link-list/navigation-link-list.component"; import {NavigationLink, NavigationLinkListComponent} from "../../navigation-link-list/navigation-link-list.component";
import { import {
AdvancedScheduleInfo, AdvancedScheduleInfo,
@ -47,7 +47,7 @@ const colors: Record<string, EventColor> = {
`, `,
], ],
}) })
export class DraggableSchedulerComponent { export class DraggableSchedulerComponent implements OnInit{
defaultNavigationLinkPath: NavigationLink[] = [ defaultNavigationLinkPath: NavigationLink[] = [
{ {
linkText: "Dashboard", linkText: "Dashboard",
@ -104,6 +104,7 @@ export class DraggableSchedulerComponent {
} }
ngOnInit() { ngOnInit() {
this.viewDate = moment().startOf('isoWeek').toDate()
this.scheduleService.schedulesGet().subscribe({ this.scheduleService.schedulesGet().subscribe({
next: resp => { next: resp => {
resp.forEach(schedule => { resp.forEach(schedule => {
@ -282,4 +283,8 @@ export class DraggableSchedulerComponent {
} }
} }
resetCalendarToToday() {
this.viewDate = moment().startOf('isoWeek').toDate();
}
} }

View File

@ -29,3 +29,20 @@
::ng-deep .cal-event-title { ::ng-deep .cal-event-title {
white-space: normal; white-space: normal;
} }
.calendar-header {
display: flex;
align-items: center;
}
.calendar-control {
display: flex;
}
.calendar-header-title {
align-content: center;
flex-grow: 1;
flex-shrink: 0;
text-align: center;
margin-right: auto;
}

View File

@ -1,8 +1,15 @@
<div class="container"> <div class="container">
<app-navigation-link-list #navLinkList [navigationLinks]="defaultNavigationLinkPath"></app-navigation-link-list> <app-navigation-link-list #navLinkList [navigationLinks]="defaultNavigationLinkPath"></app-navigation-link-list>
<p>Tets</p>
<div class="schedule-header"> <div class="schedule-header">
<h1>Monday, {{ viewDate | calendarDate:(view + 'ViewTitle'):'en':1 }}</h1> <div class="calendar-control">
<button mat-flat-button color="primary" mwlCalendarPreviousView [view]="'week'" [(viewDate)]="viewDate">Previous</button>
<button mat-flat-button mwlCalendarToday (click)="resetCalendarToToday()">Today</button>
<button mat-flat-button color="primary" mwlCalendarNextView [view]="'week'" [(viewDate)]="viewDate">Next</button>
</div>
<div class="calendar-date-title">
<h1>Monday, {{ viewDate | calendarDate:(view + 'ViewTitle'):'en':1 }}</h1>
</div>
<mat-form-field style="float:right;"> <mat-form-field style="float:right;">
<mat-label>Schedule Strategy</mat-label> <mat-label>Schedule Strategy</mat-label>
<mat-select [(ngModel)]="scheduleStrategy"> <mat-select [(ngModel)]="scheduleStrategy">

View File

@ -80,6 +80,7 @@ export class SchedulerComponent implements OnInit{
} }
ngOnInit(): void { ngOnInit(): void {
this.viewDate = moment().startOf('isoWeek').toDate();
this.activatedRoute.paramMap.subscribe(params => { this.activatedRoute.paramMap.subscribe(params => {
if (params.has('taskgroupID')) { if (params.has('taskgroupID')) {
this.taskgroupID = Number(params.get('taskgroupID')); this.taskgroupID = Number(params.get('taskgroupID'));
@ -131,8 +132,6 @@ export class SchedulerComponent implements OnInit{
protected readonly CalendarView = CalendarView; protected readonly CalendarView = CalendarView;
timeClick(clickedDate: Date) { timeClick(clickedDate: Date) {
console.log(clickedDate)
if(this.basicScheduler != undefined && this.scheduleStrategy === 1) { if(this.basicScheduler != undefined && this.scheduleStrategy === 1) {
this.basicScheduler.setDate(clickedDate) this.basicScheduler.setDate(clickedDate)
} else if(this.advancedScheduler != undefined && this.scheduleStrategy === 3) { } else if(this.advancedScheduler != undefined && this.scheduleStrategy === 3) {
@ -335,4 +334,8 @@ export class SchedulerComponent implements OnInit{
}) })
this.refresh.next(); this.refresh.next();
} }
resetCalendarToToday() {
this.viewDate = moment().startOf('isoWeek').toDate();
}
} }

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