Compare commits

..

696 Commits
master ... dev

Author SHA1 Message Date
70c2ab3f8c Изменил(а) на 'README.md' 2024-06-03 15:24:32 +04:00
9c2fcef028 Изменил(а) на 'README.md' 2024-06-03 15:18:57 +04:00
0a8a5f2df4 Remember me 2024-05-10 21:24:11 +04:00
7713078596 Fix header 2024-05-04 12:35:22 +04:00
e6b4ed9f2c #247 -- Fix paper dates 2024-05-02 19:16:18 +04:00
6dc88fdada #247 -- Fix html 2024-05-02 18:01:23 +04:00
234b043d72 #247 -- Fix jenkinsfile 2024-05-02 14:22:29 +04:00
f522ed9b81 #247 -- Fail test 2024-05-02 14:19:34 +04:00
6f6a8b0eac #247 -- Fix jenkinsfile 2024-05-02 14:18:56 +04:00
eb5ad650c9 #247 -- Fix jenkinsfile 2024-05-02 14:17:44 +04:00
9274dfc3d0 #247 -- Fix test 2024-05-02 14:15:23 +04:00
41b5d42330 #247 -- Add failed test 2024-05-02 13:59:12 +04:00
c6c0db0232 #247 -- Add failed test 2024-05-02 13:32:26 +04:00
6a04b5e037 #247 -- Add test class 2024-05-02 13:27:11 +04:00
a9c617075f #247 -- Fix jenkins file 2024-05-02 13:17:05 +04:00
db4620694c Merge pull request '#247 Remove primefaces dependency' (#248) from 247-restore-mvc into dev
Reviewed-on: #248
2024-05-02 13:10:01 +04:00
70c950cdd7 #247 -- Add jenkinsfile 2024-05-02 13:00:48 +04:00
a9e8336986 #247 -- Fix jpa mapping, update springdoc 2024-05-02 11:53:38 +04:00
23797bae9e #247 -- Update spring version, gradle version 2024-04-26 13:53:40 +04:00
37c1d0db08 Add user ids 2024-04-24 12:15:11 +04:00
b49adee62a Add user ids 2024-04-24 11:59:48 +04:00
c8382c4aea #247 -- Fix html 2024-04-23 17:14:44 +04:00
6e40343d6c #247 -- Remove latex and fix paper list 2024-04-23 17:02:48 +04:00
55a76daa5a #247 -- Restore mvc 2024-03-27 10:14:42 +04:00
5371df1f50 #247 Remove primefaces dependency 2024-03-26 15:08:14 +04:00
Anton Romanov
4ab3637d9c Update README.md 2020-11-02 06:19:31 +00:00
Anton Romanov
893f7ae1f2 add timetable url 2020-09-05 11:53:49 +04:00
Anton Romanov
06f657f5c2 add timetable url 2020-09-05 11:51:29 +04:00
Anton Romanov
b13f331f2c fix urls 2020-05-25 08:44:07 +04:00
Anton Romanov
12973109d3 fix params 2020-04-27 20:13:52 +04:00
Anton Romanov
278e2135bb paper to conference 2020-04-27 20:13:19 +04:00
Anton Romanov
b662437afe add conferences 2020-04-27 18:34:22 +04:00
Anton Romanov
5ae17fbe83 fix select all 2020-04-26 12:34:51 +04:00
Anton Romanov
3f16c8a078 fix user date 2020-04-25 23:51:14 +04:00
Anton Romanov
e3da8c710f fix sout 2020-04-25 23:17:47 +04:00
Anton Romanov
54b992a7f3 try to fix grants kias 2020-04-25 22:46:35 +04:00
Anton Romanov
e20fb468f9 fix 2020-04-25 22:08:28 +04:00
Anton Romanov
1a3ffb7bab fix params and hrefs 2020-04-25 21:42:15 +04:00
Anton Romanov
d29416fb76 fix deploy script 2020-04-25 21:24:58 +04:00
Anton Romanov
37053d853b Merge branch 'jsf' into 'dev'
Jsf

See merge request romanov73/ng-tracker!119
2020-04-25 16:52:19 +00:00
Anton Romanov
b961c8e3dc fix checkstyle 2020-04-25 20:43:48 +04:00
Anton Romanov
3dd6210f42 fix checkstyle 2020-04-25 20:39:44 +04:00
Anton Romanov
5520f19357 show grants 2020-04-25 20:34:35 +04:00
Anton Romanov
2cc3008dc5 complete dashboard 2020-04-25 18:45:12 +04:00
Anton Romanov
708a1a6d32 add dynamic deadlines 2020-04-25 01:30:27 +04:00
Anton Romanov
751195bf96 some layout fixes 2020-04-25 00:48:21 +04:00
Anton Romanov
6adb3fec71 Merge remote-tracking branch 'origin/jsf' into jsf
# Conflicts:
#	src/main/resources/META-INF/resources/admin/user.xhtml
2020-04-24 22:51:45 +04:00
Anton Romanov
ae0a1f3532 fix layout 2020-04-24 18:23:34 +04:00
Anton Romanov
e167a68bc6 add conference button 2020-04-24 13:48:28 +04:00
Anton Romanov
6b717f26d3 fix selection 2020-04-24 13:06:06 +04:00
Anton Romanov
b20ab96b55 fix check unique name of grant 2020-03-28 11:20:29 +04:00
Anton Romanov
2c55293e0e fix check unique name of grant 2020-03-28 10:46:35 +04:00
Anton Romanov
a14735699c fix date parsing 2020-03-28 10:27:47 +04:00
Anton Romanov
9f21850767 move patronymic field 2020-02-24 13:53:33 +04:00
Anton Romanov
abde7f311c fix user page 2020-02-22 17:21:48 +04:00
Anton Romanov
5333258c62 login field 2020-02-22 17:19:35 +04:00
Anton Romanov
2149dfd32f save user 2020-02-22 10:20:59 +04:00
Anton Romanov
34c5e79cbb edit user 2020-02-22 09:03:18 +04:00
Anton Romanov
2110c21be7 fix editor 2020-02-17 23:16:13 +04:00
Anton Romanov
30e06335e9 fix logo 2020-02-17 15:55:16 +04:00
Anton Romanov
c528711431 fix logo 2020-02-17 15:15:31 +04:00
Anton Romanov
0bb9768bda create on submit 2020-02-17 14:40:53 +04:00
Anton Romanov
52d6210875 hide pagination 2020-02-17 14:38:36 +04:00
Anton Romanov
65569732d6 show message on delete 2020-02-17 13:07:57 +04:00
Anton Romanov
1d0c90d932 confirm delete 2020-02-17 13:07:39 +04:00
Anton Romanov
440def2b71 fix layout 2020-02-17 12:56:19 +04:00
Anton Romanov
1460e26127 remove papers 2020-02-17 10:22:26 +04:00
Anton Romanov
1f5cde4b66 relax checkstyle 2020-02-17 00:06:00 +04:00
Anton Romanov
10a99d42cf add delete papers button 2020-02-17 00:02:58 +04:00
Anton Romanov
90c11c6946 show details 2020-02-15 10:16:56 +04:00
Anton Romanov
134f75666c Merge remote-tracking branch 'origin/jsf' into jsf 2020-02-14 09:35:42 +04:00
Anton Romanov
b8d492724c image 2020-02-14 09:35:34 +04:00
Anton Romanov
bc48a486ee quick add paper 2020-02-13 23:44:48 +04:00
Anton Romanov
c36876f7e7 style 2020-02-10 10:45:43 +04:00
Anton Romanov
a136acb0b4 show users 2019-11-28 10:33:36 +04:00
Anton Romanov
7d1f5e9059 fix codestyle 2019-11-28 07:58:38 +04:00
Anton Romanov
4c4c1b2015 fix template 2019-11-28 07:52:42 +04:00
Anton Romanov
6b90d7b0c0 fix messages 2019-11-27 23:36:48 +04:00
Anton Romanov
fa03edf32d fix messages 2019-11-27 23:36:33 +04:00
Anton Romanov
4e1d99392a fix dependency 2019-11-27 21:48:53 +04:00
Anton Romanov
ac55481bc6 add oauth2 google 2019-11-27 19:41:10 +04:00
Anton Romanov
71448364d7 fix login / logout 2019-11-27 13:31:08 +04:00
Anton Romanov
c57914db7c auth 2019-11-27 08:49:01 +04:00
Anton Romanov
ab20b3843f fix font size 2019-11-26 23:09:50 +04:00
Anton Romanov
268a311a87 add filter 2019-11-26 23:02:02 +04:00
Anton Romanov
a67eb23714 send all developer letters to romanov73 2019-11-26 22:36:57 +04:00
Anton Romanov
5ee1f33de1 add papers dashboard 2019-11-26 22:34:24 +04:00
Anton Romanov
107ddb90ac add side commands 2019-11-24 23:22:05 +04:00
Anton Romanov
ac6bd13c6c show label for paper status 2019-11-24 22:54:55 +04:00
Anton Romanov
e7061f4545 fix columns 2019-11-24 20:58:07 +04:00
Anton Romanov
d741bd019a display authors 2019-11-24 20:55:16 +04:00
Anton Romanov
846d94bb46 display paper comment 2019-11-23 10:48:44 +04:00
Anton Romanov
5755cf2f92 save paper 2019-11-23 10:26:05 +04:00
Anton Romanov
7587ff7a51 show paper type 2019-11-23 09:27:15 +04:00
Anton Romanov
6c220355ee display some of paper 2019-11-22 23:47:59 +04:00
Anton Romanov
779f286988 add some menu 2019-11-22 08:38:44 +04:00
Anton Romanov
7753dd104c show paper page 2019-11-21 14:36:25 +04:00
Anton Romanov
48955b9cfd show paper statuses 2019-11-21 11:30:09 +04:00
Anton Romanov
9665653234 show paper list 2019-11-21 10:54:48 +04:00
Anton Romanov
04f545db1c show paper list 2019-11-21 10:18:39 +04:00
Anton Romanov
746f443931 fix primefaces repo 2019-11-21 09:37:09 +04:00
Anton Romanov
1be74769bf fix ports and dependencies 2019-11-21 09:35:50 +04:00
Anton Romanov
2cdec4bcda jsf initial 2019-11-21 08:37:37 +04:00
Anton Romanov
a17dac55e2 fix jdk 2019-11-08 16:36:53 +04:00
Anton Romanov
9e6993f136 Merge branch 'move-to-jdk11' into 'dev'
update versions

Closes #73

See merge request romanov73/ng-tracker!34
2019-11-08 10:48:03 +00:00
Anton Romanov
0647438bfb #73 fix jdk 2019-11-08 14:29:16 +04:00
Anton Romanov
41c4ee7997 fix htmlunit js errors 2019-10-26 11:47:32 +04:00
Anton Romanov
9d3ee273f6 fix spring boot version 2019-06-24 14:53:55 +04:00
Anton Romanov
3267138524 fix warnings 2019-06-22 13:50:15 +04:00
Anton Romanov
df1bf873ff fix warnings 2019-06-22 13:31:53 +04:00
Anton Romanov
24f447aed7 fix tests 2019-06-22 11:58:01 +04:00
Anton Romanov
36c4e52e37 Merge branch 'dev' into move-to-jdk11
# Conflicts:
#	src/main/java/ru/ulstu/conference/service/ConferenceService.java
#	src/main/java/ru/ulstu/grant/model/Grant.java
#	src/main/java/ru/ulstu/grant/service/GrantService.java
#	src/main/java/ru/ulstu/paper/model/Paper.java
#	src/main/java/ru/ulstu/paper/service/PaperService.java
#	src/main/java/ru/ulstu/project/model/Project.java
#	src/main/java/ru/ulstu/project/model/ProjectDto.java
#	src/main/java/ru/ulstu/students/model/Task.java
#	src/main/java/ru/ulstu/students/service/TaskService.java
#	src/main/java/ru/ulstu/timeline/model/Event.java
#	src/main/java/ru/ulstu/timeline/model/EventDto.java
#	src/main/java/ru/ulstu/timeline/service/EventService.java
#	src/main/java/ru/ulstu/user/service/UserService.java
#	src/main/resources/application.properties
#	src/main/resources/db/changelog-master.xml
#	src/main/resources/public/css/conference.css
#	src/main/resources/public/js/conference.js
#	src/main/resources/public/js/tasks.js
#	src/main/resources/templates/conferences/conference.html
#	src/main/resources/templates/grants/grant.html
#	src/main/resources/templates/papers/paper.html
2019-06-21 04:22:06 +04:00
Anton Romanov
529db0442c fix grant dashboard indicators 2019-06-13 14:50:21 +04:00
Anton Romanov
db97892af2 fix grant indicators 2019-06-13 14:48:02 +04:00
Anton Romanov
ff19001f1f fix grant doubling cause date comparison 2019-06-11 22:09:30 +04:00
Anton Romanov
2012a58fc2 show active grants 2019-06-10 12:15:01 +04:00
Anton Romanov
9ba4476f80 restore dependencies 2019-06-08 14:43:08 +04:00
Anton Romanov
098f70ede6 Merge remote-tracking branch 'origin/dev' into dev 2019-06-08 14:37:07 +04:00
Anton Romanov
d84b1fcbdc use HtmlUnit instead of selenium webdriver for grants loading 2019-06-08 14:36:12 +04:00
Anton Romanov
b44bbaec75 Merge branch '95-block-user' into 'dev'
Resolve "Блокировка пользователя"

Closes #95

See merge request romanov73/ng-tracker!110
2019-06-08 08:29:44 +00:00
Anton Romanov
436c15e727 Merge branch '104-module-tests-grant' into 'dev'
Resolve "Реализовать модульные тесты"

See merge request romanov73/ng-tracker!115
2019-06-08 06:02:09 +00:00
T-Midnight
e4f5bede2a #104 add 3 more tests 2019-06-07 22:39:20 +04:00
T-Midnight
888fecf687 #104 add unit tests 2019-06-07 20:55:59 +04:00
T-Midnight
51ed732ae8 #104 fix web element in integration test 2019-06-07 20:54:38 +04:00
Anton Romanov
18bb0b85ac sout driver path 2019-06-07 15:53:09 +04:00
Anton Romanov
615c70d12a sout driver path 2019-06-07 15:35:15 +04:00
Artem.Arefev
96d166d031 #95 block user html 2019-06-07 12:23:03 +04:00
Artem.Arefev
fb23f182de #95 merged with dev 2019-06-07 11:39:44 +04:00
Anton Romanov
f8c1e52ca4 add kias loader to rest 2019-06-07 09:48:07 +04:00
Anton Romanov
59e52aaf4a different drivers 2019-06-06 17:07:25 +04:00
Anton Romanov
dc467ec72c Merge branch '112-ping-stats' into 'dev'
#112 fix ping authors in grant

Closes #112

See merge request romanov73/ng-tracker!114
2019-06-05 20:28:47 +00:00
Artem.Arefev
019ac6e0ad #112 fix ping authors in grant 2019-06-06 00:21:19 +04:00
Anton Romanov
1ccec83390 Merge branch '112-ping-stats' into 'dev'
Resolve "Сводка по ping активностей"

Closes #112

See merge request romanov73/ng-tracker!109
2019-06-05 20:04:44 +00:00
Artem.Arefev
4104844b1e #95 merged with dev 2019-06-06 00:01:03 +04:00
Artem.Arefev
c0afabc37c #112 merged with dev 2019-06-05 23:57:33 +04:00
Anton Romanov
624573a47a Merge branch '103-integr-tests-grant' into 'dev'
Resolve "Реализовать интеграционные автотесты для проверки модулей"

See merge request romanov73/ng-tracker!106
2019-06-05 19:46:59 +00:00
T-Midnight
fddc15af5a #103 add tests for authors and description 2019-06-05 23:14:52 +04:00
Artem.Arefev
bdb8fd8ce4 Merge remote-tracking branch 'origin/dev' into 112-ping-stats 2019-06-05 18:12:38 +04:00
T-Midnight
acd58005de #103 merge with 44 2019-06-05 15:52:29 +04:00
T-Midnight
1ff38fc80e #103 merge with dev 2019-06-05 09:36:29 +04:00
T-Midnight
c77702704f #103 merge with dev 2019-06-05 09:34:51 +04:00
Anton Romanov
44824e53b2 Merge branch '103-paper-integr-tests' into 'dev'
Resolve "Реализовать интеграционные автотесты для проверки модулей"

See merge request romanov73/ng-tracker!111
2019-06-05 04:57:33 +00:00
Anton Romanov
bacd3827e3 Merge branch '101-projecgt-timeline' into 'dev'
Resolve "Генерация таймлайна для проекта"

Closes #101

See merge request romanov73/ng-tracker!85
2019-06-05 04:55:15 +00:00
T-Midnight
0cd8003dd7 #103 add tests for deadline 2019-06-04 16:26:42 +04:00
Васин Антон
bdff81d25e #101 tests edited 2019-06-03 20:42:49 +03:00
Васин Антон
482964fe53 #101 EventService edited 2019-06-03 20:21:46 +03:00
Васин Антон
dc52968ddf Merge branch '101-projecgt-timeline' of gitlab.com:romanov73/ng-tracker into 101-projecgt-timeline 2019-06-03 14:40:09 +03:00
Artem.Arefev
22abf6a27d #95 blocking user 2019-06-03 02:11:35 +04:00
Artem.Arefev
abea3c7dad #112 ping model changed 2019-06-02 21:53:51 +04:00
Семенова Мария
23d4e5602f #103 integration auto tests 2019-06-01 23:16:39 +04:00
a.vasin
bde4ac5f1c #101 event service edited 2019-06-01 13:25:12 +04:00
Artem.Arefev
3898dcf1c1 #112 changed mapping 2019-06-01 12:57:20 +04:00
Artem.Arefev
2d230afa35 #112changed mapping 2019-06-01 12:56:37 +04:00
a.vasin
db3252d822 #101 event service edited 2019-06-01 12:55:13 +04:00
a.vasin
e6dc2abdd9 #101 event service edited 2019-06-01 12:23:52 +04:00
a.vasin
ae8dc58a9d #101 event service edited 2019-06-01 12:16:59 +04:00
a.vasin
38478835fb #101 event service edited 2019-06-01 12:03:42 +04:00
a.vasin
7edb9d2aa3 #101 event service edited 2019-06-01 11:56:38 +04:00
a.vasin
961a6a318e #101 event service edited 2019-06-01 11:51:01 +04:00
a.vasin
267bd5b0f3 #101 event service edited 2019-06-01 11:44:41 +04:00
a.vasin
a5ac2bcbc2 Merge branch 'dev' of gitlab.com:romanov73/ng-tracker into 101-projecgt-timeline 2019-06-01 09:44:46 +04:00
a.vasin
291f4e1e33 #101 db edited 2019-06-01 09:44:25 +04:00
Artem.Arefev
53307c6add #95 init 2019-05-31 22:42:59 +04:00
Artem.Arefev
a405267092 merged with dev 2019-05-31 22:42:19 +04:00
Васин Антон
1224cc7a23 Merge branch 'dev' of gitlab.com:romanov73/ng-tracker into 101-projecgt-timeline 2019-05-31 16:04:01 +03:00
Anton Romanov
a878f8c22c fix remove older events 2019-05-31 09:06:21 +04:00
Anton Romanov
d2ce6d604e fix merging collection 2019-05-31 08:46:21 +04:00
Anton Romanov
b4b7b9087e fix npe 2019-05-31 08:12:57 +04:00
a.vasin
a7b48e1534 #101 project tests 2019-05-31 02:23:15 +04:00
a.vasin
9388302a47 #101 project tests 2019-05-31 01:08:40 +04:00
Artem.Arefev
e680aa30c4 #112 ping activity 2019-05-31 00:33:21 +04:00
a.vasin
4498b71259 #101 project tests 2019-05-30 09:53:27 +04:00
a.vasin
632c6299b7 #101 files attach modified 2019-05-30 00:08:13 +04:00
a.vasin
9013d79228 #101 grant attach 2019-05-29 23:40:30 +04:00
a.vasin
192adbfa0b #101 no projects message 2019-05-29 18:40:14 +04:00
a.vasin
eb30d07d10 #101 project deadlines on timeline 2019-05-29 18:27:34 +04:00
a.vasin
eceb8ec528 #101 project model edited 2019-05-29 17:52:15 +04:00
Anton Romanov
330ffc4df1 Merge branch '98-project-tasks' into 'dev'
Resolve "Задачи проекта"

Closes #98

See merge request romanov73/ng-tracker!74
2019-05-29 04:56:30 +00:00
Васин Антон
77ce908d58 #98 deadline edited 2019-05-28 16:55:08 +03:00
Васин Антон
8ffafd6693 #98 deadline imports edited 2019-05-28 16:46:12 +03:00
Васин Антон
e967e2bfee Merge branch 'dev' of https://gitlab.com/romanov73/ng-tracker into 98-project-tasks 2019-05-28 16:17:37 +03:00
Васин Антон
c25392337a #98 project deadlines edited 2019-05-28 16:16:41 +03:00
a.vasin
3b0a2dd964 #98 executors list added 2019-05-28 11:12:27 +04:00
a.vasin
8d1e410e83 Merge branch 'dev' of gitlab.com:romanov73/ng-tracker into 98-project-tasks 2019-05-28 00:41:15 +04:00
a.vasin
eb87c6d52f #98 project statuses edited 2019-05-28 00:40:36 +04:00
Artem.Arefev
a35bcfce1b #112 merged with dev 2019-05-27 22:47:01 +04:00
Anton Romanov
6258e7b6bf Merge branch '91-users-info' into 'dev'
Resolve "Сводка по пользователям"

Closes #91

See merge request romanov73/ng-tracker!99
2019-05-27 18:03:41 +00:00
Artem.Arefev
c4b35ddf6a #91 merged with dev 2019-05-27 21:53:55 +04:00
Васин Антон
7388e12e3f #98 edited project executors 2019-05-27 18:19:31 +03:00
Васин Антон
4bb4fd6bca #98 changelog edited 2019-05-27 09:35:58 +03:00
Васин Антон
4eeb79ab80 #98 changelog edited 2019-05-27 09:19:52 +03:00
Anton Romanov
336a16ff73 some refactor 2019-05-27 09:14:24 +04:00
Artem.Arefev
0e7fdac980 Merge remote-tracking branch 'origin/dev' into 91-users-info 2019-05-27 00:42:54 +04:00
Artem.Arefev
482e2b3595 #112 base ping activities 2019-05-27 00:42:43 +04:00
Anton Romanov
2b911017b1 Merge branch '120-kias' into 'dev'
Resolve "Загрузка грантов в сайта kias"

Closes #120

See merge request romanov73/ng-tracker!94
2019-05-25 17:40:59 +00:00
Anton Romanov
0cd3055176 #120 disable tests 2019-05-25 21:33:06 +04:00
Anton Romanov
280c39dae4 #120 fix variable 2019-05-25 21:32:20 +04:00
Anton Romanov
828d320e0f #120 try to run test in docker 2019-05-25 21:16:26 +04:00
Anton Romanov
678397e970 #120 test classes refactor 2019-05-25 21:15:54 +04:00
Anton Romanov
916bbae414 #120 add debug email 2019-05-25 21:15:21 +04:00
Anton Romanov
477a9fd6ff #120 move to service 2019-05-25 15:48:32 +04:00
Anton Romanov
59d6edb818 #120 refactor 2019-05-25 15:42:08 +04:00
Artem.Arefev
f4479c2ab7 #91 fixed app properties 2019-05-25 14:11:57 +04:00
Artem.Arefev
193b2b3a32 #91 using RestTemplate & show error on timetable loading exception 2019-05-25 14:03:43 +04:00
Anton Romanov
837a9f465c #120 merge dev 2019-05-25 12:39:44 +04:00
Anton Romanov
eba3592410 Merge branch '127-paper-references' into 'dev'
Resolve "Ведение списка литературы статей"

Closes #127

See merge request romanov73/ng-tracker!108
2019-05-24 19:43:27 +00:00
Семенова Мария
22195813ae #127 fixes 2019-05-24 16:15:38 +04:00
Семенова Мария
43e7b9fe1f Merge branch 'dev' into 127-paper-references 2019-05-24 16:14:02 +04:00
Anton Romanov
308da4113d fix week number calculation 2019-05-24 13:26:02 +04:00
Anton Romanov
c9ecae9842 Merge branch '104-students-mod-tests' into 'dev'
Resolve "Реализовать модульные тесты"

See merge request romanov73/ng-tracker!107
2019-05-24 06:37:03 +00:00
Anton Romanov
d4364b9767 Merge branch '89-restore-password' into 'dev'
Resolve "Восстановление пароля"

Closes #89

See merge request romanov73/ng-tracker!101
2019-05-24 06:34:18 +00:00
Artem.Arefev
505a054cc8 Merge remote-tracking branch 'origin/dev' into 91-users-info 2019-05-24 01:53:54 +04:00
Artem.Arefev
8bb9e3a844 #89 jquery 2019-05-24 01:52:50 +04:00
Artem.Arefev
661da17f73 Merge remote-tracking branch 'origin/dev' into 89-restore-password 2019-05-24 01:36:01 +04:00
Семенова Мария
01bcac2680 #127 allow nullable year 2019-05-24 00:26:38 +04:00
Семенова Мария
421ed635e8 Merge branch 'dev' into 127-paper-references 2019-05-24 00:18:07 +04:00
Семенова Мария
24a1276005 #127 autocomplete 2019-05-24 00:14:46 +04:00
Семенова Мария
512a805e8c #127 references formatting 2019-05-23 17:26:22 +04:00
ASH
ab17b9f152 #104 mod tests period task 2019-05-23 16:45:09 +04:00
Anton Romanov
181086c9db #120 disable start browser on run application 2019-05-23 16:36:48 +04:00
ASH
82e454a50b #104 mod tests generate task 2019-05-23 16:17:04 +04:00
Anton Romanov
c303d65c8d #120 move to services 2019-05-23 16:02:44 +04:00
Семенова Мария
7c1b124c94 #127 references tab, crud 2019-05-23 15:48:46 +04:00
Семенова Мария
29cfadef02 #127 reference model, schema 2019-05-23 15:02:55 +04:00
ASH
ef521123dd #104 mod tests check repeatings 2019-05-23 14:31:34 +04:00
Anton Romanov
82ae42f7fc Merge branch '125-bug-date-conf' into 'dev'
Resolve "Bug: ошибка при попытке сохранить конференцию с невыбранными датами"

Closes #125

See merge request romanov73/ng-tracker!103
2019-05-23 09:56:21 +00:00
Anton Romanov
af09938e66 Merge branch '103-students-integ-tests' into 'dev'
Resolve "Реализовать интеграционные автотесты для проверки модулей"

See merge request romanov73/ng-tracker!100
2019-05-23 09:50:30 +00:00
Anton Romanov
1c8359f900 #103 modify files permissions 2019-05-23 13:54:44 +04:00
T-Midnight
47131f1fb7 #103 add tests for papers 2019-05-23 13:43:18 +04:00
ASH
284a3f51e9 #104 mod tests filter and create tasks 2019-05-23 12:07:34 +04:00
ASH
bd24525315 #103 integration tests 2019-05-23 00:15:03 +04:00
T-Midnight
3e9bbb3584 #103 create tests for create, update and delete functions 2019-05-22 23:15:04 +04:00
T-Midnight
16885cc94f #103 update overriding method 2019-05-22 23:12:30 +04:00
T-Midnight
b1c090b0ea #103 add selenium-support library 2019-05-22 23:11:06 +04:00
T-Midnight
ecda92326b #103 create blank classes 2019-05-22 16:04:51 +04:00
T-Midnight
457f1da985 #120 fix checkRun and checkStyle 2019-05-22 15:45:23 +04:00
T-Midnight
5f214620bf #120 use loading from kias 2019-05-22 15:16:20 +04:00
T-Midnight
c21739bfc6 #120 parse kias page 2019-05-22 15:12:45 +04:00
T-Midnight
bab621677e #120 add methods for checking unique title and date of grant 2019-05-22 15:10:51 +04:00
Nightblade73
8b52518c4a #125 check method 2019-05-21 15:53:42 +04:00
Artem.Arefev
d7c4e6b222 #91 base users dashboard 2019-05-21 02:09:07 +04:00
T-Midnight
bb9f412480 #120 check unique grant name 2019-05-20 20:49:03 +04:00
T-Midnight
c0e66e81a2 #120 drop unnecessary table column 2019-05-20 20:47:10 +04:00
T-Midnight
1823c1ba50 #120 create kias page 2019-05-20 18:37:24 +04:00
Artem.Arefev
e468646cd6 89 removed getCurrentUser 2019-05-19 00:47:49 +04:00
Artem.Arefev
90799356ab 89 password reset 2019-05-19 00:42:24 +04:00
Anton Romanov
59bc0dbd34 disable dev mode on demo 2019-05-18 13:13:09 +04:00
Anton Romanov
d076f35ff7 fix user timetable url 2019-05-18 13:00:02 +04:00
Anton Romanov
56f083e757 Merge branch '87-inviting-user' into 'dev'
Resolve "Приглашение нового пользователя"

Closes #87

See merge request romanov73/ng-tracker!95
2019-05-17 10:36:07 +00:00
Artem.Arefev
532e007b0b 87 merged with dev 2019-05-17 14:31:08 +04:00
Anton Romanov
3dbf635fb6 Merge branch '88-change-password' into 'dev'
Resolve "Смена пароля"

Closes #88

See merge request romanov73/ng-tracker!96
2019-05-17 10:23:24 +00:00
Artem.Arefev
3da374326b 88 replacing all alerts in users.js 2019-05-17 14:16:41 +04:00
Васин Антон
4213524dbd Merge branch 'dev' into 98-project-tasks 2019-05-17 11:40:21 +03:00
Васин Антон
f960d4de1b #98 deadline model edited 2019-05-17 11:30:26 +03:00
Artem.Arefev
740adc5318 88 js using showFeedbackMessage 2019-05-17 12:23:45 +04:00
Artem.Arefev
b8281c527a 87 removed unused imports 2019-05-17 12:20:55 +04:00
Artem.Arefev
7163937a53 87 using showFeedBackMessage 2019-05-17 12:20:08 +04:00
Васин Антон
097f7827b0 #98 db edited 2019-05-17 10:30:34 +03:00
Anton Romanov
83aba158b6 Merge branch '104-module-test-conf' into 'dev'
Resolve "Реализовать модульные тесты"

See merge request romanov73/ng-tracker!92
2019-05-17 07:27:21 +00:00
Васин Антон
50314246f5 Merge branch 'dev' of https://gitlab.com/romanov73/ng-tracker into dev 2019-05-17 10:10:38 +03:00
Artem.Arefev
76d3adb464 87 small fix whitespace 2019-05-17 08:58:27 +04:00
Artem.Arefev
64357c2508 88 fixed changePassword request data 2019-05-17 04:35:33 +04:00
Artem.Arefev
6a62e61caf 87 error handling + ajax + rest 2019-05-17 04:34:03 +04:00
Artem.Arefev
b9748905d1 Merge branch '88-change-password' into 87-inviting-user 2019-05-17 03:59:28 +04:00
Artem.Arefev
fbd618a6d0 88 changed error text to russian 2019-05-17 03:59:09 +04:00
Artem.Arefev
052e4a1aef 88 rest changePassword + ajax 2019-05-17 03:55:22 +04:00
Artem.Arefev
4fc8bc3717 Merge branch '87-inviting-user' into 88-change-password 2019-05-17 02:01:56 +04:00
Artem.Arefev
728fa42972 87 error handling 2019-05-17 02:01:26 +04:00
Nightblade73
dc34c7bfb7 #104 fixed conference-row style 2019-05-16 18:07:18 +04:00
Nightblade73
5263393379 #104 remove chart example from dashboard 2019-05-16 17:55:34 +04:00
Nightblade73
80de18d3ee #104 create fixed, remove update 2019-05-16 16:31:10 +04:00
Nightblade73
bde9cb51fb #104 some methods fixed 2019-05-16 15:55:29 +04:00
Nightblade73
c0937d721a #104 removePaper, addPaper, takePart fixed 2019-05-16 15:35:32 +04:00
Nightblade73
ce7b4c9c7a #104 addDeadline, removeDeadline fixed 2019-05-16 13:33:26 +04:00
Anton Romanov
19a6b45cf9 Merge branch '79-students-tags-generation' into 'dev'
Resolve "Генерация периодических задач по тегам"

Closes #79

See merge request romanov73/ng-tracker!80
2019-05-16 03:30:46 +00:00
Artem.Arefev
c47d4f8a05 #88 removed unused imports 2019-05-16 01:17:04 +04:00
Artem.Arefev
33f62c04e7 Merge branch '87-inviting-user' into 88-change-password 2019-05-16 01:03:14 +04:00
Artem.Arefev
d50673f5fa 87-inviting-user small fix in mail template, and changed default user name 2019-05-16 01:01:31 +04:00
Artem.Arefev
f8f501b8ff 88-change-password base 2019-05-16 00:38:53 +04:00
ASH
cd1caa559e Merge branch 'dev' into 79-students-tags-generation
# Conflicts:
#	src/main/java/ru/ulstu/students/service/TaskService.java
2019-05-16 00:14:05 +04:00
ASH
bc9cca62d6 #79 refactoring 2019-05-15 23:47:05 +04:00
Artem.Arefev
ca3159a66b Merge branch '87-inviting-user' into 88-change-password 2019-05-15 22:35:30 +04:00
Artem.Arefev
3226cc3971 87 fixed UserControllerV2 logger 2019-05-15 22:27:06 +04:00
Artem.Arefev
48a18a3a57 87 fixed imports 2019-05-15 22:24:19 +04:00
Artem.Arefev
d88f67ce00 87 transactional inviting 2019-05-15 03:08:21 +04:00
Artem.Arefev
11ef644e5e 88 inviting user base 2019-05-15 02:48:44 +04:00
Nightblade73
1e06edfcc0 Merge remote-tracking branch 'remotes/origin/dev' into 104-module-test-conf
# Conflicts:
#	src/main/java/ru/ulstu/conference/service/ConferenceService.java
2019-05-15 01:28:08 +04:00
Nightblade73
7952787229 #104 add new tests, fixes 2019-05-15 01:14:02 +04:00
Nightblade73
00c5d5f755 #104 test refactoring 2019-05-15 00:54:30 +04:00
Artem.Arefev
3d02f551cc Merge branch 'lk_v2' into 87-inviting-user 2019-05-15 00:53:52 +04:00
Artem.Arefev
95fc9da47d lk base, created from dev 2019-05-15 00:49:54 +04:00
Nightblade73
11cab955b4 #104 test create 2019-05-14 18:51:03 +04:00
Nightblade73
c88c77cd7d #104 test find one dto 2019-05-14 18:20:01 +04:00
Nightblade73
1c5c05b5e4 #104 test take part 2019-05-14 18:01:50 +04:00
Nightblade73
e6cb991463 #104 test is member 2019-05-14 17:54:18 +04:00
Nightblade73
a8d987b01f #104 test copy from dto method 2019-05-14 17:49:22 +04:00
Nightblade73
3a9fde3404 #104 setUp fields 2019-05-14 16:20:19 +04:00
Nightblade73
9da5fd8a7a #104 shock, the first unit test works 2019-05-14 00:02:30 +04:00
Anton Romanov
51851baa48 Merge branch '103-autotest-conf' into 'dev'
Resolve "Реализовать интеграционные автотесты для проверки модулей"

See merge request romanov73/ng-tracker!90
2019-05-13 19:46:29 +00:00
Anton Romanov
10a9bd7a28 Merge branch '111-unique-name-control-conf' into 'dev'
Resolve "Контроль уникальности названия"

See merge request romanov73/ng-tracker!86
2019-05-13 19:20:44 +00:00
Nightblade73
58a8495835 Merge remote-tracking branch 'remotes/origin/dev' into 103-autotest-conf
# Conflicts:
#	src/main/java/ru/ulstu/timeline/service/EventService.java
2019-05-13 20:27:52 +04:00
Nightblade73
ab59cb524e #103 fix code style 2019-05-13 20:26:13 +04:00
Nightblade73
1f8722e3ff #103 code refactoring 2019-05-13 20:13:53 +04:00
Nightblade73
6044d6f8e3 #111 save method refactor 2019-05-13 19:08:21 +04:00
Anton Romanov
a3afdeb988 Merge branch '123-student-task-timeline' into 'dev'
Resolve "Добавление таймлайна для дедлайнов задач"

Closes #123

See merge request romanov73/ng-tracker!91
2019-05-13 07:15:57 +00:00
Anton Romanov
aaa21d591d Merge branch '121-reduce-paper-title' into 'dev'
Resolve "Сокращение названий статей в прикреплении"

Closes #121

See merge request romanov73/ng-tracker!89
2019-05-13 06:54:49 +00:00
T-Midnight
f6830d499b #121 update view 2019-05-12 15:31:50 +04:00
T-Midnight
99ec7af319 #121 reduce paper title 2019-05-12 15:30:09 +04:00
T-Midnight
e1907d3169 #121 change Paper to PaperDto in attaching papers 2019-05-12 15:28:47 +04:00
Nightblade73
451e7e5d04 #103 fix code style 2019-05-12 13:50:46 +04:00
Nightblade73
5cbbb6c319 #103 fix code style 2019-05-12 13:49:49 +04:00
Nightblade73
70062992ae #103 clear code 2019-05-12 13:45:17 +04:00
Nightblade73
fe53c86136 #103 fixed delete conf test 2019-05-12 13:42:50 +04:00
ASH
5b4180e685 #123 fixing layout 2019-05-12 11:04:43 +04:00
ASH
a11e10dec4 #123 adding task timeline 2019-05-12 01:00:26 +04:00
Nightblade73
d846192046 #111 fixes 2019-05-12 00:28:03 +04:00
ASH
7798508d4f Merge branch 'dev' into 79-students-tags-generation
# Conflicts:
#	src/main/resources/db/changelog-20190505_000000-schema.xml
#	src/main/resources/db/changelog-master.xml
2019-05-11 23:26:21 +04:00
ASH
c59bb45c70 #79 fixing codestyle 2019-05-11 23:06:30 +04:00
ASH
0de34c89fe #79 fixing planner and year generation 2019-05-11 22:58:57 +04:00
Nightblade73
b2e8a43cee #103 delete conf test 2019-05-11 00:51:57 +04:00
Nightblade73
3f32a61ed2 Merge remote-tracking branch 'origin/103-autotest-conf' into 103-autotest-conf
# Conflicts:
#	src/test/java/IndexConferenceTest.java
2019-05-10 23:38:54 +04:00
Nightblade73
6edcf8f594 #103 add sort and filter test, fixed delete conference, if it has fk with event 2019-05-10 23:36:07 +04:00
Nightblade73
4686406954 #103 add undock article 2019-05-10 21:15:49 +04:00
Nightblade73
4e4e7ae194 #103 add paper transition 2019-05-10 20:54:43 +04:00
Nightblade73
cad8682088 #103 add adding article 2019-05-10 20:07:55 +04:00
Nightblade73
d9a4224317 #103 add attach article 2019-05-10 19:15:22 +04:00
Nightblade73
7b4318a3b5 #103 add delete deadline 2019-05-10 17:40:24 +04:00
Nightblade73
0cb7b05c25 #103 add check take part 2019-05-10 17:21:36 +04:00
Nightblade73
253f4b4aad #103 add check new deadline 2019-05-10 17:03:47 +04:00
Nightblade73
1ad66d6fb1 #103 change name method test 2019-05-10 15:54:12 +04:00
Nightblade73
961fdf9397 #70 added conference class, added create method test 2019-05-10 15:07:47 +04:00
Anton Romanov
ff7f535980 Merge branch '119-notification-grants' into 'dev'
Resolve "Реализовать уведомления на почту"

Closes #119

See merge request romanov73/ng-tracker!84
2019-05-09 04:18:55 +00:00
T-Midnight
77e2ad0651 #119 add send notification functions 2019-05-09 01:24:55 +04:00
T-Midnight
74a8dcbd8a #119 add leader changed notification 2019-05-09 01:23:17 +04:00
T-Midnight
4262446aef #119 create all mail templates 2019-05-09 01:21:56 +04:00
T-Midnight
b640dea99a #119 create scheduler 2019-05-09 00:45:54 +04:00
T-Midnight
2d9fd05060 #119 create grantCreateNotification mail template 2019-05-08 23:32:37 +04:00
Nightblade73
b57142e28f #70 added unique name control 2019-05-08 17:08:37 +04:00
T-Midnight
e3ad5ba510 Merge remote-tracking branch 'remotes/origin/dev' into 119-notification-grants 2019-05-08 16:22:39 +04:00
Anton Romanov
09aa3d0084 Merge branch '122-bug-leader-grants' into 'dev'
Resolve "Bug: не отображается cписок грантов"

Closes #122

See merge request romanov73/ng-tracker!88
2019-05-08 09:25:37 +00:00
Anton Romanov
662847698e Merge branch '109-paper-attach-control' into 'dev'
Resolve "Контроль прикрепления статей"

Closes #109

See merge request romanov73/ng-tracker!87
2019-05-08 09:10:03 +00:00
Семенова Мария
2fba252df0 #109 show other paper attachs 2019-05-07 23:53:10 +04:00
T-Midnight
7ffe04f1db #122 move to right directory 2019-05-07 22:47:27 +04:00
T-Midnight
d244437858 #122 fix bug 2019-05-07 22:35:44 +04:00
T-Midnight
934d194df1 #119 gelete unnecessary column 2019-05-07 22:15:49 +04:00
Семенова Мария
1e07c5424d #109 only one conference for paper 2019-05-07 21:35:50 +04:00
Семенова Мария
dffd839905 #109 only uncompleted for grant 2019-05-07 20:26:49 +04:00
Васин Антон
279cc0e18a #101 project model edited 2019-05-07 14:00:24 +03:00
Васин Антон
b1e101c940 #101 db event edited 2019-05-07 13:34:00 +03:00
T-Midnight
2dae39a100 #119 create grants notification service 2019-05-06 23:57:16 +04:00
Васин Антон
241c489b21 #98 deadline edited 2019-05-06 22:10:40 +03:00
Васин Антон
52ae197f34 Merge branch 'dev' into 98-project-tasks 2019-05-06 21:57:30 +03:00
Васин Антон
4025aa67ca #98 project completion added 2019-05-06 21:51:58 +03:00
ASH
65dea9bce2 #79 adding task planer generation 2019-05-06 22:39:08 +04:00
Васин Антон
4bab980f62 #98 deadline model and service edited 2019-05-06 20:17:10 +03:00
Васин Антон
ee55e08fee #98 project tasks deadline edited 2019-05-06 17:43:20 +03:00
Васин Антон
82ab40a608 Merge branch 'dev' of https://gitlab.com/romanov73/ng-tracker into dev 2019-05-06 13:04:13 +03:00
Anton Romanov
2dff183662 Merge branch '32-timeline-grants' into 'dev'
Resolve "Создать страницу таймлайна дедлайнов"

Closes #32

See merge request romanov73/ng-tracker!83
2019-05-06 07:06:04 +00:00
T-Midnight
da382b659a #32 add deadlines on timeline page 2019-05-06 00:32:28 +04:00
T-Midnight
114f6769ac #32 create changelog 2019-05-05 23:54:02 +04:00
T-Midnight
beb334f2fa #32 add variable "events" 2019-05-04 23:59:03 +04:00
Anton Romanov
68737b976f Merge branch '117-filter-users' into 'dev'
Resolve "Фильтрация участников гранта по двум новым параметрам"

Closes #117

See merge request romanov73/ng-tracker!77
2019-05-03 05:58:19 +00:00
Anton Romanov
6eed8591b4 Merge branch '70-notification-conf' into 'dev'
Resolve "Оповещения о дедлайнах конференции"

Closes #70

See merge request romanov73/ng-tracker!76
2019-05-03 05:56:33 +00:00
T-Midnight
74d43dcd0d #117 resolve last discussion 2019-05-02 22:49:58 +04:00
T-Midnight
0955388f27 #117 fix port 2019-05-02 22:00:53 +04:00
T-Midnight
de625923e9 #117 resolve discussions v.2 2019-05-02 21:56:54 +04:00
T-Midnight
b334b5d70e #117 resolve discussions 2019-05-02 21:42:06 +04:00
T-Midnight
8b333ab3a6 Merge branch '38-attach-file-grants' into 117-filter-users 2019-05-02 21:29:20 +04:00
Nightblade73
6350e1c0d6 #70 add hashCode for deadline 2019-05-02 14:51:22 +04:00
Nightblade73
6820c617f3 #70 remove conflicts 2019-05-02 14:42:08 +04:00
Nightblade73
60bdd9d233 #70 fixes 2019-05-02 14:35:40 +04:00
T-Midnight
c8cfde67a9 Merge remote-tracking branch 'remotes/origin/dev' into 38-attach-file-grants 2019-05-01 00:21:56 +04:00
Anton Romanov
a6f2177179 Merge branch '114-bug-projects-list' into 'dev'
Resolve "Bug: не отображается список проектов"

Closes #114

See merge request romanov73/ng-tracker!82
2019-04-30 20:12:51 +00:00
T-Midnight
1f6d15b74b #38 create changelogs 2019-04-30 23:55:31 +04:00
T-Midnight
a69a257f09 #38 add styles 2019-04-30 23:43:47 +04:00
T-Midnight
6442a67ff1 #38 update view 2019-04-30 23:41:51 +04:00
T-Midnight
2ebd61016d #38 add variable "files" 2019-04-30 23:40:40 +04:00
ASH
7ce8b20841 #79 fixing bug 2019-04-30 22:05:57 +04:00
Nightblade73
0e062f1337 #70 fast fix 2019-04-30 11:41:36 +04:00
Nightblade73
9edcf35338 #70 added ping notification 2019-04-30 10:43:36 +04:00
Васин Антон
5c677a975c #114 changelog edited 2019-04-30 01:01:30 +03:00
Васин Антон
83f3f7d6b9 Merge branch 'dev' of https://gitlab.com/romanov73/ng-tracker into dev 2019-04-30 00:32:02 +03:00
ASH
b4c11a7f90 #79 year generation 2019-04-28 23:58:35 +04:00
Nightblade73
0e8752e460 #70 style fixes 2019-04-27 20:34:49 +04:00
Nightblade73
e178cd1639 #70 added checking empty fields of deadline, fix bug on EventDto 2019-04-27 09:45:47 +04:00
T-Midnight
9cf002ad95 Merge remote-tracking branch 'remotes/origin/dev' into 117-filter-users 2019-04-26 15:22:04 +04:00
T-Midnight
39f3c69479 #117 add scopus papers filter 2019-04-26 15:16:04 +04:00
Nightblade73
dbcdb96dbf #70 added event method, don't work, because trying to find null entity 2019-04-26 15:12:34 +04:00
Anton Romanov
a352f561fa Merge branch '118-bug-create-paper-notification' into 'dev'
Resolve "Bug: не отправляется сообщение о создании новой статьи"

Closes #118

See merge request romanov73/ng-tracker!79
2019-04-26 07:57:36 +00:00
Васин Антон
b2d4d52675 Merge remote-tracking branch 'origin/dev' into dev 2019-04-26 10:01:21 +03:00
Семенова Мария
a8fbf98d85 #118 check if next deadline present 2019-04-26 10:37:50 +04:00
Anton Romanov
4d2d7fa113 fix lambda 2019-04-26 09:47:41 +04:00
Anton Romanov
9393fbe326 fix deprecated imports 2019-04-26 09:46:38 +04:00
Nightblade73
51877023d1 #70 added new column to event 2019-04-26 09:28:20 +04:00
Anton Romanov
1fe2f5469b Merge branch '108-references-formatting' into 'dev'
Resolve "Форматирование списка литературы"

Closes #108

See merge request romanov73/ng-tracker!78
2019-04-26 04:24:09 +00:00
T-Midnight
51e121ae24 #117 add BAK papers filter 2019-04-26 00:29:20 +04:00
Семенова Мария
8f3e3fd9a7 #108 add formatting methods 2019-04-26 00:00:01 +04:00
Семенова Мария
71ec7bb726 #108 add reference dto 2019-04-25 22:08:24 +04:00
Nightblade73
34925b81ff #70 added schedule for deadline of conference 2019-04-25 21:17:48 +04:00
Nightblade73
16e9bf1fb5 #70 added update notification for all participants 2019-04-25 19:15:19 +04:00
Nightblade73
c489ebbf91 #70 added create notification for all users about new conference 2019-04-25 17:12:39 +04:00
Anton Romanov
88ec35faa0 Merge branch '68-ping-conf' into 'dev'
Resolve "Ping конференции в списке конференций"

Closes #68

See merge request romanov73/ng-tracker!69
2019-04-25 10:00:34 +00:00
Anton Romanov
fc94ea1f26 Merge branch '116-delete-deadline' into 'dev'
Resolve "Удаление дедлайна"

Closes #116

See merge request romanov73/ng-tracker!75
2019-04-25 09:48:38 +00:00
T-Midnight
7853496048 #116 add style for delete icon 2019-04-25 13:26:40 +04:00
T-Midnight
2bb5189fff #116 update view 2019-04-25 13:25:56 +04:00
T-Midnight
4fa0c14ae6 #116 add removeDeadline method 2019-04-25 13:25:32 +04:00
T-Midnight
7c5a0826c5 #116 add new variable 2019-04-25 13:24:36 +04:00
T-Midnight
8ced83ad2b #116 delete annotation 2019-04-25 13:23:36 +04:00
Nightblade73
bc73265109 Merge remote-tracking branch 'remotes/origin/dev' into 68-ping-conf
# Conflicts:
#	src/main/java/ru/ulstu/conference/repository/ConferenceRepository.java
#	src/main/java/ru/ulstu/conference/service/ConferenceService.java
#	src/main/resources/db/changelog-master.xml
2019-04-24 22:41:48 +04:00
Nightblade73
b77619777e #68 added dashboard-card styles depending on the conference.ping count 2019-04-24 22:34:56 +04:00
Nightblade73
70d260c34b #68 ping but style 2019-04-24 21:52:13 +04:00
Nightblade73
d4b514a9b0 #68 added ping in db 2019-04-24 21:24:32 +04:00
Nightblade73
d921def09d #68 added ping method 2019-04-24 21:05:25 +04:00
Nightblade73
f556b969b4 #68 added demo version of charts, using highcharts lib 2019-04-24 18:55:52 +04:00
Nightblade73
b16b3ed2e3 #68 added class structure 2019-04-24 17:41:19 +04:00
Nightblade73
5bff419dbd #68 added ping table 2019-04-24 16:44:17 +04:00
Anton Romanov
4dd0a6c210 fix merge bug 2019-04-24 13:45:09 +04:00
Anton Romanov
bb2518e5f4 Merge branch '76-students-tags-filter' into 'dev'
Resolve "Фильтр задач по типу (тегам)"

Closes #77, #75, and #76

See merge request romanov73/ng-tracker!61
2019-04-24 09:36:03 +00:00
Anton Romanov
1e6fbdc1fa Merge branch '64-add-article-conf' into 'dev'
Resolve "Добавить новую статью к конференции"

Closes #64

See merge request romanov73/ng-tracker!70
2019-04-24 09:35:08 +00:00
Anton Romanov
54c6fe815d Merge branch '113-delete-project' into 'dev'
Resolve "Реализовать удаление проекта"

Closes #113

See merge request romanov73/ng-tracker!71
2019-04-24 09:34:12 +00:00
Nightblade73
d37c9bda57 #64 excluded adding articles with the same name 2019-04-24 10:17:32 +04:00
Nightblade73
fe55890518 #64 more style fixes 2019-04-24 10:12:42 +04:00
Nightblade73
7eb5dce94e #64 style fixes 2019-04-24 09:42:00 +04:00
ASH
7248a84c30 #76 adding sorting 2019-04-24 01:03:56 +04:00
Васин Антон
02d643727e #113 projects/projects edited 2019-04-23 23:32:40 +03:00
Васин Антон
50a0f8aa78 #113 projects.js added 2019-04-23 23:19:25 +03:00
Васин Антон
2418e953be #113 line fragment edited 2019-04-23 23:15:52 +03:00
Васин Антон
e32da7c7c2 #113 delete function 2019-04-23 23:11:45 +03:00
Anton Romanov
3aea19088d Merge branch '115-follow-up-from-resolve' into 'dev'
Resolve "Follow-up from "Resolve "Прикрепление статей к гранту"""

Closes #115

See merge request romanov73/ng-tracker!73
2019-04-23 19:17:17 +00:00
Anton Romanov
8f2f6adc3b #64 show global message 2019-04-23 23:15:22 +04:00
T-Midnight
c18ecea13b #115 move method to service 2019-04-23 22:03:06 +04:00
T-Midnight
bf515a3fcb Merge remote-tracking branch 'remotes/origin/107-attach-article' into 115-follow-up-from-resolve 2019-04-23 21:47:54 +04:00
Васин Антон
2d6de6b535 Merge branch 'dev' of https://gitlab.com/romanov73/ng-tracker into dev 2019-04-23 19:52:38 +03:00
Anton Romanov
39f44403c1 Merge branch '114-bug-projects-list' into 'dev'
Resolve "Bug: не отображается список проектов"

Closes #114

See merge request romanov73/ng-tracker!72
2019-04-23 12:14:22 +00:00
Васин Антон
2f3c1addbb #114 unused imports removed 2019-04-23 14:20:17 +03:00
Васин Антон
c78ea05255 #114 update edited 2019-04-23 14:11:42 +03:00
T-Midnight
26969dba5b #107 merge with dev 2019-04-23 15:02:41 +04:00
T-Midnight
6df1a87367 #107 merge with dev 2019-04-23 15:01:47 +04:00
T-Midnight
546b0dc323 #107 add styles 2019-04-23 14:51:51 +04:00
Васин Антон
41bd00d645 project dashboard edited 2019-04-23 13:40:11 +03:00
Anton Romanov
955bdaa438 fix repository method 2019-04-23 13:55:59 +04:00
Anton Romanov
60dfad5d76 Merge branch 'dev' into move-to-jdk11
# Conflicts:
#	src/main/resources/db/changelog-master.xml
2019-04-23 13:51:21 +04:00
Nightblade73
6d6ea3136d #64 dont show error message 2019-04-23 13:37:56 +04:00
Васин Антон
70920cc612 Merge branch 'dev' of https://gitlab.com/romanov73/ng-tracker into dev 2019-04-23 12:33:56 +03:00
T-Midnight
d3b8be2cf1 #107 add view of the selected papers 2019-04-23 13:21:13 +04:00
Anton Romanov
e16b1da761 fix script 2019-04-23 12:46:17 +04:00
Anton Romanov
09cae66ca4 fix image 2019-04-23 12:38:15 +04:00
Anton Romanov
7684bac74d Merge branch 'dev' into move-to-jdk11
# Conflicts:
#	build.gradle
#	src/main/java/ru/ulstu/grant/model/GrantDto.java
#	src/main/java/ru/ulstu/grant/service/GrantService.java
#	src/main/java/ru/ulstu/paper/model/PaperDto.java
#	src/main/java/ru/ulstu/project/model/Project.java
2019-04-23 11:35:41 +04:00
Anton Romanov
5e86952cb6 Merge branch '97-edit-project' into 'dev'
Resolve "Редактирование проекта"

Closes #97

See merge request romanov73/ng-tracker!59
2019-04-23 07:34:13 +00:00
Васин Антон
019fe7c652 #97 adding deadlines 2019-04-23 10:32:23 +03:00
ASH
3698d31bc8 #76 fixing conflicts 2019-04-22 21:52:26 +04:00
Nightblade73
53cc777734 #64 delete conference refactor 2019-04-22 21:46:42 +04:00
Васин Антон
53cc947a17 #97 copy from DTO edited 2019-04-22 15:48:29 +03:00
Васин Антон
ba565746f5 #97 dashboard added 2019-04-22 14:41:58 +03:00
Васин Антон
519dd51446 #97 dashboard added 2019-04-22 14:31:46 +03:00
Васин Антон
349e7373ff #97 save function 2019-04-22 14:19:01 +03:00
Nightblade73
2767403128 #64 added saving in db 2019-04-22 15:11:52 +04:00
Nightblade73
5bfeaff054 #64 added method addPaper 2019-04-22 11:13:04 +04:00
Anton Romanov
b6ced3ce1a Merge branch '60-sort-conf' into 'dev'
Resolve "Сортировка списка конференций"

Closes #60

See merge request romanov73/ng-tracker!66
2019-04-22 03:12:00 +00:00
Anton Romanov
7fac92b52f Merge branch '110-paper-type' into 'dev'
Resolve "Тип статьи"

Closes #110

See merge request romanov73/ng-tracker!67
2019-04-22 03:10:48 +00:00
ASH
6876d09557 #76 adding style to filters 2019-04-21 19:02:27 +04:00
Nightblade73
ddd21dab1c #60 added dashboard 2019-04-21 17:18:44 +04:00
ASH
8400c5d40d Merge remote-tracking branch 'remotes/origin/dev' into 76-students-tags-filter
# Conflicts:
#	src/main/resources/templates/students/dashboard.html
2019-04-21 15:47:56 +04:00
Nightblade73
a4ae42f072 #60 added sorting 2019-04-21 15:03:31 +04:00
Семенова Мария
a3d1834ab8 #110 add paper type 2019-04-21 12:17:31 +04:00
Anton Romanov
bc98785be9 Merge branch '59-filter-conference' into 'dev'
Resolve "Фильтрация списка конференции"

Closes #59

See merge request romanov73/ng-tracker!65
2019-04-19 14:46:23 +00:00
Nightblade73
a9f4a326c5 #59 fixed styles 2019-04-19 18:38:56 +04:00
Nightblade73
338d7c2e09 #59 added begin-end dates in conferenceRow 2019-04-19 18:32:24 +04:00
T-Midnight
eec739a49f #41 create simple attach of articles 2019-04-19 17:49:36 +04:00
T-Midnight
f29d31b840 #41 create changelog 2019-04-19 17:45:22 +04:00
Nightblade73
34033fac5f #59 added filtration 2019-04-19 17:36:46 +04:00
Nightblade73
e2b49689d5 #59 changed filterDto 2019-04-19 17:31:30 +04:00
Nightblade73
9f664b2618 #59 add front thymeleaf 2019-04-19 17:30:30 +04:00
Anton Romanov
21ba06170a Merge branch '106-papers-bug' into 'dev'
Resolve "Bug: не отображается список статей"

Closes #106

See merge request romanov73/ng-tracker!62
2019-04-19 13:13:10 +00:00
Anton Romanov
9e31bfa7d7 #106 add checkstyle rules 2019-04-19 17:08:12 +04:00
Anton Romanov
2d0f2aeecd Merge branch '69-take-part-conf' into 'dev'
Resolve "Принять участие в конференции пользователю"

Closes #69

See merge request romanov73/ng-tracker!56
2019-04-19 13:05:07 +00:00
Nightblade73
b623402aa8 #69 changed method getConference in controller 2019-04-19 14:39:07 +04:00
Nightblade73
9edcebb2f5 #69 changed isCurrentUserParticipant 2019-04-19 14:29:08 +04:00
Nightblade73
713e50043e Merge remote-tracking branch 'remotes/origin/dev' into 69-take-part-conf
# Conflicts:
#	src/main/resources/db/changelog-master.xml
2019-04-19 14:24:32 +04:00
Anton Romanov
9506057bb1 Merge branch '41-js' into 'dev'
Resolve "Переход к гранту со страницы панели управления"

Closes #41

See merge request romanov73/ng-tracker!63
2019-04-19 09:52:24 +00:00
T-Midnight
f387b4eb52 #41 add link to the grant page 2019-04-19 11:36:27 +04:00
Семенова Мария
6c8554a0b8 #106 change boolean to nullable 2019-04-18 23:37:08 +04:00
ASH
7bec7b4e44 #76 filters added 2019-04-18 23:15:32 +04:00
Anton Romanov
5a55e3cfc8 Merge branch '42--2' into 'dev'
Resolve "Форма добавления и фильтра участников гранта"

Closes #42

See merge request romanov73/ng-tracker!44
2019-04-18 18:40:37 +00:00
T-Midnight
958a0d461b #42 merge with dev 2019-04-18 22:35:07 +04:00
T-Midnight
416ad7eeda #42 merge with dev 2019-04-18 22:34:20 +04:00
Anton Romanov
3bdb8798cd Merge branch '105-paper-latex-editing' into 'dev'
Resolve "Генерация PDF файла из формата latex"

Closes #105

See merge request romanov73/ng-tracker!60
2019-04-18 18:31:18 +00:00
ASH
59887e5141 #76 delete function added 2019-04-18 21:57:56 +04:00
ASH
9da227ab34 #76 fixing dashboard 2019-04-18 21:38:55 +04:00
Семенова Мария
6c6a748978 #105 danger message type 2019-04-18 19:03:04 +04:00
Семенова Мария
a2dca6b7c6 Merge branch 'dev' into paper-latex-editing
# Conflicts:
#	src/main/java/ru/ulstu/paper/model/Paper.java
#	src/main/java/ru/ulstu/paper/model/PaperDto.java
#	src/main/java/ru/ulstu/paper/service/PaperService.java
#	src/main/resources/db/changelog-master.xml
#	src/main/resources/templates/papers/paper.html
2019-04-18 18:20:51 +04:00
Васин Антон
f1f7c1f0f6 #97 cancel button edited 2019-04-18 16:49:10 +03:00
Nightblade73
96431701df #69 added button disabling take part, if cur user already taken part 2019-04-18 15:38:45 +04:00
Васин Антон
6469ddcd42 Merge branch 'dev' of https://gitlab.com/romanov73/ng-tracker into dev 2019-04-18 13:37:29 +03:00
Nightblade73
8fd352aaa4 #69 added styles 2019-04-18 14:33:49 +04:00
Anton Romanov
8474fb492f Merge branch '96-edit-project-page' into 'dev'
Resolve "Страница редактирования проекта"

Closes #96

See merge request romanov73/ng-tracker!57
2019-04-18 09:32:48 +00:00
Васин Антон
d015b02862 #96 removed wildcards from imports 2019-04-18 13:26:11 +03:00
Васин Антон
ced3b0a978 #96 database edited 2019-04-18 12:10:27 +03:00
T-Midnight
e284298200 #42 rename variables 2019-04-18 13:09:50 +04:00
Васин Антон
b722687050 #96 edit project page 2019-04-18 10:32:43 +03:00
Nightblade73
918079ac89 #69 fixed not working code, now user can take part in conference and choose participation and deposit 2019-04-18 11:20:44 +04:00
Семенова Мария
789fda9c98 remove nonstopmode from bibtex 2019-04-18 10:49:36 +04:00
Anton Romanov
4eef57bce7 Merge branch '102-autotesting' into 'dev'
Resolve "Классы для автотестов"

Closes #102

See merge request romanov73/ng-tracker!58
2019-04-17 14:17:41 +00:00
Anton Romanov
32c7261c2e #102 restore old swagger 2019-04-17 18:13:21 +04:00
Anton Romanov
4615183ae4 #102 temporary skip tests until fix docker container 2019-04-17 17:46:06 +04:00
Anton Romanov
49a379ab3c #102 temporary skip tests until fix docker container 2019-04-17 17:37:43 +04:00
Anton Romanov
5b89ed7284 #102 fix code style 2019-04-17 17:26:54 +04:00
Anton Romanov
cfbe36197b #102 add auto tests 2019-04-17 17:20:20 +04:00
Васин Антон
e85c814f70 #96 project comment added 2019-04-17 14:46:42 +03:00
Васин Антон
255692d6ea #96 project status added 2019-04-17 14:38:07 +03:00
Васин Антон
f079e34a57 #96 project title added 2019-04-17 14:18:35 +03:00
Васин Антон
4ea40931eb #96 project status fragment added 2019-04-17 14:06:38 +03:00
Васин Антон
a89d93a9b0 #96 project line fragment added 2019-04-17 14:01:45 +03:00
Nightblade73
7e4d8d4918 #69 added method take part in conference 2019-04-17 14:51:19 +04:00
Васин Антон
ca3e87a8c5 #96 edit project blank page 2019-04-17 13:50:22 +03:00
T-Midnight
506fa01fab Revert: #42 merge with dev 2019-04-17 13:42:22 +04:00
T-Midnight
97d7d00098 #42 merge with dev 2019-04-17 13:30:14 +04:00
T-Midnight
1e6b3cba3a #42 delete blank lines, fix js, fix leaderId validation 2019-04-17 13:25:10 +04:00
Nightblade73
8564f2cf34 #69 managed to create a connection through a new entity 2019-04-17 13:00:48 +04:00
Васин Антон
92a0674b95 Merge branch 'dev' of https://gitlab.com/romanov73/ng-tracker into dev 2019-04-17 11:44:54 +03:00
Васин Антон
8fbce55028 #86 projects main page 2019-04-17 11:04:35 +03:00
Anton Romanov
487aa578a7 Merge branch '86-projects-main-page' into 'dev'
Resolve "Создать страницу списка проектов"

Closes #86

See merge request romanov73/ng-tracker!53
2019-04-17 07:35:00 +00:00
Васин Антон
f5c1bb940c #86 projects main page 2019-04-17 11:24:30 +03:00
Nightblade73
14c28050c7 #65 changed interface 2019-04-17 11:19:23 +04:00
Anton Romanov
b05a32edac fix issue template 2019-04-17 09:33:58 +04:00
Anton Romanov
7491d7e9e4 Merge branch '65-undock-article' into 'dev'
Resolve "Удалить статью"

Closes #65

See merge request romanov73/ng-tracker!55
2019-04-16 11:13:20 +00:00
Nightblade73
81d07645c2 #65 added delete method of article, fixed copyFromDto method 2019-04-16 14:18:49 +04:00
Anton Romanov
3facc0c26e Merge branch '74-students-add-new-task' into 'dev'
Resolve "Добавление новой задачи"

Closes #78 and #74

See merge request romanov73/ng-tracker!47
2019-04-16 09:36:58 +00:00
Anton Romanov
d81d1cf72c #74 some code fixes 2019-04-16 13:41:10 +04:00
Anton Romanov
0c719d8886 Merge branch '66-attach-exist-article' into 'dev'
Resolve "Прикрепление статьи"

Closes #66

See merge request romanov73/ng-tracker!54
2019-04-16 09:33:57 +00:00
Nightblade73
d4b38d314f #66 fixed bug, when attach-article lose what needed to attach after add or remove deadline 2019-04-16 13:22:15 +04:00
anastasia shulga
95f70f425a Update2 TagService.java 2019-04-16 08:21:36 +00:00
anastasia shulga
dbd61ce80c Update TagService.java 2019-04-16 07:55:37 +00:00
Nightblade73
dca644eba1 #66 added handling of adding articles not added to the picker. 2019-04-16 10:42:40 +04:00
Nightblade73
fbf9a7943b #66 changed from Set to List 2019-04-16 09:51:31 +04:00
Nightblade73
735cbb5f7b #66 added front-end part 2019-04-16 09:46:24 +04:00
Anton Romanov
06b5d66d3e Merge branch '58-delete-conf' into 'dev'
Resolve "Удаление конференции"

Closes #58

See merge request romanov73/ng-tracker!51
2019-04-15 17:32:22 +00:00
Nightblade73
909c657c89 #58 added delete confirm 2019-04-15 15:48:17 +04:00
Nightblade73
0cc8de2d32 #58 added delete method of conference 2019-04-15 10:36:55 +04:00
Anton Romanov
9e657a7d2d Merge branch '62-delete-deadline' into 'dev'
Resolve "Удаление дедлайна"

Closes #62

See merge request romanov73/ng-tracker!50
2019-04-14 19:33:45 +00:00
Nightblade73
f88f035e65 #55 little fix 2019-04-14 21:34:39 +04:00
ASH
1f36e04cd3 #74 fully adding tags 2019-04-14 21:24:22 +04:00
Nightblade73
8cfc64ea85 #55 added delete input style 2019-04-14 20:42:11 +04:00
ASH
d6a11a5902 #74 fixing codestyle and tags 2019-04-14 17:50:23 +04:00
Anton Romanov
8b2a559d37 #42 fix thymeleaf expressions 2019-04-13 23:56:24 +04:00
Anton Romanov
34499abd60 #62 fix remove deadline in other JPA operation 2019-04-13 22:59:59 +04:00
Nightblade73
9711febefb #55 added delete deadline 2019-04-13 13:02:36 +04:00
T-Midnight
1756f29505 #42 filter authors by leader and degree 2019-04-13 12:39:53 +04:00
Nightblade73
b4a2a8086d #62 remove verification of empty deadline list 2019-04-12 15:51:06 +04:00
Anton Romanov
4955e9a637 #4--2 merge with dev 2019-04-11 22:39:59 +04:00
Anton Romanov
cafb3abcee #4--2 merge with dev 2019-04-11 22:37:32 +04:00
T-Midnight
bd3513118c #42 this don't work 2019-04-11 21:42:28 +04:00
T-Midnight
f7d766f02d #42 rename birth_date column 2019-04-11 21:37:24 +04:00
ASH
5eae7305c4 #74 codestyle 2019-04-11 00:14:03 +04:00
ASH
f019806a8e #74 fixing adding and db everything added except tags 2019-04-10 23:57:55 +04:00
T-Midnight
e8461e26eb #42 fix birthDate and degree to User 2019-04-10 10:09:41 +04:00
T-Midnight
51c755ac07 #42 method hasErrors didn't work, return to the previous state 2019-04-10 09:39:07 +04:00
ASH
9b697c6f3f #74 adding models, controllers and services 2019-04-09 23:18:39 +04:00
T-Midnight
e2e10477ac #42 delete GrantStatusDto 2019-04-09 21:31:23 +04:00
Anton Romanov
d1813f656e Merge branch '61-adding-deadline' into 'dev'
Resolve "Добавление дедлайна для конференции"

Closes #61

See merge request romanov73/ng-tracker!49
2019-04-09 12:34:06 +00:00
Nightblade73
c308a5e5af #55 Navigation's method "hasErrors" don't work. it returns String, not redirection. 2019-04-09 14:47:14 +04:00
Nightblade73
689a7799e3 #55 added method in controller 2019-04-08 22:04:30 +04:00
Anton Romanov
518f587eed Merge branch '85-issue-templates' into 'dev'
Resolve "Шаблоны задач"

Closes #85

See merge request romanov73/ng-tracker!48
2019-04-08 07:36:33 +00:00
user
3017366c91 №85 try to add issue template 2019-04-08 11:27:15 +03:00
Anton Romanov
7dca991c2f Merge branch '55-new-conf' into 'dev'
Resolve "Добавление новой конференции"

Closes #55

See merge request romanov73/ng-tracker!43
2019-04-08 03:33:40 +00:00
Anton Romanov
e350f8b3c1 #55 refactor controller navigation, fix conference edit url 2019-04-08 07:40:26 +04:00
Nightblade73
c49b56916c #55 added initialization of fields in ConferenceDto 2019-04-07 10:08:13 +04:00
Nightblade73
db43da9ec0 #55 added nav controller 2019-04-07 10:01:44 +04:00
Nightblade73
3e5aeaf290 #55 fast fixes 2019-04-06 14:41:10 +04:00
Nightblade73
926cd02096 #55 fixed adding to DB 2019-04-06 11:05:30 +04:00
Anton Romanov
b9af7c20c7 fix grids 2019-04-06 00:11:49 +04:00
T-Midnight
7465803162 #42 add columns 'birth_date'&'degree' to User 2019-04-05 22:06:16 +04:00
Anton Romanov
d26ab93629 Merge branch '83-docker-hub' into 'dev'
Resolve "Образ для docker hub"

Closes #83

See merge request romanov73/ng-tracker!46
2019-04-05 18:03:16 +00:00
Anton Romanov
e0ca29fbab #83 fix wrong entity 2019-04-05 21:47:42 +04:00
Nightblade73
eb524d49d0 #55 added html side, don't work, because can't parse date, like in deadlines 2019-04-05 18:01:43 +04:00
Anton Romanov
72add3638b #83 check CI 2019-04-05 18:01:12 +04:00
Anton Romanov
0feef9016a #83 disable cache 2019-04-05 17:48:23 +04:00
Anton Romanov
94dabd07fb #83 fix code 2019-04-05 17:47:10 +04:00
Anton Romanov
7a7dfb337f #83 fix postgres service 2019-04-05 17:41:31 +04:00
Anton Romanov
c7cdbe9044 #83 add tasks, modify build script for passing application properties 2019-04-05 17:35:17 +04:00
Anton Romanov
fe1820d540 #83 try to change container 2019-04-05 16:37:03 +04:00
Nightblade73
67bfad22f9 #55 added create and update methods 2019-04-05 16:30:45 +04:00
Anton Romanov
4a05d52e4c #83 try to change container 2019-04-05 16:25:10 +04:00
Anton Romanov
bbc398251f #83 try to change container 2019-04-05 16:16:40 +04:00
Anton Romanov
2cf3e52596 #73 merge dev into jdk11 2019-04-05 14:11:13 +04:00
Anton Romanov
0d7c594a94 Merge branch '82-paper-formatted-list' into 'dev'
Resolve "Метод в rest для список опубликованных статей"

Closes #82

See merge request romanov73/ng-tracker!45
2019-04-05 09:42:30 +00:00
Anton Romanov
54edeb0559 #82 fix user abbreviate 2019-04-05 13:39:53 +04:00
Anton Romanov
91d2168012 #82 show paper formatted lines 2019-04-05 13:34:38 +04:00
Nightblade73
d6b7fe790a #55 added transition to the page new conference 2019-04-05 13:21:15 +04:00
Nightblade73
9d69f75530 #55 fixes 2019-04-04 20:26:38 +04:00
Nightblade73
2d04b1b43a #55 added findAll method in ConferenceService 2019-04-04 17:58:22 +04:00
Nightblade73
d189891e8c #55 added ConferenceFilterDto 2019-04-04 17:47:18 +04:00
Nightblade73
e3bbade40b #55 added ConferenceDto 2019-04-04 17:39:28 +04:00
Nightblade73
dc12a671d2 #55 added setters/getters 2019-04-04 12:50:12 +04:00
Nightblade73
be2dd291f6 #55 added conference model without user's participation and deposit. May be needed new user model. 2019-04-04 12:48:05 +04:00
T-Midnight
99a8550696 #42 merge dev into 42 2019-04-04 09:44:51 +04:00
T-Midnight
566b7821d1 #42 merge dev into 42 2019-04-04 09:43:26 +04:00
T-Midnight
8a7117d713 #42 Add leader and authors 2019-04-04 09:38:18 +04:00
Семенова Мария
ded0ab482a add nonstopmode 2019-04-03 17:46:45 +04:00
Anton Romanov
4104aa04cd fixes for wrong build. entities always extends BaseEntity, tables must contains version column 2019-04-03 10:39:55 +04:00
Anton Romanov
54bbd2375d Merge branch '57-classes-creating' into 'dev'
Resolve "Создание классов для модуля Конференции"

Closes #57

See merge request romanov73/ng-tracker!42
2019-04-03 04:03:46 +00:00
Nightblade73
0428bad048 #57 created classes 2019-04-02 10:53:09 +04:00
Anton Romanov
0c84f30498 Merge branch '81-students-create-database' into 'dev'
Resolve "Создание базы данных"

Closes #81

See merge request romanov73/ng-tracker!41
2019-04-01 05:36:15 +00:00
Anton Romanov
5ffb2d547e Merge branch 'dev' into 81-students-create-database
# Conflicts:
#	src/main/resources/db/changelog-master.xml
2019-04-01 09:42:40 +04:00
Anton Romanov
61d4c67aac Merge branch '56-creating-tables-in-DB' into 'dev'
Resolve "Создание таблиц в БД по модулю конференций"

Closes #56

See merge request romanov73/ng-tracker!40
2019-04-01 05:27:43 +00:00
Anton Romanov
c2dc080d23 Merge branch '71-add-task-layout' into 'dev'
Resolve "Верстка страницы добавления новой задачи, ПУ и списка задач"

Closes #71

See merge request romanov73/ng-tracker!29
2019-04-01 05:17:39 +00:00
ASH
4e89c65c22 #81 adding main tables 2019-03-31 18:58:57 +04:00
ASH
2ad03a5689 #71 adding dashboard 2019-03-31 13:47:15 +04:00
Nightblade73
e93f618779 #56 added database schema 2019-03-31 13:12:43 +04:00
Anton Romanov
76d4c15db5 Merge branch '18-paper-timeline' into 'dev'
Resolve "Реализовать добавление в таймлайн событий по дедлайнам статей"

Closes #18

See merge request romanov73/ng-tracker!39
2019-03-30 07:12:26 +00:00
Anton Romanov
e98445bb48 Merge branch '53-vyorstka-stranitsy-spiska-konferentsiy' into 'dev'
Resolve "Вёрстка страницы списка конференций"

Closes #53

See merge request romanov73/ng-tracker!33
2019-03-30 07:10:47 +00:00
Семенова Мария
030e1a3afb Merge branch 'dev' into 18-paper-timeline
# Conflicts:
#	src/main/java/ru/ulstu/paper/model/Paper.java
#	src/main/resources/db/changelog-master.xml
2019-03-28 18:32:44 +04:00
Anton Romanov
ba64b7df16 Merge branch 'restore-commits-page' into 'dev'
partially restored commits page

See merge request romanov73/ng-tracker!38
2019-03-28 11:58:02 +00:00
Anton Romanov
103ff05846 fix displaying commits 2019-03-28 15:53:31 +03:00
Anton Romanov
539095c89e partially restored commits page 2019-03-28 14:59:35 +04:00
Семенова Мария
0c34571354 remove JLR library using 2019-03-28 14:51:17 +04:00
Anton Romanov
7269f45662 Merge branch '80-no-records-message' into 'dev'
Resolve "Добавить сообщения на пустые страницы"

Closes #80

See merge request romanov73/ng-tracker!37
2019-03-28 10:39:06 +00:00
Anton Romanov
7b0b7a041a #80 hide mvc controllers from api 2019-03-28 14:45:39 +04:00
Anton Romanov
c70c35f4f3 #80 add no records message 2019-03-28 14:36:58 +04:00
Семенова Мария
2f0c461524 #18 add paper events 2019-03-28 12:40:10 +04:00
Nightblade73
01b082c31b #53 changed style like in module "papers" 2019-03-28 10:15:15 +04:00
Anton Romanov
e74fcb316c #33 small external link 2019-03-27 13:27:49 +04:00
Anton Romanov
37e20fb472 Update README.md 2019-03-27 09:07:02 +00:00
Anton Romanov
1dbb9b9136 Merge branch '33-paper-url' into 'dev'
Resolve "Добавить в конференцию/статью ссылку на сайт"

Closes #33

See merge request romanov73/ng-tracker!36
2019-03-27 07:58:58 +00:00
ASH
af3c0c0faa #71 fixing layout n adding 2019-03-26 10:49:26 +04:00
Семенова Мария
cf9a7f895f pdf generating 2019-03-25 13:17:34 +04:00
Nightblade73
79cfd7c0ab #53 added pagination style, css fixes 2019-03-25 11:41:36 +04:00
Nightblade73
cc1f5c00c5 #53 adapted, refactor css 2019-03-24 16:17:26 +04:00
Nightblade73
99468a0cea #53 added actual.html, css fixes 2019-03-24 13:48:34 +04:00
Nightblade73
bff824bc06 #53 added control panel 2019-03-24 12:46:15 +04:00
Семенова Мария
10fe7e8a4e paper files list fragment, latex attachs upload 2019-03-24 12:42:21 +04:00
Семенова Мария
c86f58d1b2 tab with latex editing 2019-03-23 22:49:11 +04:00
Семенова Мария
c21e8afc1f latex text in paper 2019-03-23 22:04:56 +04:00
Nightblade73
ea4e25aded #53 added years filter forms 2019-03-23 15:19:48 +04:00
Nightblade73
edd6aee00f #53 fast fix 2019-03-23 12:52:52 +04:00
Nightblade73
50dbe8cb8f #53 added custom checkboxes, added selection of all conferences 2019-03-23 12:39:53 +04:00
Семенова Мария
b90e7c054b #33 link in new tab 2019-03-23 12:23:30 +04:00
Семенова Мария
c228f5aee0 Merge branch 'dev' into 33-paper-url
# Conflicts:
#	src/main/java/ru/ulstu/paper/model/Paper.java
#	src/main/java/ru/ulstu/paper/service/PaperService.java
#	src/main/resources/db/changelog-master.xml
2019-03-23 12:04:51 +04:00
Anton Romanov
f5ce1aa269 Merge branch '13-paper-files' into 'dev'
Resolve "Загрузка и сохранение файлов статей"

Closes #13

See merge request romanov73/ng-tracker!35
2019-03-22 10:36:09 +00:00
Anton Romanov
482e74e10e #13 reduce of code 2019-03-22 13:58:03 +04:00
Anton Romanov
7012c00c5f #13 fix condition 2019-03-22 13:52:06 +04:00
Семенова Мария
a0b65f341b #13 streams refactoring 2019-03-22 13:21:32 +04:00
Семенова Мария
5da9de1bab #13 rename 'deleted', move creating fileDto to service 2019-03-22 09:32:21 +04:00
Семенова Мария
c702e2abb4 #13 fileDataDto instead of Object[] 2019-03-21 18:26:28 +04:00
Nightblade73
9182a71015 #53 added ping style 2019-03-21 11:30:28 +04:00
Nightblade73
d356c21944 #53 added buttons, added bottom pagination 2019-03-21 09:55:38 +04:00
Nightblade73
89e0d1a291 #53 customization css styles 2019-03-20 21:15:45 +04:00
Anton Romanov
167de9bf65 #73 fix deprecated parameters 2019-03-20 20:35:24 +04:00
Anton Romanov
993a034527 #73 restore authentication 2019-03-20 20:32:10 +04:00
Anton Romanov
9bd954ea9b #73 fix new thymeleaf syntax 2019-03-20 20:31:46 +04:00
Anton Romanov
1487affb8e #73 fix deprecated annotations and classes 2019-03-20 19:20:28 +04:00
Nightblade73
cb673d8782 #53 remake of conference list without table 2019-03-20 18:33:15 +04:00
Nightblade73
1364e8e84d #53 added multi selection, added selection of all items 2019-03-20 16:48:55 +04:00
Anton Romanov
e74261184f #73 first fixes by update versions 2019-03-20 14:37:57 +04:00
Семенова Мария
3c068df201 #13 some refactoring 2019-03-19 17:59:19 +04:00
Семенова Мария
1a522f7b44 Merge branch 'dev' into 13-paper-files 2019-03-19 17:41:02 +04:00
Nightblade73
5dc54dda8b #53 added supporting russian language, added linkable row in table 2019-03-19 15:08:45 +04:00
Семенова Мария
e6bf603edc #33 url in paper 2019-03-18 23:31:33 +04:00
Anton Romanov
c374cb4232 merge deploy environments 2019-03-18 22:35:01 +04:00
Anton Romanov
d35e0f7ba3 add environment 2019-03-18 22:25:28 +04:00
Семенова Мария
1425cceb63 #13 download files 2019-03-18 21:02:26 +04:00
Семенова Мария
8dc5eec35c #13 add files to db 2019-03-18 19:17:28 +04:00
Nightblade73
fd22aecd22 #53 added supporting bootstrap style 2019-03-18 18:41:59 +04:00
Семенова Мария
4fb8061653 #13 addNewFile js function 2019-03-18 18:39:15 +04:00
Семенова Мария
e609b27518 Merge branch 'dev' into 13-paper-files
# Conflicts:
#	src/main/java/ru/ulstu/paper/model/PaperDto.java
2019-03-18 16:13:22 +04:00
Семенова Мария
cb394edf90 #13 file list on paper page 2019-03-18 16:02:55 +04:00
Anton Romanov
9418a47a1d Merge branch '50-refactorForGrants' into 'dev'
Resolve "Тех. долг: отрефакторить контроллеры и модели"

Closes #50

See merge request romanov73/ng-tracker!32
2019-03-18 11:08:15 +00:00
T-Midnight
29df7120bf Delete DeadlineDTO and update usages 2019-03-18 14:27:54 +04:00
Семенова Мария
0764d961fa #13 add fileDataDto 2019-03-18 13:00:34 +04:00
Семенова Мария
7b601c744f #13 change model, schema 2019-03-18 11:07:30 +04:00
Nightblade73
6296b661a9 #53 added conference js file 2019-03-16 14:44:34 +04:00
Nightblade73
a236fc50bc #53 added datatables lib support 2019-03-16 14:39:56 +04:00
T-Midnight
99d85a5648 Add new status for grant 2019-03-15 12:24:02 +04:00
T-Midnight
c25c17d8ba Rename title 2019-03-15 12:19:25 +04:00
T-Midnight
de96be2471 Create Navigation class to avoid "magic strings" and code duplication 2019-03-15 12:19:01 +04:00
Anton Romanov
ae58a5b6e4 Merge branch '72-link-to-timetable' into 'dev'
Resolve "Ссылка на расписание пользователя"

Closes #72

See merge request romanov73/ng-tracker!31
2019-03-13 07:16:32 +00:00
Anton Romanov
90bb94d864 add patronymic 2019-03-12 14:44:11 +04:00
Anton Romanov
48894b2176 display user in filter 2019-03-12 13:40:48 +04:00
Anton Romanov
da7a17ee49 add service methods 2019-03-12 12:51:59 +03:00
Anton Romanov
20ecb47867 add timetable link 2019-03-12 12:35:09 +03:00
ASH
bd975c53f3 #71 adding pages and layout 2019-03-11 22:46:51 +04:00
Anton Romanov
3169551968 Merge branch '54-view-conference' into 'dev'
Resolve "Вёрстка страницы просмотра информации о конференции"

Closes #54

See merge request romanov73/ng-tracker!26
2019-03-11 10:49:07 +00:00
Nightblade73
5cb865eb70 #54 deleted edit btn 2019-03-11 14:43:32 +04:00
Nightblade73
2fec35264c #54 add back link, css fixes 2019-03-11 12:58:40 +04:00
Nightblade73
f90d92b19d #54 add custom paper-list 2019-03-11 11:36:00 +04:00
Nightblade73
d332282e03 #54 add custom deadline-list, add edit-button, add edit and delete icons 2019-03-10 22:15:09 +04:00
Nightblade73
7fff337c3a #54 add member list 2019-03-07 22:50:37 +04:00
Nightblade73
76ec5add30 #54 part of make-up 2019-03-06 20:51:46 +04:00
Nightblade73
c21a65a075 #54 add transitions 2019-03-06 16:48:51 +04:00
Anton Romanov
42fdb51337 fix login 2019-03-06 16:40:33 +04:00
Nightblade73
93e68b1929 #50 creating html page, changing href 2019-03-06 16:27:25 +04:00
Anton Romanov
febdb0b027 Merge branch '29-page-header' into 'dev'
Resolve "Адаптивный заголовок на странице"

Closes #29

See merge request romanov73/ng-tracker!28
2019-03-06 12:25:34 +00:00
Anton Romanov
cb73340c3f fix css 2019-03-06 16:19:43 +04:00
Anton Romanov
4226be6406 fix props 2019-03-06 14:36:46 +03:00
Anton Romanov
dd90bd24a9 fix props 2019-03-06 14:35:09 +03:00
user
285b43c63c header fix 2019-03-06 14:25:02 +03:00
303 changed files with 14174 additions and 2761 deletions

View File

@ -1,30 +1,28 @@
image: ubuntu:18.04 image: romanov73/is:ng-tracker-container-11
cache:
key: "$CI_PROJECT_ID"
paths:
- .gradle/
variables: variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false" GRADLE_OPTS: "-Dorg.gradle.daemon=false"
before_script: before_script:
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - service postgresql stop
- apt-get install openjdk-8-jdk git -y - service postgresql start
- eval $(ssh-agent -s) - eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
- mkdir -p ~/.ssh - mkdir -p ~/.ssh
- chmod 700 ~/.ssh - chmod 700 ~/.ssh
- git log --pretty="%cn;%cd;%s" > src/main/resources/commits.log
build: build:
stage: build stage: build
script: ./gradlew assemble script: ./gradlew assemble
cache:
key: "$CI_PROJECT_ID" checkRun:
policy: push stage: test
paths: script: ./gradlew bootRun -Dng-tracker.check-run=true
- build
- .gradle checkStyle:
stage: test
script: ./gradlew check -x test
deploy: deploy:
stage: deploy stage: deploy
@ -32,9 +30,6 @@ deploy:
- sh deploy/gdccloud/deploy.sh - sh deploy/gdccloud/deploy.sh
only: only:
- dev - dev
cache: environment:
key: "$CI_PROJECT_ID" name: staging
policy: pull url: http://193.110.3.124:8080
paths:
- build
- .gradle

View File

@ -0,0 +1,46 @@
## Краткое описание задачи
Что требуется сделать
## `Опционально` Список верстаемых страниц
Будут затронуты страницы:
* page1.html
* page2.html
* page3.html
## `Опционально` Список затрагиваемых модулей
При реализации задачи потребуется также реализовать методы контроллера
## `Опционально` Список реализуемых функций
После выполнения задачи станет доступным:
* просмотр `entity_name`
* редактирование `entity_name`
* валидация `entity_name`
## `Опционально` Сценарии работы
Сценарий просмотра:
1. Зайти на главную страницу приложения
2. Перейти в раздел `section_name`
3. Перейти к списку `entity_name`
4. Выбрать нужную `entity_name` и нажать на нее
Сценарий редактирования:
1. Зайти на главную страницу приложения
2. Перейти в раздел `section_name`
3. Перейти к списку `entity_name`
4. Выбрать нужную `entity_name` и нажать на нее
5. Внести нужные правки в поля и сохранить
## Описание конечного результата, дающего возможность проверки выполнения задачи: компоненты проекта, сценарии работы
* Сверстаны страницы page1.hml, page2.hml, page3.hml
* Реализован контроллер для обслуживания страниц
* Сохранение в БД еще не реализовано
* Валидация происходит по полям `field1, field2`
* Сценарий просмотра проверяется при ручном внечении записей в БД

19
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,19 @@
pipeline {
agent any
stages {
stage('Test') {
steps {
sh "./gradlew clean test --info"
}
}
}
post {
always {
script {
if (currentBuild.currentResult == 'FAILURE') {
step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: "a.romanov@ulstu.ru", sendToIndividuals: true])
}
}
}
}
}

View File

@ -7,7 +7,6 @@
2. Создать новую функцию автоматизированной системы управления задчами - интеллектуальную постановку задач исполнителям. 2. Создать новую функцию автоматизированной системы управления задчами - интеллектуальную постановку задач исполнителям.
3. Получить платформу для обкатки научных проектов магистрантов по созданию интеллектуальны систем. 3. Получить платформу для обкатки научных проектов магистрантов по созданию интеллектуальны систем.
4. Получить проект для обучения бакалавров современым технологиям разработки. 4. Получить проект для обучения бакалавров современым технологиям разработки.
5. Создать систему хранения и трансляции опыта между участниками научной группы.
[Демо версия доступна здесь](http://193.110.3.124:8080) [Для разворачивания проекта и ведения разработки ознакомьтесь с wiki](https://git.athene.tech/romanov73/ng-tracker/wiki/home)
[Для разворачивания проекта и ведения разработки ознакомьтесь с wiki](https://gitlab.com/romanov73/ng-tracker/wikis/home)

View File

@ -1,34 +1,23 @@
buildscript { plugins {
ext { id 'java'
versionSpringBoot = '1.5.10.RELEASE' id 'org.springframework.boot' version '3.2.4'
} id 'io.spring.dependency-management' version '1.1.4'
id 'checkstyle'
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath group: 'org.springframework.boot', name: 'spring-boot-gradle-plugin', version: versionSpringBoot
}
} }
group 'ru.ulstu' group 'ru.ulstu'
version '0.1.0-SNAPSHOT' version '0.1.0-SNAPSHOT'
apply plugin: 'application'
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'checkstyle'
mainClassName = 'ru.ulstu.NgTrackerApplication'
build.dependsOn checkstyleMain build.dependsOn checkstyleMain
bootRun.dependsOn checkstyleMain bootRun.dependsOn checkstyleMain
sourceCompatibility = 1.8 java {
targetCompatibility = 1.8 sourceCompatibility = '17'
}
bootRun {
systemProperties = System.properties
}
checkstyle { checkstyle {
@ -60,7 +49,7 @@ checkstyle {
checkstyle checkstyle
} }
dependencies{ dependencies {
assert project.hasProperty("checkstyleVersion") assert project.hasProperty("checkstyleVersion")
checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}" checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}"
@ -72,9 +61,16 @@ task health(dependsOn: [
'checkstyleMain' 'checkstyleMain'
]) ])
test {
useJUnitPlatform()
}
jar { jar {
baseName = 'ng-tracker' enabled = false
}
bootJar {
archiveFileName = String.format('%s-%s.jar', rootProject.name, version)
} }
compileJava { compileJava {
@ -86,43 +82,39 @@ repositories {
mavenCentral() mavenCentral()
} }
configurations {
compile.exclude module: "spring-boot-starter-tomcat"
compile.exclude module: "bcmail-jdk14"
compile.exclude module: "bcprov-jdk14"
compile.exclude module: "bctsp-jdk14"
}
dependencies { dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web' implementation('org.springframework.boot:spring-boot-starter-web') {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-security' exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop' }
compile group: 'org.springframework.boot', name: 'spring-boot-starter-mail' implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-jetty' implementation group: 'org.springframework.boot', name: 'spring-boot-starter-aop'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa' implementation group: 'org.springframework.boot', name: 'spring-boot-starter-mail'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf' implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jetty'
compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-springsecurity4' implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner' implementation group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5' implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation'
implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect'
implementation group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-springsecurity6'
implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner'
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5'
compile group: 'postgresql', name: 'postgresql', version: '9.1-901.jdbc4' implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.5'
compile group: 'org.liquibase', name: 'liquibase-core', version: '3.5.3' implementation group: 'org.liquibase', name: 'liquibase-core', version: '4.27.0'
compile group: 'com.mattbertolini', name: 'liquibase-slf4j', version: '2.0.0' implementation group: 'com.mattbertolini', name: 'liquibase-slf4j', version: '2.0.0'
compile group: 'org.apache.poi', name: 'poi', version: '3.9' implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.7'
compile group: 'org.apache.poi', name: 'poi-ooxml', version: '3.9'
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.7' implementation group: 'org.webjars', name: 'bootstrap', version: '5.3.3'
runtimeOnly group: 'org.webjars', name: 'bootstrap-select', version: '1.4.2'
implementation group: 'org.webjars', name: 'jquery', version: '3.7.1'
implementation group: 'org.webjars', name: 'jquery-easing', version: '1.4.1'
implementation group: 'org.webjars', name: 'font-awesome', version: '4.7.0'
compile group: 'org.webjars', name: 'bootstrap', version: '4.1.0' implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.8.0'
compile group: 'org.webjars', name: 'bootstrap-select', version: '1.13.3' implementation group: 'net.sourceforge.htmlunit', name: 'htmlunit', version: '2.35.0'
compile group: 'org.webjars', name: 'jquery', version: '3.3.1-1' implementation group: 'xalan', name: 'xalan', version: '2.7.2'
compile group: 'org.webjars.npm', name: 'jquery.easing', version: '1.4.1'
compile group: 'org.webjars', name: 'font-awesome', version: '4.7.0'
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.5.0' implementation group: 'org.springframework.boot', name: 'spring-boot-starter-test'
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.5.0' testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.10.2'
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test'
} }

View File

@ -100,7 +100,7 @@
<!-- Checks for imports --> <!-- Checks for imports -->
<!-- See http://checkstyle.sf.net/config_import.html --> <!-- See http://checkstyle.sf.net/config_import.html -->
<!--<module name="AvoidStarImport"/>--> <module name="AvoidStarImport"/>
<module name="IllegalImport"/> <!-- defaults to sun.* packages --> <module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<module name="RedundantImport"/> <module name="RedundantImport"/>
<!--module name="UnusedImports"> <!--module name="UnusedImports">
@ -136,7 +136,7 @@
<module name="AvoidNestedBlocks"/> <module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/> <module name="EmptyBlock"/>
<module name="LeftCurly"/> <module name="LeftCurly"/>
<!--<module name="NeedBraces"/>--> <module name="NeedBraces"/>
<module name="RightCurly"/> <module name="RightCurly"/>
<!-- Checks for common coding problems --> <!-- Checks for common coding problems -->

View File

@ -18,6 +18,6 @@ fi
ssh $USERSERVER "cd /tmp && rm -rf $ARTIFACT_NAME*.jar && echo `date` 'killed' >> log_$ARTIFACT_NAME" ssh $USERSERVER "cd /tmp && rm -rf $ARTIFACT_NAME*.jar && echo `date` 'killed' >> log_$ARTIFACT_NAME"
scp build/libs/$ARTIFACT_NAME-0.1.0-SNAPSHOT.jar $USERSERVER:/tmp/$ARTIFACT_NAME-0.1.0-SNAPSHOT.jar scp build/libs/$ARTIFACT_NAME-0.1.0-SNAPSHOT.jar $USERSERVER:/tmp/$ARTIFACT_NAME-0.1.0-SNAPSHOT.jar
ssh $USERSERVER -f "cd /tmp/ && /opt/jdk1.8.0_192/bin/java -jar $ARTIFACT_NAME-0.1.0-SNAPSHOT.jar -Xms 512m -Xmx 1024m --server.port=8443 --server.http.port=8080 --ng-tracker.base-url=http://193.110.3.124:8080 >> /home/user/logfile_$ARTIFACT_NAME" & ssh $USERSERVER -f "cd /tmp/ && /opt/jdk-11/bin/java -jar $ARTIFACT_NAME-0.1.0-SNAPSHOT.jar -Xms 512m -Xmx 1024m --server.port=8080 --server.http.port=8443 --ng-tracker.base-url=http://193.110.3.124:8080 --ng-tracker.dev-mode=false --ng-tracker.driver-path=/home/user >> /home/user/logfile_$ARTIFACT_NAME" &
sleep 10 sleep 10
echo "is deployed" echo "is deployed"

View File

@ -2,4 +2,6 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true

View File

@ -2,13 +2,30 @@ package ru.ulstu;
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.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import ru.ulstu.configuration.ApplicationProperties;
import ru.ulstu.core.repository.JpaDetachableRepositoryImpl; import ru.ulstu.core.repository.JpaDetachableRepositoryImpl;
@SpringBootApplication @SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = JpaDetachableRepositoryImpl.class) @EnableJpaRepositories(repositoryBaseClass = JpaDetachableRepositoryImpl.class)
public class NgTrackerApplication { public class NgTrackerApplication {
private final ApplicationProperties applicationProperties;
public NgTrackerApplication(ApplicationProperties applicationProperties) {
this.applicationProperties = applicationProperties;
}
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(NgTrackerApplication.class, args); SpringApplication.run(NgTrackerApplication.class, args);
} }
@EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
System.out.println("hello world, I have just started up");
if (applicationProperties.isCheckRun()) {
System.exit(0);
}
}
} }

View File

@ -4,20 +4,17 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.configuration.Constants;
import ru.ulstu.core.model.response.PageableItems;
import ru.ulstu.commit.model.CommitListDto; import ru.ulstu.commit.model.CommitListDto;
import ru.ulstu.commit.service.CommitService; import ru.ulstu.commit.service.CommitService;
import ru.ulstu.configuration.Constants;
import ru.ulstu.core.model.response.PageableItems;
import ru.ulstu.core.model.response.Response; import ru.ulstu.core.model.response.Response;
import ru.ulstu.odin.controller.OdinController; import ru.ulstu.odin.controller.OdinController;
import ru.ulstu.odin.model.OdinVoid; import ru.ulstu.odin.model.OdinVoid;
import static ru.ulstu.commit.controller.CommitController.URL;
@RestController @RestController
@RequestMapping(URL) @RequestMapping(Constants.API_1_0 + "commits")
public class CommitController extends OdinController<CommitListDto, OdinVoid> { public class CommitController extends OdinController<CommitListDto, OdinVoid> {
public static final String URL = Constants.API_1_0 + "commits";
private final CommitService commitService; private final CommitService commitService;
public CommitController(CommitService commitService) { public CommitController(CommitService commitService) {

View File

@ -0,0 +1,165 @@
package ru.ulstu.conference.controller;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import ru.ulstu.conference.model.ConferenceDto;
import ru.ulstu.conference.model.ConferenceFilterDto;
import ru.ulstu.conference.model.ConferenceUser;
import ru.ulstu.conference.service.ConferenceService;
import ru.ulstu.user.model.User;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import static ru.ulstu.core.controller.Navigation.CONFERENCES_PAGE;
import static ru.ulstu.core.controller.Navigation.CONFERENCE_PAGE;
import static ru.ulstu.core.controller.Navigation.REDIRECT_TO;
@Controller()
@RequestMapping(value = "/conferences")
@Hidden
public class ConferenceController {
private final ConferenceService conferenceService;
public ConferenceController(ConferenceService conferenceService) {
this.conferenceService = conferenceService;
}
@GetMapping("/conferences")
public void getConferences(ModelMap modelMap) {
modelMap.put("filteredConferences", new ConferenceFilterDto(conferenceService.findAllDto()));
}
@PostMapping("/conferences")
public void filterConferences(@Valid ConferenceFilterDto conferenceFilterDto, ModelMap modelMap) {
modelMap.put("filteredConferences", new ConferenceFilterDto(conferenceService.filter(conferenceFilterDto),
conferenceFilterDto.getFilterUserId(),
conferenceFilterDto.getYear()));
}
@GetMapping("/dashboard")
public void getDashboard(ModelMap modelMap) {
modelMap.put("conferences", conferenceService.findAllActiveDto());
conferenceService.setChartData(modelMap); // example
}
@GetMapping("/conference")
public void getConference(ModelMap modelMap, @RequestParam(value = "id") Integer id) {
if (id != null && id > 0) {
modelMap.put("conferenceDto", conferenceService.getExistConferenceById(id));
} else {
modelMap.put("conferenceDto", conferenceService.getNewConference());
}
}
@PostMapping(value = "/conferences", params = "deleteConference")
public String delete(@RequestParam("deleteConference") Integer conferenceId) throws IOException {
conferenceService.delete(conferenceId);
return String.format(REDIRECT_TO, CONFERENCES_PAGE);
}
@PostMapping(value = "/conference", params = "save")
public String save(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException {
if (!conferenceService.save(conferenceDto, errors)) {
return CONFERENCE_PAGE;
}
return String.format(REDIRECT_TO, CONFERENCES_PAGE);
}
@PostMapping(value = "/conference", params = "addDeadline")
public String addDeadline(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException {
conferenceService.filterEmptyDeadlines(conferenceDto);
if (errors.hasErrors()) {
return CONFERENCE_PAGE;
}
conferenceService.addDeadline(conferenceDto);
return CONFERENCE_PAGE;
}
@PostMapping(value = "/conference", params = "removeDeadline")
public String removeDeadline(@Valid ConferenceDto conferenceDto, Errors errors,
@RequestParam(value = "removeDeadline") Integer deadlineIndex) throws IOException {
if (errors.hasErrors()) {
return CONFERENCE_PAGE;
}
conferenceService.removeDeadline(conferenceDto, deadlineIndex);
return CONFERENCE_PAGE;
}
@PostMapping(value = "/conference", params = "addPaper")
public String addPaper(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException {
if (errors.hasErrors()) {
return CONFERENCE_PAGE;
}
conferenceService.addPaper(conferenceDto);
return CONFERENCE_PAGE;
}
@PostMapping(value = "/conference", params = "removePaper")
public String removePaper(@Valid ConferenceDto conferenceDto, Errors errors,
@RequestParam(value = "removePaper") Integer paperIndex) throws IOException {
if (errors.hasErrors()) {
return CONFERENCE_PAGE;
}
conferenceService.removePaper(conferenceDto, paperIndex);
return CONFERENCE_PAGE;
}
@PostMapping(value = "/conference", params = "takePart")
public String takePart(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException {
if (errors.hasErrors()) {
return CONFERENCE_PAGE;
}
conferenceService.takePart(conferenceDto);
return CONFERENCE_PAGE;
}
@PostMapping(value = "/conference", params = "pingConference")
public String ping(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException {
if (errors.hasErrors()) {
return CONFERENCE_PAGE;
}
conferenceService.ping(conferenceDto);
return CONFERENCE_PAGE;
}
@ModelAttribute("allParticipation")
public List<ConferenceUser.Participation> getAllParticipation() {
return conferenceService.getAllParticipations();
}
@ModelAttribute("allDeposit")
public List<ConferenceUser.Deposit> getAllDeposit() {
return conferenceService.getAllDeposit();
}
@ModelAttribute("allUsers")
public List<User> getAllUsers() {
return conferenceService.getAllUsers();
}
@ModelAttribute("allYears")
public List<Integer> getAllYears() {
List<Integer> years = new ArrayList<>();
for (int i = Calendar.getInstance().get(Calendar.YEAR); i > 2010; i--) {
years.add(i);
}
return years;
}
}

View File

@ -0,0 +1,177 @@
package ru.ulstu.conference.model;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OrderBy;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.validation.constraints.NotBlank;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.format.annotation.DateTimeFormat;
import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.core.model.EventSource;
import ru.ulstu.core.model.UserActivity;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.paper.model.Paper;
import ru.ulstu.timeline.model.Event;
import ru.ulstu.user.model.User;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@Entity
@Table(name = "conference")
@DiscriminatorValue("CONFERENCE")
public class Conference extends BaseEntity implements UserActivity, EventSource {
@NotBlank
private String title;
private String description;
private String url;
private int ping = 0;
@Column(name = "begin_date")
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date beginDate = new Date();
@Column(name = "end_date")
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date endDate = new Date();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "conference_id", unique = true)
@Fetch(FetchMode.SUBSELECT)
@OrderBy("date")
private List<Deadline> deadlines = new ArrayList<>();
@OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
@JoinColumn(name = "conference_id")
private List<Paper> papers = new ArrayList<>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "conference_id", unique = true)
private List<ConferenceUser> users = new ArrayList<>();
public Conference() {
}
public Conference(@NotBlank String title) {
this.title = title;
}
public String getTitle() {
return title;
}
@Override
public List<User> getRecipients() {
List<User> list = new ArrayList<>();
getUsers().forEach(conferenceUser -> list.add(conferenceUser.getUser()));
return list;
}
@Override
public void addObjectToEvent(Event event) {
event.setConference(this);
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPing() {
return ping;
}
public void setPing(int ping) {
this.ping = ping;
}
public Date getBeginDate() {
return beginDate;
}
public void setBeginDate(Date beginDate) {
this.beginDate = beginDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public List<Deadline> getDeadlines() {
return deadlines;
}
public void setDeadlines(List<Deadline> deadlines) {
this.deadlines = deadlines;
}
public List<Paper> getPapers() {
return papers;
}
public void setPapers(List<Paper> papers) {
this.papers = papers;
}
public List<ConferenceUser> getUsers() {
return users;
}
public void setUsers(List<ConferenceUser> users) {
this.users = users;
}
public Optional<Deadline> getNextDeadline() {
return deadlines
.stream()
.filter(deadline -> deadline.getDate() != null)
.sorted(Comparator.comparing(Deadline::getDate))
.filter(d -> d.getDate().after(new Date()))
.findFirst();
}
@Override
public Set<User> getActivityUsers() {
return getUsers().stream().map(ConferenceUser::getUser).collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,253 @@
package ru.ulstu.conference.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import org.springframework.format.annotation.DateTimeFormat;
import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.name.NameContainer;
import ru.ulstu.paper.model.Paper;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import static ru.ulstu.core.util.StreamApiUtils.convert;
public class ConferenceDto extends NameContainer {
private final static String BEGIN_DATE = "Начало: ";
private final static String END_DATE = "Конец: ";
private Integer id;
@NotEmpty
@Size(min = 2, max = 400)
private String title;
@Size(max = 500)
private String description = "";
@Size(max = 255)
private String url = "";
private int ping = 0;
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date beginDate = new Date();
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date endDate = new Date();
private List<Deadline> deadlines = new ArrayList<>();
private List<Integer> removedDeadlineIds = new ArrayList<>();
private List<Integer> userIds = new ArrayList<>();
private List<Integer> paperIds = new ArrayList<>();
private List<Paper> papers = new ArrayList<>();
private List<Paper> notSelectedPapers = new ArrayList<>();
private List<ConferenceUser> users = new ArrayList<>();
private boolean disabledTakePart = false;
public ConferenceDto() {
}
@JsonCreator
public ConferenceDto(@JsonProperty("id") Integer id,
@JsonProperty("title") String title,
@JsonProperty("description") String description,
@JsonProperty("url") String url,
@JsonProperty("ping") Integer ping,
@JsonProperty("beginDate") Date beginDate,
@JsonProperty("endDate") Date endDate,
@JsonProperty("deadlines") List<Deadline> deadlines,
@JsonProperty("userIds") List<Integer> userIds,
@JsonProperty("paperIds") List<Integer> paperIds,
@JsonProperty("users") List<ConferenceUser> users,
@JsonProperty("papers") List<Paper> papers,
@JsonProperty("notSelectedPapers") List<Paper> notSelectedPapers,
@JsonProperty("notSelectedPapers") Boolean disabledTakePart) {
this.id = id;
this.title = title;
this.description = description;
this.url = url;
this.ping = ping;
this.beginDate = beginDate;
this.endDate = endDate;
this.deadlines = deadlines;
this.userIds = userIds;
this.paperIds = paperIds;
this.users = users;
this.papers = papers;
this.notSelectedPapers = notSelectedPapers;
this.disabledTakePart = disabledTakePart;
}
public ConferenceDto(Conference conference) {
this.id = conference.getId();
this.title = conference.getTitle();
this.description = conference.getDescription();
this.url = conference.getUrl();
this.ping = conference.getPing();
this.beginDate = conference.getBeginDate();
this.endDate = conference.getEndDate();
this.deadlines = conference.getDeadlines();
this.userIds = convert(conference.getUsers(), BaseEntity::getId);
this.paperIds = convert(conference.getPapers(), BaseEntity::getId);
this.users = conference.getUsers();
this.papers = conference.getPapers();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPing() {
return ping;
}
public void setPing(int ping) {
this.ping = ping;
}
public Date getBeginDate() {
return beginDate;
}
public void setBeginDate(Date beginDate) {
this.beginDate = beginDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public List<Deadline> getDeadlines() {
return deadlines;
}
public void setDeadlines(List<Deadline> deadlines) {
this.deadlines = deadlines;
}
public List<Integer> getUserIds() {
return userIds;
}
public void setUserIds(List<Integer> userIds) {
this.userIds = userIds;
}
public List<Integer> getPaperIds() {
return paperIds;
}
public void setPaperIds(List<Integer> paperIds) {
this.paperIds = paperIds;
}
public List<Paper> getPapers() {
return papers;
}
public void setPapers(List<Paper> papers) {
this.papers = papers;
}
public List<ConferenceUser> getUsers() {
return users;
}
public void setUsers(List<ConferenceUser> users) {
this.users = users;
}
public boolean isDisabledTakePart() {
return disabledTakePart;
}
public void setDisabledTakePart(boolean disabledTakePart) {
this.disabledTakePart = disabledTakePart;
}
public List<Integer> getRemovedDeadlineIds() {
return removedDeadlineIds;
}
public void setRemovedDeadlineIds(List<Integer> removedDeadlineIds) {
this.removedDeadlineIds = removedDeadlineIds;
}
public List<Paper> getNotSelectedPapers() {
return notSelectedPapers;
}
public void setNotSelectedPapers(List<Paper> notSelectedPapers) {
this.notSelectedPapers = notSelectedPapers;
}
public String getDatesString() {
return BEGIN_DATE + beginDate.toString().split(" ")[0] + " " + END_DATE + endDate.toString().split(" ")[0];
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ConferenceDto that = (ConferenceDto) o;
return ping == that.ping &&
disabledTakePart == that.disabledTakePart &&
Objects.equals(id, that.id) &&
Objects.equals(title, that.title) &&
Objects.equals(description, that.description) &&
Objects.equals(url, that.url) &&
Objects.equals(deadlines, that.deadlines) &&
Objects.equals(removedDeadlineIds, that.removedDeadlineIds) &&
Objects.equals(userIds, that.userIds) &&
Objects.equals(paperIds, that.paperIds) &&
Objects.equals(papers, that.papers) &&
Objects.equals(notSelectedPapers, that.notSelectedPapers) &&
Objects.equals(users, that.users);
}
@Override
public int hashCode() {
return Objects.hash(id, title, description, url, ping, beginDate, endDate, deadlines, removedDeadlineIds,
userIds, paperIds, papers, notSelectedPapers, users, disabledTakePart);
}
}

View File

@ -0,0 +1,47 @@
package ru.ulstu.conference.model;
import java.util.List;
public class ConferenceFilterDto {
private List<ConferenceDto> conferences;
private Integer filterUserId;
private Integer year;
public ConferenceFilterDto() {
}
public ConferenceFilterDto(List<ConferenceDto> conferences, Integer filterUserId, Integer year) {
this.conferences = conferences;
this.filterUserId = filterUserId;
this.year = year;
}
public ConferenceFilterDto(List<ConferenceDto> conferences) {
this(conferences, null, null);
}
public List<ConferenceDto> getConferences() {
return conferences;
}
public void setConferences(List<ConferenceDto> conferences) {
this.conferences = conferences;
}
public Integer getFilterUserId() {
return filterUserId;
}
public void setFilterUserId(Integer filterUserId) {
this.filterUserId = filterUserId;
}
public Integer getYear() {
return year;
}
public void setYear(Integer year) {
this.year = year;
}
}

View File

@ -0,0 +1,110 @@
package ru.ulstu.conference.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.user.model.User;
@Entity
@Table(name = "users_conference")
public class ConferenceUser extends BaseEntity {
public enum Participation {
INTRAMURAL("Очная"),
EXTRAMURAL("Заочная");
private final String participationName;
Participation(String name) {
this.participationName = name;
}
public String getParticipation() {
return participationName;
}
}
public enum Deposit {
ARTICLE("Статья"),
REPORT("Доклад"),
PRESENTATION("Презентация");
private final String depositName;
Deposit(String name) {
this.depositName = name;
}
public String getDeposit() {
return depositName;
}
}
@NotNull
@Column(name = "participation", nullable = false)
@Enumerated(value = EnumType.STRING)
private Participation participation = Participation.INTRAMURAL;
@NotNull
@Column(name = "deposit", nullable = false)
@Enumerated(value = EnumType.STRING)
private Deposit deposit = Deposit.ARTICLE;
@ManyToOne(optional = false)
@JoinColumn(name = "users_id")
private User user;
public ConferenceUser() {
}
public ConferenceUser(User user) {
this.user = user;
this.deposit = Deposit.REPORT;
}
@JsonCreator
public ConferenceUser(@JsonProperty("id") Integer id,
@JsonProperty("deposit") Participation participation,
@JsonProperty("deposit") Deposit deposit,
@JsonProperty("user") User user) {
this.setId(id);
this.participation = participation;
this.deposit = deposit;
this.user = user;
}
public Participation getParticipation() {
return participation;
}
public void setParticipation(Participation participation) {
this.participation = participation;
}
public Deposit getDeposit() {
return deposit;
}
public void setDeposit(Deposit deposit) {
this.deposit = deposit;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

View File

@ -0,0 +1,36 @@
package ru.ulstu.conference.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.conference.model.Conference;
import ru.ulstu.name.BaseRepository;
import ru.ulstu.user.model.User;
import java.util.Date;
import java.util.List;
public interface ConferenceRepository extends JpaRepository<Conference, Integer>, BaseRepository {
@Query("SELECT c FROM Conference c LEFT JOIN c.users u WHERE (:user IS NULL OR u.user = :user) " +
"AND (YEAR(c.beginDate) = :year OR :year IS NULL) ORDER BY c.beginDate DESC")
List<Conference> findByUserAndYear(@Param("user") User user, @Param("year") Integer year);
@Query("SELECT c FROM Conference c WHERE c.beginDate > :date")
List<Conference> findAllActive(@Param("date") Date date);
@Query("SELECT case when count(c) > 0 then true else false end FROM Conference c JOIN c.papers p WHERE p.id = :paperId")
boolean isPaperAttached(@Param("paperId") Integer paperId);
@Modifying
@Query("UPDATE Conference c SET c.ping = (c.ping + 1) WHERE c.id = :id")
int updatePingConference(@Param("id") Integer id);
@Override
@Query("SELECT title FROM Conference c WHERE (c.title = :name) AND (:id IS NULL OR c.id != :id) ")
List<String> findByNameAndNotId(@Param("name") String name, @Param("id") Integer id);
@Query("SELECT c FROM Conference c LEFT JOIN c.users u WHERE (:user IS NULL OR u.user = :user) " +
"AND (u.participation = 'INTRAMURAL') AND (c.beginDate <= CURRENT_DATE) AND (c.endDate >= CURRENT_DATE)")
Conference findActiveByUser(@Param("user") User user);
}

View File

@ -0,0 +1,7 @@
package ru.ulstu.conference.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.conference.model.ConferenceUser;
public interface ConferenceUserRepository extends JpaRepository<ConferenceUser, Integer> {
}

View File

@ -0,0 +1,112 @@
package ru.ulstu.conference.service;
import org.springframework.stereotype.Service;
import ru.ulstu.conference.model.Conference;
import ru.ulstu.core.util.DateUtils;
import ru.ulstu.ping.service.PingService;
import ru.ulstu.user.service.MailService;
import ru.ulstu.user.service.UserService;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class ConferenceNotificationService {
private final static int YESTERDAY = -1;
private final static int DAYS_TO_DEADLINE_NOTIFICATION = 7;
private final static String TEMPLATE_PING = "conferencePingNotification";
private final static String TEMPLATE_DEADLINE = "conferenceDeadlineNotification";
private final static String TEMPLATE_CREATE = "conferenceCreateNotification";
private final static String TEMPLATE_UPDATE_DEADLINES = "conferenceUpdateDeadlinesNotification";
private final static String TEMPLATE_UPDATE_DATES = "conferenceUpdateDatesNotification";
private final static String TITLE_PING = "Обратите внимание на конференцию: %s";
private final static String TITLE_DEADLINE = "Приближается дедлайн конференции: %s";
private final static String TITLE_CREATE = "Создана новая конференция: %s";
private final static String TITLE_UPDATE_DEADLINES = "Изменения дедлайнов в конференции: %s";
private final static String TITLE_UPDATE_DATES = "Изменение дат проведения конференции: %s";
private final MailService mailService;
private final UserService userService;
private final PingService pingService;
public ConferenceNotificationService(MailService mailService,
UserService userService,
PingService pingService) {
this.mailService = mailService;
this.userService = userService;
this.pingService = pingService;
}
public void sendDeadlineNotifications(List<Conference> conferences) {
Date now = DateUtils.addDays(new Date(), DAYS_TO_DEADLINE_NOTIFICATION);
conferences
.stream()
.filter(conference -> needToSendDeadlineNotification(conference, now))
.forEach(this::sendMessageDeadline);
}
private boolean needToSendDeadlineNotification(Conference conference, Date compareDate) {
return (conference.getNextDeadline().isPresent())
&& conference.getNextDeadline().get().getDate().after(new Date())
&& conference.getNextDeadline().get().getDate().before(compareDate);
}
private void sendMessageDeadline(Conference conference) {
Map<String, Object> variables = Map.of("conference", conference);
sendForAllParticipants(variables, conference, TEMPLATE_DEADLINE, String.format(TITLE_DEADLINE, conference.getTitle()));
}
public void sendCreateNotification(Conference conference) {
Map<String, Object> variables = Map.of("conference", conference);
sendForAllUsers(variables, String.format(TITLE_CREATE, conference.getTitle()));
}
public void updateDeadlineNotification(Conference conference) {
Map<String, Object> variables = Map.of("conference", conference);
sendForAllParticipants(variables, conference, TEMPLATE_UPDATE_DEADLINES, String.format(TITLE_UPDATE_DEADLINES, conference.getTitle()));
}
public void updateConferencesDatesNotification(Conference conference, Date oldBeginDate, Date oldEndDate) {
Map<String, Object> variables = Map.of("conference", conference, "oldBeginDate", oldBeginDate, "oldEndDate", oldEndDate);
sendForAllParticipants(variables, conference, TEMPLATE_UPDATE_DATES, String.format(TITLE_UPDATE_DATES, conference.getTitle()));
}
private void sendForAllUsers(Map<String, Object> variables, String title) {
userService.findAll().forEach(user -> mailService.sendEmailFromTemplate(variables, user, ConferenceNotificationService.TEMPLATE_CREATE, title));
}
private void sendForAllParticipants(Map<String, Object> variables, Conference conference, String template, String title) {
conference.getUsers().forEach(conferenceUser -> mailService.sendEmailFromTemplate(variables, conferenceUser.getUser(), template, title));
}
public void sendPingNotifications(List<Conference> conferences) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.DAY_OF_MONTH, YESTERDAY);
conferences
.stream()
.filter(conference -> {
Integer pingCount = pingService.countPingYesterday(conference, calendar);
return needToSendPingNotification(conference, pingCount);
})
.forEach(this::sendMessagePing);
}
private boolean needToSendPingNotification(Conference conference, Integer pingCount) {
if (pingCount > 0) {
conference.setPing((Integer) pingCount);
return true;
}
return false;
}
private void sendMessagePing(Conference conference) {
Map<String, Object> variables = Map.of("conference", conference);
sendForAllParticipants(variables, conference, TEMPLATE_PING, String.format(TITLE_PING, conference.getTitle()));
}
}

View File

@ -0,0 +1,37 @@
package ru.ulstu.conference.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class ConferenceScheduler {
private final static boolean IS_DEADLINE_NOTIFICATION_BEFORE_WEEK = true;
private final Logger log = LoggerFactory.getLogger(ConferenceScheduler.class);
private final ConferenceNotificationService conferenceNotificationService;
private final ConferenceService conferenceService;
public ConferenceScheduler(ConferenceNotificationService conferenceNotificationService,
ConferenceService conferenceService) {
this.conferenceNotificationService = conferenceNotificationService;
this.conferenceService = conferenceService;
}
@Scheduled(cron = "0 0 8 * * MON", zone = "Europe/Samara")
public void checkDeadlineBeforeWeek() {
log.debug("ConferenceScheduler.checkDeadlineBeforeWeek started");
conferenceNotificationService.sendDeadlineNotifications(conferenceService.findAll());
log.debug("ConferenceScheduler.checkDeadlineBeforeWeek finished");
}
@Scheduled(cron = "0 0 8 * * *", zone = "Europe/Samara")
public void checkNewPing() {
log.debug("ConferenceScheduler.checkPing started");
conferenceNotificationService.sendPingNotifications(conferenceService.findAll());
log.debug("ConferenceScheduler.checkPing finished");
}
}

View File

@ -0,0 +1,358 @@
package ru.ulstu.conference.service;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors;
import ru.ulstu.conference.model.Conference;
import ru.ulstu.conference.model.ConferenceDto;
import ru.ulstu.conference.model.ConferenceFilterDto;
import ru.ulstu.conference.model.ConferenceUser;
import ru.ulstu.conference.repository.ConferenceRepository;
import ru.ulstu.core.util.DateUtils;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.deadline.service.DeadlineService;
import ru.ulstu.name.BaseService;
import ru.ulstu.paper.model.Paper;
import ru.ulstu.paper.service.PaperService;
import ru.ulstu.ping.service.PingService;
import ru.ulstu.timeline.service.EventService;
import ru.ulstu.user.model.User;
import ru.ulstu.user.service.UserService;
import java.io.IOException;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
import static org.springframework.util.ObjectUtils.isEmpty;
import static ru.ulstu.core.util.StreamApiUtils.convert;
@Service
public class ConferenceService extends BaseService {
private final static int MAX_DISPLAY_SIZE = 40;
private final ConferenceRepository conferenceRepository;
private final ConferenceUserService conferenceUserService;
private final DeadlineService deadlineService;
private final PaperService paperService;
private final UserService userService;
private final PingService pingService;
private final ConferenceNotificationService conferenceNotificationService;
private final EventService eventService;
public ConferenceService(ConferenceRepository conferenceRepository,
ConferenceUserService conferenceUserService,
DeadlineService deadlineService,
PaperService paperService,
UserService userService,
PingService pingService,
ConferenceNotificationService conferenceNotificationService,
EventService eventService) {
this.baseRepository = conferenceRepository;
this.conferenceRepository = conferenceRepository;
this.conferenceUserService = conferenceUserService;
this.deadlineService = deadlineService;
this.paperService = paperService;
this.userService = userService;
this.pingService = pingService;
this.conferenceNotificationService = conferenceNotificationService;
this.eventService = eventService;
}
public ConferenceDto getExistConferenceById(Integer id) {
ConferenceDto conferenceDto = new ConferenceDto(conferenceRepository.getOne(id));
conferenceDto.setNotSelectedPapers(getNotSelectPapers(conferenceDto.getPaperIds()));
conferenceDto.setDisabledTakePart(isCurrentUserParticipant(conferenceDto.getUsers()));
return conferenceDto;
}
public ConferenceDto getNewConference() {
ConferenceDto conferenceDto = new ConferenceDto();
conferenceDto.setNotSelectedPapers(getNotSelectPapers(new ArrayList<>()));
return conferenceDto;
}
public List<Conference> findAll() {
return conferenceRepository.findAll(Sort.by(Sort.Direction.DESC, "beginDate"));
}
public List<ConferenceDto> findAllDto() {
List<ConferenceDto> conferences = convert(findAll(), ConferenceDto::new);
conferences.forEach(conferenceDto -> conferenceDto.setTitle(StringUtils.abbreviate(conferenceDto.getTitle(), MAX_DISPLAY_SIZE)));
return conferences;
}
public boolean save(ConferenceDto conferenceDto, Errors errors) throws IOException {
conferenceDto.setName(conferenceDto.getTitle());
filterEmptyDeadlines(conferenceDto);
checkEmptyFieldsOfDeadline(conferenceDto, errors);
checkEmptyFieldsOfDates(conferenceDto, errors);
checkUniqueName(conferenceDto,
errors,
conferenceDto.getId(),
"Конференция с таким именем уже существует");
if (errors.hasErrors()) {
return false;
}
if (isEmpty(conferenceDto.getId())) {
create(conferenceDto);
} else {
update(conferenceDto);
}
return true;
}
public Conference save(Conference conference) {
if (isEmpty(conference.getId())) {
return create(conference);
} else {
return update(conference);
}
}
@Transactional
public Conference create(ConferenceDto conferenceDto) throws IOException {
return create(copyFromDto(new Conference(), conferenceDto));
}
@Transactional
public Conference create(Conference conference) {
conference = conferenceRepository.save(conference);
conferenceNotificationService.sendCreateNotification(conference);
return conference;
}
@Transactional
private Conference update(ConferenceDto conferenceDto) throws IOException {
return update(copyFromDto(conferenceRepository.getOne(conferenceDto.getId()), conferenceDto));
}
@Transactional
private Conference update(Conference conference) {
Conference oldConference = conferenceRepository.getOne(conference.getId());
List<Deadline> oldDeadlines = oldConference.getDeadlines().stream()
.map(this::copyDeadline)
.collect(Collectors.toList());
Date oldBeginDate = conference.getBeginDate();
Date oldEndDate = conference.getEndDate();
conferenceRepository.save(conference);
sendNotificationAfterUpdateDeadlines(conference, oldDeadlines);
if (!conference.getBeginDate().equals(oldBeginDate) || !conference.getEndDate().equals(oldEndDate)) {
conferenceNotificationService.updateConferencesDatesNotification(conference, oldBeginDate, oldEndDate);
}
return conference;
}
@Transactional
public boolean delete(Integer conferenceId) {
if (conferenceRepository.existsById(conferenceId)) {
eventService.removeConferencesEvent(conferenceRepository.getOne(conferenceId));
conferenceRepository.deleteById(conferenceId);
return true;
}
return false;
}
@Transactional
public boolean delete(List<Conference> conferences) {
conferences.forEach(conference -> delete(conference.getId()));
return true;
}
public ConferenceDto addDeadline(ConferenceDto conferenceDto) {
conferenceDto.getDeadlines().add(new Deadline());
return conferenceDto;
}
public ConferenceDto removeDeadline(ConferenceDto conferenceDto, Integer deadlineIndex) throws IOException {
if (conferenceDto.getDeadlines().get(deadlineIndex).getId() != null) {
conferenceDto.getRemovedDeadlineIds().add(conferenceDto.getDeadlines().get(deadlineIndex).getId());
}
conferenceDto.getDeadlines().remove((int) deadlineIndex);
return conferenceDto;
}
public ConferenceDto addPaper(ConferenceDto conferenceDto) {
Paper paper = new Paper();
paper.setTitle(userService.getCurrentUser().getLastName() + "_" + conferenceDto.getTitle() + "_" + (new Date()).getTime());
paper.setStatus(Paper.PaperStatus.DRAFT);
conferenceDto.getPapers().add(paper);
return conferenceDto;
}
public ConferenceDto removePaper(ConferenceDto conferenceDto, Integer paperIndex) throws IOException {
Paper removedPaper = conferenceDto.getPapers().remove((int) paperIndex);
if (removedPaper.getId() != null) {
conferenceDto.getNotSelectedPapers().add(removedPaper);
}
return conferenceDto;
}
public ConferenceDto takePart(ConferenceDto conferenceDto) throws IOException {
conferenceDto.getUsers().add(new ConferenceUser(userService.getCurrentUser()));
conferenceDto.setDisabledTakePart(true);
return conferenceDto;
}
private List<Paper> getNotSelectPapers(List<Integer> paperIds) {
return paperService.findAllNotSelect(paperIds);
}
public List<User> getAllUsers() {
return userService.findAll();
}
public List<ConferenceUser.Participation> getAllParticipations() {
return Arrays.asList(ConferenceUser.Participation.values());
}
public List<ConferenceUser.Deposit> getAllDeposit() {
return Arrays.asList(ConferenceUser.Deposit.values());
}
private Conference copyFromDto(Conference conference, ConferenceDto conferenceDto) throws IOException {
conference.setTitle(conferenceDto.getTitle());
conference.setDescription(conferenceDto.getDescription());
conference.setUrl(conferenceDto.getUrl());
conference.setBeginDate(conferenceDto.getBeginDate());
conference.setEndDate(conferenceDto.getEndDate());
conference.getPapers().clear();
conferenceDto.getPapers().forEach(paper -> conference.getPapers().add(paper.getId() != null ? paperService.findPaperById(paper.getId()) : paperService.create(paper)));
conference.setDeadlines(deadlineService.saveOrCreate(conferenceDto.getDeadlines()));
conference.setUsers(conferenceUserService.saveOrCreate(conferenceDto.getUsers()));
if (conferenceDto.getPaperIds() != null && !conferenceDto.getPaperIds().isEmpty()) {
conferenceDto.getPaperIds().forEach(paperId ->
conference.getPapers().add(paperService.findPaperById(paperId)));
}
return conference;
}
private boolean isCurrentUserParticipant(List<ConferenceUser> conferenceUsers) {
return conferenceUsers.stream().anyMatch(participant -> participant.getUser().equals(userService.getCurrentUser()));
}
public List<ConferenceDto> filter(ConferenceFilterDto conferenceFilterDto) {
return convert(conferenceRepository.findByUserAndYear(
conferenceFilterDto.getFilterUserId() == null ? null : userService.findById(conferenceFilterDto.getFilterUserId()),
conferenceFilterDto.getYear()), ConferenceDto::new);
}
public List<ConferenceDto> findAllActiveDto() {
return convert(findAllActive(), ConferenceDto::new);
}
public List<Conference> findAllActive() {
return conferenceRepository.findAllActive(new Date());
}
public boolean isAttachedToConference(Integer paperId) {
return conferenceRepository.isPaperAttached(paperId);
}
@Transactional
public void ping(ConferenceDto conferenceDto) throws IOException {
pingService.addPing(findOne(conferenceDto.getId()));
conferenceRepository.updatePingConference(conferenceDto.getId());
}
public Conference findOne(Integer conferenceId) {
return conferenceRepository.getOne(conferenceId);
}
public void setChartData(ModelMap modelMap) {
//first, add the regional sales
Integer northeastSales = 17089;
Integer westSales = 10603;
Integer midwestSales = 5223;
Integer southSales = 10111;
modelMap.addAttribute("northeastSales", northeastSales);
modelMap.addAttribute("southSales", southSales);
modelMap.addAttribute("midwestSales", midwestSales);
modelMap.addAttribute("westSales", westSales);
//now add sales by lure type
List<Integer> inshoreSales = Arrays.asList(4074, 3455, 4112);
List<Integer> nearshoreSales = Arrays.asList(3222, 3011, 3788);
List<Integer> offshoreSales = Arrays.asList(7811, 7098, 6455);
modelMap.addAttribute("inshoreSales", inshoreSales);
modelMap.addAttribute("nearshoreSales", nearshoreSales);
modelMap.addAttribute("offshoreSales", offshoreSales);
}
private void sendNotificationAfterUpdateDeadlines(Conference conference, List<Deadline> oldDeadlines) {
if (oldDeadlines.size() != conference.getDeadlines().size()) {
conferenceNotificationService.updateDeadlineNotification(conference);
return;
}
if (conference.getDeadlines()
.stream()
.filter(deadline -> !oldDeadlines.contains(deadline))
.count() > 0) {
conferenceNotificationService.updateDeadlineNotification(conference);
}
}
private Deadline copyDeadline(Deadline oldDeadline) {
Deadline newDeadline = new Deadline(oldDeadline.getDate(), oldDeadline.getDescription());
newDeadline.setId(oldDeadline.getId());
return newDeadline;
}
private void checkEmptyFieldsOfDeadline(ConferenceDto conferenceDto, Errors errors) {
for (Deadline deadline : conferenceDto.getDeadlines()) {
if (deadline.getDate() == null || deadline.getDescription().isEmpty()) {
errors.rejectValue("deadlines", "errorCode", "Все поля дедлайна должны быть заполнены");
}
}
}
private void checkEmptyFieldsOfDates(ConferenceDto conferenceDto, Errors errors) {
if (conferenceDto.getBeginDate() == null || conferenceDto.getEndDate() == null) {
errors.rejectValue("beginDate", "errorCode", "Даты должны быть заполнены");
}
}
public void filterEmptyDeadlines(ConferenceDto conferenceDto) {
conferenceDto.setDeadlines(conferenceDto.getDeadlines().stream()
.filter(dto -> dto.getDate() != null || !org.springframework.util.StringUtils.isEmpty(dto.getDescription()))
.collect(Collectors.toList()));
}
public Conference getActiveConferenceByUser(User user) {
return conferenceRepository.findActiveByUser(user);
}
public Conference createByTitle(String newConferenceTitle) {
Conference conference = new Conference(newConferenceTitle);
conference.setBeginDate(DateUtils.localDateToDate(DateUtils.convertToLocalDate(new Date()).plus(1, ChronoUnit.WEEKS)));
conference.setEndDate(DateUtils.localDateToDate(DateUtils.convertToLocalDate(new Date()).plus(2, ChronoUnit.WEEKS)));
conference.getUsers().add(new ConferenceUser(userService.getCurrentUser()));
conference.getDeadlines().add(deadlineService.createWithOffset(new Date(), 1, ChronoUnit.WEEKS));
return save(conference);
}
public List<Conference> findAllActiveByCurrentUser() {
return findAllActive()
.stream()
.filter(conference -> conference.getUsers()
.stream()
.anyMatch(user -> user.getUser().equals(userService.getCurrentUser())))
.collect(toList());
}
}

View File

@ -0,0 +1,46 @@
package ru.ulstu.conference.service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.ulstu.conference.model.ConferenceUser;
import ru.ulstu.conference.repository.ConferenceUserRepository;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ConferenceUserService {
private final ConferenceUserRepository conferenceUserRepository;
public ConferenceUserService(ConferenceUserRepository conferenceUserRepository) {
this.conferenceUserRepository = conferenceUserRepository;
}
public List<ConferenceUser> saveOrCreate(List<ConferenceUser> users) {
return users
.stream()
.map(user -> {
return user.getId() != null ? update(user) : create(user);
}).collect(Collectors.toList());
}
@Transactional
private ConferenceUser update(ConferenceUser user) {
ConferenceUser updateUser = conferenceUserRepository.getOne(user.getId());
updateUser.setDeposit(user.getDeposit());
updateUser.setParticipation(user.getParticipation());
conferenceUserRepository.save(updateUser);
return updateUser;
}
@Transactional
private ConferenceUser create(ConferenceUser user) {
ConferenceUser newUser = new ConferenceUser();
newUser.setDeposit(user.getDeposit());
newUser.setParticipation(user.getParticipation());
newUser.setUser(user.getUser());
newUser = conferenceUserRepository.save(newUser);
return newUser;
}
}

View File

@ -1,6 +1,6 @@
package ru.ulstu.configuration; package ru.ulstu.configuration;
import org.hibernate.validator.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -11,12 +11,20 @@ import org.springframework.validation.annotation.Validated;
public class ApplicationProperties { public class ApplicationProperties {
@NotBlank @NotBlank
private String baseUrl; private String baseUrl;
@NotBlank @NotBlank
private String undeadUserLogin; private String undeadUserLogin;
private boolean devMode; private boolean devMode;
private boolean useHttps; private boolean useHttps;
private boolean checkRun;
private String debugEmail;
private String driverPath;
public boolean isUseHttps() { public boolean isUseHttps() {
return useHttps; return useHttps;
} }
@ -48,4 +56,28 @@ public class ApplicationProperties {
public void setDevMode(boolean devMode) { public void setDevMode(boolean devMode) {
this.devMode = devMode; this.devMode = devMode;
} }
public boolean isCheckRun() {
return checkRun;
}
public void setCheckRun(boolean checkRun) {
this.checkRun = checkRun;
}
public String getDebugEmail() {
return debugEmail;
}
public void setDebugEmail(String debugEmail) {
this.debugEmail = debugEmail;
}
public String getDriverPath() {
return driverPath;
}
public void setDriverPath(String driverPath) {
this.driverPath = driverPath;
}
} }

View File

@ -5,7 +5,11 @@ public class Constants {
public static final String MAIL_ACTIVATE = "Account activation"; public static final String MAIL_ACTIVATE = "Account activation";
public static final String MAIL_RESET = "Password reset"; public static final String MAIL_RESET = "Password reset";
public static final String MAIL_INVITE = "Account registration";
public static final String MAIL_CHANGE_PASSWORD = "Password has been changed";
public static final int MIN_PASSWORD_LENGTH = 6; public static final int MIN_PASSWORD_LENGTH = 6;
public static final int MAX_PASSWORD_LENGTH = 32;
public static final String LOGIN_REGEX = "^[_'.@A-Za-z0-9-]*$"; public static final String LOGIN_REGEX = "^[_'.@A-Za-z0-9-]*$";
@ -17,4 +21,5 @@ public class Constants {
public static final String PASSWORD_RESET_REQUEST_PAGE = "/resetRequest"; public static final String PASSWORD_RESET_REQUEST_PAGE = "/resetRequest";
public static final String PASSWORD_RESET_PAGE = "/reset"; public static final String PASSWORD_RESET_PAGE = "/reset";
public static final int RESET_KEY_LENGTH = 6;
} }

View File

@ -1,30 +0,0 @@
package ru.ulstu.configuration;
import org.eclipse.jetty.server.ServerConnector;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.jetty.JettyServerCustomizer;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HttpListenerConfiguration implements EmbeddedServletContainerCustomizer {
@Value("${server.http.port}")
private int httpPort;
private void configureJetty(JettyEmbeddedServletContainerFactory jettyFactory) {
jettyFactory.addServerCustomizers((JettyServerCustomizer) server -> {
ServerConnector serverConnector = new ServerConnector(server);
serverConnector.setPort(httpPort);
server.addConnector(serverConnector);
});
}
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof JettyEmbeddedServletContainerFactory) {
configureJetty((JettyEmbeddedServletContainerFactory) container);
}
}
}

View File

@ -1,10 +1,10 @@
package ru.ulstu.configuration; package ru.ulstu.configuration;
import nz.net.ultraq.thymeleaf.LayoutDialect; import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect; import org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;
import org.thymeleaf.spring4.SpringTemplateEngine; import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.thymeleaf.templateresolver.ITemplateResolver; import org.thymeleaf.templateresolver.ITemplateResolver;
@ -17,30 +17,17 @@ public class MailTemplateConfiguration {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine(); final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(templateResolver); templateEngine.addTemplateResolver(templateResolver);
templateEngine.addTemplateResolver(emailTemplateResolver()); templateEngine.addTemplateResolver(emailTemplateResolver());
templateEngine.addTemplateResolver(mvcTemplateResolver());
templateEngine.addDialect(new LayoutDialect()); templateEngine.addDialect(new LayoutDialect());
templateEngine.addDialect(sec); templateEngine.addDialect(sec);
return templateEngine; return templateEngine;
} }
public ClassLoaderTemplateResolver emailTemplateResolver() { private ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver(); ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("mail_templates/"); emailTemplateResolver.setPrefix("/mail_templates/");
emailTemplateResolver.setTemplateMode("HTML5"); emailTemplateResolver.setTemplateMode("HTML");
emailTemplateResolver.setSuffix(".html"); emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setOrder(1);
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name()); emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver; return emailTemplateResolver;
} }
public ClassLoaderTemplateResolver mvcTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("templates");
emailTemplateResolver.setTemplateMode("HTML5");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setOrder(2);
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver;
}
} }

View File

@ -3,16 +3,18 @@ package ru.ulstu.configuration;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration @Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter { public class MvcConfiguration implements WebMvcConfigurer {
@Override @Override
public void addViewControllers(ViewControllerRegistry registry) { public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/{articlename:\\w+}"); registry.addViewController("/{articlename:\\w+}");
//registry.addViewController("/admin/{articlename:\\w+}"); registry.addViewController("/admin/{articlename:\\w+}");
registry.addViewController("/papers/{articlename:\\w+}"); registry.addViewController("/papers/{articlename:\\w+}");
registry.addViewController("/grants/{articlename:\\w+}"); registry.addViewController("/grants/{articlename:\\w+}");
registry.addViewController("/conferences/{articlename:\\w+}");
registry.addViewController("/students/{articlename:\\w+}");
registry.addRedirectViewController("/", "/index"); registry.addRedirectViewController("/", "/index");
registry.addRedirectViewController("/default", "/index"); registry.addRedirectViewController("/default", "/index");
} }

View File

@ -5,26 +5,32 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import ru.ulstu.core.model.AuthFailureHandler;
import ru.ulstu.user.controller.UserController; import ru.ulstu.user.controller.UserController;
import ru.ulstu.user.model.UserRoleConstants; import ru.ulstu.user.model.UserRoleConstants;
import ru.ulstu.user.service.UserService; import ru.ulstu.user.service.UserService;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) public class SecurityConfiguration {
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class); private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
@Autowired
private Environment env;
@Value("${server.http.port}") @Value("${server.http.port}")
private int httpPort; private int httpPort;
@Value("${server.port}") @Value("${server.port}")
@ -35,76 +41,77 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final AuthenticationSuccessHandler authenticationSuccessHandler; private final AuthenticationSuccessHandler authenticationSuccessHandler;
private final LogoutSuccessHandler logoutSuccessHandler; private final LogoutSuccessHandler logoutSuccessHandler;
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final AuthenticationFailureHandler authenticationFailureHandler;
public SecurityConfiguration(UserService userService, public SecurityConfiguration(UserService userService,
BCryptPasswordEncoder bCryptPasswordEncoder, BCryptPasswordEncoder bCryptPasswordEncoder,
AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationSuccessHandler authenticationSuccessHandler,
LogoutSuccessHandler logoutSuccessHandler, LogoutSuccessHandler logoutSuccessHandler,
ApplicationProperties applicationProperties) { ApplicationProperties applicationProperties,
AuthFailureHandler authenticationFailureHandler) {
this.userService = userService; this.userService = userService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder; this.bCryptPasswordEncoder = bCryptPasswordEncoder;
this.authenticationSuccessHandler = authenticationSuccessHandler; this.authenticationSuccessHandler = authenticationSuccessHandler;
this.logoutSuccessHandler = logoutSuccessHandler; this.logoutSuccessHandler = logoutSuccessHandler;
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.authenticationFailureHandler = authenticationFailureHandler;
} }
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf() http.csrf(AbstractHttpConfigurer::disable);
.disable();
if (applicationProperties.isDevMode()) { if (applicationProperties.isDevMode()) {
log.debug("Security disabled"); log.debug("Security disabled");
http.authorizeRequests() http.authorizeHttpRequests((authz) -> authz
.anyRequest() .anyRequest()
.permitAll(); .permitAll()
http.anonymous() );
.principal("developer") http.anonymous((anonymousCustomizer) -> anonymousCustomizer
.authorities(UserRoleConstants.ADMIN); .principal("admin")
.authorities(UserRoleConstants.ADMIN)
);
} else { } else {
log.debug("Security enabled"); log.debug("Security enabled");
http.authorizeRequests() http.authorizeHttpRequests((authz) -> authz
.antMatchers(UserController.ACTIVATE_URL).permitAll() .requestMatchers(UserController.ACTIVATE_URL).permitAll()
.antMatchers(Constants.PASSWORD_RESET_REQUEST_PAGE).permitAll() .requestMatchers(Constants.PASSWORD_RESET_REQUEST_PAGE).permitAll()
.antMatchers(Constants.PASSWORD_RESET_PAGE).permitAll() .requestMatchers(Constants.PASSWORD_RESET_PAGE).permitAll()
.antMatchers(UserController.URL + UserController.REGISTER_URL).permitAll() .requestMatchers("/users/block").permitAll()
.antMatchers(UserController.URL + UserController.ACTIVATE_URL).permitAll() .requestMatchers(UserController.URL + UserController.REGISTER_URL).permitAll()
.antMatchers(UserController.URL + UserController.PASSWORD_RESET_REQUEST_URL).permitAll() .requestMatchers(UserController.URL + UserController.ACTIVATE_URL).permitAll()
.antMatchers(UserController.URL + UserController.PASSWORD_RESET_URL).permitAll() .requestMatchers(UserController.URL + UserController.PASSWORD_RESET_REQUEST_URL).permitAll()
.antMatchers("/swagger-ui.html").hasAuthority(UserRoleConstants.ADMIN) .requestMatchers(UserController.URL + UserController.PASSWORD_RESET_URL).permitAll()
.anyRequest().authenticated() .requestMatchers("/swagger-ui.html").hasAuthority(UserRoleConstants.ADMIN)
.and() .anyRequest().authenticated())
.formLogin() .formLogin((formLoginCustomizer) -> formLoginCustomizer
.loginPage("/login") .loginPage("/login")
.successHandler(authenticationSuccessHandler) .successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler)
.permitAll() .permitAll()
.and() )
.logout() .rememberMe(rememberMe -> rememberMe.key("uniqueAndSecret"))
.logout((logoutCustomizer) -> logoutCustomizer
.logoutSuccessHandler(logoutSuccessHandler) .logoutSuccessHandler(logoutSuccessHandler)
.logoutSuccessUrl(Constants.LOGOUT_URL) .logoutSuccessUrl(Constants.LOGOUT_URL)
.invalidateHttpSession(false) .invalidateHttpSession(false)
.clearAuthentication(true) .clearAuthentication(true)
.deleteCookies(Constants.COOKIES_NAME) .deleteCookies(Constants.COOKIES_NAME)
.permitAll(); .permitAll()
);
http.csrf(AbstractHttpConfigurer::disable);
} }
if (applicationProperties.isUseHttps()) { return http.build();
http.portMapper()
.http(httpPort)
.mapsTo(httpsPort)
.and()
.requiresChannel()
.anyRequest()
.requiresSecure();
} }
} @Bean
public WebSecurityCustomizer webSecurityCustomizer() {
@Override return (web) -> web.ignoring()
public void configure(WebSecurity web) { .requestMatchers("/css/**",
web.ignoring() "/javax.faces.resource/**",
.antMatchers("/css/**") "/js/**",
.antMatchers("/js/**") "/templates/**",
.antMatchers("/templates/**") "/webjars/**",
.antMatchers("/webjars/**"); "/img/**");
} }
@Autowired @Autowired

View File

@ -1,23 +0,0 @@
package ru.ulstu.configuration;
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public Docket swaggerApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(Predicates.not(PathSelectors.regex("/error")))
.build();
}
}

View File

@ -4,9 +4,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.validation.FieldError; import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.ModelAttribute;
import ru.ulstu.core.error.EntityIdIsNullException; import ru.ulstu.core.error.EntityIdIsNullException;
import ru.ulstu.core.model.ErrorConstants; import ru.ulstu.core.model.ErrorConstants;
import ru.ulstu.core.model.response.Response; import ru.ulstu.core.model.response.Response;
@ -20,14 +19,25 @@ import ru.ulstu.user.error.UserNotActivatedException;
import ru.ulstu.user.error.UserNotFoundException; import ru.ulstu.user.error.UserNotFoundException;
import ru.ulstu.user.error.UserPasswordsNotValidOrNotMatchException; import ru.ulstu.user.error.UserPasswordsNotValidOrNotMatchException;
import ru.ulstu.user.error.UserResetKeyError; import ru.ulstu.user.error.UserResetKeyError;
import ru.ulstu.user.error.UserSendingMailException;
import ru.ulstu.user.service.UserService;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RestController //@ControllerAdvice
@ControllerAdvice
public class AdviceController { public class AdviceController {
private final Logger log = LoggerFactory.getLogger(AdviceController.class); private final Logger log = LoggerFactory.getLogger(AdviceController.class);
private final UserService userService;
public AdviceController(UserService userService) {
this.userService = userService;
}
@ModelAttribute("flashMessage")
public String getFlashMessage() {
return null;
}
private Response<Void> handleException(ErrorConstants error) { private Response<Void> handleException(ErrorConstants error) {
log.warn(error.toString()); log.warn(error.toString());
@ -97,4 +107,9 @@ public class AdviceController {
public ResponseExtended<String> handleUserIsUndeadException(Throwable e) { public ResponseExtended<String> handleUserIsUndeadException(Throwable e) {
return handleException(ErrorConstants.USER_UNDEAD_ERROR, e.getMessage()); return handleException(ErrorConstants.USER_UNDEAD_ERROR, e.getMessage());
} }
@ExceptionHandler(UserSendingMailException.class)
public ResponseExtended<String> handleUserSendingMailException(Throwable e) {
return handleException(ErrorConstants.USER_SENDING_MAIL_EXCEPTION, e.getMessage());
}
} }

View File

@ -0,0 +1,19 @@
package ru.ulstu.core.controller;
import org.springframework.validation.Errors;
public class Navigation {
public static final String REDIRECT_TO = "redirect:%s";
public static final String GRANTS_PAGE = "/grants/grants";
public static final String GRANT_PAGE = "/grants/grant";
public static final String CONFERENCES_PAGE = "/conferences/conferences";
public static final String CONFERENCE_PAGE = "/conferences/conference";
public static String hasErrors(Errors errors, String page) {
if (errors.hasErrors()) {
return page;
}
return null;
}
}

View File

@ -1,7 +0,0 @@
package ru.ulstu.core.error;
public class XlsLoadException extends Exception {
public XlsLoadException(String s) {
super(s);
}
}

View File

@ -1,7 +0,0 @@
package ru.ulstu.core.error;
public class XlsParseException extends Exception {
public XlsParseException(String s) {
super(s);
}
}

View File

@ -6,19 +6,19 @@ import org.springframework.data.domain.Sort;
import java.io.Serializable; import java.io.Serializable;
public class OffsetablePageRequest implements Pageable, Serializable { public class OffsetablePageRequest implements Pageable, Serializable {
private final int offset; private final long offset;
private final int count; private final int count;
private final Sort sort; private final Sort sort;
public OffsetablePageRequest(int offset, int count) { public OffsetablePageRequest(long offset, int count) {
this(offset, count, null); this(offset, count, null);
} }
public OffsetablePageRequest(int offset, int count, Sort.Direction direction, String... properties) { public OffsetablePageRequest(long offset, int count, Sort.Direction direction, String... properties) {
this(offset, count, new Sort(direction, properties)); this(offset, count, Sort.by(direction, properties));
} }
public OffsetablePageRequest(int offset, int count, Sort sort) { public OffsetablePageRequest(long offset, int count, Sort sort) {
if (offset < 0) { if (offset < 0) {
throw new IllegalArgumentException("Offset value must not be less than zero!"); throw new IllegalArgumentException("Offset value must not be less than zero!");
} }
@ -30,6 +30,12 @@ public class OffsetablePageRequest implements Pageable, Serializable {
this.sort = sort; this.sort = sort;
} }
@Override
public Pageable withPage(int pageNumber) {
//TODO
return null;
}
@Override @Override
public Sort getSort() { public Sort getSort() {
return sort; return sort;
@ -42,11 +48,11 @@ public class OffsetablePageRequest implements Pageable, Serializable {
@Override @Override
public int getPageNumber() { public int getPageNumber() {
return offset / count; return (int) (offset / count);
} }
@Override @Override
public int getOffset() { public long getOffset() {
return offset; return offset;
} }
@ -65,7 +71,7 @@ public class OffsetablePageRequest implements Pageable, Serializable {
return hasPrevious() ? previous() : first(); return hasPrevious() ? previous() : first();
} }
public Pageable previous() { private Pageable previous() {
return getOffset() == 0 ? this : new OffsetablePageRequest(getOffset() - getPageSize(), getPageSize(), getSort()); return getOffset() == 0 ? this : new OffsetablePageRequest(getOffset() - getPageSize(), getPageSize(), getSort());
} }
@ -89,9 +95,9 @@ public class OffsetablePageRequest implements Pageable, Serializable {
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; long result = 1;
result = prime * result + offset; result = prime * result + offset;
result = prime * result + count; result = prime * result + count;
return result; return (int) result;
} }
} }

View File

@ -0,0 +1,21 @@
package ru.ulstu.core.model;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import ru.ulstu.user.error.UserBlockedException;
import java.io.IOException;
@Component
public class AuthFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException ex) throws IOException {
if (ex.getClass() == UserBlockedException.class) {
response.sendRedirect("/users/block");
}
}
}

View File

@ -1,10 +1,16 @@
package ru.ulstu.core.model; package ru.ulstu.core.model;
import javax.persistence.*; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.Version;
import jakarta.validation.constraints.NotNull;
import java.io.Serializable; import java.io.Serializable;
@MappedSuperclass @MappedSuperclass
public abstract class BaseEntity implements Serializable, Comparable { public abstract class BaseEntity implements Serializable, Comparable<BaseEntity> {
@Id @Id
@GeneratedValue(strategy = GenerationType.TABLE) @GeneratedValue(strategy = GenerationType.TABLE)
private Integer id; private Integer id;
@ -12,14 +18,6 @@ public abstract class BaseEntity implements Serializable, Comparable {
@Version @Version
private Integer version; private Integer version;
public BaseEntity() {
}
public BaseEntity(Integer id, Integer version) {
this.id = id;
this.version = version;
}
public Integer getId() { public Integer getId() {
return id; return id;
} }
@ -71,8 +69,8 @@ public abstract class BaseEntity implements Serializable, Comparable {
} }
@Override @Override
public int compareTo(Object o) { public int compareTo(@NotNull BaseEntity o) {
return id != null ? id.compareTo(((BaseEntity) o).getId()) : -1; return id != null ? id.compareTo(o.getId()) : -1;
} }
public void reset() { public void reset() {

View File

@ -6,17 +6,18 @@ public enum ErrorConstants {
VALIDATION_ERROR(2, "Validation error"), VALIDATION_ERROR(2, "Validation error"),
USER_ID_EXISTS(100, "New user can't have id"), USER_ID_EXISTS(100, "New user can't have id"),
USER_ACTIVATION_ERROR(101, "Invalid activation key"), USER_ACTIVATION_ERROR(101, "Invalid activation key"),
USER_EMAIL_EXISTS(102, "User with same email already exists"), USER_EMAIL_EXISTS(102, "Пользователь с таким почтовым ящиком уже существует"),
USER_LOGIN_EXISTS(103, "User with same login already exists"), USER_LOGIN_EXISTS(103, "Пользователь с таким логином уже существует"),
USER_PASSWORDS_NOT_VALID_OR_NOT_MATCH(104, "User passwords is not valid or not match"), USER_PASSWORDS_NOT_VALID_OR_NOT_MATCH(104, "Пароли введены неверно"),
USER_NOT_FOUND(105, "User is not found"), USER_NOT_FOUND(105, "Аккаунт не найден"),
USER_NOT_ACTIVATED(106, "User is not activated"), USER_NOT_ACTIVATED(106, "User is not activated"),
USER_RESET_ERROR(107, "Invalid reset key"), USER_RESET_ERROR(107, "Некорректный ключ подтверждения"),
USER_UNDEAD_ERROR(108, "Can't edit/delete that user"), USER_UNDEAD_ERROR(108, "Can't edit/delete that user"),
FILE_UPLOAD_ERROR(110, "File upload error"); FILE_UPLOAD_ERROR(110, "File upload error"),
USER_SENDING_MAIL_EXCEPTION(111, "Во время отправки приглашения пользователю произошла ошибка");
private int code; private final int code;
private String message; private final String message;
ErrorConstants(int code, String message) { ErrorConstants(int code, String message) {
this.code = code; this.code = code;

View File

@ -0,0 +1,17 @@
package ru.ulstu.core.model;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.timeline.model.Event;
import ru.ulstu.user.model.User;
import java.util.List;
public interface EventSource {
List<Deadline> getDeadlines();
String getTitle();
List<User> getRecipients();
void addObjectToEvent(Event event);
}

View File

@ -1,34 +0,0 @@
package ru.ulstu.core.model;
import java.util.ArrayList;
import java.util.List;
public class TreeDto {
private Integer id;
private String text;
private List<TreeDto> children = new ArrayList<>();
public TreeDto() {
}
public <T extends TreeEntity> TreeDto(TreeEntity item) {
this.text = item.toString();
this.id = item.getId();
}
public TreeDto(String rootName) {
this.text = rootName;
}
public String getText() {
return text;
}
public List<TreeDto> getChildren() {
return children;
}
public Integer getId() {
return id;
}
}

View File

@ -1,16 +0,0 @@
package ru.ulstu.core.model;
import java.util.List;
public interface TreeEntity<T> {
Integer getId();
List<T> getChildren();
void setChildren(List<T> children);
T getParent();
void setParent(T parent);
}

View File

@ -0,0 +1,11 @@
package ru.ulstu.core.model;
import ru.ulstu.user.model.User;
import java.util.Set;
public interface UserActivity {
String getTitle();
Set<User> getActivityUsers();
}

View File

@ -1,9 +0,0 @@
package ru.ulstu.core.model;
import ru.ulstu.user.model.User;
import java.util.Set;
public interface UserContainer {
Set<User> getUsers();
}

View File

@ -1,8 +1,8 @@
package ru.ulstu.core.model.response; package ru.ulstu.core.model.response;
class ControllerResponse<D, E> { class ControllerResponse<D, E> {
private D data; private final D data;
private ControllerResponseError<E> error; private final ControllerResponseError<E> error;
ControllerResponse(D data) { ControllerResponse(D data) {
this.data = data; this.data = data;

View File

@ -3,8 +3,8 @@ package ru.ulstu.core.model.response;
import ru.ulstu.core.model.ErrorConstants; import ru.ulstu.core.model.ErrorConstants;
class ControllerResponseError<D> { class ControllerResponseError<D> {
private ErrorConstants description; private final ErrorConstants description;
private D data; private final D data;
ControllerResponseError(ErrorConstants description, D data) { ControllerResponseError(ErrorConstants description, D data) {
this.description = description; this.description = description;

View File

@ -11,6 +11,6 @@ public class Response<D> extends ResponseEntity<Object> {
} }
public Response(ErrorConstants error) { public Response(ErrorConstants error) {
super(new ControllerResponse<Void, Void>(new ControllerResponseError<>(error, null)), HttpStatus.OK); super(new ControllerResponse<Void, Void>(new ControllerResponseError<>(error, null)), HttpStatus.BAD_REQUEST);
} }
} }

View File

@ -7,6 +7,6 @@ import ru.ulstu.core.model.ErrorConstants;
public class ResponseExtended<E> extends ResponseEntity<Object> { public class ResponseExtended<E> extends ResponseEntity<Object> {
public ResponseExtended(ErrorConstants error, E errorData) { public ResponseExtended(ErrorConstants error, E errorData) {
super(new ControllerResponse<Void, E>(new ControllerResponseError<E>(error, errorData)), HttpStatus.OK); super(new ControllerResponse<Void, E>(new ControllerResponseError<E>(error, errorData)), HttpStatus.BAD_REQUEST);
} }
} }

View File

@ -0,0 +1,69 @@
package ru.ulstu.core.navigation;
public class Page {
public static final String INDEX = "/index.html";
public static final String PAPER = "/paper/paper.html";
public static final String PAPER_LIST = "/paper/papers.html";
public static final String PAPER_DASHBOARD = "/paper/dashboard.html";
public static final String GRANT = "/grant/grant.html";
public static final String GRANT_LIST = "/grant/grants.html";
public static final String GRANT_DASHBOARD = "/grant/dashboard.html";
public static final String USER_LIST = "/admin/users.html";
public static final String LOGOUT = "/logout";
public static final String CONFERENCE = "/conference/conference.html";
public static final String CONFERENCE_DASHBOARD = "/conference/dashboard.html";
public static final String CONFERENCE_LIST = "/conference/conferences.html";
public static final String PROJECT_DASHBOARD = "/conference/dashboard.html";
public String getIndex() {
return INDEX;
}
public String getPaperList() {
return PAPER_LIST;
}
public String getPaperDashboard() {
return PAPER_DASHBOARD;
}
public String getUserList() {
return USER_LIST;
}
public String getLogout() {
return LOGOUT;
}
public String getGrantList() {
return GRANT_LIST;
}
public String getGrantDashboard() {
return GRANT_DASHBOARD;
}
public String getPaper() {
return PAPER;
}
public String getGrant() {
return GRANT;
}
public String getConferenceDashboard() {
return CONFERENCE_DASHBOARD;
}
public String getProjectDashboard() {
return PROJECT_DASHBOARD;
}
public String getConference() {
return CONFERENCE;
}
public String getConferenceList() {
return CONFERENCE_LIST;
}
}

View File

@ -1,14 +1,14 @@
package ru.ulstu.core.repository; package ru.ulstu.core.repository;
import jakarta.persistence.EntityManager;
import org.springframework.data.jpa.repository.support.JpaEntityInformation; import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository; import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import javax.persistence.EntityManager;
import java.io.Serializable; import java.io.Serializable;
public class JpaDetachableRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> public class JpaDetachableRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
implements JpaDetachableRepository<T, ID> { implements JpaDetachableRepository<T, ID> {
private EntityManager entityManager; private final EntityManager entityManager;
public JpaDetachableRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) { public JpaDetachableRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager); super(entityInformation, entityManager);

View File

@ -1,31 +0,0 @@
package ru.ulstu.core.service;
import org.springframework.stereotype.Service;
import ru.ulstu.core.model.TreeDto;
import ru.ulstu.core.model.TreeEntity;
import java.util.List;
import java.util.function.Predicate;
@Service
public class TreeService<T extends TreeEntity> {
public TreeDto getTree(String rootName, List<T> rootItems) {
return addChildNode(new TreeDto(rootName), rootItems, element -> true);
}
public TreeDto getTree(String rootName, List<T> rootItems, Predicate<T> filterPredicate) {
return addChildNode(new TreeDto(rootName), rootItems, filterPredicate);
}
private TreeDto addChildNode(TreeDto currentRoot, List<T> children, Predicate<T> filterPredicate) {
if (children != null) {
children.stream()
.filter(filterPredicate)
.forEach(item -> {
TreeDto newNode = new TreeDto(item);
currentRoot.getChildren().add(addChildNode(newNode, item.getChildren(), filterPredicate));
});
}
return currentRoot;
}
}

View File

@ -1,207 +0,0 @@
package ru.ulstu.core.service;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import ru.ulstu.core.error.XlsParseException;
import java.io.*;
public class XlsDocumentBuilder {
private static final int DEFAULT_SHEET_NUM = 0;
private File documentFile;
private Workbook workBook;
private Sheet currentSheet;
/**
* Constructor for reading and writing data from/to *.[xls|xlsx] document
*
* @param file contains existing document for reading or new document to save
*/
public XlsDocumentBuilder(File file) throws IOException, XlsParseException {
this.documentFile = file;
if (file.exists()) {
workBook = getWorkBook(file);
currentSheet = workBook.getSheetAt(DEFAULT_SHEET_NUM);
} else {
workBook = new XSSFWorkbook();
currentSheet = workBook.createSheet();
}
}
private Workbook getWorkBook(File file) throws XlsParseException, IOException {
InputStream inputStream = new PushbackInputStream(new FileInputStream(file), 4096);
if (isXlsx(inputStream)) {
return new XSSFWorkbook(inputStream);
} else if (isExcel(inputStream)) {
return new HSSFWorkbook(inputStream);
}
throw new XlsParseException("Wrong document format");
}
/**
* Change active sheet to write or read data
*
* @param index index of sheet to activate
*/
public XlsDocumentBuilder setActiveSheet(int index) {
workBook.setActiveSheet(index);
currentSheet = workBook.getSheetAt(index);
return this;
}
/**
* Create new sheet in document and set it active
*
* @param sheetName
*/
public XlsDocumentBuilder insertNewSheet(String sheetName) {
currentSheet = workBook.createSheet(sheetName);
workBook.setActiveSheet(getSheetCount() - 1);
return this;
}
public XlsDocumentBuilder insertNewSheet(String sheetName, int order) {
insertNewSheet(sheetName);
workBook.setSheetOrder(sheetName, order);
return this;
}
/**
* Returns number of sheet in document
*
* @return sheets count
*/
public int getSheetCount() {
return workBook.getNumberOfSheets();
}
/**
* Returns number of rows in sheet
*
* @return rows count
*/
public int getRowCount() {
return currentSheet.getLastRowNum();
}
/**
* Returns number of columns in sheet
*
* @return columns count
*/
public int getColumnCount() {
Row row = currentSheet.getRow(getRowCount());
if (row == null) {
return 0;
}
return row.getLastCellNum() - 1;
}
/**
* Returns converted to string representation of cell value
*
* @param rowIndex row index of current sheet
* @param colIndex column index of current sheet
* @return string value of cell
*/
public String getCellAsString(int rowIndex, int colIndex) {
Cell cell = currentSheet.getRow(rowIndex).getCell(colIndex);
cell.setCellType(Cell.CELL_TYPE_STRING);
return cell.getStringCellValue();
}
/**
* Sets string cell value
*
* @param rowIndex row index of current sheet
* @param colIndex column index of current sheet
*/
public XlsDocumentBuilder setCellValue(int rowIndex, int colIndex, String value) {
if (currentSheet.getRow(rowIndex) == null) {
currentSheet.createRow(rowIndex);
}
if (currentSheet.getRow(rowIndex).getCell(colIndex) == null) {
currentSheet.getRow(rowIndex).createCell(colIndex);
}
Cell cell = currentSheet.getRow(rowIndex).getCell(colIndex);
cell.setCellValue(value);
setColumnAutosize(colIndex, colIndex);
return this;
}
public XlsDocumentBuilder setCellValue(int rowIndex, int colIndex, int value) {
return setCellValue(rowIndex, colIndex, String.valueOf(value));
}
public XlsDocumentBuilder setCellValue(int rowIndex, int colIndex, long value) {
return setCellValue(rowIndex, colIndex, String.valueOf(value));
}
/**
* Save current file
*/
public XlsDocumentBuilder save() throws IOException {
OutputStream out = new FileOutputStream(documentFile);
workBook.write(out);
return this;
}
private boolean isExcel(InputStream i) throws IOException {
return (POIFSFileSystem.hasPOIFSHeader(i) || POIXMLDocument.hasOOXMLHeader(i));
}
private boolean isXlsx(InputStream i) throws IOException {
return POIXMLDocument.hasOOXMLHeader(i);
}
public int getActiveSheetIndex() {
return workBook.getActiveSheetIndex();
}
public XlsDocumentBuilder mergeCells(int rowFrom, int rowTo, int colFrom, int colTo) {
currentSheet.addMergedRegion(new CellRangeAddress(rowFrom, rowTo, colFrom, colTo));
return this;
}
public void setRegionBorderWithMedium(int rowFrom, int rowTo, int colFrom, int colTo) {
for (int row = rowFrom; row < rowTo; row++) {
for (int col = colFrom; col <= colTo; col++) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(row, row, col, col);
RegionUtil.setBorderBottom(CellStyle.BORDER_THIN, cellRangeAddress, currentSheet, workBook);
RegionUtil.setBorderLeft(CellStyle.BORDER_THIN, cellRangeAddress, currentSheet, workBook);
RegionUtil.setBorderRight(CellStyle.BORDER_THIN, cellRangeAddress, currentSheet, workBook);
RegionUtil.setBorderTop(CellStyle.BORDER_THIN, cellRangeAddress, currentSheet, workBook);
}
}
}
public XlsDocumentBuilder setColumnAutosize(int from, int to) {
for (int col = from; col <= to; col++) {
currentSheet.autoSizeColumn(col, true);
}
return this;
}
public XlsDocumentBuilder setRowAutosize(int from, int to) {
CellStyle style = workBook.createCellStyle();
style.setWrapText(true);
for (int row = from; row <= to; row++) {
for (int col = 0; col <= currentSheet.getRow(row).getLastCellNum(); col++) {
if (currentSheet.getRow(row).getCell(col) != null) {
currentSheet.getRow(row).getCell(col).setCellStyle(style);
}
}
}
return this;
}
public XlsDocumentBuilder deleteSheet(int index) {
workBook.removeSheetAt(index);
return this;
}
}

View File

@ -1,6 +1,11 @@
package ru.ulstu.core.util; package ru.ulstu.core.util;
import java.time.*; import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -9,9 +14,12 @@ import java.util.List;
public class DateUtils { public class DateUtils {
public static Date clearTime(Date date) { public static Date clearTime(Date date) {
if (date == null) {
return null;
}
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
calendar.setTime(date); calendar.setTime(date);
calendar.set(Calendar.HOUR, 0); calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0); calendar.set(Calendar.MILLISECOND, 0);
@ -24,7 +32,7 @@ public class DateUtils {
return cal; return cal;
} }
public static List<Month> getMonths () { public static List<Month> getMonths() {
return Arrays.asList(Month.values()); return Arrays.asList(Month.values());
} }
@ -49,4 +57,16 @@ public class DateUtils {
cal.add(Calendar.DAY_OF_MONTH, count); cal.add(Calendar.DAY_OF_MONTH, count);
return cal.getTime(); return cal.getTime();
} }
public static Date addYears(Date date, int count) {
Calendar cal = getCalendar(date);
cal.add(Calendar.YEAR, count);
return cal.getTime();
}
public static LocalDate convertToLocalDate(Date dateToConvert) {
return dateToConvert.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
}
} }

View File

@ -1,17 +0,0 @@
package ru.ulstu.core.util;
public class NumberUtils {
public static Double ceil(Double number) {
if (number == null) {
return 0.0;
}
return Double.valueOf(Math.ceil(number));
}
public static Double round(Double number) {
if (number == null) {
return 0.0;
}
return Double.valueOf(Math.ceil(number * 100)) / 100;
}
}

View File

@ -11,12 +11,12 @@ public class StreamApiUtils {
public static <T, R> List<T> convert(List<R> entities, Function<R, T> converter) { public static <T, R> List<T> convert(List<R> entities, Function<R, T> converter) {
return entities == null return entities == null
? Collections.emptyList() ? Collections.emptyList()
: entities.stream().map(e -> converter.apply(e)).collect(Collectors.toList()); : entities.stream().map(converter).collect(Collectors.toList());
} }
public static <T, R> Set<T> convert(Set<R> entities, Function<R, T> converter) { public static <T, R> Set<T> convert(Set<R> entities, Function<R, T> converter) {
return entities == null return entities == null
? Collections.emptySet() ? Collections.emptySet()
: entities.stream().map(e -> converter.apply(e)).collect(Collectors.toSet()); : entities.stream().map(converter).collect(Collectors.toSet());
} }
} }

View File

@ -1,20 +1,34 @@
package ru.ulstu.deadline.model; package ru.ulstu.deadline.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import org.springframework.format.annotation.DateTimeFormat;
import ru.ulstu.core.model.BaseEntity; import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.user.model.User;
import javax.persistence.Entity;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Objects;
@Entity @Entity
public class Deadline extends BaseEntity { public class Deadline extends BaseEntity {
private String description; private String description;
@Temporal(value = TemporalType.TIMESTAMP) @Temporal(value = TemporalType.DATE)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date date; private Date date;
@OneToMany(targetEntity = User.class, fetch = FetchType.EAGER)
private List<User> executors;
private Boolean done;
public Deadline() { public Deadline() {
} }
@ -23,6 +37,26 @@ public class Deadline extends BaseEntity {
this.description = description; this.description = description;
} }
public Deadline(Date deadlineDate, String description, List<User> executors, Boolean done) {
this.date = deadlineDate;
this.description = description;
this.executors = executors;
this.done = done;
}
@JsonCreator
public Deadline(@JsonProperty("id") Integer id,
@JsonProperty("description") String description,
@JsonProperty("date") Date date,
@JsonProperty("executors") List<User> executors,
@JsonProperty("done") Boolean done) {
this.setId(id);
this.description = description;
this.date = date;
this.executors = executors;
this.done = done;
}
public String getDescription() { public String getDescription() {
return description; return description;
} }
@ -38,4 +72,47 @@ public class Deadline extends BaseEntity {
public void setDate(Date date) { public void setDate(Date date) {
this.date = date; this.date = date;
} }
public List<User> getExecutors() {
return executors;
}
public void setExecutors(List<User> executors) {
this.executors = executors;
}
public Boolean getDone() {
return done;
}
public void setDone(Boolean done) {
this.done = done;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
Deadline deadline = (Deadline) o;
if (getId() == null && deadline.getId() == null &&
description == null && deadline.description == null &&
date == null && deadline.date == null) {
return true;
}
return getId().equals(deadline.getId()) &&
description.equals(deadline.description) &&
date.equals(deadline.date);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), description, date, executors, done);
}
} }

View File

@ -1,58 +0,0 @@
package ru.ulstu.deadline.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
public class DeadlineDto {
private Integer id;
private String description;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date date;
public DeadlineDto() {
}
@JsonCreator
public DeadlineDto(@JsonProperty("id") Integer id,
@JsonProperty("description") String description,
@JsonProperty("date") Date date) {
this.id = id;
this.description = description;
this.date = date;
}
public DeadlineDto(Deadline deadline) {
this.id = deadline.getId();
this.description = deadline.getDescription();
this.date = deadline.getDate();
}
public Integer getId() {
return id;
}
public String getDescription() {
return description;
}
public Date getDate() {
return date;
}
public void setId(Integer id) {
this.id = id;
}
public void setDescription(String description) {
this.description = description;
}
public void setDate(Date date) {
this.date = date;
}
}

View File

@ -2,8 +2,14 @@ package ru.ulstu.deadline.repository;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.deadline.model.Deadline; import ru.ulstu.deadline.model.Deadline;
import java.util.Date;
public interface DeadlineRepository extends JpaRepository<Deadline, Integer> { public interface DeadlineRepository extends JpaRepository<Deadline, Integer> {
@Query("SELECT d.date FROM Grant g JOIN g.deadlines d WHERE (g.id = :id) AND (d.date = :date)")
Date findByGrantIdAndDate(@Param("id") Integer grantId, @Param("date") Date date);
} }

View File

@ -2,10 +2,12 @@ package ru.ulstu.deadline.service;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import ru.ulstu.core.util.DateUtils;
import ru.ulstu.deadline.model.Deadline; import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.deadline.model.DeadlineDto;
import ru.ulstu.deadline.repository.DeadlineRepository; import ru.ulstu.deadline.repository.DeadlineRepository;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -17,29 +19,63 @@ public class DeadlineService {
this.deadlineRepository = deadlineRepository; this.deadlineRepository = deadlineRepository;
} }
public List<Deadline> saveOrCreate(List<DeadlineDto> deadlines) { public List<Deadline> saveOrCreate(List<Deadline> deadlines) {
return deadlines.stream().map(deadlineDto -> { return deadlines
return deadlineDto.getId() != null ? update(deadlineDto) : create(deadlineDto); .stream()
.map(deadline -> {
return deadline.getId() != null ? update(deadline) : create(deadline);
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }
@Transactional @Transactional
public Deadline update(DeadlineDto deadlineDto) { private Deadline update(Deadline deadline) {
Deadline deadline = deadlineRepository.findOne(deadlineDto.getId()); Deadline updateDeadline = deadlineRepository.getOne(deadline.getId());
deadlineRepository.save(copyFromDto(deadline, deadlineDto)); updateDeadline.setDate(deadline.getDate());
return deadline; updateDeadline.setDescription(deadline.getDescription());
updateDeadline.setExecutors(deadline.getExecutors());
updateDeadline.setDone(deadline.getDone());
deadlineRepository.save(updateDeadline);
return updateDeadline;
} }
@Transactional @Transactional
public Deadline create(DeadlineDto deadlineDto) { public Deadline create(Deadline deadline) {
Deadline newDeadline = copyFromDto(new Deadline(), deadlineDto); Deadline newDeadline = new Deadline();
newDeadline.setDate(deadline.getDate());
newDeadline.setDescription(deadline.getDescription());
newDeadline.setExecutors(deadline.getExecutors());
newDeadline.setDone(deadline.getDone());
newDeadline = deadlineRepository.save(newDeadline); newDeadline = deadlineRepository.save(newDeadline);
return newDeadline; return newDeadline;
} }
private Deadline copyFromDto(Deadline deadline, DeadlineDto deadlineDto) { public Deadline create(Date date) {
deadline.setDate(deadlineDto.getDate()); Deadline deadline = new Deadline();
deadline.setDescription(deadlineDto.getDescription()); deadline.setDate(date);
return deadline; return create(deadline);
}
public Deadline create(String description, Date date) {
Deadline deadline = new Deadline();
deadline.setDate(date);
deadline.setDescription(description);
return create(deadline);
}
@Transactional
public void remove(Integer deadlineId) {
deadlineRepository.deleteById(deadlineId);
}
public Date findByGrantIdAndDate(Integer id, Date date) {
return deadlineRepository.findByGrantIdAndDate(id, date);
}
public Deadline createWithOffset(Date date, long value, ChronoUnit chronoUnit) {
return create(DateUtils.localDateToDate(DateUtils.convertToLocalDate(date).plus(value, chronoUnit)));
}
public void delete(List<Deadline> deadlines) {
deadlineRepository.deleteInBatch(deadlines);
} }
} }

View File

@ -13,6 +13,7 @@ import org.springframework.web.multipart.MultipartFile;
import ru.ulstu.configuration.Constants; import ru.ulstu.configuration.Constants;
import ru.ulstu.core.model.response.Response; import ru.ulstu.core.model.response.Response;
import ru.ulstu.file.model.FileData; import ru.ulstu.file.model.FileData;
import ru.ulstu.file.model.FileDataDto;
import ru.ulstu.file.service.FileService; import ru.ulstu.file.service.FileService;
import java.io.IOException; import java.io.IOException;
@ -20,13 +21,10 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import static ru.ulstu.file.FileController.URL;
@RestController @RestController
@RequestMapping(URL) @RequestMapping(Constants.API_1_0 + "files")
public class FileController { public class FileController {
public static final String URL = Constants.API_1_0 + "files";
private final FileService fileService; private final FileService fileService;
public FileController(FileService fileService) { public FileController(FileService fileService) {
@ -51,7 +49,7 @@ public class FileController {
} }
@PostMapping("/uploadTmpFile") @PostMapping("/uploadTmpFile")
public Response<String> upload(@RequestParam("file") MultipartFile multipartFile) throws IOException { public Response<FileDataDto> upload(@RequestParam("file") MultipartFile multipartFile) throws IOException {
return new Response(fileService.uploadToTmpDir(multipartFile)); return new Response<>(fileService.createFromMultipartFile(multipartFile));
} }
} }

View File

@ -1,10 +1,10 @@
package ru.ulstu.file.model; package ru.ulstu.file.model;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import ru.ulstu.core.model.BaseEntity; import ru.ulstu.core.model.BaseEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.Date; import java.util.Date;
@Entity @Entity
@ -19,6 +19,9 @@ public class FileData extends BaseEntity {
private byte[] data; private byte[] data;
@Column(name = "is_latex_attach")
private Boolean isLatexAttach;
public String getName() { public String getName() {
return name; return name;
} }
@ -50,4 +53,12 @@ public class FileData extends BaseEntity {
public void setData(byte[] data) { public void setData(byte[] data) {
this.data = data; this.data = data;
} }
public Boolean isLatexAttach() {
return isLatexAttach;
}
public void setLatexAttach(Boolean latexAttach) {
isLatexAttach = latexAttach;
}
} }

View File

@ -0,0 +1,95 @@
package ru.ulstu.file.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class FileDataDto {
private Integer id;
private String name;
private String fileName;
private String tmpFileName;
private boolean deleted;
private Boolean isLatexAttach;
public FileDataDto() {
}
@JsonCreator
public FileDataDto(@JsonProperty("id") Integer id,
@JsonProperty("name") String name,
@JsonProperty("isLatexAttach") Boolean isLatexAttach,
@JsonProperty("fileName") String fileName,
@JsonProperty("tmpFileName") String tmpFileName) {
this.id = id;
this.name = name;
this.fileName = fileName;
this.tmpFileName = tmpFileName;
this.isLatexAttach = isLatexAttach;
}
public FileDataDto(FileData fileData) {
this.id = fileData.getId();
this.name = fileData.getName();
this.isLatexAttach = fileData.isLatexAttach();
}
public FileDataDto(String fileName, String tmpFileName) {
this.fileName = fileName;
this.tmpFileName = tmpFileName;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getTmpFileName() {
return tmpFileName;
}
public void setTmpFileName(String tmpFileName) {
this.tmpFileName = tmpFileName;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public Boolean isLatexAttach() {
return isLatexAttach;
}
public Boolean getIsLatexAttach() {
return isLatexAttach;
}
public void setLatexAttach(Boolean latexAttach) {
isLatexAttach = latexAttach;
}
public void setIsLatexAttach(Boolean latexAttach) {
isLatexAttach = latexAttach;
}
}

View File

@ -1,15 +1,24 @@
package ru.ulstu.file.service; package ru.ulstu.file.service;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import ru.ulstu.file.model.FileData; import ru.ulstu.file.model.FileData;
import ru.ulstu.file.model.FileDataDto;
import ru.ulstu.file.repostory.FileRepository; import ru.ulstu.file.repostory.FileRepository;
import ru.ulstu.paper.model.PaperDto;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
@ -18,24 +27,24 @@ public class FileService {
private final static int META_FILE_NAME_INDEX = 0; private final static int META_FILE_NAME_INDEX = 0;
private final static int META_FILE_SIZE_INDEX = 1; private final static int META_FILE_SIZE_INDEX = 1;
private String tmpDir; private final String tmpDir;
private FileRepository fileRepository; private final FileRepository fileRepository;
public FileService(FileRepository fileRepository) { public FileService(FileRepository fileRepository) {
tmpDir = System.getProperty("java.io.tmpdir"); tmpDir = System.getProperty("java.io.tmpdir");
this.fileRepository = fileRepository; this.fileRepository = fileRepository;
} }
public FileData createFileFromTmp(String tmpFileName) throws IOException { private FileData createFileFromTmp(String tmpFileName) throws IOException {
FileData fileData = new FileData(); FileData fileData = new FileData();
fileData.setData(getTmpFile(tmpFileName)); fileData.setData(getTmpFile(tmpFileName));
fileData.setName(getTmpFileName(tmpFileName)); fileData.setSize(getTmpFileSize(tmpFileName));
fileData.setCreateDate(new Date()); fileData.setCreateDate(new Date());
return fileRepository.save(fileData); return fileRepository.save(fileData);
} }
public String uploadToTmpDir(MultipartFile multipartFile) throws IOException { private String uploadToTmpDir(MultipartFile multipartFile) throws IOException {
String tmpFileName = String.valueOf(System.currentTimeMillis()); String tmpFileName = String.valueOf(System.currentTimeMillis()) + UUID.randomUUID();
Files.write(getTmpFilePath(tmpFileName), multipartFile.getBytes()); Files.write(getTmpFilePath(tmpFileName), multipartFile.getBytes());
String meta = multipartFile.getOriginalFilename() + "\n" + multipartFile.getSize(); String meta = multipartFile.getOriginalFilename() + "\n" + multipartFile.getSize();
Files.write(getTmpFileMetaPath(tmpFileName), meta.getBytes(UTF_8)); Files.write(getTmpFileMetaPath(tmpFileName), meta.getBytes(UTF_8));
@ -47,7 +56,7 @@ public class FileService {
.split("\n"); .split("\n");
} }
public long getTmpFileSize(String tmpFileName) throws IOException { private long getTmpFileSize(String tmpFileName) throws IOException {
return Long.valueOf(getMeta(tmpFileName)[META_FILE_SIZE_INDEX]).longValue(); return Long.valueOf(getMeta(tmpFileName)[META_FILE_SIZE_INDEX]).longValue();
} }
@ -60,7 +69,7 @@ public class FileService {
} }
public FileData getFile(Integer fileId) { public FileData getFile(Integer fileId) {
return fileRepository.findOne(fileId); return fileRepository.getOne(fileId);
} }
public void deleteTmpFile(String tmpFileName) throws IOException { public void deleteTmpFile(String tmpFileName) throws IOException {
@ -78,4 +87,63 @@ public class FileService {
public void deleteFile(FileData fileData) { public void deleteFile(FileData fileData) {
fileRepository.delete(fileData); fileRepository.delete(fileData);
} }
public List<FileData> saveOrCreate(List<FileDataDto> fileDtos) throws IOException {
List<FileData> files = new ArrayList<>();
for (FileDataDto file : fileDtos) {
files.add(file.getId() != null ? update(file) : create(file));
}
return files;
}
@Transactional
private FileData update(FileDataDto fileDataDto) {
FileData file = fileRepository.getOne(fileDataDto.getId());
return fileRepository.save(copyFromDto(file, fileDataDto));
}
@Transactional
private FileData create(FileDataDto fileDataDto) throws IOException {
FileData newFile = createFileFromTmp(fileDataDto.getTmpFileName());
copyFromDto(newFile, fileDataDto);
return fileRepository.save(newFile);
}
private FileData copyFromDto(FileData fileData, FileDataDto fileDataDto) {
fileData.setName(fileDataDto.getName());
fileData.setLatexAttach(fileDataDto.isLatexAttach());
return fileData;
}
@Transactional
public void delete(Integer fileId) {
fileRepository.delete(fileRepository.getOne(fileId));
}
public FileDataDto createFromMultipartFile(MultipartFile multipartFile) throws IOException {
return new FileDataDto(multipartFile.getOriginalFilename(), uploadToTmpDir(multipartFile));
}
public void createLatexAttachs(PaperDto paper) throws IOException {
for (FileDataDto fileDataDto : paper.getFiles()
.stream()
.filter(f -> (f.isLatexAttach() != null && f.isLatexAttach()) && !f.isDeleted())
.collect(Collectors.toList())) {
if (fileDataDto.getId() == null) {
File oldFile = getTmpFilePath(fileDataDto.getTmpFileName()).toFile();
File renamed = getTmpFilePath(fileDataDto.getName()).toFile();
oldFile.renameTo(renamed);
} else {
Files.write(getTmpFilePath(fileDataDto.getName()), fileRepository.getOne(fileDataDto.getId()).getData());
}
}
}
public File createLatexFile(PaperDto paper) throws IOException {
BufferedWriter writer = Files.newBufferedWriter(getTmpFilePath(paper.getTitle() + ".tex"));
writer.write(paper.getLatexText());
writer.close();
return getTmpFilePath(paper.getTitle() + ".tex").toFile();
}
} }

View File

@ -1,5 +1,7 @@
package ru.ulstu.grant.controller; package ru.ulstu.grant.controller;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
@ -9,21 +11,25 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import ru.ulstu.deadline.model.DeadlineDto; import org.springframework.web.bind.annotation.ResponseBody;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.grant.model.Grant; import ru.ulstu.grant.model.Grant;
import ru.ulstu.grant.model.GrantDto; import ru.ulstu.grant.model.GrantDto;
import ru.ulstu.grant.service.GrantService; import ru.ulstu.grant.service.GrantService;
import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.user.model.User;
import javax.validation.Valid;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.util.StringUtils.isEmpty; import static ru.ulstu.core.controller.Navigation.GRANTS_PAGE;
import static ru.ulstu.core.controller.Navigation.GRANT_PAGE;
import static ru.ulstu.core.controller.Navigation.REDIRECT_TO;
@Controller() @Controller()
@RequestMapping(value = "/grants") @RequestMapping(value = "/grants")
@Hidden
public class GrantController { public class GrantController {
private final GrantService grantService; private final GrantService grantService;
@ -38,54 +44,70 @@ public class GrantController {
@GetMapping("/dashboard") @GetMapping("/dashboard")
public void getDashboard(ModelMap modelMap) { public void getDashboard(ModelMap modelMap) {
modelMap.put("grants", grantService.findAllDto()); modelMap.put("grants", grantService.findAllActiveDto());
} }
@GetMapping("/grant") @GetMapping("/grant")
public void getGrant(ModelMap modelMap, @RequestParam(value = "id") Integer id) { public void getGrant(ModelMap modelMap, @RequestParam(value = "id") Integer id) {
if (id != null && id > 0) { if (id != null && id > 0) {
modelMap.put("grantDto", grantService.findOneDto(id)); GrantDto grantDto = grantService.getExistGrantById(id);
attachPaper(grantDto);
modelMap.put("grantDto", grantDto);
} else { } else {
modelMap.put("grantDto", new GrantDto()); modelMap.put("grantDto", new GrantDto());
} }
} }
@PostMapping(value = "/grant", params = "save") @PostMapping(value = "/grant", params = "save")
public String save(@Valid GrantDto grantDto, Errors errors) throws IOException { public String save(@Valid GrantDto grantDto, Errors errors)
filterEmptyDeadlines(grantDto); throws IOException {
if (grantDto.getDeadlines().isEmpty()) { if (!grantService.save(grantDto, errors)) {
errors.rejectValue("deadlines", "errorCode", "Не может быть пустым"); return GRANT_PAGE;
} }
if (errors.hasErrors()) { return String.format(REDIRECT_TO, GRANTS_PAGE);
return "/grants/grant";
} }
grantService.save(grantDto);
return "redirect:/grants/grants"; @PostMapping(value = "/grant", params = "filterUsers")
public String filterUsers() {
return GRANT_PAGE;
}
@PostMapping(value = "/grant", params = "attachPaper")
public String attachPaper(GrantDto grantDto) {
grantService.attachPaper(grantDto);
return GRANT_PAGE;
} }
@PostMapping(value = "/grant", params = "addDeadline") @PostMapping(value = "/grant", params = "addDeadline")
public String addDeadline(@Valid GrantDto grantDto, Errors errors) { public String addDeadline(@Valid GrantDto grantDto, Errors errors) {
filterEmptyDeadlines(grantDto); grantService.filterEmptyDeadlines(grantDto);
if (errors.hasErrors()) { if (errors.hasErrors()) {
return "/grants/grant"; return GRANT_PAGE;
} }
grantDto.getDeadlines().add(new DeadlineDto()); grantDto.getDeadlines().add(new Deadline());
return "/grants/grant"; return GRANT_PAGE;
}
@PostMapping(value = "/grant", params = "removeDeadline")
public String removeDeadline(GrantDto grantDto,
@RequestParam(value = "removeDeadline") Integer deadlineId) {
grantService.removeDeadline(grantDto, deadlineId);
return GRANT_PAGE;
} }
@PostMapping(value = "/grant", params = "createProject") @PostMapping(value = "/grant", params = "createProject")
public String createProject(@Valid GrantDto grantDto, Errors errors) { public String createProject(@Valid GrantDto grantDto, Errors errors) throws IOException {
if (errors.hasErrors()) { if (errors.hasErrors()) {
return "/grants/grant"; return GRANT_PAGE;
} }
grantService.createProject(grantDto); grantService.createProject(grantDto);
return "/grants/grant"; return GRANT_PAGE;
} }
@GetMapping("/delete/{grant-id}") @GetMapping("/delete/{grant-id}")
public String delete(@PathVariable("grant-id") Integer grantId) throws IOException { public String delete(@PathVariable("grant-id") Integer grantId) throws IOException {
grantService.delete(grantId); grantService.delete(grantId);
return "redirect:/grants/grants"; return String.format(REDIRECT_TO, GRANTS_PAGE);
} }
@ModelAttribute("allStatuses") @ModelAttribute("allStatuses")
@ -93,9 +115,19 @@ public class GrantController {
return grantService.getGrantStatuses(); return grantService.getGrantStatuses();
} }
private void filterEmptyDeadlines(GrantDto grantDto) { @ModelAttribute("allAuthors")
grantDto.setDeadlines(grantDto.getDeadlines().stream() public List<User> getAllAuthors(GrantDto grantDto) {
.filter(dto -> dto.getDate() != null || !isEmpty(dto.getDescription())) return grantService.getGrantAuthors(grantDto);
.collect(Collectors.toList())); }
@ModelAttribute("allPapers")
public List<PaperDto> getAllPapers() {
return grantService.getAllUncompletedPapers();
}
@ResponseBody
@PostMapping(value = "/ping")
public void ping(@RequestParam("grantId") int grantId) throws IOException {
grantService.ping(grantId);
} }
} }

View File

@ -0,0 +1,29 @@
package ru.ulstu.grant.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.configuration.Constants;
import ru.ulstu.grant.service.GrantService;
import java.io.IOException;
import java.text.ParseException;
import static ru.ulstu.paper.controller.PaperRestController.URL;
@RestController
@RequestMapping(URL)
public class GrantRestController {
public static final String URL = Constants.API_1_0 + "grants";
private final GrantService grantService;
public GrantRestController(GrantService grantService) {
this.grantService = grantService;
}
@GetMapping("/grab")
public void grab() throws IOException, ParseException {
grantService.createFromKias();
}
}

View File

@ -1,46 +1,70 @@
package ru.ulstu.grant.model; package ru.ulstu.grant.model;
import org.hibernate.validator.constraints.NotBlank; import jakarta.persistence.CascadeType;
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OrderBy;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import ru.ulstu.core.model.BaseEntity; import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.core.model.EventSource;
import ru.ulstu.core.model.UserActivity;
import ru.ulstu.deadline.model.Deadline; import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.file.model.FileData; import ru.ulstu.file.model.FileData;
import ru.ulstu.paper.model.Paper;
import ru.ulstu.project.model.Project; import ru.ulstu.project.model.Project;
import ru.ulstu.timeline.model.Event;
import ru.ulstu.user.model.User;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
@Entity @Entity
@Table(name = "grants") @Table(name = "grants")
public class Grant extends BaseEntity { @DiscriminatorValue("GRANT")
public class Grant extends BaseEntity implements UserActivity, EventSource {
public enum GrantStatus { public enum GrantStatus {
APPLICATION("Заявка"), APPLICATION("Заявка", "text-draft"),
ON_COMPETITION("Отправлен на конкурс"), ON_COMPETITION("Отправлен на конкурс", "text-review"),
SUCCESSFUL_PASSAGE("Успешное прохождение"), SUCCESSFUL_PASSAGE("Успешное прохождение", "text-accepted"),
IN_WORK("В работе"), IN_WORK("В работе", "text-primary"),
COMPLETED("Завершен"), COMPLETED("Завершен", "text-success"),
FAILED("Провалены сроки"); FAILED("Провалены сроки", "text-failed"),
LOADED_FROM_KIAS("Загружен автоматически", "text-warning"),
SKIPPED("Не интересует", "text-not-accepted");
private String statusName; private final String statusName;
private final String elementClass;
GrantStatus(String statusName) { GrantStatus(String statusName, String elementClass) {
this.statusName = statusName; this.statusName = statusName;
this.elementClass = elementClass;
} }
public String getStatusName() { public String getStatusName() {
return statusName; return statusName;
} }
public String getElementClass() {
return elementClass;
}
} }
@NotBlank @NotBlank
@ -49,23 +73,41 @@ public class Grant extends BaseEntity {
@Enumerated(value = EnumType.STRING) @Enumerated(value = EnumType.STRING)
private GrantStatus status = GrantStatus.APPLICATION; private GrantStatus status = GrantStatus.APPLICATION;
@OneToMany(cascade = CascadeType.ALL) @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "grant_id") @JoinColumn(name = "grant_id")
@OrderBy("date")
private List<Deadline> deadlines = new ArrayList<>(); private List<Deadline> deadlines = new ArrayList<>();
//Описание гранта
@NotNull
private String comment; private String comment;
//Заявка на грант @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@ManyToOne @JoinColumn(name = "grant_id", unique = true)
@JoinColumn(name = "file_id") @Fetch(FetchMode.SUBSELECT)
private FileData application; private List<FileData> files = new ArrayList<>();
@ManyToOne(cascade = CascadeType.ALL) @ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "project_id") @JoinColumn(name = "project_id")
private Project project; private Project project;
@ManyToMany(fetch = FetchType.EAGER)
private Set<User> authors = new HashSet<>();
@NotNull
@ManyToOne
@JoinColumn(name = "leader_id")
private User leader;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "grants_papers",
joinColumns = {@JoinColumn(name = "grant_id")},
inverseJoinColumns = {@JoinColumn(name = "paper_id")})
@Fetch(FetchMode.SUBSELECT)
private List<Paper> papers = new ArrayList<>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "grant_id")
private List<Event> events = new ArrayList<>();
public GrantStatus getStatus() { public GrantStatus getStatus() {
return status; return status;
} }
@ -90,18 +132,28 @@ public class Grant extends BaseEntity {
this.comment = comment; this.comment = comment;
} }
public FileData getApplication() { public List<FileData> getFiles() {
return application; return files;
} }
public void setApplication(FileData application) { public void setFiles(List<FileData> files) {
this.application = application; this.files = files;
} }
public String getTitle() { public String getTitle() {
return title; return title;
} }
@Override
public List<User> getRecipients() {
return authors != null ? new ArrayList<>(authors) : Collections.emptyList();
}
@Override
public void addObjectToEvent(Event event) {
event.setGrant(this);
}
public void setTitle(String title) { public void setTitle(String title) {
this.title = title; this.title = title;
} }
@ -114,6 +166,43 @@ public class Grant extends BaseEntity {
this.project = project; this.project = project;
} }
public Set<User> getAuthors() {
return authors;
}
public void setAuthors(Set<User> authors) {
this.authors = authors;
}
@Override
public Set<User> getActivityUsers() {
return getAuthors();
}
public User getLeader() {
return leader;
}
public void setLeader(User leader) {
this.leader = leader;
}
public List<Paper> getPapers() {
return papers;
}
public void setPapers(List<Paper> papers) {
this.papers = papers;
}
public List<Event> getEvents() {
return events;
}
public void setEvents(List<Event> events) {
this.events = events;
}
public Optional<Deadline> getNextDeadline() { public Optional<Deadline> getNextDeadline() {
return deadlines return deadlines
.stream() .stream()

View File

@ -2,53 +2,105 @@ package ru.ulstu.grant.model;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import ru.ulstu.deadline.model.DeadlineDto; import org.apache.commons.lang3.StringUtils;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.file.model.FileDataDto;
import ru.ulstu.name.NameContainer;
import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.project.model.ProjectDto; import ru.ulstu.project.model.ProjectDto;
import ru.ulstu.user.model.UserDto;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static ru.ulstu.core.util.StreamApiUtils.convert; import static ru.ulstu.core.util.StreamApiUtils.convert;
public class GrantDto { public class GrantDto extends NameContainer {
private final static int MAX_AUTHORS_LENGTH = 60;
private Integer id; private Integer id;
@NotEmpty @NotEmpty
private String title; private String title;
private Grant.GrantStatus status; private Grant.GrantStatus status;
private List<DeadlineDto> deadlines = new ArrayList<>(); private List<Deadline> deadlines = new ArrayList<>();
private String comment; private String comment;
private String applicationFileName; private List<FileDataDto> files = new ArrayList<>();
private ProjectDto project; private ProjectDto project;
private Set<Integer> authorIds;
private Set<UserDto> authors;
private Integer leaderId;
private boolean wasLeader;
private boolean hasAge;
private boolean hasDegree;
private boolean hasBAKPapers;
private boolean hasScopusPapers;
private List<Integer> paperIds = new ArrayList<>();
private List<PaperDto> papers = new ArrayList<>();
private List<Integer> removedDeadlineIds = new ArrayList<>();
public GrantDto() { public GrantDto() {
deadlines.add(new DeadlineDto()); deadlines.add(new Deadline());
} }
@JsonCreator @JsonCreator
public GrantDto(@JsonProperty("id") Integer id, public GrantDto(@JsonProperty("id") Integer id,
@JsonProperty("title") String title, @JsonProperty("title") String title,
@JsonProperty("status") Grant.GrantStatus status, @JsonProperty("status") Grant.GrantStatus status,
@JsonProperty("deadlines") List<DeadlineDto> deadlines, @JsonProperty("deadlines") List<Deadline> deadlines,
@JsonProperty("comment") String comment, @JsonProperty("comment") String comment,
@JsonProperty("project") ProjectDto project) { @JsonProperty("files") List<FileDataDto> files,
@JsonProperty("project") ProjectDto project,
@JsonProperty("authorIds") Set<Integer> authorIds,
@JsonProperty("authors") Set<UserDto> authors,
@JsonProperty("leaderId") Integer leaderId,
@JsonProperty("wasLeader") boolean wasLeader,
@JsonProperty("hasAge") boolean hasAge,
@JsonProperty("hasDegree") boolean hasDegree,
@JsonProperty("paperIds") List<Integer> paperIds,
@JsonProperty("papers") List<PaperDto> papers) {
this.id = id; this.id = id;
this.title = title; this.title = title;
this.status = status; this.status = status;
this.deadlines = deadlines; this.deadlines = deadlines;
this.comment = comment; this.comment = comment;
this.applicationFileName = null; this.files = files;
this.project = project; this.project = project;
this.authorIds = authorIds;
this.authors = authors;
this.leaderId = leaderId;
this.wasLeader = wasLeader;
this.hasAge = hasAge;
this.hasDegree = hasDegree;
this.paperIds = paperIds;
this.papers = papers;
} }
public GrantDto(Grant grant) { public GrantDto(Grant grant) {
this.id = grant.getId(); this.id = grant.getId();
this.title = grant.getTitle(); this.title = grant.getTitle();
this.status = grant.getStatus(); this.status = grant.getStatus();
this.deadlines = convert(grant.getDeadlines(), DeadlineDto::new); this.deadlines = grant.getDeadlines();
this.comment = grant.getComment(); this.comment = grant.getComment();
this.files = convert(grant.getFiles(), FileDataDto::new);
this.project = grant.getProject() == null ? null : new ProjectDto(grant.getProject()); this.project = grant.getProject() == null ? null : new ProjectDto(grant.getProject());
this.applicationFileName = grant.getApplication() == null ? null : grant.getApplication().getName(); this.authorIds = convert(grant.getAuthors(), user -> user.getId());
this.authors = convert(grant.getAuthors(), UserDto::new);
this.leaderId = grant.getLeader().getId();
this.wasLeader = false;
this.hasAge = false;
this.hasDegree = false;
this.paperIds = convert(grant.getPapers(), paper -> paper.getId());
this.papers = convert(grant.getPapers(), PaperDto::new);
}
public GrantDto(String grantTitle, Date deadLineDate) {
this.title = grantTitle;
deadlines.add(new Deadline(deadLineDate, "Окончание приёма заявок"));
status = Grant.GrantStatus.LOADED_FROM_KIAS;
} }
public Integer getId() { public Integer getId() {
@ -75,11 +127,11 @@ public class GrantDto {
this.status = status; this.status = status;
} }
public List<DeadlineDto> getDeadlines() { public List<Deadline> getDeadlines() {
return deadlines; return deadlines;
} }
public void setDeadlines(List<DeadlineDto> deadlines) { public void setDeadlines(List<Deadline> deadlines) {
this.deadlines = deadlines; this.deadlines = deadlines;
} }
@ -91,6 +143,14 @@ public class GrantDto {
this.comment = comment; this.comment = comment;
} }
public List<FileDataDto> getFiles() {
return files;
}
public void setFiles(List<FileDataDto> files) {
this.files = files;
}
public ProjectDto getProject() { public ProjectDto getProject() {
return project; return project;
} }
@ -99,11 +159,98 @@ public class GrantDto {
this.project = project; this.project = project;
} }
public String getApplicationFileName() { public Set<Integer> getAuthorIds() {
return applicationFileName; return authorIds;
} }
public void setApplicationFileName(String applicationFileName) { public void setAuthorIds(Set<Integer> authorIds) {
this.applicationFileName = applicationFileName; this.authorIds = authorIds;
}
public Set<UserDto> getAuthors() {
return authors;
}
public void setAuthors(Set<UserDto> authors) {
this.authors = authors;
}
public String getAuthorsString() {
return StringUtils.abbreviate(authors
.stream()
.map(author -> author.getLastName())
.collect(Collectors.joining(", ")), MAX_AUTHORS_LENGTH);
}
public Integer getLeaderId() {
return leaderId;
}
public void setLeaderId(Integer leaderId) {
this.leaderId = leaderId;
}
public boolean isWasLeader() {
return wasLeader;
}
public void setWasLeader(boolean wasLeader) {
this.wasLeader = wasLeader;
}
public boolean isHasAge() {
return hasAge;
}
public void setHasAge(boolean hasAge) {
this.hasAge = hasAge;
}
public boolean isHasDegree() {
return hasDegree;
}
public void setHasDegree(boolean hasDegree) {
this.hasDegree = hasDegree;
}
public List<Integer> getPaperIds() {
return paperIds;
}
public void setPaperIds(List<Integer> paperIds) {
this.paperIds = paperIds;
}
public List<PaperDto> getPapers() {
return papers;
}
public void setPapers(List<PaperDto> papers) {
this.papers = papers;
}
public List<Integer> getRemovedDeadlineIds() {
return removedDeadlineIds;
}
public void setRemovedDeadlineIds(List<Integer> removedDeadlineIds) {
this.removedDeadlineIds = removedDeadlineIds;
}
public boolean isHasBAKPapers() {
return hasBAKPapers;
}
public void setHasBAKPapers(boolean hasBAKPapers) {
this.hasBAKPapers = hasBAKPapers;
}
public boolean isHasScopusPapers() {
return hasScopusPapers;
}
public void setHasScopusPapers(boolean hasScopusPapers) {
this.hasScopusPapers = hasScopusPapers;
} }
} }

View File

@ -1,19 +0,0 @@
package ru.ulstu.grant.model;
public class GrantStatusDto {
private final String id;
private final String name;
public GrantStatusDto(Grant.GrantStatus status) {
this.id = status.name();
this.name = status.getStatusName();
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,55 @@
package ru.ulstu.grant.page;
import com.gargoylesoftware.htmlunit.html.DomNode;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlTableRow;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class KiasPage {
private final static String KIAS_GRANT_DATE_FORMAT = "dd.MM.yyyy HH:mm";
private final HtmlPage page;
public KiasPage(HtmlPage page) {
this.page = page;
}
public boolean goToNextPage() {
try {
HtmlElement nextPageLink = page.getHtmlElementById("js-ctrlNext");
if (nextPageLink.isDisplayed()) {
nextPageLink.click();
return true;
}
} finally {
return false;
}
}
public List<DomNode> getPageOfGrants() {
return page.getByXPath("/html/body/div[2]/div/div[2]/main/div[1]/table/tbody/tr");
}
public String getGrantTitle(DomNode grant) {
return ((DomNode) grant.getFirstByXPath("td[2]")).getTextContent() + " "
+ ((DomNode) grant.getFirstByXPath("td[@class='tertiary']/a")).getTextContent();
}
public Date parseDeadLineDate(DomNode grantElement) throws ParseException {
String deadlineDate = getFirstDeadline(grantElement); //10.06.2019 23:59
SimpleDateFormat formatter = new SimpleDateFormat(KIAS_GRANT_DATE_FORMAT);
return formatter.parse(deadlineDate);
}
private String getFirstDeadline(DomNode grantElement) {
return ((DomNode) grantElement.getFirstByXPath("td[5]")).getTextContent();
}
public boolean isTableRowGrantLine(DomNode grantElement) {
return !((HtmlTableRow) grantElement).getAttribute("class").contains("pagerSavedHeightSpacer");
}
}

View File

@ -1,8 +1,25 @@
package ru.ulstu.grant.repository; package ru.ulstu.grant.repository;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.grant.model.Grant; import ru.ulstu.grant.model.Grant;
import ru.ulstu.name.BaseRepository;
public interface GrantRepository extends JpaRepository<Grant, Integer> { import java.util.List;
public interface GrantRepository extends JpaRepository<Grant, Integer>, BaseRepository {
List<Grant> findByStatus(Grant.GrantStatus status);
Grant findFirstByTitle(String title);
Grant findGrantById(Integer grantId);
@Override
@Query("SELECT title FROM Grant g WHERE (g.title = :name) AND (:id IS NULL OR g.id != :id) ")
List<String> findByNameAndNotId(@Param("name") String name, @Param("id") Integer id);
@Query("SELECT g FROM Grant g WHERE (g.status <> 'SKIPPED') AND (g.status <> 'COMPLETED')")
List<Grant> findAllActive();
} }

View File

@ -0,0 +1,72 @@
package ru.ulstu.grant.service;
import org.springframework.stereotype.Service;
import ru.ulstu.core.util.DateUtils;
import ru.ulstu.grant.model.Grant;
import ru.ulstu.user.model.User;
import ru.ulstu.user.service.MailService;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Service
public class GrantNotificationService {
private final static int DAYS_TO_DEADLINE_NOTIFICATION = 7;
private final static String TEMPLATE_DEADLINE = "grantDeadlineNotification";
private final static String TEMPLATE_CREATE = "grantCreateNotification";
private final static String TEMPLATE_AUTHORS_CHANGED = "grantAuthorsChangeNotification";
private final static String TEMPLATE_LEADER_CHANGED = "grantLeaderChangeNotification";
private final static String TITLE_DEADLINE = "Приближается дедлайн гранта: %s";
private final static String TITLE_CREATE = "Создан грант: %s";
private final static String TITLE_AUTHORS_CHANGED = "Изменился состав рабочей группы гранта: %s";
private final static String TITLE_LEADER_CHANGED = "Изменился руководитель гранта: %s";
private final MailService mailService;
public GrantNotificationService(MailService mailService) {
this.mailService = mailService;
}
public void sendDeadlineNotifications(List<Grant> grants, boolean isDeadlineBeforeWeek) {
Date now = DateUtils.addDays(new Date(), DAYS_TO_DEADLINE_NOTIFICATION);
grants.stream()
.filter(grant -> needToSendDeadlineNotification(grant, now, isDeadlineBeforeWeek))
.forEach(grant -> sendMessageDeadline(grant));
}
private boolean needToSendDeadlineNotification(Grant grant, Date compareDate, boolean isDeadlineBeforeWeek) {
return (grant.getNextDeadline().isPresent())
&& (compareDate.before(grant.getNextDeadline().get().getDate()) && isDeadlineBeforeWeek
|| compareDate.after(grant.getNextDeadline().get().getDate()) && !isDeadlineBeforeWeek)
&& grant.getNextDeadline().get().getDate().after(new Date());
}
private void sendMessageDeadline(Grant grant) {
Map<String, Object> variables = Map.of("grant", grant);
sendForAllAuthors(variables, grant, TEMPLATE_DEADLINE, String.format(TITLE_DEADLINE, grant.getTitle()));
}
public void sendCreateNotification(Grant grant) {
Map<String, Object> variables = Map.of("grant", grant);
sendForAllAuthors(variables, grant, TEMPLATE_CREATE, String.format(TITLE_CREATE, grant.getTitle()));
}
public void sendAuthorsChangeNotification(Grant grant, Set<User> oldAuthors) {
Map<String, Object> variables = Map.of("grant", grant, "oldAuthors", oldAuthors);
sendForAllAuthors(variables, grant, TEMPLATE_AUTHORS_CHANGED, String.format(TITLE_AUTHORS_CHANGED, grant.getTitle()));
}
public void sendLeaderChangeNotification(Grant grant, User oldLeader) {
Map<String, Object> variables = Map.of("grant", grant, "oldLeader", oldLeader);
sendForAllAuthors(variables, grant, TEMPLATE_LEADER_CHANGED, String.format(TITLE_LEADER_CHANGED, grant.getTitle()));
}
private void sendForAllAuthors(Map<String, Object> variables, Grant grant, String template, String title) {
Set<User> allAuthors = grant.getAuthors();
allAuthors.forEach(author -> mailService.sendEmailFromTemplate(variables, author, template, title));
mailService.sendEmailFromTemplate(variables, grant.getLeader(), template, title);
}
}

View File

@ -0,0 +1,41 @@
package ru.ulstu.grant.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class GrantScheduler {
private final static boolean IS_DEADLINE_NOTIFICATION_BEFORE_WEEK = true;
private final Logger log = LoggerFactory.getLogger(GrantScheduler.class);
private final GrantNotificationService grantNotificationService;
private final GrantService grantService;
public GrantScheduler(GrantNotificationService grantNotificationService,
GrantService grantService) {
this.grantNotificationService = grantNotificationService;
this.grantService = grantService;
}
@Scheduled(cron = "0 0 8 * * MON", zone = "Europe/Samara")
public void checkDeadlineBeforeWeek() {
log.debug("GrantScheduler.checkDeadlineBeforeWeek started");
grantNotificationService.sendDeadlineNotifications(grantService.findAllActive(), IS_DEADLINE_NOTIFICATION_BEFORE_WEEK);
log.debug("GrantScheduler.checkDeadlineBeforeWeek finished");
}
@Scheduled(cron = "0 0 8 * * ?", zone = "Europe/Samara")
public void loadGrantsFromKias() {
log.debug("GrantScheduler.loadGrantsFromKias started");
// try {
// grantService.createFromKias();
// } catch (ParseException | IOException e) {
// e.printStackTrace();
// }
log.debug("GrantScheduler.loadGrantsFromKias finished");
}
}

View File

@ -1,44 +1,86 @@
package ru.ulstu.grant.service; package ru.ulstu.grant.service;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.Errors;
import ru.ulstu.core.util.DateUtils;
import ru.ulstu.deadline.model.Deadline; import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.deadline.service.DeadlineService; import ru.ulstu.deadline.service.DeadlineService;
import ru.ulstu.file.model.FileDataDto;
import ru.ulstu.file.service.FileService; import ru.ulstu.file.service.FileService;
import ru.ulstu.grant.model.Grant; import ru.ulstu.grant.model.Grant;
import ru.ulstu.grant.model.GrantDto; import ru.ulstu.grant.model.GrantDto;
import ru.ulstu.grant.repository.GrantRepository; import ru.ulstu.grant.repository.GrantRepository;
import ru.ulstu.project.model.Project; import ru.ulstu.name.BaseService;
import ru.ulstu.paper.model.Paper;
import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.paper.service.PaperService;
import ru.ulstu.ping.service.PingService;
import ru.ulstu.project.model.ProjectDto; import ru.ulstu.project.model.ProjectDto;
import ru.ulstu.project.service.ProjectService; import ru.ulstu.project.service.ProjectService;
import ru.ulstu.timeline.service.EventService;
import ru.ulstu.user.model.User;
import ru.ulstu.user.service.UserService;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException;
import java.time.temporal.ChronoUnit;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
import static org.springframework.util.ObjectUtils.isEmpty; import static org.springframework.util.ObjectUtils.isEmpty;
import static ru.ulstu.core.util.StreamApiUtils.convert; import static ru.ulstu.core.util.StreamApiUtils.convert;
import static ru.ulstu.grant.model.Grant.GrantStatus.APPLICATION; import static ru.ulstu.grant.model.Grant.GrantStatus.APPLICATION;
@Service @Service
public class GrantService { public class GrantService extends BaseService {
private final static int MAX_DISPLAY_SIZE = 40; private final Logger log = LoggerFactory.getLogger(GrantService.class);
private final GrantRepository grantRepository; private final GrantRepository grantRepository;
private final ProjectService projectService; private final ProjectService projectService;
private final DeadlineService deadlineService; private final DeadlineService deadlineService;
private final FileService fileService; private final FileService fileService;
private final UserService userService;
private final PaperService paperService;
private final EventService eventService;
private final GrantNotificationService grantNotificationService;
private final KiasService kiasService;
private final PingService pingService;
public GrantService(GrantRepository grantRepository, public GrantService(GrantRepository grantRepository,
FileService fileService, FileService fileService,
DeadlineService deadlineService, DeadlineService deadlineService,
ProjectService projectService) { ProjectService projectService,
UserService userService,
PaperService paperService,
EventService eventService,
GrantNotificationService grantNotificationService,
KiasService kiasService,
PingService pingService) {
this.grantRepository = grantRepository; this.grantRepository = grantRepository;
this.projectService = projectService; this.kiasService = kiasService;
this.baseRepository = grantRepository;
this.fileService = fileService; this.fileService = fileService;
this.deadlineService = deadlineService; this.deadlineService = deadlineService;
this.projectService = projectService;
this.userService = userService;
this.paperService = paperService;
this.eventService = eventService;
this.grantNotificationService = grantNotificationService;
this.pingService = pingService;
}
public GrantDto getExistGrantById(Integer id) {
return new GrantDto(findById(id));
} }
public List<Grant> findAll() { public List<Grant> findAll() {
@ -46,20 +88,16 @@ public class GrantService {
} }
public List<GrantDto> findAllDto() { public List<GrantDto> findAllDto() {
List<GrantDto> grants = convert(findAll(), GrantDto::new); return convert(findAll(), GrantDto::new);
grants.forEach(grantDto -> grantDto.setTitle(StringUtils.abbreviate(grantDto.getTitle(), MAX_DISPLAY_SIZE)));
return grants;
}
public GrantDto findOneDto(Integer id) {
return new GrantDto(grantRepository.findOne(id));
} }
@Transactional @Transactional
public Integer create(GrantDto grantDto) throws IOException { public Grant create(GrantDto grantDto) throws IOException {
Grant newGrant = copyFromDto(new Grant(), grantDto); Grant newGrant = copyFromDto(new Grant(), grantDto);
newGrant = grantRepository.save(newGrant); newGrant = grantRepository.save(newGrant);
return newGrant.getId(); eventService.createFromObject(newGrant, Collections.emptyList(), false, "гранта");
grantNotificationService.sendCreateNotification(newGrant);
return newGrant;
} }
private Grant copyFromDto(Grant grant, GrantDto grantDto) throws IOException { private Grant copyFromDto(Grant grant, GrantDto grantDto) throws IOException {
@ -70,59 +108,296 @@ public class GrantService {
grant.setProject(projectService.findById(grantDto.getProject().getId())); grant.setProject(projectService.findById(grantDto.getProject().getId()));
} }
grant.setDeadlines(deadlineService.saveOrCreate(grantDto.getDeadlines())); grant.setDeadlines(deadlineService.saveOrCreate(grantDto.getDeadlines()));
if (grantDto.getApplicationFileName() != null) { if (!grant.getFiles().isEmpty()) {
grant.setApplication(fileService.createFileFromTmp(grantDto.getApplicationFileName())); grant.setFiles(fileService.saveOrCreate(grantDto.getFiles().stream()
.filter(f -> !f.isDeleted())
.collect(toList())));
}
grant.getAuthors().clear();
if (grantDto.getAuthorIds() != null && !grantDto.getAuthorIds().isEmpty()) {
grantDto.getAuthorIds().forEach(authorIds -> grant.getAuthors().add(userService.findById(authorIds)));
}
if (grantDto.getLeaderId() != null) {
grant.setLeader(userService.findById(grantDto.getLeaderId()));
}
grant.getPapers().clear();
if (grantDto.getPaperIds() != null && !grantDto.getPaperIds().isEmpty()) {
grantDto.getPaperIds().forEach(paperIds -> grant.getPapers().add(paperService.findPaperById(paperIds)));
} }
return grant; return grant;
} }
public void createProject(GrantDto grantDto) {
public void createProject(GrantDto grantDto) throws IOException {
grantDto.setProject( grantDto.setProject(
new ProjectDto(projectService.save(new ProjectDto(grantDto.getTitle())))); new ProjectDto(projectService.save(new ProjectDto(grantDto.getTitle()))));
} }
@Transactional @Transactional
public Integer update(GrantDto grantDto) throws IOException { private Integer update(GrantDto grantDto) throws IOException {
Grant grant = grantRepository.findOne(grantDto.getId()); Grant grant = findById(grantDto.getId());
Grant.GrantStatus oldStatus = grant.getStatus(); Set<User> oldAuthors = new HashSet<>(grant.getAuthors());
if (grantDto.getApplicationFileName() != null && grant.getApplication() != null) { User oldLeader = grant.getLeader();
fileService.deleteFile(grant.getApplication()); for (FileDataDto file : grantDto.getFiles().stream()
.filter(f -> f.isDeleted() && f.getId() != null)
.collect(toList())) {
fileService.delete(file.getId());
} }
grantDto.getRemovedDeadlineIds().forEach(deadlineService::remove);
grantRepository.save(copyFromDto(grant, grantDto)); grantRepository.save(copyFromDto(grant, grantDto));
grant.getAuthors().forEach(author -> {
if (!oldAuthors.contains(author)) {
grantNotificationService.sendAuthorsChangeNotification(grant, oldAuthors);
}
});
oldAuthors.forEach(oldAuthor -> {
if (!grant.getAuthors().contains(oldAuthor)) {
grantNotificationService.sendAuthorsChangeNotification(grant, oldAuthors);
}
});
if (grant.getLeader() != oldLeader) {
grantNotificationService.sendLeaderChangeNotification(grant, oldLeader);
}
eventService.updateGrantDeadlines(grant);
return grant.getId(); return grant.getId();
} }
@Transactional @Transactional
public void delete(Integer grantId) throws IOException { public boolean delete(Integer grantId) throws IOException {
Grant grant = grantRepository.findOne(grantId); Grant grant = findById(grantId);
if (grant.getApplication() != null) { if (grant != null) {
fileService.deleteFile(grant.getApplication());
}
//возможно при удалении гранта будет удаляться и проект, к нему привязанный
grantRepository.delete(grant); grantRepository.delete(grant);
return true;
}
return false;
} }
public List<Grant.GrantStatus> getGrantStatuses() { public List<Grant.GrantStatus> getGrantStatuses() {
return Arrays.asList(Grant.GrantStatus.values()); return Arrays.asList(Grant.GrantStatus.values());
} }
@Transactional public boolean save(GrantDto grantDto, Errors errors) throws IOException {
public Grant create(String title, Project projectId, Date deadlineDate) { grantDto.setName(grantDto.getTitle());
Grant grant = new Grant(); filterEmptyDeadlines(grantDto);
grant.setTitle(title); checkEmptyDeadlines(grantDto, errors);
grant.setComment("Комментарий к гранту 1"); checkEmptyLeader(grantDto, errors);
grant.setProject(projectId); checkUniqueName(grantDto, errors, grantDto.getId(), "Грант с таким именем уже существует");
grant.setStatus(APPLICATION); if (errors.hasErrors()) {
grant.getDeadlines().add(new Deadline(deadlineDate, "первый дедлайн")); return false;
grant = grantRepository.save(grant);
return grant;
} }
public void save(GrantDto grantDto) throws IOException {
if (isEmpty(grantDto.getId())) { if (isEmpty(grantDto.getId())) {
create(grantDto); create(grantDto);
} else { } else {
update(grantDto); update(grantDto);
} }
return true;
}
private boolean saveFromKias(GrantDto grantDto) throws IOException {
grantDto.setName(grantDto.getTitle());
String title = checkUniqueName(grantDto, grantDto.getId()); //проверка уникальности имени
if (title != null) {
Grant grantFromDB = grantRepository.findFirstByTitle(title); //грант с таким же названием из бд
if (checkSameDeadline(grantDto, grantFromDB.getId())) { //если дедайны тоже совпадают
return false;
} else { //иначе грант уже был в системе, но в другом году, поэтому надо создать
create(grantDto);
return true;
}
} else { //иначе такого гранта ещё нет, поэтому надо создать
create(grantDto);
return true;
}
}
private void checkEmptyLeader(GrantDto grantDto, Errors errors) {
if (grantDto.getLeaderId().equals(-1)) {
errors.rejectValue("leaderId", "errorCode", "Укажите руководителя");
}
}
private void checkEmptyDeadlines(GrantDto grantDto, Errors errors) {
if (grantDto.getDeadlines().isEmpty()) {
errors.rejectValue("deadlines", "errorCode", "Не может быть пусто");
}
}
private boolean checkSameDeadline(GrantDto grantDto, Integer id) {
Date date = DateUtils.clearTime(grantDto.getDeadlines().get(0).getDate()); //дата с сайта киас
Date foundGrantDate = DateUtils.clearTime(deadlineService.findByGrantIdAndDate(id, date));
return foundGrantDate != null && foundGrantDate.compareTo(date) == 0;
}
public List<User> getGrantAuthors(GrantDto grantDto) {
List<User> filteredUsers = userService.filterByAgeAndDegree(grantDto.isHasAge(), grantDto.isHasDegree());
if (grantDto.isWasLeader()) {
filteredUsers = checkContains(filteredUsers, getCompletedGrantLeaders());
}
if (grantDto.isHasBAKPapers()) {
filteredUsers = checkContains(filteredUsers, getBAKAuthors());
}
if (grantDto.isHasScopusPapers()) {
filteredUsers = checkContains(filteredUsers, getScopusAuthors());
}
return filteredUsers;
}
private List<User> checkContains(List<User> filteredUsers, List<User> checkUsers) {
return filteredUsers.stream()
.filter(checkUsers::contains)
.collect(toList());
}
private List<User> getCompletedGrantLeaders() {
return grantRepository.findByStatus(Grant.GrantStatus.COMPLETED)
.stream()
.map(Grant::getLeader)
.collect(toList());
}
public List<PaperDto> getGrantPapers(List<Integer> paperIds) {
return paperService.findAllSelect(paperIds);
}
public List<PaperDto> getAllUncompletedPapers() {
return paperService.findAllNotCompleted();
}
public List<PaperDto> attachPaper(GrantDto grantDto) {
if (!grantDto.getPaperIds().isEmpty()) {
grantDto.getPapers().clear();
grantDto.setPapers(getGrantPapers(grantDto.getPaperIds()));
} else {
grantDto.getPapers().clear();
}
return grantDto.getPapers();
}
public GrantDto removeDeadline(GrantDto grantDto, Integer deadlineId) {
if (grantDto.getDeadlines().get(deadlineId).getId() != null) {
grantDto.getRemovedDeadlineIds().add(grantDto.getDeadlines().get(deadlineId).getId());
}
grantDto.getDeadlines().remove((int) deadlineId);
return grantDto;
}
private List<User> getCompletedPapersAuthors(Paper.PaperType type) {
List<Paper> papers = paperService.findAllCompletedByType(type);
return papers.stream()
.filter(paper -> paper.getAuthors() != null)
.flatMap(paper -> paper.getAuthors().stream())
.collect(toList());
}
private List<User> getBAKAuthors() {
return getCompletedPapersAuthors(Paper.PaperType.VAK)
.stream()
.distinct()
.collect(toList());
}
private List<User> getScopusAuthors() {
List<User> authors = getCompletedPapersAuthors(Paper.PaperType.SCOPUS);
return authors
.stream()
.filter(author -> Collections.frequency(authors, author) > 3)
.collect(toList());
}
public List<Deadline> filterEmptyDeadlines(GrantDto grantDto) {
grantDto.setDeadlines(grantDto.getDeadlines().stream()
.filter(dto -> dto.getDate() != null || !StringUtils.isEmpty(dto.getDescription()))
.collect(Collectors.toList()));
return grantDto.getDeadlines();
}
@Transactional
public void createFromKias() throws IOException, ParseException {
for (GrantDto grantDto : kiasService.getNewGrantsDto()) {
if (saveFromKias(grantDto)) {
log.debug("GrantScheduler.loadGrantsFromKias new grant was loaded");
} else {
log.debug("GrantScheduler.loadGrantsFromKias grant wasn't loaded, cause it's already exists");
}
}
}
public List<GrantDto> findAllActiveDto() {
return convert(findAllActive(), GrantDto::new);
}
public List<Grant> findAllActive() {
return grantRepository.findAllActive();
}
public Grant findById(Integer id) {
return grantRepository.getOne(id);
}
@Transactional
public void ping(int grantId) throws IOException {
pingService.addPing(findById(grantId));
}
public void save(Grant grant) {
if (isEmpty(grant.getId())) {
create(grant);
} else {
update(grant);
}
}
@Transactional
public Grant create(Grant grant) {
Grant newGrant = grantRepository.save(grant);
grantNotificationService.sendCreateNotification(newGrant);
return newGrant;
}
@Transactional
public Integer update(Grant newGrant) {
Grant oldGrant = grantRepository.getOne(newGrant.getId());
//Grant.GrantStatus oldStatus = oldGrant.getStatus();
Set<User> oldAuthors = new HashSet<>(oldGrant.getAuthors());
newGrant = grantRepository.save(newGrant);
for (User author : newGrant.getAuthors()) {
if (!oldAuthors.contains(author)) {
grantNotificationService.sendCreateNotification(newGrant);
}
}
// if (newGrant.getStatus() != oldStatus) {
// grantNotificationService.statusChangeNotification(newPaper, oldStatus);
// }
return newGrant.getId();
}
public void createByTitle(String newGrantTitle) {
Grant grant = new Grant();
grant.setTitle(newGrantTitle);
grant.setStatus(APPLICATION);
grant.getAuthors().add(userService.getCurrentUser());
grant.setLeader(userService.getCurrentUser());
grant.getDeadlines().add(deadlineService.createWithOffset(new Date(), 1, ChronoUnit.WEEKS));
create(grant);
}
public List<Grant> findAllActiveByCurrentUser() {
return findAllActive()
.stream()
.filter(grant -> grant.getAuthors().contains(userService.getCurrentUser()) ||
grant.getLeader().equals(userService.getCurrentUser()))
.collect(toList());
}
public void delete(List<Grant> grants) {
grants.forEach(grant -> delete(grant));
}
public void delete(Grant grant) {
deadlineService.delete(grant.getDeadlines());
grantRepository.delete(grant);
} }
} }

View File

@ -0,0 +1,73 @@
package ru.ulstu.grant.service;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomNode;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.springframework.stereotype.Service;
import ru.ulstu.configuration.ApplicationProperties;
import ru.ulstu.grant.model.GrantDto;
import ru.ulstu.grant.page.KiasPage;
import ru.ulstu.user.service.UserService;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
@Service
public class KiasService {
private final static String BASE_URL = "https://www.rfbr.ru/rffi/ru/contest_search?CONTEST_STATUS_ID=%s&CONTEST_TYPE=%s&CONTEST_YEAR=%s";
private final static String CONTEST_STATUS_ID = "1";
private final static String CONTEST_TYPE = "-1";
private final UserService userService;
public KiasService(UserService userService,
ApplicationProperties applicationProperties) {
this.userService = userService;
}
public List<GrantDto> getNewGrantsDto() throws ParseException, IOException {
Integer leaderId = userService.findOneByLoginIgnoreCase("admin").getId();
List<GrantDto> grants = new ArrayList<>();
try (WebClient webClient = new WebClient()) {
webClient.setJavaScriptTimeout(60 * 1000);
webClient.getOptions().setThrowExceptionOnScriptError(false);
for (Integer year : generateGrantYears()) {
final HtmlPage page = webClient.getPage(String.format(BASE_URL, CONTEST_STATUS_ID, CONTEST_TYPE, year));
grants.addAll(getKiasGrants(page));
}
}
grants.forEach(grantDto -> grantDto.setLeaderId(leaderId));
return grants;
}
private List<GrantDto> getKiasGrants(HtmlPage page) throws ParseException {
List<GrantDto> newGrants = new ArrayList<>();
KiasPage kiasPage = new KiasPage(page);
do {
newGrants.addAll(getGrantsFromPage(kiasPage));
} while (kiasPage.goToNextPage()); //проверка существования следующей страницы с грантами
return newGrants;
}
private List<GrantDto> getGrantsFromPage(KiasPage kiasPage) throws ParseException {
List<GrantDto> grants = new ArrayList<>();
for (DomNode grantElement : kiasPage.getPageOfGrants()) {
if (kiasPage.isTableRowGrantLine(grantElement)) {
GrantDto grantDto = new GrantDto(
kiasPage.getGrantTitle(grantElement),
kiasPage.parseDeadLineDate(grantElement));
grants.add(grantDto);
}
}
return grants;
}
private List<Integer> generateGrantYears() {
return Arrays.asList(Calendar.getInstance().get(Calendar.YEAR),
Calendar.getInstance().get(Calendar.YEAR) + 1);
}
}

View File

@ -0,0 +1,23 @@
package ru.ulstu.index.controller;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import ru.ulstu.core.controller.AdviceController;
import ru.ulstu.user.service.UserService;
@Controller()
@RequestMapping(value = "/index")
@Hidden
public class IndexController extends AdviceController {
public IndexController(UserService userService) {
super(userService);
}
@GetMapping
public void currentUser(ModelMap modelMap) {
//нужен здесь для добавления параметров на стартовой странице
}
}

View File

@ -0,0 +1,25 @@
package ru.ulstu.index.model;
public class Section {
private final String title;
private final String image;
private final String href;
public Section(String title, String href, String image) {
this.title = title;
this.image = image;
this.href = href;
}
public String getTitle() {
return title;
}
public String getImage() {
return image;
}
public String getHref() {
return href;
}
}

View File

@ -0,0 +1,9 @@
package ru.ulstu.name;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface BaseRepository {
List<String> findByNameAndNotId(@Param("name") String name, @Param("id") Integer id);
}

View File

@ -0,0 +1,36 @@
package ru.ulstu.name;
import org.springframework.stereotype.Service;
import org.springframework.validation.Errors;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
public abstract class BaseService {
public BaseRepository baseRepository;
protected void checkUniqueName(NameContainer nameContainer, Errors errors, Integer id, String errorMessage) {
if (nameContainer.getName().equals(getUnique(baseRepository.findByNameAndNotId(nameContainer.getName(), id)))) {
errors.rejectValue("title", "errorCode", errorMessage);
}
}
protected String checkUniqueName(NameContainer nameContainer, Integer id) {
String foundName = getUnique(baseRepository.findByNameAndNotId(nameContainer.getName(), id));
if (nameContainer.getName().equals(foundName)) {
return foundName;
}
return null;
}
private String getUnique(List<String> names) {
return Optional.ofNullable(names)
.orElse(new ArrayList<>())
.stream()
.findAny()
.orElse(null);
}
}

View File

@ -0,0 +1,14 @@
package ru.ulstu.name;
public abstract class NameContainer {
private String name = "";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -9,10 +9,10 @@ import ru.ulstu.odin.service.OdinService;
public abstract class OdinController<L, E extends OdinDto> { public abstract class OdinController<L, E extends OdinDto> {
public static final String META_LIST_URL = "/meta/list"; public static final String META_LIST_URL = "/meta/list";
public static final String META_ELEMENT_URL = "/meta/element"; private static final String META_ELEMENT_URL = "/meta/element";
private Class<L> listDtoClass; private final Class<L> listDtoClass;
private Class<E> elementDtoClass; private final Class<E> elementDtoClass;
@Autowired @Autowired
private OdinService<L, E> odinService; private OdinService<L, E> odinService;

View File

@ -3,6 +3,7 @@ package ru.ulstu.odin.model;
import ru.ulstu.core.error.OdinException; import ru.ulstu.core.error.OdinException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -14,9 +15,9 @@ public class OdinCollectionField extends OdinField {
ParameterizedType genericType = (ParameterizedType) field.getGenericType(); ParameterizedType genericType = (ParameterizedType) field.getGenericType();
Type fieldElementClass = genericType.getActualTypeArguments()[0]; Type fieldElementClass = genericType.getActualTypeArguments()[0];
try { try {
OdinDto someInstance = (OdinDto) ((Class) (fieldElementClass)).newInstance(); OdinDto someInstance = (OdinDto) ((Class) (fieldElementClass)).getDeclaredConstructor().newInstance();
this.path = someInstance.getControllerPath(); this.path = someInstance.getControllerPath();
} catch (IllegalAccessException | InstantiationException e) { } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
throw new OdinException(String.format("Can't create new instance, check default constructor of %s", throw new OdinException(String.format("Can't create new instance, check default constructor of %s",
fieldElementClass.getTypeName())); fieldElementClass.getTypeName()));
} }

View File

@ -1,14 +1,14 @@
package ru.ulstu.odin.model; package ru.ulstu.odin.model;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import ru.ulstu.core.error.OdinException; import ru.ulstu.core.error.OdinException;
import ru.ulstu.odin.model.annotation.OdinCaption; import ru.ulstu.odin.model.annotation.OdinCaption;
import ru.ulstu.odin.model.annotation.OdinReadOnly; import ru.ulstu.odin.model.annotation.OdinReadOnly;
import ru.ulstu.odin.model.annotation.OdinVisible; import ru.ulstu.odin.model.annotation.OdinVisible;
import javax.validation.constraints.NotNull;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -32,15 +32,15 @@ public abstract class OdinField implements Comparable {
} }
} }
private Field field; private final OdinFieldType fieldType;
protected final OdinFieldType fieldType; private final String fieldName;
protected final String fieldName; private final String caption;
protected final String caption; private final OdinVisible.OdinVisibleType visible;
protected final OdinVisible.OdinVisibleType visible; private final boolean readOnly;
protected final boolean readOnly; private final boolean notEmpty;
protected final boolean notEmpty; private final Field field;
public OdinField(Field field, OdinFieldType fieldType) { OdinField(Field field, OdinFieldType fieldType) {
this.field = field; this.field = field;
this.fieldName = getFieldName(field); this.fieldName = getFieldName(field);
this.caption = Optional.ofNullable(getValueFromAnnotation(OdinCaption.class, "value")) this.caption = Optional.ofNullable(getValueFromAnnotation(OdinCaption.class, "value"))
@ -93,7 +93,7 @@ public abstract class OdinField implements Comparable {
} }
} }
protected <T> T getValue(Class<? extends Annotation> annotationClass, String valueName, Class<T> clazz) { <T> T getValue(Class<? extends Annotation> annotationClass, String valueName, Class<T> clazz) {
if (field.isAnnotationPresent(annotationClass)) { if (field.isAnnotationPresent(annotationClass)) {
return cast(getValueFromAnnotation(annotationClass, valueName), clazz); return cast(getValueFromAnnotation(annotationClass, valueName), clazz);
} }
@ -126,8 +126,12 @@ public abstract class OdinField implements Comparable {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
if (o == null || getClass() != o.getClass()) return false; return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
OdinField odinField = (OdinField) o; OdinField odinField = (OdinField) o;
return Objects.equals(fieldName, odinField.fieldName); return Objects.equals(fieldName, odinField.fieldName);
} }

View File

@ -3,6 +3,7 @@ package ru.ulstu.odin.model;
import ru.ulstu.core.error.OdinException; import ru.ulstu.core.error.OdinException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
public class OdinObjectField extends OdinField { public class OdinObjectField extends OdinField {
@ -12,9 +13,9 @@ public class OdinObjectField extends OdinField {
super(field, OdinFieldType.OBJECT); super(field, OdinFieldType.OBJECT);
Type fieldElementClass = field.getType(); Type fieldElementClass = field.getType();
try { try {
OdinDto someInstance = (OdinDto) ((Class) (fieldElementClass)).newInstance(); OdinDto someInstance = (OdinDto) ((Class) (fieldElementClass)).getDeclaredConstructor().newInstance();
this.path = someInstance.getControllerPath(); this.path = someInstance.getControllerPath();
} catch (IllegalAccessException | InstantiationException e) { } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
throw new OdinException(String.format("Can't create new instance, check default constructor of %s", throw new OdinException(String.format("Can't create new instance, check default constructor of %s",
fieldElementClass.getTypeName())); fieldElementClass.getTypeName()));
} }

View File

@ -1,10 +1,10 @@
package ru.ulstu.odin.model; package ru.ulstu.odin.model;
import org.hibernate.validator.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Size;
import ru.ulstu.odin.model.annotation.OdinString; import ru.ulstu.odin.model.annotation.OdinString;
import ru.ulstu.odin.model.annotation.OdinString.OdinStringType; import ru.ulstu.odin.model.annotation.OdinString.OdinStringType;
import javax.validation.constraints.Size;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import static ru.ulstu.odin.model.annotation.OdinString.OdinStringType.EMAIL; import static ru.ulstu.odin.model.annotation.OdinString.OdinStringType.EMAIL;

View File

@ -1,4 +0,0 @@
package ru.ulstu.odinexample.controller;
public class OdinExampleController {
}

View File

@ -1,4 +0,0 @@
package ru.ulstu.odinexample.model;
public class OdinExampleDto {
}

View File

@ -1,103 +0,0 @@
package ru.ulstu.odinexample.model;
import ru.ulstu.core.util.DateUtils;
import ru.ulstu.odin.model.annotation.OdinCaption;
import ru.ulstu.odin.model.annotation.OdinDate;
import ru.ulstu.odin.model.annotation.OdinNumeric;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
public class OdinExampleListDto {
@OdinCaption("instant")
@OdinDate(type = OdinDate.OdinDateType.DATETIME)
private Instant instant;
@OdinCaption("date")
private Date date;
@OdinCaption("localdate")
private LocalDate localDate;
@OdinCaption("localtime")
@OdinDate(type = OdinDate.OdinDateType.TIME)
private LocalTime localTime;
@OdinCaption("localdatetime")
@OdinDate(type = OdinDate.OdinDateType.DATETIME)
private LocalDateTime localDateTime;
@OdinCaption("int")
private int intval;
@OdinCaption("int+settings")
@OdinNumeric(precision = 5, scale = 2)
private int intvalset;
@OdinCaption("float")
private float floatval;
@OdinCaption("double")
private double aDouble;
@OdinCaption("double+set")
@OdinNumeric(precision = 5, scale = 3)
private double aDoubles;
@OdinCaption("int+positive")
@OdinNumeric(positiveOnly = true, scale = 2)
private int invalpos;
public OdinExampleListDto() {
this.instant = Instant.now();
this.date = new Date();
this.localDate = LocalDate.now();
this.localTime = LocalTime.now();
this.localDateTime = LocalDateTime.now();
intval = -134;
intvalset = 1343423232;
floatval = 2323.44F;
aDouble = -232323.43434;
aDoubles = 0.456456456;
invalpos = -23232323;
}
public Date getInstant() {
return DateUtils.instantToDate(instant);
}
public Date getDate() {
return date;
}
public Date getLocalDate() {
return DateUtils.localDateToDate(localDate);
}
public Date getLocalTime() {
return DateUtils.localTimeToDate(localTime);
}
public Date getLocalDateTime() {
return DateUtils.localDateTimeToDate(localDateTime);
}
public int getIntval() {
return intval;
}
public int getIntvalset() {
return intvalset;
}
public float getFloatval() {
return floatval;
}
public double getaDouble() {
return aDouble;
}
public double getaDoubles() {
return aDoubles;
}
public int getInvalpos() {
return invalpos;
}
}

View File

@ -1,4 +0,0 @@
package ru.ulstu.odinexample.service;
public class OdinExampleService {
}

View File

@ -1,59 +1,74 @@
package ru.ulstu.paper.controller; package ru.ulstu.paper.controller;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import ru.ulstu.deadline.model.DeadlineDto; import ru.ulstu.conference.service.ConferenceService;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.paper.model.AutoCompleteData;
import ru.ulstu.paper.model.Paper; import ru.ulstu.paper.model.Paper;
import ru.ulstu.paper.model.PaperDto; import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.paper.model.PaperFilterDto; import ru.ulstu.paper.model.PaperListDto;
import ru.ulstu.paper.service.LatexService;
import ru.ulstu.paper.service.PaperService; import ru.ulstu.paper.service.PaperService;
import ru.ulstu.user.model.User; import ru.ulstu.user.model.User;
import javax.validation.Valid;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.springframework.util.StringUtils.isEmpty;
@Controller() @Controller()
@RequestMapping(value = "/papers") @RequestMapping(value = "/papers")
@Hidden
public class PaperController { public class PaperController {
private final PaperService paperService; private final PaperService paperService;
private final ConferenceService conferenceService;
private final LatexService latexService;
public PaperController(PaperService paperService) { public PaperController(PaperService paperService,
ConferenceService conferenceService,
LatexService latexService) {
this.paperService = paperService; this.paperService = paperService;
this.conferenceService = conferenceService;
this.latexService = latexService;
} }
@GetMapping("/papers") @GetMapping("/papers")
public void getPapers(ModelMap modelMap) { public void getPapers(ModelMap modelMap) {
modelMap.put("filteredPapers", new PaperFilterDto(paperService.findAllDto(), null, null)); modelMap.put("filteredPapers", new PaperListDto(paperService.findAllDto(), null, null));
} }
@PostMapping("/papers") @PostMapping("/papers")
public void filterPapers(@Valid PaperFilterDto paperFilterDto, ModelMap modelMap) { public void listPapers(@Valid PaperListDto paperListDto, ModelMap modelMap) {
modelMap.put("filteredPapers", new PaperFilterDto(paperService.filter(paperFilterDto), if (paperListDto.getPaperDeleteId() != null) {
paperFilterDto.getFilterAuthorId(), if (conferenceService.isAttachedToConference(paperListDto.getPaperDeleteId())) {
paperFilterDto.getYear())); modelMap.put("flashMessage", "Статью нельзя удалить, она прикреплена к конференции");
} else {
paperService.delete(paperListDto.getPaperDeleteId());
}
}
modelMap.put("filteredPapers", new PaperListDto(paperService.filter(paperListDto),
paperListDto.getFilterAuthorId(),
paperListDto.getYear()));
} }
@GetMapping("/dashboard") @GetMapping("/dashboard")
public void getDashboard(ModelMap modelMap) { public void getDashboard(ModelMap modelMap) {
modelMap.put("papers", paperService.findAllActive()); modelMap.put("papers", paperService.findAllActiveDto());
} }
@GetMapping("/paper") @GetMapping("/paper")
public void getPapers(ModelMap modelMap, @RequestParam(value = "id") Integer id) { public void getPaper(ModelMap modelMap, @RequestParam(value = "id") Integer id) {
if (id != null && id > 0) { if (id != null && id > 0) {
modelMap.put("paperDto", paperService.findOneDto(id)); modelMap.put("paperDto", paperService.findOneDto(id));
} else { } else {
@ -80,21 +95,20 @@ public class PaperController {
if (errors.hasErrors()) { if (errors.hasErrors()) {
return "/papers/paper"; return "/papers/paper";
} }
paperDto.getDeadlines().add(new DeadlineDto()); paperDto.getDeadlines().add(new Deadline());
return "/papers/paper"; return "/papers/paper";
} }
@GetMapping("/delete/{paper-id}")
public String delete(@PathVariable("paper-id") Integer paperId) throws IOException {
paperService.delete(paperId);
return "redirect:/papers/papers";
}
@ModelAttribute("allStatuses") @ModelAttribute("allStatuses")
public List<Paper.PaperStatus> getPaperStatuses() { public List<Paper.PaperStatus> getPaperStatuses() {
return paperService.getPaperStatuses(); return paperService.getPaperStatuses();
} }
@ModelAttribute("allTypes")
public List<Paper.PaperType> getPaperTypes() {
return paperService.getPaperTypes();
}
@ModelAttribute("allAuthors") @ModelAttribute("allAuthors")
public List<User> getAllAuthors() { public List<User> getAllAuthors() {
return paperService.getPaperAuthors(); return paperService.getPaperAuthors();
@ -109,9 +123,14 @@ public class PaperController {
return years; return years;
} }
@ModelAttribute("autocompleteData")
public AutoCompleteData getAutocompleteData() {
return paperService.getAutoCompleteData();
}
private void filterEmptyDeadlines(PaperDto paperDto) { private void filterEmptyDeadlines(PaperDto paperDto) {
paperDto.setDeadlines(paperDto.getDeadlines().stream() paperDto.setDeadlines(paperDto.getDeadlines().stream()
.filter(dto -> dto.getDate() != null || !isEmpty(dto.getDescription())) .filter(dto -> dto.getDate() != null || !dto.getDescription().isEmpty())
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
} }

View File

@ -1,5 +1,6 @@
package ru.ulstu.paper.controller; package ru.ulstu.paper.controller;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
@ -7,14 +8,15 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.configuration.Constants; import ru.ulstu.configuration.Constants;
import ru.ulstu.core.model.response.Response; import ru.ulstu.core.model.response.Response;
import ru.ulstu.paper.model.PaperDto; import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.paper.model.PaperFilterDto; import ru.ulstu.paper.model.PaperListDto;
import ru.ulstu.paper.model.ReferenceDto;
import ru.ulstu.paper.service.PaperService; import ru.ulstu.paper.service.PaperService;
import javax.validation.Valid;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -38,7 +40,7 @@ public class PaperRestController {
@GetMapping("/{paper-id}") @GetMapping("/{paper-id}")
public Response<PaperDto> getPaper(@PathVariable("paper-id") Integer paperId) { public Response<PaperDto> getPaper(@PathVariable("paper-id") Integer paperId) {
return new Response(paperService.findById(paperId)); return new Response<>(paperService.findById(paperId));
} }
@PostMapping @PostMapping
@ -54,11 +56,26 @@ public class PaperRestController {
@DeleteMapping("/{paper-id}") @DeleteMapping("/{paper-id}")
public Response<Boolean> delete(@PathVariable("paper-id") Integer paperId) throws IOException { public Response<Boolean> delete(@PathVariable("paper-id") Integer paperId) throws IOException {
paperService.delete(paperId); paperService.delete(paperId);
return new Response<>(true); return new Response<>(Boolean.TRUE);
} }
@PostMapping("/filter") @PostMapping("/filter")
public Response<List<PaperDto>> filter(@RequestBody @Valid PaperFilterDto paperFilterDto) throws IOException { public Response<List<PaperDto>> filter(@RequestBody @Valid PaperListDto paperListDto) throws IOException {
return new Response<>(paperService.filter(paperFilterDto)); return new Response<>(paperService.filter(paperListDto));
}
@GetMapping("formatted-list")
public Response<List<String>> getFormattedPaperList() {
return new Response<>(paperService.getFormattedPaperList());
}
@PostMapping("/getFormattedReference")
public Response<String> getFormattedReference(@RequestBody @Valid ReferenceDto referenceDto) {
return new Response<>(paperService.getFormattedReference(referenceDto));
}
@PostMapping(value = "/ping")
public void ping(@RequestParam("paperId") int paperId) throws IOException {
paperService.ping(paperId);
} }
} }

View File

@ -0,0 +1,43 @@
package ru.ulstu.paper.model;
import java.util.ArrayList;
import java.util.List;
public class AutoCompleteData {
private List<String> authors = new ArrayList<>();
private List<String> publicationTitles = new ArrayList<>();
private List<String> publishers = new ArrayList<>();
private List<String> journalOrCollectionTitles = new ArrayList<>();
public List<String> getAuthors() {
return authors;
}
public void setAuthors(List<String> authors) {
this.authors = authors;
}
public List<String> getPublicationTitles() {
return publicationTitles;
}
public void setPublicationTitles(List<String> publicationTitles) {
this.publicationTitles = publicationTitles;
}
public List<String> getPublishers() {
return publishers;
}
public void setPublishers(List<String> publishers) {
this.publishers = publishers;
}
public List<String> getJournalOrCollectionTitles() {
return journalOrCollectionTitles;
}
public void setJournalOrCollectionTitles(List<String> journalOrCollectionTitles) {
this.journalOrCollectionTitles = journalOrCollectionTitles;
}
}

View File

@ -1,56 +1,87 @@
package ru.ulstu.paper.model; package ru.ulstu.paper.model;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OrderBy;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.validation.constraints.NotBlank;
import org.hibernate.annotations.Fetch; import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.FetchMode;
import org.hibernate.validator.constraints.NotBlank; import org.springframework.format.annotation.DateTimeFormat;
import ru.ulstu.conference.model.Conference;
import ru.ulstu.core.model.BaseEntity; import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.core.model.UserContainer; import ru.ulstu.core.model.EventSource;
import ru.ulstu.core.model.UserActivity;
import ru.ulstu.deadline.model.Deadline; import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.file.model.FileData; import ru.ulstu.file.model.FileData;
import ru.ulstu.grant.model.Grant;
import ru.ulstu.timeline.model.Event;
import ru.ulstu.user.model.User; import ru.ulstu.user.model.User;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@Entity @Entity
public class Paper extends BaseEntity implements UserContainer { @DiscriminatorValue("PAPER")
public class Paper extends BaseEntity implements UserActivity, EventSource {
public enum PaperStatus { public enum PaperStatus {
ATTENTION("Обратить внимание"), ATTENTION("Обратить внимание", "text-warning"),
ON_PREPARATION("На подготовке"), ON_PREPARATION("На подготовке", "text-primary"),
ON_REVIEW("Отправлена на проверку"), ON_REVIEW("Отправлена на проверку", "text-review"),
ACCEPTED("Принята"), ACCEPTED("Принята", "text-accepted"),
NOT_ACCEPTED("Не принята"), NOT_ACCEPTED("Не принята", "text-not-accepted"),
COMPLETED("Завершена (опубликована)"), COMPLETED("Завершена (опубликована)", "text-success"),
DRAFT("Черновик"), DRAFT("Черновик", "text-draft"),
FAILED("Провалены сроки"); FAILED("Провалены сроки", "text-failed");
private String statusName; private final String statusName;
private final String elementClass;
PaperStatus(String name) { PaperStatus(String name, String elementClass) {
this.statusName = name; this.statusName = name;
this.elementClass = elementClass;
} }
public String getStatusName() { public String getStatusName() {
return statusName; return statusName;
} }
public String getElementClass() {
return elementClass;
}
}
public enum PaperType {
OTHER("Прочая публикация"),
VAK("ВАК"),
SCOPUS("Scopus"),
WEB_OF_SCIENCE("Web Of Science");
private final String typeName;
PaperType(String name) {
this.typeName = name;
}
public String getTypeName() {
return typeName;
}
} }
@NotBlank @NotBlank
@ -59,15 +90,20 @@ public class Paper extends BaseEntity implements UserContainer {
@Enumerated(value = EnumType.STRING) @Enumerated(value = EnumType.STRING)
private PaperStatus status = PaperStatus.DRAFT; private PaperStatus status = PaperStatus.DRAFT;
@Enumerated(value = EnumType.STRING)
private PaperType type = PaperType.OTHER;
@Column(name = "create_date") @Column(name = "create_date")
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX")
private Date createDate = new Date(); private Date createDate = new Date();
@Column(name = "update_date") @Column(name = "update_date")
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX")
private Date updateDate = new Date(); private Date updateDate = new Date();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "paper_id", unique = true) @JoinColumn(name = "paper_id", unique = true)
@Fetch(FetchMode.SUBSELECT) @Fetch(FetchMode.SUBSELECT)
@OrderBy("date") @OrderBy("date")
@ -75,14 +111,32 @@ public class Paper extends BaseEntity implements UserContainer {
private String comment; private String comment;
private String url;
private Boolean locked = false; private Boolean locked = false;
@ManyToOne @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "file_id") @JoinColumn(name = "paper_id")
private FileData fileData; private List<Event> events = new ArrayList<>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "paper_id", unique = true)
@Fetch(FetchMode.SUBSELECT)
private List<FileData> files = new ArrayList<>();
@ManyToMany(fetch = FetchType.EAGER) @ManyToMany(fetch = FetchType.EAGER)
private Set<User> authors = new HashSet<>(); private Set<User> authors = new HashSet<>();
@ManyToOne()
@JoinColumn(name = "conference_id")
private Conference conference;
@ManyToMany(mappedBy = "papers")
private List<Grant> grants;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "paper_id", unique = true)
@Fetch(FetchMode.SUBSELECT)
private List<Reference> references = new ArrayList<>();
public PaperStatus getStatus() { public PaperStatus getStatus() {
return status; return status;
@ -92,6 +146,14 @@ public class Paper extends BaseEntity implements UserContainer {
this.status = status; this.status = status;
} }
public PaperType getType() {
return type;
}
public void setType(PaperType type) {
this.type = type;
}
public Date getCreateDate() { public Date getCreateDate() {
return createDate; return createDate;
} }
@ -132,18 +194,28 @@ public class Paper extends BaseEntity implements UserContainer {
this.locked = locked; this.locked = locked;
} }
public FileData getFileData() { public List<FileData> getFiles() {
return fileData; return files;
} }
public void setFileData(FileData fileData) { public void setFiles(List<FileData> files) {
this.fileData = fileData; this.files = files;
} }
public String getTitle() { public String getTitle() {
return title; return title;
} }
@Override
public List<User> getRecipients() {
return new ArrayList<>(authors);
}
@Override
public void addObjectToEvent(Event event) {
event.setPaper(this);
}
public void setTitle(String title) { public void setTitle(String title) {
this.title = title; this.title = title;
} }
@ -156,11 +228,51 @@ public class Paper extends BaseEntity implements UserContainer {
this.authors = authors; this.authors = authors;
} }
public List<Event> getEvents() {
return events;
}
public void setEvents(List<Event> events) {
this.events = events;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Conference getConference() {
return conference;
}
public void setConference(Conference conference) {
this.conference = conference;
}
public List<Grant> getGrants() {
return grants;
}
public void setGrants(List<Grant> grants) {
this.grants = grants;
}
@Override @Override
public Set<User> getUsers() { public Set<User> getActivityUsers() {
return getAuthors(); return getAuthors();
} }
public List<Reference> getReferences() {
return references;
}
public void setReferences(List<Reference> references) {
this.references = references;
}
public Optional<Deadline> getNextDeadline() { public Optional<Deadline> getNextDeadline() {
return deadlines return deadlines
.stream() .stream()
@ -178,4 +290,35 @@ public class Paper extends BaseEntity implements UserContainer {
.findAny() .findAny()
.isPresent(); .isPresent();
} }
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
Paper paper = (Paper) o;
return Objects.equals(title, paper.title) &&
status == paper.status &&
type == paper.type &&
Objects.equals(deadlines, paper.deadlines) &&
Objects.equals(comment, paper.comment) &&
Objects.equals(url, paper.url) &&
Objects.equals(locked, paper.locked) &&
Objects.equals(events, paper.events) &&
Objects.equals(files, paper.files) &&
Objects.equals(authors, paper.authors) &&
Objects.equals(conference, paper.conference) &&
Objects.equals(grants, paper.grants);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), title, status, type, createDate, updateDate, deadlines, comment, url, locked, events, files, authors, conference, grants);
}
} }

View File

@ -2,12 +2,15 @@ package ru.ulstu.paper.model;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.NotEmpty; import org.springframework.format.annotation.DateTimeFormat;
import ru.ulstu.deadline.model.DeadlineDto; import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.file.model.FileDataDto;
import ru.ulstu.user.model.UserDto; import ru.ulstu.user.model.UserDto;
import javax.validation.constraints.Size;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -24,66 +27,77 @@ public class PaperDto {
@Size(min = 3, max = 254) @Size(min = 3, max = 254)
private String title; private String title;
private Paper.PaperStatus status; private Paper.PaperStatus status;
private Paper.PaperType type;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX")
private Date createDate; private Date createDate;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX")
private Date updateDate; private Date updateDate;
@NotEmpty @NotEmpty
private List<DeadlineDto> deadlines = new ArrayList<>(); private List<Deadline> deadlines = new ArrayList<>();
private String comment; private String comment;
private String url;
private Boolean locked; private Boolean locked;
private String tmpFileName; private List<FileDataDto> files = new ArrayList<>();
private Integer fileId;
private String fileName;
private Date fileCreateDate;
private Set<Integer> authorIds; private Set<Integer> authorIds;
private Set<UserDto> authors; private Set<UserDto> authors;
private Integer filterAuthorId; private Integer filterAuthorId;
private String latexText;
private List<ReferenceDto> references = new ArrayList<>();
private ReferenceDto.FormatStandard formatStandard = ReferenceDto.FormatStandard.GOST;
public PaperDto() { public PaperDto() {
deadlines.add(new DeadlineDto()); deadlines.add(new Deadline());
} }
@JsonCreator @JsonCreator
public PaperDto(@JsonProperty("id") Integer id, public PaperDto(@JsonProperty("id") Integer id,
@JsonProperty("title") String title, @JsonProperty("title") String title,
@JsonProperty("status") Paper.PaperStatus status, @JsonProperty("status") Paper.PaperStatus status,
@JsonProperty("type") Paper.PaperType type,
@JsonProperty("createDate") Date createDate, @JsonProperty("createDate") Date createDate,
@JsonProperty("updateDate") Date updateDate, @JsonProperty("updateDate") Date updateDate,
@JsonProperty("deadlines") List<DeadlineDto> deadlines, @JsonProperty("deadlines") List<Deadline> deadlines,
@JsonProperty("comment") String comment, @JsonProperty("comment") String comment,
@JsonProperty("latex_text") String latexText,
@JsonProperty("url") String url,
@JsonProperty("locked") Boolean locked, @JsonProperty("locked") Boolean locked,
@JsonProperty("tmpFileName") String tmpFileName, @JsonProperty("files") List<FileDataDto> files,
@JsonProperty("authorIds") Set<Integer> authorIds, @JsonProperty("authorIds") Set<Integer> authorIds,
@JsonProperty("authors") Set<UserDto> authors) { @JsonProperty("authors") Set<UserDto> authors,
@JsonProperty("references") List<ReferenceDto> references,
@JsonProperty("formatStandard") ReferenceDto.FormatStandard formatStandard) {
this.id = id; this.id = id;
this.title = title; this.title = title;
this.status = status; this.status = status;
this.type = type;
this.createDate = createDate; this.createDate = createDate;
this.updateDate = updateDate; this.updateDate = updateDate;
this.deadlines = deadlines; this.deadlines = deadlines;
this.comment = comment; this.comment = comment;
this.url = url;
this.latexText = latexText;
this.locked = locked; this.locked = locked;
this.tmpFileName = tmpFileName; this.files = files;
this.fileId = null;
this.fileName = null;
this.fileCreateDate = null;
this.authors = authors; this.authors = authors;
this.references = references;
this.formatStandard = formatStandard;
} }
public PaperDto(Paper paper) { public PaperDto(Paper paper) {
this.id = paper.getId(); this.id = paper.getId();
this.title = paper.getTitle(); this.title = paper.getTitle();
this.status = paper.getStatus(); this.status = paper.getStatus();
this.type = paper.getType();
this.createDate = paper.getCreateDate(); this.createDate = paper.getCreateDate();
this.updateDate = paper.getUpdateDate(); this.updateDate = paper.getUpdateDate();
this.deadlines = convert(paper.getDeadlines(), DeadlineDto::new); this.deadlines = paper.getDeadlines();
this.comment = paper.getComment(); this.comment = paper.getComment();
this.url = paper.getUrl();
this.locked = paper.getLocked(); this.locked = paper.getLocked();
this.tmpFileName = null; this.files = convert(paper.getFiles(), FileDataDto::new);
this.fileId = paper.getFileData() == null ? null : paper.getFileData().getId(); this.authorIds = convert(paper.getAuthors(), BaseEntity::getId);
this.fileName = paper.getFileData() == null ? null : paper.getFileData().getName();
this.fileCreateDate = paper.getFileData() == null ? null : paper.getFileData().getCreateDate();
this.authorIds = convert(paper.getAuthors(), user -> user.getId());
this.authors = convert(paper.getAuthors(), UserDto::new); this.authors = convert(paper.getAuthors(), UserDto::new);
this.references = convert(paper.getReferences(), ReferenceDto::new);
} }
public Integer getId() { public Integer getId() {
@ -110,6 +124,14 @@ public class PaperDto {
this.status = status; this.status = status;
} }
public Paper.PaperType getType() {
return type;
}
public void setType(Paper.PaperType type) {
this.type = type;
}
public Date getCreateDate() { public Date getCreateDate() {
return createDate; return createDate;
} }
@ -126,11 +148,11 @@ public class PaperDto {
this.updateDate = updateDate; this.updateDate = updateDate;
} }
public List<DeadlineDto> getDeadlines() { public List<Deadline> getDeadlines() {
return deadlines; return deadlines;
} }
public void setDeadlines(List<DeadlineDto> deadlines) { public void setDeadlines(List<Deadline> deadlines) {
this.deadlines = deadlines; this.deadlines = deadlines;
} }
@ -150,36 +172,12 @@ public class PaperDto {
this.locked = locked; this.locked = locked;
} }
public String getTmpFileName() { public List<FileDataDto> getFiles() {
return tmpFileName; return files;
} }
public void setTmpFileName(String tmpFileName) { public void setFiles(List<FileDataDto> files) {
this.tmpFileName = tmpFileName; this.files = files;
}
public Integer getFileId() {
return fileId;
}
public void setFileId(Integer fileId) {
this.fileId = fileId;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public Date getFileCreateDate() {
return fileCreateDate;
}
public void setFileCreateDate(Date fileCreateDate) {
this.fileCreateDate = fileCreateDate;
} }
public Set<UserDto> getAuthors() { public Set<UserDto> getAuthors() {
@ -198,10 +196,26 @@ public class PaperDto {
this.authorIds = authorIds; this.authorIds = authorIds;
} }
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getLatexText() {
return latexText;
}
public void setLatexText(String latexText) {
this.latexText = latexText;
}
public String getAuthorsString() { public String getAuthorsString() {
return StringUtils.abbreviate(authors return StringUtils.abbreviate(authors
.stream() .stream()
.map(author -> author.getLastName()) .map(UserDto::getLastName)
.collect(Collectors.joining(", ")), MAX_AUTHORS_LENGTH); .collect(Collectors.joining(", ")), MAX_AUTHORS_LENGTH);
} }
@ -212,4 +226,20 @@ public class PaperDto {
public void setFilterAuthorId(Integer filterAuthorId) { public void setFilterAuthorId(Integer filterAuthorId) {
this.filterAuthorId = filterAuthorId; this.filterAuthorId = filterAuthorId;
} }
public List<ReferenceDto> getReferences() {
return references;
}
public void setReferences(List<ReferenceDto> references) {
this.references = references;
}
public ReferenceDto.FormatStandard getFormatStandard() {
return formatStandard;
}
public void setFormatStandard(ReferenceDto.FormatStandard formatStandard) {
this.formatStandard = formatStandard;
}
} }

View File

@ -2,15 +2,16 @@ package ru.ulstu.paper.model;
import java.util.List; import java.util.List;
public class PaperFilterDto { public class PaperListDto {
private List<PaperDto> papers; private List<PaperDto> papers;
private Integer filterAuthorId; private Integer filterAuthorId;
private Integer paperDeleteId;
private Integer year; private Integer year;
public PaperFilterDto() { public PaperListDto() {
} }
public PaperFilterDto(List<PaperDto> paperDtos, Integer filterAuthorId, Integer year) { public PaperListDto(List<PaperDto> paperDtos, Integer filterAuthorId, Integer year) {
this.papers = paperDtos; this.papers = paperDtos;
this.filterAuthorId = filterAuthorId; this.filterAuthorId = filterAuthorId;
this.year = year; this.year = year;
@ -39,4 +40,12 @@ public class PaperFilterDto {
public void setYear(Integer year) { public void setYear(Integer year) {
this.year = year; this.year = year;
} }
public Integer getPaperDeleteId() {
return paperDeleteId;
}
public void setPaperDeleteId(Integer paperDeleteId) {
this.paperDeleteId = paperDeleteId;
}
} }

View File

@ -0,0 +1,87 @@
package ru.ulstu.paper.model;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import ru.ulstu.core.model.BaseEntity;
@Entity
public class Reference extends BaseEntity {
private String authors;
@Column(name = "publication_title")
private String publicationTitle;
@Column(name = "publication_year")
private Integer publicationYear;
private String publisher;
private String pages;
@Column(name = "journal_or_collection_title")
private String journalOrCollectionTitle;
@Enumerated(value = EnumType.STRING)
@Column(name = "reference_type")
private ReferenceDto.ReferenceType referenceType = ReferenceDto.ReferenceType.ARTICLE;
public String getAuthors() {
return authors;
}
public void setAuthors(String authors) {
this.authors = authors;
}
public String getPublicationTitle() {
return publicationTitle;
}
public void setPublicationTitle(String publicationTitle) {
this.publicationTitle = publicationTitle;
}
public Integer getPublicationYear() {
return publicationYear;
}
public void setPublicationYear(Integer publicationYear) {
this.publicationYear = publicationYear;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getPages() {
return pages;
}
public void setPages(String pages) {
this.pages = pages;
}
public String getJournalOrCollectionTitle() {
return journalOrCollectionTitle;
}
public void setJournalOrCollectionTitle(String journalOrCollectionTitle) {
this.journalOrCollectionTitle = journalOrCollectionTitle;
}
public ReferenceDto.ReferenceType getReferenceType() {
return referenceType;
}
public void setReferenceType(ReferenceDto.ReferenceType referenceType) {
this.referenceType = referenceType;
}
}

View File

@ -0,0 +1,166 @@
package ru.ulstu.paper.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ReferenceDto {
public enum ReferenceType {
ARTICLE("Статья"),
BOOK("Книга");
private final String typeName;
ReferenceType(String name) {
this.typeName = name;
}
public String getTypeName() {
return typeName;
}
}
public enum FormatStandard {
GOST("ГОСТ"),
SPRINGER("Springer");
private final String standardName;
FormatStandard(String name) {
this.standardName = name;
}
public String getStandardName() {
return standardName;
}
}
private Integer id;
private String authors;
private String publicationTitle;
private Integer publicationYear;
private String publisher;
private String pages;
private String journalOrCollectionTitle;
private ReferenceType referenceType;
private FormatStandard formatStandard;
private boolean deleted;
@JsonCreator
public ReferenceDto(
@JsonProperty("id") Integer id,
@JsonProperty("authors") String authors,
@JsonProperty("publicationTitle") String publicationTitle,
@JsonProperty("publicationYear") Integer publicationYear,
@JsonProperty("publisher") String publisher,
@JsonProperty("pages") String pages,
@JsonProperty("journalOrCollectionTitle") String journalOrCollectionTitle,
@JsonProperty("referenceType") ReferenceType referenceType,
@JsonProperty("formatStandard") FormatStandard formatStandard,
@JsonProperty("isDeleted") boolean deleted) {
this.id = id;
this.authors = authors;
this.publicationTitle = publicationTitle;
this.publicationYear = publicationYear;
this.publisher = publisher;
this.pages = pages;
this.journalOrCollectionTitle = journalOrCollectionTitle;
this.referenceType = referenceType;
this.formatStandard = formatStandard;
this.deleted = deleted;
}
public ReferenceDto(Reference reference) {
this.id = reference.getId();
this.authors = reference.getAuthors();
this.publicationTitle = reference.getPublicationTitle();
this.publicationYear = reference.getPublicationYear();
this.publisher = reference.getPublisher();
this.pages = reference.getPages();
this.journalOrCollectionTitle = reference.getJournalOrCollectionTitle();
this.referenceType = reference.getReferenceType();
}
public ReferenceDto() {
referenceType = ReferenceType.ARTICLE;
}
public String getAuthors() {
return authors;
}
public void setAuthors(String authors) {
this.authors = authors;
}
public String getPublicationTitle() {
return publicationTitle;
}
public void setPublicationTitle(String publicationTitle) {
this.publicationTitle = publicationTitle;
}
public Integer getPublicationYear() {
return publicationYear;
}
public void setPublicationYear(Integer publicationYear) {
this.publicationYear = publicationYear;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getPages() {
return pages;
}
public void setPages(String pages) {
this.pages = pages;
}
public String getJournalOrCollectionTitle() {
return journalOrCollectionTitle;
}
public void setJournalOrCollectionTitle(String journalOrCollectionTitle) {
this.journalOrCollectionTitle = journalOrCollectionTitle;
}
public ReferenceType getReferenceType() {
return referenceType;
}
public void setReferenceType(ReferenceType referenceType) {
this.referenceType = referenceType;
}
public FormatStandard getFormatStandard() {
return formatStandard;
}
public void setFormatStandard(FormatStandard formatStandard) {
this.formatStandard = formatStandard;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public boolean getDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
}

View File

@ -12,4 +12,16 @@ public interface PaperRepository extends JpaRepository<Paper, Integer> {
@Query("SELECT p FROM Paper p WHERE (:author IS NULL OR :author MEMBER OF p.authors) AND (YEAR(p.createDate) = :year OR :year IS NULL)") @Query("SELECT p FROM Paper p WHERE (:author IS NULL OR :author MEMBER OF p.authors) AND (YEAR(p.createDate) = :year OR :year IS NULL)")
List<Paper> filter(@Param("author") User author, @Param("year") Integer year); List<Paper> filter(@Param("author") User author, @Param("year") Integer year);
List<Paper> findByIdNotIn(List<Integer> paperIds);
List<Paper> findAllByIdIn(List<Integer> paperIds);
List<Paper> findByTypeAndStatus(Paper.PaperType type, Paper.PaperStatus status);
List<Paper> findByStatusNot(Paper.PaperStatus status);
List<Paper> findByConferenceIsNullAndStatusNot(Paper.PaperStatus status);
List<Paper> findByIdNotInAndConferenceIsNullAndStatusNot(List<Integer> paperIds, Paper.PaperStatus status);
} }

View File

@ -0,0 +1,23 @@
package ru.ulstu.paper.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import ru.ulstu.paper.model.Reference;
import java.util.List;
public interface ReferenceRepository extends JpaRepository<Reference, Integer> {
void deleteById(Integer id);
@Query("SELECT DISTINCT r.authors FROM Reference r")
List<String> findDistinctAuthors();
@Query("SELECT DISTINCT r.publicationTitle FROM Reference r")
List<String> findDistinctPublicationTitles();
@Query("SELECT DISTINCT r.publisher FROM Reference r")
List<String> findDistinctPublishers();
@Query("SELECT DISTINCT r.journalOrCollectionTitle FROM Reference r where r.journalOrCollectionTitle <> ''")
List<String> findDistinctJournalOrCollectionTitles();
}

View File

@ -0,0 +1,77 @@
package ru.ulstu.paper.service;
import org.springframework.stereotype.Service;
import ru.ulstu.file.service.FileService;
import ru.ulstu.paper.model.PaperDto;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
@Service
public class LatexService {
private static final String PDF_LATEX_ERROR = "Errors occurred while executing pdfLaTeX.";
private static final String BIBTEX_ERROR = "Errors occurred while executing bibtex.";
private String errorMessage;
private File pdfFile;
private final FileService fileService;
public LatexService(FileService fileService) {
this.fileService = fileService;
}
public byte[] generatePdfFromLatexFile(PaperDto paper) throws IOException, InterruptedException {
fileService.createLatexAttachs(paper);
File tex = fileService.createLatexFile(paper);
if (!generate(paper.getTitle(), tex.getParentFile())) {
throw new IOException(errorMessage);
}
return Files.readAllBytes(pdfFile.toPath());
}
private int startProcess(String[] args, File dir, String message) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder(args);
processBuilder.redirectErrorStream(true);
processBuilder.directory(dir);
Process process = processBuilder.start();
InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
try (BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
String line = bufferedReader.readLine();
while (line != null) {
line = bufferedReader.readLine();
}
}
int exitCode = process.waitFor();
if (exitCode != 0) {
errorMessage = message + " Exit value of the process: " + exitCode;
}
return exitCode;
}
private boolean generate(String filename, File dir) throws IOException, InterruptedException {
startProcess(new String[]{"pdflatex", filename, "--interaction=nonstopmode"}, dir, PDF_LATEX_ERROR);
startProcess(new String[]{"bibtex", filename}, dir, BIBTEX_ERROR);
if (startProcess(new String[]{"pdflatex", filename, "--interaction=nonstopmode"}, dir, PDF_LATEX_ERROR) != 0) {
return false;
}
return checkPdf(filename, dir);
}
private boolean checkPdf(String filename, File dir) {
pdfFile = new File(dir.getAbsolutePath() + File.separator + filename + ".pdf");
if (pdfFile.isFile()) {
return true;
} else {
errorMessage = "The pdf file could not be created.";
return false;
}
}
}

View File

@ -1,6 +1,5 @@
package ru.ulstu.paper.service; package ru.ulstu.paper.service;
import com.google.common.collect.ImmutableMap;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.core.util.DateUtils; import ru.ulstu.core.util.DateUtils;
import ru.ulstu.paper.model.Paper; import ru.ulstu.paper.model.Paper;
@ -46,22 +45,22 @@ public class PaperNotificationService {
} }
private void sendMessageDeadline(Paper paper) { private void sendMessageDeadline(Paper paper) {
Map<String, Object> variables = ImmutableMap.of("paper", paper); Map<String, Object> variables = Map.of("paper", paper);
sendForAllAuhtors(variables, paper, TEMPLATE_DEADLINE, TITLE_DEADLINE); sendForAllAuhtors(variables, paper, TEMPLATE_DEADLINE, TITLE_DEADLINE);
} }
public void sendCreateNotification(Paper paper) { public void sendCreateNotification(Paper paper) {
Map<String, Object> variables = ImmutableMap.of("paper", paper); Map<String, Object> variables = Map.of("paper", paper);
sendForAllAuhtors(variables, paper, TEMPLATE_CREATE, TITLE_CREATE); sendForAllAuhtors(variables, paper, TEMPLATE_CREATE, TITLE_CREATE);
} }
public void statusChangeNotification(Paper paper, Paper.PaperStatus oldStatus) { public void statusChangeNotification(Paper paper, Paper.PaperStatus oldStatus) {
Map<String, Object> variables = ImmutableMap.of("paper", paper, "oldStatus", oldStatus); Map<String, Object> variables = Map.of("paper", paper, "oldStatus", oldStatus);
sendForAllAuhtors(variables, paper, TEMPLATE_STATUS_CHANGED, TITLE_STATUS_CHANGED); sendForAllAuhtors(variables, paper, TEMPLATE_STATUS_CHANGED, TITLE_STATUS_CHANGED);
} }
public void sendFailedNotification(Paper paper, Paper.PaperStatus oldStatus) { public void sendFailedNotification(Paper paper, Paper.PaperStatus oldStatus) {
Map<String, Object> variables = ImmutableMap.of("paper", paper, "oldStatus", oldStatus); Map<String, Object> variables = Map.of("paper", paper, "oldStatus", oldStatus);
sendForAllAuhtors(variables, paper, TEMPLATE_FAILED, TITLE_FAILED); sendForAllAuhtors(variables, paper, TEMPLATE_FAILED, TITLE_FAILED);
} }

View File

@ -5,15 +5,24 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import ru.ulstu.deadline.model.Deadline; import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.deadline.service.DeadlineService; import ru.ulstu.deadline.service.DeadlineService;
import ru.ulstu.file.model.FileDataDto;
import ru.ulstu.file.service.FileService; import ru.ulstu.file.service.FileService;
import ru.ulstu.paper.model.AutoCompleteData;
import ru.ulstu.paper.model.Paper; import ru.ulstu.paper.model.Paper;
import ru.ulstu.paper.model.PaperDto; import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.paper.model.PaperFilterDto; import ru.ulstu.paper.model.PaperListDto;
import ru.ulstu.paper.model.Reference;
import ru.ulstu.paper.model.ReferenceDto;
import ru.ulstu.paper.repository.PaperRepository; import ru.ulstu.paper.repository.PaperRepository;
import ru.ulstu.paper.repository.ReferenceRepository;
import ru.ulstu.ping.service.PingService;
import ru.ulstu.timeline.service.EventService;
import ru.ulstu.user.model.User; import ru.ulstu.user.model.User;
import ru.ulstu.user.service.UserService; import ru.ulstu.user.service.UserService;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat;
import java.time.temporal.ChronoUnit;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
@ -21,6 +30,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
import static org.springframework.util.ObjectUtils.isEmpty; import static org.springframework.util.ObjectUtils.isEmpty;
import static ru.ulstu.core.util.StreamApiUtils.convert; import static ru.ulstu.core.util.StreamApiUtils.convert;
import static ru.ulstu.paper.model.Paper.PaperStatus.ATTENTION; import static ru.ulstu.paper.model.Paper.PaperStatus.ATTENTION;
@ -28,27 +38,42 @@ import static ru.ulstu.paper.model.Paper.PaperStatus.COMPLETED;
import static ru.ulstu.paper.model.Paper.PaperStatus.DRAFT; import static ru.ulstu.paper.model.Paper.PaperStatus.DRAFT;
import static ru.ulstu.paper.model.Paper.PaperStatus.FAILED; import static ru.ulstu.paper.model.Paper.PaperStatus.FAILED;
import static ru.ulstu.paper.model.Paper.PaperStatus.ON_PREPARATION; import static ru.ulstu.paper.model.Paper.PaperStatus.ON_PREPARATION;
import static ru.ulstu.paper.model.Paper.PaperType.OTHER;
import static ru.ulstu.paper.model.ReferenceDto.FormatStandard.GOST;
import static ru.ulstu.paper.model.ReferenceDto.ReferenceType.ARTICLE;
import static ru.ulstu.paper.model.ReferenceDto.ReferenceType.BOOK;
@Service @Service
@Transactional
public class PaperService { public class PaperService {
private final static int MAX_DISPLAY_SIZE = 40; private final static int MAX_DISPLAY_SIZE = 40;
private final static String PAPER_FORMATTED_TEMPLATE = "%s %s";
private final PaperNotificationService paperNotificationService; private final PaperNotificationService paperNotificationService;
private final PaperRepository paperRepository; private final PaperRepository paperRepository;
private final UserService userService; private final UserService userService;
private final DeadlineService deadlineService; private final DeadlineService deadlineService;
private final FileService fileService; private final FileService fileService;
private final EventService eventService;
private final ReferenceRepository referenceRepository;
private final PingService pingService;
public PaperService(PaperRepository paperRepository, public PaperService(PaperRepository paperRepository,
ReferenceRepository referenceRepository,
FileService fileService, FileService fileService,
PaperNotificationService paperNotificationService, PaperNotificationService paperNotificationService,
UserService userService, UserService userService,
DeadlineService deadlineService) { DeadlineService deadlineService,
EventService eventService,
PingService pingService) {
this.paperRepository = paperRepository; this.paperRepository = paperRepository;
this.referenceRepository = referenceRepository;
this.fileService = fileService; this.fileService = fileService;
this.paperNotificationService = paperNotificationService; this.paperNotificationService = paperNotificationService;
this.userService = userService; this.userService = userService;
this.deadlineService = deadlineService; this.deadlineService = deadlineService;
this.eventService = eventService;
this.pingService = pingService;
} }
public List<Paper> findAll() { public List<Paper> findAll() {
@ -56,41 +81,59 @@ public class PaperService {
} }
public List<PaperDto> findAllDto() { public List<PaperDto> findAllDto() {
List<PaperDto> papers = convert(findAll(), PaperDto::new); return convert(findAll(), PaperDto::new);
papers.forEach(paperDto -> paperDto.setTitle(StringUtils.abbreviate(paperDto.getTitle(), MAX_DISPLAY_SIZE)));
return papers;
} }
public List<PaperDto> findAllActive() { public List<Paper> findAllActive() {
return findAllDto() return findAll()
.stream() .stream()
.filter(paper -> paper.getStatus() != COMPLETED && paper.getStatus() != FAILED) .filter(paper -> paper.getStatus() != COMPLETED && paper.getStatus() != FAILED)
.collect(Collectors.toList()); .collect(toList());
}
public List<Paper> findAllActiveByCurrentUser() {
return findAllActive()
.stream()
.filter(paper -> paper.getAuthors().contains(userService.getCurrentUser()))
.collect(toList());
}
public List<PaperDto> findAllActiveDto() {
return convert(findAllActive(), PaperDto::new);
} }
public PaperDto findOneDto(Integer id) { public PaperDto findOneDto(Integer id) {
return new PaperDto(paperRepository.findOne(id)); return new PaperDto(paperRepository.findById(id).orElseThrow());
} }
@Transactional @Transactional
public Integer create(PaperDto paperDto) throws IOException { public Integer create(PaperDto paperDto) throws IOException {
Paper newPaper = copyFromDto(new Paper(), paperDto); Paper newPaper = copyFromDto(new Paper(), paperDto);
newPaper = paperRepository.save(newPaper); return create(newPaper).getId();
}
@Transactional
public Paper create(Paper paper) {
Paper newPaper = paperRepository.save(paper);
newPaper.setCreateDate(new Date());
paperNotificationService.sendCreateNotification(newPaper); paperNotificationService.sendCreateNotification(newPaper);
return newPaper.getId(); return newPaper;
} }
private Paper copyFromDto(Paper paper, PaperDto paperDto) throws IOException { private Paper copyFromDto(Paper paper, PaperDto paperDto) throws IOException {
paper.setComment(paperDto.getComment()); paper.setComment(paperDto.getComment());
paper.setUrl(paperDto.getUrl());
paper.setCreateDate(paper.getCreateDate() == null ? new Date() : paper.getCreateDate()); paper.setCreateDate(paper.getCreateDate() == null ? new Date() : paper.getCreateDate());
paper.setLocked(paperDto.getLocked()); paper.setLocked(paperDto.getLocked());
paper.setStatus(paperDto.getStatus() == null ? DRAFT : paperDto.getStatus()); paper.setStatus(paperDto.getStatus() == null ? DRAFT : paperDto.getStatus());
paper.setType(paperDto.getType() == null ? OTHER : paperDto.getType());
paper.setTitle(paperDto.getTitle()); paper.setTitle(paperDto.getTitle());
paper.setUpdateDate(new Date()); paper.setUpdateDate(new Date());
paper.setDeadlines(deadlineService.saveOrCreate(paperDto.getDeadlines())); paper.setDeadlines(deadlineService.saveOrCreate(paperDto.getDeadlines()));
if (paperDto.getTmpFileName() != null) { paper.setReferences(saveOrCreateReferences(paperDto.getReferences()));
paper.setFileData(fileService.createFileFromTmp(paperDto.getTmpFileName())); paper.setFiles(fileService.saveOrCreate(paperDto.getFiles().stream()
} .filter(f -> !f.isDeleted())
.collect(toList())));
paper.getAuthors().clear(); paper.getAuthors().clear();
if (paperDto.getAuthorIds() != null && !paperDto.getAuthorIds().isEmpty()) { if (paperDto.getAuthorIds() != null && !paperDto.getAuthorIds().isEmpty()) {
paperDto.getAuthorIds().forEach(authorIds -> paper.getAuthors().add(userService.findById(authorIds))); paperDto.getAuthorIds().forEach(authorIds -> paper.getAuthors().add(userService.findById(authorIds)));
@ -98,15 +141,59 @@ public class PaperService {
return paper; return paper;
} }
private List<Reference> saveOrCreateReferences(List<ReferenceDto> references) {
return references
.stream()
.filter(reference -> !reference.getDeleted())
.map(reference -> reference.getId() != null ? updateReference(reference) : createReference(reference))
.collect(Collectors.toList());
}
@Transactional
private Reference updateReference(ReferenceDto referenceDto) {
Reference updateReference = referenceRepository.getOne(referenceDto.getId());
copyFromDto(updateReference, referenceDto);
referenceRepository.save(updateReference);
return updateReference;
}
@Transactional
private Reference createReference(ReferenceDto referenceDto) {
Reference newReference = new Reference();
copyFromDto(newReference, referenceDto);
newReference = referenceRepository.save(newReference);
return newReference;
}
private Reference copyFromDto(Reference reference, ReferenceDto referenceDto) {
reference.setAuthors(referenceDto.getAuthors());
reference.setJournalOrCollectionTitle(referenceDto.getJournalOrCollectionTitle());
reference.setPages(referenceDto.getPages());
reference.setPublicationTitle(referenceDto.getPublicationTitle());
reference.setPublicationYear(referenceDto.getPublicationYear());
reference.setPublisher(referenceDto.getPublisher());
reference.setReferenceType(referenceDto.getReferenceType());
return reference;
}
@Transactional @Transactional
public Integer update(PaperDto paperDto) throws IOException { public Integer update(PaperDto paperDto) throws IOException {
Paper paper = paperRepository.findOne(paperDto.getId()); Paper paper = paperRepository.getOne(paperDto.getId());
Paper.PaperStatus oldStatus = paper.getStatus(); Paper.PaperStatus oldStatus = paper.getStatus();
Set<User> oldAuthors = new HashSet<>(paper.getAuthors()); Set<User> oldAuthors = new HashSet<>(paper.getAuthors());
if (paperDto.getTmpFileName() != null && paper.getFileData() != null) {
fileService.deleteFile(paper.getFileData()); for (FileDataDto file : paperDto.getFiles().stream()
.filter(f -> f.isDeleted() && f.getId() != null)
.collect(toList())) {
fileService.delete(file.getId());
} }
paperRepository.save(copyFromDto(paper, paperDto)); paperRepository.save(copyFromDto(paper, paperDto));
for (ReferenceDto referenceDto : paperDto.getReferences().stream()
.filter(f -> f.getDeleted() && f.getId() != null)
.collect(toList())) {
referenceRepository.deleteById(referenceDto.getId());
}
eventService.updatePaperDeadlines(paper);
paper.getAuthors().forEach(author -> { paper.getAuthors().forEach(author -> {
if (!oldAuthors.contains(author)) { if (!oldAuthors.contains(author)) {
@ -122,18 +209,46 @@ public class PaperService {
} }
@Transactional @Transactional
public void delete(Integer paperId) throws IOException { public Integer update(Paper newPaper) {
Paper paper = paperRepository.findOne(paperId); Paper oldPaper = paperRepository.getOne(newPaper.getId());
if (paper.getFileData() != null) { Paper.PaperStatus oldStatus = oldPaper.getStatus();
fileService.deleteFile(paper.getFileData()); Set<User> oldAuthors = new HashSet<>(oldPaper.getAuthors());
newPaper.setUpdateDate(new Date());
newPaper = paperRepository.save(newPaper);
for (User author : newPaper.getAuthors()) {
if (!oldAuthors.contains(author)) {
paperNotificationService.sendCreateNotification(newPaper);
} }
paperRepository.delete(paper); }
if (newPaper.getStatus() != oldStatus) {
paperNotificationService.statusChangeNotification(newPaper, oldStatus);
}
return newPaper.getId();
}
@Transactional
public void delete(Integer paperId) {
delete(paperRepository.getOne(paperId));
} }
public List<Paper.PaperStatus> getPaperStatuses() { public List<Paper.PaperStatus> getPaperStatuses() {
return Arrays.asList(Paper.PaperStatus.values()); return Arrays.asList(Paper.PaperStatus.values());
} }
public List<Paper.PaperType> getPaperTypes() {
return Arrays.asList(Paper.PaperType.values());
}
public List<ReferenceDto.FormatStandard> getFormatStandards() {
return Arrays.asList(ReferenceDto.FormatStandard.values());
}
public List<ReferenceDto.ReferenceType> getReferenceTypes() {
return Arrays.asList(ReferenceDto.ReferenceType.values());
}
@Transactional @Transactional
public Paper create(String title, User user, Date deadlineDate) { public Paper create(String title, User user, Date deadlineDate) {
Paper paper = new Paper(); Paper paper = new Paper();
@ -143,14 +258,16 @@ public class PaperService {
paper.setCreateDate(new Date()); paper.setCreateDate(new Date());
paper.setUpdateDate(new Date()); paper.setUpdateDate(new Date());
paper.setStatus(DRAFT); paper.setStatus(DRAFT);
paper.setType(OTHER);
paper = paperRepository.save(paper); paper = paperRepository.save(paper);
paperNotificationService.sendCreateNotification(paper); paperNotificationService.sendCreateNotification(paper);
eventService.createFromPaper(paper);
return paper; return paper;
} }
public List<PaperDto> filter(PaperFilterDto filterDto) { public List<PaperDto> filter(PaperListDto filterDto) {
return convert(sortPapers(paperRepository.filter( return convert(sortPapers(paperRepository.filter(
filterDto.getFilterAuthorId() == null ? null : userService.findById(filterDto.getFilterAuthorId()), filterDto.getFilterAuthorId() == null ? null : userService.findById(filterDto.getFilterAuthorId()),
filterDto.getYear())), PaperDto::new); filterDto.getYear())), PaperDto::new);
@ -165,7 +282,7 @@ public class PaperService {
return statusCompareResult; return statusCompareResult;
} }
return paper1.getTitle().compareTo(paper2.getTitle()); return paper1.getTitle().compareTo(paper2.getTitle());
}).collect(Collectors.toList()); }).collect(toList());
} }
public PaperDto findPaper(int id) { public PaperDto findPaper(int id) {
@ -179,7 +296,7 @@ public class PaperService {
&& (paper.getStatus() == ON_PREPARATION && (paper.getStatus() == ON_PREPARATION
|| paper.getStatus() == DRAFT || paper.getStatus() == DRAFT
|| paper.getStatus() == ATTENTION)) || paper.getStatus() == ATTENTION))
.collect(Collectors.toList()); .collect(toList());
papers.forEach(paper -> { papers.forEach(paper -> {
Paper.PaperStatus oldStatus = paper.getStatus(); Paper.PaperStatus oldStatus = paper.getStatus();
paper.setStatus(Paper.PaperStatus.FAILED); paper.setStatus(Paper.PaperStatus.FAILED);
@ -196,11 +313,133 @@ public class PaperService {
} }
} }
public void save(Paper paper) {
if (isEmpty(paper.getId())) {
create(paper);
} else {
update(paper);
}
}
public PaperDto findById(Integer paperId) { public PaperDto findById(Integer paperId) {
return new PaperDto(paperRepository.findOne(paperId)); return new PaperDto(paperRepository.getOne(paperId));
}
public Paper findPaperById(Integer paperId) {
return paperRepository.getOne(paperId);
}
public List<Paper> findAllNotSelect(List<Integer> paperIds) {
if (!paperIds.isEmpty()) {
return sortPapers(paperRepository.findByIdNotInAndConferenceIsNullAndStatusNot(paperIds, COMPLETED));
} else {
return sortPapers(paperRepository.findByConferenceIsNullAndStatusNot(COMPLETED));
}
}
public List<PaperDto> findAllNotCompleted() {
return convert(paperRepository.findByStatusNot(COMPLETED), PaperDto::new);
}
public List<PaperDto> findAllSelect(List<Integer> paperIds) {
return convert(paperRepository.findAllByIdIn(paperIds), PaperDto::new);
} }
public List<User> getPaperAuthors() { public List<User> getPaperAuthors() {
return userService.findAll(); return userService.findAll();
} }
public List<String> getFormattedPaperList() {
return findAllCompleted()
.stream()
.map(paper -> String.format(PAPER_FORMATTED_TEMPLATE, paper.getTitle(), getAuthors(paper)))
.collect(toList());
}
private List<Paper> findAllCompleted() {
return findAll()
.stream()
.filter(paper -> paper.getStatus() == COMPLETED)
.collect(toList());
}
private String getAuthors(Paper paper) {
return paper.getAuthors()
.stream()
.map(User::getUserAbbreviate)
.collect(Collectors.joining(", "));
}
public String getFormattedReference(ReferenceDto referenceDto) {
return referenceDto.getFormatStandard() == GOST
? getGostReference(referenceDto)
: getSpringerReference(referenceDto);
}
public String getFormattedReferences(PaperDto paperDto) {
return String.join("\r\n", paperDto.getReferences()
.stream()
.filter(r -> !r.getDeleted())
.map(r -> {
r.setFormatStandard(paperDto.getFormatStandard());
return getFormattedReference(r);
})
.collect(Collectors.toList()));
}
private String getGostReference(ReferenceDto referenceDto) {
return MessageFormat.format(referenceDto.getReferenceType() == BOOK ? "{0} {1} - {2}{3}. - {4}с." : "{0} {1}{5} {2}{3}. С. {4}.",
referenceDto.getAuthors(),
referenceDto.getPublicationTitle(),
StringUtils.isEmpty(referenceDto.getPublisher()) ? "" : referenceDto.getPublisher() + ", ",
referenceDto.getPublicationYear() != null ? referenceDto.getPublicationYear().toString() : "",
referenceDto.getPages(),
StringUtils.isEmpty(referenceDto.getJournalOrCollectionTitle()) ? "." : " // " + referenceDto.getJournalOrCollectionTitle() + ".");
}
private String getSpringerReference(ReferenceDto referenceDto) {
return MessageFormat.format("{0} ({1}) {2}.{3} {4}pp {5}",
referenceDto.getAuthors(),
referenceDto.getPublicationYear() != null ? referenceDto.getPublicationYear().toString() : "",
referenceDto.getPublicationTitle(),
referenceDto.getReferenceType() == ARTICLE ? " " + referenceDto.getJournalOrCollectionTitle() + "," : "",
StringUtils.isEmpty(referenceDto.getPublisher()) ? "" : referenceDto.getPublisher() + ", ",
referenceDto.getPages());
}
public List<Paper> findAllCompletedByType(Paper.PaperType type) {
return paperRepository.findByTypeAndStatus(type, Paper.PaperStatus.COMPLETED);
}
public AutoCompleteData getAutoCompleteData() {
AutoCompleteData autoCompleteData = new AutoCompleteData();
autoCompleteData.setAuthors(referenceRepository.findDistinctAuthors());
autoCompleteData.setJournalOrCollectionTitles(referenceRepository.findDistinctJournalOrCollectionTitles());
autoCompleteData.setPublicationTitles(referenceRepository.findDistinctPublicationTitles());
autoCompleteData.setPublishers(referenceRepository.findDistinctPublishers());
return autoCompleteData;
}
@Transactional
public void ping(int paperId) throws IOException {
pingService.addPing(findPaperById(paperId));
}
public void createByTitle(String newPaperTitle) {
Paper paper = new Paper();
paper.setTitle(newPaperTitle);
paper.setStatus(DRAFT);
paper.getAuthors().add(userService.getCurrentUser());
paper.getDeadlines().add(deadlineService.createWithOffset(new Date(), 1, ChronoUnit.WEEKS));
create(paper);
}
public void delete(List<Paper> papers) {
papers.forEach(paper -> delete(paper));
}
public void delete(Paper paper) {
deadlineService.delete(paper.getDeadlines());
paperRepository.delete(paper);
}
} }

View File

@ -0,0 +1,82 @@
package ru.ulstu.ping.model;
import jakarta.persistence.Column;
import jakarta.persistence.DiscriminatorType;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import org.hibernate.annotations.Any;
import org.hibernate.annotations.AnyDiscriminator;
import org.hibernate.annotations.AnyDiscriminatorValue;
import org.hibernate.annotations.AnyKeyJavaClass;
import org.springframework.format.annotation.DateTimeFormat;
import ru.ulstu.conference.model.Conference;
import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.core.model.UserActivity;
import ru.ulstu.grant.model.Grant;
import ru.ulstu.paper.model.Paper;
import ru.ulstu.project.model.Project;
import ru.ulstu.user.model.User;
import java.util.Date;
@Entity
@Table(name = "ping")
public class Ping extends BaseEntity {
@Temporal(value = TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date date;
@ManyToOne(optional = false)
@JoinColumn(name = "users_id")
private User user;
@Column(name = "activity_type", insertable = false, updatable = false)
private String activityType;
@Any
@AnyDiscriminator(DiscriminatorType.STRING)
@AnyKeyJavaClass(Integer.class)
@JoinColumn(name = "activity_id")
@Column(name = "activity_type")
@AnyDiscriminatorValue(entity = Conference.class, discriminator = "CONFERENCE")
@AnyDiscriminatorValue(entity = Paper.class, discriminator = "PAPER")
@AnyDiscriminatorValue(entity = Project.class, discriminator = "PROJECT")
@AnyDiscriminatorValue(entity = Grant.class, discriminator = "GRANT")
private UserActivity activity;
public Ping() {
}
public Ping(Date date, User user) {
this.date = date;
this.user = user;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public UserActivity getActivity() {
return this.activity;
}
public void setActivity(UserActivity activity) {
this.activity = activity;
}
}

View File

@ -0,0 +1,35 @@
package ru.ulstu.ping.model;
import ru.ulstu.user.model.User;
import java.util.ArrayList;
import java.util.List;
public class PingInfo {
private User user;
private List<Ping> pings = new ArrayList<>();
public PingInfo(User user) {
this.user = user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Ping> getPings() {
return pings;
}
public void setPings(List<Ping> pings) {
this.pings = pings;
}
public void addPing(Ping ping) {
this.pings.add(ping);
}
}

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