2230 Commits

Author SHA1 Message Date
41d8dbad5d simplify decompression and decoding 2023-07-12 11:25:58 +02:00
203faa4257 Remove debug messages and move data inflation into api fn 2023-07-12 11:11:15 +02:00
960f36c740 Fix BrokenPipeError handling in cqi_over_socketio 2023-07-12 10:54:52 +02:00
c3834ca400 Outsource Static Viz to extensions logic 2023-07-11 15:52:44 +02:00
572fdf3a00 Small updates custom stopword list 2023-07-11 13:40:20 +02:00
22b43a689f Merge branch 'visualizations-update' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into visualizations-update 2023-07-11 09:33:22 +02:00
deec9e8a76 Custom Stopword List Settings 2023-07-11 09:33:11 +02:00
688b96ffee remove debug messages and increase chunk size in cqi 2023-07-07 11:47:34 +02:00
a9973e9c8e Add compression to static corpus data, use chunked computation, hide read corpus ids in corpus analysis 2023-07-06 13:02:22 +02:00
413b6111df Implement fast boundary computation for ent and s s_attrs 2023-07-03 15:31:28 +02:00
a9f05fffdf Fix Error handling in corpus analysis app 2023-07-03 13:28:52 +02:00
7936ac270b Merge branch 'visualizations-update' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into visualizations-update 2023-07-03 11:17:13 +02:00
1eabf18b13 Remove timeout in cqi js 2023-07-03 11:17:07 +02:00
94dc25750c Merge branch 'visualizations-update' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into visualizations-update 2023-07-03 11:06:59 +02:00
beb157092e New visualizations for frequencies 2023-07-03 11:06:43 +02:00
1cd9540e5b Improve cqi extension structure 2023-06-30 15:36:45 +02:00
912bd7da07 Remove TODOs that are done 2023-06-30 14:18:07 +02:00
e21ef2422d cqi-js: implement timeout 2023-06-30 14:13:34 +02:00
c52c966863 Better marking for non standard cqi additions ins cqi js 2023-06-30 12:55:32 +02:00
a7a948908f Small fixes and remove old cqi_over_socketio interface 2023-06-30 12:19:18 +02:00
3a97b1a07a Remove mention of old cqi client 2023-06-30 12:11:17 +02:00
315b538c30 Replace the old js CQiClient with fully featured new one 2023-06-30 12:10:17 +02:00
07103ee4e5 Fix issues in cqi_over_sio 2023-06-29 13:17:29 +02:00
efa8712cd9 Add a full featured cqi Javascript client for cqi_over_sio 2023-06-29 12:09:28 +02:00
e816a2fb15 implement missing cqi over socketio functions 2023-06-23 09:22:34 +02:00
6c31788402 Visualization fix for real data 2023-06-22 16:38:06 +02:00
1c98c5070a Merge branch 'visualizations-update' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into visualizations-update 2023-06-22 16:23:55 +02:00
1e33366820 fix cache loading string instead of parsing json 2023-06-22 16:44:29 +02:00
71013f1dc5 Add missing data and data cache to vis data generator function 2023-06-22 16:42:28 +02:00
142c82cc36 New data structure implementation 2023-06-22 16:23:46 +02:00
f84ac48975 Add test snippet for fast cpos boundary calculation for s_attrs 2023-06-22 14:19:14 +02:00
2739dc4b4f Remove debug code 2023-06-22 13:21:19 +02:00
eb2abf8282 Merge branch 'visualizations-update' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into visualizations-update 2023-06-22 12:46:36 +02:00
529c778772 codestyle 2023-06-22 12:45:33 +02:00
be51044059 Fix cqi_over_socketio not handling cqi status correctly 2023-06-22 12:45:23 +02:00
e194ce7541 Add token category selection for freqs graph 2023-06-21 17:05:36 +02:00
19e01d6709 Script fix + small optical changes 2023-06-21 08:46:08 +02:00
d6e17e1554 Update for real data visualization 2023-06-19 18:33:36 +02:00
11b697145b Merge branch 'visualizations-update' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into visualizations-update 2023-06-19 13:42:05 +02:00
11e1789d83 visualization testing 2023-06-19 13:41:56 +02:00
f037c31b88 Add more visualization data 2023-06-19 13:22:20 +02:00
972f514e6b Implementation of visdata v2 2023-06-16 17:35:54 +02:00
e6d8d72e52 Add visualization data method to cqi over socketio 2023-06-14 14:50:04 +02:00
91e68360ac Analysis Overview fix 2023-06-14 13:57:58 +02:00
71359523ba Sort Mechanics Text Info List 2023-06-13 17:18:00 +02:00
cc508cf4eb Visualization Testing Corpus Analysis 2023-06-13 15:41:34 +02:00
b7ca2a2cf6 Add new cqi method to get data for the new corpus overview 2023-06-12 13:01:27 +02:00
21d6072f6f Query Builder input fix 2023-06-12 11:53:51 +02:00
b8bcb159a2 Hide Community Update code 2023-06-07 15:13:47 +02:00
15e7fa6dd3 Rename function 2023-06-07 14:34:29 +02:00
589c4a6c56 print deletion 2023-06-07 13:51:12 +02:00
9ffc41a133 update clickable list item 2023-06-07 13:49:07 +02:00
4944d31dd5 getUser back to CorpusList 2023-06-07 13:39:04 +02:00
62d20409ea Sleep Timer fix CorpusList 2023-06-07 11:29:00 +02:00
8aeafc33bd Admin page Corpus List fix 2023-06-07 11:23:59 +02:00
a54ff2e35a Update OCR-Models list + small fix for empty list 2023-06-07 10:35:16 +02:00
e93449ba73 Reload Dashboard after deletion/unfollow corpus 2023-06-06 15:47:21 +02:00
c2471e1848 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-06-06 15:39:53 +02:00
4c277cd685 Corpus List update 2023-06-06 15:39:47 +02:00
d6789a0388 Remove Anonymous from cfr selection in follow link gen 2023-06-06 13:47:24 +02:00
793de849ef Allow to change role by using a corpus follow link 2023-06-06 13:44:02 +02:00
f4b30433e6 Add back community update code 2023-06-06 11:48:58 +02:00
c2a6b9d746 comment out community update code 2023-06-05 16:52:20 +02:00
59950aba5b Typo fix 2023-06-05 15:55:12 +02:00
d619795815 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-06-05 15:49:19 +02:00
0e786803ee List Selection expansion & select all fix 2023-06-05 15:49:11 +02:00
ac2f27150b typo fixes 2023-06-05 14:02:53 +02:00
526fd1769e First works on adding select to joblist 2023-06-05 13:44:07 +02:00
86318b9a7d disable role select for self 2023-06-05 13:01:14 +02:00
e326e1ab81 remove debug follower list 2023-06-05 11:27:08 +02:00
2f3ddc6b81 Remove all cqi inga function code fragments 2023-06-05 10:42:52 +02:00
44d98dfa46 Add inga method to cqi_over_socketio 2023-06-01 11:24:09 +02:00
6648b3548b Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-05-31 16:10:15 +02:00
367c2ce5e0 Fix corpus follower on user page + optgroup models 2023-05-31 16:10:05 +02:00
5cc07f2e13 Some more events (unregistered for now) 2023-05-17 12:30:13 +02:00
fab259522e Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-05-15 15:18:54 +02:00
b795cfa891 Small update Corpus File List Selection 2023-05-15 15:18:44 +02:00
184e78ef0b Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-05-15 14:28:49 +02:00
202700b129 fix cqi over socketio corpus.update_db command 2023-05-15 14:28:27 +02:00
49ff1aa284 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-05-15 14:01:49 +02:00
ce32b03f4a Update Public Corpus Page 2023-05-15 14:01:41 +02:00
fbf663fee3 fix corpus reset cli command 2023-05-15 12:22:38 +02:00
66a54dae10 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-05-15 12:00:19 +02:00
60a59383c7 A better application structure 2023-05-15 12:00:13 +02:00
0cf955bd2f CorpusFile selection+restore public_corpus page 2023-05-12 13:43:38 +02:00
1c47d2a346 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-05-11 16:33:28 +02:00
336bbc39e4 Move cli interface code in package 2023-05-11 16:33:21 +02:00
595bda98ef Fix wrong admin check 2023-05-09 15:32:09 +02:00
91e42d6d92 Revert changes and fix some typos 2023-05-09 14:18:59 +02:00
8c935820e8 Better and more live updated on corpus follower actions 2023-05-08 15:20:42 +02:00
e4593d5922 Fix issue with admin view of Corpus Lists 2023-05-08 11:34:10 +02:00
c3306563f0 Change logic for colorization of followed corpora in corpus Lists 2023-05-08 11:32:28 +02:00
47b9a90cb6 Typo fix 2023-05-05 08:45:27 +02:00
b07addc5c3 (Public-)Corpus List fix+highligting owner status 2023-05-05 08:41:14 +02:00
8a85dd9e61 Live status for follower 2023-05-02 11:47:29 +02:00
c6db277436 Corpus Follower List Fix 2023-04-28 13:24:30 +02:00
6c76d27a32 Update corpus page 2023-04-27 15:11:18 +02:00
817a13dfff First take on cleaning up the corpus analysis template code 2023-04-21 15:00:54 +02:00
078f88d4ec Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-04-18 15:59:13 +02:00
2768a96133 Rename contributions create templates 2023-04-18 16:11:24 +02:00
69b5e9b48b Link fix 2023-04-18 15:55:53 +02:00
a844cdb45b Rename routes and templates in corpora package 2023-04-18 11:32:04 +02:00
8dd3669af4 checking terms of use confirmation update 2023-04-17 09:43:12 +02:00
e67dc49976 Database update 2023-04-14 11:29:49 +02:00
8538fc705f Terms of use confirmation 2023-04-13 16:08:07 +02:00
144bb38d75 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-04-12 16:49:14 +02:00
ac47a9e57f New default avatar, placeholder texts removed 2023-04-12 16:49:04 +02:00
0de14ea5db cleanup CorpusFollowerPermissions 2023-04-12 12:45:41 +02:00
98b1c15aa0 Fix some incompatible requirements 2023-04-12 09:31:01 +02:00
8e7d44ec57 Settings ui polish 2023-04-11 15:03:12 +02:00
4ca2c0c873 Fix typos and simplification 2023-04-11 13:30:38 +02:00
2fd7e35b99 Add missing imports 2023-04-11 12:39:37 +02:00
3a2295487c Fix some privacy issues 2023-04-11 11:46:33 +02:00
77fc8a42f1 Move the last bits of the settings package to the user package 2023-04-06 08:42:21 +02:00
6abf119c0c Fix some things in admin backend 2023-04-05 13:59:31 +02:00
719e6da9c8 deactivate automatic python venv activation in vscode terminal 2023-04-05 12:27:32 +02:00
ca25ea0b80 Change logic to check whether a user folder is empty or not 2023-04-05 12:05:34 +02:00
477e583be9 fix settings page delete user function 2023-04-04 09:14:32 +02:00
ee82dafb7c Fix admin user settings template 2023-04-04 09:01:51 +02:00
423709b4eb Add a prefix for nopaque's data within the application context 2023-04-04 08:56:19 +02:00
a27caaa8a2 Use a better redirect mechanic in the proxied settings route 2023-04-04 08:44:25 +02:00
87798f4781 completly move settings logic to users package 2023-04-03 16:34:03 +02:00
6e6fa49f79 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-04-03 15:25:59 +02:00
f1d8b81923 move settings related json routes to users package 2023-04-03 15:25:55 +02:00
c3d429ed83 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-31 14:28:18 +02:00
4d2d4fcc40 Add followed corpora to Corpus List 2023-03-31 14:28:11 +02:00
2289106ac7 Fix last seen not set error on admin user page 2023-03-31 14:17:08 +02:00
451a0a3955 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-31 11:47:52 +02:00
9167bffa61 New user avatar 2023-03-31 11:46:17 +02:00
491e24f0a3 Fix jobinputlist 2023-03-31 09:32:59 +02:00
43751b44ac Fix missing job status value in toast notification 2023-03-31 09:25:13 +02:00
cff4b2c588 Fix problems with new forms 2023-03-31 09:14:21 +02:00
cca0185500 Remove latest extension recommendation 2023-03-31 09:13:55 +02:00
5c776e0fb6 Move delete user method in users package 2023-03-30 13:36:11 +02:00
9ce5ff8cba add extension and setting recommendations 2023-03-30 13:07:02 +02:00
35b239877a fix missing username pattern 2023-03-29 14:32:52 +02:00
e4a8ad911f Update admin user settings 2023-03-29 14:32:35 +02:00
9b2353105e Add NopaqueForm as a base for all others 2023-03-29 09:25:08 +02:00
9de09519d6 more normalization 2023-03-28 14:19:37 +02:00
b41436c844 normalize template parameters from database 2023-03-28 14:11:46 +02:00
09b3afc880 Update message in request 2023-03-27 14:01:56 +02:00
df870c1c7d Update settings page 2023-03-27 13:56:24 +02:00
020de69e45 settings update 2023-03-27 10:22:43 +02:00
9e58578761 fix wrong link in request 2023-03-24 13:57:47 +01:00
5b6eae7645 Cleanup 2023-03-23 17:42:51 +01:00
57813b4bc2 Fix link issues 2023-03-22 12:06:33 +01:00
622d32fa45 UI enhancements 2023-03-21 10:50:29 +01:00
a676475b55 Fix JobList delete function 2023-03-21 09:14:16 +01:00
f2bbcdc441 Rename manual modal template 2023-03-20 16:02:12 +01:00
685db81c85 Fix TesseractOCRPipelineModelList.js 2023-03-20 16:00:54 +01:00
575eeae94a Fix errors from settings move 2023-03-20 16:00:25 +01:00
3d4403e997 Move breadcrumbs 2023-03-20 15:33:49 +01:00
333e6b268e Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-20 15:32:45 +01:00
ff4406aaae Move elements in navigation bars 2023-03-20 15:31:25 +01:00
41096445a6 small update settings page+new package 'settings' 2023-03-17 15:56:37 +01:00
823e42faf0 Replace roadmap with manual 2023-03-16 10:31:58 +01:00
faf5a61808 Update sidenav 2023-03-16 09:58:56 +01:00
f8e94a721f Change how the user avatar is exchanged between client und server 2023-03-16 09:54:48 +01:00
7ea7b6d7a7 Rework sidenav 2023-03-16 09:29:57 +01:00
268d00ce72 Icon + public profile section update on edit page 2023-03-15 12:46:17 +01:00
666397046d Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-15 09:42:13 +01:00
8d21bfe434 Small fix edit profile page 2023-03-15 09:42:07 +01:00
743ed52fd6 Align carets on the right 2023-03-15 09:37:36 +01:00
0f8c1b1cb4 New profile page 2023-03-15 09:24:09 +01:00
bd86a71222 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-15 09:19:14 +01:00
464ae8ecc3 New user Settings page 2023-03-15 09:18:11 +01:00
fac6ba11ed Move settings 2023-03-14 15:41:23 +01:00
0520caeddd fix 2023-03-14 14:27:41 +01:00
6e9a6fa5a1 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-14 14:25:10 +01:00
4c97929b1b Move contributions to dashboard 2023-03-14 14:25:05 +01:00
2efc9533ec Add breadcrumbs to admin package 2023-03-14 14:24:52 +01:00
f1be57e509 Avatar condition and breadcrumb update 2023-03-14 14:21:23 +01:00
777151b2bf Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-14 13:32:42 +01:00
c14abf5200 Javascript Changes users 2023-03-14 13:32:32 +01:00
b8e63d2342 Add Icons for users breadcrumbs 2023-03-14 12:20:29 +01:00
8dba78c474 Return default user avatar if not set 2023-03-14 12:12:05 +01:00
8aebe27aa8 Fix wrong route decorator 2023-03-14 11:58:06 +01:00
a9767bf3c3 Add breadcrumbs to users package 2023-03-14 11:44:15 +01:00
c91004d6ba Implement flask-breadcrumbs everywhere 2023-03-14 11:13:35 +01:00
bac526b927 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-13 16:23:51 +01:00
90ac30bba3 Implement Flask-Breadcrumbs 2023-03-13 16:22:42 +01:00
4c05c6cc18 merge settings into users route 2023-03-13 15:04:44 +01:00
018805a1b6 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-13 13:29:08 +01:00
646f735ab2 Reviewed User package and invite user optical fix 2023-03-13 13:29:01 +01:00
eec056e010 Change template base variable name 2023-03-13 12:05:35 +01:00
f348d1ed23 Add missing method to route 2023-03-13 11:24:01 +01:00
e03b5258ef Codestyle enhancements 2023-03-13 09:49:59 +01:00
ca53974e50 Update the generic error handling again. Added type hints 2023-03-13 08:36:51 +01:00
5c2225c43e Let the generic error handler generate json again 2023-03-13 08:20:09 +01:00
a1af3e34d2 Remove unused print statement 2023-03-13 07:58:33 +01:00
7e54d56ed5 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-10 17:03:48 +01:00
bda18e64c8 Small Dashboard Job List fix 2023-03-10 17:03:37 +01:00
b6f155a06b Fix error_handler 2023-03-10 15:17:24 +01:00
ecb577628b Remove debug comments 2023-03-10 14:55:10 +01:00
6ba3f9c849 Add settings to project vscode settings.yml 2023-03-10 12:56:09 +01:00
2529dfeb62 remove testroute 2023-03-10 12:07:18 +01:00
c589fd1f78 Remove unused function in utils 2023-03-10 10:34:46 +01:00
21819bfd9b Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-10 10:33:16 +01:00
aaf14a9952 Rework corpora package 2023-03-10 10:33:11 +01:00
57a598ed20 Reviewed Job Package 2023-03-10 08:47:03 +01:00
3789f61ca4 scripts fix 2023-03-09 15:10:55 +01:00
42b421c2e0 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-09 14:56:44 +01:00
d6fcaa97bf rework jobs package 1/2 2023-03-09 14:55:52 +01:00
465a7dc0af Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-09 14:55:12 +01:00
59de68e6fa More rework 2023-03-09 14:55:08 +01:00
5f27ce2801 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-09 13:18:47 +01:00
92cc2cd419 pagination fix, 1st example implemantation corpora 2023-03-09 13:18:39 +01:00
fdad10991c More restructuring 2023-03-09 12:07:16 +01:00
53bba2afb0 Restructure Contributions with nested blueprints 2023-03-08 15:22:40 +01:00
6bb4594937 Restructure javascript 2023-03-08 11:42:53 +01:00
0d7fca9b0b Fix logic error 2023-03-08 10:41:54 +01:00
0e7e5933cc Better exception handling in json-routes 2023-03-08 10:34:46 +01:00
09fdad2162 Standardize code for reference 2023-03-07 16:34:49 +01:00
9272150212 combine content_negotiation related decorators 2023-03-07 16:32:15 +01:00
cb830a6f9b Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-06 15:04:11 +01:00
7770d4d478 Restructure toggle ispublic requests 2023-03-06 15:04:06 +01:00
cfa4fa68f2 Remove dev route 2023-03-06 15:03:33 +01:00
b98e30022e restructure corpus routes file and add new decorators 2023-03-06 15:03:13 +01:00
4fb5f2f2dc Add content negotiation related route decorators 2023-03-06 15:02:46 +01:00
fecbb50d39 bug fixes and unfollow_corpus update 2023-03-06 12:27:24 +01:00
8a55ce902e color SCSS update social area+ decorator fix 2023-03-02 15:08:50 +01:00
b364480de6 Public Page update 2023-03-02 09:59:47 +01:00
e11b2e3c1a Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-02 09:57:59 +01:00
2dc7efbc8d Update follow corpus by token method 2023-03-02 09:57:43 +01:00
c01068e96b cleanup imports 2023-03-01 16:33:29 +01:00
73cb566db2 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-03-01 16:33:03 +01:00
145b80356d Redesign corpus page and add possibility to add followers by username for owner 2023-03-01 16:31:41 +01:00
ed195af6a2 corpus follower permission decorator update 2023-03-01 15:14:51 +01:00
b1586b3679 social-area page and profile page update 2023-03-01 14:09:15 +01:00
ec6d0a6477 corpus permission decorator + sidenav update 2023-02-28 10:27:10 +01:00
d2828cabbe Explanation update and profile link button 2023-02-24 15:46:44 +01:00
8b01777318 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-24 15:22:33 +01:00
e2ddbf26f1 Update User Card and Share link with specific role 2023-02-24 15:22:26 +01:00
3147bed90a codestyle enhancements 2023-02-24 10:34:42 +01:00
c565b08f9c Found a better solution for default role assignments 2023-02-24 10:30:42 +01:00
ff3ac3658f Yet another small fix 2023-02-24 10:02:28 +01:00
17ec3e292a Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-24 09:47:18 +01:00
122cce98a1 another small fix 2023-02-24 09:46:35 +01:00
cb31afe723 small fix 2023-02-24 09:44:09 +01:00
d0b369efaf Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-24 09:30:43 +01:00
b27a1051af import share link token generation to models.py 2023-02-24 09:30:29 +01:00
0609e2cd72 Fix follow corpus mechanics 2023-02-24 09:27:20 +01:00
1d85e96d3a Let the Corpus owner change Roles of followers 2023-02-23 15:18:53 +01:00
132875bb34 Remove unused import 2023-02-23 13:06:06 +01:00
9e5bb7ad90 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-23 13:05:11 +01:00
38d09a3490 Integrate CorpusFollowerRoles 2023-02-23 13:05:04 +01:00
a459d6607a Update Share Link 2023-02-23 09:50:09 +01:00
5881588160 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-22 16:00:11 +01:00
3ad942f17b Share link implementation for followers 2023-02-22 16:00:04 +01:00
1be8a449fe cleanup in models file 2023-02-22 09:35:19 +01:00
288014969a Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-21 16:23:14 +01:00
68dc8de476 Add function to dynamically add followers to CorpusFollowerList 2023-02-21 16:23:10 +01:00
4fab75f0e2 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-21 16:18:58 +01:00
726e781692 share link generator update 2023-02-21 16:18:04 +01:00
d699fd09e5 Add live data updates for corpus follower lists 2023-02-21 13:59:11 +01:00
ff238cd823 Change style of contributionlists 2023-02-21 11:05:23 +01:00
8d70e93856 Update CorpusFollowerAssociation table 2023-02-21 11:05:09 +01:00
8168a2384f Add unfollow and view function to corpusfollowerlist 2023-02-20 16:15:17 +01:00
2dc41fd387 Add CorpusFollowerList and functions 2023-02-20 10:40:33 +01:00
5837e05024 Add routes for CorpusFollower permission management 2023-02-15 16:17:25 +01:00
112d1ec020 Merge branch 'public-corpus' into development 2023-02-15 11:32:44 +01:00
fc8517649f Remove debug messages and more leftovers 2023-02-15 11:31:47 +01:00
dcdb71ac74 Remove more UI leftovers from community update 2023-02-15 11:30:27 +01:00
23cdfb1441 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-15 11:00:10 +01:00
3e8bc5214c Remove public share mechanisms until legal matters are clarified 2023-02-15 10:56:54 +01:00
df1862b0a4 Bump Flask-Hashids version 2023-02-15 10:42:55 +01:00
1f7baa6390 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-13 10:17:05 +01:00
8595e2a203 Share link expiration update and small fixes 2023-02-13 10:16:44 +01:00
874c963cc4 Fix some list problems 2023-02-10 14:51:47 +01:00
1767ceee01 Remove function call of missing function 2023-02-10 09:53:59 +01:00
dabf0d1344 Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-10 09:43:05 +01:00
33a54b6206 Corpus first share link 2023-02-10 09:37:31 +01:00
428400df3f Add public switch without form 2023-02-09 16:22:37 +01:00
1f9ff9884d Merge branch 'public-corpus' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into public-corpus 2023-02-09 15:25:13 +01:00
5a4464ebb3 Change sqlalchemy version 2023-02-09 15:24:33 +01:00
e03b54cfcd update public corpora list on dashboard 2023-02-09 14:03:03 +01:00
91a800f7fd Add analyse button in public corpus pages 2023-02-09 12:10:37 +01:00
52fa23ff65 Fix some problems after merge 2023-02-09 12:02:00 +01:00
66fbf4d57b update corpus public page 2023-02-09 11:56:02 +01:00
4d227415d9 Merge branch 'development' into public-corpus 2023-02-09 11:54:58 +01:00
b83f8e8fb9 Fix admin lists 2023-02-09 11:33:16 +01:00
f06508b412 New Public Corpus Page 2023-02-09 11:21:03 +01:00
71d13d482b Add back old news implementation 2023-02-09 11:07:13 +01:00
a7136df5d2 let followers analyse corpus 2023-02-09 11:06:03 +01:00
965bc9d68a Update public corpus logic 2023-02-09 11:05:27 +01:00
817c9c376f Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2023-02-08 15:57:25 +01:00
5b6e889443 New public corpus route 2023-02-07 16:06:09 +01:00
96520fa46f Merge branch 'following-mechanics' into development 2023-02-07 08:58:30 +01:00
2b164fc51d remove new news system as it needs more work 2023-02-06 15:50:07 +01:00
ea48e479f2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2023-02-06 12:12:28 +01:00
c8cfbc8e21 Query Builder fix and placeholder change 2023-02-06 12:12:19 +01:00
2546884816 Add missing migrationscript messages 2023-02-06 11:48:01 +01:00
bd6f94582b some testing 2023-02-06 10:52:36 +01:00
b0f61b28fe Small changes on the Corpus page 2023-02-02 09:14:50 +01:00
1f27749661 Compatibility fix 2023-01-31 14:12:40 +01:00
e2cdcd3f7c first implementation of follow mechanics 2023-01-31 08:59:42 +01:00
bba79f6494 Add .vscode config files 2023-01-25 16:03:28 +01:00
75df6cafa8 Downgrade Python version to match Python current Ubuntu LTS package version 2023-01-25 16:03:09 +01:00
97bba2498b Add m2m corpus-follower table 2023-01-23 11:50:12 +01:00
62bd21ad84 Update Flask Hashids 2023-01-20 08:58:41 +01:00
7a9e6f5d6f Add an icon for the export button 2023-01-19 15:02:51 +01:00
d025e7c3c7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2023-01-19 14:59:13 +01:00
14820643ed Add export options to subcorpora 2023-01-19 14:59:09 +01:00
eb2d7d9538 User following mechanics 2023-01-19 08:58:57 +01:00
8b8df68781 Fix dnspython version to 2.2.1 2023-01-17 09:45:07 +01:00
ce96de240d Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2023-01-16 15:46:30 +01:00
f36b4fb317 Add a first csv export idea 2023-01-16 15:46:26 +01:00
8b7c334007 Corpus Following Functions & small QB fix 2023-01-16 15:43:43 +01:00
d669ed3ffc New SpaCy NLP Version 2023-01-16 08:26:17 +01:00
112be76217 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2023-01-12 16:26:38 +01:00
7b20b11c6e add user_corpus m2m relationship 2023-01-12 16:26:33 +01:00
f4a378d9d3 Query Builder fixes 2023-01-12 15:40:28 +01:00
0bf54ad00b Updated Clean Up 2023-01-12 10:05:14 +01:00
b832536f2b Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2023-01-12 09:26:08 +01:00
f1b9680764 Cleanup of tests to push into live system 2023-01-12 09:25:58 +01:00
d462c1e4d6 Rename PublicUserList to UserList 2023-01-11 13:47:09 +01:00
ce03201133 Remove debug message 2023-01-11 13:39:48 +01:00
f972c13b81 Fix contributionslists share toggle 2023-01-11 13:29:47 +01:00
632aab258b Simplify News aggregation 2023-01-10 10:04:15 +01:00
6facf133bc Update some html to element generation code 2023-01-10 10:04:01 +01:00
900ef1ad6d Simplify onclick code for ressource lists 2023-01-10 10:03:27 +01:00
0891176fd7 Use the move curser for draggable="true" elements 2023-01-10 10:02:32 +01:00
0222a1f16e Fix Ressource Displays to show status again 2023-01-10 10:01:54 +01:00
ecea33ffa9 Make Utils functions more stable 2023-01-09 10:03:52 +01:00
7836774fef Update AdminUserList 2023-01-09 08:45:47 +01:00
381716f87a Enhance list onClick handling 2023-01-05 15:03:59 +01:00
9977128cb9 Remove old resource lists 2023-01-05 14:12:22 +01:00
52249351a4 fix flask-hashids verison 2023-01-05 09:26:15 +01:00
d6b772c2e8 Remove helper comments 2023-01-05 08:11:27 +01:00
8b18571725 Rework all Resource Lists 2023-01-04 20:00:37 +01:00
7b88493e7d Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2023-01-03 17:03:56 +01:00
77b58d03c3 Change List.js integration and rename service-icon css 2023-01-03 17:03:47 +01:00
647969ef0e profile to users 2022-12-23 18:08:33 +01:00
30739f9111 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-12-23 09:56:01 +01:00
5e34252cb4 Fix ID/Hashid Problem 2022-12-23 09:55:46 +01:00
980b8cc1d3 Codestyle enhancements 2022-12-22 16:02:12 +01:00
320811279c Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-12-22 13:58:00 +01:00
598f67078a Change how user data is get and subscribed 2022-12-22 13:57:55 +01:00
55b7428045 Manually add Caroline Minuscle Model to HTR service 2022-12-22 13:57:37 +01:00
e633b834c6 Adding date and time to news content 2022-12-21 15:23:59 +01:00
f5a1cf75dd Bug fixes and new styling for the news page 2022-12-21 14:38:17 +01:00
c79bc1ed57 Update Dashboard2 2022-12-21 14:34:53 +01:00
14d7dfc957 Update some logic for avatars 2022-12-19 16:25:10 +01:00
c27d6ec0fe use hashid for serialization 2022-12-19 15:46:17 +01:00
b8637fcb9f Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-12-19 15:37:48 +01:00
c00f5230a1 Some changes for profile 2022-12-19 15:35:06 +01:00
7674550f33 Merge branch 'profile-page' into development 2022-12-19 15:04:00 +01:00
7d368ed0ac Avatar picture dashboard list 2022-12-19 15:02:43 +01:00
c0d015acd8 Merge branch 'profile-page' into development 2022-12-19 12:51:06 +01:00
d9699b9c6d Avatar Update 2022-12-19 12:46:18 +01:00
9904e54c51 Add dashboard2 2022-12-15 09:53:19 +01:00
5a396ce214 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-12-13 15:05:20 +01:00
3c4bf096d4 Merge branch 'profile-page' into development 2022-12-13 15:05:08 +01:00
61a6ddd4be Privacy settings for profile pages 2022-12-13 15:01:04 +01:00
a413b41dfd Update News page 2022-12-12 15:37:33 +01:00
69152f5e6a Remove PublicCorporaList.js 2022-12-12 13:18:22 +01:00
65c907a990 Add search functionality to public corpora page 2022-12-07 14:12:30 +01:00
f056a15ba8 Merge branch 'development' into public-corpora 2022-12-07 14:05:21 +01:00
c51a47a9aa Add first work for masto news and update public coropora page 2022-12-07 14:04:36 +01:00
85330a42f7 Merge branch 'profile-page' into development 2022-12-07 14:03:31 +01:00
7856e97402 Social area update 2022-12-07 14:02:33 +01:00
3ee62f0a82 profile page update for other users 2022-12-05 16:25:54 +01:00
91f38a4713 update migrations script 2022-12-05 09:50:42 +01:00
be517a04af Update profile page with avatar 2022-12-05 09:40:02 +01:00
620d9d1ea2 add missing file 2022-11-30 15:13:52 +01:00
7be410d66a Change migrationscript running order 2022-11-30 15:13:20 +01:00
4e6aec3575 Merge branch 'development' into public-corpora 2022-11-30 14:59:10 +01:00
c8d7de434f Extend CorpusList for use in public corpora route 2022-11-30 14:58:45 +01:00
b98e711ad5 Merge branch 'profile-page' into development 2022-11-30 14:56:17 +01:00
a009bbe1f9 Profile page 2022-11-30 14:36:42 +01:00
102772d1a7 user settings page 2022-11-29 16:46:33 +01:00
5491cb184a add all files for last commit 2022-11-29 15:28:10 +01:00
5864aa653e standardize db col names and some preliminary work for public corpora 2022-11-29 15:27:50 +01:00
f8d4b601f7 Fix corpus building process for vrt files without entities 2022-11-25 10:46:46 +01:00
aff85f2145 Remove last edited date from FileMixin 2022-11-24 12:24:29 +01:00
28b1461ef9 Fix tesseract-ocr-pipeline job creation process 2022-11-24 12:24:11 +01:00
9c49c164de update icon 2022-11-22 09:31:00 +01:00
37fb764d15 update icon 2022-11-22 09:28:25 +01:00
c0f6c9333c update contribute share button 2022-11-21 16:35:11 +01:00
0128c6310b Bug fixes 2022-11-21 15:41:07 +01:00
3f5750a000 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-11-21 14:22:23 +01:00
5df3c8be35 bug fixes 2022-11-21 14:08:49 +01:00
a822a2e3a0 Fix issues 2022-11-18 16:02:24 +01:00
3e9d749574 Small fix titles 2022-11-18 13:46:52 +01:00
2ef5063a44 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development
update breadcrumbs
2022-11-18 13:37:36 +01:00
3d170487eb Update breadcrumbs contributions package 2022-11-18 13:36:58 +01:00
7dbbf9db48 Let everyone upload new models 2022-11-18 13:28:58 +01:00
01caa88b1c Use spacy-nlp-pipeline 0.1.1 as new latest version 2022-11-18 12:33:00 +01:00
9216f4ea1d update service version 2022-11-18 12:24:21 +01:00
821571e97f Some updates regarding contributions 2022-11-18 11:51:41 +01:00
3004334d05 simplification 2022-11-17 13:10:06 +01:00
b0447e2544 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-11-17 13:07:25 +01:00
56add67481 rename toggle public status routes 2022-11-17 13:06:12 +01:00
f4ec47ad57 Share toggle update & fix 2022-11-17 12:48:19 +01:00
9c8271aec5 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development
share toggle update in contributions
2022-11-17 12:12:31 +01:00
d412f2c61a share toggle update in contributions 2022-11-17 12:11:21 +01:00
bbea1553b8 Remove darkmode setting 2022-11-17 10:52:46 +01:00
e92624f0c0 Simplify code for editing models via forms 2022-11-17 10:46:16 +01:00
527ab5ac0f better job form handling 2022-11-16 16:05:34 +01:00
f1677e2931 Fix url issues and remove unused modules 2022-11-16 14:15:52 +01:00
1f896b9bff fix wrong urls in contributions 2022-11-15 15:22:41 +01:00
9d34a5b71b Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-11-15 15:11:19 +01:00
cd72614c0f Contributions update revised 2022-11-15 15:11:16 +01:00
7bfbe4fd32 Merge branch 'binarization-threshold' into development 2022-11-14 15:53:48 +01:00
df5ae19e68 Addition pipeline_name in Contribution Package 2022-11-14 15:02:41 +01:00
176a67757a small fixes 2022-11-14 12:25:26 +01:00
9502891536 Merge branch 'development' into binarization-threshold 2022-11-11 15:39:40 +01:00
6164c3e7d9 Add migration script message and formatting 2022-11-11 15:01:32 +01:00
622d99155e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-11-11 14:59:17 +01:00
346f8f1dc5 Update Dockerfile logic 2022-11-11 14:59:14 +01:00
ca4abc3269 Small fixes 2022-11-11 13:38:41 +01:00
79d76f158f update binarization threshold 2022-11-10 16:19:58 +01:00
a8af1f3d23 vtest image testing 2022-11-10 13:33:13 +01:00
f4f0628b60 Ocropus nlbin threshold extension 2022-11-10 12:14:03 +01:00
ad17ec2cc8 Preliminary work for nlp model runtime integration 2022-11-09 13:51:42 +01:00
033872718e Small changes in the contribution package 2022-11-08 14:11:57 +01:00
05340ea7ff Contribution Package Spacy NLP 2022-11-07 09:15:38 +01:00
46ba14b923 Contribution Package Tesseract OCR 2022-11-03 15:38:35 +01:00
024eeaa063 Merge branch 'development' into contributions 2022-10-26 12:13:39 +02:00
1faa98b4e8 Adjustment Contribution Package 2022-10-26 12:02:53 +02:00
6f353684e7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-10-26 10:39:29 +02:00
0c809cc75c Merge branch 'contributors-update' into development 2022-10-26 10:38:25 +02:00
a2fd880a16 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-10-26 10:34:11 +02:00
0b656d3cf1 Add parallel fs changes to migration scripts and cleanup 2022-10-26 10:34:07 +02:00
24851b38d9 Move route, cleanup and first fixes 2022-10-26 10:23:22 +02:00
36d3ea2ce0 Remove helper comments and add service versions dynamically to select. 2022-10-26 10:12:54 +02:00
40a71ad9dd fix model contribution. 2022-10-25 13:07:10 +02:00
0b3456f877 Small fixes 2022-10-24 15:01:13 +02:00
cbf3abb424 Add SpaCyNLPPipelineModel to flask shell context 2022-10-21 13:33:25 +02:00
8bee4196d3 URL revision 2022-10-21 09:46:15 +02:00
0009a0bacf Query Builder implementation 2022-10-20 15:52:25 +02:00
20b1a96862 New CSS File 2022-10-13 15:15:53 +02:00
b9e5939c1b Add SpaCyNLPModel database model 2022-10-13 15:05:54 +02:00
89ccca11eb Add new configuration variable to .env template 2022-10-13 11:09:47 +02:00
2ead38bbe4 Add new config option. DOCKER_NETWORK_NAME 2022-10-12 15:32:47 +02:00
399d41dd08 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-10-12 15:10:58 +02:00
dc3709decb Remove the TranskribusHTRPipelineModel and fetch data on request. 2022-10-12 15:10:55 +02:00
2e45db10ca Optical adjustments 2.0 2022-10-12 14:08:42 +02:00
f96bac93f2 Optical code adjustments 2022-10-12 14:05:01 +02:00
236d3e7ee4 Rename tables for pipeline models 2022-10-12 10:23:05 +02:00
2470c8dfef Remove redundant code 2022-10-11 11:32:50 +02:00
25b3939cc2 Merge branch 'master' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque 2022-10-07 09:45:07 +02:00
086fe22649 Fix some bugs in corpus analysis and simplify code 2022-10-07 09:43:11 +02:00
ca27f2e6f2 Fix TranskribusHTRModel display problems 2022-10-04 15:33:51 +02:00
1c8f4f7e9c Add is_public column to corpora db table 2022-10-04 15:33:22 +02:00
40348cebe1 Remove version change handling in templates as it is already implemented in CreateJobForm.js 2022-10-04 15:32:31 +02:00
0e982e0749 Remove QueryBuilder artifacts from merge 2022-10-04 13:24:04 +02:00
970bd25f4c Make migration script messages more precise 2022-10-04 13:06:15 +02:00
5fb4329d5f Add tesseract-ocr-pipeline and transkribus-htr-pipeline v0.1.1 2022-10-04 13:05:20 +02:00
b662a3a4d1 Configure migrate to detect type changes in models 2022-10-04 13:02:11 +02:00
9802fdd175 Add form and template for adding a model. 2022-10-02 23:49:14 +02:00
61098535be Update gitignore. 2022-10-02 23:47:15 +02:00
740ebcb40d small url creation fix 2022-09-20 15:11:20 +02:00
dc86c1e85d fix wrong url creation 2022-09-20 15:02:44 +02:00
650a77f055 Remove merge leftover 2022-09-07 15:16:32 +02:00
7372e538f4 Add querybuilder js file 2022-09-07 14:56:40 +02:00
7fe183bf2a Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2022-09-07 14:53:51 +02:00
f46544451e Code Style 2022-09-07 14:47:42 +02:00
f09403e61d QueryBuilder 1.1 2022-09-07 14:22:59 +02:00
d537a38712 Querybuilder 1.0 2022-09-07 09:06:21 +02:00
ceef272d06 Add API functionality 2022-09-02 13:24:14 +02:00
dedccad70a Restructure project 2/2 2022-09-02 13:08:01 +02:00
8e1d94bb5d Restructure project 2022-09-02 13:07:30 +02:00
ec9225b881 Restructure imports (3rd party imports first) 2022-09-02 13:02:04 +02:00
8f03c2aea7 Add some handy css classes 2022-09-02 12:57:30 +02:00
131afd6419 New logic for forms including file upload. 2022-09-02 12:56:59 +02:00
9781425602 Query Builder New Design 2022-08-03 16:21:11 +02:00
4497567de0 Final prototype 2022-08-01 10:00:12 +02:00
7acb3b40c2 use hashids in jwt 2022-07-18 17:37:05 +02:00
1f3ca9664d Remove dummy /users route 2022-07-18 17:10:44 +02:00
29900f3ab1 Update some JS libraries 2022-07-18 17:10:21 +02:00
1de9fce854 Switch from Authlib to pyJWT 2022-07-18 17:10:09 +02:00
12bba0564f Migrate to Flask 2 2022-07-15 12:24:04 +02:00
bab98c52a1 Move docker-compose example files in subdirectory 2022-07-15 12:22:19 +02:00
81e5027544 Add settings from VSCode Docker extension 2022-07-15 12:16:54 +02:00
5cbc6ea822 Prototype Query Builder for demo only 2022-07-13 14:06:22 +02:00
42ad6e27e2 Add Contributions Mockup and fix email notifications on job status change 2022-07-11 12:14:01 +02:00
018f9e752c Fix event names 2022-07-08 15:52:15 +02:00
4e5957eea2 Change the Subscription Logic for Socket.IO Data exchange 2022-07-08 11:46:47 +02:00
5771e156ce Change the APScheduler Logic and try to catch more errors in Daemon 2022-07-04 14:11:10 +02:00
76924956de Change the user session SocketIO Logic 2022-07-04 14:09:17 +02:00
b8bf004684 Restructure code and use APScheduler for daemon functionality 2022-06-28 12:30:02 +02:00
7c52d3f392 Add Hint on how to store your job data 2022-06-14 12:00:22 +02:00
7e8f24e6bf Fix model selection in HTR service page 2022-05-19 09:56:14 +02:00
31f91aaecb Fix model selection 2022-05-17 16:16:31 +02:00
b4a9f81dfb Fix README 2022-05-17 16:16:22 +02:00
4016af23f0 Fix some dependencies 2022-05-17 16:16:14 +02:00
8136cedccb Add a manual page 2022-05-17 15:31:05 +02:00
6b8d4d87bb Fix a JS error regarding non existent data for query results 2022-05-05 15:11:36 +02:00
80a18386ee Fix some display issues on smaller screens for the landing page 2022-05-05 15:11:02 +02:00
a4e65cac33 Update FAQ 2022-05-05 15:10:44 +02:00
c7c9fece46 Bump Socket.IO client version 2022-05-05 15:10:28 +02:00
7362bb5514 Codestyle enhancements 2022-05-05 15:10:03 +02:00
0a8b32e57e Config cleanup 2022-05-05 15:07:36 +02:00
b4082a2547 Update services.yml 2022-04-29 13:04:03 +02:00
7b10a6be2e Add April 2022 update news 2022-04-28 14:35:05 +02:00
d61e68c690 Add necessary environment variable in development docker compose 2022-04-28 14:34:48 +02:00
603212e1df Fix add corpus file form 2022-04-26 12:05:46 +02:00
d68f30db8b Add transkribus models 2022-04-25 16:09:06 +02:00
d076b25189 Update .env template 2022-04-25 15:21:39 +02:00
51af30aff3 Fix credential issues 2022-04-25 15:21:30 +02:00
10b5254e82 Restructure code 2022-04-25 11:32:10 +02:00
fc1389e8b1 Change the scaling logic and switch back to the socketio web server 2022-04-22 16:36:12 +02:00
ccdd0d3faa Integrate TranskribusHTRModels 2022-04-22 15:27:52 +02:00
9d4001f469 Reimplement corpus import and activate it again 2022-04-19 11:48:44 +02:00
de4a83582d simplify form code 2022-04-19 11:48:14 +02:00
d35ca7c261 Disable binarization for old ocr service versions. Add new ocr service version (including binarization) 2022-04-13 16:39:51 +02:00
43ea898394 Fix corpus build process 2022-04-13 09:47:02 +02:00
63217a7e1d Fix uploading corpus files 2022-04-13 09:08:11 +02:00
4146e3789b normalize vrt on build 2022-04-12 16:11:40 +02:00
99ddd2e3dd normalize forms 2022-04-12 16:11:24 +02:00
54b5635e9c Merge branch 'master' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque 2022-04-04 13:31:15 +02:00
ce997e69ea Rename all services, use scss, cleanup, add sandpaper conversion script 2022-04-04 13:31:09 +02:00
f425ca6fa1 Fix missing color for icons in corpus lists 2022-02-17 11:53:54 +01:00
8fd59f8078 Fix network name in traefik docker compose template 2022-02-17 09:06:37 +01:00
10768fbaa4 Remove wrong type annotations 2022-02-17 09:06:18 +01:00
15e897f005 Delete unused files, restructure assets and use scss 2022-02-15 09:25:34 +01:00
585a6ba796 Rename some IntEnumColumn related stuff 2022-02-10 12:01:31 +01:00
86d14f748f More generic implementation of fake enum db types 2022-02-09 16:02:37 +01:00
247ac801b0 Rename font files 2022-02-08 15:56:01 +01:00
27b1174a15 fix docker compose traefik template 2022-02-08 15:49:50 +01:00
91b447a861 Add log folder via dummy file to repo 2022-02-08 15:41:56 +01:00
3226b87136 Set default value for NOPAQUE_DATA_DIR 2022-02-08 15:39:15 +01:00
3ea774263b Update .env.tpl 2022-02-08 15:11:06 +01:00
df6ab3991c Use enums where appropriate. This commit includes new migrations that are NOT compatible with older nopaque instances 2022-02-08 12:26:20 +01:00
fe938c0ca2 Big update, corpus analysis reworked, versioned services, preliminary work for contributions 2022-02-03 12:39:16 +01:00
0647537192 Fix automatic id generation for RessourceLists 2022-01-14 14:14:04 +01:00
e356be77da Implement authentication with before_request in admin package 2021-12-13 12:20:32 +01:00
82543d883f Use HashidMixin from flask_hashids 2021-12-13 12:20:01 +01:00
37c244b30c Remove unused package from requirements 2021-12-13 12:19:35 +01:00
44f9d0a560 Further codestyle improvements 2021-12-09 15:39:45 +01:00
40bd169101 Some cleanup (css, html, js) 2021-12-09 12:50:14 +01:00
067273df6d Minor Codestyle updates. 2021-12-08 15:36:10 +01:00
982d5bc46f Fix broken download link in job result lists 2021-12-08 14:45:15 +01:00
3d99b8770c Codestyle enhancements 2021-12-08 14:45:05 +01:00
1fd7a2e38c Add nopaque video to index 2021-12-08 11:51:34 +01:00
832a0283bd Some styling for ressource lists 2021-12-08 11:25:52 +01:00
63527da37f Use Flask-Hashids package 2021-12-08 11:25:33 +01:00
e1004a0181 First attempts to use type hinting 2021-12-07 14:18:05 +01:00
9d30dda733 Codestyle 2021-12-06 14:42:49 +01:00
b3f34648c4 Bug fixes 2021-12-03 16:10:54 +01:00
5b5d7a6601 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2021-12-03 15:02:06 +01:00
3e37cb8582 Fix some navigation issues 2021-12-03 14:56:56 +01:00
123537cd16 Add new roles and a new permission 2021-12-03 14:07:03 +01:00
89f518fe38 Sort lists by ressources creation date. CSS and HTML cleanup 2021-12-03 12:01:50 +01:00
03a57fd7ee Create a proper class for the upload form 2021-12-02 16:25:48 +01:00
d8f11a9759 update nopaque forms 2021-12-02 13:48:48 +01:00
962e58f2d3 Enable auto initialization for ressource lists 2021-12-02 11:16:06 +01:00
f977c808ec Even better solution for concurrent promise handling 2021-12-01 17:52:09 +01:00
ff514368c3 Try to avoid requesting user data multiple times 2021-12-01 17:07:05 +01:00
82745629bc Bug fixes 2021-12-01 16:03:55 +01:00
12ec6be60b JS codestyle enhancements 2021-12-01 14:15:20 +01:00
72ba61f369 Only reveal hashids to the ui 2021-11-30 16:22:16 +01:00
3e227dc4cf Remove deploy token from template. The token is already revoked so no need to be concerned! 2021-11-25 15:41:50 +01:00
33c87cb6d9 Remove deploy token from template. The token is already revoked so no need to be concerned! 2021-11-25 15:40:09 +01:00
9308618e63 New faq and service desk 2021-11-18 12:09:15 +01:00
904747ec66 Add dependencies and missing exception handling 2021-11-18 08:39:56 +01:00
a2e4fd2df5 Add news regarding current maintenance state 2021-11-16 15:50:07 +01:00
f6c2292e03 Big Corpus analysis update 2021-11-16 15:23:57 +01:00
c1436c2a5d Add model section to template and add API link to sidenav 2021-11-15 14:54:08 +01:00
70d541690f Add 503 error handler 2021-11-15 14:36:18 +01:00
f711eec53b Remove access log from gunicorn 2021-11-15 14:35:37 +01:00
3a23fb5dc8 Add new config variables 2021-11-15 14:34:07 +01:00
b43ec14424 Change docker-compose traefik config to match new development toolbox 2021-11-15 14:19:07 +01:00
4988e5e9a6 Fix some bugs in tests 2021-11-15 14:10:28 +01:00
99674e6a7f Bump Python version 2021-11-15 14:09:55 +01:00
2f2992da3a Remove deleted file from Dockerfile 2021-09-22 14:15:53 +02:00
1ccdccd0bc Fix cli run commands 2021-09-22 14:13:59 +02:00
8618e1b8bf Remove unused files. 2021-09-22 14:01:47 +02:00
ee0efcf17f Rename cli functions to not interfere 2021-09-22 13:58:46 +02:00
17cbfd71b4 Rename TaskRunner to Daemon (because it essentially is one) and restructure cli 2021-09-22 13:53:39 +02:00
e0219e84c9 Preliminary work for better socket.io event handling. 2021-09-22 13:52:51 +02:00
d29190907f code cleanup 2021-09-22 13:51:45 +02:00
1832f1d3c8 Remove unused import 2021-09-22 13:50:43 +02:00
08fec74cff Use threading.Thread for @background decorator again. 2021-09-22 13:50:26 +02:00
371cd30893 Let socketio decorators return instead of randomly emiting messages. 2021-09-22 13:49:22 +02:00
0d96a572e4 Change api root routes, so that they don't have a trailing slash 2021-09-16 14:20:18 +02:00
5469bd0ec1 Don't use module level logger functions 2021-09-16 11:15:31 +02:00
2af74db46f Make it possible to configure different log levels for stderr and file logging 2021-09-16 11:04:47 +02:00
e2c68a1a80 Enable advanced logging features 2021-09-15 17:58:17 +02:00
727553412f add flag to socketio, hope it will improve firefox compatibility 2021-09-15 15:26:43 +02:00
6c7f3be785 Let gunicorn print access log to the terminal 2021-09-15 15:26:13 +02:00
1b342d5159 Use gunicorn as the default webserver 2021-09-15 14:15:23 +02:00
34c4f38b52 Fix bug on corpus analysis startup 2021-09-15 14:14:23 +02:00
52c25fd563 Simplify Config setup and move some functions to dedicated files 2021-09-15 12:31:53 +02:00
8a69d6364a Add more examples 2021-09-14 16:17:26 +02:00
523faaea05 Fix wording 2021-09-14 13:01:19 +02:00
a5b1df9e95 Add simple api package including authentication (BasicAuth and TokenAuth) 2021-09-14 12:52:23 +02:00
def01d474e Add UTC flag to date strings 2021-09-14 12:51:49 +02:00
0a9bea0740 Remove api fragments 2021-09-13 17:38:07 +02:00
05c6f1afa6 Simplify Login mechanism code 2021-09-13 17:36:19 +02:00
81ed16603d Remove current_app and current_user usage in forms. 2021-09-13 16:36:48 +02:00
10483c1e45 Fix Date display issue in UserList 2021-09-13 16:35:09 +02:00
4950a407af rename blueprint variables (blueprint_name -> bp) and view files (views.py -> routes.py) 2021-09-13 11:45:43 +02:00
bc5c8ef074 handle email job status updates with the sqlalchemy event handlers 2021-09-10 16:25:32 +02:00
281e568edf Use ISO 8601 as the default datetime format 2021-09-08 12:56:51 +02:00
8c871d83d0 Upgrade python version 3.9.0 -> 3.9.7 2021-09-08 12:56:27 +02:00
9d59aa3409 Move event handlers to a dedicated event directory 2021-09-07 13:50:23 +02:00
0861d931ce Add an abort criterion when exporting query results 2021-08-24 09:50:32 +02:00
cedce5545d Fix wrong corpus analysis link in sidenav 2021-08-24 09:21:43 +02:00
e2669e6c25 Add missing exception handler 2021-08-23 16:43:47 +02:00
5cd18c4c2a Sort after list ressource list insertions 2021-08-23 16:34:25 +02:00
280c544297 Fix job result duplication after job restart 2021-08-23 16:31:06 +02:00
a5782f932c Do not manually emit corpus changes via socket. 2021-08-23 12:29:31 +02:00
c7b2c413d3 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2021-08-23 11:04:10 +02:00
fd5fcf9821 Change exception handling in corpus analysis 2021-08-23 11:04:09 +02:00
1a59b19124 Handle all ressource events with unified sqlalchemy event handlers. 2021-08-20 14:41:40 +02:00
98a43ec86f Use sqlalchemy events to emit jsonpatches to the client. 2021-08-18 15:11:11 +02:00
5662140a8d Add a flag to all db Model to_dict methods: include_relationships 2021-08-18 15:09:56 +02:00
869c1ba632 Fix corpus service creation 2021-08-16 12:09:50 +02:00
99c43cc1a6 some style updates 2021-08-09 11:02:09 +02:00
575dc45242 Rework a lot of daemon code. Add missing patch messages 2021-08-04 17:07:59 +02:00
da350474fb standardize the use of service name handles, e.g. file-setup instead of file_setup 2021-08-04 12:26:49 +02:00
ec7a88f36e Simplify color setup in templates 2021-08-04 09:07:18 +02:00
468b079d63 simplify gitignore 2021-07-20 15:29:42 +02:00
d6ab379418 Change directory structure (move ./nopaque/* to ./) 2021-07-20 15:07:42 +02:00
ff39d8d650 Check if a cqpserver container up for running corpus analysis sessions 2021-07-16 13:07:01 +02:00
1120d094b2 Use correct color for error messages 2021-07-16 11:10:54 +02:00
096424e1e4 Restructure some javascript 2021-07-16 10:51:39 +02:00
03adcdeebc Restructure some css 2021-07-16 10:51:14 +02:00
11a9b4f640 create small subtemplates for each block und apply new breadcrumbs logic 2021-05-28 15:51:23 +02:00
adbd212660 Update color scheme definition and some codestyle enhancements 2021-05-27 13:05:46 +02:00
bc6f06bc48 Fix Flask version number 2021-05-12 11:03:37 +02:00
33f22bb73c Remove unused imports 2021-05-12 11:03:18 +02:00
bc87bf67bf more exception handling 2021-05-08 16:47:41 +02:00
966cdc824a remove validity check of result files for now 2021-05-07 16:53:41 +02:00
2d0f6f50f8 Fix edge case problems in corpus analysis 2021-05-07 15:49:47 +02:00
a357ae2857 Remove dummy UI elements and open the CQP Tutorial in a dedicated browsertab 2021-05-05 15:05:24 +02:00
c0d337137e Designpatch 2/2 2021-05-05 10:05:12 +02:00
04e53fef98 Designpatch 1/2 2021-05-04 17:27:57 +02:00
430bcf53ea Fix non functioning sidebar button in mobile view 2021-05-03 15:59:02 +02:00
2964ab7a13 Remove nopaque title section on homepage 2021-05-03 15:58:39 +02:00
f2a5fe3143 Make Jobs restartable when they are "complete" 2021-05-03 11:12:40 +02:00
f4233093c0 Remove debug code 2021-05-03 11:12:13 +02:00
9790e783e3 Add missing migrations 2021-04-14 14:16:32 +02:00
f65ab646e9 implement fixed version numbers 2021-04-14 12:00:09 +02:00
2f9ecf8048 Update service pages and how version data is gathered. 2021-03-26 13:10:42 +01:00
55d94ea329 Use hard coded values for ressources 2021-03-26 12:15:33 +01:00
45f37fcf24 Add new nopaque icons 2021-03-26 11:35:43 +01:00
351004b795 First work on fixed versioning 2021-02-19 13:00:52 +01:00
76e3ffb9fa integrate flash method into the nopaque appClient 2021-02-09 15:05:49 +01:00
63ec304263 Make the AppClient a subscriber of current_user jobs 2021-02-09 13:59:43 +01:00
846ba31023 Only create a TaskRunner object when task execution is triggered by the cli 2021-02-09 11:10:30 +01:00
49e4c837d6 fix query_result path logic 2021-02-01 13:50:07 +01:00
ab9e5347be Add missing socketio messages 2021-02-01 13:39:38 +01:00
996ed1c790 Remove user session loop. Instead send ressource updates directly on change 2021-02-01 12:51:07 +01:00
ee9fdd1017 Use console.error for error message 2021-02-01 10:00:05 +01:00
37f98bb4ec Use the user data reference to access corpora, jobs or query results. Now all values should update as they should in lists an displays 2021-02-01 09:57:10 +01:00
54be3b4a79 Reduce daemon sleep timer even more 3 -> 1 2021-01-28 13:22:07 +01:00
a76c8f1d29 Remove Corpus.max_nr_of_tokens column, instead set it as primitve class member 2021-01-28 11:33:04 +01:00
c8dc215c02 Change db values Corpus.current_nr_or_tokens and Corpus.max_nr_of_tokens from BIGINT to Integer 2021-01-28 11:29:58 +01:00
a30ade34b1 Reduce daemon sleep timer 10 -> 3 2021-01-28 11:26:41 +01:00
9cff7d76aa Use simple Python 3 super() funtion 2021-01-28 11:26:09 +01:00
2b1a74efb8 use flush, refresh and rollback instead of intemediate commit statements 2021-01-28 11:25:02 +01:00
07191b36b2 More template code for query builder 2021-01-18 15:07:13 +01:00
ea5bace7db Add query builder template 2021-01-18 14:45:26 +01:00
6675dfc3c0 Rename UserList 2021-01-18 14:21:54 +01:00
e0bbc517e9 Use Flask-Assets to compile multiple Javascript files to one 2021-01-18 13:22:00 +01:00
6bc5e5f7b1 Remove Debug statements 2021-01-18 13:21:39 +01:00
18c96fce4b Some Renaming 2021-01-18 12:50:58 +01:00
bda7a782ec Wording update 2021-01-18 09:25:08 +01:00
8552cbd20c Merge branch 'daemon-rework' 2021-01-14 15:24:20 +01:00
84c86c81e7 Make the corpus analysis runnable again 2021-01-14 15:18:50 +01:00
223ae773d6 reference corresponding ressources (jobs/queryresults) in JobList and QueryResultList 2021-01-14 12:30:49 +01:00
f8bdfa3a04 use 'msg' instead of 'desc' key for error messages 2021-01-13 15:44:39 +01:00
4bf456d8ef Check if corpus is exportable before exporting it 2021-01-13 15:43:23 +01:00
a52db602d9 Add back corpus export. 2021-01-13 15:23:04 +01:00
0f263df9b2 User CorpusList and QueryResultList in Corpus analysis service page. 2021-01-13 12:10:31 +01:00
fc9c1a4732 Add necessary condition to enable build button 2021-01-13 12:05:25 +01:00
a8643aa9f4 Add Breadcrumbs and UserList to admin package 2021-01-13 11:57:46 +01:00
3d53b673fd Implement UserList 2021-01-13 11:57:13 +01:00
24bd0fa174 Remove table headline "actions" from ressource lists 2021-01-13 11:56:51 +01:00
16dc87bc94 Register RessourceList click event listener in base Class. 2021-01-13 11:55:58 +01:00
7b9af7ba15 Implement more patch options for lists and display dummy object if list is empty 2021-01-12 15:25:54 +01:00
1b3d0c1467 Remove analysis button in corpuslist for now 2021-01-11 15:51:56 +01:00
ea3416af4c Add build and analyze button 2021-01-11 15:43:15 +01:00
84ae5fd22a Change loading animation 2021-01-11 14:46:19 +01:00
581fd5bcb5 Seperate Lists and Displays in seperated files 2021-01-11 13:36:45 +01:00
d90b0c409c Implement remove operation for CorpusFileLists 2021-01-07 16:40:48 +01:00
009ee4365b Add back description to Corpus page. 2021-01-07 15:02:54 +01:00
9fb92c5a65 Bump Socket.IO Version and update to new List and Display logic for live data 2021-01-07 14:51:44 +01:00
1b5b935a28 Rework list handling 2020-12-15 14:38:52 +01:00
85385ef7e4 bump list.js version 2020-12-15 14:38:24 +01:00
231ce24d23 Remove unused second backup 2020-12-15 14:38:01 +01:00
1003c4494d Progress on list rework 2020-12-07 16:10:40 +01:00
1883a9bc63 Start redesign of RessourceLists 2020-12-04 14:16:11 +01:00
a2102a48ca Add url properties to db models 2020-12-04 14:16:00 +01:00
29dbdc9f94 Add URL property to some models 2020-12-03 15:13:24 +01:00
4c92fdfb6c Fix file path management and download bugs 2020-12-02 14:26:17 +01:00
9dde839148 Add migration for new database design 2020-12-02 14:25:46 +01:00
a25cbf4bb0 Add some more documentation to environment variables 2020-11-23 09:07:57 +01:00
adac32e54f Fix bug 2020-11-23 08:47:55 +01:00
501871f9a7 Remove double paginations 2020-11-22 16:03:41 +01:00
ece2d450d7 Rename label of build corpus services 2020-11-22 16:03:19 +01:00
d1b39449e8 Fix service icons in job lists, Readd publishing year in corpus_file lists 2020-11-22 16:02:51 +01:00
c3c3b70030 Change the verification, it a user is allowed to view a corpus_file 2020-11-22 16:01:59 +01:00
8cc748de94 add stuff to enable instance scaling 2020-11-19 15:20:49 +01:00
b786bbdfb1 Change default value of NOPAQUE_DAEMON_ENABLED from False to True 2020-11-19 15:20:18 +01:00
ab5db4ae83 Codestyle update (less use of #noqa) 2020-11-19 12:31:29 +01:00
66887f21b8 Add config variables to generate url outside of request contexts 2020-11-19 12:30:13 +01:00
b606710edf Do not activate the python venv, everytime you execute daemon tasks 2020-11-19 12:29:40 +01:00
ba7789224b Create send_notification function 2020-11-19 09:41:22 +01:00
ddee38e2a5 Delete old daemon package and fix typos 2020-11-17 14:58:03 +01:00
d187a83b54 Merge branch 'daemon-rework' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into daemon-rework 2020-11-17 10:16:41 +01:00
7e84b54467 Add config variables in order to create links outside of a request context 2020-11-17 10:16:40 +01:00
19338ba8d5 Add daemon loop 2020-11-13 15:01:53 +01:00
5427698a47 Remove debog print statements 2020-11-13 13:54:07 +01:00
f3f6612a57 daemon is now tasks 2020-11-13 13:33:32 +01:00
5a06a6b241 More exception handling. Remove unused database models. New common view structure! 2020-11-13 10:01:51 +01:00
cb9da5c7dd Simplify daemon logic 2020-11-09 16:14:19 +01:00
0f30e518af First steps 2020-11-06 15:07:58 +01:00
9e2cc6486c Add NOPAQUE_HOST and NOPAQUE_PORT variables 2020-11-06 10:28:05 +01:00
ab21768311 smaller rework while getting an overview 2020-11-04 14:54:27 +01:00
9c9790be89 codestyle in nopaque base template 2020-11-04 13:30:48 +01:00
3923f6dd32 Upgrade to python 3.9.0 2020-11-04 13:30:06 +01:00
eb61038fd2 Change image tag (:latest) in master branch 2020-11-03 14:19:50 +01:00
b1509c3f6a Fix scroll to top 2020-11-03 11:46:37 +01:00
5343d1b06e Remove service icon from job page headline 2020-11-03 10:12:06 +01:00
fb8bcb2f82 Fix wrong link in query results breadcrumbs 2020-11-03 10:04:18 +01:00
a92358ef21 Add color setting for disabled tabs 2020-11-03 09:57:00 +01:00
4d783492c0 Add breadcrumbs to query_results package 2020-11-03 09:53:37 +01:00
2e4983a8db Use different colors to highlight the roadmap 2020-11-02 16:33:28 +01:00
5bc2501334 Change breadcrumb start to home icon 2020-11-02 16:29:22 +01:00
ac2683776e Roadmap update 2020-11-02 15:41:58 +01:00
b060791057 Add Roadmap 2020-11-02 13:06:37 +01:00
317e1fa0d9 one color navbar 2020-11-02 11:18:50 +01:00
f21f3e007d Add breadcrumbs to corpora package 2020-11-02 10:47:38 +01:00
4c310eaea8 Add breadcrumbs to services package 2020-11-02 10:31:49 +01:00
850087f628 Add breadcrumbs to auth package 2020-11-02 10:01:02 +01:00
917005afa7 Fix z-index on parallax pages 2020-11-02 09:31:24 +01:00
e36d633771 Do not use hardcoded title in settings 2020-11-02 09:30:01 +01:00
88f32e9195 breadcrumbs intermediate 2020-10-30 15:01:41 +01:00
4d0f12129c Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-10-30 11:01:01 +01:00
4f8be203ab Add margin for <main> 2020-10-30 11:00:56 +01:00
79dd307d76 Make publishing year data required again 2020-10-30 10:58:07 +01:00
eb2f47e3a5 Add light grey background color as default 2020-10-30 10:52:46 +01:00
5010b94925 Fix color setup on job page 2020-10-30 10:35:29 +01:00
18ba922ce9 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-10-30 10:19:45 +01:00
5cc6a9ab93 Merge branch 'template-rework' into development 2020-10-30 10:02:19 +01:00
3f18064342 flag contact email adress as optional 2020-10-30 09:29:36 +01:00
0ecd61c9b3 unifiy roadmap 2020-10-29 19:21:33 +01:00
5d1a01358f rename images 2020-10-29 18:09:36 +01:00
94fa11060e Add corpus import/export and some fixes etc. 2020-10-29 15:20:30 +01:00
4052991b08 Rework corpora package 2020-10-29 14:45:55 +01:00
554702130c Apply color scheme on add corpus file page 2020-10-29 09:14:37 +01:00
ffa7a7812a Rework corpora/query results 2020-10-28 16:13:41 +01:00
9c36ed3cc8 Some finetuning 2020-10-28 15:34:12 +01:00
c305c01e55 Use two scheme colors instead of one 2020-10-28 12:25:36 +01:00
51110529e2 Remove minified material design icons css 2020-10-28 12:04:03 +01:00
2240657e8c fix multiple things 2020-10-28 11:21:05 +01:00
6757123078 Bake constants in boot.sh script instead of .env 2020-10-28 09:16:58 +01:00
1c9bd3c0fc Some cosmetics for service package 2020-10-27 14:38:00 +01:00
c8f93103c9 finetune general settings 2020-10-27 14:24:47 +01:00
934ec4af42 Set default form values in view function. Use inheritance for admin forms 2020-10-27 14:23:23 +01:00
58e5116eb3 Remove unused files 2020-10-26 13:04:48 +01:00
a996d36f2d Rework jobs package 2020-10-26 13:04:12 +01:00
73a597fdd2 Rework service package 2020-10-26 12:47:06 +01:00
03db3f8c35 Rework some basics again 2020-10-26 12:46:46 +01:00
e57822a4bd Add missing import 2020-10-26 11:23:19 +01:00
f4be897c73 Fix 2020-10-26 11:17:25 +01:00
4f8426c0b0 Merge branch 'template-rework' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into template-rework 2020-10-26 10:37:02 +01:00
0fa7812104 Add constants to config 2020-10-26 10:36:52 +01:00
21af48bc52 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-10-23 16:11:15 +02:00
c60055e8f4 Fix placeholder text color for file inputs/uploads. 2020-10-23 16:11:08 +02:00
66d848926e Add login and register menu points for mobile view 2020-10-23 14:27:29 +02:00
700e11ec23 Rename and rework profile packege (new name settings) 2020-10-23 13:52:01 +02:00
1092033a19 Update modal code 2020-10-23 10:54:06 +02:00
70a1725f31 Enhance modal code 2020-10-23 10:44:27 +02:00
6d2abeb5df Rework main package 2020-10-23 10:42:52 +02:00
e14f397ec3 Rework error package 2020-10-23 10:30:56 +02:00
310809cc51 Add missing title ids to admin pages 2020-10-23 10:26:36 +02:00
780de62db2 Rework auth package 2020-10-23 10:26:04 +02:00
b840746fed Rework admin package 2020-10-23 10:17:14 +02:00
23441dab2e intermediate 2020-10-23 08:51:46 +02:00
0ef7355ca1 Add init call to config initialization 2020-10-21 13:20:46 +02:00
eedd75ed69 Next big config update. Check the .env.tpl and db.env.tpl 2020-10-21 13:07:10 +02:00
107c944bef Fix that is described in ticket 134 2020-10-15 09:35:16 +02:00
7ce0c77a73 Avoid error if query did not yield any results. 2020-10-14 10:42:13 +02:00
93d7aa2170 Latest README update, before i forget. 2020-10-13 10:15:55 +02:00
69ad42801a Fix contact email adress 2020-10-12 17:16:55 +02:00
6e4c90f844 Update all third party css/font/js 2020-10-12 14:06:19 +02:00
4e9701b796 Add neccessary header to docker-compose.traefik.yml. 2020-10-12 14:01:42 +02:00
e7ff3984b5 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-10-12 13:28:26 +02:00
ea6ccae76a Merge content into main package 2020-10-12 13:28:19 +02:00
2dc630e877 Create extra package for errors 2020-10-12 13:26:35 +02:00
9de8cbf04e Add comment 2020-10-12 11:29:33 +02:00
31b8ea5809 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-10-12 11:07:57 +02:00
42ec04e2c8 User ...args instead of arguments object 2020-10-12 11:07:51 +02:00
cb1228c392 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-10-09 17:51:06 +02:00
5eb12d0f03 bump image version 2020-10-09 17:50:59 +02:00
dce3109cb7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-10-09 16:15:54 +02:00
4ec3ce01fa Show right match_count per text, not per last incoming chunk 2020-10-09 16:15:47 +02:00
b44a5e1113 fix indent 2020-10-09 15:32:09 +02:00
baebdbe399 Add new config variables (defaults are what you want if you don't have http to https redirect enabled) 2020-10-09 14:43:23 +02:00
e777006137 Add comment 2020-10-09 12:00:59 +02:00
1c8146e4a5 Codestyle update 2020-10-08 23:10:07 +02:00
99a8ea98e2 Rename NOPAQUE_STORAGE to DATA_DIR 2020-10-08 15:34:28 +02:00
51306cf530 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-10-08 15:09:19 +02:00
0b50764676 Fix to lowercase 2020-10-08 15:09:13 +02:00
771d399f9c Update daemon/tasks/models.py 2020-10-08 15:09:02 +02:00
fb76cf256c Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-10-08 12:50:42 +02:00
ae9d357beb fix 2020-10-08 12:48:43 +02:00
cf6f8e82ee Merge query_results into corpora blueprint 2020-10-08 12:48:29 +02:00
da53220d8c fix default setting for NOPAQUE_DATA_DIR 2020-10-08 12:47:47 +02:00
dff92cbf4d Huge config update and smtp fix for daemon 2020-10-08 12:34:02 +02:00
5e221d90ad Move query_results and interactions into corpora template folder 2020-10-08 09:48:49 +02:00
5961a3f843 Rework query_results/inspect template to load listeners from view listeners. 2020-10-08 09:25:06 +02:00
20074ebeae Move vanilla javascript event listeners into view listeners. 2020-10-07 15:52:43 +02:00
4241c13e13 Some small fixes 2020-10-07 14:48:47 +02:00
8c707fa81c Add match_count represnetation for the user. 2020-10-05 16:55:02 +02:00
f195b72ebd Add match_count for texts in results.data and results.fullResultsData. 2020-10-02 15:32:03 +02:00
370a002af3 Small fix to show 5 elements in corpus view list. 2020-09-30 10:17:33 +02:00
28213574f4 Simplify addToSubResults(). 2020-09-24 16:13:16 +02:00
3cb71c2acb FIx Typos 2020-09-24 11:11:30 +02:00
b6986e2581 Close corpus analysis init modal only if meta data has been recieved. 2020-09-24 10:13:15 +02:00
b5ec4906c5 Fix error that did not delete old results when fetching new results from the server. 2020-09-24 09:49:59 +02:00
609a887d73 Fix missing Icons in corpus file edit 2020-09-23 16:34:46 +02:00
92d47a0b8d Fix missing html class in user admin view bugging list js 2020-09-23 16:20:00 +02:00
6e1ca2d7e2 Activate logging. 2020-09-23 15:39:27 +02:00
1604cdeaf6 Add warning about .stand-off.vrt 2020-09-23 15:38:53 +02:00
8083382046 Cleanup and documentation. 2020-09-23 15:09:45 +02:00
ad636d308d Bundle redundant event listeners. 2020-09-22 12:45:24 +02:00
3c86a2f334 Fix Modal init 2020-09-22 12:44:54 +02:00
61658410b2 Fix tables and add bottom paginatio nto all tables 2020-09-22 11:18:34 +02:00
9523568211 Add beta launch news 2020-09-21 15:25:28 +02:00
f53689af2c Add About/FAQ page 2020-09-21 14:37:46 +02:00
3572966190 Remove playground blueprint 2020-09-21 10:55:47 +02:00
6ad6251585 Remove playground 2020-09-21 10:42:24 +02:00
be8d688fdd Set Job colors on Job result pages. 2020-09-21 10:36:04 +02:00
be50a0eb4b Link Feedback mail template to button 2020-09-18 11:42:22 +02:00
4e5fc27579 remove workflow for now 2020-09-17 13:29:55 +02:00
269368e940 Fix missing RessourceList import. 2020-09-17 11:12:08 +02:00
ad21fe178c Deactivate client logging 2020-09-16 14:50:00 +02:00
dbf5affffc Add new way to get results with full contest to provide moreuser feedback 2020-09-16 14:24:50 +02:00
d3545d93a5 Add restart policy 2020-09-16 14:21:41 +02:00
78ac2250e1 minor things 2020-09-16 14:13:06 +02:00
021375f68d Fix query results viewer etc. to work with results having eitehr full or no context. 2020-09-16 10:41:02 +02:00
25670b6231 Fix inspect results not showing becasue of missing or statement. 2020-09-16 09:58:52 +02:00
d82e848303 Remove row margin 2020-09-16 09:43:28 +02:00
dce15d2861 Fix inspect context not showing error 2020-09-16 09:40:04 +02:00
a63323eab7 Change layout 2020-09-16 09:29:02 +02:00
eaba2879dd Rework expert mode switch 2020-09-16 09:15:32 +02:00
c0472eb6c5 Add switch to download full context results or not. 2020-09-15 17:18:22 +02:00
27f40b98a3 Fix broken links 2020-09-15 13:47:18 +02:00
877d87439e Fix download buttons on new query 2020-09-15 11:54:53 +02:00
d80802a479 Remove logging 2020-09-14 15:09:13 +02:00
72753d445a Fixes 2020-09-14 15:02:01 +02:00
3efe32bcf7 Fix admin user view 2020-09-11 16:36:35 +02:00
a87792b2cc Fix typo 2020-09-11 15:56:27 +02:00
49331f14f7 Fix typo 2020-09-11 15:55:56 +02:00
7e451b422e Fix typo 2020-09-11 15:54:58 +02:00
1bb265b7f4 Add show corpus metadata function to result inspect. 2020-09-11 15:53:30 +02:00
0b4e151bef Fix admin page 2020-09-11 15:52:49 +02:00
0d2720700e Pagination fixes 2020-09-10 15:49:18 +02:00
6b05651f05 Add Results viewer functionality with ne javascript and fix some errors. 2020-09-10 15:33:04 +02:00
fd1d1c2fc3 Fix create sub results showing even if other result creation is running. 2020-09-10 08:53:36 +02:00
1e316d6852 Intermediate push 2020-09-09 16:01:12 +02:00
9ae74cc9de Fix enable/disable toggle of buttons etc. with new client.isBusy field. 2020-09-09 14:35:00 +02:00
ff7881662c Documentation for Client.js 2020-09-09 09:31:20 +02:00
ccee6071e8 Tweak search button css 2020-09-08 16:34:55 +02:00
17e9b7d4ed Add some doc strings. 2020-09-08 16:19:30 +02:00
7186f5a777 Fix the search button 2020-09-08 15:56:02 +02:00
d6a19a9d7c Add single inspect results download 2020-09-08 14:14:52 +02:00
e1f4b0f35e Use headline ID instead of class 2020-09-08 11:00:00 +02:00
bed76df32f Add headline class to headline element 2020-09-08 10:55:51 +02:00
3d76a585a8 Merge branch 'javascript-rework' into development 2020-09-08 10:48:48 +02:00
7d6666c248 Remove baks before merge 2020-09-08 10:43:13 +02:00
ccfbf852b2 Feature parity with old implementation 2020-09-08 10:42:39 +02:00
521fd72d9b Add more old functionality 2020-09-07 16:30:47 +02:00
0eda40d0e7 Add more old functionality 2020-08-28 15:54:48 +02:00
fba591ee74 Fix corpus analysis 2020-08-28 15:26:04 +02:00
73160c8210 Add more old functionality 2020-08-27 16:12:21 +02:00
64f8f82fe8 Add logic for data export etc. 2020-08-26 16:55:24 +02:00
6d79b5a90c Use macro for color scheme generation and change logo for tablet and mobile 2020-08-26 16:14:36 +02:00
a64150278d Use the proper image file for navbar and favicon 2020-08-25 16:08:50 +02:00
763183435d Add result rendering for the user etc. 2020-08-25 15:56:04 +02:00
7531a58f96 Some more missing colors 2020-08-25 15:54:23 +02:00
884ac93c5b Adding tab color 2020-08-25 15:50:07 +02:00
443667197e Adding colors on more places 2020-08-25 15:37:45 +02:00
7d7d275dc4 Add text color classes 2020-08-25 15:26:36 +02:00
45b8beb053 fixes and shrinking 2020-08-25 15:02:16 +02:00
2216bffee8 Further color updates 2020-08-25 11:49:43 +02:00
d2453c2cc3 Work on View notifications 2020-08-24 16:33:37 +02:00
d88980ffb1 More coloring 2020-08-24 14:44:35 +02:00
e9de641e30 More color integration 2020-08-24 14:21:16 +02:00
0507ae4e34 first change with new MVCish pattern 2020-08-21 16:33:47 +02:00
778ff509ff Add custom colors to services in menu 2020-08-21 12:35:48 +02:00
dabeb818d1 New project structure 2020-08-20 18:14:35 +02:00
21ce07f3ef Push before rework part 2 2020-08-20 16:03:37 +02:00
b3e8976c1c Further rework 2020-08-17 16:15:34 +02:00
f94d21fa96 Add rudimentary rework of corpus analysis 2020-08-10 14:48:45 +02:00
25ea9ba583 Remove asynch rework because it was already event driven 2020-08-07 17:32:10 +02:00
6b1f588f29 Add asynch version of Session initialization 2020-08-06 16:08:03 +02:00
301b090fc0 Some fixes and enhancements befor javascript rework 2020-08-06 10:42:35 +02:00
a390fbb0ce Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-08-03 10:23:17 +02:00
49325ad2b8 Add GDPR statment and links 2020-08-03 10:23:11 +02:00
30bde863c9 Remove legacy code 2020-07-30 14:25:14 +02:00
715c37813c First RessourceList update 2020-07-30 14:17:51 +02:00
889c568ceb Update README 2020-07-28 13:14:14 +02:00
7ec576e690 Add important feature! 2020-07-23 16:07:12 +02:00
46087060d8 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-22 13:15:59 +02:00
d042e4f31d Enhance metadata view and analysis/result viewer interface 2020-07-22 13:15:55 +02:00
a92079beb3 Add query results to dashboard 2020-07-22 12:16:33 +02:00
3cb8ec9697 Fixe missing modal and add user feedback to flat buttons in analysis 2020-07-21 15:30:56 +02:00
5b9afbc66c Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-21 13:40:22 +02:00
1b853f3338 Soem clean up and restructure 2020-07-21 13:40:17 +02:00
914ee5d98a Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-20 14:08:18 +02:00
4b42b05dcf Add missing command in README 2020-07-20 14:08:12 +02:00
5949c9997a fuuuu dnspython 2020-07-20 14:07:57 +02:00
322c97ebf4 Fix latest migration script 2020-07-20 14:07:38 +02:00
7dfc3ab877 Add metadata view to nalysis interface and result viewer 2020-07-20 13:44:57 +02:00
ce79b59bf8 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-20 09:31:28 +02:00
3e50c2f275 First setup for metadata modal view 2020-07-20 09:31:27 +02:00
38a450802f Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-17 08:43:07 +02:00
ada7007a0e Add delete button in job and corpus lists. 2020-07-17 08:43:02 +02:00
398d5c2989 Preperations vor metadata modal in analysis and import 2020-07-16 16:00:38 +02:00
d4c6b72761 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-16 14:41:05 +02:00
6f0fd5bc73 Add delete function for services 2020-07-16 14:40:57 +02:00
5e02f96c58 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-16 14:00:56 +02:00
7ccd2a1c7c Rework results download. To alwas generate full inspect context. 2020-07-16 14:00:52 +02:00
db16cbf7d6 Add mockup 2020-07-16 11:53:13 +02:00
ac3b20d304 Remove old result package 2020-07-15 14:52:41 +02:00
0714070a9b Fully integrate new query_results model. old one is now deprecated. 2020-07-15 13:16:31 +02:00
ba49bb39e9 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-15 11:07:09 +02:00
7cf04cbe29 Some changes to query result list 2020-07-15 11:07:03 +02:00
323b8b82ee Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-15 11:02:14 +02:00
644369d1e9 Add compare_type=True to Migrate constructor 2020-07-15 11:02:06 +02:00
44963b1606 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-15 08:57:46 +02:00
06427e81f3 Use capitalized classnames 2020-07-15 08:57:39 +02:00
13a6ef95c3 Fix rseults only showing after page navigation in import viewer 2020-07-14 15:51:02 +02:00
e9eaa49826 Removed redundant range functions and create one class method for its purpose. 2020-07-14 10:59:02 +02:00
82c26a02bb Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-14 09:25:37 +02:00
b2d093e9fe Intermediate result viewer push 2020-07-14 09:24:04 +02:00
56e6049665 Remove merge markers.... 2020-07-13 15:34:17 +02:00
ac3310fea5 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-13 15:33:58 +02:00
6760061d53 Add a parallel package for query results. 2020-07-13 15:33:00 +02:00
cdd421e48a Rename some result views and templates 2020-07-10 13:27:06 +02:00
2b3d08b277 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-10 11:44:12 +02:00
ab1d9a2001 Remove logs 2020-07-10 11:44:07 +02:00
b69c54a762 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-10 11:39:42 +02:00
af947ee3bc Use appropriate methods and variable naming 2020-07-10 11:39:37 +02:00
94701ab3b0 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-10 11:39:21 +02:00
8d96c1ee41 Tooltips everywhere! 2020-07-10 11:39:16 +02:00
d480f92e30 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-10 11:36:58 +02:00
7f8797d227 Delete files in db model methods. 2020-07-10 11:36:54 +02:00
5f7b846784 Unify tables: right alaign and some html fixes 2020-07-10 09:32:16 +02:00
d4eb9e7663 Add result json import validation 2020-07-09 15:41:25 +02:00
f86f3f4fd5 Move file deletion to model methods. add restart job button. 2020-07-09 15:07:43 +02:00
e20a6a31d9 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-09 09:42:34 +02:00
53b4b57b61 Add job restart url /jobs/job_id/restart 2020-07-09 09:42:30 +02:00
84f1d7dc39 Add download function to imported result. 2020-07-08 16:03:44 +02:00
ea7bb82661 Unify more tables (Corpus: corpus files view) 2020-07-08 15:24:18 +02:00
43f79291aa Unify job input tables 2020-07-08 11:35:47 +02:00
0fff7801fd Unify more tables 2020-07-07 16:06:09 +02:00
7648149584 Results import fixes and additions. Table creation rework. 2020-07-07 15:08:15 +02:00
5867871de2 Remove spaces 2020-07-03 14:46:04 +02:00
3080443a81 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-03 14:42:04 +02:00
1811623583 Add function to import exported results and view them after the import 2020-07-03 14:41:57 +02:00
c9cb52279b Add terms of use 2020-07-03 11:17:47 +02:00
20adc1af34 change some documentation. 2020-07-02 12:01:40 +02:00
5addc9c28a remove obsolete flag 2020-07-02 11:50:14 +02:00
6c9e9dfb57 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-07-01 08:44:23 +02:00
527857f6f6 Hide progress spinner if a job failed. 2020-07-01 08:44:19 +02:00
a997fbe0ee Fix for the previous fix 2020-06-30 15:15:06 +02:00
c6704f3554 Fix add to subcorpus btns not showing when results per page are updated 2020-06-30 14:37:11 +02:00
820845b499 Some small fixes and user feedback 2020-06-29 11:09:12 +02:00
5764e918f5 Cosmetics III 2020-06-26 13:13:18 +02:00
9f341b90b9 Some more documentation! 2020-06-26 10:04:54 +02:00
74104922b6 Some documentation 2020-06-26 09:51:10 +02:00
e9cd5dafd1 Cosmetics II 2020-06-25 18:01:02 +02:00
b29f2ca5ee Add cosmetics 2020-06-25 17:44:55 +02:00
afd5201c05 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-06-25 10:52:00 +02:00
2113065075 Export sub results 2020-06-25 10:51:51 +02:00
84672bba6b Fix some variables naming 2020-06-25 10:51:13 +02:00
106fd75c75 fix ocr command 2020-06-23 15:20:05 +02:00
ead0117bbb More Analysis Javascript updates for unified interaction handeling 2020-06-19 15:49:11 +02:00
ab61819005 New analysis interface 2020-06-19 12:30:05 +02:00
be4377a231 Cookie security only if https is set in the config. 2020-06-17 09:26:37 +02:00
b427a5e6f1 Use matches instead of one match in match context 2020-06-16 14:05:58 +02:00
af50da4936 Add compress flag for ocr jobs 2020-06-16 09:34:46 +02:00
1817532d27 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-06-15 16:14:21 +02:00
4f8ba7cb3e Update for new cqi package 2020-06-15 16:14:16 +02:00
44688eff65 Add more cosmetics 2020-06-10 16:00:33 +02:00
b99bfd9854 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-06-10 15:10:29 +02:00
c30ab8f584 Some cosmetic fixes 2020-06-10 15:10:23 +02:00
e000324e8e Remove stupid logs 2020-06-10 14:35:25 +02:00
66827bbdb1 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-06-10 14:26:00 +02:00
7e34892147 Rework job page input file view 2020-06-10 14:25:57 +02:00
4735df7c60 Add missing configuration to .env.tpl 2020-06-10 14:25:57 +02:00
b3e467beac Update daemon 2020-06-10 14:18:02 +02:00
6e26e38326 Add True as default if NOPAQUE_EXECUTE_NOTIFICATIONS is not set 2020-06-10 09:39:16 +02:00
84319681a2 Update 2020-06-09 15:59:41 +02:00
d92efba805 Update README 2020-06-09 13:27:02 +02:00
d59268dd29 Add docker-compose.override.yml template duplicate, edit and save it as docker-compose.override.yml next to docker-compose.yml 2020-06-09 12:49:50 +02:00
59003593b6 All configuration via .env file. (This replaces the nopaque.env file) 2020-06-09 12:46:08 +02:00
f32c6e9faa Fix 2020-06-08 14:56:43 +02:00
66cee12dcb Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-06-08 13:53:06 +02:00
3449964345 Put execute_flag into enviroment file 2020-06-08 13:52:54 +02:00
71cea57397 blubb 2020-06-08 13:47:34 +02:00
4727ce32c6 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-06-08 11:55:31 +02:00
1faf8f9ab2 Add playground blueprint 2020-06-08 11:55:20 +02:00
e0f32ee9eb Remove sleep 2020-06-08 11:28:02 +02:00
50a483cbfc Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-06-08 10:24:28 +02:00
b56a8362ff Avoid that threads of the same type can be executed twice or thrice etc. 2020-06-08 10:23:32 +02:00
a5a008db2f Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/nopaque into development 2020-06-08 10:14:21 +02:00
023aade995 Some changes for convinience 2020-06-08 10:14:15 +02:00
9e88330433 Remove unecessary sessions 2020-06-05 15:25:16 +02:00
bb68784026 Fix 2020-06-05 15:19:01 +02:00
59b27d96ca Add todos 2020-06-05 15:17:37 +02:00
056fbe273c Update 2020-06-05 15:12:59 +02:00
cb2b64fa9d integrate nopaque repo 2020-06-05 14:42:04 +02:00
450ddf69fc Use more restrictive ssl settings 2020-06-03 11:18:15 +02:00
4ac4fcb4ff Add security enhancements. See: https://blog.miguelgrinberg.com/post/cookie-security-for-flask-applications 2020-06-02 16:51:08 +02:00
9f62e782f0 Add permanent redirect from http to https 2020-06-02 10:02:27 +02:00
d5569fa65b flashed messages for unauthenticated users too! 2020-05-27 13:34:55 +02:00
ba916b70bd Change location where socket is initialized...again 2020-05-27 13:32:07 +02:00
94d99862bd Use werkzeugs pre implemented ProxyFix middleware 2020-05-27 12:52:41 +02:00
814821a2bd Make flask respect https! :D See: https://stackoverflow.com/questions/14810795/flask-url-for-generating-http-url-instead-of-https/37842465#37842465 2020-05-27 11:36:28 +02:00
01bc246035 Some minor fixes for logformat. 2020-05-27 11:35:49 +02:00
ecac2c481c Only initialize socket when the user is logged in 2020-05-27 11:11:54 +02:00
afd7469178 Rework logging code 2020-05-27 11:03:50 +02:00
9d893db403 update 2020-05-26 15:39:46 +02:00
f137b8df9b Add ssl config for local development. 2020-05-26 14:40:44 +02:00
eccf9691c1 Add missing import. Remove unused import. 2020-05-26 14:29:01 +02:00
af527c1cf3 Bump socketio-client version. (2.2.0 -> 2.3.0) 2020-05-26 14:26:11 +02:00
d4e81b11e0 Fix foreign user data transmission for admins 2020-05-20 10:32:39 +02:00
8d201a29ae Proper socketio_login/admin_required decorators 2020-05-20 09:36:59 +02:00
f86301112b Remove unused .png 2020-05-20 09:36:23 +02:00
2af6daccf2 switch parallax images so that the code image is displayed when the user is logged in 2020-05-19 14:39:23 +02:00
b93bcb36f7 update 2020-05-19 14:27:35 +02:00
ddfa0f47bf Add new config variable and rename opaque_domain -> nopaque_domain 2020-05-19 14:19:23 +02:00
94a193f6dd Add legal notice and gitlab link as button 2020-05-19 10:25:16 +02:00
c93d641fe4 Let daemon depend on web container, to make sure that db migrations are applied before daemon starts. 2020-05-19 09:27:21 +02:00
6f842a1092 Remove unnecessary deletes which hare handled by cascade options 2020-05-18 14:53:31 +02:00
22114dd464 Add all necessary models to flask shell context 2020-05-18 14:47:04 +02:00
8f4cd9a375 Add additional new __repr_ function 2020-05-18 13:46:12 +02:00
243eba2f78 Add new __repr__ function. 2020-05-18 11:59:19 +02:00
6e81e424c4 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-05-15 15:07:50 +02:00
9ce00ff5e0 Merge notify into daemon 2020-05-15 14:43:12 +02:00
7a6cbccbd2 First working mail notification system 2020-05-14 15:30:13 +02:00
3d41b18daf Jobpage rework 2020-05-13 16:36:06 +02:00
2b9d098857 Add notification service 2020-05-11 16:09:18 +02:00
07c104196f Add Notification model 2020-05-11 16:09:09 +02:00
cb8f3faae0 Add curren ttoken and max token nr 2020-05-04 12:08:43 +02:00
c49684611a Add more metadata 2020-05-04 11:05:17 +02:00
58295b986d Rename some things. Add metadata to downloadable json 2020-04-30 15:21:55 +02:00
1350e6ddd6 Add metadata object on analysis 2020-04-30 14:45:54 +02:00
a17771a772 Better comments 2020-04-30 12:56:59 +02:00
08b909b9a8 Add new field to dict method. Always keep in mind to do this, when you or modify a field. 2020-04-30 11:32:48 +02:00
f87fe589c1 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-30 11:29:01 +02:00
e1b07d8719 Handle user data streams different 1/2
In the future this will be much more performant!
2020-04-30 11:28:55 +02:00
d4318cb205 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-29 16:15:12 +02:00
d54a3d3f33 First metadata addition 2020-04-29 16:15:11 +02:00
b7fc804b40 Sort things a bit... this should get improved in the future 2020-04-29 12:17:16 +02:00
2ceb53cac1 remove double '#' 2020-04-28 17:22:43 +02:00
e92d43eed0 Better wording 2020-04-28 17:19:48 +02:00
4d677244e0 Some styling 2020-04-28 16:33:47 +02:00
86c4b77085 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-28 11:20:41 +02:00
7f06dc5ff6 Add settings for https 2020-04-28 11:20:35 +02:00
eb5e5c3253 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-27 16:16:59 +02:00
deda16f0f5 Add meta data recv after corpus analysis init 2020-04-27 16:16:57 +02:00
c67c033aec Rework notification system 2020-04-27 15:22:20 +02:00
b30382e605 beauty enhancements 2020-04-27 14:33:49 +02:00
f744e32d7e Fix email function 2020-04-27 14:08:59 +02:00
45a3c664a2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-27 13:51:07 +02:00
565274fce1 A lot of database changes and add options to change notification level 2020-04-27 13:50:54 +02:00
5dfaf51793 Add download for context data. 2020-04-27 13:25:29 +02:00
76e7d65017 Some comments 2020-04-27 10:30:38 +02:00
a879558ec4 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-27 10:27:11 +02:00
9d3194c1be setting_dark_mode migration 2020-04-27 10:27:06 +02:00
ab4a7807cf remove gunicorn from entrypoint 2020-04-27 10:20:47 +02:00
7cfa3bd022 Change darmode setting 2020-04-27 10:19:20 +02:00
3a05a4d2f4 Switch back to socketio server while development 2020-04-27 09:34:12 +02:00
98fecacb11 use cqi from pypi 2020-04-24 15:44:40 +02:00
7fc1084749 Add notifications on status changes of jobs and corpora 2020-04-24 15:22:04 +02:00
606c8cf761 Add flask command switch to docker-entrypoint again 2020-04-23 15:31:10 +02:00
d520184d1d Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-23 13:41:43 +02:00
4a7f2dbb24 Add word-break to corpus file list. 2020-04-23 13:41:37 +02:00
9e693fc440 Remove &nsbp; 2020-04-23 13:28:13 +02:00
a4f122bdab Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-23 12:40:04 +02:00
154631dcb4 Add placeholder to indicate required file types in forms 2020-04-23 12:39:59 +02:00
1c27c0a36c uncomment log messages 2020-04-23 12:10:36 +02:00
d9353e3d7d Clean up 2020-04-23 12:07:08 +02:00
191f197b6c clean up 2020-04-23 11:21:20 +02:00
7efb16246f Clean up and better text break in amtch context 2020-04-23 11:18:50 +02:00
a1439f37d7 Set callbac kfor match_context 2020-04-23 10:37:44 +02:00
bbcf5c5312 Add some documentation 2020-04-23 09:40:43 +02:00
3a989534cf Make the app arg in @background functions a bit less magical 2020-04-23 08:35:18 +02:00
83c05d93b0 Make delete user function a background task 2020-04-23 08:24:11 +02:00
edc0b34032 Process corpus files in task, not in database model 2020-04-23 07:56:23 +02:00
e882af8888 add email validator to requirements. Because of any reasons it is needed now 2020-04-22 16:00:21 +02:00
bb8a542eed Small fixes 2020-04-22 09:29:45 +02:00
60cc93a806 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-21 18:34:27 +02:00
bc27744946 Create and use a decorator for background functions 2020-04-21 18:34:21 +02:00
beba4c1558 Fix expert mode automatic activation 2020-04-21 10:45:40 +02:00
c7f7036306 Visual fix 2020-04-21 10:41:08 +02:00
a3c049c4ed Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-21 10:31:40 +02:00
ddc7859002 Some visual stuff 2020-04-21 10:31:34 +02:00
79c9ca97b2 Fix Typos 2020-04-21 10:28:04 +02:00
29f1be5c80 Delete functions should not throw an error, if the ressource does not exists. -> Consider it as deleted if does not exist 2020-04-21 10:27:42 +02:00
e83c762551 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-21 10:26:49 +02:00
461f80be20 Change email function names 2020-04-21 10:26:44 +02:00
78f93a884b Move down from 100 to 50 words lr context 2020-04-20 15:09:08 +02:00
716e1c357a fix typo in env.tpl 2020-04-20 14:47:39 +02:00
d16e749ee7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-20 14:24:41 +02:00
7dd27fb007 Change some email settings. MAIL_DEFAULT_SENDER removed. 2020-04-20 14:24:36 +02:00
b4c98a9713 Last fix 2020-04-20 13:59:28 +02:00
986336618b Add fix 2020-04-20 13:55:11 +02:00
f7dc83f51d Disable export in inspect modal 2020-04-20 13:49:59 +02:00
80c049ae06 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-20 13:48:44 +02:00
6126477825 Finalize inspect view display options 2020-04-20 13:48:40 +02:00
8a9db7f4b8 Add validation flag if field is required. 2020-04-20 11:12:20 +02:00
339107fd08 Fix Ports 2020-04-20 10:40:10 +02:00
889976dc9b Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-20 10:11:51 +02:00
15373ed00f - Use gunicorn
- Add env variable GUNICORN_WORKERS (default: 1)
- new Port (8000)
- You don't need to run "flask deploy" by hand anymore
2020-04-20 10:11:45 +02:00
2eb3d2f03e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-20 09:59:34 +02:00
f91583484e Simplify the deployment process. You don't need to use 'flask db upgrade' or 'flask insert-initial-database-entries' anymore. Instead you just need to use 'flask deploy'. 2020-04-20 08:56:49 +02:00
188aeae88f Fix wrong macro usage. 2020-04-17 19:50:21 +02:00
5fa1ba385b Update 2020-04-17 16:00:40 +02:00
b9ebb64fcc Change macro names 2020-04-17 11:13:11 +02:00
1f0a87a474 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-17 11:07:47 +02:00
3aafe664a3 Add macros and use them 2020-04-17 11:04:09 +02:00
9145265e4b Add expert mode and higlight sentences switch to inspect. WIP 2020-04-16 15:06:03 +02:00
fe26c56344 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-16 13:49:24 +02:00
1567e6e134 Filx text break 2020-04-16 13:49:21 +02:00
23ffbe5f6b Fix link after service renaming (file-setup) 2020-04-16 13:48:31 +02:00
6177093a51 Set characters according to metadata label 2020-04-16 13:47:52 +02:00
72e585395b status update handling for corpus list 2020-04-16 13:28:09 +02:00
f356d4bb89 Naming... 2020-04-16 10:21:22 +02:00
8cec7b2d3a Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-16 09:40:45 +02:00
fede774196 Change nopaque upload forms. Add corpus file form has an upload progress bar now. 2020-04-16 09:40:38 +02:00
bcd431da22 fix 2020-04-15 15:22:48 +02:00
4992ac73a8 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-15 15:11:31 +02:00
8b27ddf5d2 fix 2020-04-15 15:11:25 +02:00
20d4d1c0b3 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-15 14:57:19 +02:00
f264b27ae5 Change validation process (currently broken) 2020-04-15 14:57:17 +02:00
68eb1d1972 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-15 14:55:36 +02:00
9031ca5845 New context options 2020-04-15 14:55:29 +02:00
b1d819444e corpus page: Only show compile buttons if corpus is unprepared AND has files. 2020-04-15 14:30:41 +02:00
b251f9993d Add message if corpus is empty 2020-04-15 12:49:26 +02:00
bbccbcfcd2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-15 10:32:27 +02:00
338e760bfb Hide analyze button if corpus is not ready for this 2020-04-15 10:32:21 +02:00
34e8d952b6 Add match context display options 2020-04-14 15:51:26 +02:00
9578a12f42 Fix match_count in resultsJSON 2020-04-14 12:46:33 +02:00
518d16d189 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-14 11:33:56 +02:00
514baf0f5e New expert mode 2020-04-14 11:31:57 +02:00
7c8ae161a9 Fix context size and codestyle 2020-04-14 09:51:33 +02:00
9a1efbe5f3 corpus logic 2020-04-09 15:14:39 +02:00
860e99dfcb Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-09 14:50:26 +02:00
b274fd1d20 Change some logic for showing/hiding buttons 2020-04-09 14:50:20 +02:00
f19f67614d Remove cascade plus new tooltip creation and destruction (a bit buggy) 2020-04-09 14:49:17 +02:00
ca333e29ee Some fixes and clean up 2020-04-09 10:17:04 +02:00
24cc8975a9 More fixes 2020-04-09 10:03:55 +02:00
faf3d01626 Fixes after renaming 2020-04-09 10:02:24 +02:00
341b53f0a1 Rename file setup service 2020-04-09 09:53:56 +02:00
33e9e40c61 new names 2020-04-09 08:18:04 +02:00
0f28b6296d Remove hardcoded values 2020-04-09 07:57:52 +02:00
5069c5facd removed variables again 2020-04-08 17:40:56 +02:00
6bbe0129b4 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-08 17:21:49 +02:00
f27d56ac6b Remove stuff and add variables 2020-04-08 17:21:42 +02:00
f69a401db6 Clean up and stuff 2020-04-08 11:37:34 +02:00
d5d0ffe7ea sort and clean variables 2020-04-08 09:57:18 +02:00
b0104fe606 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-08 09:46:38 +02:00
0146a92f6d reverse array 2020-04-08 09:46:37 +02:00
ca833c966a fixes and doc 2020-04-07 16:36:27 +02:00
08dba25de3 fix 2020-04-07 16:30:27 +02:00
a1cdfd498a Remove wrapper 2020-04-07 16:27:28 +02:00
83a607728d cqi package update and changes to match the new functions 2020-04-07 16:25:44 +02:00
90ef828e61 Make analyse OOP style 2020-04-07 13:13:48 +02:00
6260f2436a Remove some useless loading animations 2020-04-07 09:53:17 +02:00
49dc7c4cdb Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-06 15:29:04 +02:00
69b17f350e Remove all pjs! 2020-04-06 15:28:58 +02:00
961027a8f7 Add global prgress for inspect activation 2020-04-06 15:27:25 +02:00
606c4dee85 CQi updates 2020-04-06 14:53:50 +02:00
b78558fc03 Fix script import 2020-04-06 14:37:38 +02:00
2aca966d13 Fix wrong expert mode check 2020-04-06 14:35:57 +02:00
99e82a1cc3 Rename pj_analyse_corpus.js to analyse_corpus.js 2020-04-06 14:33:58 +02:00
52efa0e821 Remove old analyse_corpus.js 2020-04-06 14:33:26 +02:00
a09f3d79a8 Rename pj_analyse_corpus.html.j2 to analyse_corpus_analyse.html.j2 2020-04-06 14:28:20 +02:00
0ffcf972ca Remove old analysis template 2020-04-06 14:27:38 +02:00
9ec1b596f8 Remove pj_ 2020-04-06 14:27:14 +02:00
19aee30b1b remove wrong inits 2020-04-06 14:18:48 +02:00
a6bcfe51b1 Rename pj_views|events|forms to views, events, forms 2020-04-06 14:16:59 +02:00
85abf7748d Delete old events 2020-04-06 14:13:45 +02:00
a6855797d5 Update new view 2020-04-06 14:12:22 +02:00
e0df6a9eca Delete old views 2020-04-06 14:12:15 +02:00
66a2fcdb34 update new forms 2020-04-06 14:09:41 +02:00
e6efb042c3 Delete old form 2020-04-06 14:09:33 +02:00
e7bed7dee1 Add comment 2020-04-06 14:09:12 +02:00
1ed696f558 Fix 2 2020-04-06 12:52:26 +02:00
41f24a03b4 Fix 2020-04-06 12:41:23 +02:00
12586bb13d First feature complete rebuilt of analysis interface 2020-04-06 12:32:29 +02:00
38e1408e01 quick fix 2020-04-06 12:01:36 +02:00
9dace02378 Fix missing icon after renaming setup_files to file_setup 2020-04-06 10:04:54 +02:00
d36346033b Bump version 2020-04-06 09:46:09 +02:00
2896f94e8d Add changes for new file_setup Pipeline 2020-04-03 18:49:45 +02:00
9da08508c0 Add changes for new OCR and NLP Pipelines 2020-04-03 17:36:38 +02:00
498defa386 Fix 2020-04-02 14:45:02 +02:00
2c93f02c11 Update 2020-04-02 14:22:03 +02:00
bface71503 use ranges 2020-04-02 11:38:27 +02:00
e14f7a517b Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-02 11:37:53 +02:00
89891da663 handle result ranges 2020-04-02 11:37:45 +02:00
848bc90b0c Bugfix 2020-04-02 10:43:01 +02:00
b8a086f389 Set list/range flag in events.py instead of the export function 2020-04-02 10:36:59 +02:00
452fb37b99 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-02 10:14:49 +02:00
6a5621b753 Add Flag to indicate if cpos lists are saved as ranges or lists. 2020-04-02 10:14:43 +02:00
fb1403e9cb Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-04-01 15:58:26 +02:00
bfd7591f4d add comment 2020-04-01 14:27:01 +02:00
37526a6b43 Use expanded List 2020-04-01 14:25:49 +02:00
8c83bb87a5 Fix to 3.1 2020-04-01 13:49:28 +02:00
46b82f5737 Corpus analysis version 3.0 lul 2020-04-01 13:44:06 +02:00
90cf1bf8a0 Fix 2020-03-31 10:27:26 +02:00
0d40f04bdd Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-31 10:19:44 +02:00
c33889f617 Enhance pj_analyse 2020-03-31 10:17:04 +02:00
257549bf69 Use Traefik for reverse proxy! :) 2020-03-30 17:27:54 +02:00
9ced65f34c Force socketio to use websockets 2020-03-30 17:27:24 +02:00
f605430bf8 Show progress bar after new query 2020-03-30 10:47:36 +02:00
4556a52ffc Abort transmission after disconnect 2020-03-30 09:01:40 +02:00
0be0e12aee add simple status check 2020-03-30 08:36:55 +02:00
6e3579b33f Update 2020-03-29 20:54:51 +02:00
4ff372de77 small updates 2020-03-29 20:33:00 +02:00
d07b73781f Update 2020-03-29 19:40:29 +02:00
f7692102a5 Update 2020-03-29 12:38:24 +02:00
2db9677659 Make it work again 2020-03-28 20:45:33 +01:00
e3fde2d5c9 compatibility fixes and add reimplementations 2020-03-28 19:29:19 +01:00
970d7024e0 Wrap socket usage in DOMContentLoaded eventlistener 2020-03-28 11:57:12 +01:00
a51394dddd Update cqi package 2020-03-28 11:56:01 +01:00
97fb8ded9a fix 2020-03-27 12:52:17 +01:00
f09c4d15f6 Ignore all errors 2020-03-27 12:43:38 +01:00
4294c2854b Make inner package imports relative 2020-03-27 12:06:11 +01:00
3bbe45d015 remove legacy code 2020-03-27 10:32:33 +01:00
3ea1f4bd9f Rename nopaque.toast to nopaque.flash which offers styling by categories 2020-03-27 10:32:14 +01:00
b0c2415f55 Codestyle++ 2020-03-27 10:13:42 +01:00
ca8d438e79 Change how flashed messages are processed 2020-03-27 10:11:19 +01:00
4af7d8d4ba Update darkreader 2020-03-27 10:10:49 +01:00
8bedbfeae5 Use slim socketio again (this time with .map file) change socket behavior 2020-03-26 17:32:26 +01:00
d6206bef34 Add mac os files to .gitignore 2020-03-26 17:31:39 +01:00
eba6af3b1e Replace the default function decorators with new socketio specific ones 2020-03-26 16:14:09 +01:00
257600a2a8 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-26 15:28:36 +01:00
08e7df4ad3 Add function to resend queries during running query 2020-03-26 15:28:11 +01:00
0db99e33fe Update cqi package 2020-03-25 15:39:32 +01:00
6b24184206 remove logger warnings 2020-03-23 13:03:40 +01:00
16b1733ec5 remove logger 2020-03-23 12:16:41 +01:00
ac14bedc62 Add neww result recieving 2020-03-23 12:14:32 +01:00
94e71b41df fix empty matches error 2020-03-23 11:24:39 +01:00
e99053e3cf rename 2020-03-23 11:18:27 +01:00
303ea166d2 fix num matches 2020-03-23 11:17:37 +01:00
e13ed86d29 new style 2020-03-23 10:28:07 +01:00
acfcc0321b Add package implementation of cqi 2020-03-23 09:10:35 +01:00
7752e7fb57 Add changes from cqiclient repository 2020-03-20 15:12:19 +01:00
7c9b9f0712 Code clean up 2020-03-19 13:59:31 +01:00
25f54f1119 Add some documentation strings 2020-03-19 12:35:30 +01:00
8a6eb04dbe Easy fix 2020-03-19 12:04:14 +01:00
7de4b391df Fix inspect activation on queryFinished 2020-03-19 11:04:36 +01:00
ebe598312f Add info tool tip 2020-03-19 10:25:09 +01:00
8147dc404a Inspect now only works when queryFinished is true 2020-03-19 09:25:23 +01:00
b12c9f85d1 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-18 15:52:57 +01:00
3111cc5175 Clean up corpus analysis and add new features 2020-03-18 15:52:53 +01:00
4c67777977 Add privacy 2020-03-18 14:44:15 +01:00
c5e56692b1 First analys_corpus clean up 2020-03-17 14:00:41 +01:00
c416d64a4c some comment changes 2020-03-17 10:47:52 +01:00
6414ab36bf Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-16 16:25:12 +01:00
63600c1301 Remove debug messages. 2020-03-16 16:25:08 +01:00
f8d3300e42 Apply context size on first load 2020-03-16 15:57:06 +01:00
37d2e8f38e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-16 13:15:25 +01:00
b8437735b4 Defensive programming inc 2020-03-16 13:15:13 +01:00
0c7620b438 add white section 2020-03-16 12:27:07 +01:00
e0e2fe017c Fix typo 2020-03-16 11:21:58 +01:00
52e5092d13 Add some Readme stuff 2020-03-16 10:49:45 +01:00
55b8fe54a8 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-12 16:06:12 +01:00
f62e317dfc Add hint in readme 2020-03-12 16:06:07 +01:00
5b9c1c3adf Add context change toast. 2020-03-12 15:09:27 +01:00
6bdc0b354b Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-12 14:49:03 +01:00
5c134dd8c5 Add interaactive context change 2020-03-12 14:48:58 +01:00
b6ffad1ae4 use variable instead of magic number 2020-03-12 14:18:38 +01:00
f4ac584668 Update 2020-03-12 14:18:07 +01:00
bcbb67b707 Remove debug log 2020-03-12 14:16:47 +01:00
e5e77d7dc2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-12 14:13:11 +01:00
416c724f70 Simplify 2020-03-12 14:13:07 +01:00
db7ccb2b11 important fix! 2020-03-12 10:34:40 +01:00
7d37f802b1 Hide prepare button 2020-03-11 15:51:55 +01:00
fa7d2da973 Update 2020-03-11 14:48:48 +01:00
cedc1f11e3 Update 2020-03-11 13:34:09 +01:00
e881401a10 Update CQi stuff 2020-03-10 16:06:47 +01:00
467080c7f8 Update UI 2020-03-07 20:20:58 +01:00
607fb016df poster 3 2020-03-02 16:10:42 +01:00
957d4a513c Update poster 2020-03-02 16:00:58 +01:00
90022d25d2 Poster 2 2020-03-02 15:45:37 +01:00
6a509646e7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-02 15:31:36 +01:00
2c78de1eb9 psoter 2020-03-02 15:31:31 +01:00
dfd7e556d2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-02 14:57:17 +01:00
fb0ca7e759 Fix job form error message generation 2020-03-02 14:57:12 +01:00
6318c753b2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-02 14:19:57 +01:00
c6f522a776 new layout 2020-03-02 14:19:54 +01:00
55a86a60f3 disable notifications for now 2020-03-02 14:15:50 +01:00
9912017d78 csrf token immediatly after form tag 2020-03-02 14:13:32 +01:00
98155e5d25 Update 2020-03-02 14:08:49 +01:00
02177ed859 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-02 14:05:34 +01:00
d08014dbbe First implementation of a feedback formular 2020-03-02 14:05:31 +01:00
d4453fd994 Sort by id 2020-03-02 13:59:16 +01:00
94f4f304ce Sort input files 2020-03-02 13:52:02 +01:00
fe9364e891 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-02 11:55:42 +01:00
cad9f2f7f5 Fix empty 2020-03-02 11:55:33 +01:00
5c62a1a013 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-02 11:55:32 +01:00
aa6d5510ce Fix problem with empty table 2020-03-02 11:55:24 +01:00
50b7f3aaf7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-02 11:55:17 +01:00
6c0e1998f2 Poster update text 2020-03-02 11:55:12 +01:00
b5e8ab376e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-03-02 11:42:04 +01:00
8a1339e42a Always show log in section on poster 2020-03-02 11:42:00 +01:00
4a8696cf16 Fix typo 2020-03-02 11:18:34 +01:00
f8524be488 Sort result files without log message 2020-03-02 11:07:25 +01:00
a0c0f3ff0c Sort result files 2020-03-02 11:06:36 +01:00
020f99d93f Remove Poster nav 2020-03-02 10:45:46 +01:00
5ea19abbfd Text updates 2020-03-02 10:42:25 +01:00
d5ecf5b9c5 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-27 16:26:08 +01:00
62b70a7532 Update 2020-02-27 16:26:04 +01:00
be423e1b5c poster pics 2020-02-27 15:44:47 +01:00
c385b21739 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-27 15:41:09 +01:00
535800558e pics+ 2020-02-27 15:41:06 +01:00
1b61182932 login page update 2020-02-27 15:39:53 +01:00
ef5b975b6a Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-27 15:33:59 +01:00
9d197ef8c7 Update according to poster texts 2020-02-27 15:33:55 +01:00
2744d107ae Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-27 15:33:43 +01:00
275e6953b7 new parallax pics 2020-02-27 15:33:37 +01:00
adf6b9e4ae Bring back the original footer 2020-02-27 15:29:36 +01:00
2e8a2751d8 schubs 2020-02-27 13:23:21 +01:00
aaaed0f214 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-27 12:19:59 +01:00
3f163ba953 posterama 2020-02-27 12:19:56 +01:00
8a688bf314 all lower case 2020-02-27 11:56:20 +01:00
c2124ebddf Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-27 11:46:30 +01:00
50d06d0eea Poster stuff 2020-02-27 11:46:28 +01:00
dbbecf595c update 2020-02-27 11:30:05 +01:00
25b66609bf New texts 2020-02-27 11:29:42 +01:00
41b171e460 Fix typo 2020-02-27 10:25:33 +01:00
d9d2f702d9 Set title for poster page 2020-02-27 10:15:04 +01:00
d27919bef3 Update texts 2020-02-27 09:55:58 +01:00
762482582d Fix background problem 2020-02-26 13:54:24 +01:00
721f424d30 poster update 2020-02-26 13:50:06 +01:00
448f1117ca Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-26 11:38:25 +01:00
934674d5ba Make some changes 2020-02-26 11:38:21 +01:00
b1a50d2339 poster 2020-02-26 11:37:59 +01:00
4728978cbf update 2020-02-25 15:56:44 +01:00
2656577f74 Add text 2020-02-25 15:10:20 +01:00
fa2af2d8b9 new poster 2020-02-25 14:53:33 +01:00
18163400e1 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-25 11:05:25 +01:00
b0c94e169e dunno 2020-02-25 11:05:19 +01:00
cf37ae163e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-25 11:00:35 +01:00
f8aa18e2a7 Add expert view to inspect view. 2020-02-25 11:00:30 +01:00
1a5af62179 Add theme color 2020-02-25 10:46:24 +01:00
2aa86fdd04 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-25 10:39:38 +01:00
f65fab0c77 Mobile styles 2020-02-25 10:39:33 +01:00
40255c7b79 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-25 10:29:44 +01:00
5568f535bd Change dark mode settings 2020-02-25 10:29:20 +01:00
9a925ee141 Update 2020-02-25 10:20:29 +01:00
b8fa1e15d3 Fix account deletion 2020-02-25 10:03:31 +01:00
f58a6f5778 Changes for page title 2020-02-25 09:59:49 +01:00
b8abc8856c Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-24 17:32:24 +01:00
697a9e3108 Update 2020-02-24 17:32:20 +01:00
423ad6a778 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-24 16:54:28 +01:00
bb536f5534 Setup Files to File Setup 2020-02-24 16:54:20 +01:00
8f209374ab Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-24 15:55:34 +01:00
47127dcd80 Remove unused file 2020-02-24 15:51:02 +01:00
ae8bf021da Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-24 15:50:09 +01:00
dbcd627284 Change button 2020-02-24 15:50:02 +01:00
f3bcbd3264 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-24 15:47:18 +01:00
c5dee67f4d Change favicon 2020-02-24 15:47:13 +01:00
2147b9e3b4 Change layout 2020-02-24 15:41:35 +01:00
e424c39b3d change title 2020-02-24 14:59:29 +01:00
945cb5e130 Poster 2020-02-24 11:50:05 +01:00
cd405d937e some scaling 2020-02-24 10:25:34 +01:00
0ce0ac5593 Change processes and services section 2020-02-24 10:21:30 +01:00
31c958cb6f move macros to new file 2020-02-24 09:27:02 +01:00
c7254781d0 Add macro for submit button 2020-02-24 09:18:49 +01:00
62263a1f88 Update buttons 2020-02-20 15:59:08 +01:00
6aa51fcd85 Add tooltip to posterpage 2020-02-20 11:19:24 +01:00
c7155badf2 fix typo 2020-02-20 10:59:54 +01:00
a1405150bb Change tilte 2020-02-20 10:58:46 +01:00
7744232e5c Set background picture to cover 2020-02-20 10:32:02 +01:00
5b0c6a86d7 Add ugly background images to log in and register page 2020-02-20 10:28:05 +01:00
9a75d07181 Update 2020-02-20 10:18:10 +01:00
4f35fb56de Add some icons 2020-02-20 10:13:35 +01:00
4c6b1ee461 Fix Settings button 2020-02-20 10:03:42 +01:00
50746ab821 Allow username for login 2020-02-20 09:45:38 +01:00
ba3f9ec214 Update 2020-02-19 16:58:56 +01:00
48685e4da6 Fix some bugs 2020-02-19 16:36:55 +01:00
75329382ab Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-19 16:25:02 +01:00
3b798cb617 Rework auth package 2020-02-19 16:24:58 +01:00
120f4778d5 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-19 15:41:00 +01:00
928ab9512b Add automatic query display option changes 2020-02-19 15:40:54 +01:00
c90cd4d8a3 Rework settings page. 2020-02-19 14:49:52 +01:00
5e4666d3c8 Fix sidenav open trigger 2020-02-19 10:17:27 +01:00
bbe31dec71 Use anchor link to scroll to login form 2020-02-19 09:49:35 +01:00
42dca19941 wording 2020-02-18 16:28:39 +01:00
8839c2882a code updates 2020-02-18 16:25:32 +01:00
db41be56c7 code updates 2020-02-18 16:13:30 +01:00
12829eada8 Update index page 2020-02-18 16:07:44 +01:00
a1d33077a3 Small changes everywhere 2020-02-18 15:44:55 +01:00
4de2fdf6d8 Simplify template 2020-02-18 15:31:10 +01:00
e611a15aac Revert admin edit_user view 2020-02-18 15:22:48 +01:00
ad588c4344 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-18 14:54:19 +01:00
1fc61f4528 Add parallax with scorllspy 2020-02-18 14:54:14 +01:00
1817b6326d more feedback 2020-02-18 14:53:35 +01:00
4f803d0aa6 Readd some stuff 2020-02-18 14:44:31 +01:00
292c24b38f Simplify nopaque.js 2020-02-18 14:39:05 +01:00
e409727ef1 updat4e 2020-02-18 13:29:59 +01:00
12aeb33aa0 New variable 2020-02-18 13:28:17 +01:00
180e420021 Change Binarization text 2020-02-18 12:10:42 +01:00
54baa8633a Add Feedback for select field in job forms 2020-02-18 12:01:36 +01:00
283fbca969 Codestyle 2020-02-18 10:37:04 +01:00
cdb352f14a Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-17 16:14:30 +01:00
c327291cbe Small changes everywhere 2020-02-17 16:14:24 +01:00
950f87668f Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-17 14:57:28 +01:00
241a40ef44 Add secure filename for modesl and services 2020-02-17 14:57:24 +01:00
75d09b985b Redesign start page 2020-02-17 14:23:19 +01:00
50596ff2ae Use new event. 2020-02-17 12:20:09 +01:00
4f5aeed215 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-17 12:01:40 +01:00
8166ca840b Update landing page 2020-02-17 12:01:36 +01:00
191066a7e4 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-17 11:59:03 +01:00
aed888086f Add create_secure_filename Job method 2020-02-17 11:58:58 +01:00
1314993a60 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-17 11:08:08 +01:00
55d7848bd3 Update service pages 2020-02-17 11:08:03 +01:00
e7e4470699 Fix unclickable inputfields 2020-02-17 10:46:42 +01:00
416cc145cf Fix unclickable input fields 2020-02-17 10:45:45 +01:00
1f0e7f1c06 update 2020-02-14 15:40:28 +01:00
545c3ae2ec update 2020-02-14 15:23:02 +01:00
fb7d5151ba Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-13 15:08:19 +01:00
0cb51a34c4 Remove unnecessary job status 2020-02-13 15:08:15 +01:00
2edb6f9fdf Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-13 14:41:07 +01:00
81402d2d6a Add check_encoding to nlp jobs 2020-02-13 14:41:02 +01:00
dec07b0d63 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-13 14:35:59 +01:00
28c523d3d3 Add some infos to the readme 2020-02-13 14:35:55 +01:00
0ea03983d6 small fix 2020-02-12 16:42:46 +01:00
0f7df4fd3b new status view 2020-02-12 16:34:31 +01:00
67dab88674 Add running indicator 2020-02-12 16:24:56 +01:00
1cbea56ba9 Change title settings 2020-02-12 15:57:31 +01:00
de699e6ccf Update Jobpage 2020-02-12 15:48:51 +01:00
72984448de Update Job Page 2020-02-12 14:48:29 +01:00
0d7f7d859c Remove unused class 2020-02-12 13:32:21 +01:00
dc17ba5824 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-12 12:19:58 +01:00
611bb6ef62 Change RessourceList 2020-02-12 12:19:54 +01:00
bb5f456e6e Remove useless row html div 2020-02-11 16:13:00 +01:00
a28726994c Update Postertexts 2020-02-11 16:12:45 +01:00
87979bf7af Add Poster to navigation, Enable Account entries on all display sizes 2020-02-11 16:07:31 +01:00
efbb48c258 Poster update 2020-02-11 09:22:29 +01:00
69de8e9369 update 2020-02-10 16:07:26 +01:00
f3ea822108 Change poster page 2020-02-10 16:06:08 +01:00
cc1ff6e685 Revert index page 2020-02-10 16:06:01 +01:00
ef64280a2b Add poster option 2020-02-10 14:05:47 +01:00
8c40a1aa96 Add Posterpage 2020-02-10 13:25:15 +01:00
aa6ee42984 Remove unused test variable 2020-02-07 16:24:15 +01:00
81ca4ef12a fix icon 2020-02-07 16:21:48 +01:00
dd5b82c70b Add corpora and jobs as sub menu point for dashboard 2020-02-07 16:11:39 +01:00
e04f3d0ac3 Some fixes 2020-02-07 16:00:48 +01:00
00238e83c3 Update merge images name 2020-02-07 15:29:07 +01:00
b65b80fb3c Fix display without roadmap 2020-02-07 15:23:39 +01:00
acf5ae32ae Add roadmap and use just one template 2020-02-07 15:21:59 +01:00
3ce28de053 rerename 2020-02-06 09:52:14 +01:00
bb0f2e43bb Rename merge images to concat images 2020-02-06 09:50:57 +01:00
6ba87a06c4 set file upload size the proper way 2020-02-05 17:20:06 +01:00
004e85aad0 Add expert view in a hacky way 2020-02-05 16:09:59 +01:00
692b887d99 Add some documentation and code style 2020-02-04 10:10:22 +01:00
1d47e38780 Update 2020-02-03 16:04:47 +01:00
14cf2c55f9 Fix result addition 2020-02-03 15:58:46 +01:00
6b77fdaa37 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-03 13:59:43 +01:00
ccb97d5773 Add match nr 2020-02-03 13:59:37 +01:00
5db94f2192 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-02-03 13:38:13 +01:00
8b087e55b7 Update 2020-02-03 13:38:08 +01:00
da766b32ca mv socket on event on match_context to nopaque.js 2020-02-03 13:01:26 +01:00
21371efde6 Continue new list building for results 2020-02-03 12:58:40 +01:00
e95cc42a22 Add empty template 2020-02-03 09:59:39 +01:00
ca4c199191 Update user page to use ressource lists 2020-01-31 14:16:25 +01:00
279cdb70a8 Remove a lot of code redundancy 2020-01-31 14:14:08 +01:00
87cf04a87f Try to make the JavaScript a bit less pythonic. :D 2020-01-31 13:41:46 +01:00
56315c4e33 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-31 13:11:35 +01:00
20200dac30 Simplify corpus and job list data structure. 2020-01-31 13:11:30 +01:00
d03e04bcb9 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-30 14:23:21 +01:00
d36598bdda Update new analysis list construction 2020-01-30 14:23:19 +01:00
6e20e00c4e Change models 2020-01-30 11:01:17 +01:00
3dad22d41a Move JobList static attributes 2020-01-29 16:34:50 +01:00
da4cc75943 Work on new list bilding 2020-01-29 16:12:57 +01:00
c1adcb93ee insert null values instead of empty attributes 2020-01-29 13:57:38 +01:00
eeba8ad2e4 Style Dockerfile 2020-01-29 11:45:14 +01:00
f4bee2051e let nginx proxy route swarm viz container 2020-01-29 11:00:18 +01:00
6bd4f16e62 Remove unused config 2020-01-29 10:59:59 +01:00
bd8d0c14c3 Merge list classes 2020-01-29 10:50:31 +01:00
26e767609a use small buttons. 2020-01-28 17:01:20 +01:00
59866dea97 Add job bundle download preview 2020-01-28 16:42:40 +01:00
c9f5488a24 use empty template for JobList and CorpusList. performance++ 2020-01-28 16:42:15 +01:00
93dcd7c32f Make this ting scaleable 2020-01-28 14:38:58 +01:00
f1ab50b283 Change event names 2020-01-28 10:08:09 +01:00
4b0e9392a7 NEw analysis stuff 2020-01-27 16:11:34 +01:00
b4427cd3ec Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-27 13:19:34 +01:00
2b1e8f34de Rename some stuff 2020-01-27 13:19:33 +01:00
2c0f009e7c Change corpus analysis init behavior 2020-01-27 13:18:54 +01:00
cd02046590 Remove add_job.js 2020-01-24 11:58:11 +01:00
6a4ad05c35 Integrate job list javascript in nopaque.js 2020-01-24 10:27:11 +01:00
4dce792b51 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-23 16:00:52 +01:00
87d6380e22 Rework corpus analysis list building part 1 2020-01-23 16:00:48 +01:00
2dafe5ff0f Fix nopaque toast 2020-01-23 12:06:30 +01:00
77f1bf6cc8 not working test 2020-01-23 11:19:37 +01:00
88873c8aee Dynamic data collection from forms 2020-01-23 09:43:51 +01:00
fb089d62f0 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-22 16:14:03 +01:00
6bafa68804 Add test package for socketio form submission 2020-01-22 16:14:00 +01:00
50df7e0ab0 Do some cosmetics and code style 2020-01-21 15:39:08 +01:00
2142fb14af Add second iteration of json download 2020-01-21 14:50:27 +01:00
d6fdf69e81 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-20 15:53:56 +01:00
74e5c47e3b Enhance analysis UI add first iteration of results download 2020-01-20 15:53:53 +01:00
5c5f7012eb Remove redundant info 2020-01-20 15:53:06 +01:00
e2dada4dc9 Remove old version 2020-01-20 15:32:38 +01:00
ed0ec31246 Fix non unique id error 2020-01-20 11:11:53 +01:00
3e85daf8ab Create and use a nopaque namespace for functions and ressources 2020-01-20 09:49:39 +01:00
cc74871f90 Cleanup 2020-01-20 09:08:42 +01:00
cc52744109 Add cheese to all toasts. 2020-01-17 15:10:11 +01:00
e5928731ec Enhance toast to grilled cheese toast! 2020-01-17 15:10:01 +01:00
9ee2e9bdbd Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-17 14:31:20 +01:00
e4b794d37c Add tmp List.js implemetation 2020-01-17 14:31:14 +01:00
cebe1c6d31 move dropdown menu code 2020-01-17 11:46:30 +01:00
501eb3756c Minor updates 2020-01-17 10:49:04 +01:00
04bfe108c3 Javascript cleanup 2020-01-17 10:42:02 +01:00
554cc735b0 Tune the new job modal 2020-01-16 15:24:24 +01:00
b0d1ba472b Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-16 15:04:17 +01:00
688591ebe8 Add sort function to corpus and job lists 2020-01-16 15:04:12 +01:00
e04b31d282 Add error handling of invalid CQP queries 2020-01-16 11:56:16 +01:00
ef1eb9976e Change query result display 2020-01-15 16:04:33 +01:00
9353a3d5db Change corpus analyse ui 2020-01-15 15:52:42 +01:00
88f87da86c Change scaling 2020-01-15 13:45:57 +01:00
8dcf195e1b Use tables instead of collections in admin user view 2020-01-15 13:20:20 +01:00
91da024f36 Remove unneccessary code 2020-01-15 13:20:04 +01:00
32f2d7dbf7 New corpus and job lists. 2020-01-15 10:52:51 +01:00
9862d32dbb Use default values for lists in admin user page 2020-01-13 15:35:21 +01:00
8c69c3881f Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-13 15:33:11 +01:00
310c652514 Package cleanup and add LICENSE files! 2020-01-13 15:33:05 +01:00
446eca2d22 Add function to edit new metadata fields 2020-01-10 12:13:42 +01:00
c2923013a3 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-10 11:29:30 +01:00
cee89dd712 continue additional metadata 2020-01-10 11:29:26 +01:00
9b5329c960 Remove ip 2020-01-10 10:29:02 +01:00
4d17bacfb7 Remove 443 Port from nginx 2020-01-10 10:17:47 +01:00
fac06310c2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-09 16:28:00 +01:00
04808dd11c Add Code for ssl 2020-01-09 16:27:55 +01:00
c958f13ea1 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-09 16:04:56 +01:00
e1a8fbc531 Add options to add more detailed metadate to corpus file 2020-01-09 16:04:52 +01:00
f52d3eb42c Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-09 15:13:52 +01:00
0a388fe4b2 Add reverse proxy 2020-01-09 15:13:47 +01:00
96700586c8 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-08 16:02:49 +01:00
8e02c2fd14 Add more metadate to corpus files 2020-01-08 16:02:42 +01:00
44054a51c3 Remove gunicorn from requirements.txt 2020-01-08 16:02:28 +01:00
5e1ab758bc Enhance Readme 2020-01-08 16:02:18 +01:00
49f07e0ac5 Add gunicorn to requirements.txt 2020-01-08 15:18:03 +01:00
2308ed9a87 Add missing ";" 2020-01-08 13:20:56 +01:00
4446260c10 Change the way how the dismiss feature is added to toasts. 2020-01-08 10:47:59 +01:00
8416bda04b Add Icon and color for "merge_images" service. 2020-01-08 10:18:15 +01:00
6d65521000 Make toasts eckig again! 2020-01-08 10:16:49 +01:00
5aa4fcd66f Add close function for Toasts 2020-01-08 10:13:58 +01:00
3532fdc8a4 Add information about securing the docker API in README 2020-01-07 15:07:08 +01:00
08a277d967 Update readme 2020-01-07 15:03:21 +01:00
a7e94b8c9b Add merge images functionality. 2020-01-07 14:39:01 +01:00
0b0838f6e0 Fix typo 2020-01-07 13:05:44 +01:00
f189460543 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2020-01-07 13:03:44 +01:00
93891a34c9 Add form and service 2020-01-07 13:03:42 +01:00
0a3f2d3a67 Add newer nlp version 2020-01-07 11:34:16 +01:00
683bf93782 Add sql alchemy engine options to common configurations. 2020-01-07 11:32:46 +01:00
65b00e47ed Readd traefik code (commented out) 2020-01-06 11:08:40 +01:00
3d04d51f4f readd depends_on flags for docker-compose 2020-01-06 10:08:58 +01:00
360ee0f450 One compose-file for docker-compose and docker stack deploy. 2020-01-06 09:42:47 +01:00
54b431c70c Merge .env files and add docker configurations for the nopaqued service. 2020-01-06 09:36:51 +01:00
852c8a22a6 Update dind swarm script. 2020-01-03 10:27:55 +01:00
fe084e87bd Cleanup shell context 2020-01-03 09:53:34 +01:00
310bcba0bc Add host.docker.internal as extra host for daemon 2019-12-20 12:47:06 +01:00
592da38946 add docker compose file for traefik 2019-12-06 10:29:38 +01:00
c9a5139a56 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-12-05 16:06:00 +01:00
e240bf7860 Show prepare button if status switches to failed. 2019-12-05 15:58:28 +01:00
39f92523c4 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-12-05 15:37:48 +01:00
467a84b18b Add certificate mounts 2019-12-05 15:37:46 +01:00
ddeee1fd49 add traefik, first attempt 2019-12-05 15:37:06 +01:00
19651433cd Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-12-04 11:03:49 +01:00
947e9f984b Add loading animation for query request 2019-12-04 10:54:40 +01:00
90c12e5800 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-12-04 10:40:15 +01:00
904e36a8bb Fix js 2019-12-04 10:40:11 +01:00
c3fe3d9247 Change loading animation 2019-12-04 10:31:01 +01:00
31ac9ddcf3 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-12-03 15:11:40 +01:00
7ec41a03be Add Inspect view 2019-12-03 15:11:31 +01:00
ccfd449260 Rename analysis container 2019-12-03 11:46:56 +01:00
a4ffee5b2e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-12-02 16:58:50 +01:00
c6c8a775f4 Update compose files 2019-12-02 16:58:44 +01:00
d57ced8a33 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-12-02 16:13:57 +01:00
94e8d0895c Add first things to get more context for one match. 2019-12-02 16:13:53 +01:00
f9f6857e4e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-12-02 14:24:37 +01:00
8bf71dea47 Fix config file name 2019-12-02 14:24:33 +01:00
d2334e6a1e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-12-02 14:19:51 +01:00
3af400a732 Add get_sentences to wrapper 2019-12-02 14:19:40 +01:00
ae30ba7186 Change email template to fit new name 2019-12-02 12:03:50 +01:00
0c55c027db Change storage dir 2019-12-02 11:57:08 +01:00
f63a850175 Renaming: opaque->nopaque 2019-12-02 11:34:28 +01:00
da2f7f6c7d Updates for stack deployment 2019-12-02 11:06:46 +01:00
6317a479f5 Back to full blown debian base images as they seem to be more reliable. 2019-11-29 15:19:25 +01:00
6db99cfba5 Change base image 2019-11-29 15:08:16 +01:00
1c9e715980 Fixe some things for query results 2019-11-28 15:19:52 +01:00
dbd580b3c0 Get results with wrapper 3.0 2019-11-28 14:14:56 +01:00
dec90e30b5 better tooltips 2019-11-28 13:45:00 +01:00
9b71fb0cc9 Add tooltips to query ui 2019-11-28 12:09:25 +01:00
acedd35e64 Change swarm startup 2019-11-28 09:57:03 +01:00
49311f58f0 Add basic style for expert view 2019-11-27 15:56:39 +01:00
54f3036d89 push 2019-11-27 13:29:43 +01:00
5411bd91bd Fix imports and hardcoded values 2019-11-27 10:18:15 +01:00
1f95c6de46 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-27 09:43:37 +01:00
3bc485cdb3 Add some output 2019-11-27 09:43:34 +01:00
b5afdf74f2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-27 09:41:22 +01:00
b3d5c15df3 CQiWrapper new data structure 2019-11-27 09:41:21 +01:00
d63b5ec266 Handle new data structure 2019-11-27 09:36:27 +01:00
9f42b9b99d Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-26 14:58:48 +01:00
58b42822dc fix stack deploy yml 2019-11-26 14:58:41 +01:00
5336eac2c9 fix stack deploy yml 2019-11-26 14:58:33 +01:00
7edd635573 fix socketio redis 2019-11-26 14:58:21 +01:00
30f60b60c2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-26 11:49:01 +01:00
00d61a7bf5 Add sentences to results 2019-11-26 11:48:54 +01:00
52b7202017 Fix CQiClient 2019-11-26 11:48:42 +01:00
f588cd743f Better output on command line 2019-11-26 11:43:08 +01:00
3d7ebfa1dd Enhancements 2019-11-26 11:39:27 +01:00
8a3e5073a3 Add dind_swarm setup and config. 2019-11-26 10:57:01 +01:00
6c9b43367b push 2019-11-25 12:31:48 +01:00
0f23cbe2a2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-25 11:56:30 +01:00
2fc092285c Dinge 2019-11-25 11:56:27 +01:00
d23656ae80 Some fixes 2019-11-25 11:51:56 +01:00
eeed9268bb Remove gzip compression 2019-11-25 10:29:05 +01:00
3d8d2b3e48 Codestyle update 2019-11-25 10:12:39 +01:00
dd469386e1 change socket logic 2019-11-22 14:13:14 +01:00
e52622a5d5 First result view 2019-11-21 16:05:17 +01:00
fd2547de0c Add compression of result dictionary and size infos for other compression or no compression methods 2019-11-21 16:05:00 +01:00
e6b27b0970 Add first setup for compression 2019-11-19 15:21:42 +01:00
1f74ad8a8e Add Wrapper Version 2.0 2019-11-19 11:48:00 +01:00
e3db29e476 Change container name for analysis 2019-11-19 11:42:23 +01:00
88b0907fc5 Fix for loop 2019-11-19 10:23:47 +01:00
fb5d9cbf7d Add errors to form, if they occur 2019-11-19 09:54:31 +01:00
96db5c1e75 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-18 16:07:12 +01:00
0ca4bf6030 Add first query result function 2019-11-18 16:07:07 +01:00
9a475f2ad2 Remove job deletion workaround 2019-11-18 15:55:19 +01:00
6d807d897d Update add job js 2019-11-18 15:41:32 +01:00
5c8ca4e22d Fix imports 2019-11-18 14:29:16 +01:00
14e869b2dd Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-18 14:26:39 +01:00
ba0e82738a Some template stuff 2019-11-18 14:24:47 +01:00
ae6e252830 Temp event query handling 2019-11-18 14:24:31 +01:00
5fdd67ebf2 Add new CQiWrapper 2019-11-18 14:24:13 +01:00
ab0e79ac3b Change add job handling (preparation for api processing) 2019-11-18 14:23:53 +01:00
8d47d16319 Remove debug statement 2019-11-18 11:22:28 +01:00
7a94b19326 Fix wrong job additions 2019-11-18 11:21:40 +01:00
0cd4be055e Change corpus analysis socket behavior 2019-11-18 11:08:33 +01:00
fc560933bc Change edit user form name 2019-11-15 14:01:36 +01:00
5fd9711da9 Simplify db lookup for queries by id 2019-11-15 13:09:12 +01:00
7457a4be94 Move admin tables in admin package. 2019-11-15 12:57:01 +01:00
aacfe40bd6 Code enhancement 2019-11-15 12:51:53 +01:00
f22bff4ed0 Updated URL Logic for admin package 2019-11-15 11:45:04 +01:00
74324ac0be Remove back to corpus button 2019-11-14 16:15:24 +01:00
3fb5802682 Cleanup corpus analysis code 2019-11-14 15:53:43 +01:00
df98f3a900 Change HTML for corpus analysis 2019-11-14 15:34:07 +01:00
1b02d73d66 Update background functions 2019-11-14 13:40:05 +01:00
7dd55c47a0 Code update to new request system 2019-11-14 13:19:05 +01:00
baf06d3106 Add user directory on registration 2019-11-14 10:01:45 +01:00
bab479db20 Change delete execution 2019-11-14 09:48:30 +01:00
1152417419 First output of query results 2019-11-12 16:45:54 +01:00
28171eb525 init materialize elements the right way. 2019-11-12 16:16:41 +01:00
5660318450 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-12 14:02:20 +01:00
dfd9d09f3f Clean up 2019-11-12 14:02:01 +01:00
4f53122515 Use CQiClient for testing purpose. 2019-11-12 14:00:03 +01:00
0d441a9364 Change import logic. 2019-11-12 13:36:22 +01:00
2bebd0256c Implement logger in another way. 2019-11-12 13:23:54 +01:00
6459c9f064 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-12 12:08:11 +01:00
55cacf53fc Add JSON handling with emit and on 2019-11-12 12:08:09 +01:00
d8b8c9f6e0 Remove unused import 2019-11-12 12:07:34 +01:00
b0c6bb9c05 Add checks if the user is allowed to start an analysis. 2019-11-12 12:04:07 +01:00
19f1dea4fa Use list comprehension instead of class methods. 2019-11-12 12:03:46 +01:00
5602ba950f Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-11 15:58:00 +01:00
388e7eaa60 Add first implementation of loading modal 2019-11-11 15:57:55 +01:00
ffed8592c8 Add new CQiWrapper 2019-11-11 15:35:37 +01:00
0392d25464 Hups 2019-11-11 14:20:44 +01:00
8a607b6dc0 Multiple analyses sessions perfectly implemented. 2019-11-11 11:51:18 +01:00
87b7f07d26 Fix event loop 2019-11-11 09:41:34 +01:00
4b0ef837ad Some renaming and moving 2019-11-08 12:21:59 +01:00
e0a1514084 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-07 15:58:24 +01:00
9be33ffc5a Add first tr to implement VQiWrapper 2019-11-07 15:51:01 +01:00
8e5e8408bd Add CQiWrapper 2019-11-07 15:48:47 +01:00
03b956c457 Remove workaround to wait for container 2019-11-07 15:28:07 +01:00
13421a9e7f Remove 2019-11-07 14:37:37 +01:00
ebf2f00e0d Add example for client management 2019-11-07 14:33:58 +01:00
3ccae085d2 Remove unused import 2019-11-07 14:33:48 +01:00
7233c74dca Add some fixes 2019-11-07 13:56:21 +01:00
7efe39cbd5 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-07 11:06:21 +01:00
d420b80ac5 Fix wrong joblist additions. 2019-11-07 11:06:16 +01:00
54c0d0f27d Fix app context 2019-11-07 10:55:23 +01:00
76fcb01186 Update socketio event names 2019-11-07 10:53:39 +01:00
19f470ca18 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-07 10:48:10 +01:00
47440880d5 Set up all things for first query 2019-11-07 10:45:12 +01:00
1b3d40eed3 Cleanup eventcode 2019-11-07 10:44:02 +01:00
414ebc73ff Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-06 15:44:10 +01:00
82ce08b938 Add CQiClient 2019-11-06 15:44:06 +01:00
0af783a5a6 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-06 15:40:47 +01:00
08aafb8f99 Add corpus analysis stuff 2019-11-06 15:40:43 +01:00
8f3517d5b6 Remove logging code 2019-11-06 15:38:00 +01:00
b0cf581da9 Remove logs 2019-11-06 15:35:27 +01:00
5aa777bc11 Set corpus analysis connection stop signal 2019-11-06 14:45:08 +01:00
1389b6b510 Change logic of how connected sessions are identified. 2019-11-06 14:35:33 +01:00
076ba7356d Move events to app package 2019-11-06 13:22:18 +01:00
7757c12dc4 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-06 10:07:40 +01:00
958779ec61 Use background tasks for file operations. 2019-11-06 10:07:34 +01:00
64dce7ed28 Set status on upload, edit, or delete 2019-11-06 10:04:29 +01:00
2d4559e4fe Show buttons only on wanted status 2019-11-06 10:04:01 +01:00
da077cae3f Simplify informationupdater 2019-11-05 16:22:48 +01:00
4bcd97c003 Only use relative imports for functions in the same package. 2019-11-05 16:22:36 +01:00
eb85869158 Add status to dictionary represantion 2019-11-05 15:35:51 +01:00
a9efc06d07 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-05 15:34:46 +01:00
b29f9f5aa8 Add information updater to corpus page. 2019-11-05 15:33:42 +01:00
d04f90dee8 Add live colors to corpu sstatus 2019-11-05 15:22:25 +01:00
f2024be050 Add back button 2019-11-05 14:23:45 +01:00
a288ce2ec3 Add merge_corpus_files to compose file for dev process 2019-11-05 14:06:36 +01:00
04fe6b063e Add sanity checks for corpus preparation 2019-11-05 13:40:31 +01:00
910a187c04 Add prepare button to corpus 2019-11-05 10:52:57 +01:00
787c6e75b3 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-05 10:32:44 +01:00
29183b8763 prepare vrt file in background thread. 2019-11-05 10:32:42 +01:00
a2f7f90137 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-05 09:57:57 +01:00
efd3be5264 Add mount for development process 2019-11-05 09:57:52 +01:00
69387ee183 Insert metadata to corpus file in constructor 2019-11-05 09:12:06 +01:00
8ef6d3a04b Fix date formatting for end-date display 2019-11-05 09:11:37 +01:00
84578c0d76 UI enhancements 2019-11-04 16:58:15 +01:00
7176ea26ad Show Corpus status on corpus page. 2019-11-04 15:40:55 +01:00
ffcc13ef5b Add status to corpus model again... 2019-11-04 15:35:09 +01:00
37d5802b42 Update 2019-11-04 15:06:54 +01:00
3bfe50b15c Add status for Corpus model 2019-11-04 14:12:15 +01:00
ce39b24937 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-04 13:19:20 +01:00
9c611afdc3 Emit query data via socketio 2019-11-04 13:19:15 +01:00
fa61f97413 Add recv_query event for testing 2019-11-04 13:18:55 +01:00
093f3bfee8 Add confirmation modals for corpus file deletion 2019-11-04 13:11:17 +01:00
eea0f4635d Add permission check for job deletion. 2019-11-04 11:04:42 +01:00
e1225c95bf Set end date field as N.a. if the job is not completed. 2019-11-04 11:04:23 +01:00
dfb7f96d2d Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-04 09:54:36 +01:00
6dd16e8e78 Add edit corpus file form 2019-11-04 09:54:30 +01:00
85629aa006 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-11-04 09:52:59 +01:00
60f1cb7573 Revert to view per formular in user settings 2019-11-04 09:52:55 +01:00
fbde788b27 Center modals 2019-11-04 09:38:47 +01:00
69a0bb9fb5 Remove unused import 2019-11-04 09:03:58 +01:00
799101d380 Move /jobs related code in dedicated package. 2019-11-04 09:03:31 +01:00
162aa5d7c5 UI Update 2019-10-31 15:56:23 +01:00
5881444b9f Use extra pages for add_corpus and add_corpus_file forms. 2019-10-31 15:29:02 +01:00
61545ed4ec Push one fix idea for multiple forms 2019-10-31 13:19:18 +01:00
755f5f3137 Add error handling 2019-10-31 11:34:45 +01:00
74d9147735 Remove FAB + Codeformatting at corpus page. 2019-10-31 10:45:01 +01:00
08ba7476f1 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-31 10:25:52 +01:00
3135eb0897 Move corpora views, and forms in package. 2019-10-31 10:25:48 +01:00
4d953f85f7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-30 15:16:42 +01:00
e9ef0d1391 Add new profile forms and views (error prone) 2019-10-30 15:16:37 +01:00
8fb52fcd31 Remove default values. 2019-10-30 14:29:17 +01:00
217a5a9e0c Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-30 14:26:17 +01:00
326507d361 Change submit button style. 2019-10-30 14:26:13 +01:00
dcea3ea8e2 Add corpus analysis fix 2019-10-30 14:15:06 +01:00
30eefbcb72 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-30 14:06:25 +01:00
0dc015b29c Add more form fields to corpus analysis 2019-10-30 14:06:23 +01:00
14f779d66a Change url logic of job handlers 2019-10-30 13:57:09 +01:00
e9d1734364 enhance routing for corpus actions 2019-10-30 13:12:31 +01:00
617cc06125 add directory creation 2019-10-30 09:20:57 +01:00
e2268f9234 add some debug logs 2019-10-30 09:02:45 +01:00
8b8939b17a Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-30 08:28:54 +01:00
7fb37dcb70 restructure corpus delete method 2019-10-30 08:28:52 +01:00
f586518e9a Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-29 17:44:24 +01:00
31c015f761 Add query analysis form options etc. 2019-10-29 17:42:32 +01:00
7dcc8c48da Also delete corpus files when a corpus gets deleted 2019-10-29 14:35:23 +01:00
0a8f6a5a44 Fix file save path 2019-10-29 13:56:32 +01:00
b4d2093986 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-29 13:47:31 +01:00
4930709c9d Add corpus file upload 2019-10-29 13:47:25 +01:00
5f29112390 Fix some things 2019-10-29 09:51:47 +01:00
f4c7af02ad Change corpus file model to save metadata. 2019-10-28 15:46:25 +01:00
8a4a7577a0 Preview for new corpus page. 2019-10-28 14:53:25 +01:00
2534b4cae7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-28 09:18:12 +01:00
b46090133d Add first iteration of query and analysis corpora page 2019-10-28 09:16:34 +01:00
4eb6e4f831 Also wait for redis 2019-10-25 15:28:45 +02:00
775ddc601e Code enhancement 2019-10-25 15:09:19 +02:00
0a6bc055a0 Rewrite download function to use ressource ids instead of paths 2019-10-25 14:27:37 +02:00
409d94d0ae Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-24 13:29:09 +02:00
810388b78b Add new values to to_dict methods 2019-10-24 13:29:02 +02:00
83f1aa1a6b Add dynamic output link creation. 2019-10-24 13:28:47 +02:00
fca352c3dd Add dir to job creation. 2019-10-24 13:28:32 +02:00
3e622ac553 Add first Corpus analysis page 2019-10-24 13:14:15 +02:00
dce834c9a1 Add full_width and limited_width templates. 2019-10-24 13:13:34 +02:00
6f8a8dbc77 Fix mount path 2019-10-23 15:21:34 +02:00
c0fab4aef3 Add bash ti image 2019-10-23 14:42:23 +02:00
f919e97446 Fix wait-for-it clone 2019-10-23 14:15:45 +02:00
5774b5120d Add git install to Dockerfile 2019-10-23 14:05:23 +02:00
ad6daa35cc Add wait-for-it.sh 2019-10-23 13:58:27 +02:00
f324bc9f3b Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-23 13:31:01 +02:00
02c4f814b8 Mount config.ini into daemon container 2019-10-23 13:30:54 +02:00
5eb13f2ab5 Add migrations 2019-10-23 11:23:29 +02:00
bf4b9808c3 Fix undefined JobList error 2019-10-23 11:23:06 +02:00
afac42464a Add CurpusFile result relation to Corpus 2019-10-23 11:22:29 +02:00
c6341cbce6 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-23 08:35:17 +02:00
2ba80146e9 Some prework for files from database update 2019-10-23 08:35:15 +02:00
488baf0b67 Fix new results table view 2019-10-22 15:28:54 +02:00
64f0082471 Add storage mount to daemon 2019-10-22 13:07:06 +02:00
83d6839fd7 Add new results table view 2019-10-22 13:06:57 +02:00
bafa522eae Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-17 13:33:19 +02:00
fcfcd7032d Add migrations. 2019-10-17 13:33:16 +02:00
82fb73de1a Add new realtion 2019-10-17 13:32:22 +02:00
85b2100e60 Add to_dict methods 2019-10-17 13:26:20 +02:00
9b4f29a849 Add Migrations 2019-10-17 11:38:31 +02:00
d554e8eef2 Add entrypoint script as volume 2019-10-17 11:21:58 +02:00
2c4a6a8cea Generalize docker-entrypoint for further flask commands 2019-10-17 11:16:08 +02:00
14503eb45a alibi file 2019-10-16 16:55:16 +02:00
abe2ed1666 add tables for files 2019-10-16 16:52:05 +02:00
8158c742d9 Use Posgres 11... It seems like there are some incompatibilities 2019-10-15 15:14:06 +02:00
313a784766 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-10-15 15:00:02 +02:00
87a0657d4c Remove footer. 2019-10-15 15:00:00 +02:00
88042dfd8e Add dark mode 2019-10-09 16:10:30 +02:00
7ad9a61e24 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-27 13:56:58 +02:00
9d6e54e966 Change how job form works. 2019-09-27 13:56:52 +02:00
a8489a5550 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-24 17:10:23 +02:00
b05718c03d Fix result file order. 2019-09-24 17:10:18 +02:00
787bf4c377 Unify service pages. 2019-09-24 16:55:24 +02:00
a267de0867 Add cancel button to delete modal. 2019-09-24 16:21:22 +02:00
6d3ccce83f Fix QueuePool size timeout error. 2019-09-24 16:16:55 +02:00
202ab2e0de Add download icons to job page download buttons. 2019-09-24 16:16:30 +02:00
1f9137be47 Fix admin user page layout. 2019-09-24 16:16:01 +02:00
873997fbbf Sort result files for sorted download buttons. 2019-09-24 16:15:46 +02:00
695a57560f Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-24 14:04:57 +02:00
ed288598cd Add delete corpora function and function to view an delete foreign jobs and corpora. 2019-09-24 14:04:49 +02:00
300832d403 further ui improvements 2019-09-24 13:42:30 +02:00
3cf42832f5 Add additional options to ocr form. 2019-09-24 12:03:24 +02:00
4858f36d76 Codestyle for auth package. 2019-09-23 16:39:36 +02:00
5749c94bca Codestyle for admin package. 2019-09-23 16:25:26 +02:00
783b8c7e82 Move auth.settings to a new package (profile) as profile.index 2019-09-23 16:11:01 +02:00
5da5e402c0 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-23 14:37:03 +02:00
4aba8cbd51 Change border 2019-09-23 14:36:52 +02:00
556e6a0ae2 Update README.md 2019-09-23 14:24:09 +02:00
8ba1d43f33 Further styling for ocr job form. 2019-09-23 14:10:27 +02:00
4c8ab6b3c1 Add dummy checkboxes for further ocr job options. 2019-09-23 13:55:25 +02:00
2d84c11282 Update .gitlab-ci.yml 2019-09-19 09:23:20 +02:00
3e3918c672 Update .gitlab-ci.yml 2019-09-19 09:22:18 +02:00
d269249db0 Only use one generic function for socketio background tasks and rename the socketio event (it's no connect so don't name it like one) 2019-09-18 14:05:56 +02:00
9f74e8ce82 Fix typo 2019-09-18 13:12:49 +02:00
43a01b8de6 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-18 12:07:06 +02:00
5ad5bc0a2f Add foreign admin views 2019-09-18 12:06:34 +02:00
f9649af08d Make CorpusList class ready for admin view. 2019-09-18 11:35:25 +02:00
daf6c15111 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-18 11:33:08 +02:00
1ebfee5cb3 Add admin view on foreign jobs. 2019-09-18 11:33:06 +02:00
b90d6114b0 Make JobList class ready for admin view. 2019-09-18 11:32:35 +02:00
0ea87de072 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-17 16:31:45 +02:00
0d060f0cbf Move job and user delete functions to utils.py 2019-09-17 16:31:41 +02:00
d7e71638a2 Update progress modal 2019-09-17 16:15:37 +02:00
09f7d7ac68 Add delete functions for jobs and users. 2019-09-17 14:36:15 +02:00
683b59bb47 Add function to cancel file upload. 2019-09-17 14:20:15 +02:00
07c4e31510 Use modals instead of toasts for progress indication. 2019-09-17 10:56:56 +02:00
70c97d44f9 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-17 10:00:45 +02:00
3cacdf8185 Set version for latest. 2019-09-17 10:00:39 +02:00
373c7ed4d9 Update .gitlab-ci.yml 2019-09-16 15:58:42 +02:00
ba838eaf1f Enhance delete_job method. 2019-09-16 14:09:07 +02:00
9005c583ca Add progress bar for file upload. 2019-09-16 12:12:42 +02:00
22a1223258 Codestyle 2019-09-13 14:02:17 +02:00
1118beaf61 Add storage as volume 2019-09-13 14:01:57 +02:00
3913663c56 Don't use migrate in setup-database routine. 2019-09-13 09:35:20 +02:00
6333c88d36 Add new migrations. 2019-09-13 09:32:30 +02:00
a1386c3e0b Delete migrations from repo 2019-09-13 09:27:01 +02:00
3a5725d943 Update .gitignore 2019-09-13 09:25:39 +02:00
f32f3c7fa6 Use logging again 2019-09-13 09:22:10 +02:00
df0e677198 Comment out logger code. 2019-09-13 08:49:23 +02:00
591850bbfd Set unbuffered binary stdout and stderr. 2019-09-13 08:49:00 +02:00
1bdae333b7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-12 16:45:12 +02:00
b2e2484725 Add job delete function. 2019-09-12 16:45:05 +02:00
2991082f1f Add different logging levels. 2019-09-12 16:44:53 +02:00
c51a9492f3 Add switch for binarization 2019-09-12 16:00:48 +02:00
6cf12fa799 Don't show character counter for EMail adresses. 2019-09-12 14:26:53 +02:00
3bb900c7eb Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-12 14:25:08 +02:00
36f10d51ee Show character counters on register page. 2019-09-12 14:25:03 +02:00
f0197b5af6 Allow Emails to be 254 characters long. 2019-09-12 14:24:43 +02:00
c6597d4e37 Add character counter for corpus form. 2019-09-12 12:05:59 +02:00
682ca30991 Fix logging. 2019-09-12 12:01:46 +02:00
2368cfb1f9 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-12 11:42:40 +02:00
86b08bc142 Add logging for production. Mount web.env into opaque_daemon. 2019-09-12 11:42:33 +02:00
926935af56 Enhance logging. 2019-09-12 11:35:23 +02:00
16fad5bb2d Add character counter to job forms. 2019-09-12 11:12:59 +02:00
129ee05b51 Fix path fix 2019-09-11 16:35:05 +02:00
437f284dd6 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-11 16:28:00 +02:00
3d93b033a2 Change log directory location 2019-09-11 16:27:54 +02:00
9f341293b9 Update README.md 2019-09-11 16:25:56 +02:00
50b21d056d Update .gitignore 2019-09-11 16:19:44 +02:00
26be218293 Update .gitignore 2019-09-11 16:11:06 +02:00
59f0018516 Update .gitignore 2019-09-11 16:09:19 +02:00
05043e16e8 Update .gitignore 2019-09-11 15:55:44 +02:00
66adec8b7d Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-11 15:53:51 +02:00
3accc058e3 Correct simple loging 2019-09-11 15:52:38 +02:00
8115c8b755 Add Version selection to NLP 2019-09-11 15:40:37 +02:00
dd7ef2a113 Fix wrong path. 2019-09-11 14:55:26 +02:00
0826f6a9f7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-11 14:53:15 +02:00
c7337a5277 Add first stopping and deletion functions etc. 2019-09-11 14:51:59 +02:00
230d057fee Add simple logging 2019-09-11 14:50:29 +02:00
53428a01bb Add workflow dummy entry. 2019-09-11 10:00:52 +02:00
1960b14d9d Re- rename edit_profile to settings 2019-09-11 09:47:26 +02:00
15a418cf7c Add navigation highlighting. 2019-09-10 16:09:35 +02:00
51d2623e2e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-10 15:10:21 +02:00
cc9460c901 Add Account navigation links for medium and small devices. 2019-09-10 15:10:16 +02:00
d537096f74 Add user self delete function 2019-09-10 14:18:20 +02:00
2f6dd37abb Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-10 13:49:14 +02:00
fda70e216e Add admin page to edit user informations. 2019-09-10 13:49:01 +02:00
48b5b09db1 Show locale time representation at corpus/job pages. 2019-09-10 13:40:26 +02:00
f87363ac13 Remove debug message. 2019-09-10 13:39:50 +02:00
8786defa01 Add function to change user email 2019-09-09 16:17:59 +02:00
97517339ff Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-09 15:21:35 +02:00
863db0a540 New storage path 2019-09-09 15:21:29 +02:00
35d126aaea Make admin user list sortable part 2 2019-09-09 15:04:43 +02:00
c7aae83438 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-09 15:02:25 +02:00
7775954123 Make admin user list sortable. 2019-09-09 15:02:17 +02:00
295ed49799 Don't use named volumes. 2019-09-09 14:58:49 +02:00
dc975935ca Use named volume for database 2019-09-09 12:05:36 +02:00
50a31967f2 Make compose file swarm ready. 2019-09-09 10:49:17 +02:00
a8395740b8 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-09 09:12:55 +02:00
cfc35b5ae7 After dockerization there are no __pycache__ directories. So we don't need to ignore them anymore. 2019-09-09 09:12:52 +02:00
28bf3b3c1d After dockerization there are no __pycache__ directories. So we don't need to ignore them anymore. 2019-09-06 14:59:32 +02:00
d87c424ee7 Rename env files to match the service naming scheme. 2019-09-06 14:23:58 +02:00
94a1c61a0f Add code as volume to enable live changes. 2019-09-06 14:00:16 +02:00
25cb960198 Rename services in compose. 2019-09-06 13:42:47 +02:00
444e1221df Rename *_env -> *.env 2019-09-06 13:11:32 +02:00
a6fc0c7826 Rename examples to tpl files. 2019-09-06 13:03:59 +02:00
339e6b8de9 Add migrations directory to repo 2019-09-06 13:03:45 +02:00
fc69eedfea Add CI script 2019-09-06 13:00:11 +02:00
b9a8c63aee Dockerize the Application. 2019-09-06 11:38:35 +02:00
1044674074 Dockerize the App! 2019-09-05 16:39:50 +02:00
b34b46ae5d Remove Merge marker. 2019-09-05 14:58:25 +02:00
e9da8befd4 Remove merge marker and readd TestingConfig class. 2019-09-05 14:49:59 +02:00
9ba7989fcc Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-05 14:47:36 +02:00
8d7f053a4c Add postgresql database 2019-09-05 14:43:36 +02:00
e3db2ecd1e Load environment variables in container. So the python-dotenv module is no longer needed! 2019-09-05 14:42:21 +02:00
0f0c40951b Use fix path! 2019-09-05 12:00:31 +02:00
78499ee731 Remove unused (since flask-socketio) FLASK_ENV variable. 2019-09-05 10:20:41 +02:00
78710ed58a Add config selection to .env example. 2019-09-05 10:20:18 +02:00
40809d9c7b Change setting names. 2019-09-05 10:12:40 +02:00
a05e37ddb6 Add .env example file. 2019-09-05 10:12:27 +02:00
f2806f9473 Codestyle. 2019-09-04 16:00:14 +02:00
3b57211da9 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-04 14:53:25 +02:00
64475afc41 Change file download view. 2019-09-04 14:53:23 +02:00
f8bee3553d Dockerize opaque flask app with docker-compose – first step 2019-09-04 14:51:46 +02:00
c6184976b8 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-09-04 14:50:33 +02:00
c5dbc7db7f Remove old Job definitions 2019-09-04 14:50:18 +02:00
bb26cba009 Codestyle. 2019-09-04 14:01:20 +02:00
aa23cf04b5 Small restructore of the design. 2019-09-04 13:51:21 +02:00
5952db0b4a Change how the job id is obtained. 2019-09-03 16:06:15 +02:00
4dc331b2fe Add corpus page. 2019-09-03 15:58:40 +02:00
633bd58087 Codestyle. 2019-09-03 09:07:09 +02:00
b904ee1e1c Change end-date value correctly. 2019-09-02 15:37:36 +02:00
8ed7697a63 Add live information updates to job page. 2019-09-02 15:25:30 +02:00
bec48e5f39 Fix method naming and add Animations.js to base template. 2019-09-02 15:24:39 +02:00
ff837aa943 Don't use extra variable for one-time use. 2019-09-02 15:24:09 +02:00
d30980bfa9 Add Animations class, including pulse. 2019-09-02 15:22:26 +02:00
6ed260b065 Remove unused import. 2019-09-02 10:59:13 +02:00
ade6d12eeb Codestyle 2019-09-02 10:42:43 +02:00
e658d2bbd0 Don't create new app instance for background tasks. Reuse the old one! 2019-09-02 10:42:28 +02:00
565d273dd4 Add comment and remove debug code. 2019-09-02 09:17:13 +02:00
6f4b9efa25 Add some comments and remove debug code. 2019-09-02 09:17:00 +02:00
7d4a1e6d37 Remove old scheduler code. 2019-08-30 14:00:08 +02:00
8f3c53dad2 Use JSON patch the correct way! 2019-08-30 13:31:00 +02:00
7702de8770 (Re)Implement live update of corpus and job lists. 2019-08-29 15:12:08 +02:00
1955d3c015 Remove old note. 2019-08-29 12:01:09 +02:00
876eb465b8 Add client side event handlers for update-* events. 2019-08-29 11:37:00 +02:00
cf56394441 Remove unused imports. 2019-08-29 11:06:32 +02:00
0d3f54d655 Implement JSON patches for corpus and job lists. 2019-08-29 10:42:53 +02:00
98de581132 Cleanup special list classes. 2019-08-28 17:31:09 +02:00
52bd8ec94e Add background task to handle data changes for corpora and jobs via socketio. 2019-08-28 17:27:43 +02:00
b48e74f560 Integrate the possibility to create a minimal app for auxillary functions. 2019-08-28 17:19:08 +02:00
e5ea98510e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-08-28 10:54:50 +02:00
417a00269d Comment out scheduler. 2019-08-28 10:54:48 +02:00
82f81c62ac Apply monkey patch to all modules supported by eventlet. 2019-08-28 09:49:25 +02:00
b580f9cb9f Disable scheduler. 2019-08-28 09:48:10 +02:00
064481d1bd Do not apply eventlets monkey patch to the thread module. 2019-08-27 10:41:01 +02:00
d34447686b Move socketio event handlers in seperate file. 2019-08-27 10:40:29 +02:00
fcd797b28d Add redis to requirements. 2019-08-27 09:28:14 +02:00
9a9e3ebf73 Add socket.io.js.map to fix the client-side "not found" error 2019-08-27 09:27:40 +02:00
9f011b27c3 Add redis message qeue 2019-08-26 14:21:06 +02:00
5771fb8ae7 Update README.md 2019-08-26 14:09:43 +02:00
dd2fcaa28d Some updates for README 2019-08-26 10:26:37 +02:00
d435a2417f Codestyle. 2019-08-26 10:02:45 +02:00
4d90b552d0 Remove default values. 2019-08-26 09:57:26 +02:00
7aef3de81d Stop polling. Use SocketIO! 2019-08-23 15:05:01 +02:00
3d8b8e9182 Merge branch 'socketio' into 'development'
Socketio

See merge request sfb1288inf/opaque!1
2019-08-22 15:16:55 +02:00
9f215d7613 Add socketio javascript 2019-08-22 15:13:10 +02:00
a44407255b Load .env file manually because socketio.run does not load it for you. 2019-08-22 14:20:54 +02:00
a5f1336847 Reenable FLASK_APP environment variable. 2019-08-22 09:43:51 +02:00
47ab22c534 Codestyle 2019-08-22 09:35:23 +02:00
19f60cfd0f Codestyle and new python package versions. 2019-08-22 09:33:34 +02:00
bfe28eca61 Add socketio. 2019-08-21 14:41:38 +02:00
3a6fdaa24b Catch more exceptions. 2019-08-21 11:40:09 +02:00
be0241519d Don't save job filtered job lists in variables. Handle service not found error. 2019-08-21 08:37:10 +02:00
a86ae5c75c Use minimal list.js file. 2019-08-20 16:12:03 +02:00
6975076fc3 Remove ugly workaround for scheduler function. Now the current app_context is used, instead of creating a new app instance. 2019-08-20 15:57:58 +02:00
5ff2ef9301 Use custom List classes for corpora and job lists. 2019-08-20 11:24:52 +02:00
74c863e0f7 Only handle difference of changes to the job list. 2019-08-19 17:09:01 +02:00
5ba08a21f4 Add jsondiffpatch. 2019-08-19 17:08:27 +02:00
8a49b8c871 Add jsondiffpatch. 2019-08-19 17:08:16 +02:00
025c51646c Add javascript code for polling with update subscibers. 2019-08-16 14:54:29 +02:00
6d0096c2cc Renome to_jsonifyable method to to_dict 2019-08-16 14:53:59 +02:00
22f6c6b4b6 Addition to last commit. 2019-08-16 09:49:47 +02:00
4a5804460f Add admin functions to api. Add to_jsonifyable method to Job and Corpus and use it in API. 2019-08-16 09:49:27 +02:00
2832dd8b6f Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-08-15 15:57:40 +02:00
388efbbd73 Add cascade deletion of jobs and corpora on user delete. 2019-08-15 15:57:27 +02:00
bccf661957 Add new admin blueprint with new user delete feature. Reorganize templates etc. 2019-08-15 15:56:53 +02:00
99614a56a9 Add switch for admins to get all jobs (of all users) 2019-08-15 13:33:15 +02:00
4ffb10fd11 Return 404 if requested ressource does not exist. 2019-08-15 12:09:00 +02:00
22f47e3213 Add information to README. 2019-08-15 12:03:16 +02:00
6bc1ef94dc Add api blueprint. 2019-08-15 12:02:50 +02:00
93330c0efb Remove api routes from main package. 2019-08-15 11:48:14 +02:00
47c3edeb7f Toggle paginations if one or less items are displayed. 2019-08-14 16:59:39 +02:00
ea399d2cdc Add api endpoints for testing. 2019-08-14 16:59:15 +02:00
b0c2f69568 Rename scheduler function 2019-08-13 14:27:02 +02:00
e3ceb19f7a Name docker client like mentioned in the api docs 2019-08-13 14:21:54 +02:00
db0c2532ad Use Flask-APScheduler. Move docker swarm logic to scheduler. 2019-08-13 14:10:50 +02:00
1fa9cbc586 pass job object instead of id. 2019-08-12 19:34:41 +02:00
a5687a3f1b Use scoped_session correctly. 2019-08-12 19:34:24 +02:00
faf54e57fa Use APScheduler to handle job execution. 2019-08-12 17:03:12 +02:00
344ba1a8e2 Add download helper for dev process 2019-08-12 10:37:02 +02:00
fa2827608c Add download helper for dev process. 2019-08-12 10:36:51 +02:00
e00d34ef81 Only use one file list. 2019-08-12 09:51:32 +02:00
759a29362c Increase desription length for corpora. 2019-08-12 08:57:21 +02:00
ad8a8a4696 use job id for swarm run instead of job object 2019-08-11 19:01:19 +02:00
a302d08405 Add infos to job model and show them on the job info pages. 2019-08-09 15:59:53 +02:00
359baf0297 Change job template. 2019-08-09 11:49:09 +02:00
a82b7292ed Change job model. 2019-08-09 11:48:43 +02:00
50273ea4d1 Use links as list items for corpora and jobs. Add colors for service types. Link jobs to job page. 2019-08-09 10:16:31 +02:00
136f2ee2b2 Add description for nlp (for now only german). 2019-08-09 10:15:51 +02:00
4d99c52983 Only use job_id as service name. 2019-08-09 09:13:24 +02:00
1d6f1a8933 Update ressource requirements. 2019-08-09 09:13:12 +02:00
388e0433fd Add searchable User table. 2019-08-08 16:06:41 +02:00
14b64f86ba Add pagination and search to dashboard. 2019-08-08 15:28:15 +02:00
f415d4ea9c Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-08-08 14:28:27 +02:00
12d9ac8727 Add list.js to base template. 2019-08-08 14:28:16 +02:00
a52ed253c0 Remove Jaas add Python 3.5 2019-08-08 13:46:55 +02:00
01c5b3603e Remove job from database if an error occurs. Remove job object from session before thread starts. 2019-08-08 12:06:01 +02:00
202ade92e9 Set name for swarm service. 2019-08-08 12:01:55 +02:00
75b587e693 Remove redundant add to session. 2019-08-07 16:03:24 +02:00
c291fac22f Add dummy text to job section 2019-08-07 15:53:37 +02:00
6f8cef26e4 Map task states to job status. Colorize status badges on dashboard. 2019-08-07 15:01:37 +02:00
267f86d342 Remove debug message. 2019-08-07 14:36:19 +02:00
3de48946b9 Update job database entries on status change. 2019-08-07 14:35:33 +02:00
9d0d386942 Fix codestyle. 2019-08-07 14:35:01 +02:00
0461139bb7 Remove unused import. 2019-08-07 14:34:45 +02:00
e52629dd7e Remove unused import. 2019-08-07 10:22:30 +02:00
0ac3ed3a29 Set 'submitted' as initial job status value. 2019-08-07 10:21:04 +02:00
ed2d1abd8c Remove debug output. 2019-08-07 10:06:28 +02:00
ce051e8024 Remove dummy lists from Dashboard, show actual corpus and job list instead. 2019-08-07 09:40:18 +02:00
3c344bf023 Remove debug output. 2019-08-06 17:05:55 +02:00
f2eaa61f3c Add link to nlp service. 2019-08-06 17:04:53 +02:00
d860a5d279 Set backrefs correctly. 2019-08-06 17:04:38 +02:00
1e1ef8f966 Fix 3/3 2019-08-06 16:09:41 +02:00
0fa106fd84 Fix 2/3 2019-08-06 16:09:02 +02:00
601b32a788 Fix 1/3 2019-08-06 16:08:38 +02:00
511b5fa7d3 Add migrations to .gitignore. 2019-08-06 16:05:44 +02:00
59016be061 Fix code for creation_date in corpus object. 2019-08-06 15:46:23 +02:00
b255f3bb4a rename createon.data to creaton.date 2019-08-06 15:41:07 +02:00
65becc1187 Add creation_data to corpus. 2019-08-06 15:39:09 +02:00
32c6b9ab8a Change path for corpora. 2019-08-06 14:56:41 +02:00
36753c3b51 Remove unused import. 2019-08-06 14:54:44 +02:00
5c1fd82451 Migrations 2019-08-06 14:54:06 +02:00
338e4111c2 Add user id to path. 2019-08-06 14:54:00 +02:00
2ed63d9a5f Add migrations. 2019-08-06 14:28:19 +02:00
6f5bf674c6 Handle job creation with the new Job class. 2019-08-06 14:27:41 +02:00
175dbceac6 Add creation and registration dates. 2019-08-06 14:26:22 +02:00
5a67164dbe Add corpus to database after creation. 2019-08-06 13:25:27 +02:00
4ec0acc080 Make Corpus model available in flask shell. 2019-08-06 13:25:10 +02:00
46b8550c65 Add corpus model. 2019-08-06 12:06:41 +02:00
ebba2913f8 Add migration script for corpora table. 2019-08-06 12:06:27 +02:00
525d53a906 Redesign db models. 2019-08-06 11:47:04 +02:00
34b87c23a7 Add corpus page. 2019-08-05 16:46:34 +02:00
e30d3fc048 Remove old migrations for new Initial db commit. 2019-08-05 16:46:00 +02:00
94dcaa55a3 Add Job model. 2019-08-05 16:45:38 +02:00
8763e0f4db Add NLP template. Add Link to NLp template. 2019-08-05 15:36:18 +02:00
a3039e0529 Comment --keep_intermediates 2019-08-05 15:35:51 +02:00
1092312e6d Add NLP view. 2019-08-05 15:35:18 +02:00
ab688e290a Make swarm run more generic 2019-08-05 14:22:16 +02:00
602ef371f8 Fix path 2019-08-05 12:25:58 +02:00
f506a562cd Add version field for ocr job 2019-08-05 12:25:51 +02:00
a1be95ff68 Rename ocr job form and add nlp job form 2019-08-05 08:36:29 +02:00
1c98dc0104 Fix config key for storage path. 2019-08-05 08:36:11 +02:00
f2f62c64eb No double initialization for javascript powered elements. 2019-08-02 15:15:02 +02:00
1b166e83e6 Add buttons to create new corpora and jobs. 2019-08-02 14:48:27 +02:00
a49e862432 Add redirect for login page if the user is already loged in. 2019-08-02 13:30:43 +02:00
0de63e2b4b Add prototype vision for dashboard elements. 2019-08-02 13:25:54 +02:00
e55d4aafab Replace lorem ipsum with german short explaination. 2019-08-02 13:25:34 +02:00
e327f0c8bf Make the about page the index page. 2019-08-02 13:24:52 +02:00
d6f60e4267 Change environment variable name: OPAQUE_FILES -> OPAQUE_STORAGE 2019-08-02 13:23:26 +02:00
df7d618b2a Add file type validation 2019-08-01 14:01:22 +02:00
c958edbae1 Fix wrong offset for navbar elements. 2019-08-01 14:01:06 +02:00
64fb17f17e Only import once from wtforms 2019-08-01 13:49:24 +02:00
ce6ec4af58 Add validator to file upload in corpus creation. 2019-08-01 12:16:49 +02:00
3964fe5444 Allow multiple file upload and add title 2019-08-01 12:16:31 +02:00
716ebdfa7c Add create corpus form to dashboard. 2019-08-01 11:47:14 +02:00
a5b7ccaeb7 Update landing page. 2019-08-01 10:33:05 +02:00
bf00670784 Update job file path. 2019-08-01 10:32:21 +02:00
78040536f2 Add input options for ocr job creation. 2019-08-01 08:22:17 +02:00
009e188924 Save output in input folder. 2019-08-01 08:21:47 +02:00
9805a6be74 Add variable containing the path to upload directory. 2019-08-01 08:21:13 +02:00
a863e8f04f Change wording. 2019-07-31 09:10:37 +02:00
5c976199cd fixed navbar and new navigation entries for serivces (nlp and ocr) 2019-07-19 15:16:20 +02:00
273cff64ea Add Layout with lorem ipsum texts to ocr page. 2019-07-19 15:15:49 +02:00
de6efc3aac Change path to fit in the development swarm. 2019-07-19 15:15:28 +02:00
2d6805a990 Remove debug information. 2019-07-19 14:42:02 +02:00
cd79061579 Don't use jaas as if offers not enough configuration possibilities. 2019-07-19 13:28:57 +02:00
7b185d929e Move ocr job to extra package. 2019-07-19 13:28:17 +02:00
724d2a47cd Delete docs, it got replaced by wiki pages. 2019-07-17 14:00:34 +02:00
da6502d665 Add dependencies to README. 2019-07-17 13:49:16 +02:00
94c51acc99 Edit layout of the about page. 2019-07-17 13:36:03 +02:00
7db27020c7 Add Docker Swarm interface. 2019-07-17 13:34:20 +02:00
735802d88e Remove options to change username and email. 2019-07-12 17:23:11 +02:00
6d1be8f391 Change colors for error messages in forms. 2019-07-12 17:22:15 +02:00
9096cc4028 Remove test message. 2019-07-12 17:21:38 +02:00
4377568fd4 Add about page. 2019-07-12 17:21:13 +02:00
6bbfc589af Add new navigation entries. 2019-07-12 17:21:04 +02:00
30f405bb88 Add some docstrings 2019-07-11 15:43:48 +02:00
4918d185c2 Add some docstrings to models.py 2019-07-11 15:33:48 +02:00
c5422638a6 Remove first APScheduler tests. 2019-07-11 15:22:33 +02:00
0266886874 Remove merge marker. 2019-07-11 09:41:33 +02:00
b82ab23079 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-11 09:40:37 +02:00
bb2b0294fa Add rudimentary job handler 2019-07-11 09:40:12 +02:00
e6446834b4 Add rudimentary job handler 2019-07-11 09:35:55 +02:00
c2139500e2 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-10 14:37:37 +02:00
ad0c754b8b Add scheduler output skeleton. 2019-07-10 14:37:31 +02:00
ef25ba7545 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-10 14:36:33 +02:00
4ec9e2ff41 Add flask_table for admin view 2019-07-10 14:36:31 +02:00
eef9ec9b37 Add title as context and remove wrong title from templates 2019-07-10 14:35:37 +02:00
d41702bc51 Add scheduler test. 2019-07-10 14:20:22 +02:00
9679ef80c8 Add scheduler. 2019-07-10 13:41:48 +02:00
0158f5bedc Add APSchedular requirement. 2019-07-10 11:26:05 +02:00
a978ea5782 Remove link from user data in sidenav. 2019-07-10 10:56:04 +02:00
d7de198302 Add migrations 2019-07-10 10:48:11 +02:00
7c1496a4df Add new opaque logo icon and sidenav header. 2019-07-10 10:09:11 +02:00
a3ca0f27ac Use new common Layout for all pages now. 2019-07-10 09:47:29 +02:00
8405f54868 Use DFG instead SFB logo in footer. 2019-07-10 09:47:04 +02:00
8a509ecc63 Layout update 2019-07-10 08:56:49 +02:00
93b67cb297 Update page layout. 2019-07-09 16:59:04 +02:00
c15ac55fe3 Delete data_dev.sqlite 2019-07-09 16:19:27 +02:00
2fb092670b Migrate 2019-07-09 16:18:41 +02:00
678ac670ea Update settings page. 2019-07-09 16:18:21 +02:00
8458271a5c Add some tests 2019-07-09 15:41:28 +02:00
79cccd36ee Add Roles and Permission models so that only admins can access /admin 2019-07-09 15:41:16 +02:00
66d9ab8a93 Add custom error pages 2019-07-09 15:39:28 +02:00
26016458dd Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-09 15:38:53 +02:00
2f19052fcb Add new users 2019-07-09 15:38:41 +02:00
1db630b74a Add missing title into render_template 2019-07-09 15:38:21 +02:00
7f76e7884f Rename account form. 2019-07-09 14:53:17 +02:00
3187cca1af Implement cards the correct way. card-action outside of card-content 2019-07-09 14:13:56 +02:00
b85c1e96a1 Delete data_dev.sqlite 2019-07-09 13:43:20 +02:00
37765c755a Rename profile to account and enable password change. 2019-07-09 13:40:33 +02:00
de2aacc2de Add auth.profile view. 2019-07-09 13:27:24 +02:00
dec9efa074 Add automatic confirmation mail after changing e-mail adress. 2019-07-09 13:27:13 +02:00
640bcc2bf1 Add dev database to .gitignore. 2019-07-09 13:20:15 +02:00
c66c28162e Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-09 13:19:11 +02:00
43be1045d9 Fix static exception for unconfirmed user requests. 2019-07-09 13:18:46 +02:00
da1ef0e1f1 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-09 11:54:58 +02:00
54181f21a2 Add new user 2019-07-09 11:54:29 +02:00
a3efdc87cc Add change profile page. 2019-07-09 11:53:40 +02:00
b311fcb9de Enable login by username. 2019-07-09 11:00:41 +02:00
ad6201b560 confirm pjentsch account 2019-07-09 11:00:25 +02:00
586bf8af37 Change maind.index to main.index 2019-07-09 10:17:58 +02:00
1ec93fa7d6 Add message to confirm account for unconfirmed users 2019-07-09 10:09:35 +02:00
68e1607af3 Change test user password 2019-07-08 16:23:52 +02:00
1936e1493d Add new password icon for login template 2019-07-08 16:09:28 +02:00
3b6c9f22dd Add email confirmation for nuew users 2019-07-08 16:09:00 +02:00
8c121a63de Add .j2 suffix for template files 2019-07-08 16:08:34 +02:00
ce5179e10d Add .j2 suffix for template files 2019-07-08 16:07:46 +02:00
5069646b96 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-08 16:07:15 +02:00
f64b6104fe Add test accounts for email confirmation 2019-07-08 15:59:54 +02:00
11a3e7551f Add email confirmation 2019-07-08 15:59:15 +02:00
ae11e04c6c Add email confirmation 2019-07-08 15:58:46 +02:00
49222eeeef Add password reset functionality. 2019-07-08 15:13:32 +02:00
30e82088b4 Add testing for register 2019-07-08 14:55:36 +02:00
bc9f64ba90 Link password reset request page to log in screen. 2019-07-08 14:14:35 +02:00
59ad0c1668 Fix wrong merge. 2019-07-08 14:08:11 +02:00
d1d5e5f114 Add registration form, view, template 2019-07-08 14:06:35 +02:00
999e51bcc5 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-08 14:05:04 +02:00
9cca7de035 Add indentation 2019-07-08 14:04:02 +02:00
1a973bfbc6 Add page for password reset. 2019-07-08 13:56:09 +02:00
4ef5b480b1 Add reset token generation functionality in User class. 2019-07-08 13:55:56 +02:00
ed921b68d7 Change default values for e-mail in config. 2019-07-08 13:55:13 +02:00
da46ff0811 Change .secretsenv to .env. 2019-07-08 13:53:51 +02:00
686b621d54 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-08 11:29:17 +02:00
bd49bb4dae Add e-mail code. 2019-07-08 11:29:11 +02:00
511ccf96f6 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-08 11:27:56 +02:00
7adaf3f22d Add register view 2019-07-08 11:27:54 +02:00
2e1aa8cf31 Remove e-mail configuration from .flaskenv. 2019-07-08 11:27:10 +02:00
baf7c1192b Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-08 11:10:35 +02:00
073b0e0e05 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-08 11:10:09 +02:00
5c0ba9f7d8 Add title as template param. 2019-07-08 11:10:09 +02:00
7a66e4a778 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-08 11:10:00 +02:00
0a9227c7c9 Return template for GET requests. 2019-07-08 11:08:49 +02:00
98fcfe1e7d Add registrationForm 2019-07-08 11:08:24 +02:00
dd4fcdfe20 Add password reset request view. 2019-07-08 11:04:52 +02:00
4076e44194 Add e-mail templates for password reset request. 2019-07-08 11:00:49 +02:00
8afb6404e7 Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development 2019-07-08 10:54:42 +02:00
311498415b Add form for password reset request. 2019-07-08 10:54:29 +02:00
3e8ce1e719 Add Flask-Mail to app instance. 2019-07-08 10:53:54 +02:00
d6ec00d9cf Add e-mail related configurations. 2019-07-08 10:53:14 +02:00
8e753be8e8 Add Flask-Mail for e-mail support. 2019-07-08 10:52:46 +02:00
adec45989c Add basic and user model testing. 2019-07-08 10:52:36 +02:00
8e86e0a0e9 Positioning 2019-07-08 10:16:23 +02:00
296db67188 Add remember me! 2019-07-08 10:07:26 +02:00
3b04addc17 Implement login form in template and add support for flash messages via a toast. 2019-07-08 09:05:59 +02:00
b6a67fcd4d Merge base templates. Add database support. Add blueprint for main. 2019-07-05 14:47:35 +02:00
f6b2dd3282 Add example image for server activities. 2019-07-05 13:55:35 +02:00
ed279deede Remove unused code. 2019-07-05 13:55:14 +02:00
228bb5ee19 Add index template and change some ids to defaults like the doc suggests. 2019-07-05 13:54:08 +02:00
ab9e50b46b Fix slidenav-trigger target 2019-07-05 11:06:37 +02:00
96960a9e25 Create and use module templates for different page sections. 2019-07-05 11:04:45 +02:00
c27408ef78 Move material icons. 2019-07-05 11:03:48 +02:00
4eb7a7b27b Add title parameter. 2019-07-05 11:02:56 +02:00
3d0fb27147 Add documentation and fixes for sidenav-fixed usage. 2019-07-05 11:02:24 +02:00
7450770518 Add picture with background color white 2019-07-04 16:07:19 +02:00
fed711d23b Add login and register templates and routes 2019-07-04 15:17:51 +02:00
e127e1e5c4 Add navigation structure. 2019-07-04 14:59:23 +02:00
05cbf1fed5 Add row structure to base template 2019-07-04 12:23:09 +02:00
fa4fa57a89 Change block name from body to page_content 2019-07-04 12:18:49 +02:00
f586d762e3 Remove footer 2019-07-04 12:01:00 +02:00
e3d4fa4d90 Add modularity to base 2019-07-04 11:59:52 +02:00
b5b6a1b9a7 Add login template 2019-07-04 11:59:24 +02:00
5f75019c8e Add favicon 2019-07-04 11:58:46 +02:00
f4fcba887d Add title if condition 2019-07-04 11:36:23 +02:00
b93bbcb756 Add auth and main lueprint structure 2019-07-04 11:24:06 +02:00
ea8250c805 Change href links to url_for() 2019-07-04 11:11:07 +02:00
8410df3231 Add material design icon font 2019-07-04 11:10:38 +02:00
bc5ec9695f Add materializecss. 2019-07-04 10:40:23 +02:00
96fc8f4064 Load config from 'config.py'. 2019-07-03 15:40:45 +02:00
f6e7b44863 Add SECRET_KEY configuration. 2019-07-03 15:40:09 +02:00
06bfb04bcc Add '.secretenv' to gitignore. 2019-07-03 15:32:58 +02:00
6b594bb7d9 Add requirements needed in the future. 2019-07-03 15:30:22 +02:00
b49fade1a2 Add folders template and static 2019-07-03 12:23:58 +02:00
da8ab512a9 Create project skeleton. 2019-07-03 10:31:23 +02:00
af4edbdb57 Update docs/platform_basics_brainstorming_2019-04-17.md 2019-07-02 15:21:33 +02:00
b8b9f3bdce Update docs/platform_basics_brainstorming_2019-04-17.md 2019-07-02 14:00:19 +02:00
856cb257a1 Update docs/platform_basics_brainstorming_2019-04-17.md 2019-07-01 15:39:37 +02:00
96b1c24aca Update docs/platform_basics_brainstorming_2019-04-17.md 2019-07-01 14:53:33 +02:00
cdd16f8401 Update docs/platform_basics_brainstorming_2019-04-17.md 2019-07-01 14:18:35 +02:00
345 changed files with 25534 additions and 24637 deletions

12
.dockerignore Normal file
View File

@ -0,0 +1,12 @@
# Exclude everything
*
# Include what we need
!app
!migrations
!tests
!.flaskenv
!boot.sh
!config.py
!nopaque.py
!requirements.txt

204
.env.tpl Normal file
View File

@ -0,0 +1,204 @@
################################################################################
# Docker #
################################################################################
# DEFAULT: ./data
# NOTE: Use `.` as <project-basedir>
# HOST_DATA_DIR=
# Example: 1000
# HINT: Use this bash command `id -u`
HOST_UID=
# Example: 1000
# HINT: Use this bash command `id -g`
HOST_GID=
# Example: 999
# HINT: Use this bash command `getent group docker | cut -d: -f3`
HOST_DOCKER_GID=
# DEFAULT: ./logs
# NOTES: Use `.` as <project-basedir>
# HOST_LOG_DIR=
# DEFAULT: nopaque_default
# DOCKER_NETWORK_NAME=
################################################################################
# Flask #
# https://flask.palletsprojects.com/en/1.1.x/config/ #
################################################################################
# CHOOSE ONE: http, https
# DEFAULT: http
# PREFERRED_URL_SCHEME=
# DEFAULT: hard to guess string
# HINT: Use this bash command `python -c "import uuid; print(uuid.uuid4().hex)"`
# SECRET_KEY=
# DEFAULT: localhost:5000
# Example: nopaque.example.com/nopaque.example.com:5000
# HINT: If your instance is publicly available on a different Port then 80/443,
# you will have to add this to the server name
# SERVER_NAME=
# CHOOSE ONE: False, True
# DEFAULT: False
# HINT: Set to true if you redirect http to https
# SESSION_COOKIE_SECURE=
################################################################################
# Flask-Assets #
# https://webassets.readthedocs.io/en/latest/ #
################################################################################
# CHOOSE ONE: False, True
# DEFAULT: False
# ASSETS_DEBUG=
################################################################################
# Flask-Hashids #
# https://github.com/Pevtrick/Flask-Hashids #
################################################################################
# DEFAULT: 16
# HASHIDS_MIN_LENGTH=
# NOTE: Use this bash command `python -c "import uuid; print(uuid.uuid4().hex)"`
# It is strongly recommended that this is NEVER the same as the SECRET_KEY
HASHIDS_SALT=
################################################################################
# Flask-Login #
# https://flask-login.readthedocs.io/en/latest/ #
################################################################################
# CHOOSE ONE: False, True
# DEFAULT: False
# HINT: Set to true if you redirect http to https
# REMEMBER_COOKIE_SECURE=
################################################################################
# Flask-Mail #
# https://pythonhosted.org/Flask-Mail/ #
################################################################################
# EXAMPLE: nopaque Admin <nopaque@example.com>
MAIL_DEFAULT_SENDER=
MAIL_PASSWORD=
# EXAMPLE: smtp.example.com
MAIL_SERVER=
# EXAMPLE: 587
MAIL_PORT=
# CHOOSE ONE: False, True
# DEFAULT: False
# MAIL_USE_SSL=
# CHOOSE ONE: False, True
# DEFAULT: False
# MAIL_USE_TLS=
# EXAMPLE: nopaque@example.com
MAIL_USERNAME=
################################################################################
# Flask-SQLAlchemy #
# https://flask-sqlalchemy.palletsprojects.com/en/2.x/config/ #
################################################################################
# DEFAULT: 'sqlite:///<nopaque-basedir>/data.sqlite'
# NOTE: Use `.` as <nopaque-basedir>,
# Don't use a SQLite database when using Docker
# SQLALCHEMY_DATABASE_URI=
################################################################################
# nopaque #
################################################################################
# An account is registered with this email adress gets automatically assigned
# the administrator role.
# EXAMPLE: admin.nopaque@example.com
NOPAQUE_ADMIN=
# DEFAULT: /mnt/nopaque
# NOTE: This must be a network share and it must be available on all Docker
# Swarm nodes
# NOPAQUE_DATA_DIR=
# CHOOSE ONE: False, True
# DEFAULT: True
# NOPAQUE_IS_PRIMARY_INSTANCE=
# transport://[userid:password]@hostname[:port]/[virtual_host]
NOPAQUE_SOCKETIO_MESSAGE_QUEUE_URI=
# NOTE: Get these from the nopaque development team
NOPAQUE_DOCKER_REGISTRY_USERNAME=
NOPAQUE_DOCKER_REGISTRY_PASSWORD=
# DEFAULT: %Y-%m-%d %H:%M:%S
# NOPAQUE_LOG_DATE_FORMAT=
# DEFAULT: [%(asctime)s] %(levelname)s in %(pathname)s (function: %(funcName)s, line: %(lineno)d): %(message)s
# NOPAQUE_LOG_FORMAT=
# DEFAULT: INFO
# CHOOSE ONE: CRITICAL, ERROR, WARNING, INFO, DEBUG
# NOPAQUE_LOG_LEVEL=
# CHOOSE ONE: False, True
# DEFAULT: True
# NOPAQUE_LOG_FILE_ENABLED=
# DEFAULT: <nopaque-basedir>/logs
# NOTE: Use `.` as <nopaque-basedir>
# NOPAQUE_LOG_FILE_DIR=
# DEFAULT: NOPAQUE_LOG_LEVEL
# CHOOSE ONE: CRITICAL, ERROR, WARNING, INFO, DEBUG
# NOPAQUE_LOG_FILE_LEVEL=
# CHOOSE ONE: False, True
# DEFAULT: False
# NOPAQUE_LOG_STDERR_ENABLED=
# CHOOSE ONE: CRITICAL, ERROR, WARNING, INFO, DEBUG
# DEFAULT: NOPAQUE_LOG_LEVEL
# NOPAQUE_LOG_STDERR_LEVEL=
# CHOOSE ONE: False, True
# DEFAULT: False
# HINT: Set this to True only if you are using a proxy in front of nopaque
# NOPAQUE_PROXY_FIX_ENABLED=
# DEFAULT: 0
# Number of values to trust for X-Forwarded-For
# NOPAQUE_PROXY_FIX_X_FOR=
# DEFAULT: 0
# Number of values to trust for X-Forwarded-Host
# NOPAQUE_PROXY_FIX_X_HOST=
# DEFAULT: 0
# Number of values to trust for X-Forwarded-Port
# NOPAQUE_PROXY_FIX_X_PORT=
# DEFAULT: 0
# Number of values to trust for X-Forwarded-Prefix
# NOPAQUE_PROXY_FIX_X_PREFIX=
# DEFAULT: 0
# Number of values to trust for X-Forwarded-Proto
# NOPAQUE_PROXY_FIX_X_PROTO=
# CHOOSE ONE: False, True
# DEFAULT: False
# NOPAQUE_TRANSKRIBUS_ENABLED=
# READ-COOP account data: https://readcoop.eu/
# NOPAQUE_READCOOP_USERNAME=
# NOPAQUE_READCOOP_PASSWORD=

1
.flaskenv Normal file
View File

@ -0,0 +1 @@
FLASK_APP=nopaque.py

170
.gitignore vendored Normal file
View File

@ -0,0 +1,170 @@
# nopaque specifics
app/static/gen/
data/
docker-compose.override.yml
logs/
!logs/dummy
*.env
*.pjentsch-testing
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"recommendations": [
"samuelcolvin.jinjahtml",
"ms-azuretools.vscode-docker",
"ms-python.python"
]
}

23
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,23 @@
{
"editor.rulers": [79],
"files.insertFinalNewline": true,
"python.terminal.activateEnvironment": false,
"[css]": {
"editor.tabSize": 2
},
"[scss]": {
"editor.tabSize": 2
},
"[html]": {
"editor.tabSize": 2
},
"[javascript]": {
"editor.tabSize": 2
},
"[jinja-html]": {
"editor.tabSize": 2
},
"[jinja-js]": {
"editor.tabSize": 2
}
}

50
Dockerfile Normal file
View File

@ -0,0 +1,50 @@
FROM python:3.8.10-slim-buster
LABEL authors="Patrick Jentsch <p.jentsch@uni-bielefeld.de>"
ARG DOCKER_GID
ARG UID
ARG GID
ENV LANG="C.UTF-8"
ENV PYTHONDONTWRITEBYTECODE="1"
ENV PYTHONUNBUFFERED="1"
RUN apt-get update \
&& apt-get install --no-install-recommends --yes \
build-essential \
libpq-dev \
&& rm --recursive /var/lib/apt/lists/*
RUN groupadd --gid "${DOCKER_GID}" docker \
&& groupadd --gid "${GID}" nopaque \
&& useradd --create-home --gid nopaque --groups "${DOCKER_GID}" --no-log-init --uid "${UID}" nopaque
USER nopaque
WORKDIR /home/nopaque
ENV PYTHON3_VENV_PATH="/home/nopaque/venv"
RUN python3 -m venv "${PYTHON3_VENV_PATH}"
ENV PATH="${PYTHON3_VENV_PATH}/bin:${PATH}"
COPY --chown=nopaque:nopaque requirements.txt .
RUN python3 -m pip install --requirement requirements.txt \
&& rm requirements.txt
COPY --chown=nopaque:nopaque app app
COPY --chown=nopaque:nopaque migrations migrations
COPY --chown=nopaque:nopaque tests tests
COPY --chown=nopaque:nopaque .flaskenv boot.sh config.py nopaque.py ./
EXPOSE 5000
ENTRYPOINT ["./boot.sh"]

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Bielefeld University - CRC 1288 - INF
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

62
README.md Normal file
View File

@ -0,0 +1,62 @@
# nopaque
nopaque bundles various tools and services that provide humanities scholars with DH methods and thus can support their various individual research processes. Using nopaque, researchers can subject digitized sources to Optical Character Recognition (OCR). The resulting text files can then be used as a data basis for Natural Language Processing (NLP). The texts are automatically subjected to various linguistic annotations. The data processed via NLP can then be summarized in the web application as corpora and analyzed by means of an information retrieval system through complex search queries. The range of functions of the web application will be successively extended according to the needs of the researchers.
## Prerequisites and requirements
1. Install docker for your system. Following the official instructions.
2. Install docker-compose. Following the official instructions.
## Configuration and startup
### **Create Docker swarm**
The generated computational workload is handled by a [Docker](https://docs.docker.com/) swarm. A swarm is a group of machines that are running Docker and joined into a cluster. It consists out of two different kinds of members, manager and worker nodes. The swarm setup process is described best in the [Docker documentation](https://docs.docker.com/engine/swarm/swarm-tutorial/).
### **Create network storage**
A shared network space is necessary so that all swarm members have access to all the data. To achieve this a [samba](https://www.samba.org/) share can be used.
You can create a samba share by using [this](https://hub.docker.com/r/dperson/samba/) Docker image.
``` bash
# Mount the Samba share on all swarm nodes (managers and workers)
username@hostname:~$ sudo mkdir /mnt/nopaque
username@hostname:~$ sudo mount --types cifs --options gid=${USER},password=nopaque,uid=${USER},user=nopaque,vers=3.0 //<SAMBA-SERVER-IP>/<SAMBA-SHARE-NAME> /mnt/nopaque
```
### **Download, configure and build nopaque**
``` bash
# Clone the nopaque repository
username@hostname:~$ git clone https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
# Create data directories
username@hostname:~$ mkdir data/{db,logs,mq}
username@hostname:~$ cp db.env.tpl db.env
username@hostname:~$ cp .env.tpl .env
# Fill out the variables within these files.
username@hostname:~$ <YOUR EDITOR> db.env
username@hostname:~$ <YOUR EDITOR> .env
# Create docker-compose.override.yml file
username@hostname:~$ touch docker-compose.override.yml
# Tweak the docker-compose.override.yml to satisfy your needs. (You can find examples inside the docker-compose directory)
username@hostname:~$ <YOUR EDITOR> docker-compose.override.yml
# Build docker images
username@hostname:~$ docker-compose build
```
### Start your instance
``` bash
# For background execution add the -d flag
docker-compose up
# To scale your app use the following command after starting it normally
docker-compose \
-f docker-compose.yml \
-f docker-compose.override.yml \
-f docker-compose.scale.yml \
up \
-d \
--no-recreate \
--scale nopaque=<NUM_INSTANCES>
```

View File

@ -0,0 +1,231 @@
- title: 'Catalan'
description: 'Catalan pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/ca_core_news_md-3.2.0/ca_core_news_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/ca_core_news_md-3.2.0'
publishing_year: 2021
pipeline_name: 'ca_core_news_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'German'
description: 'German pipeline optimized for CPU. Components: tok2vec, tagger, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.2.0/de_core_news_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/de_core_news_md-3.2.0'
publishing_year: 2021
pipeline_name: 'de_core_news_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'Greek'
description: 'Greek pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/el_core_news_md-3.2.0/el_core_news_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/el_core_news_md-3.2.0'
publishing_year: 2021
pipeline_name: 'el_core_news_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'English'
description: 'English pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.2.0/en_core_web_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/en_core_web_md-3.2.0'
publishing_year: 2021
pipeline_name: 'en_core_web_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'Spanish'
description: 'Spanish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/es_core_news_md-3.2.0/es_core_news_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/es_core_news_md-3.2.0'
publishing_year: 2021
pipeline_name: 'es_core_news_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'French'
description: 'French pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/fr_core_news_md-3.2.0/fr_core_news_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/fr_core_news_md-3.2.0'
publishing_year: 2021
pipeline_name: 'fr_core_news_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'Italian'
description: 'Italian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/it_core_news_md-3.2.0/it_core_news_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/it_core_news_md-3.2.0'
publishing_year: 2021
pipeline_name: 'it_core_news_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'Polish'
description: 'Polish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/pl_core_news_md-3.2.0/pl_core_news_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/pl_core_news_md-3.2.0'
publishing_year: 2021
pipeline_name: 'pl_core_news_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'Russian'
description: 'Russian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/ru_core_news_md-3.2.0/ru_core_news_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/ru_core_news_md-3.2.0'
publishing_year: 2021
pipeline_name: 'ru_core_news_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'Chinese'
description: 'Chinese pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler.'
url: 'https://github.com/explosion/spacy-models/releases/download/zh_core_web_md-3.2.0/zh_core_web_md-3.2.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/zh_core_web_md-3.2.0'
publishing_year: 2021
pipeline_name: 'zh_core_web_md'
version: '3.2.0'
compatible_service_versions:
- '0.1.0'
- title: 'Catalan'
description: 'Catalan pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/ca_core_news_md-3.4.0/ca_core_news_md-3.4.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/ca_core_news_md-3.4.0'
publishing_year: 2022
pipeline_name: 'ca_core_news_md'
version: '3.4.0'
compatible_service_versions:
- '0.1.1'
- '0.1.2'
- title: 'German'
description: 'German pipeline optimized for CPU. Components: tok2vec, tagger, morphologizer, parser, lemmatizer (trainable_lemmatizer), senter, ner.'
url: 'https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.4.0/de_core_news_md-3.4.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/de_core_news_md-3.4.0'
publishing_year: 2022
pipeline_name: 'de_core_news_md'
version: '3.4.0'
compatible_service_versions:
- '0.1.1'
- '0.1.2'
- title: 'Greek'
description: 'Greek pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, lemmatizer (trainable_lemmatizer), senter, ner, attribute_ruler.'
url: 'https://github.com/explosion/spacy-models/releases/download/el_core_news_md-3.4.0/el_core_news_md-3.4.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/el_core_news_md-3.4.0'
publishing_year: 2022
pipeline_name: 'el_core_news_md'
version: '3.4.0'
compatible_service_versions:
- '0.1.1'
- '0.1.2'
- title: 'English'
description: 'English pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.4.1/en_core_web_md-3.4.1.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/en_core_web_md-3.4.1'
publishing_year: 2022
pipeline_name: 'en_core_web_md'
version: '3.4.1'
compatible_service_versions:
- '0.1.1'
- '0.1.2'
- title: 'Spanish'
description: 'Spanish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/es_core_news_md-3.4.0/es_core_news_md-3.4.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/es_core_news_md-3.4.0'
publishing_year: 2022
pipeline_name: 'es_core_news_md'
version: '3.4.0'
compatible_service_versions:
- '0.1.1'
- '0.1.2'
- title: 'French'
description: 'French pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/fr_core_news_md-3.4.0/fr_core_news_md-3.4.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/fr_core_news_md-3.4.0'
publishing_year: 2022
pipeline_name: 'fr_core_news_md'
version: '3.4.0'
compatible_service_versions:
- '0.1.1'
- '0.1.2'
- title: 'Italian'
description: 'Italian pipeline optimized for CPU. Components: tok2vec, morphologizer, tagger, parser, lemmatizer (trainable_lemmatizer), senter, ner'
url: 'https://github.com/explosion/spacy-models/releases/download/it_core_news_md-3.4.0/it_core_news_md-3.4.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/it_core_news_md-3.4.0'
publishing_year: 2022
pipeline_name: 'it_core_news_md'
version: '3.4.0'
compatible_service_versions:
- '0.1.1'
- '0.1.2'
- title: 'Polish'
description: 'Polish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, lemmatizer (trainable_lemmatizer), tagger, senter, ner.'
url: 'https://github.com/explosion/spacy-models/releases/download/pl_core_news_md-3.4.0/pl_core_news_md-3.4.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/pl_core_news_md-3.4.0'
publishing_year: 2022
pipeline_name: 'pl_core_news_md'
version: '3.4.0'
compatible_service_versions:
- '0.1.1'
- '0.1.2'
- title: 'Russian'
description: 'Russian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
url: 'https://github.com/explosion/spacy-models/releases/download/ru_core_news_md-3.4.0/ru_core_news_md-3.4.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/ru_core_news_md-3.4.0'
publishing_year: 2022
pipeline_name: 'ru_core_news_md'
version: '3.4.0'
compatible_service_versions:
- '0.1.1'
- '0.1.2'
- title: 'Chinese'
description: 'Chinese pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler.'
url: 'https://github.com/explosion/spacy-models/releases/download/zh_core_web_md-3.4.0/zh_core_web_md-3.4.0.tar.gz'
publisher: 'Explosion'
publisher_url: 'https://github.com/explosion'
publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/zh_core_web_md-3.4.0'
publishing_year: 2022
pipeline_name: 'zh_core_web_md'
version: '3.4.0'
compatible_service_versions:
- '0.1.1'
- '0.1.2'

File diff suppressed because it is too large Load Diff

103
app/__init__.py Normal file
View File

@ -0,0 +1,103 @@
from apifairy import APIFairy
from config import Config
from docker import DockerClient
from flask import Flask
from flask_apscheduler import APScheduler
from flask_assets import Environment
from flask_breadcrumbs import Breadcrumbs, default_breadcrumb_root
from flask_login import LoginManager
from flask_mail import Mail
from flask_marshmallow import Marshmallow
from flask_migrate import Migrate
from flask_paranoid import Paranoid
from flask_socketio import SocketIO
from flask_sqlalchemy import SQLAlchemy
from flask_hashids import Hashids
from werkzeug.exceptions import HTTPException
apifairy = APIFairy()
assets = Environment()
breadcrumbs = Breadcrumbs()
db = SQLAlchemy()
docker_client = DockerClient()
hashids = Hashids()
login = LoginManager()
login.login_view = 'auth.login'
login.login_message = 'Please log in to access this page.'
ma = Marshmallow()
mail = Mail()
migrate = Migrate(compare_type=True)
paranoid = Paranoid()
paranoid.redirect_view = '/'
scheduler = APScheduler()
socketio = SocketIO()
def create_app(config: Config = Config) -> Flask:
''' Creates an initialized Flask (WSGI Application) object. '''
app = Flask(__name__)
app.config.from_object(config)
config.init_app(app)
docker_client.login(
app.config['NOPAQUE_DOCKER_REGISTRY_USERNAME'],
password=app.config['NOPAQUE_DOCKER_REGISTRY_PASSWORD'],
registry=app.config['NOPAQUE_DOCKER_REGISTRY']
)
apifairy.init_app(app)
assets.init_app(app)
breadcrumbs.init_app(app)
db.init_app(app)
hashids.init_app(app)
login.init_app(app)
ma.init_app(app)
mail.init_app(app)
migrate.init_app(app, db)
paranoid.init_app(app)
scheduler.init_app(app)
socketio.init_app(app, message_queue=app.config['NOPAQUE_SOCKETIO_MESSAGE_QUEUE_URI']) # noqa
from .admin import bp as admin_blueprint
default_breadcrumb_root(admin_blueprint, '.admin')
app.register_blueprint(admin_blueprint, url_prefix='/admin')
from .api import bp as api_blueprint
app.register_blueprint(api_blueprint, url_prefix='/api')
from .auth import bp as auth_blueprint
default_breadcrumb_root(auth_blueprint, '.')
app.register_blueprint(auth_blueprint)
from .contributions import bp as contributions_blueprint
default_breadcrumb_root(contributions_blueprint, '.contributions')
app.register_blueprint(contributions_blueprint, url_prefix='/contributions')
from .corpora import bp as corpora_blueprint
default_breadcrumb_root(corpora_blueprint, '.corpora')
app.register_blueprint(corpora_blueprint, cli_group='corpus', url_prefix='/corpora')
from .errors import bp as errors_bp
app.register_blueprint(errors_bp)
from .jobs import bp as jobs_blueprint
default_breadcrumb_root(jobs_blueprint, '.jobs')
app.register_blueprint(jobs_blueprint, url_prefix='/jobs')
from .main import bp as main_blueprint
default_breadcrumb_root(main_blueprint, '.')
app.register_blueprint(main_blueprint, cli_group=None)
from .services import bp as services_blueprint
default_breadcrumb_root(services_blueprint, '.services')
app.register_blueprint(services_blueprint, url_prefix='/services')
from .settings import bp as settings_blueprint
default_breadcrumb_root(settings_blueprint, '.settings')
app.register_blueprint(settings_blueprint, url_prefix='/settings')
from .users import bp as users_blueprint
default_breadcrumb_root(users_blueprint, '.users')
app.register_blueprint(users_blueprint, url_prefix='/users')
return app

20
app/admin/__init__.py Normal file
View File

@ -0,0 +1,20 @@
from flask import Blueprint
from flask_login import login_required
from app.decorators import admin_required
bp = Blueprint('admin', __name__)
@bp.before_request
@login_required
@admin_required
def before_request():
'''
Ensures that the routes in this package can be visited only by users with
administrator privileges (login_required and admin_required).
'''
pass
from . import json_routes, routes

16
app/admin/forms.py Normal file
View File

@ -0,0 +1,16 @@
from flask_wtf import FlaskForm
from wtforms import SelectField, SubmitField
from app.models import Role
class UpdateUserForm(FlaskForm):
role = SelectField('Role')
submit = SubmitField()
def __init__(self, user, *args, **kwargs):
if 'data' not in kwargs:
kwargs['data'] = {'role': user.role.hashid}
if 'prefix' not in kwargs:
kwargs['prefix'] = 'update-user-form'
super().__init__(*args, **kwargs)
self.role.choices = [(x.hashid, x.name) for x in Role.query.all()]

23
app/admin/json_routes.py Normal file
View File

@ -0,0 +1,23 @@
from flask import abort, request
from app import db
from app.decorators import content_negotiation
from app.models import User
from . import bp
@bp.route('/users/<hashid:user_id>/confirmed', methods=['PUT'])
@content_negotiation(consumes='application/json', produces='application/json')
def update_user_role(user_id):
confirmed = request.json
if not isinstance(confirmed, bool):
abort(400)
user = User.query.get_or_404(user_id)
user.confirmed = confirmed
db.session.commit()
response_data = {
'message': (
f'User "{user.username}" is now '
f'{"confirmed" if confirmed else "unconfirmed"}'
)
}
return response_data, 200

146
app/admin/routes.py Normal file
View File

@ -0,0 +1,146 @@
from flask import abort, flash, redirect, render_template, url_for
from flask_breadcrumbs import register_breadcrumb
from app import db, hashids
from app.models import Avatar, Corpus, Role, User
from app.users.settings.forms import (
UpdateAvatarForm,
UpdatePasswordForm,
UpdateNotificationsForm,
UpdateAccountInformationForm,
UpdateProfileInformationForm
)
from . import bp
from .forms import UpdateUserForm
from app.users.utils import (
user_endpoint_arguments_constructor as user_eac,
user_dynamic_list_constructor as user_dlc
)
@bp.route('')
@register_breadcrumb(bp, '.', '<i class="material-icons left">admin_panel_settings</i>Administration')
def admin():
return render_template(
'admin/admin.html.j2',
title='Administration'
)
@bp.route('/corpora')
@register_breadcrumb(bp, '.corpora', 'Corpora')
def corpora():
corpora = Corpus.query.all()
return render_template(
'admin/corpora.html.j2',
title='Corpora',
corpora=corpora
)
@bp.route('/users')
@register_breadcrumb(bp, '.users', '<i class="material-icons left">group</i>Users')
def users():
users = User.query.all()
return render_template(
'admin/users.html.j2',
title='Users',
users=users
)
@bp.route('/users/<hashid:user_id>')
@register_breadcrumb(bp, '.users.entity', '', dynamic_list_constructor=user_dlc)
def user(user_id):
user = User.query.get_or_404(user_id)
corpora = Corpus.query.filter(Corpus.user == user).all()
return render_template(
'admin/user.html.j2',
title=user.username,
user=user,
corpora=corpora
)
@bp.route('/users/<hashid:user_id>/settings', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.users.entity.settings', '<i class="material-icons left">settings</i>Settings')
def user_settings(user_id):
user = User.query.get_or_404(user_id)
update_account_information_form = UpdateAccountInformationForm(user)
update_profile_information_form = UpdateProfileInformationForm(user)
update_avatar_form = UpdateAvatarForm()
update_password_form = UpdatePasswordForm(user)
update_notifications_form = UpdateNotificationsForm(user)
update_user_form = UpdateUserForm(user)
# region handle update profile information form
if update_profile_information_form.submit.data and update_profile_information_form.validate():
user.about_me = update_profile_information_form.about_me.data
user.location = update_profile_information_form.location.data
user.organization = update_profile_information_form.organization.data
user.website = update_profile_information_form.website.data
user.full_name = update_profile_information_form.full_name.data
db.session.commit()
flash('Your changes have been saved')
return redirect(url_for('.user_settings', user_id=user.id))
# endregion handle update profile information form
# region handle update avatar form
if update_avatar_form.submit.data and update_avatar_form.validate():
try:
Avatar.create(
update_avatar_form.avatar.data,
user=user
)
except (AttributeError, OSError):
abort(500)
db.session.commit()
flash('Your changes have been saved')
return redirect(url_for('.user_settings', user_id=user.id))
# endregion handle update avatar form
# region handle update account information form
if update_account_information_form.submit.data and update_account_information_form.validate():
user.email = update_account_information_form.email.data
user.username = update_account_information_form.username.data
db.session.commit()
flash('Profile settings updated')
return redirect(url_for('.user_settings', user_id=user.id))
# endregion handle update account information form
# region handle update password form
if update_password_form.submit.data and update_password_form.validate():
user.password = update_password_form.new_password.data
db.session.commit()
flash('Your changes have been saved')
return redirect(url_for('.user_settings', user_id=user.id))
# endregion handle update password form
# region handle update notifications form
if update_notifications_form.submit.data and update_notifications_form.validate():
user.setting_job_status_mail_notification_level = \
update_notifications_form.job_status_mail_notification_level.data
db.session.commit()
flash('Your changes have been saved')
return redirect(url_for('.user_settings', user_id=user.id))
# endregion handle update notifications form
# region handle update user form
if update_user_form.submit.data and update_user_form.validate():
role_id = hashids.decode(update_user_form.role.data)
user.role = Role.query.get(role_id)
db.session.commit()
flash('Your changes have been saved')
return redirect(url_for('.user_settings', user_id=user.id))
# endregion handle update user form
return render_template(
'admin/user_settings.html.j2',
title='Settings',
update_account_information_form=update_account_information_form,
update_avatar_form=update_avatar_form,
update_notifications_form=update_notifications_form,
update_password_form=update_password_form,
update_profile_information_form=update_profile_information_form,
update_user_form=update_user_form,
user=user
)

14
app/api/__init__.py Normal file
View File

@ -0,0 +1,14 @@
from flask import Blueprint
bp = Blueprint('api', __name__)
from .tokens import bp as tokens_blueprint
bp.register_blueprint(tokens_blueprint, url_prefix='/tokens')
from .users import bp as users_blueprint
bp.register_blueprint(users_blueprint, url_prefix='/users')
from .jobs import bp as jobs_blueprint
bp.register_blueprint(jobs_blueprint, url_prefix='/jobs')

48
app/api/auth.py Normal file
View File

@ -0,0 +1,48 @@
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth
from werkzeug.exceptions import Forbidden, Unauthorized
from app.models import User
basic_auth = HTTPBasicAuth()
token_auth = HTTPTokenAuth()
auth_error_responses = {
Unauthorized.code: Unauthorized.description,
Forbidden.code: Forbidden.description
}
@basic_auth.verify_password
def verify_password(email_or_username, password):
user = User.query.filter((User.email == email_or_username.lower()) | (User.username == email_or_username)).first()
if user is not None and user.verify_password(password):
return user
@basic_auth.error_handler
def basic_auth_error(status):
error = (Forbidden if status == 403 else Unauthorized)()
return {
'code': error.code,
'message': error.name,
'description': error.description,
}, error.code, {'WWW-Authenticate': 'Form'}
@token_auth.verify_token
def verify_token(token):
return User.verify_access_token(token) if token else None
@token_auth.error_handler
def token_auth_error(status):
error = (Forbidden if status == 403 else Unauthorized)()
return {
'code': error.code,
'message': error.name,
'description': error.description,
}, error.code
@basic_auth.get_user_roles
@token_auth.get_user_roles
def get_user_roles(user):
return [user.role.name]

102
app/api/jobs.py Normal file
View File

@ -0,0 +1,102 @@
from apifairy import authenticate, response
from apifairy.decorators import body, other_responses
from flask import abort, Blueprint
from werkzeug.exceptions import InternalServerError
from app import db, hashids
from app.models import Job, JobInput, JobStatus, TesseractOCRPipelineModel
from .schemas import EmptySchema, JobSchema, SpaCyNLPPipelineJobSchema, TesseractOCRPipelineJobSchema, TesseractOCRPipelineModelSchema
from .auth import auth_error_responses, token_auth
bp = Blueprint('jobs', __name__)
job_schema = JobSchema()
jobs_schema = JobSchema(many=True)
spacy_nlp_pipeline_job_schema = SpaCyNLPPipelineJobSchema()
tesseract_ocr_pipeline_job_schema = TesseractOCRPipelineJobSchema()
tesseract_ocr_pipeline_model_schema = TesseractOCRPipelineModelSchema()
tesseract_ocr_pipeline_models_schema = TesseractOCRPipelineModelSchema(many=True)
@bp.route('', methods=['GET'])
@authenticate(token_auth, role='Administrator')
@response(jobs_schema)
@other_responses(auth_error_responses)
def get_jobs():
"""Get all jobs"""
return Job.query.all()
@bp.route('/tesseract-ocr-pipeline', methods=['POST'])
@authenticate(token_auth)
@body(tesseract_ocr_pipeline_job_schema, location='form')
@response(job_schema)
@other_responses({**auth_error_responses, InternalServerError.code: InternalServerError.description})
def create_tesseract_ocr_pipeline_job(args):
"""Create a new Tesseract OCR Pipeline job"""
current_user = token_auth.current_user()
try:
job = Job.create(
title=args['title'],
description=args['description'],
service='tesseract-ocr-pipeline',
service_args={
'model': hashids.decode(args['model_id']),
'binarization': args['binarization']
},
service_version=args['service_version'],
user=current_user
)
except OSError:
abort(500)
try:
JobInput.create(args['pdf'], job=job)
except OSError:
abort(500)
job.status = JobStatus.SUBMITTED
db.session.commit()
return job, 201
@bp.route('/tesseract-ocr-pipeline/models', methods=['GET'])
@authenticate(token_auth)
@response(tesseract_ocr_pipeline_models_schema)
@other_responses(auth_error_responses)
def get_tesseract_ocr_models():
"""Get all Tesseract OCR Models"""
return TesseractOCRPipelineModel.query.all()
@bp.route('/<hashid:job_id>', methods=['DELETE'])
@authenticate(token_auth)
@response(EmptySchema, status_code=204)
@other_responses(auth_error_responses)
def delete_job(job_id):
"""Delete a job by id"""
current_user = token_auth.current_user()
job = Job.query.get(job_id)
if job is None:
abort(404)
if not (job.user == current_user or current_user.is_administrator()):
abort(403)
try:
job.delete()
except OSError as e:
abort(500)
db.session.commit()
return {}, 204
@bp.route('/<hashid:job_id>', methods=['GET'])
@authenticate(token_auth)
@response(job_schema)
@other_responses(auth_error_responses)
def get_job(job_id):
"""Get a job by id"""
current_user = token_auth.current_user()
job = Job.query.get(job_id)
if job is None:
abort(404)
if not (job.user == current_user or current_user.is_administrator()):
abort(403)
return job

173
app/api/schemas.py Normal file
View File

@ -0,0 +1,173 @@
from apifairy.fields import FileField
from marshmallow import validate, validates, ValidationError
from marshmallow.decorators import post_dump
from app import ma
from app.models import (
Job,
JobStatus,
TesseractOCRPipelineModel,
Token,
User,
UserSettingJobStatusMailNotificationLevel
)
from app.services import SERVICES
class EmptySchema(ma.Schema):
pass
class TokenSchema(ma.SQLAlchemySchema):
class Meta:
model = Token
ordered = True
access_token = ma.String(required=True)
refresh_token = ma.String()
class TesseractOCRPipelineModelSchema(ma.SQLAlchemySchema):
class Meta:
model = TesseractOCRPipelineModel
ordered = True
hashid = ma.String(data_key='id', dump_only=True)
user_hashid = ma.String(data_key='user_id', dump_only=True)
title = ma.auto_field(
required=True,
validate=validate.Length(min=1, max=64)
)
description = ma.auto_field(
required=True,
validate=validate.Length(min=1, max=255)
)
version = ma.String(
required=True,
validate=validate.Length(min=1, max=16)
)
compatible_service_versions = ma.List(
ma.String(required=True, validate=validate.Length(min=1, max=16)),
required=True,
validate=validate.Length(min=1, max=255)
)
publisher = ma.String(
required=True,
validate=validate.Length(min=1, max=128)
)
publisher_url = ma.String(
validate=[validate.URL(), validate.Length(min=1, max=512)]
)
publishing_url = ma.String(
required=True,
validate=[validate.URL(), validate.Length(min=1, max=512)]
)
publishing_year = ma.Int(
required=True
)
is_public = ma.Boolean(required=True)
class JobSchema(ma.SQLAlchemySchema):
class Meta:
model = Job
ordered = True
hashid = ma.String(data_key='id', dump_only=True)
user_hashid = ma.String(data_key='user_id', dump_only=True)
title = ma.auto_field(
required=True,
validate=validate.Length(min=1, max=32)
)
description = ma.auto_field(
required=True,
validate=validate.Length(min=1, max=255)
)
creation_date = ma.auto_field(dump_only=True)
end_date = ma.auto_field(dump_only=True)
service = ma.String(
dump_only=True,
validate=validate.OneOf(SERVICES.keys())
)
service_args = ma.Dict(dump_only=True)
service_version = ma.String(dump_only=True)
status = ma.String(
dump_only=True,
validate=validate.OneOf(list(JobStatus.__members__.keys()))
)
@post_dump(pass_original=True)
def post_dump(self, serialized_job, job, **kwargs):
serialized_job['status'] = job.status.name
return serialized_job
class TesseractOCRPipelineJobSchema(JobSchema):
binarization = ma.Boolean(load_only=True, missing=False)
model_id = ma.String(required=True, load_only=True)
service_version = ma.auto_field(
required=True,
validate=[validate.Length(min=1, max=16), validate.OneOf(list(SERVICES['tesseract-ocr-pipeline']['versions'].keys()))]
)
pdf = FileField()
@validates('pdf')
def validate_pdf(self, value):
if value.mimetype != 'application/pdf':
raise ValidationError('PDF files only!')
class SpaCyNLPPipelineJobSchema(JobSchema):
binarization = ma.Boolean(load_only=True, missing=False)
model_id = ma.String(required=True, load_only=True)
service_version = ma.auto_field(
required=True,
validate=[validate.Length(min=1, max=16), validate.OneOf(list(SERVICES['tesseract-ocr-pipeline']['versions'].keys()))]
)
txt = FileField(required=True)
@validates('txt')
def validate_txt(self, value):
if value.mimetype != 'text/plain':
raise ValidationError('Plain text files only!')
class UserSchema(ma.SQLAlchemySchema):
class Meta:
model = User
ordered = True
hashid = ma.String(data_key='id', dump_only=True)
username = ma.auto_field(
validate=[
validate.Length(min=1, max=64),
validate.Regexp(
User.username_pattern,
error='Usernames must have only letters, numbers, dots or underscores'
)
]
)
email = ma.auto_field(validate=validate.Email())
member_since = ma.auto_field(dump_only=True)
last_seen = ma.auto_field(dump_only=True)
password = ma.String(load_only=True)
last_seen = ma.auto_field(dump_only=True)
setting_job_status_mail_notification_level = ma.String(
validate=validate.OneOf(list(UserSettingJobStatusMailNotificationLevel.__members__.keys()))
)
@validates('email')
def validate_email(self, email):
if User.query.filter(User.email == email).first():
raise ValidationError('Email already registered')
@validates('username')
def validate_username(self, username):
if User.query.filter(User.username == username).first():
raise ValidationError('Username already in use')
@post_dump(pass_original=True)
def post_dump(self, serialized_user, user, **kwargs):
serialized_user['setting_job_status_mail_notification_level'] = \
user.setting_job_status_mail_notification_level.name
return serialized_user

58
app/api/tokens.py Normal file
View File

@ -0,0 +1,58 @@
from apifairy import authenticate, body, response, other_responses
from flask import Blueprint, request, abort
from app import db
from app.models import Token, User
from .auth import basic_auth
from .schemas import EmptySchema, TokenSchema
bp = Blueprint('tokens', __name__)
token_schema = TokenSchema()
@bp.route('', methods=['DELETE'])
@response(EmptySchema, status_code=204, description='Token revoked')
@other_responses({401: 'Invalid access token'})
def delete_token():
"""Revoke an access token"""
access_token = request.headers['Authorization'].split()[1]
token = Token.query.filter(Token.access_token == access_token).first()
if token is None: # pragma: no cover
abort(401)
token.expire()
db.session.commit()
return {}
@bp.route('', methods=['POST'])
@authenticate(basic_auth)
@response(token_schema)
@other_responses({401: 'Invalid username or password'})
def create_token():
"""Create new access and refresh tokens"""
user = basic_auth.current_user()
token = user.generate_auth_token()
db.session.add(token)
Token.clean() # keep token table clean of old tokens
db.session.commit()
return token, 200
@bp.route('', methods=['PUT'])
@body(token_schema)
@response(token_schema, description='Newly issued access and refresh tokens')
@other_responses({401: 'Invalid access or refresh token'})
def refresh_token(args):
"""Refresh an access token"""
access_token = args.get('access_token')
refresh_token = args.get('refresh_token')
if access_token is None or refresh_token is None:
abort(401)
token = User.verify_refresh_token(refresh_token, access_token)
if token is None:
abort(401)
token.expire()
new_token = token.user.generate_auth_token()
db.session.add_all([token, new_token])
db.session.commit()
return new_token, 200

99
app/api/users.py Normal file
View File

@ -0,0 +1,99 @@
from apifairy import authenticate, body, response
from apifairy.decorators import other_responses
from flask import abort, Blueprint
from werkzeug.exceptions import InternalServerError
from app import db
from app.email import create_message, send
from app.models import User
from .schemas import EmptySchema, UserSchema
from .auth import auth_error_responses, token_auth
bp = Blueprint('users', __name__)
user_schema = UserSchema()
users_schema = UserSchema(many=True)
@bp.route('', methods=['GET'])
@authenticate(token_auth, role='Administrator')
@response(users_schema)
@other_responses(auth_error_responses)
def get_users():
"""Get all users"""
return User.query.all()
@bp.route('', methods=['POST'])
@body(user_schema)
@response(user_schema, 201)
@other_responses({InternalServerError.code: InternalServerError.description})
def create_user(args):
"""Create a new user"""
try:
user = User.create(
email=args['email'].lower(),
password=args['password'],
username=args['username']
)
except OSError:
abort(500)
msg = create_message(
user.email,
'Confirm Your Account',
'auth/email/confirm',
token=user.generate_confirm_token(),
user=user
)
send(msg)
db.session.commit()
return user, 201
@bp.route('/<hashid:user_id>', methods=['DELETE'])
@authenticate(token_auth)
@response(EmptySchema, status_code=204)
@other_responses(auth_error_responses)
def delete_user(user_id):
"""Delete a user by id"""
current_user = token_auth.current_user()
user = User.query.get(user_id)
if user is None:
abort(404)
if not (user == current_user or current_user.is_administrator()):
abort(403)
user.delete()
db.session.commit()
return {}, 204
@bp.route('/<hashid:user_id>', methods=['GET'])
@authenticate(token_auth)
@response(user_schema)
@other_responses(auth_error_responses)
@other_responses({404: 'User not found'})
def get_user(user_id):
"""Retrieve a user by id"""
current_user = token_auth.current_user()
user = User.query.get(user_id)
if user is None:
abort(404)
if not (user == current_user or current_user.is_administrator()):
abort(403)
return user
@bp.route('/<username>', methods=['GET'])
@authenticate(token_auth)
@response(user_schema)
@other_responses(auth_error_responses)
@other_responses({404: 'User not found'})
def get_user_by_username(username):
"""Retrieve a user by username"""
current_user = token_auth.current_user()
user = User.query.filter(User.username == username).first()
if user is None:
abort(404)
if not (user == current_user or current_user.is_administrator()):
abort(403)
return user

5
app/auth/__init__.py Normal file
View File

@ -0,0 +1,5 @@
from flask import Blueprint
bp = Blueprint('auth', __name__)
from . import routes

108
app/auth/forms.py Normal file
View File

@ -0,0 +1,108 @@
from flask_wtf import FlaskForm
from wtforms import (
BooleanField,
PasswordField,
StringField,
SubmitField,
ValidationError
)
from wtforms.validators import InputRequired, Email, EqualTo, Length, Regexp
from app.models import User
class RegistrationForm(FlaskForm):
email = StringField(
'Email',
validators=[InputRequired(), Email(), Length(max=254)]
)
username = StringField(
'Username',
validators=[
InputRequired(),
Length(max=64),
Regexp(
User.username_pattern,
message=(
'Usernames must have only letters, numbers, dots or '
'underscores'
)
)
]
)
password = PasswordField(
'Password',
validators=[
InputRequired(),
EqualTo('password_2', message='Passwords must match')
]
)
password_2 = PasswordField(
'Password confirmation',
validators=[
InputRequired(),
EqualTo('password', message='Passwords must match')
]
)
terms_of_use_accepted = BooleanField(
'I have read and accept the terms of use',
validators=[InputRequired()]
)
submit = SubmitField()
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'registration-form'
super().__init__(*args, **kwargs)
def validate_email(self, field):
if User.query.filter_by(email=field.data.lower()).first():
raise ValidationError('Email already registered')
def validate_username(self, field):
if User.query.filter_by(username=field.data).first():
raise ValidationError('Username already in use')
class LoginForm(FlaskForm):
user = StringField('Email or username', validators=[InputRequired()])
password = PasswordField('Password', validators=[InputRequired()])
remember_me = BooleanField('Keep me logged in')
submit = SubmitField()
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'login-form'
super().__init__(*args, **kwargs)
class ResetPasswordRequestForm(FlaskForm):
email = StringField('Email', validators=[InputRequired(), Email()])
submit = SubmitField()
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'reset-password-request-form'
super().__init__(*args, **kwargs)
class ResetPasswordForm(FlaskForm):
password = PasswordField(
'New password',
validators=[
InputRequired(),
EqualTo('password_2', message='Passwords must match')
]
)
password_2 = PasswordField(
'New password confirmation',
validators=[
InputRequired(),
EqualTo('password', message='Passwords must match')
]
)
submit = SubmitField()
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'reset-password-form'
super().__init__(*args, **kwargs)

190
app/auth/routes.py Normal file
View File

@ -0,0 +1,190 @@
from flask import abort, flash, redirect, render_template, request, url_for
from flask_breadcrumbs import register_breadcrumb
from flask_login import current_user, login_user, login_required, logout_user
from app import db
from app.email import create_message, send
from app.models import User
from . import bp
from .forms import (
LoginForm,
ResetPasswordForm,
ResetPasswordRequestForm,
RegistrationForm
)
@bp.before_app_request
def before_request():
"""
Checks if a user is unconfirmed when visiting specific sites. Redirects to
unconfirmed view if user is unconfirmed.
"""
if current_user.is_authenticated:
current_user.ping()
db.session.commit()
if (not current_user.confirmed
and request.endpoint
and request.blueprint != 'auth'
and request.endpoint != 'static'):
return redirect(url_for('auth.unconfirmed'))
@bp.route('/register', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.register', 'Register')
def register():
if current_user.is_authenticated:
return redirect(url_for('main.dashboard'))
form = RegistrationForm()
if form.validate_on_submit():
try:
user = User.create(
email=form.email.data.lower(),
password=form.password.data,
username=form.username.data,
terms_of_use_accepted=form.terms_of_use_accepted.data
)
except OSError:
flash('Internal Server Error', category='error')
abort(500)
flash(f'User "{user.username}" created')
token = user.generate_confirm_token()
msg = create_message(
user.email,
'Confirm Your Account',
'auth/email/confirm',
token=token,
user=user
)
send(msg)
flash('A confirmation email has been sent to you by email')
db.session.commit()
return redirect(url_for('.login'))
return render_template(
'auth/register.html.j2',
title='Register',
form=form
)
@bp.route('/login', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.login', 'Login')
def login():
if current_user.is_authenticated:
return redirect(url_for('main.dashboard'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter((User.email == form.user.data.lower()) | (User.username == form.user.data)).first()
if user and user.verify_password(form.password.data):
login_user(user, form.remember_me.data)
next = request.args.get('next')
if next is None or not next.startswith('/'):
next = url_for('main.dashboard')
flash('You have been logged in')
return redirect(next)
flash('Invalid email/username or password', category='error')
return render_template(
'auth/login.html.j2',
title='Log in',
form=form
)
@bp.route('/logout')
@login_required
def logout():
logout_user()
flash('You have been logged out')
return redirect(url_for('main.index'))
@bp.route('/unconfirmed')
@register_breadcrumb(bp, '.unconfirmed', 'Unconfirmed')
@login_required
def unconfirmed():
if current_user.confirmed:
return redirect(url_for('main.dashboard'))
return render_template(
'auth/unconfirmed.html.j2',
title='Unconfirmed'
)
@bp.route('/confirm-request')
@login_required
def confirm_request():
if current_user.confirmed:
return redirect(url_for('main.dashboard'))
token = current_user.generate_confirm_token()
msg = create_message(
current_user.email,
'Confirm Your Account',
'auth/email/confirm',
token=token,
user=current_user
)
send(msg)
flash('A new confirmation email has been sent to you by email')
return redirect(url_for('.unconfirmed'))
@bp.route('/confirm/<token>')
@login_required
def confirm(token):
if current_user.confirmed:
return redirect(url_for('main.dashboard'))
if current_user.confirm(token):
db.session.commit()
flash('You have confirmed your account')
return redirect(url_for('main.dashboard'))
flash('The confirmation link is invalid or has expired', category='error')
return redirect(url_for('.unconfirmed'))
@bp.route('/reset-password-request', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.reset_password_request', 'Password Reset')
def reset_password_request():
if current_user.is_authenticated:
return redirect(url_for('main.dashboard'))
form = ResetPasswordRequestForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data.lower()).first()
if user is not None:
token = user.generate_reset_password_token()
msg = create_message(
user.email,
'Reset Your Password',
'auth/email/reset_password',
token=token,
user=user
)
send(msg)
flash(
'An email with instructions to reset your password has been sent '
'to you'
)
return redirect(url_for('.login'))
return render_template(
'auth/reset_password_request.html.j2',
title='Password Reset',
form=form
)
@bp.route('/reset-password/<token>', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.reset_password', 'Password Reset')
def reset_password(token):
if current_user.is_authenticated:
return redirect(url_for('main.dashboard'))
form = ResetPasswordForm()
if form.validate_on_submit():
if User.reset_password(token, form.password.data):
db.session.commit()
flash('Your password has been updated')
return redirect(url_for('.login'))
return redirect(url_for('main.index'))
return render_template(
'auth/reset_password.html.j2',
title='Password Reset',
form=form,
token=token
)

View File

@ -0,0 +1,23 @@
from flask import Blueprint
from flask_login import login_required
bp = Blueprint('contributions', __name__)
@bp.before_request
@login_required
def before_request():
'''
Ensures that the routes in this package can only be visited by users that
are logged in.
'''
pass
from . import (
routes,
spacy_nlp_pipeline_models,
tesseract_ocr_pipeline_models,
transkribus_htr_pipeline_models
)

View File

@ -0,0 +1,47 @@
from flask_wtf import FlaskForm
from wtforms import (
StringField,
SubmitField,
SelectMultipleField,
IntegerField
)
from wtforms.validators import InputRequired, Length
class ContributionBaseForm(FlaskForm):
title = StringField(
'Title',
validators=[InputRequired(), Length(max=64)]
)
description = StringField(
'Description',
validators=[InputRequired(), Length(max=255)]
)
version = StringField(
'Version',
validators=[InputRequired(), Length(max=16)]
)
publisher = StringField(
'Publisher',
validators=[InputRequired(), Length(max=128)]
)
publisher_url = StringField(
'Publisher URL',
validators=[InputRequired(), Length(max=512)]
)
publishing_url = StringField(
'Publishing URL',
validators=[InputRequired(), Length(max=512)]
)
publishing_year = IntegerField(
'Publishing year',
validators=[InputRequired()]
)
compatible_service_versions = SelectMultipleField(
'Compatible service versions'
)
submit = SubmitField()
class UpdateContributionBaseForm(ContributionBaseForm):
pass

View File

@ -0,0 +1,9 @@
from flask import redirect, url_for
from flask_breadcrumbs import register_breadcrumb
from . import bp
@bp.route('')
@register_breadcrumb(bp, '.', '<i class="material-icons left">new_label</i>My Contributions')
def contributions():
return redirect(url_for('main.dashboard', _anchor='contributions'))

View File

@ -0,0 +1,2 @@
from .. import bp
from . import json_routes, routes

View File

@ -0,0 +1,48 @@
from flask_wtf.file import FileField, FileRequired
from wtforms import StringField, ValidationError
from wtforms.validators import InputRequired, Length
from app.services import SERVICES
from ..forms import ContributionBaseForm, UpdateContributionBaseForm
class CreateSpaCyNLPPipelineModelForm(ContributionBaseForm):
spacy_model_file = FileField(
'File',
validators=[FileRequired()]
)
pipeline_name = StringField(
'Pipeline name',
validators=[InputRequired(), Length(max=64)]
)
def validate_spacy_model_file(self, field):
if not field.data.filename.lower().endswith('.tar.gz'):
raise ValidationError('.tar.gz files only!')
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'create-spacy-nlp-pipeline-model-form'
super().__init__(*args, **kwargs)
service_manifest = SERVICES['spacy-nlp-pipeline']
self.compatible_service_versions.choices = [('', 'Choose your option')]
self.compatible_service_versions.choices += [
(x, x) for x in service_manifest['versions'].keys()
]
self.compatible_service_versions.default = ''
class UpdateSpaCyNLPPipelineModelForm(UpdateContributionBaseForm):
pipeline_name = StringField(
'Pipeline name',
validators=[InputRequired(), Length(max=64)]
)
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'edit-spacy-nlp-pipeline-model-form'
super().__init__(*args, **kwargs)
service_manifest = SERVICES['spacy-nlp-pipeline']
self.compatible_service_versions.choices = [('', 'Choose your option')]
self.compatible_service_versions.choices += [
(x, x) for x in service_manifest['versions'].keys()
]
self.compatible_service_versions.default = ''

View File

@ -0,0 +1,52 @@
from flask import abort, current_app, request
from flask_login import current_user
from threading import Thread
from app import db
from app.decorators import content_negotiation, permission_required
from app.models import SpaCyNLPPipelineModel
from .. import bp
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['DELETE'])
@content_negotiation(produces='application/json')
def delete_spacy_model(spacy_nlp_pipeline_model_id):
def _delete_spacy_model(app, spacy_nlp_pipeline_model_id):
with app.app_context():
snpm = SpaCyNLPPipelineModel.query.get(spacy_nlp_pipeline_model_id)
snpm.delete()
db.session.commit()
snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
if not (snpm.user == current_user or current_user.is_administrator()):
abort(403)
thread = Thread(
target=_delete_spacy_model,
args=(current_app._get_current_object(), snpm.id)
)
thread.start()
response_data = {
'message': \
f'SpaCy NLP Pipeline Model "{snpm.title}" marked for deletion'
}
return response_data, 202
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>/is_public', methods=['PUT'])
@permission_required('CONTRIBUTE')
@content_negotiation(consumes='application/json', produces='application/json')
def update_spacy_nlp_pipeline_model_is_public(spacy_nlp_pipeline_model_id):
is_public = request.json
if not isinstance(is_public, bool):
abort(400)
snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
if not (snpm.user == current_user or current_user.is_administrator()):
abort(403)
snpm.is_public = is_public
db.session.commit()
response_data = {
'message': (
f'SpaCy NLP Pipeline Model "{snpm.title}"'
f' is now {"public" if is_public else "private"}'
)
}
return response_data, 200

View File

@ -0,0 +1,77 @@
from flask import abort, flash, redirect, render_template, url_for
from flask_breadcrumbs import register_breadcrumb
from flask_login import current_user
from app import db
from app.models import SpaCyNLPPipelineModel
from . import bp
from .forms import (
CreateSpaCyNLPPipelineModelForm,
UpdateSpaCyNLPPipelineModelForm
)
from .utils import (
spacy_nlp_pipeline_model_dlc as spacy_nlp_pipeline_model_dlc
)
@bp.route('/spacy-nlp-pipeline-models')
@register_breadcrumb(bp, '.spacy_nlp_pipeline_models', 'SpaCy NLP Pipeline Models')
def spacy_nlp_pipeline_models():
return render_template(
'contributions/spacy_nlp_pipeline_models/spacy_nlp_pipeline_models.html.j2',
title='SpaCy NLP Pipeline Models'
)
@bp.route('/spacy-nlp-pipeline-models/create', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.spacy_nlp_pipeline_models.create', 'Create')
def create_spacy_nlp_pipeline_model():
form = CreateSpaCyNLPPipelineModelForm()
if form.is_submitted():
if not form.validate():
return {'errors': form.errors}, 400
try:
snpm = SpaCyNLPPipelineModel.create(
form.spacy_model_file.data,
compatible_service_versions=form.compatible_service_versions.data,
description=form.description.data,
pipeline_name=form.pipeline_name.data,
publisher=form.publisher.data,
publisher_url=form.publisher_url.data,
publishing_url=form.publishing_url.data,
publishing_year=form.publishing_year.data,
is_public=False,
title=form.title.data,
version=form.version.data,
user=current_user
)
except OSError:
abort(500)
db.session.commit()
flash(f'SpaCy NLP Pipeline model "{snpm.title}" created')
return {}, 201, {'Location': url_for('.spacy_nlp_pipeline_models')}
return render_template(
'contributions/spacy_nlp_pipeline_models/create.html.j2',
title='Create SpaCy NLP Pipeline Model',
form=form
)
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.spacy_nlp_pipeline_models.entity', '', dynamic_list_constructor=spacy_nlp_pipeline_model_dlc)
def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id):
snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
if not (snpm.user == current_user or current_user.is_administrator()):
abort(403)
form = UpdateSpaCyNLPPipelineModelForm(data=snpm.to_json_serializeable())
if form.validate_on_submit():
form.populate_obj(snpm)
if db.session.is_modified(snpm):
flash(f'SpaCy NLP Pipeline model "{snpm.title}" updated')
db.session.commit()
return redirect(url_for('.spacy_nlp_pipeline_models'))
return render_template(
'contributions/spacy_nlp_pipeline_models/spacy_nlp_pipeline_model.html.j2',
title=f'{snpm.title} {snpm.version}',
form=form,
spacy_nlp_pipeline_model=snpm
)

View File

@ -0,0 +1,13 @@
from flask import request, url_for
from app.models import SpaCyNLPPipelineModel
def spacy_nlp_pipeline_model_dlc():
snpm_id = request.view_args['spacy_nlp_pipeline_model_id']
snpm = SpaCyNLPPipelineModel.query.get_or_404(snpm_id)
return [
{
'text': f'{snpm.title} {snpm.version}',
'url': url_for('.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=snpm_id)
}
]

View File

@ -0,0 +1,2 @@
from .. import bp
from . import json_routes, routes

View File

@ -0,0 +1,39 @@
from flask_wtf.file import FileField, FileRequired
from wtforms import ValidationError
from app.services import SERVICES
from ..forms import ContributionBaseForm, UpdateContributionBaseForm
class CreateTesseractOCRPipelineModelForm(ContributionBaseForm):
tesseract_model_file = FileField(
'File',
validators=[FileRequired()]
)
def validate_tesseract_model_file(self, field):
if not field.data.filename.lower().endswith('.traineddata'):
raise ValidationError('traineddata files only!')
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'create-tesseract-ocr-pipeline-model-form'
service_manifest = SERVICES['tesseract-ocr-pipeline']
super().__init__(*args, **kwargs)
self.compatible_service_versions.choices = [('', 'Choose your option')]
self.compatible_service_versions.choices += [
(x, x) for x in service_manifest['versions'].keys()
]
self.compatible_service_versions.default = ''
class UpdateTesseractOCRPipelineModelForm(UpdateContributionBaseForm):
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'edit-tesseract-ocr-pipeline-model-form'
service_manifest = SERVICES['tesseract-ocr-pipeline']
super().__init__(*args, **kwargs)
self.compatible_service_versions.choices = [('', 'Choose your option')]
self.compatible_service_versions.choices += [
(x, x) for x in service_manifest['versions'].keys()
]
self.compatible_service_versions.default = ''

View File

@ -0,0 +1,52 @@
from flask import abort, current_app, request
from flask_login import current_user
from threading import Thread
from app import db
from app.decorators import content_negotiation, permission_required
from app.models import TesseractOCRPipelineModel
from . import bp
@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>', methods=['DELETE'])
@content_negotiation(produces='application/json')
def delete_tesseract_model(tesseract_ocr_pipeline_model_id):
def _delete_tesseract_ocr_pipeline_model(app, tesseract_ocr_pipeline_model_id):
with app.app_context():
topm = TesseractOCRPipelineModel.query.get(tesseract_ocr_pipeline_model_id)
topm.delete()
db.session.commit()
topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
if not (topm.user == current_user or current_user.is_administrator()):
abort(403)
thread = Thread(
target=_delete_tesseract_ocr_pipeline_model,
args=(current_app._get_current_object(), topm.id)
)
thread.start()
response_data = {
'message': \
f'Tesseract OCR Pipeline Model "{topm.title}" marked for deletion'
}
return response_data, 202
@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>/is_public', methods=['PUT'])
@permission_required('CONTRIBUTE')
@content_negotiation(consumes='application/json', produces='application/json')
def update_tesseract_ocr_pipeline_model_is_public(tesseract_ocr_pipeline_model_id):
is_public = request.json
if not isinstance(is_public, bool):
abort(400)
topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
if not (topm.user == current_user or current_user.is_administrator()):
abort(403)
topm.is_public = is_public
db.session.commit()
response_data = {
'message': (
f'Tesseract OCR Pipeline Model "{topm.title}"'
f' is now {"public" if is_public else "private"}'
)
}
return response_data, 200

View File

@ -0,0 +1,76 @@
from flask import abort, flash, redirect, render_template, url_for
from flask_breadcrumbs import register_breadcrumb
from flask_login import current_user
from app import db
from app.models import TesseractOCRPipelineModel
from . import bp
from .forms import (
CreateTesseractOCRPipelineModelForm,
UpdateTesseractOCRPipelineModelForm
)
from .utils import (
tesseract_ocr_pipeline_model_dlc as tesseract_ocr_pipeline_model_dlc
)
@bp.route('/tesseract-ocr-pipeline-models')
@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models', 'Tesseract OCR Pipeline Models')
def tesseract_ocr_pipeline_models():
return render_template(
'contributions/tesseract_ocr_pipeline_models/tesseract_ocr_pipeline_models.html.j2',
title='Tesseract OCR Pipeline Models'
)
@bp.route('/tesseract-ocr-pipeline-models/create', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models.create', 'Create')
def create_tesseract_ocr_pipeline_model():
form = CreateTesseractOCRPipelineModelForm()
if form.is_submitted():
if not form.validate():
return {'errors': form.errors}, 400
try:
topm = TesseractOCRPipelineModel.create(
form.tesseract_model_file.data,
compatible_service_versions=form.compatible_service_versions.data,
description=form.description.data,
publisher=form.publisher.data,
publisher_url=form.publisher_url.data,
publishing_url=form.publishing_url.data,
publishing_year=form.publishing_year.data,
is_public=False,
title=form.title.data,
version=form.version.data,
user=current_user
)
except OSError:
abort(500)
db.session.commit()
flash(f'Tesseract OCR Pipeline model "{topm.title}" created')
return {}, 201, {'Location': url_for('.tesseract_ocr_pipeline_models')}
return render_template(
'contributions/tesseract_ocr_pipeline_models/create.html.j2',
title='Create Tesseract OCR Pipeline Model',
form=form
)
@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models.entity', '', dynamic_list_constructor=tesseract_ocr_pipeline_model_dlc)
def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id):
topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
if not (topm.user == current_user or current_user.is_administrator()):
abort(403)
form = UpdateTesseractOCRPipelineModelForm(data=topm.to_json_serializeable())
if form.validate_on_submit():
form.populate_obj(topm)
if db.session.is_modified(topm):
flash(f'Tesseract OCR Pipeline model "{topm.title}" updated')
db.session.commit()
return redirect(url_for('.tesseract_ocr_pipeline_models'))
return render_template(
'contributions/tesseract_ocr_pipeline_models/tesseract_ocr_pipeline_model.html.j2',
title=f'{topm.title} {topm.version}',
form=form,
tesseract_ocr_pipeline_model=topm
)

View File

@ -0,0 +1,13 @@
from flask import request, url_for
from app.models import TesseractOCRPipelineModel
def tesseract_ocr_pipeline_model_dlc():
topm_id = request.view_args['tesseract_ocr_pipeline_model_id']
topm = TesseractOCRPipelineModel.query.get_or_404(topm_id)
return [
{
'text': f'{topm.title} {topm.version}',
'url': url_for('.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=topm_id)
}
]

View File

@ -0,0 +1,2 @@
from .. import bp
from . import routes

View File

@ -0,0 +1,7 @@
from flask import abort
from . import bp
@bp.route('/transkribus_htr_pipeline_models')
def transkribus_htr_pipeline_models():
return abort(503)

View File

22
app/converters/cli.py Normal file
View File

@ -0,0 +1,22 @@
import click
from . import bp
from .sandpaper import SandpaperConverter
@bp.cli.group('converter')
def converter():
''' Converter commands. '''
pass
@converter.group('sandpaper')
def sandpaper_converter():
''' Sandpaper converter commands. '''
pass
@sandpaper_converter.command('run')
@click.argument('json_db_file')
@click.argument('data_dir')
def run_sandpaper_converter(json_db_file, data_dir):
''' Run the sandpaper converter. '''
sandpaper_converter = SandpaperConverter(json_db_file, data_dir)
sandpaper_converter.run()

112
app/converters/sandpaper.py Normal file
View File

@ -0,0 +1,112 @@
from flask import current_app
from app import db
from app.models import User, Corpus, CorpusFile
from datetime import datetime
import json
import os
import shutil
class SandpaperConverter:
def __init__(self, json_db_file, data_dir):
self.json_db_file = json_db_file
self.data_dir = data_dir
def run(self):
with open(self.json_db_file, 'r') as f:
json_db = json.loads(f.read())
for json_user in json_db:
if not json_user['confirmed']:
current_app.logger.info(f'Skip unconfirmed user {json_user["username"]}')
continue
user_dir = os.path.join(self.data_dir, str(json_user['id']))
self.convert_user(json_user, user_dir)
db.session.commit()
def convert_user(self, json_user, user_dir):
current_app.logger.info(f'Create User {json_user["username"]}...')
user = User(
confirmed=json_user['confirmed'],
email=json_user['email'],
last_seen=datetime.fromtimestamp(json_user['last_seen']),
member_since=datetime.fromtimestamp(json_user['member_since']),
password_hash=json_user['password_hash'], # TODO: Needs to be added manually
username=json_user['username']
)
db.session.add(user)
db.session.flush(objects=[user])
db.session.refresh(user)
try:
user.makedirs()
except OSError as e:
current_app.logger.error(e)
db.session.rollback()
raise Exception('Internal Server Error')
for json_corpus in json_user['corpora'].values():
if not json_corpus['files'].values():
current_app.logger.info(f'Skip empty corpus {json_corpus["title"]}')
continue
corpus_dir = os.path.join(user_dir, 'corpora', str(json_corpus['id']))
self.convert_corpus(json_corpus, user, corpus_dir)
current_app.logger.info('Done')
def convert_corpus(self, json_corpus, user, corpus_dir):
current_app.logger.info(f'Create Corpus {json_corpus["title"]}...')
corpus = Corpus(
user=user,
creation_date=datetime.fromtimestamp(json_corpus['creation_date']),
description=json_corpus['description'],
title=json_corpus['title']
)
db.session.add(corpus)
db.session.flush(objects=[corpus])
db.session.refresh(corpus)
try:
corpus.makedirs()
except OSError as e:
current_app.logger.error(e)
db.session.rollback()
raise Exception('Internal Server Error')
for json_corpus_file in json_corpus['files'].values():
self.convert_corpus_file(json_corpus_file, corpus, corpus_dir)
current_app.logger.info('Done')
def convert_corpus_file(self, json_corpus_file, corpus, corpus_dir):
current_app.logger.info(f'Create CorpusFile {json_corpus_file["title"]}...')
corpus_file = CorpusFile(
corpus=corpus,
address=json_corpus_file['address'],
author=json_corpus_file['author'],
booktitle=json_corpus_file['booktitle'],
chapter=json_corpus_file['chapter'],
editor=json_corpus_file['editor'],
filename=json_corpus_file['filename'],
institution=json_corpus_file['institution'],
journal=json_corpus_file['journal'],
mimetype='application/vrt+xml',
pages=json_corpus_file['pages'],
publisher=json_corpus_file['publisher'],
publishing_year=json_corpus_file['publishing_year'],
school=json_corpus_file['school'],
title=json_corpus_file['title']
)
db.session.add(corpus_file)
db.session.flush(objects=[corpus_file])
db.session.refresh(corpus_file)
try:
shutil.copy2(
os.path.join(corpus_dir, json_corpus_file['filename']),
corpus_file.path
)
except:
current_app.logger.warning(
'Can not convert corpus file: '
f'{os.path.join(corpus_dir, json_corpus_file["filename"])}'
' -> '
f'{corpus_file.path}'
)
current_app.logger.info('Done')

117
app/converters/vrt.py Normal file
View File

@ -0,0 +1,117 @@
from flask import current_app
def normalize_vrt_file(input_file, output_file):
def check_pos_attribute_order(vrt_lines):
# The following orders are possible:
# since 26.02.2019: 'word,lemma,simple_pos,pos,ner'
# since 26.03.2021: 'word,pos,lemma,simple_pos,ner'
# since 27.01.2022: 'word,pos,lemma,simple_pos'
# This Function tries to find out which order we have by looking at the
# number of attributes and the position of the simple_pos attribute
SIMPLE_POS_LABELS = [
'ADJ', 'ADP', 'ADV', 'AUX', 'CONJ',
'DET', 'INTJ', 'NOUN', 'NUM', 'PART',
'PRON', 'PROPN', 'PUNCT', 'SCONJ', 'SYM',
'VERB', 'X'
]
for line in vrt_lines:
if line.startswith('<'):
continue
pos_attrs = line.rstrip('\n').split('\t')
num_pos_attrs = len(pos_attrs)
if num_pos_attrs == 4:
if pos_attrs[3] in SIMPLE_POS_LABELS:
return ['word', 'pos', 'lemma', 'simple_pos']
continue
elif num_pos_attrs == 5:
if pos_attrs[2] in SIMPLE_POS_LABELS:
return ['word', 'lemma', 'simple_pos', 'pos', 'ner']
elif pos_attrs[3] in SIMPLE_POS_LABELS:
return ['word', 'pos', 'lemma', 'simple_pos', 'ner']
continue
return None
def check_has_ent_as_s_attr(vrt_lines):
for line in vrt_lines:
if line.startswith('<ent'):
return True
return False
def pos_attrs_to_string_1(pos_attrs):
return f'{pos_attrs[0]}\t{pos_attrs[3]}\t{pos_attrs[1]}\t{pos_attrs[2]}\n'
def pos_attrs_to_string_2(pos_attrs):
return f'{pos_attrs[0]}\t{pos_attrs[1]}\t{pos_attrs[2]}\t{pos_attrs[3]}\n'
current_app.logger.info(f'Converting {input_file}...')
with open(input_file) as f:
input_vrt_lines = f.readlines()
pos_attr_order = check_pos_attribute_order(input_vrt_lines)
has_ent_as_s_attr = check_has_ent_as_s_attr(input_vrt_lines)
current_app.logger.info(f'Detected pos_attr_order: [{",".join(pos_attr_order)}]')
current_app.logger.info(f'Detected has_ent_as_s_attr: {has_ent_as_s_attr}')
if pos_attr_order == ['word', 'lemma', 'simple_pos', 'pos', 'ner']:
pos_attrs_to_string_function = pos_attrs_to_string_1
elif pos_attr_order == ['word', 'pos', 'lemma', 'simple_pos', 'ner']:
pos_attrs_to_string_function = pos_attrs_to_string_2
elif pos_attr_order == ['word', 'pos', 'lemma', 'simple_pos']:
pos_attrs_to_string_function = pos_attrs_to_string_2
else:
raise Exception('Can not handle format')
current_ent = None
multi_line_tag_definition = False
output_vrt = ''
for line in input_vrt_lines:
if line.strip() == '':
continue
if line.startswith('<'):
if not has_ent_as_s_attr:
if current_ent is not None:
output_vrt += '</ent>\n'
current_ent = None
if not line.rstrip().endswith('>'):
multi_line_tag_definition = True
if line.startswith('<text'):
output_vrt += '<text>\n'
if line.startswith('</text>'):
output_vrt += '</text>\n'
elif line.startswith('<s'):
output_vrt += '<s>\n'
elif line.startswith('</s>'):
output_vrt += '</s>\n'
elif line.startswith('<ent'):
output_vrt += line
elif line.startswith('</ent>'):
output_vrt += line
continue
if multi_line_tag_definition and line.rstrip().endswith('>'):
multi_line_tag_definition = False
continue
pos_attrs = line.rstrip('\n').split('\t')
if not has_ent_as_s_attr and len(pos_attrs) > 4:
if pos_attrs[4].lower() in ['null', 'none']:
if current_ent:
output_vrt += '</ent>\n'
current_ent = None
else:
if current_ent is None:
output_vrt += f'<ent type="{pos_attrs[4]}">\n'
current_ent = pos_attrs[4]
elif current_ent != pos_attrs[4]:
output_vrt += '</ent>\n'
current_ent = None
output_vrt += f'<ent type="{pos_attrs[4]}">\n'
current_ent = pos_attrs[4]
output_vrt += pos_attrs_to_string_function(pos_attrs)
with open(output_file, 'w') as f:
f.write(output_vrt)

19
app/corpora/__init__.py Normal file
View File

@ -0,0 +1,19 @@
from flask import Blueprint
from flask_login import login_required
bp = Blueprint('corpora', __name__)
bp.cli.short_help = 'Corpus commands.'
@bp.before_request
@login_required
def before_request():
'''
Ensures that the routes in this package can only be visited by users that
are logged in.
'''
pass
from . import cli, cqi_over_sio, files, followers, routes, json_routes

27
app/corpora/cli.py Normal file
View File

@ -0,0 +1,27 @@
from app.models import Corpus, CorpusStatus
import os
import shutil
from app import db
from . import bp
@bp.cli.command('reset')
def reset():
''' Reset built corpora. '''
status = [
CorpusStatus.QUEUED,
CorpusStatus.BUILDING,
CorpusStatus.BUILT,
CorpusStatus.STARTING_ANALYSIS_SESSION,
CorpusStatus.RUNNING_ANALYSIS_SESSION,
CorpusStatus.CANCELING_ANALYSIS_SESSION
]
for corpus in [x for x in Corpus.query.all() if x.status in status]:
print(f'Resetting corpus {corpus}')
shutil.rmtree(os.path.join(corpus.path, 'cwb'), ignore_errors=True)
os.mkdir(os.path.join(corpus.path, 'cwb'))
os.mkdir(os.path.join(corpus.path, 'cwb', 'data'))
os.mkdir(os.path.join(corpus.path, 'cwb', 'registry'))
corpus.status = CorpusStatus.UNPREPARED
corpus.num_analysis_sessions = 0
db.session.commit()

View File

@ -0,0 +1,113 @@
from cqi import CQiClient
from cqi.errors import CQiException
from flask import session
from flask_login import current_user
from flask_socketio import ConnectionRefusedError
from threading import Lock
from app import db, hashids, socketio
from app.decorators import socketio_login_required
from app.models import Corpus, CorpusStatus
import math
'''
This package tunnels the Corpus Query interface (CQi) protocol through
Socket.IO (SIO) by wrapping each CQi function in a seperate SIO event.
This module only handles the SIO connect/disconnect, which handles the setup
and teardown of necessary ressources for later use. Each CQi function has a
corresponding SIO event. The event handlers are spread across the different
modules within this package.
Basic concept:
1. A client connects to the SIO namespace and provides the id of a corpus to be
analysed.
1.1 The analysis session counter of the corpus is incremented.
1.2 A CQiClient and a (Mutex) Lock belonging to it is created.
1.3 Wait until the CQP server is running.
1.4 Connect the CQiClient to the server.
1.5 Save the CQiClient and the Lock in the session for subsequential use.
2. A client emits an event and may provide a single json object with necessary
arguments for the targeted CQi function.
3. A SIO event handler (decorated with cqi_over_socketio) gets executed.
- The event handler function defines all arguments. Hence the client
is sent as a single json object, the decorator decomposes it to fit
the functions signature. This also includes type checking and proper
use of the lock (acquire/release) mechanism.
4. Wait for more events
5. The client disconnects from the SIO namespace
1.1 The analysis session counter of the corpus is decremented.
1.2 The CQiClient and (Mutex) Lock belonging to it are teared down.
'''
NAMESPACE = '/cqi_over_sio'
from .cqi import * # noqa
@socketio.on('connect', namespace=NAMESPACE)
@socketio_login_required
def connect(auth):
# the auth variable is used in a hacky way. It contains the corpus id for
# which a corpus analysis session should be started.
corpus_id = hashids.decode(auth['corpus_id'])
corpus = Corpus.query.get(corpus_id)
if corpus is None:
# return {'code': 404, 'msg': 'Not Found'}
raise ConnectionRefusedError('Not Found')
if not (corpus.user == current_user
or current_user.is_following_corpus(corpus)
or current_user.is_administrator()):
# return {'code': 403, 'msg': 'Forbidden'}
raise ConnectionRefusedError('Forbidden')
if corpus.status not in [
CorpusStatus.BUILT,
CorpusStatus.STARTING_ANALYSIS_SESSION,
CorpusStatus.RUNNING_ANALYSIS_SESSION,
CorpusStatus.CANCELING_ANALYSIS_SESSION
]:
# return {'code': 424, 'msg': 'Failed Dependency'}
raise ConnectionRefusedError('Failed Dependency')
if corpus.num_analysis_sessions is None:
corpus.num_analysis_sessions = 0
db.session.commit()
corpus.num_analysis_sessions = Corpus.num_analysis_sessions + 1
db.session.commit()
retry_counter = 20
while corpus.status != CorpusStatus.RUNNING_ANALYSIS_SESSION:
if retry_counter == 0:
corpus.num_analysis_sessions = Corpus.num_analysis_sessions - 1
db.session.commit()
return {'code': 408, 'msg': 'Request Timeout'}
socketio.sleep(3)
retry_counter -= 1
db.session.refresh(corpus)
cqi_client = CQiClient(f'cqpserver_{corpus_id}', timeout=math.inf)
session['cqi_over_sio'] = {
'corpus_id': corpus_id,
'cqi_client': cqi_client,
'cqi_client_lock': Lock(),
}
# return {'code': 200, 'msg': 'OK'}
@socketio.on('disconnect', namespace=NAMESPACE)
def disconnect():
try:
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
cqi_client_lock: Lock = session['cqi_over_sio']['cqi_client_lock']
except KeyError:
return
cqi_client_lock.acquire()
try:
cqi_client.api.ctrl_bye()
except (BrokenPipeError, CQiException):
pass
cqi_client_lock.release()
corpus = Corpus.query.get(session['cqi_over_sio']['corpus_id'])
corpus.num_analysis_sessions = Corpus.num_analysis_sessions - 1
db.session.commit()
session.pop('cqi_over_sio')
# return {'code': 200, 'msg': 'OK'}

View File

@ -0,0 +1,110 @@
from cqi import CQiClient
from cqi.errors import CQiException
from cqi.status import CQiStatus
from flask import session
from inspect import signature
from threading import Lock
from typing import Callable, Dict, List
from app import socketio
from app.decorators import socketio_login_required
from . import NAMESPACE as ns
from .extensions import CQI_EXTENSION_FUNCTION_NAMES
from . import extensions as extensions_module
CQI_FUNCTION_NAMES: List[str] = [
'ask_feature_cl_2_3',
'ask_feature_cqi_1_0',
'ask_feature_cqp_2_3',
'cl_alg2cpos',
'cl_attribute_size',
'cl_cpos2alg',
'cl_cpos2id',
'cl_cpos2lbound',
'cl_cpos2rbound',
'cl_cpos2str',
'cl_cpos2struc',
'cl_drop_attribute',
'cl_id2cpos',
'cl_id2freq',
'cl_id2str',
'cl_idlist2cpos',
'cl_lexicon_size',
'cl_regex2id',
'cl_str2id',
'cl_struc2cpos',
'cl_struc2str',
'corpus_alignment_attributes',
'corpus_charset',
'corpus_drop_corpus',
'corpus_full_name',
'corpus_info',
'corpus_list_corpora',
'corpus_positional_attributes',
'corpus_properties',
'corpus_structural_attribute_has_values',
'corpus_structural_attributes',
'cqp_drop_subcorpus',
'cqp_dump_subcorpus',
'cqp_fdist_1',
'cqp_fdist_2',
'cqp_list_subcorpora',
'cqp_query',
'cqp_subcorpus_has_field',
'cqp_subcorpus_size',
'ctrl_bye',
'ctrl_connect',
'ctrl_last_general_error',
'ctrl_ping',
'ctrl_user_abort'
]
@socketio.on('cqi', namespace=ns)
@socketio_login_required
def cqi_over_sio(fn_name: str, fn_args: Dict = {}):
try:
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
cqi_client_lock: Lock = session['cqi_over_sio']['cqi_client_lock']
except KeyError:
return {'code': 424, 'msg': 'Failed Dependency'}
if fn_name in CQI_FUNCTION_NAMES:
fn: Callable = getattr(cqi_client.api, fn_name)
elif fn_name in CQI_EXTENSION_FUNCTION_NAMES:
fn: Callable = getattr(extensions_module, fn_name)
else:
return {'code': 400, 'msg': 'Bad Request'}
for param in signature(fn).parameters.values():
if param.default is param.empty:
if param.name not in fn_args:
return {'code': 400, 'msg': 'Bad Request'}
else:
if param.name not in fn_args:
continue
if type(fn_args[param.name]) is not param.annotation:
return {'code': 400, 'msg': 'Bad Request'}
cqi_client_lock.acquire()
try:
fn_return_value = fn(**fn_args)
except BrokenPipeError as e:
return {'code': 500, 'msg': 'Internal Server Error'}
except CQiException as e:
return {
'code': 502,
'msg': 'Bad Gateway',
'payload': {
'code': e.code,
'desc': e.description,
'msg': e.__class__.__name__
}
}
finally:
cqi_client_lock.release()
if isinstance(fn_return_value, CQiStatus):
payload = {
'code': fn_return_value.code,
'msg': fn_return_value.__class__.__name__
}
else:
payload = fn_return_value
return {'code': 200, 'msg': 'OK', 'payload': payload}

View File

@ -0,0 +1,314 @@
from collections import Counter
from cqi import CQiClient
from cqi.models.corpora import Corpus as CQiCorpus
from cqi.models.attributes import (
PositionalAttribute as CQiPositionalAttribute,
StructuralAttribute as CQiStructuralAttribute
)
from cqi.status import StatusOk as CQiStatusOk
from flask import session
from typing import Dict, List
import gzip
import json
import math
import os
from app import db
from app.models import Corpus
from .utils import lookups_by_cpos, partial_export_subcorpus, export_subcorpus
CQI_EXTENSION_FUNCTION_NAMES: List[str] = [
'ext_corpus_update_db',
'ext_corpus_static_data',
'ext_corpus_paginate_corpus',
'ext_cqp_paginate_subcorpus',
'ext_cqp_partial_export_subcorpus',
'ext_cqp_export_subcorpus',
]
def ext_corpus_update_db(corpus: str) -> CQiStatusOk:
db_corpus = Corpus.query.get(session['cqi_over_sio']['corpus_id'])
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
cqi_corpus: CQiCorpus = cqi_client.corpora.get(corpus)
db_corpus.num_tokens = cqi_corpus.size
db.session.commit()
return CQiStatusOk()
def ext_corpus_static_data(corpus: str) -> Dict:
db_corpus = Corpus.query.get(session['cqi_over_sio']['corpus_id'])
static_corpus_data_file = os.path.join(db_corpus.path, 'cwb', 'static.json.gz')
if os.path.exists(static_corpus_data_file):
with open(static_corpus_data_file, 'rb') as f:
return f.read()
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
cqi_corpus: CQiCorpus = cqi_client.corpora.get(corpus)
cqi_p_attrs: Dict[str, CQiPositionalAttribute] = {
p_attr.name: p_attr
for p_attr in cqi_corpus.positional_attributes.list()
}
cqi_s_attrs: Dict[str, CQiStructuralAttribute] = {
s_attr.name: s_attr
for s_attr in cqi_corpus.structural_attributes.list()
}
static_corpus_data = {
'corpus': {
'bounds': [0, cqi_corpus.size - 1],
'counts': {
'token': cqi_corpus.size
},
'freqs': {}
},
'p_attrs': {},
's_attrs': {},
'values': {'p_attrs': {}, 's_attrs': {}}
}
for p_attr in cqi_p_attrs.values():
static_corpus_data['corpus']['freqs'][p_attr.name] = {}
chunk_size = 10000
p_attr_id_list = list(range(p_attr.lexicon_size))
chunks = [p_attr_id_list[i:i+chunk_size] for i in range(0, len(p_attr_id_list), chunk_size)]
del p_attr_id_list
for chunk in chunks:
# print(f'corpus.freqs.{p_attr.name}: {chunk[0]} - {chunk[-1]}')
static_corpus_data['corpus']['freqs'][p_attr.name].update(
dict(zip(chunk, p_attr.freqs_by_ids(chunk)))
)
del chunks
static_corpus_data['p_attrs'][p_attr.name] = {}
cpos_list = list(range(cqi_corpus.size))
chunks = [cpos_list[i:i+chunk_size] for i in range(0, len(cpos_list), chunk_size)]
del cpos_list
for chunk in chunks:
# print(f'p_attrs.{p_attr.name}: {chunk[0]} - {chunk[-1]}')
static_corpus_data['p_attrs'][p_attr.name].update(
dict(zip(chunk, p_attr.ids_by_cpos(chunk)))
)
del chunks
static_corpus_data['values']['p_attrs'][p_attr.name] = {}
p_attr_id_list = list(range(p_attr.lexicon_size))
chunks = [p_attr_id_list[i:i+chunk_size] for i in range(0, len(p_attr_id_list), chunk_size)]
del p_attr_id_list
for chunk in chunks:
# print(f'values.p_attrs.{p_attr.name}: {chunk[0]} - {chunk[-1]}')
static_corpus_data['values']['p_attrs'][p_attr.name].update(
dict(zip(chunk, p_attr.values_by_ids(chunk)))
)
del chunks
for s_attr in cqi_s_attrs.values():
if s_attr.has_values:
continue
static_corpus_data['corpus']['counts'][s_attr.name] = s_attr.size
static_corpus_data['s_attrs'][s_attr.name] = {'lexicon': {}, 'values': None}
static_corpus_data['values']['s_attrs'][s_attr.name] = {}
##########################################################################
# A faster way to get cpos boundaries for smaller s_attrs #
##########################################################################
# if s_attr.name in ['s', 'ent']:
# cqi_corpus.query('Last', f'<{s_attr.name}> []* </{s_attr.name}>;')
# cqi_subcorpus = cqi_corpus.subcorpora.get('Last')
# first_match = 0
# last_match = cqi_subcorpus.size - 1
# match_boundaries = zip(
# range(first_match, last_match + 1),
# cqi_subcorpus.dump(cqi_subcorpus.fields['match'], first_match, last_match),
# cqi_subcorpus.dump(cqi_subcorpus.fields['matchend'], first_match, last_match)
# )
# for id, lbound, rbound in match_boundaries:
# static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id] = {}
# static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['bounds'] = [lbound, rbound]
# static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts'] = {}
# static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts']['token'] = rbound - lbound + 1
# cqi_subcorpus.drop()
for id in range(0, s_attr.size):
# print(f's_attrs.{s_attr.name}.lexicon.{id}')
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id] = {
'bounds': None,
'counts': None,
'freqs': None
}
if s_attr.name != 'text':
continue
lbound, rbound = s_attr.cpos_by_id(id)
# print(f's_attrs.{s_attr.name}.lexicon.{id}.bounds')
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['bounds'] = [lbound, rbound]
# print(f's_attrs.{s_attr.name}.lexicon.{id}.counts')
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts'] = {}
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts']['token'] = rbound - lbound + 1
cpos_list = list(range(lbound, rbound + 1))
chunks = [cpos_list[i:i+chunk_size] for i in range(0, len(cpos_list), chunk_size)]
del cpos_list
ent_ids = set()
for chunk in chunks:
# print(f'Gather ent_ids from cpos: {chunk[0]} - {chunk[-1]}')
ent_ids.update({x for x in cqi_s_attrs['ent'].ids_by_cpos(chunk) if x != -1})
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts']['ent'] = len(ent_ids)
del ent_ids
s_ids = set()
for chunk in chunks:
# print(f'Gather s_ids from cpos: {chunk[0]} - {chunk[-1]}')
s_ids.update({x for x in cqi_s_attrs['s'].ids_by_cpos(chunk) if x != -1})
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts']['s'] = len(s_ids)
del s_ids
# print(f's_attrs.{s_attr.name}.lexicon.{id}.freqs')
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['freqs'] = {}
for p_attr in cqi_p_attrs.values():
p_attr_ids = []
for chunk in chunks:
# print(f'Gather p_attr_ids from cpos: {chunk[0]} - {chunk[-1]}')
p_attr_ids.extend(p_attr.ids_by_cpos(chunk))
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['freqs'][p_attr.name] = dict(Counter(p_attr_ids))
del p_attr_ids
del chunks
sub_s_attrs = cqi_corpus.structural_attributes.list(filters={'part_of': s_attr})
s_attr_value_names: List[str] = [
sub_s_attr.name[(len(s_attr.name) + 1):]
for sub_s_attr in sub_s_attrs
]
s_attr_id_list = list(range(s_attr.size))
chunks = [s_attr_id_list[i:i+chunk_size] for i in range(0, len(s_attr_id_list), chunk_size)]
del s_attr_id_list
sub_s_attr_values = []
for sub_s_attr in sub_s_attrs:
tmp = []
for chunk in chunks:
tmp.extend(sub_s_attr.values_by_ids(chunk))
sub_s_attr_values.append(tmp)
del tmp
del chunks
# print(f's_attrs.{s_attr.name}.values')
static_corpus_data['s_attrs'][s_attr.name]['values'] = s_attr_value_names
# print(f'values.s_attrs.{s_attr.name}')
static_corpus_data['values']['s_attrs'][s_attr.name] = {
s_attr_id: {
s_attr_value_name: sub_s_attr_values[s_attr_value_name_idx][s_attr_id_idx]
for s_attr_value_name_idx, s_attr_value_name in enumerate(
static_corpus_data['s_attrs'][s_attr.name]['values']
)
} for s_attr_id_idx, s_attr_id in enumerate(range(0, s_attr.size))
}
del sub_s_attr_values
with gzip.open(static_corpus_data_file, 'wt') as f:
json.dump(static_corpus_data, f)
del static_corpus_data
with open(static_corpus_data_file, 'rb') as f:
return f.read()
def ext_corpus_paginate_corpus(
corpus: str,
page: int = 1,
per_page: int = 20
) -> Dict:
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
cqi_corpus = cqi_client.corpora.get(corpus)
# Sanity checks
if (
per_page < 1
or page < 1
or (
cqi_corpus.size > 0
and page > math.ceil(cqi_corpus.size / per_page)
)
):
return {'code': 416, 'msg': 'Range Not Satisfiable'}
first_cpos = (page - 1) * per_page
last_cpos = min(cqi_corpus.size, first_cpos + per_page)
cpos_list = [*range(first_cpos, last_cpos)]
lookups = lookups_by_cpos(cqi_corpus, cpos_list)
payload = {}
# the items for the current page
payload['items'] = [cpos_list]
# the lookups for the items
payload['lookups'] = lookups
# the total number of items matching the query
payload['total'] = cqi_corpus.size
# the number of items to be displayed on a page.
payload['per_page'] = per_page
# The total number of pages
payload['pages'] = math.ceil(payload['total'] / payload['per_page'])
# the current page number (1 indexed)
payload['page'] = page if payload['pages'] > 0 else None
# True if a previous page exists
payload['has_prev'] = payload['page'] > 1 if payload['page'] else False
# True if a next page exists.
payload['has_next'] = payload['page'] < payload['pages'] if payload['page'] else False # noqa
# Number of the previous page.
payload['prev_num'] = payload['page'] - 1 if payload['has_prev'] else None
# Number of the next page
payload['next_num'] = payload['page'] + 1 if payload['has_next'] else None
return payload
def ext_cqp_paginate_subcorpus(
subcorpus: str,
context: int = 50,
page: int = 1,
per_page: int = 20
) -> Dict:
corpus_name, subcorpus_name = subcorpus.split(':', 1)
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
cqi_corpus = cqi_client.corpora.get(corpus_name)
cqi_subcorpus = cqi_corpus.subcorpora.get(subcorpus_name)
# Sanity checks
if (
per_page < 1
or page < 1
or (
cqi_subcorpus.size > 0
and page > math.ceil(cqi_subcorpus.size / per_page)
)
):
return {'code': 416, 'msg': 'Range Not Satisfiable'}
offset = (page - 1) * per_page
cutoff = per_page
cqi_results_export = export_subcorpus(
cqi_subcorpus, context=context, cutoff=cutoff, offset=offset)
payload = {}
# the items for the current page
payload['items'] = cqi_results_export.pop('matches')
# the lookups for the items
payload['lookups'] = cqi_results_export
# the total number of items matching the query
payload['total'] = cqi_subcorpus.size
# the number of items to be displayed on a page.
payload['per_page'] = per_page
# The total number of pages
payload['pages'] = math.ceil(payload['total'] / payload['per_page'])
# the current page number (1 indexed)
payload['page'] = page if payload['pages'] > 0 else None
# True if a previous page exists
payload['has_prev'] = payload['page'] > 1 if payload['page'] else False
# True if a next page exists.
payload['has_next'] = payload['page'] < payload['pages'] if payload['page'] else False # noqa
# Number of the previous page.
payload['prev_num'] = payload['page'] - 1 if payload['has_prev'] else None
# Number of the next page
payload['next_num'] = payload['page'] + 1 if payload['has_next'] else None
return payload
def ext_cqp_partial_export_subcorpus(
subcorpus: str,
match_id_list: list,
context: int = 50
) -> Dict:
corpus_name, subcorpus_name = subcorpus.split(':', 1)
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
cqi_corpus = cqi_client.corpora.get(corpus_name)
cqi_subcorpus = cqi_corpus.subcorpora.get(subcorpus_name)
cqi_subcorpus_partial_export = partial_export_subcorpus(cqi_subcorpus, match_id_list, context=context)
return cqi_subcorpus_partial_export
def ext_cqp_export_subcorpus(
subcorpus: str,
context: int = 50
) -> Dict:
corpus_name, subcorpus_name = subcorpus.split(':', 1)
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
cqi_corpus = cqi_client.corpora.get(corpus_name)
cqi_subcorpus = cqi_corpus.subcorpora.get(subcorpus_name)
cqi_subcorpus_export = export_subcorpus(cqi_subcorpus, context=context)
return cqi_subcorpus_export

View File

@ -0,0 +1,133 @@
from cqi.models.corpora import Corpus
from cqi.models.subcorpora import Subcorpus
from typing import Dict, List
from app.models import Corpus
def lookups_by_cpos(corpus: Corpus, cpos_list: List[int]) -> Dict:
lookups = {}
lookups['cpos_lookup'] = {cpos: {} for cpos in cpos_list}
for attr in corpus.positional_attributes.list():
cpos_attr_values = attr.values_by_cpos(cpos_list)
for i, cpos in enumerate(cpos_list):
lookups['cpos_lookup'][cpos][attr.attrs['name']] = \
cpos_attr_values[i]
for attr in corpus.structural_attributes.list():
# We only want to iterate over non subattributes, identifiable by
# attr.attrs['has_values'] == False
if attr.attrs['has_values']:
continue
cpos_attr_ids = attr.ids_by_cpos(cpos_list)
for i, cpos in enumerate(cpos_list):
if cpos_attr_ids[i] == -1:
continue
lookups['cpos_lookup'][cpos][attr.attrs['name']] = cpos_attr_ids[i]
occured_attr_ids = [x for x in set(cpos_attr_ids) if x != -1]
if not occured_attr_ids:
continue
subattrs = corpus.structural_attributes.list(filters={'part_of': attr})
if not subattrs:
continue
lookup_name = f'{attr.attrs["name"]}_lookup'
lookups[lookup_name] = {}
for attr_id in occured_attr_ids:
lookups[lookup_name][attr_id] = {}
for subattr in subattrs:
subattr_name = subattr.attrs['name'][(len(attr.attrs['name']) + 1):] # noqa
for i, subattr_value in enumerate(subattr.values_by_ids(occured_attr_ids)): # noqa
lookups[lookup_name][occured_attr_ids[i]][subattr_name] = subattr_value # noqa
return lookups
def partial_export_subcorpus(
subcorpus: Subcorpus,
match_id_list: List[int],
context: int = 25
) -> Dict:
if subcorpus.size == 0:
return {"matches": []}
match_boundaries = []
for match_id in match_id_list:
if match_id < 0 or match_id >= subcorpus.size:
continue
match_boundaries.append(
(
match_id,
subcorpus.dump(subcorpus.fields['match'], match_id, match_id)[0],
subcorpus.dump(subcorpus.fields['matchend'], match_id, match_id)[0]
)
)
cpos_set = set()
matches = []
for match_boundary in match_boundaries:
match_num, match_start, match_end = match_boundary
c = (match_start, match_end)
if match_start == 0 or context == 0:
lc = None
cpos_list_lbound = match_start
else:
lc_lbound = max(0, (match_start - context))
lc_rbound = match_start - 1
lc = (lc_lbound, lc_rbound)
cpos_list_lbound = lc_lbound
if match_end == (subcorpus.collection.corpus.size - 1) or context == 0:
rc = None
cpos_list_rbound = match_end
else:
rc_lbound = match_end + 1
rc_rbound = min(
(match_end + context),
(subcorpus.collection.corpus.size - 1)
)
rc = (rc_lbound, rc_rbound)
cpos_list_rbound = rc_rbound
match = {'num': match_num, 'lc': lc, 'c': c, 'rc': rc}
matches.append(match)
cpos_set.update(range(cpos_list_lbound, cpos_list_rbound + 1))
lookups = lookups_by_cpos(subcorpus.collection.corpus, list(cpos_set))
return {'matches': matches, **lookups}
def export_subcorpus(
subcorpus: Subcorpus,
context: int = 25,
cutoff: float = float('inf'),
offset: int = 0
) -> Dict:
if subcorpus.size == 0:
return {"matches": []}
first_match = max(0, offset)
last_match = min((offset + cutoff - 1), (subcorpus.size - 1))
match_boundaries = zip(
range(first_match, last_match + 1),
subcorpus.dump(subcorpus.fields['match'], first_match, last_match),
subcorpus.dump(subcorpus.fields['matchend'], first_match, last_match)
)
cpos_set = set()
matches = []
for match_num, match_start, match_end in match_boundaries:
c = (match_start, match_end)
if match_start == 0 or context == 0:
lc = None
cpos_list_lbound = match_start
else:
lc_lbound = max(0, (match_start - context))
lc_rbound = match_start - 1
lc = (lc_lbound, lc_rbound)
cpos_list_lbound = lc_lbound
if match_end == (subcorpus.collection.corpus.size - 1) or context == 0:
rc = None
cpos_list_rbound = match_end
else:
rc_lbound = match_end + 1
rc_rbound = min(
(match_end + context),
(subcorpus.collection.corpus.size - 1)
)
rc = (rc_lbound, rc_rbound)
cpos_list_rbound = rc_rbound
match = {'num': match_num, 'lc': lc, 'c': c, 'rc': rc}
matches.append(match)
cpos_set.update(range(cpos_list_lbound, cpos_list_rbound + 1))
lookups = lookups_by_cpos(subcorpus.collection.corpus, list(cpos_set))
return {'matches': matches, **lookups}

33
app/corpora/decorators.py Normal file
View File

@ -0,0 +1,33 @@
from flask import abort
from flask_login import current_user
from functools import wraps
from app.models import Corpus, CorpusFollowerAssociation
def corpus_follower_permission_required(*permissions):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
corpus_id = kwargs.get('corpus_id')
corpus = Corpus.query.get_or_404(corpus_id)
if not (corpus.user == current_user or current_user.is_administrator()):
cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first()
if cfa is None:
abort(403)
if not all([cfa.role.has_permission(p) for p in permissions]):
abort(403)
return f(*args, **kwargs)
return decorated_function
return decorator
def corpus_owner_or_admin_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
corpus_id = kwargs.get('corpus_id')
corpus = Corpus.query.get_or_404(corpus_id)
if not (corpus.user == current_user or current_user.is_administrator()):
abort(403)
return f(*args, **kwargs)
return decorated_function

45
app/corpora/events.py Normal file
View File

@ -0,0 +1,45 @@
from flask_login import current_user
from flask_socketio import join_room
from app import hashids, socketio
from app.decorators import socketio_login_required
from app.models import Corpus
@socketio.on('GET /corpora/<corpus_id>')
@socketio_login_required
def get_corpus(corpus_hashid):
corpus_id = hashids.decode(corpus_hashid)
corpus = Corpus.query.get(corpus_id)
if corpus is None:
return {'options': {'status': 404, 'statusText': 'Not found'}}
if not (
corpus.is_public
or corpus.user == current_user
or current_user.is_administrator()
):
return {'options': {'status': 403, 'statusText': 'Forbidden'}}
return {
'body': corpus.to_json_serializable(),
'options': {
'status': 200,
'statusText': 'OK',
'headers': {'Content-Type: application/json'}
}
}
@socketio.on('SUBSCRIBE /corpora/<corpus_id>')
@socketio_login_required
def subscribe_corpus(corpus_hashid):
corpus_id = hashids.decode(corpus_hashid)
corpus = Corpus.query.get(corpus_id)
if corpus is None:
return {'options': {'status': 404, 'statusText': 'Not found'}}
if not (
corpus.is_public
or corpus.user == current_user
or current_user.is_administrator()
):
return {'options': {'status': 403, 'statusText': 'Forbidden'}}
join_room(f'/corpora/{corpus.hashid}')
return {'options': {'status': 200, 'statusText': 'OK'}}

View File

@ -0,0 +1,2 @@
from .. import bp
from . import json_routes, routes

View File

@ -0,0 +1,54 @@
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired
from wtforms import (
StringField,
SubmitField,
ValidationError,
IntegerField
)
from wtforms.validators import InputRequired, Length
class CorpusFileBaseForm(FlaskForm):
author = StringField(
'Author',
validators=[InputRequired(), Length(max=255)]
)
publishing_year = IntegerField(
'Publishing year',
validators=[InputRequired()]
)
title = StringField(
'Title',
validators=[InputRequired(), Length(max=255)]
)
address = StringField('Adress', validators=[Length(max=255)])
booktitle = StringField('Booktitle', validators=[Length(max=255)])
chapter = StringField('Chapter', validators=[Length(max=255)])
editor = StringField('Editor', validators=[Length(max=255)])
institution = StringField('Institution', validators=[Length(max=255)])
journal = StringField('Journal', validators=[Length(max=255)])
pages = StringField('Pages', validators=[Length(max=255)])
publisher = StringField('Publisher', validators=[Length(max=255)])
school = StringField('School', validators=[Length(max=255)])
submit = SubmitField()
class CreateCorpusFileForm(CorpusFileBaseForm):
vrt = FileField('File', validators=[FileRequired()])
def validate_vrt(self, field):
if not field.data.filename.lower().endswith('.vrt'):
raise ValidationError('VRT files only!')
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'create-corpus-file-form'
super().__init__(*args, **kwargs)
class UpdateCorpusFileForm(CorpusFileBaseForm):
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'update-corpus-file-form'
super().__init__(*args, **kwargs)

View File

@ -0,0 +1,30 @@
from flask import abort, current_app
from threading import Thread
from app import db
from app.decorators import content_negotiation
from app.models import CorpusFile
from ..decorators import corpus_follower_permission_required
from . import bp
@bp.route('/<hashid:corpus_id>/files/<hashid:corpus_file_id>', methods=['DELETE'])
@corpus_follower_permission_required('MANAGE_FILES')
@content_negotiation(produces='application/json')
def delete_corpus_file(corpus_id, corpus_file_id):
def _delete_corpus_file(app, corpus_file_id):
with app.app_context():
corpus_file = CorpusFile.query.get(corpus_file_id)
corpus_file.delete()
db.session.commit()
corpus_file = CorpusFile.query.filter_by(corpus_id=corpus_id, id=corpus_file_id).first_or_404()
thread = Thread(
target=_delete_corpus_file,
args=(current_app._get_current_object(), corpus_file.id)
)
thread.start()
response_data = {
'message': f'Corpus File "{corpus_file.title}" marked for deletion',
'category': 'corpus'
}
return response_data, 202

100
app/corpora/files/routes.py Normal file
View File

@ -0,0 +1,100 @@
from flask import (
abort,
flash,
redirect,
render_template,
send_from_directory,
url_for
)
from flask_breadcrumbs import register_breadcrumb
import os
from app import db
from app.models import Corpus, CorpusFile, CorpusStatus
from ..decorators import corpus_follower_permission_required
from ..utils import corpus_endpoint_arguments_constructor as corpus_eac
from . import bp
from .forms import CreateCorpusFileForm, UpdateCorpusFileForm
from .utils import corpus_file_dynamic_list_constructor as corpus_file_dlc
@bp.route('/<hashid:corpus_id>/files')
@register_breadcrumb(bp, '.entity.files', 'Files', endpoint_arguments_constructor=corpus_eac)
def corpus_files(corpus_id):
return redirect(url_for('.corpus', _anchor='files', corpus_id=corpus_id))
@bp.route('/<hashid:corpus_id>/files/create', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.entity.files.create', 'Create', endpoint_arguments_constructor=corpus_eac)
@corpus_follower_permission_required('MANAGE_FILES')
def create_corpus_file(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id)
form = CreateCorpusFileForm()
if form.is_submitted():
if not form.validate():
response = {'errors': form.errors}
return response, 400
try:
corpus_file = CorpusFile.create(
form.vrt.data,
address=form.address.data,
author=form.author.data,
booktitle=form.booktitle.data,
chapter=form.chapter.data,
editor=form.editor.data,
institution=form.institution.data,
journal=form.journal.data,
pages=form.pages.data,
publisher=form.publisher.data,
publishing_year=form.publishing_year.data,
school=form.school.data,
title=form.title.data,
mimetype='application/vrt+xml',
corpus=corpus
)
except (AttributeError, OSError):
abort(500)
corpus.status = CorpusStatus.UNPREPARED
db.session.commit()
flash(f'Corpus File "{corpus_file.filename}" added', category='corpus')
return '', 201, {'Location': corpus.url}
return render_template(
'corpora/files/create.html.j2',
title='Add corpus file',
form=form,
corpus=corpus
)
@bp.route('/<hashid:corpus_id>/files/<hashid:corpus_file_id>', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.entity.files.entity', '', dynamic_list_constructor=corpus_file_dlc)
@corpus_follower_permission_required('MANAGE_FILES')
def corpus_file(corpus_id, corpus_file_id):
corpus_file = CorpusFile.query.filter_by(corpus_id=corpus_id, id=corpus_file_id).first_or_404()
form = UpdateCorpusFileForm(data=corpus_file.to_json_serializeable())
if form.validate_on_submit():
form.populate_obj(corpus_file)
if db.session.is_modified(corpus_file):
corpus_file.corpus.status = CorpusStatus.UNPREPARED
db.session.commit()
flash(f'Corpus file "{corpus_file.filename}" updated', category='corpus')
return redirect(corpus_file.corpus.url)
return render_template(
'corpora/files/corpus_file.html.j2',
title='Edit corpus file',
form=form,
corpus=corpus_file.corpus,
corpus_file=corpus_file
)
@bp.route('/<hashid:corpus_id>/files/<hashid:corpus_file_id>/download')
@corpus_follower_permission_required('VIEW')
def download_corpus_file(corpus_id, corpus_file_id):
corpus_file = CorpusFile.query.filter_by(corpus_id=corpus_id, id=corpus_file_id).first_or_404()
return send_from_directory(
os.path.dirname(corpus_file.path),
os.path.basename(corpus_file.path),
as_attachment=True,
attachment_filename=corpus_file.filename,
mimetype=corpus_file.mimetype
)

View File

@ -0,0 +1,15 @@
from flask import request, url_for
from app.models import CorpusFile
from ..utils import corpus_endpoint_arguments_constructor as corpus_eac
def corpus_file_dynamic_list_constructor():
corpus_id = request.view_args['corpus_id']
corpus_file_id = request.view_args['corpus_file_id']
corpus_file = CorpusFile.query.filter_by(corpus_id=corpus_id, id=corpus_file_id).first_or_404()
return [
{
'text': f'{corpus_file.author}: {corpus_file.title} ({corpus_file.publishing_year})',
'url': url_for('.corpus_file', corpus_id=corpus_id, corpus_file_id=corpus_file_id)
}
]

View File

@ -0,0 +1,2 @@
from .. import bp
from . import json_routes

View File

@ -0,0 +1,76 @@
from flask import abort, flash, jsonify, make_response, request
from flask_login import current_user
from app import db
from app.decorators import content_negotiation
from app.models import (
Corpus,
CorpusFollowerAssociation,
CorpusFollowerRole,
User
)
from ..decorators import corpus_follower_permission_required
from . import bp
# @bp.route('/<hashid:corpus_id>/followers', methods=['POST'])
# @corpus_follower_permission_required('MANAGE_FOLLOWERS')
# @content_negotiation(consumes='application/json', produces='application/json')
# def create_corpus_followers(corpus_id):
# usernames = request.json
# if not (isinstance(usernames, list) or all(isinstance(u, str) for u in usernames)):
# abort(400)
# corpus = Corpus.query.get_or_404(corpus_id)
# for username in usernames:
# user = User.query.filter_by(username=username, is_public=True).first_or_404()
# user.follow_corpus(corpus)
# db.session.commit()
# response_data = {
# 'message': f'Users are now following "{corpus.title}"',
# 'category': 'corpus'
# }
# return response_data, 200
# @bp.route('/<hashid:corpus_id>/followers/<hashid:follower_id>/role', methods=['PUT'])
# @corpus_follower_permission_required('MANAGE_FOLLOWERS')
# @content_negotiation(consumes='application/json', produces='application/json')
# def update_corpus_follower_role(corpus_id, follower_id):
# role_name = request.json
# if not isinstance(role_name, str):
# abort(400)
# cfr = CorpusFollowerRole.query.filter_by(name=role_name).first()
# if cfr is None:
# abort(400)
# cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=follower_id).first_or_404()
# cfa.role = cfr
# db.session.commit()
# response_data = {
# 'message': f'User "{cfa.follower.username}" is now {cfa.role.name}',
# 'category': 'corpus'
# }
# return response_data, 200
# @bp.route('/<hashid:corpus_id>/followers/<hashid:follower_id>', methods=['DELETE'])
# def delete_corpus_follower(corpus_id, follower_id):
# cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=follower_id).first_or_404()
# if not (
# current_user.id == follower_id
# or current_user == cfa.corpus.user
# or CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first().role.has_permission('MANAGE_FOLLOWERS')
# or current_user.is_administrator()):
# abort(403)
# if current_user.id == follower_id:
# flash(f'You are no longer following "{cfa.corpus.title}"', 'corpus')
# response = make_response()
# response.status_code = 204
# else:
# response_data = {
# 'message': f'"{cfa.follower.username}" is not following "{cfa.corpus.title}" anymore',
# 'category': 'corpus'
# }
# response = jsonify(response_data)
# response.status_code = 200
# cfa.follower.unfollow_corpus(cfa.corpus)
# db.session.commit()
# return response

33
app/corpora/forms.py Normal file
View File

@ -0,0 +1,33 @@
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, TextAreaField
from wtforms.validators import InputRequired, Length
class CorpusBaseForm(FlaskForm):
description = TextAreaField(
'Description',
validators=[InputRequired(), Length(max=255)]
)
title = StringField('Title', validators=[InputRequired(), Length(max=32)])
submit = SubmitField()
class CreateCorpusForm(CorpusBaseForm):
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'create-corpus-form'
super().__init__(*args, **kwargs)
class UpdateCorpusForm(CorpusBaseForm):
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'update-corpus-form'
super().__init__(*args, **kwargs)
class ImportCorpusForm(FlaskForm):
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'import-corpus-form'
super().__init__(*args, **kwargs)

125
app/corpora/json_routes.py Normal file
View File

@ -0,0 +1,125 @@
from datetime import datetime
from flask import abort, current_app, request, url_for
from flask_login import current_user
from threading import Thread
from app import db
from app.decorators import content_negotiation
from app.models import Corpus, CorpusFollowerRole
from . import bp
from .decorators import corpus_follower_permission_required, corpus_owner_or_admin_required
import nltk
from string import punctuation
@bp.route('/<hashid:corpus_id>', methods=['DELETE'])
@corpus_owner_or_admin_required
@content_negotiation(produces='application/json')
def delete_corpus(corpus_id):
def _delete_corpus(app, corpus_id):
with app.app_context():
corpus = Corpus.query.get(corpus_id)
corpus.delete()
db.session.commit()
corpus = Corpus.query.get_or_404(corpus_id)
thread = Thread(
target=_delete_corpus,
args=(current_app._get_current_object(), corpus.id)
)
thread.start()
response_data = {
'message': f'Corpus "{corpus.title}" marked for deletion',
'category': 'corpus'
}
return response_data, 200
@bp.route('/<hashid:corpus_id>/build', methods=['POST'])
@corpus_follower_permission_required('MANAGE_FILES')
@content_negotiation(produces='application/json')
def build_corpus(corpus_id):
def _build_corpus(app, corpus_id):
with app.app_context():
corpus = Corpus.query.get(corpus_id)
corpus.build()
db.session.commit()
corpus = Corpus.query.get_or_404(corpus_id)
if len(corpus.files.all()) == 0:
abort(409)
thread = Thread(
target=_build_corpus,
args=(current_app._get_current_object(), corpus_id)
)
thread.start()
response_data = {
'message': f'Corpus "{corpus.title}" marked for building',
'category': 'corpus'
}
return response_data, 202
@bp.route('/stopwords')
@content_negotiation(produces='application/json')
def get_stopwords():
nltk.download('stopwords')
languages = ["german", "english", "catalan", "greek", "spanish", "french", "italian", "russian", "chinese"]
stopwords = {}
for language in languages:
stopwords[language] = nltk.corpus.stopwords.words(language)
stopwords['punctuation'] = list(punctuation) + ['', '|']
stopwords['user_stopwords'] = []
response_data = stopwords
return response_data, 202
# @bp.route('/<hashid:corpus_id>/generate-share-link', methods=['POST'])
# @corpus_follower_permission_required('MANAGE_FOLLOWERS')
# @content_negotiation(consumes='application/json', produces='application/json')
# def generate_corpus_share_link(corpus_id):
# data = request.json
# if not isinstance(data, dict):
# abort(400)
# expiration = data.get('expiration')
# if not isinstance(expiration, str):
# abort(400)
# role_name = data.get('role')
# if not isinstance(role_name, str):
# abort(400)
# expiration_date = datetime.strptime(expiration, '%b %d, %Y')
# cfr = CorpusFollowerRole.query.filter_by(name=role_name).first()
# if cfr is None:
# abort(400)
# corpus = Corpus.query.get_or_404(corpus_id)
# token = current_user.generate_follow_corpus_token(corpus.hashid, role_name, expiration_date)
# corpus_share_link = url_for(
# 'corpora.follow_corpus',
# corpus_id=corpus_id,
# token=token,
# _external=True
# )
# response_data = {
# 'message': 'Corpus share link generated',
# 'category': 'corpus',
# 'corpusShareLink': corpus_share_link
# }
# return response_data, 200
# @bp.route('/<hashid:corpus_id>/is_public', methods=['PUT'])
# @corpus_owner_or_admin_required
# @content_negotiation(consumes='application/json', produces='application/json')
# def update_corpus_is_public(corpus_id):
# is_public = request.json
# if not isinstance(is_public, bool):
# abort(400)
# corpus = Corpus.query.get_or_404(corpus_id)
# corpus.is_public = is_public
# db.session.commit()
# response_data = {
# 'message': (
# f'Corpus "{corpus.title}" is now'
# f' {"public" if is_public else "private"}'
# ),
# 'category': 'corpus'
# }
# return response_data, 200

121
app/corpora/routes.py Normal file
View File

@ -0,0 +1,121 @@
from flask import abort, flash, redirect, render_template, url_for
from flask_breadcrumbs import register_breadcrumb
from flask_login import current_user
from app import db
from app.models import (
Corpus,
CorpusFollowerAssociation,
CorpusFollowerRole,
User
)
from . import bp
from .decorators import corpus_follower_permission_required
from .forms import CreateCorpusForm
from .utils import (
corpus_endpoint_arguments_constructor as corpus_eac,
corpus_dynamic_list_constructor as corpus_dlc
)
@bp.route('')
@register_breadcrumb(bp, '.', '<i class="nopaque-icons left">I</i>My Corpora')
def corpora():
return redirect(url_for('main.dashboard', _anchor='corpora'))
@bp.route('/create', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.create', 'Create')
def create_corpus():
form = CreateCorpusForm()
if form.validate_on_submit():
try:
corpus = Corpus.create(
title=form.title.data,
description=form.description.data,
user=current_user
)
except OSError:
abort(500)
db.session.commit()
flash(f'Corpus "{corpus.title}" created', 'corpus')
return redirect(corpus.url)
return render_template(
'corpora/create.html.j2',
title='Create corpus',
form=form
)
@bp.route('/<hashid:corpus_id>')
@register_breadcrumb(bp, '.entity', '', dynamic_list_constructor=corpus_dlc)
def corpus(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id)
cfrs = CorpusFollowerRole.query.all()
# TODO: Better solution for filtering admin
users = User.query.filter(User.is_public == True, User.id != current_user.id, User.id != corpus.user.id, User.role_id < 4).all()
cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first()
if cfa is None:
if corpus.user == current_user or current_user.is_administrator():
cfr = CorpusFollowerRole.query.filter_by(name='Administrator').first()
else:
cfr = CorpusFollowerRole.query.filter_by(name='Anonymous').first()
else:
cfr = cfa.role
if corpus.user == current_user or current_user.is_administrator():
return render_template(
'corpora/corpus.html.j2',
title=corpus.title,
corpus=corpus,
cfr=cfr,
cfrs=cfrs,
users = users
)
if (current_user.is_following_corpus(corpus) or corpus.is_public):
abort(404)
# cfas = CorpusFollowerAssociation.query.filter(Corpus.id == corpus_id, CorpusFollowerAssociation.follower_id != corpus.user.id).all()
# return render_template(
# 'corpora/public_corpus.html.j2',
# title=corpus.title,
# corpus=corpus,
# cfrs=cfrs,
# cfr=cfr,
# cfas=cfas,
# users = users
# )
abort(403)
@bp.route('/<hashid:corpus_id>/analysis')
@corpus_follower_permission_required('VIEW')
@register_breadcrumb(bp, '.entity.analysis', 'Analysis', endpoint_arguments_constructor=corpus_eac)
def analysis(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id)
return render_template(
'corpora/analysis.html.j2',
corpus=corpus,
title=f'Analyse Corpus {corpus.title}'
)
# @bp.route('/<hashid:corpus_id>/follow/<token>')
# def follow_corpus(corpus_id, token):
# corpus = Corpus.query.get_or_404(corpus_id)
# if current_user.follow_corpus_by_token(token):
# db.session.commit()
# flash(f'You are following "{corpus.title}" now', category='corpus')
# return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
# abort(403)
@bp.route('/import', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.import', 'Import')
def import_corpus():
abort(503)
@bp.route('/<hashid:corpus_id>/export')
@corpus_follower_permission_required('VIEW')
@register_breadcrumb(bp, '.entity.export', 'Export', endpoint_arguments_constructor=corpus_eac)
def export_corpus(corpus_id):
abort(503)

17
app/corpora/utils.py Normal file
View File

@ -0,0 +1,17 @@
from flask import request, url_for
from app.models import Corpus
def corpus_endpoint_arguments_constructor():
return {'corpus_id': request.view_args['corpus_id']}
def corpus_dynamic_list_constructor():
corpus_id = request.view_args['corpus_id']
corpus = Corpus.query.get_or_404(corpus_id)
return [
{
'text': f'<i class="material-icons left">book</i>{corpus.title}',
'url': url_for('.corpus', corpus_id=corpus_id)
}
]

11
app/daemon/__init__.py Normal file
View File

@ -0,0 +1,11 @@
from app import db
from flask import Flask
from .corpus_utils import check_corpora
from .job_utils import check_jobs
def daemon(app: Flask):
with app.app_context():
check_corpora()
check_jobs()
db.session.commit()

225
app/daemon/corpus_utils.py Normal file
View File

@ -0,0 +1,225 @@
from app import docker_client
from app.models import Corpus, CorpusStatus
from flask import current_app
import docker
import os
import shutil
def check_corpora():
corpora = Corpus.query.all()
for corpus in [x for x in corpora if x.status == CorpusStatus.SUBMITTED]:
_create_build_corpus_service(corpus)
for corpus in [x for x in corpora if x.status in [CorpusStatus.QUEUED, CorpusStatus.BUILDING]]:
_checkout_build_corpus_service(corpus)
for corpus in [x for x in corpora if x.status == CorpusStatus.BUILT and x.num_analysis_sessions > 0]:
corpus.status = CorpusStatus.STARTING_ANALYSIS_SESSION
for corpus in [x for x in corpora if x.status == CorpusStatus.RUNNING_ANALYSIS_SESSION and x.num_analysis_sessions == 0]:
corpus.status = CorpusStatus.CANCELING_ANALYSIS_SESSION
for corpus in [x for x in corpora if x.status == CorpusStatus.RUNNING_ANALYSIS_SESSION]:
_checkout_analysing_corpus_container(corpus)
for corpus in [x for x in corpora if x.status == CorpusStatus.STARTING_ANALYSIS_SESSION]:
_create_cqpserver_container(corpus)
for corpus in [x for x in corpora if x.status == CorpusStatus.CANCELING_ANALYSIS_SESSION]:
_remove_cqpserver_container(corpus)
def _create_build_corpus_service(corpus):
''' # Docker service settings # '''
''' ## Command ## '''
command = ['bash', '-c']
command.append(
f'mkdir /corpora/data/nopaque-{corpus.hashid.lower()}'
' && '
'cwb-encode'
' -c utf8'
f' -d /corpora/data/nopaque-{corpus.hashid.lower()}'
' -f /root/files/corpus.vrt'
f' -R /usr/local/share/cwb/registry/nopaque-{corpus.hashid.lower()}'
' -P pos -P lemma -P simple_pos'
' -S ent:0+type -S s:0'
' -S text:0+address+author+booktitle+chapter+editor+institution+journal+pages+publisher+publishing_year+school+title'
' -xsB -9'
' && '
f'cwb-make -V NOPAQUE-{corpus.hashid.upper()}'
)
''' ## Constraints ## '''
constraints = ['node.role==worker']
''' ## Image ## '''
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}cwb:r1702'
''' ## Labels ## '''
labels = {
'origin': current_app.config['SERVER_NAME'],
'type': 'corpus.build',
'corpus_id': str(corpus.id)
}
''' ## Mounts ## '''
mounts = []
''' ### Data mount ### '''
data_mount_source = os.path.join(corpus.path, 'cwb', 'data')
data_mount_target = '/corpora/data'
data_mount = f'{data_mount_source}:{data_mount_target}:rw'
# Make sure that their is no data in the data directory
shutil.rmtree(data_mount_source, ignore_errors=True)
os.makedirs(data_mount_source)
mounts.append(data_mount)
''' ### File mount ### '''
file_mount_source = os.path.join(corpus.path, 'cwb', 'corpus.vrt')
file_mount_target = '/root/files/corpus.vrt'
file_mount = f'{file_mount_source}:{file_mount_target}:ro'
mounts.append(file_mount)
''' ### Registry mount ### '''
registry_mount_source = os.path.join(corpus.path, 'cwb', 'registry')
registry_mount_target = '/usr/local/share/cwb/registry'
registry_mount = f'{registry_mount_source}:{registry_mount_target}:rw'
# Make sure that their is no data in the registry directory
shutil.rmtree(registry_mount_source, ignore_errors=True)
os.makedirs(registry_mount_source)
mounts.append(registry_mount)
''' ## Name ## '''
name = f'build-corpus_{corpus.id}'
''' ## Restart policy ## '''
restart_policy = docker.types.RestartPolicy()
try:
docker_client.services.create(
image,
command=command,
constraints=constraints,
labels=labels,
mounts=mounts,
name=name,
restart_policy=restart_policy,
user='0:0'
)
except docker.errors.DockerException as e:
current_app.logger.error(f'Create service "{name}" failed: {e}')
return
corpus.status = CorpusStatus.QUEUED
def _checkout_build_corpus_service(corpus):
service_name = f'build-corpus_{corpus.id}'
try:
service = docker_client.services.get(service_name)
except docker.errors.NotFound as e:
current_app.logger.error(f'Get service "{service_name}" failed: {e}')
corpus.status = CorpusStatus.FAILED
return
except docker.errors.DockerException as e:
current_app.logger.error(f'Get service "{service_name}" failed: {e}')
service_tasks = service.tasks()
if not service_tasks:
return
task_state = service_tasks[0].get('Status').get('State')
if corpus.status == CorpusStatus.QUEUED and task_state != 'pending':
corpus.status = CorpusStatus.BUILDING
return
elif corpus.status == CorpusStatus.BUILDING and task_state == 'complete':
corpus.status = CorpusStatus.BUILT
elif corpus.status == CorpusStatus.BUILDING and task_state == 'failed':
corpus.status = CorpusStatus.FAILED
else:
return
try:
service.remove()
except docker.errors.DockerException as e:
current_app.logger.error(f'Remove service "{service_name}" failed: {e}')
def _create_cqpserver_container(corpus):
''' # Docker container settings # '''
''' ## Command ## '''
command = []
command.append(
'echo "host *;" > cqpserver.init'
' && '
'echo "user anonymous \\"\\";" >> cqpserver.init'
' && '
'cqpserver -I cqpserver.init'
)
''' ## Detach ## '''
detach = True
''' ## Entrypoint ## '''
entrypoint = ['bash', '-c']
''' ## Image ## '''
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}cwb:r1702'
''' ## Name ## '''
name = f'cqpserver_{corpus.id}'
''' ## Network ## '''
network = f'{current_app.config["DOCKER_NETWORK_NAME"]}'
''' ## Volumes ## '''
volumes = []
''' ### Corpus data volume ### '''
data_volume_source = os.path.join(corpus.path, 'cwb', 'data')
data_volume_target = '/corpora/data'
# data_volume_source = os.path.join(corpus.path, 'cwb', 'data', f'nopaque_{corpus.id}')
# data_volume_target = f'/corpora/data/nopaque_{corpus.hashid.lower()}'
data_volume = f'{data_volume_source}:{data_volume_target}:rw'
volumes.append(data_volume)
''' ### Corpus registry volume ### '''
registry_volume_source = os.path.join(corpus.path, 'cwb', 'registry')
registry_volume_target = '/usr/local/share/cwb/registry'
# registry_volume_source = os.path.join(corpus.path, 'cwb', 'registry', f'nopaque_{corpus.id}')
# registry_volume_target = f'/usr/local/share/cwb/registry/nopaque_{corpus.hashid.lower()}'
registry_volume = f'{registry_volume_source}:{registry_volume_target}:rw'
volumes.append(registry_volume)
# Check if a cqpserver container already exists. If this is the case,
# remove it and create a new one
try:
container = docker_client.containers.get(name)
except docker.errors.NotFound:
pass
except docker.errors.DockerException as e:
current_app.logger.error(f'Get container "{name}" failed: {e}')
return
else:
try:
container.remove(force=True)
except docker.errors.DockerException as e:
current_app.logger.error(f'Remove container "{name}" failed: {e}')
return
try:
docker_client.containers.run(
image,
command=command,
detach=detach,
entrypoint=entrypoint,
name=name,
network=network,
user='0:0',
volumes=volumes
)
except docker.errors.ImageNotFound as e:
current_app.logger.error(
f'Run container "{name}" failed '
f'due to "docker.errors.ImageNotFound" error: {e}'
)
corpus.status = CorpusStatus.FAILED
return
except docker.errors.DockerException as e:
current_app.logger.error(f'Run container "{name}" failed: {e}')
return
corpus.status = CorpusStatus.RUNNING_ANALYSIS_SESSION
def _checkout_analysing_corpus_container(corpus):
container_name = f'cqpserver_{corpus.id}'
try:
docker_client.containers.get(container_name)
except docker.errors.NotFound as e:
current_app.logger.error(f'Get container "{container_name}" failed: {e}')
corpus.num_analysis_sessions = 0
corpus.status = CorpusStatus.BUILT
except docker.errors.DockerException as e:
current_app.logger.error(f'Get container "{container_name}" failed: {e}')
def _remove_cqpserver_container(corpus):
container_name = f'cqpserver_{corpus.id}'
try:
container = docker_client.containers.get(container_name)
except docker.errors.NotFound:
corpus.status = CorpusStatus.BUILT
return
except docker.errors.DockerException as e:
current_app.logger.error(f'Get container "{container_name}" failed: {e}')
return
try:
container.remove(force=True)
except docker.errors.DockerException as e:
current_app.logger.error(f'Remove container "{container_name}" failed: {e}')

234
app/daemon/job_utils.py Normal file
View File

@ -0,0 +1,234 @@
from app import db, docker_client, hashids
from app.models import (
Job,
JobResult,
JobStatus,
TesseractOCRPipelineModel,
SpaCyNLPPipelineModel
)
from datetime import datetime
from flask import current_app
from werkzeug.utils import secure_filename
import docker
import json
import os
import shutil
def check_jobs():
jobs = Job.query.all()
for job in [x for x in jobs if x.status == JobStatus.SUBMITTED]:
_create_job_service(job)
for job in [x for x in jobs if x.status in [JobStatus.QUEUED, JobStatus.RUNNING]]:
_checkout_job_service(job)
for job in [x for x in jobs if x.status == JobStatus.CANCELING]:
_remove_job_service(job)
def _create_job_service(job):
''' # Docker service settings # '''
''' ## Service specific settings ## '''
if job.service == 'file-setup-pipeline':
mem_mb = 512
n_cores = 2
executable = 'file-setup-pipeline'
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}file-setup-pipeline:v{job.service_version}'
elif job.service == 'tesseract-ocr-pipeline':
mem_mb = 1024
n_cores = 4
executable = 'tesseract-ocr-pipeline'
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}tesseract-ocr-pipeline:v{job.service_version}'
elif job.service == 'transkribus-htr-pipeline':
mem_mb = 1024
n_cores = 4
executable = 'transkribus-htr-pipeline'
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}transkribus-htr-pipeline:v{job.service_version}'
elif job.service == 'spacy-nlp-pipeline':
mem_mb = 1024
n_cores = 1
executable = 'spacy-nlp-pipeline'
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}spacy-nlp-pipeline:v{job.service_version}'
''' ## Command ## '''
command = f'{executable} -i /input -o /output'
command += ' --log-dir /logs'
command += f' --mem-mb {mem_mb}'
command += f' --n-cores {n_cores}'
if job.service == 'spacy-nlp-pipeline':
model_id = hashids.decode(job.service_args['model'])
model = SpaCyNLPPipelineModel.query.get(model_id)
if model is None:
job.status = JobStatus.FAILED
return
command += f' -m {model.pipeline_name}'
if 'encoding_detection' in job.service_args and job.service_args['encoding_detection']:
command += ' --check-encoding'
elif job.service == 'tesseract-ocr-pipeline':
command += f' -m {job.service_args["model"]}'
if 'binarization' in job.service_args and job.service_args['binarization']:
command += ' --binarize'
if 'ocropus_nlbin_threshold' in job.service_args and job.service_args['ocropus_nlbin_threshold']:
value = job.service_args['ocropus_nlbin_threshold']
command += f' --ocropus-nlbin-threshold {value}'
elif job.service == 'transkribus-htr-pipeline':
transkribus_htr_pipeline_model_id = job.service_args['model']
command += f' -m {transkribus_htr_pipeline_model_id}'
readcoop_username = current_app.config.get('NOPAQUE_READCOOP_USERNAME')
command += f' --readcoop-username "{readcoop_username}"'
readcoop_password = current_app.config.get('NOPAQUE_READCOOP_PASSWORD')
command += f' --readcoop-password "{readcoop_password}"'
if 'binarization' in job.service_args and job.service_args['binarization']:
command += ' --binarize'
''' ## Constraints ## '''
constraints = ['node.role==worker']
''' ## Labels ## '''
labels = {
'origin': current_app.config['SERVER_NAME'],
'type': 'job',
'job_id': str(job.id)
}
''' ## Mounts ## '''
mounts = []
''' ### Input mount(s) ### '''
input_mount_target_base = '/input'
if job.service == 'file-setup-pipeline':
input_mount_target_base += f'/{secure_filename(job.title)}'
for job_input in job.inputs:
input_mount_source = job_input.path
input_mount_target = f'{input_mount_target_base}/{job_input.filename}'
input_mount = f'{input_mount_source}:{input_mount_target}:ro'
mounts.append(input_mount)
if job.service == 'tesseract-ocr-pipeline':
if isinstance(job.service_args['model'], str):
model_id = hashids.decode(job.service_args['model'])
elif isinstance(job.service_args['model'], int):
model_id = job.service_args['model']
else:
job.status = JobStatus.FAILED
return
model = TesseractOCRPipelineModel.query.get(model_id)
if model is None:
job.status = JobStatus.FAILED
return
models_mount_source = model.path
models_mount_target = f'/usr/local/share/tessdata/{model.id}.traineddata'
models_mount = f'{models_mount_source}:{models_mount_target}:ro'
mounts.append(models_mount)
elif job.service == 'spacy-nlp-pipeline':
model_id = hashids.decode(job.service_args['model'])
model = SpaCyNLPPipelineModel.query.get(model_id)
if model is None:
job.status = JobStatus.FAILED
return
models_mount_source = model.path
models_mount_target = f'/usr/local/share/spacy/models/{model.filename}'
models_mount = f'{models_mount_source}:{models_mount_target}:ro'
mounts.append(models_mount)
''' ### Output mount ### '''
output_mount_source = os.path.join(job.path, 'results')
output_mount_target = '/output'
output_mount = f'{output_mount_source}:{output_mount_target}:rw'
# Make sure that their is no data in the output directory
shutil.rmtree(output_mount_source, ignore_errors=True)
os.makedirs(output_mount_source)
mounts.append(output_mount)
''' ### Pipeline data mount ### '''
pyflow_data_mount_source = os.path.join(job.path, 'pipeline_data')
pyflow_data_mount_target = '/logs/pyflow.data'
pyflow_data_mount = f'{pyflow_data_mount_source}:{pyflow_data_mount_target}:rw'
# Make sure that their is no data in the output directory
shutil.rmtree(pyflow_data_mount_source, ignore_errors=True)
os.makedirs(pyflow_data_mount_source)
mounts.append(pyflow_data_mount)
''' ## Name ## '''
name = f'job_{job.id}'
''' ## Resources ## '''
resources = docker.types.Resources(
cpu_reservation=n_cores * (10 ** 9),
mem_reservation=mem_mb * (10 ** 6)
)
''' ## Restart policy ## '''
restart_policy = docker.types.RestartPolicy()
try:
docker_client.services.create(
image,
command=command,
constraints=constraints,
labels=labels,
mounts=mounts,
name=name,
resources=resources,
restart_policy=restart_policy,
user='0:0'
)
except docker.errors.DockerException as e:
current_app.logger.error(f'Create service "{name}" failed: {e}')
return
job.status = JobStatus.QUEUED
def _checkout_job_service(job):
service_name = f'job_{job.id}'
try:
service = docker_client.services.get(service_name)
except docker.errors.NotFound as e:
current_app.logger.error(f'Get service "{service_name}" failed: {e}')
job.status = JobStatus.FAILED
return
except docker.errors.DockerException as e:
current_app.logger.error(f'Get service "{service_name}" failed: {e}')
return
service_tasks = service.tasks()
if not service_tasks:
return
task_state = service_tasks[0].get('Status').get('State')
if job.status == JobStatus.QUEUED and task_state != 'pending':
job.status = JobStatus.RUNNING
return
elif job.status == JobStatus.RUNNING and task_state == 'complete':
job.status = JobStatus.COMPLETED
results_dir = os.path.join(job.path, 'results')
with open(os.path.join(results_dir, 'outputs.json')) as f:
outputs = json.load(f)
for output in outputs:
filename = os.path.basename(output['file'])
job_result = JobResult(
filename=filename,
job=job,
mimetype=output['mimetype']
)
if 'description' in output:
job_result.description = output['description']
db.session.add(job_result)
db.session.flush(objects=[job_result])
db.session.refresh(job_result)
os.rename(
os.path.join(results_dir, output['file']),
job_result.path
)
elif job.status == JobStatus.RUNNING and task_state == 'failed':
job.status = JobStatus.FAILED
else:
return
job.end_date = datetime.utcnow()
try:
service.remove()
except docker.errors.DockerException as e:
current_app.logger.error(f'Remove service "{service_name}" failed: {e}')
def _remove_job_service(job):
service_name = f'job_{job.id}'
try:
service = docker_client.services.get(service_name)
except docker.errors.NotFound:
job.status = JobStatus.CANCELED
return
except docker.errors.DockerException as e:
current_app.logger.error(f'Get service "{service_name}" failed: {e}')
return
try:
service.update(mounts=None)
except docker.errors.DockerException as e:
current_app.logger.error(f'Update service "{service_name}" failed: {e}')
return
try:
service.remove()
except docker.errors.DockerException as e:
current_app.logger.error(f'Remove "{service_name}" service failed: {e}')

99
app/decorators.py Normal file
View File

@ -0,0 +1,99 @@
from flask import abort, current_app, request
from flask_login import current_user
from functools import wraps
from threading import Thread
from typing import List, Union
from werkzeug.exceptions import NotAcceptable
from app.models import Permission
def permission_required(permission):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.can(permission):
abort(403)
return f(*args, **kwargs)
return decorated_function
return decorator
def admin_required(f):
return permission_required(Permission.ADMINISTRATE)(f)
def socketio_login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if current_user.is_authenticated:
return f(*args, **kwargs)
else:
return {'code': 401, 'msg': 'Unauthorized'}
return decorated_function
def socketio_permission_required(permission):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.can(permission):
return {'code': 403, 'msg': 'Forbidden'}
return f(*args, **kwargs)
return decorated_function
return decorator
def socketio_admin_required(f):
return socketio_permission_required(Permission.ADMINISTRATE)(f)
def background(f):
'''
' This decorator executes a function in a Thread.
' Decorated functions need to be executed within a code block where an
' app context exists.
'
' NOTE: An app object is passed as a keyword argument to the decorated
' function.
'''
@wraps(f)
def wrapped(*args, **kwargs):
kwargs['app'] = current_app._get_current_object()
thread = Thread(target=f, args=args, kwargs=kwargs)
thread.start()
return thread
return wrapped
def content_negotiation(
produces: Union[str, List[str], None] = None,
consumes: Union[str, List[str], None] = None
):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
provided = request.mimetype
if consumes is None:
consumeables = None
elif isinstance(consumes, str):
consumeables = {consumes}
elif isinstance(consumes, list) and all(isinstance(x, str) for x in consumes):
consumeables = {*consumes}
else:
raise TypeError()
accepted = {*request.accept_mimetypes.values()}
if produces is None:
produceables = None
elif isinstance(produces, str):
produceables = {produces}
elif isinstance(produces, list) and all(isinstance(x, str) for x in produces):
produceables = {*produces}
else:
raise TypeError()
if produceables is not None and len(produceables & accepted) == 0:
raise NotAcceptable()
if consumeables is not None and provided not in consumeables:
raise NotAcceptable()
return f(*args, **kwargs)
return decorated_function
return decorator

25
app/email.py Normal file
View File

@ -0,0 +1,25 @@
from flask import current_app, render_template
from flask_mail import Message
from threading import Thread
from app import mail
def create_message(recipient, subject, template, **kwargs):
subject_prefix: str = current_app.config['NOPAQUE_MAIL_SUBJECT_PREFIX']
msg: Message = Message(
body=render_template(f'{template}.txt.j2', **kwargs),
html=render_template(f'{template}.html.j2', **kwargs),
recipients=[recipient],
subject=f'{subject_prefix} {subject}'
)
return msg
def send(msg, *args, **kwargs):
def _send(app, msg):
with app.app_context():
mail.send(msg)
thread = Thread(target=_send, args=[current_app._get_current_object(), msg])
thread.start()
return thread

5
app/errors/__init__.py Normal file
View File

@ -0,0 +1,5 @@
from flask import Blueprint
bp = Blueprint('errors', __name__)
from . import handlers

14
app/errors/handlers.py Normal file
View File

@ -0,0 +1,14 @@
from flask import jsonify, render_template, request
from werkzeug.exceptions import HTTPException
from . import bp
@bp.app_errorhandler(HTTPException)
def handle_http_exception(error):
''' Generic HTTP exception handler '''
accept_json = request.accept_mimetypes.accept_json
accept_html = request.accept_mimetypes.accept_html
if accept_json and not accept_html:
response = jsonify(str(error))
return response, error.code
return render_template('errors/error.html.j2', error=error), error.code

18
app/jobs/__init__.py Normal file
View File

@ -0,0 +1,18 @@
from flask import Blueprint
from flask_login import login_required
bp = Blueprint('jobs', __name__)
@bp.before_request
@login_required
def before_request():
'''
Ensures that the routes in this package can only be visited by users that
are logged in.
'''
pass
from . import routes, json_routes

73
app/jobs/json_routes.py Normal file
View File

@ -0,0 +1,73 @@
from flask import abort, current_app
from flask_login import current_user
from threading import Thread
import os
from app import db
from app.decorators import admin_required, content_negotiation
from app.models import Job, JobStatus
from . import bp
@bp.route('/<hashid:job_id>', methods=['DELETE'])
@content_negotiation(produces='application/json')
def delete_job(job_id):
def _delete_job(app, job_id):
with app.app_context():
job = Job.query.get(job_id)
job.delete()
db.session.commit()
job = Job.query.get_or_404(job_id)
if not (job.user == current_user or current_user.is_administrator()):
abort(403)
thread = Thread(
target=_delete_job,
args=(current_app._get_current_object(), job_id)
)
thread.start()
response_data = {
'message': f'Job "{job.title}" marked for deletion'
}
return response_data, 202
@bp.route('/<hashid:job_id>/log')
@admin_required
@content_negotiation(produces='application/json')
def job_log(job_id):
job = Job.query.get_or_404(job_id)
if job.status not in [JobStatus.COMPLETED, JobStatus.FAILED]:
response = {'errors': {'message': 'Job status is not completed or failed'}}
return response, 409
with open(os.path.join(job.path, 'pipeline_data', 'logs', 'pyflow_log.txt')) as log_file:
log = log_file.read()
response_data = {
'jobLog': log
}
return response_data, 200
@bp.route('/<hashid:job_id>/restart', methods=['POST'])
@content_negotiation(produces='application/json')
def restart_job(job_id):
def _restart_job(app, job_id):
with app.app_context():
job = Job.query.get(job_id)
job.restart()
db.session.commit()
job = Job.query.get_or_404(job_id)
if not (job.user == current_user or current_user.is_administrator()):
abort(403)
if job.status == JobStatus.FAILED:
response = {'errors': {'message': 'Job status is not "failed"'}}
return response, 409
thread = Thread(
target=_restart_job,
args=(current_app._get_current_object(), job_id)
)
thread.start()
response_data = {
'message': f'Job "{job.title}" marked for restarting'
}
return response_data, 202

60
app/jobs/routes.py Normal file
View File

@ -0,0 +1,60 @@
from flask import (
abort,
redirect,
render_template,
send_from_directory,
url_for
)
from flask_breadcrumbs import register_breadcrumb
from flask_login import current_user
import os
from app.models import Job, JobInput, JobResult
from . import bp
from .utils import job_dynamic_list_constructor as job_dlc
@bp.route('')
@register_breadcrumb(bp, '.', '<i class="nopaque-icons left">J</i>My Jobs')
def corpora():
return redirect(url_for('main.dashboard', _anchor='jobs'))
@bp.route('/<hashid:job_id>')
@register_breadcrumb(bp, '.entity', '', dynamic_list_constructor=job_dlc)
def job(job_id):
job = Job.query.get_or_404(job_id)
if not (job.user == current_user or current_user.is_administrator()):
abort(403)
return render_template(
'jobs/job.html.j2',
title='Job',
job=job
)
@bp.route('/<hashid:job_id>/inputs/<hashid:job_input_id>/download')
def download_job_input(job_id, job_input_id):
job_input = JobInput.query.filter_by(job_id=job_id, id=job_input_id).first_or_404()
if not (job_input.job.user == current_user or current_user.is_administrator()):
abort(403)
return send_from_directory(
os.path.dirname(job_input.path),
os.path.basename(job_input.path),
as_attachment=True,
attachment_filename=job_input.filename,
mimetype=job_input.mimetype
)
@bp.route('/<hashid:job_id>/results/<hashid:job_result_id>/download')
def download_job_result(job_id, job_result_id):
job_result = JobResult.query.filter_by(job_id=job_id, id=job_result_id).first_or_404()
if not (job_result.job.user == current_user or current_user.is_administrator()):
abort(403)
return send_from_directory(
os.path.dirname(job_result.path),
os.path.basename(job_result.path),
as_attachment=True,
attachment_filename=job_result.filename,
mimetype=job_result.mimetype
)

13
app/jobs/utils.py Normal file
View File

@ -0,0 +1,13 @@
from flask import request, url_for
from app.models import Job
def job_dynamic_list_constructor():
job_id = request.view_args['job_id']
job = Job.query.get_or_404(job_id)
return [
{
'text': f'<i class="nopaque-icons left service-icons" data-service="{job.service}"></i>{job.title}',
'url': url_for('.job', job_id=job_id)
}
]

5
app/main/__init__.py Normal file
View File

@ -0,0 +1,5 @@
from flask import Blueprint
bp = Blueprint('main', __name__, cli_group=None)
from . import cli, routes

45
app/main/cli.py Normal file
View File

@ -0,0 +1,45 @@
from flask import current_app
from flask_migrate import upgrade
import os
from app.models import (
CorpusFollowerRole,
Role,
SpaCyNLPPipelineModel,
TesseractOCRPipelineModel,
User
)
from . import bp
@bp.cli.command('deploy')
def deploy():
''' Run deployment tasks. '''
# Make default directories
print('Make default directories')
base_dir = current_app.config['NOPAQUE_DATA_DIR']
default_dirs = [
os.path.join(base_dir, 'tmp'),
os.path.join(base_dir, 'users')
]
for dir in default_dirs:
if os.path.exists(dir):
if not os.path.isdir(dir):
raise NotADirectoryError(f'{dir} is not a directory')
else:
os.mkdir(dir)
# migrate database to latest revision
print('Migrate database to latest revision')
upgrade()
# Insert/Update default database values
print('Insert/Update default Roles')
Role.insert_defaults()
print('Insert/Update default Users')
User.insert_defaults()
print('Insert/Update default CorpusFollowerRoles')
CorpusFollowerRole.insert_defaults()
print('Insert/Update default SpaCyNLPPipelineModels')
SpaCyNLPPipelineModel.insert_defaults()
print('Insert/Update default TesseractOCRPipelineModels')
TesseractOCRPipelineModel.insert_defaults()

92
app/main/routes.py Normal file
View File

@ -0,0 +1,92 @@
from flask import flash, redirect, render_template, url_for
from flask_breadcrumbs import register_breadcrumb
from flask_login import current_user, login_required, login_user
from app.auth.forms import LoginForm
from app.models import Corpus, User
from sqlalchemy import or_
from . import bp
@bp.route('/', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.', '<i class="material-icons">home</i>')
def index():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter((User.email == form.user.data.lower()) | (User.username == form.user.data)).first()
if user and user.verify_password(form.password.data):
login_user(user, form.remember_me.data)
flash('You have been logged in')
return redirect(url_for('.dashboard'))
flash('Invalid email/username or password', category='error')
redirect(url_for('.index'))
return render_template(
'main/index.html.j2',
title='nopaque',
form=form
)
@bp.route('/faq')
@register_breadcrumb(bp, '.faq', 'Frequently Asked Questions')
def faq():
return render_template(
'main/faq.html.j2',
title='Frequently Asked Questions'
)
@bp.route('/dashboard')
@register_breadcrumb(bp, '.dashboard', '<i class="material-icons left">dashboard</i>Dashboard')
@login_required
def dashboard():
return render_template(
'main/dashboard.html.j2',
title='Dashboard'
)
# @bp.route('/user_manual')
# @register_breadcrumb(bp, '.user_manual', '<i class="material-icons left">help</i>User manual')
# def user_manual():
# return render_template('main/user_manual.html.j2', title='User manual')
@bp.route('/news')
@register_breadcrumb(bp, '.news', '<i class="material-icons left">email</i>News')
def news():
return render_template(
'main/news.html.j2',
title='News'
)
@bp.route('/privacy_policy')
@register_breadcrumb(bp, '.privacy_policy', 'Private statement (GDPR)')
def privacy_policy():
return render_template(
'main/privacy_policy.html.j2',
title='Privacy statement (GDPR)'
)
@bp.route('/terms_of_use')
@register_breadcrumb(bp, '.terms_of_use', 'Terms of Use')
def terms_of_use():
return render_template(
'main/terms_of_use.html.j2',
title='Terms of Use'
)
# @bp.route('/social-area')
# @register_breadcrumb(bp, '.social_area', '<i class="material-icons left">group</i>Social Area')
# @login_required
# def social_area():
# corpora = Corpus.query.filter(Corpus.is_public == True, Corpus.user != current_user).all()
# users = User.query.filter(User.is_public == True, User.id != current_user.id).all()
# return render_template(
# 'main/social_area.html.j2',
# title='Social Area',
# corpora=corpora,
# users=users
# )

1815
app/models.py Normal file

File diff suppressed because it is too large Load Diff

25
app/services/__init__.py Normal file
View File

@ -0,0 +1,25 @@
from flask import Blueprint
from flask_login import login_required
import os
import yaml
services_file = \
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'services.yml')
with open(services_file, 'r') as f:
SERVICES = yaml.safe_load(f)
bp = Blueprint('services', __name__)
@bp.before_request
@login_required
def before_request():
'''
Ensures that the routes in this package can only be visited by users that
are logged in.
'''
pass
from . import routes # noqa

192
app/services/forms.py Normal file
View File

@ -0,0 +1,192 @@
from flask_wtf import FlaskForm
from flask_login import current_user
from flask_wtf.file import FileField, FileRequired
from wtforms import (
BooleanField,
DecimalRangeField,
MultipleFileField,
SelectField,
StringField,
SubmitField,
ValidationError
)
from wtforms.validators import InputRequired, Length
from app.models import SpaCyNLPPipelineModel, TesseractOCRPipelineModel
from . import SERVICES
class CreateJobBaseForm(FlaskForm):
description = StringField(
'Description',
validators=[InputRequired(), Length(max=255)]
)
title = StringField(
'Title',
validators=[InputRequired(), Length(max=32)]
)
version = SelectField('Version', validators=[InputRequired()])
submit = SubmitField()
class CreateFileSetupPipelineJobForm(CreateJobBaseForm):
images = MultipleFileField('File(s)', validators=[InputRequired()])
def validate_images(form, field):
valid_mimetypes = ['image/jpeg', 'image/png', 'image/tiff']
for image in field.data:
if image.mimetype not in valid_mimetypes:
raise ValidationError('JPEG, PNG and TIFF files only!')
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'create-file-setup-pipeline-job-form'
service_manifest = SERVICES['file-setup-pipeline']
version = kwargs.pop('version', service_manifest['latest_version'])
super().__init__(*args, **kwargs)
self.version.choices = [(x, x) for x in service_manifest['versions']]
self.version.data = version
self.version.default = service_manifest['latest_version']
class CreateTesseractOCRPipelineJobForm(CreateJobBaseForm):
binarization = BooleanField('Binarization')
pdf = FileField('File', validators=[FileRequired()])
model = SelectField('Model', validators=[InputRequired()])
ocropus_nlbin_threshold = DecimalRangeField(
render_kw={'min': 0, 'max': 1, 'step': 0.1, 'start': [0.5], 'disabled': True}
)
def validate_binarization(self, field):
service_info = SERVICES['tesseract-ocr-pipeline']['versions'][self.version.data]
if field.data:
if not('methods' in service_info and 'binarization' in service_info['methods']):
raise ValidationError('Binarization is not available')
def validate_pdf(self, field):
if field.data.mimetype != 'application/pdf':
raise ValidationError('PDF files only!')
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'create-tesseract-ocr-pipeline-job-form'
service_manifest = SERVICES['tesseract-ocr-pipeline']
version = kwargs.pop('version', service_manifest['latest_version'])
super().__init__(*args, **kwargs)
service_info = service_manifest['versions'][version]
if self.binarization.render_kw is None:
self.binarization.render_kw = {}
self.binarization.render_kw['disabled'] = True
if self.ocropus_nlbin_threshold.render_kw is None:
self.ocropus_nlbin_threshold.render_kw = {}
self.ocropus_nlbin_threshold.render_kw['disabled'] = True
if 'methods' in service_info:
if 'binarization' in service_info['methods']:
del self.binarization.render_kw['disabled']
if 'ocropus_nlbin_threshold' in service_info['methods']:
del self.ocropus_nlbin_threshold.render_kw['disabled']
user_models = [
x for x in current_user.tesseract_ocr_pipeline_models.order_by(TesseractOCRPipelineModel.title).all()
]
models = [
x for x in TesseractOCRPipelineModel.query.order_by(TesseractOCRPipelineModel.title).all()
if version in x.compatible_service_versions and (x.is_public == True or x.user == current_user)
]
self.model.choices = {
'': [('', 'Choose your option')],
'Your models': [(x.hashid, f'{x.title} [{x.version}]') for x in user_models] if user_models else [(0, 'Nothing here yet...')],
'Public models': [(x.hashid, f'{x.title} [{x.version}]') for x in models]
}
self.model.default = ''
self.version.choices = [(x, x) for x in service_manifest['versions']]
self.version.data = version
self.version.default = service_manifest['latest_version']
class CreateTranskribusHTRPipelineJobForm(CreateJobBaseForm):
binarization = BooleanField('Binarization')
pdf = FileField('File', validators=[FileRequired()])
model = SelectField('Model', validators=[InputRequired()])
def validate_binarization(self, field):
service_info = SERVICES['transkribus-htr-pipeline']['versions'][self.version.data]
if field.data:
if(
'methods' not in service_info
or 'binarization' not in service_info['methods']
):
raise ValidationError('Binarization is not available')
def validate_pdf(self, field):
if field.data.mimetype != 'application/pdf':
raise ValidationError('PDF files only!')
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'create-transkribus-htr-pipeline-job-form'
transkribus_htr_pipeline_models = kwargs.pop('transkribus_htr_pipeline_models', [])
service_manifest = SERVICES['transkribus-htr-pipeline']
version = kwargs.pop('version', service_manifest['latest_version'])
super().__init__(*args, **kwargs)
service_info = service_manifest['versions'][version]
if self.binarization.render_kw is None:
self.binarization.render_kw = {}
self.binarization.render_kw['disabled'] = True
if 'methods' in service_info:
if 'binarization' in service_info['methods']:
del self.binarization.render_kw['disabled']
self.model.choices = [('', 'Choose your option')]
self.model.choices += [(x['modelId'], x['name']) for x in transkribus_htr_pipeline_models]
self.model.default = ''
self.version.choices = [(x, x) for x in service_manifest['versions']]
self.version.data = version
self.version.default = service_manifest['latest_version']
class CreateSpacyNLPPipelineJobForm(CreateJobBaseForm):
encoding_detection = BooleanField('Encoding detection', render_kw={'disabled': True})
txt = FileField('File', validators=[FileRequired()])
model = SelectField('Model', validators=[InputRequired()])
def validate_encoding_detection(self, field):
service_info = SERVICES['spacy-nlp-pipeline']['versions'][self.version.data]
if field.data:
if(
'methods' not in service_info
or 'encoding_detection' not in service_info['methods']
):
raise ValidationError('Encoding detection is not available')
def validate_txt(form, field):
if field.data.mimetype != 'text/plain':
raise ValidationError('Plain text files only!')
def __init__(self, *args, **kwargs):
if 'prefix' not in kwargs:
kwargs['prefix'] = 'create-spacy-nlp-pipeline-job-form'
service_manifest = SERVICES['spacy-nlp-pipeline']
version = kwargs.pop('version', service_manifest['latest_version'])
super().__init__(*args, **kwargs)
service_info = service_manifest['versions'][version]
print(service_info)
if self.encoding_detection.render_kw is None:
self.encoding_detection.render_kw = {}
self.encoding_detection.render_kw['disabled'] = True
if 'methods' in service_info:
if 'encoding_detection' in service_info['methods']:
del self.encoding_detection.render_kw['disabled']
user_models = [
x for x in current_user.spacy_nlp_pipeline_models.order_by(SpaCyNLPPipelineModel.title).all()
]
models = [
x for x in SpaCyNLPPipelineModel.query.filter(SpaCyNLPPipelineModel.user != current_user, SpaCyNLPPipelineModel.is_public == True).order_by(SpaCyNLPPipelineModel.title).all()
if version in x.compatible_service_versions
]
self.model.choices = {
'': [('', 'Choose your option')],
'Your models': [(x.hashid, f'{x.title} [{x.version}]') for x in user_models] if user_models else [(0, 'Nothing here yet...')],
'Public models': [(x.hashid, f'{x.title} [{x.version}]') for x in models]
}
self.model.default = ''
self.version.choices = [(x, x) for x in service_manifest['versions']]
self.version.data = version
self.version.default = version

231
app/services/routes.py Normal file
View File

@ -0,0 +1,231 @@
from flask import abort, current_app, flash, Markup, redirect, render_template, request, url_for
from flask_breadcrumbs import register_breadcrumb
from flask_login import current_user
import requests
from app import db, hashids
from app.models import (
Job,
JobInput,
JobStatus,
TesseractOCRPipelineModel,
SpaCyNLPPipelineModel
)
from . import bp, SERVICES
from .forms import (
CreateFileSetupPipelineJobForm,
CreateTesseractOCRPipelineJobForm,
CreateTranskribusHTRPipelineJobForm,
CreateSpacyNLPPipelineJobForm
)
@bp.route('/services')
@register_breadcrumb(bp, '.', 'Services')
def services():
return redirect(url_for('main.dashboard'))
@bp.route('/file-setup-pipeline', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.file_setup_pipeline', '<i class="nopaque-icons service-icons left" data-service="file-setup-pipeline"></i>File Setup')
def file_setup_pipeline():
service = 'file-setup-pipeline'
service_manifest = SERVICES[service]
version = request.args.get('version', service_manifest['latest_version'])
if version not in service_manifest['versions']:
abort(404)
form = CreateFileSetupPipelineJobForm(prefix='create-job-form', version=version)
if form.is_submitted():
if not form.validate():
response = {'errors': form.errors}
return response, 400
try:
job = Job.create(
title=form.title.data,
description=form.description.data,
service=service,
service_args={},
service_version=form.version.data,
user=current_user
)
except OSError:
abort(500)
for input_file in form.images.data:
try:
JobInput.create(input_file, job=job)
except (AttributeError, OSError):
abort(500)
job.status = JobStatus.SUBMITTED
db.session.commit()
message = Markup(f'Job "<a href="{job.url}">{job.title}</a>" created')
flash(message, 'job')
return {}, 201, {'Location': job.url}
return render_template(
'services/file_setup_pipeline.html.j2',
title=service_manifest['name'],
form=form
)
@bp.route('/tesseract-ocr-pipeline', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.tesseract_ocr_pipeline', '<i class="nopaque-icons service-icons left" data-service="tesseract-ocr-pipeline"></i>Tesseract OCR Pipeline')
def tesseract_ocr_pipeline():
service_name = 'tesseract-ocr-pipeline'
service_manifest = SERVICES[service_name]
version = request.args.get('version', service_manifest['latest_version'])
if version not in service_manifest['versions']:
abort(404)
form = CreateTesseractOCRPipelineJobForm(prefix='create-job-form', version=version)
if form.is_submitted():
if not form.validate():
response = {'errors': form.errors}
return response, 400
try:
job = Job.create(
title=form.title.data,
description=form.description.data,
service=service_name,
service_args={
'binarization': form.binarization.data,
'model': hashids.decode(form.model.data),
'ocropus_nlbin_threshold': float(form.ocropus_nlbin_threshold.data)
},
service_version=form.version.data,
user=current_user
)
except OSError:
abort(500)
try:
JobInput.create(form.pdf.data, job=job)
except (AttributeError, OSError):
abort(500)
job.status = JobStatus.SUBMITTED
db.session.commit()
message = Markup(f'Job "<a href="{job.url}">{job.title}</a>" created')
flash(message, 'job')
return {}, 201, {'Location': job.url}
tesseract_ocr_pipeline_models = [
x for x in TesseractOCRPipelineModel.query.all()
if version in x.compatible_service_versions and (x.is_public == True or x.user == current_user)
]
user_tesseract_ocr_pipeline_models_count = len(current_user.tesseract_ocr_pipeline_models.all())
return render_template(
'services/tesseract_ocr_pipeline.html.j2',
title=service_manifest['name'],
form=form,
tesseract_ocr_pipeline_models=tesseract_ocr_pipeline_models,
user_tesseract_ocr_pipeline_models_count=user_tesseract_ocr_pipeline_models_count
)
@bp.route('/transkribus-htr-pipeline', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.transkribus_htr_pipeline', '<i class="nopaque-icons service-icons left" data-service="transkribus-htr-pipeline"></i>Transkribus HTR Pipeline')
def transkribus_htr_pipeline():
if not current_app.config.get('NOPAQUE_TRANSKRIBUS_ENABLED'):
abort(404)
service = 'transkribus-htr-pipeline'
service_manifest = SERVICES[service]
version = request.args.get('version', service_manifest['latest_version'])
if version not in service_manifest['versions']:
abort(404)
r = requests.get(
'https://transkribus.eu/TrpServer/rest/models/text',
headers={'Accept': 'application/json'}
)
if r.status_code != 200:
abort(500)
transkribus_htr_pipeline_models = r.json()['trpModelMetadata']
transkribus_htr_pipeline_models.append({'modelId': 48513, 'name': 'Caroline Minuscle', 'language': 'lat', 'isoLanguages': ['lat']})
form = CreateTranskribusHTRPipelineJobForm(
prefix='create-job-form',
transkribus_htr_pipeline_models=transkribus_htr_pipeline_models,
version=version
)
if form.is_submitted():
if not form.validate():
response = {'errors': form.errors}
return response, 400
try:
job = Job.create(
title=form.title.data,
description=form.description.data,
service=service,
service_args={
'binarization': form.binarization.data,
'model': form.model.data
},
service_version=form.version.data,
user=current_user
)
except OSError:
abort(500)
try:
JobInput.create(form.pdf.data, job=job)
except (AttributeError, OSError):
abort(500)
job.status = JobStatus.SUBMITTED
db.session.commit()
message = Markup(f'Job "<a href="{job.url}">{job.title}</a>" created')
flash(message, 'job')
return {}, 201, {'Location': job.url}
return render_template(
'services/transkribus_htr_pipeline.html.j2',
title=service_manifest['name'],
form=form,
transkribus_htr_pipeline_models=transkribus_htr_pipeline_models
)
@bp.route('/spacy-nlp-pipeline', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.spacy_nlp_pipeline', '<i class="nopaque-icons service-icons left" data-service="spacy-nlp-pipeline"></i>SpaCy NLP Pipeline')
def spacy_nlp_pipeline():
service = 'spacy-nlp-pipeline'
service_manifest = SERVICES[service]
version = request.args.get('version', SERVICES[service]['latest_version'])
if version not in service_manifest['versions']:
abort(404)
form = CreateSpacyNLPPipelineJobForm(prefix='create-job-form', version=version)
spacy_nlp_pipeline_models = SpaCyNLPPipelineModel.query.all()
user_spacy_nlp_pipeline_models_count = len(current_user.spacy_nlp_pipeline_models.all())
if form.is_submitted():
if not form.validate():
response = {'errors': form.errors}
return response, 400
try:
job = Job.create(
title=form.title.data,
description=form.description.data,
service=service,
service_args={
'encoding_detection': form.encoding_detection.data,
'model': form.model.data
},
service_version=form.version.data,
user=current_user
)
except OSError:
abort(500)
try:
JobInput.create(form.txt.data, job=job)
except (AttributeError, OSError):
abort(500)
job.status = JobStatus.SUBMITTED
db.session.commit()
message = Markup(f'Job "<a href="{job.url}">{job.title}</a>" created')
flash(message, 'job')
return {}, 201, {'Location': job.url}
return render_template(
'services/spacy_nlp_pipeline.html.j2',
title=service_manifest['name'],
form=form,
spacy_nlp_pipeline_models=spacy_nlp_pipeline_models,
user_spacy_nlp_pipeline_models_count=user_spacy_nlp_pipeline_models_count
)
@bp.route('/corpus-analysis')
@register_breadcrumb(bp, '.corpus_analysis', '<i class="nopaque-icons service-icons left" data-service="corpus-analysis"></i>Corpus Analysis')
def corpus_analysis():
return render_template(
'services/corpus_analysis.html.j2',
title='Corpus Analysis'
)

60
app/services/services.yml Normal file
View File

@ -0,0 +1,60 @@
# TODO: This could also be done via GitLab/GitHub APIs
file-setup-pipeline:
name: 'File Setup Pipeline'
publisher: 'Bielefeld University - CRC 1288 - INF'
latest_version: '0.1.0'
versions:
0.1.0:
publishing_year: 2022
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/file-setup-pipeline/-/releases/v0.1.0'
tesseract-ocr-pipeline:
name: 'Tesseract OCR Pipeline'
publisher: 'Bielefeld University - CRC 1288 - INF'
latest_version: '0.1.1'
versions:
0.1.0:
methods:
- 'binarization'
publishing_year: 2022
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/releases/v0.1.0'
0.1.1:
methods:
- 'binarization'
- 'ocropus_nlbin_threshold'
publishing_year: 2022
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/releases/v0.1.1'
transkribus-htr-pipeline:
name: 'Transkribus HTR Pipeline'
publisher: 'Bielefeld University - CRC 1288 - INF'
latest_version: '0.1.1'
versions:
0.1.0:
methods:
- 'binarization'
publishing_year: 2022
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/transkribus-htr-pipeline/-/releases/v0.1.0'
0.1.1:
methods:
- 'binarization'
publishing_year: 2022
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/transkribus-htr-pipeline/-/releases/v0.1.1'
spacy-nlp-pipeline:
name: 'SpaCy NLP Pipeline'
publisher: 'Bielefeld University - CRC 1288 - INF'
latest_version: '0.1.2'
versions:
0.1.0:
methods:
- 'encoding_detection'
publishing_year: 2022
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.0'
0.1.1:
methods:
- 'encoding_detection'
publishing_year: 2022
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.1'
0.1.2:
methods:
- 'encoding_detection'
publishing_year: 2022
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.2'

18
app/settings/__init__.py Normal file
View File

@ -0,0 +1,18 @@
from flask import Blueprint
from flask_login import login_required
bp = Blueprint('settings', __name__)
@bp.before_request
@login_required
def before_request():
'''
Ensures that the routes in this package can only be visited by users that
are logged in.
'''
pass
from . import routes

12
app/settings/routes.py Normal file
View File

@ -0,0 +1,12 @@
from flask import g, url_for
from flask_breadcrumbs import register_breadcrumb
from flask_login import current_user
from app.users.settings.routes import settings as settings_route
from . import bp
@bp.route('/settings', methods=['GET', 'POST'])
@register_breadcrumb(bp, '.', '<i class="material-icons left">settings</i>Settings')
def settings():
g._nopaque_redirect_location_on_post = url_for('.settings')
return settings_route(current_user.id)

290
app/static/css/colors.scss Normal file
View File

@ -0,0 +1,290 @@
/// Map deep get
/// @author Kitty Giraudel
/// @access public
/// @param {Map} $map - Map
/// @param {Arglist} $keys - Key chain
/// @return {*} - Desired value
@function map-deep-get($map, $keys...) {
@each $key in $keys {
$map: map-get($map, $key);
}
@return $map;
}
$color: (
"baseline": (
"primary": #00426f,
"primary-variant": #1a5c89,
"secondary": #00426f,
"secondary-variant": #1a5c89,
"background": #ffffff,
"surface": #ffffff,
"error": #b00020
),
"social-area": (
"base": #d6ae86,
"darken": #C98536,
"lighten": #EAE2DB
),
"service": (
"corpus-analysis": (
"base": #aa9cc9,
"darken": #6b3f89,
"lighten": #ebe8f6
),
"file-setup-pipeline": (
"base": #d5dc95,
"darken": #a1b300,
"lighten": #f2f3e1
),
"spacy-nlp-pipeline": (
"base": #98acd2,
"darken": #0064a3,
"lighten": #e5e8f5
),
"tesseract-ocr-pipeline": (
"base": #a9d8c8,
"darken": #00a58b,
"lighten": #e7f4f1
),
"transkribus-htr-pipeline": (
"base": #607d8b,
"darken": #37474f,
"lighten": #cfd8dc
)
),
"status": (
"corpus": (
"UNPREPARED": #9e9e9e,
"QUEUED": #2196f3,
"BUILDING": #ffc107,
"BUILT": #4caf50,
"FAILED": #f44336,
"STARTING_ANALYSIS_SESSION": #2196f3,
"RUNNING_ANALYSIS_SESSION": #4caf50,
"CANCELING_ANALYSIS_SESSION": #ff5722
),
"job": (
"INITIALIZING": #9e9e9e,
"SUBMITTED": #9e9e9e,
"QUEUED": #2196f3,
"RUNNING": #ffc107,
"CANCELING": #ff5722,
"CANCELED": #ff5722,
"COMPLETED": #4caf50,
"FAILED": #f44336
)
),
"s-attr": (
"PERSON": #a6e22d,
"PER": #a6e22d,
"NORP": #ef60b4,
"FACILITY": #43c6fc,
"ORG": #43c6fc,
"GPE": #fd9720,
"LOC": #fd9720,
"PRODUCT": #a99dfb,
"MISC": #a99dfb,
"EVENT": #fc0,
"WORK_OF_ART": #fc0,
"LANGUAGE": #fc0,
"DATE": #2fbbab,
"TIME": #2fbbab,
"PERCENT": #bbb,
"MONEY": #bbb,
"QUANTITY": #bbb,
"ORDINAL": #bbb,
"CARDINAL": #bbb
)
);
@each $key, $color-code in map-get($color, "baseline") {
.#{$key}-color {
background-color: $color-code !important;
}
.#{$key}-color-border {
border-color: $color-code !important;
}
.#{$key}-color-text {
color: $color-code !important;
}
}
@each $key, $color-code in map-get($color, "social-area") {
.social-area-color-#{$key} {
background-color: $color-code !important;
}
.social-area-color-border-#{$key} {
border-color: $color-code !important;
}
}
@each $service-name, $color-palette in map-get($color, "service") {
.service-color[data-service="#{$service-name}"] {
background-color: map-get($color-palette, "base") !important;
&.darken {
background-color: map-get($color-palette, "darken") !important;
}
&.lighten {
background-color: map-get($color-palette, "lighten") !important;
}
}
.service-color-border[data-service="#{$service-name}"] {
border-color: map-get($color-palette, "base") !important;
&.border-darken {
border-color: map-get($color-palette, "darken") !important;
}
&.border-lighten {
border-color: map-get($color-palette, "lighten") !important;
}
}
.service-color-text[data-service="#{$service-name}"] {
color: map-get($color-palette, "base") !important;
&.text-darken {
color: map-get($color-palette, "darken") !important;
}
&.text-lighten {
color: map-get($color-palette, "lighten") !important;
}
}
.service-scheme[data-service="#{$service-name}"] {
background-color: map-get($color-palette, "lighten");
.btn, .btn-small, .btn-large, .btn-floating {
background-color: map-get($color-palette, "darken");
&:hover {
background-color: map-get($color-palette, "base");
}
}
.pagination {
li.active {
background-color: map-get($color-palette, "darken");
}
}
.table-of-contents {
a.active, a:hover {
border-color: map-get($color-palette, "darken");
}
}
.tabs {
.tab {
&.disabled {
a {
color: inherit;
&:hover {
color: change-color(map-get($color-palette, "darken"), $alpha: 0.15);
}
}
}
a {
color: inherit;
&:focus, &:hover, &.active {
color: map-get($color-palette, "darken");
}
&:focus, &.active, &.active:focus {
background-color: change-color(map-get($color-palette, "darken"), $alpha: 0.15);
}
}
}
.indicator {
background-color: map-get($color-palette, "darken");
}
}
}
}
@each $ressource-name, $color-palette in map-get($color, "status") {
@each $key, $color-code in $color-palette {
.#{$ressource-name}-status-color[data-status="#{$key}"] {
background-color: $color-code !important;
}
.#{$ressource-name}-status-color-border[data-status="#{$key}"] {
border-color: $color-code !important;
}
.#{$ressource-name}-status-color-text[data-status="#{$key}"] {
color: $color-code !important;
}
}
}
@each $key, $color-code in map-get($color, "s-attr") {
.chip.s-attr[data-s-attr-type="ent"][data-s-attr-ent-type="#{$key}"] {
background-color: $color-code !important;
}
}
main {
.btn, .btn-small, .btn-large, .btn-floating {
background-color: map-deep-get($color, "baseline", "secondary");
&:hover {
background-color: map-deep-get($color, "baseline", "secondary-variant");
}
}
.pagination {
li.active {
background-color: map-deep-get($color, "baseline", "secondary");
}
}
.table-of-contents {
a.active, a:hover {
border-color: map-deep-get($color, "baseline", "secondary");
}
}
.tabs {
.tab {
&.disabled {
a {
color: inherit;
&:hover {
color: change-color(map-deep-get($color, "baseline", "secondary"), $alpha: 0.15);
}
}
}
a {
color: inherit;
&:focus, &:hover, &.active {
color: map-deep-get($color, "baseline", "secondary");
}
&:focus, &.active, &.active:focus {
background-color: change-color(map-deep-get($color, "baseline", "secondary"), $alpha: 0.15);
}
}
}
.indicator {
background-color: map-deep-get($color, "baseline", "secondary");
}
}
}

View File

@ -0,0 +1,31 @@
/*
* Spacing
*/
$spacing-shortcuts: ("margin": "mg", "padding": "pd");
$spacing-directions: ("top": "t", "right": "r", "bottom": "b", "left": "l");
$spacing-values: ("0": 0, "1": 0.25rem, "2": 0.5rem, "3": 0.75rem, "4": 1rem, "5": 1.5rem, "6": 3rem, "auto": auto);
@each $spacing-shortcut-name, $spacing-shortcut-value in $spacing-shortcuts {
@each $spacing-name, $spacing-value in $spacing-values {
// All directions
.#{$spacing-shortcut-value}-#{$spacing-name} {
#{$spacing-shortcut-name}: $spacing-value !important;
}
// Horizontal axis
.#{$spacing-shortcut-value}x-#{$spacing-name} {
#{$spacing-shortcut-name}-left: $spacing-value !important;
#{$spacing-shortcut-name}-right: $spacing-value !important;
}
// Vertical axis
.#{$spacing-shortcut-value}y-#{$spacing-name} {
#{$spacing-shortcut-name}-top: $spacing-value !important;
#{$spacing-shortcut-name}-bottom: $spacing-value !important;
}
// Cardinal directions
@each $spacing-direction-name, $spacing-direction-value in $spacing-directions {
.#{$spacing-shortcut-value}#{$spacing-direction-value}-#{$spacing-name} {
#{$spacing-shortcut-name}-#{$spacing-direction-name}: $spacing-value !important;
}
}
}
}

View File

@ -0,0 +1,8 @@
.parallax-container .parallax {
z-index: 0;
}
.autocomplete-content {
width: 100% !important;
left: 0 !important;
}

View File

@ -0,0 +1,12 @@
/*
* The sidenav-fixed class is used which causes the sidenav to be fixed and open
* on large screens and hides to the regular functionality on smaller screens.
* In order to prevent the sidenav to overlap the content, the content (in our
* case header, main and footer) gets an offset equal to the width of the
* sidenav.
*/
@media only screen and (min-width : 993px) {
header, main, footer {padding-left: 300px;}
.modal:not(.bottom-sheet) {left: 300px;}
.navbar-fixed > nav {width: calc(100% - 300px)}
}

View File

@ -0,0 +1,18 @@
/*
* Sticky Footer: https://materializecss.com/footer.html#sticky-footer
* A sticky footer always stays on the bottom of the page regardless of how
* little content is on the page. However, this footer will be pushed down if
* there is a lot of content, so it is different from a fixed footer.
*
* Note: This may cause issues in Internet Explorer which has weak support for
* flexbox.
*/
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1 0 auto;
}

View File

@ -0,0 +1,33 @@
@font-face {
font-family: 'Nopaque Icons';
font-style: normal;
font-weight: 400;
src: local('nopaque Icons'),
local('NopaqueIcons-Regular'),
url(../fonts/nopaque_icons/NopaqueIcons-Regular.otf) format('opentype');
}
.nopaque-icons {
font-family: 'Nopaque Icons';
font-weight: normal;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
/* Support for IE. */
font-feature-settings: 'liga';
}

View File

@ -0,0 +1,146 @@
.modal-conent {
overflow-x: hidden;
}
#concordance-query-builder {
width: 70%;
}
#concordance-query-builder nav {
background-color: #6B3F89;
margin-top: -25px;
margin-left: -25px;
width: 105%;
}
#query-builder-nav{
padding-left: 15px;
}
#close-query-builder {
margin-right: 50px;
cursor: pointer;
}
#general-options-query-builder-tutorial-info-icon {
color: black;
}
#your-query {
border-bottom-style: solid;
border-bottom-width: 1px;
}
#insert-query-button {
background-color: #00426f;
text-align: center;
}
#structural-attr h6 {
margin-left: 15px;
}
#add-structural-attribute-tutorial-info-icon {
color: black;
}
#sentence {
background-color:#FD9720;
}
#entity {
background-color: #A6E22D;
}
#text-annotation {
background-color: #2FBBAB;
}
#no-value-metadata-message {
padding-top: 25px;
margin-left: -20px;
}
#token-kind-selector {
background-color: #f2eff7;
padding: 15px;
border-top-style: solid;
border-color: #6B3F89;
}
#token-kind-selector.s5 {
margin-top: 15px;
}
#token-kind-selector h6 {
margin-left: 15px;
}
#token-tutorial-info-icon {
color: black;
}
#no-value-message {
padding-top: 25px;
margin-left: -20px;
}
#token-edit-options h6 {
margin-left: 15px;
}
#edit-options-tutorial-info-icon {
color: black;
}
#incidence-modifiers-button a{
background-color: #2FBBAB;
}
#incidence-modifiers a{
background-color: white;
}
#ignore-case {
margin-left: 5px;
}
#or, #and {
background-color: #fc0;
}
#betweenNM {
width: 60%;
}
#query-builder-tutorial-modal {
width: 60%;
}
#query-builder-tutorial-modal ul {
margin-top: 10px;
}
#query-builder-tutorial {
padding:15px;
}
#scroll-up-button-query-builder-tutorial {
background-color: #28B3D1;
}
[data-type="start-sentence"], [data-type="end-sentence"] {
background-color: #FD9720;
}
[data-type="start-empty-entity"], [data-type="start-entity"], [data-type="end-entity"] {
background-color: #A6E22D;
}
[data-type="start-text-annotation"]{
background-color: #2FBBAB;
}
[data-type="token"] {
background-color: #28B3D1;
}

67
app/static/css/style.css Normal file
View File

@ -0,0 +1,67 @@
/* Change navbar height bacause an extended and fixed navbar is used */
.navbar-fixed {
height: 112px;
}
/* Change placholdertext color of file uplaod fields */
::placeholder {
color: #9e9e9e;
opacity: 1;
}
/*
* changes preoloader size etc. to fit visually better with the chip status
* indicator of jobs
*/
.status-spinner {
margin-bottom: -10px;
width: 30px !important;
height: 30px !important;
}
#manual-modal .manual-chapter-title {
display: none;
}
.show-if-only-child:not(:only-child) {
display: none !important;
}
.btn-scale-x2 {
transform: scale(2);
}
.btn-scale-x2 .nopaque-icons.service-icons {
font-size: 2.5rem;
}
/* Fix material icon vertical alignment when nested in various elements */
h1 .nopaque-icons, h2 .nopaque-icons, h3 .nopaque-icons, h4 .nopaque-icons, .tab .nopaque-icons, .tab .material-icons {
line-height: inherit;
}
.corpus-status-text, .job-status-text {text-transform: lowercase;}
.corpus-status-text[data-status]:empty::before, .job-status-text[data-status]:empty::before {content: attr(data-status);}
.service-scheme[data-service="file-setup-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "E";}
.service-scheme[data-service="tesseract-ocr-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "F";}
.service-scheme[data-service="transkribus-htr-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "F";}
.service-scheme[data-service="spacy-nlp-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "G";}
.service-scheme[data-service="corpus-analysis"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "H";}
.nopaque-icons.service-icons[data-service="file-setup-pipeline"]:empty::before {content: "E";}
.nopaque-icons.service-icons[data-service="tesseract-ocr-pipeline"]:empty::before {content: "F";}
.nopaque-icons.service-icons[data-service="transkribus-htr-pipeline"]:empty::before {content: "F";}
.nopaque-icons.service-icons[data-service="spacy-nlp-pipeline"]:empty::before {content: "G";}
.nopaque-icons.service-icons[data-service="corpus-analysis"]:empty::before {content: "H";}
[draggable="true"] {cursor: move !important;}
.clickable {cursor: pointer !important;}
.chip.s-attr .chip.p-attr {background-color: inherit;}
.width-25 {width: 25%;}
.width-50 {width: 50%;}
.width-75 {width: 75%;}
.width-100 {width: 100%;}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

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