Author SHA1 Message Date
Michal Kváček 7b3f9f1717 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-05-25 14:46:10 +02:00
Michal Kváček 6037f88260 FIX: fix alert on contact form 2016-05-25 14:45:47 +02:00
peter 3df68ad5cd FEATURE: added google+ link into social icons 2016-04-25 19:01:10 +02:00
peter b06f884b4a FIX: fixed image placement in assortment detail for mobile 2016-04-25 18:54:38 +02:00
peter 53894d4657 FEAUTRE: fixed horizontal overflow on mobiles - another rule 2016-04-25 18:48:49 +02:00
peter 91683a48e2 FEAUTRE: fixed horizontal overflow on mobiles 2016-04-25 18:32:42 +02:00
peter 66f0873bc8 FEATURE: fixed mobile design flaws 2016-04-25 17:55:05 +02:00
peter c17ddd48f8 Some small graphical changes 2016-04-20 21:12:50 +02:00
Michal Kváček fc88a82888 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-20 19:23:50 +02:00
Michal Kváček bfcab20dad Merge branch 'dev' into test.customwristbands.cz 2016-04-20 19:23:38 +02:00
Michal Kváček 93bafee2e7 FIX: redirect to directory detail after file delete 2016-04-20 19:23:26 +02:00
Michal Kváček 3a6211c875 FIX: fix escaped pagination in content overview 2016-04-20 19:22:57 +02:00
peter e072e0e4af FEATURE: added some more changes for client 2016-04-19 00:16:38 +02:00
peter 070e929bf7 FEATURE: changes according to client mostly in texts and some graphical changes. HTML code validation changes 2016-04-18 23:48:40 +02:00
Michal Kváček 6dd6394ff1 Merge branch 'dev' into test.customwristbands.cz 2016-04-11 02:09:22 +02:00
Michal Kváček 5c6b72f83a Merge branch 'module_gallery' into dev 2016-04-11 01:35:28 +02:00
Michal Kváček 6a4cbb0a5c FEATURE: display only modules, which manages content in Web content tab 2016-04-11 01:35:09 +02:00
Michal Kváček 098ea3e7b1 FEATURE #1551: add deleting directory after page deletion. 2016-04-11 01:34:01 +02:00
Michal Kváček a48bed04b1 FEATURE: add content id to directory name (only for galleries) 2016-04-11 01:33:27 +02:00
Michal Kváček 288b1043b5 FEATURE #1551: add method for deleting extra content 2016-04-11 01:20:11 +02:00
Michal Kváček 492225e176 Merge branch 'dev' into test.customwristbands.cz 2016-04-08 14:14:40 +02:00
Michal Kváček 951a8314b7 FIX: fix escaping latin accents to HTML entities 2016-04-08 01:21:44 +02:00
Michal Kváček c99cee7a27 FEATURE: make CKEditor look nicer 2016-04-08 01:08:04 +02:00
Michal Kváček e94fff384a Merge branch 'sitemap' into dev 2016-04-08 00:17:06 +02:00
Michal Kváček 08026b286a FEATURE: remove config from .gitignore and turn on cache 2016-04-08 00:16:56 +02:00
Michal Kváček 5b97335536 REFACTORING: remove unnecessary files from public directory 2016-04-08 00:16:29 +02:00
Michal Kváček 8b157052e0 FEATURE: move robots.txt from public into root directory 2016-04-08 00:14:06 +02:00
Michal Kváček 01d9df4dd0 FEATURE: add all directories and files into .htaccess to be prevented from viewing from website 2016-04-08 00:13:46 +02:00
Michal Kváček 971fc796a8 FEATURE #1550: compute changefreq for entries in sitemap 2016-04-07 23:45:53 +02:00
Michal Kváček fa28de48ca DOCUMENTATION: add documentation for controller with sitemap 2016-04-07 23:17:48 +02:00
Michal Kváček 037d0c8dff FIX: remove spaces BEFORE <?php tagg a index.php 2016-04-07 23:00:05 +02:00
Michal Kváček 18ead80b5f FEATURE #1550: add basic sitemap
Probably will not work, because Laravel prepends first line of document with some spaces or what. However maybe its just behavior on my localhost.
2016-04-07 22:18:11 +02:00
peter d75c2838d3 FIX: homepage assortment list 2016-04-07 19:50:01 +02:00
peter 25860ae501 Merge branch 'test.customwristbands.cz' into customwristbands.cz 2016-04-07 19:47:47 +02:00
peter 56e2636e6c FEATURE: changes according to client 2016-04-07 19:47:29 +02:00
peter 509ae17fca Merge branch 'customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into customwristbands.cz 2016-04-07 18:16:01 +02:00
peter a20b9144a5 FEATURE: binarity footer for default layout 2016-04-07 18:15:12 +02:00
peter 59503baa9c Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-07 18:13:53 +02:00
peter b996ef493d FEATURES: changed layout according to what clients asked for, added binarity link into footer, some other small changes 2016-04-07 18:13:29 +02:00
Michal Kváček 5bc077989f Merge branch 'test.customwristbands.cz' into dev 2016-04-07 00:24:04 +02:00
Michal Kváček 725c379cd7 Merge branch 'customwristbands.cz' into dev 2016-04-07 00:23:51 +02:00
Michal Kváček eb8e7badd6 Merge branch 'customwristbands.cz' into test.customwristbands.cz 2016-04-07 00:23:30 +02:00
peter 0cc1916346 Merge branch 'test.customwristbands.cz' into customwristbands.cz 2016-04-07 00:14:49 +02:00
peter 5116fedac0 FIX: contact layout lat and long changes from parseInt to parseFloat 2016-04-07 00:14:21 +02:00
Michal Kváček 474405c69d FIX: fix ambiguous module_handler in content overview 2016-04-06 23:55:18 +02:00
Michal Kváček 74838f96fa FEATURE: remove page name from button in overview 2016-04-06 20:33:10 +02:00
Michal Kváček d231065fb8 Merge branch 'dev' into test.customwristbands.cz 2016-04-06 20:31:02 +02:00
Michal Kváček 7fc01fa1ec FIX: fix typo in COALESCE and escaping 2016-04-06 20:30:55 +02:00
Michal Kváček 5858820cb7 Merge branch 'dev' into test.customwristbands.cz 2016-04-06 20:28:22 +02:00
Michal Kváček 43051501bd FIX: when user did not fill his name, use email for content overview 2016-04-06 20:28:16 +02:00
Michal Kváček e3d715d2d0 Merge branch 'dev' into test.customwristbands.cz 2016-04-06 20:23:54 +02:00
Michal Kváček a4af5e2bac FIX: fix content page overview - changed join to left join 2016-04-06 20:23:47 +02:00
Michal Kváček 666557b585 Merge branch 'dev' into test.customwristbands.cz 2016-04-06 20:19:27 +02:00
Michal Kváček 85c33e9ada FEATURE: make overview in content pages little bit cleaner 2016-04-06 20:19:11 +02:00
Michal Kváček 6690d7423e FEATURE: swap date and action name in log 2016-04-06 19:13:46 +02:00
Michal Kváček d996c4c800 FIX: fix menu 'active' status when homepage is displayed 2016-04-06 19:10:33 +02:00
Michal Kváček de287abf24 OPTIMALIZATION: cache widget area content for one pageload 2016-04-06 19:06:03 +02:00
Michal Kváček fc9f3a403b FEATURE #1544: add social profile links into settings 2016-04-06 18:55:56 +02:00
Michal Kváček dcce436c59 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-06 18:02:25 +02:00
Michal Kváček 543cce17fa FIX: fix exception when debug bar was not installed 2016-04-06 18:01:31 +02:00
peter 2f7a3790b9 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-06 17:45:30 +02:00
peter d721aaf185 FEATURES: changes according to clients requests, simple mail template, some other small changes 2016-04-06 17:45:05 +02:00
Michal Kváček 303a84904e Merge branch 'dev' into test.customwristbands.cz 2016-04-06 17:26:15 +02:00
Michal Kváček e2f6fed4b1 Merge branch 'customwristbands.cz' into test.customwristbands.cz 2016-04-06 17:26:12 +02:00
Michal Kváček 87e4e96ca5 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-06 17:26:03 +02:00
Michal Kváček d7e5351d5b Merge branch 'widget_menu' into dev 2016-04-06 17:25:01 +02:00
Michal Kváček 1efaaaa4e0 FIX: fix failing menu on non-existing page 2016-04-06 17:24:29 +02:00
Michal Kváček 2eeb3227d3 FEATURE #1546: add subject for contact form 2016-04-06 17:23:46 +02:00
Michal Kváček b7c70bab7e FIX: fix duplicate url
In this way, deleted page will no longer "occupy" url.
2016-04-06 02:13:15 +02:00
Michal Kváček c3085180c0 Merge branch 'customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into customwristbands.cz 2016-04-06 02:03:44 +02:00
Michal Kváček 885dc691b2 Merge branch 'dev' into test.customwristbands.cz 2016-04-06 02:03:20 +02:00
Michal Kváček 4594e84945 FIX: change url to something random after content delete.
In this way, deleted page will no longer "occupy" url.
2016-04-06 01:48:14 +02:00
peter c42f860e9f Merge branch 'test.customwristbands.cz' into customwristbands.cz 2016-04-05 23:51:03 +02:00
peter 0ba38d146c FEATURE: removed some data from gallery 2016-04-05 23:48:59 +02:00
peter a42c1fb6c7 Merge branch 'customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into customwristbands.cz 2016-04-05 23:38:59 +02:00
peter b46c99efc4 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-05 23:38:03 +02:00
peter dddabe7724 FEATURE: added sortiment subpage template 2016-04-05 23:37:40 +02:00
Michal Kváček afc2af6e9b Merge branch 'customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into customwristbands.cz 2016-04-05 22:28:44 +02:00
Michal Kváček 9fe7e04e2f Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-05 22:28:16 +02:00
Michal Kváček ced6f978a8 FEATURE: add check for failed git pull in update 2016-04-05 22:27:22 +02:00
peter 522110aea1 FIX: homepage error 2016-04-05 22:06:15 +02:00
peter 5d1254da18 FEATURE: changed homepage template 2016-04-05 21:53:52 +02:00
Michal Kváček 7446e2f4ef FEATURE: add unlimited depth of subpages 2016-04-05 21:42:22 +02:00
Michal Kváček 9570ad3da3 FIX: fix view method in creating new user 2016-04-05 21:01:33 +02:00
peter 54f0566ee2 FEATURE: functional gallery template and lightbox 2016-04-05 19:26:56 +02:00
Michal Kváček d17a0ec8ef Merge branch 'dev' into test.customwristbands.cz 2016-04-04 23:40:22 +02:00
Michal Kváček ae1772652f FEATURE: add switch for installing on true - without git@binarity.cz: 2016-04-04 23:02:12 +02:00
Michal Kváček 19ad81a432 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-04 22:56:19 +02:00
Michal Kváček dac9de0024 FEATURE: add script for update and improve little bit installation 2016-04-04 22:53:17 +02:00
peter 281a1ed0ba FEATURE: defaults for address 2016-04-04 22:14:55 +02:00
Michal Kváček 9d2488e589 FEATURE: sort settings extensions 2016-04-04 22:00:47 +02:00
peter d3437aa2de FEATURE: functional contact page 2016-04-04 22:00:17 +02:00
Michal Kváček 1a33c74c6d REFACTORING: return / instaed of DIRECTORY_SEPARATOR in service providers 2016-04-04 21:48:05 +02:00
Michal Kváček 439b048590 FEATURE: add groups to published views in modules 2016-04-04 21:44:15 +02:00
Michal Kváček 743c6bdb07 FEATURE: add info about not-set homepage into contents overview 2016-04-04 21:43:11 +02:00
Michal Kváček 51b60440be FIX: catch exceptions on homepage 2016-04-04 21:42:13 +02:00
Michal Kváček ceaf9e7d6a FIX: fix saving new column type for content 2016-04-04 21:19:32 +02:00
Michal Kváček 30dcd045a6 FEATURE: add blade macro @upload 2016-04-04 21:15:54 +02:00
Michal Kváček a020e72dc5 FIX: fix publishing module views 2016-04-04 20:55:08 +02:00
Michal Kváček 3c90e20dd3 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-04 20:45:20 +02:00
Michal Kváček 33bd049d92 Merge branch 'dev' into test.customwristbands.cz 2016-04-04 20:45:04 +02:00
peter b06c2bf5a0 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-04 20:42:00 +02:00
Michal Kváček 090aed23cb FEATURE: add template helper for uploaded files url 2016-04-04 20:41:46 +02:00
peter d0411feebf FEATURE #1525: functional contact form template 2016-04-04 20:41:33 +02:00
Michal Kváček 3613c0fcf5 Merge branch 'test.customwristbands.cz' of binarity.cz:/opt/git/internal/cms/minicms into test.customwristbands.cz 2016-04-04 20:29:58 +02:00
Michal Kváček aff8e992d6 Merge branch 'module_contact_form' into dev 2016-04-04 20:29:24 +02:00
Michal Kváček 2d25e00d76 FEATURE: add second email into contact form
This commit adds second email into contact form - this one may be different from email used for delivering messages.
2016-04-04 20:26:51 +02:00
Michal Kváček 0f18b6361e FEATURE: add ajax response to contact form 2016-04-04 20:26:25 +02:00
Michal Kváček f27ad7c421 FIX: fix theme:set command.
This command did not set theme properly, when THEME was in .env file, but with no value (THEME= only - as default in .env.example).
2016-04-04 20:20:33 +02:00
peter 753b0cf2e2 FEATURE #1525: fully functional homepage design 2016-04-04 19:07:51 +02:00
peter 85dcf29c41 FIX: returned back .env.example 2016-04-04 11:13:11 +02:00
peter 503d209319 FIX: removed echo 2016-04-04 11:12:04 +02:00
peter ccf71dba81 FEATURE: more directory separators for static pages provider 2016-04-04 11:05:09 +02:00
peter 3646c79e1d Merge branch 'dev' into test.customwristbands.cz 2016-04-04 11:02:48 +02:00
peter 1f3cc2eebb FEATURE: directory separator for static pages provider 2016-04-04 11:01:49 +02:00
Michal Kváček 8a33f1b4c7 FIX: convert / to DIRECTORY_SEPARATOR for gallery and contact form 2016-04-04 10:59:52 +02:00
Michal Kváček 08cb40b004 Merge branch 'module_gallery' into dev 2016-04-03 02:39:09 +02:00
Michal Kváček 96d6f517dc FEATURE: add translation for template path 2016-04-03 02:39:03 +02:00
Michal Kváček d4ad1406bf Merge branch 'module_contact_form' into dev 2016-04-03 02:37:04 +02:00
Michal Kváček 9b2451fd98 FEATURE: add directory name for error pages 2016-04-03 02:36:30 +02:00
Michal Kváček 90b6979237 FIX: fix template path name for contact form 2016-04-03 02:35:44 +02:00
Michal Kváček 97ba21df98 FIX: remove link to non-existing controller 2016-04-03 02:35:14 +02:00
Michal Kváček c481f374a0 FIX: fix forgotten var_dump & die in EditContent 2016-04-03 02:20:56 +02:00
Michal Kváček d3f31c578f Merge branch 'module_static_pages' into dev 2016-04-03 02:16:46 +02:00
Michal Kváček 7947926f8d REFACTORING: remove not-used events and listeners in static pages 2016-04-03 02:16:36 +02:00
Michal Kváček a989421036 REFACTORING: remove some unneccessary files 2016-04-03 02:16:07 +02:00
Michal Kváček d0438f56dd FEATURE: add content page logging 2016-04-03 02:14:55 +02:00
Michal Kváček 7de45fe377 FEATURE #1532: add ip and user agent into logged information 2016-04-03 02:13:46 +02:00
Michal Kváček 9f8eb230e8 FIX: add .woff into supported extensions from assets 2016-04-03 00:47:00 +02:00
Michal Kváček 1914c17deb Merge branch 'test.customwristbands.cz' into dev 2016-04-03 00:45:44 +02:00
Michal Kváček 181f8a7e23 FIX: fix typo in homepage subpages 2016-04-02 21:25:14 +02:00
Michal Kváček 3a84279916 FIX: fix .htaccess so it can work properly with assets directory 2016-04-02 20:44:18 +02:00
Michal Kváček cfa9e2b09c Merge branch 'module_gallery' into dev 2016-04-02 20:26:49 +02:00
Michal Kváček 5178c7236b Merge branch 'dev' into test.customwristbands.cz 2016-04-02 20:09:27 +02:00
Michal Kváček 1e6bc86800 FEATURE: add basic templates for errors handling 2016-04-02 20:09:24 +02:00
Michal Kváček a620bf9e32 FEATURE: add possibility to style errors (404, 503 and unavailable homepage) 2016-04-02 20:08:55 +02:00
Michal Kváček 7cc04bc9ce FIX: fix exception cathing when registering template path 2016-04-02 20:08:02 +02:00
Michal Kváček a56fdfb6ce Merge branch 'dev' into test.customwristbands.cz 2016-04-02 19:20:37 +02:00
Michal Kváček 213283b51f Merge branch 'widget_orbit_slider' into dev 2016-04-02 19:20:19 +02:00
Michal Kváček 369cefe15f FEATURE: add blade template for homepage 2016-04-02 19:19:26 +02:00
Michal Kváček 284837bf12 REFACTORING: change p to button in slider 2016-04-02 19:17:31 +02:00
Michal Kváček a0ec4fc02f FIX: do not forget old values when creating slider 2016-04-02 19:14:48 +02:00
Michal Kváček f11c673173 FIX: fix widget saving - cast array to object when needed 2016-04-02 19:13:13 +02:00
Michal Kváček ce030a40d4 FEATURE: cache results for Content::subpages() 2016-04-02 19:11:46 +02:00
Michal Kváček 31c1648597 FEATURE #1530: make urls without /public
This change consist in renaming server.php to index.php, tweaking /.htaccess and replacing all asset('../resources....') with asset('resource/...') path. Everything should work fine now.
2016-04-02 16:56:53 +02:00
Michal Kváček 7bb63aca3f Merge branch 'cwbs_template' into dev 2016-04-02 13:26:21 +02:00
Michal Kváček 497708283f FEATURE #1528: add button for creating slider from gallery 2016-04-02 13:14:58 +02:00
Michal Kváček 2797ff0a89 REFACTORING: move method prepareSettings from presenter into widget handler 2016-04-02 10:35:48 +02:00
Michal Kváček 307dbe0459 FEATURE: add settings for displaying/hiding bullets in slider 2016-04-02 10:15:13 +02:00
Michal Kváček 9f4cc158db FEATURE #1527: add settings for displaying more images per row 2016-04-02 09:56:53 +02:00
Michal Kváček 19e0977bbb FEATURE #1496: add simple menu 2016-04-02 08:03:35 +02:00
peter 3900462229 FEATURE #1525: responsive menu 2016-04-02 00:53:51 +02:00
peter c48b99eaf0 Merge branch 'cwbs_template' of binarity.cz:/opt/git/internal/cms/minicms into cwbs_template 2016-04-01 23:33:57 +02:00
peter 34060ebf2e FEATURE #1525: responsive designs for small devices 2016-04-01 23:32:40 +02:00
Michal Kváček bc73fbc208 Merge branch 'dev' into widget_menu 2016-04-01 21:57:44 +02:00
Michal Kváček 32604653fb FEATURE: add default template for gallery 2016-04-01 21:51:15 +02:00
Michal Kváček 8de2c67323 Merge branch 'module_gallery' into cwbs_template 2016-04-01 21:50:55 +02:00
Michal Kváček f9afcae389 FEATURE #1526: add simple photogallery
Photogallery currently works with directories, UI is terrible, but it works.
2016-04-01 21:50:05 +02:00
Michal Kváček b9f721006d Merge branch 'search' into dev 2016-04-01 20:52:26 +02:00
Michal Kváček 3f7c048ad0 Merge branch 'dev' into module_contact_form 2016-04-01 20:49:00 +02:00
Michal Kváček acd85a1cad FEATURE: add editation to contact form 2016-04-01 20:48:44 +02:00
Michal Kváček 811f2162c9 FEATURE: force history to save even module_settings fields 2016-04-01 20:47:55 +02:00
Michal Kváček 3f03af7e03 FIX: copy-paste error - content editation used form for creating content 2016-04-01 20:47:43 +02:00
peter 7a71bbe90e Merge branch 'cwbs_template' of binarity.cz:/opt/git/internal/cms/minicms into cwbs_template 2016-04-01 19:37:29 +02:00
peter 5e51edcd48 FEATURE #1525: Added responsive version of contacts page for 1000px 2016-04-01 19:34:50 +02:00
Michal Kváček f0f95cc04f FEATURE: add basic for contact form 2016-04-01 17:52:10 +02:00
Michal Kváček 7a23ca1d3f Merge branch 'dev' into cwbs_template 2016-04-01 17:51:50 +02:00
Michal Kváček 9cda47f93d Merge branch 'module_contact_form' into dev 2016-04-01 17:51:03 +02:00
Michal Kváček a478f1491e FEATURE: make email sending working 2016-04-01 17:50:49 +02:00
Michal Kváček 5f050a7dea FEATURE: set config for sending emails 2016-04-01 17:48:23 +02:00
peter c2f024f8b8 FEATURE #1525: homepage for 1000px version ready 2016-04-01 17:10:45 +02:00
Michal Kváček f90f43fcd6 FEATURE: create module for contact form.
Currently contact form can be created, edit is not done yet. And also email sending neither work, now.
2016-04-01 17:04:10 +02:00
Michal Kváček 8838ecc6b1 FIX: fix ModuleManager service provider.
This service provider checked, if FILE was writable. When no file existed, it could not be writtable and therefore no module.json was created.
2016-04-01 17:03:04 +02:00
Michal Kváček efd2465b8b FIX: fix saving settings
Until now, only existing settings could be saved. No new records, only updates.
2016-04-01 17:00:55 +02:00
Michal Kváček 0c1162589c FIX: fix content edit
Content edit was strongly limited only on static pages. This limit was removed in this commit.
2016-04-01 17:00:10 +02:00
Michal Kváček 509ef1752e FEATURE: add publishing assets and views into installer 2016-04-01 12:06:59 +02:00
Michal Kváček 10dfe6b22e FEATURE: temporarily hide custom fields 2016-04-01 02:31:42 +02:00
Michal Kváček 5661a3d849 FIX #1438: disable role and status change for logged user 2016-04-01 02:06:22 +02:00
Michal Kváček cf2b4ac529 FEATURE: temporarily hide dashboard. 2016-04-01 02:04:09 +02:00
Michal Kváček 2b61709ade FEATURE #1522: add orbit slider
Had to change some things in global widgets management and also in html code widget. Sorry for this ugly commit..
2016-04-01 01:59:16 +02:00
Michal Kváček 6378d17753 FEATURE #1424: add title photo to list of all pages 2016-03-31 22:56:31 +02:00
Michal Kváček 590e1eeaca FEATURE #1423: add uploading of title photo for content pages 2016-03-31 22:39:38 +02:00
Michal Kváček 7d674357fe FEATURE #1518: split templates for content and for homepage 2016-03-31 21:15:24 +02:00
Michal Kváček e789b02a93 FEATURE #1523: add subpages for content 2016-03-31 21:12:54 +02:00
Michal Kváček acc7541ab9 FIX: fix history handling - null values were not updated 2016-03-31 21:11:51 +02:00
Michal Kváček 5045dca3d4 Merge branch 'cwbs_template' into dev 2016-03-31 20:07:03 +02:00
Michal Kváček c99e7c156d FEATURE: move views for default_theme into resource directory 2016-03-31 16:50:42 +02:00
Michal Kváček bc80ccc8e5 Merge branch 'dev' into cwbs_template 2016-03-31 16:50:14 +02:00
Michal Kváček 5494121dfb FEATURE #1518: add assets and views for static pages 2016-03-31 16:50:00 +02:00
Michal Kváček 26e5a52943 FEATURE: provide default template for displaying content of static pages 2016-03-31 16:48:50 +02:00
Michal Kváček 7a51c913d3 FEATURE #1524: merge views into one directory 2016-03-31 16:47:40 +02:00
Michal Kváček c49f4f2c5f Merge branch 'dev' into cwbs_template 2016-03-31 15:42:24 +02:00
Michal Kváček 980fec83c0 FEATURE: add config stubs into .env.example 2016-03-31 15:42:03 +02:00
Michal Kváček 473342490c FEATURE: add new blade macro @asset
This macro is used for loading path for assets on visitor page
2016-03-31 15:35:23 +02:00
peter b40815eec7 FEATURE: added contact template 2016-03-25 21:51:25 +01:00
peter 7317a51a24 FEATURE: added about us template 2016-03-25 21:16:54 +01:00
peter b228fe4615 FEATURE: added gallery template 2016-03-25 20:53:58 +01:00
peter c0f3c2cf07 FEATURE: some small changes in homepage, added assortment layout 2016-03-25 20:44:53 +01:00
peter 9b9362b8e9 FEATURE: initial cwbs template for homepage 2016-03-25 18:46:04 +01:00
Michal Kváček 7ef09ec326 FIX: make installator push created branch even into remote 2016-03-22 21:59:54 +01:00
Michal Kváček 86d7ffdab9 Merge branch 'dev' of binarity.cz:/opt/git/internal/cms/minicms into dev 2016-03-22 21:58:40 +01:00
Michal Kváček d6f0489b5f FEATURE: add installator for this CMS
Installator is written in bash as interactive script.
2016-03-22 21:58:05 +01:00
Michal Kváček 64aec15c8a FIX: fix seed for custom field resources 2016-03-22 16:05:58 +01:00
Michal Kváček 28c065e106 FEATURE: prevent running some service providers in artisan 2016-03-22 16:02:08 +01:00
Michal Kváček 98090f69df FEATURE: add artisan commands for creating db structure 2016-03-22 15:54:47 +01:00
Michal Kváček c2463f5e59 FEATURE: move theme into .env file 2016-03-22 15:53:45 +01:00
Michal Kváček 7788a598f4 FEATURE: *in progress* working on menu widgets 2016-03-22 15:53:23 +01:00
Michal Kváček 6c7122b494 FEATURE: prepare class structure for menu widget. 2016-03-15 15:02:36 +01:00
Michal Kváček 29b0eab314 FEATURE: divide search engines into admin and visitor ones.
After this separation, search engine may be registered once for visitor area (with one presenter) and once for admin area (with different presenter).
2016-03-15 14:12:03 +01:00
Michal Kváček 12f05586ed Merge branch 'search' into dev 2016-03-15 14:03:45 +01:00
Michal Kváček 35fe7aada3 FIX: fix saving meta keywords in content pages.
Keywords were not saved, instaed description was saved two times.
2016-03-15 14:03:10 +01:00
Michal Kváček 55ee35d14b FIX: remove spaces before and after searched string in input 2016-03-15 14:02:01 +01:00
Michal Kváček 3c9c53e04d DOCUMENTATION: add documentation for Search controller 2016-03-15 14:01:24 +01:00
Michal Kváček 6f50549072 FEATURE: register file searching 2016-03-15 14:00:53 +01:00
Michal Kváček b3da43921b FEATURE: prevent searching empty string.
This commit adds exception handling for serching empty string
2016-03-15 14:00:19 +01:00
Michal Kváček c4e65e18c4 FEATURE: add parent class for all search engines 2016-03-15 13:57:40 +01:00
Michal Kváček afbf3d1327 FEATURE: use overviewTiles for list of content pages 2016-03-14 23:27:16 +01:00
Michal Kváček 4d19d4388a FEATURE: add search form to top of page 2016-03-14 23:26:22 +01:00
Michal Kváček 81f6f4e46f FEATURE: add search form with results 2016-03-14 23:26:05 +01:00
Michal Kváček 72d00c8e64 FEATURE: add searching in content pages 2016-03-14 23:25:07 +01:00
Michal Kváček 8a94f1dbab FEATURE: add registering for new search engines. 2016-03-14 17:10:14 +01:00
Michal Kváček a237133227 DOCUMENTATION: add documentantion for installation commands 2016-03-14 13:23:57 +01:00
Michal Kváček 9ac8c24673 Merge branch 'static_pages' into dev 2016-03-14 13:16:26 +01:00
Michal Kváček bee7e732cc FEATURE: move module configuration into database 2016-03-14 13:16:04 +01:00
Michal Kváček e7c5a69f81 FEATURE: add commands for installing modules 2016-03-14 13:15:43 +01:00
Michal Kváček 6d13576185 FEATURE: use module_settings field instaed of config().
This way should be more reliable, because config() is available only after publishing module, however I can't publish module when it does not have config (module.json). In this way I can select all modules from database and generate module.json for each of them.
2016-03-14 13:14:01 +01:00
Michal Kváček 14f2673842 FEATURE: add module_settings to modules table 2016-03-14 13:13:18 +01:00
Michal Kváček 1bd00f1a4f Merge branch 'static_pages' into dev 2016-03-14 10:14:50 +01:00
Michal Kváček 4326105304 Merge branch 'edit' into dev 2016-03-14 10:14:19 +01:00
Michal Kváček c3008f3dcc FEATURE: add extended modules database structure 2016-03-14 10:12:28 +01:00
Michal Kváček e6880c82ec FIX: fix error when module does not have ID yet 2016-03-14 10:11:15 +01:00
Michal Kváček ca2318a529 REFACTORING: make .gitignore nicer 2016-03-14 10:11:15 +01:00
Michal Kváček b707d27c3f FEATURE: add service provider for generating module.json 2016-03-14 10:11:15 +01:00
Michal Kváček f9562d55aa FEATURE: remove published (unwanted) config from /config directory 2016-03-14 10:11:15 +01:00
Michal Kváček a39a402011 FEATURE: add extended modules database structure
FEATURE: add extended modules database structure

squash
2016-03-14 10:11:01 +01:00
Michal Kváček 892a597912 FEATURE: allow enabling of static pages via database 2016-03-14 10:10:00 +01:00
Michal Kváček 85e9e6ebb6 Merge branch 'settings' into dev 2016-03-14 00:53:48 +01:00
Michal Kváček 2941d694da FEATURE: remove hard-coded shared variable "vendorName" 2016-03-14 00:53:04 +01:00
Michal Kváček 2a6672934d FEATURE: add automacally loaded settings into all views 2016-03-14 00:47:06 +01:00
Michal Kváček 0313a1239f FEATURE: add saving settings 2016-03-14 00:46:09 +01:00
Michal Kváček 603e989b1e FEATURE: add registrators for settings form 2016-03-14 00:26:17 +01:00
Michal Kváček 62a600b5fc FEATURE: seed settings table with some basic data 2016-03-14 00:25:56 +01:00
Michal Kváček 1353fbfd79 FEATURE: add settings table 2016-03-14 00:25:46 +01:00
Michal Kváček df3bc22954 FEATURE #1508: merge files and directories overview.
This commit merges list of all uploaded files and created directories into one page. It also modifies way of uploading files. Special page for uploading files was removed (because of no support for directories) and files can be uploaded only via overview.
2016-03-13 22:50:20 +01:00
Michal Kváček 069367a816 FEATURE #1508: add directories to uploaded files
This commit contains both creating and editing directories.
2016-03-13 22:49:29 +01:00
Michal Kváček 8af9943100 FEATURE: remove link to uploading image
Image upload and normal file uploads are same functions. Image can be uploaded via uploading normal file.
2016-03-13 15:24:12 +01:00
Michal Kváček 97fc32c3ae FEATURE #1508: add database structure for directories 2016-03-13 14:41:05 +01:00
Michal Kváček 063ba90ce8 FIX: allow menu registration only for logged user
This funcionality should be acomplished using "auth" middleware, however I am not sure if order of middlewares matter. For this case I have added one if to this middleware.
2016-03-12 11:17:12 +01:00
Michal Kváček 141df72356 FEATURE #1509: remove admin menu from vistors area
Moved middleware providing registration of menu into admin area
2016-03-11 16:48:18 +01:00
Michal Kváček a9a4cb70f0 FIX: fixing some missing translations and other minor bugs 2016-03-11 16:27:26 +01:00
Michal Kváček 0a1a25b300 Merge branch 'static_pages' into dev 2016-03-11 15:48:51 +01:00
Michal Kváček d0601c4fdd FEATURE: add links from history detail back to edit form 2016-03-11 15:48:15 +01:00
Michal Kváček eed7e15650 FEATURE #1507: adapt static pages for new modular content management 2016-03-11 15:47:27 +01:00
Michal Kváček 9f5bd46ca3 FEATURE #1507: modularize content management 2016-03-11 15:43:11 +01:00
Michal Kváček 3407707046 FEATURE: display content with given template 2016-03-09 22:27:43 +01:00
Michal Kváček 03dbf22eb0 FEATURE: add saving templates to static pages 2016-03-09 22:27:43 +01:00
Michal Kváček 661d5c486d REFACTORING: refactor code a little bit.
Removed redundant empty lines, merging config made little bit "cleaner"
2016-03-09 22:24:01 +01:00
Michal Kváček d52dcbcf55 FEATURE: add registering template path 2016-03-09 22:23:31 +01:00
Michal Kváček d7565ec7bf FEATURE: update project dependencies 2016-03-09 22:19:02 +01:00
Michal Kváček d7b247a2e3 FEATURE: add translation of "template" for content history 2016-03-09 22:17:46 +01:00
Michal Kváček a67417380f FEATURE: add enumeration for translating module handlers for their ids
This feature will need bit more optimalization. This is somehow weird approach.
2016-03-09 22:11:49 +01:00
Michal Kváček f79fc78868 FIX: supress error when trying to open non-existing template 2016-03-09 22:09:42 +01:00
Michal Kváček fc58a4d31c FEATURE: allow copying only when directory is wirtable 2016-03-09 22:09:24 +01:00
Michal Kváček fe9e76bf28 FEATURE: add namespaces for copied templates 2016-03-09 22:08:28 +01:00
Michal Kváček 8aa2ebd0b0 FEATURE: add support for registering template paths with module id 2016-03-09 22:07:50 +01:00
Michal Kváček bb7106d706 FEATURE: add module id into contents table 2016-03-09 21:55:27 +01:00
Michal Kváček 464eaf8b17 REFACTORING: remove unneeded AdminMenusProvider 2016-03-08 23:42:16 +01:00
Michal Kváček b6a1a4d444 FIX: fixed broken namespaced translations.
Translations was broken because namespace "staticpages" was loaded (registered) after first usage of this namespace. I do not understand this bug, however it should be fixed now.
2016-03-08 23:42:06 +01:00
Michal Kváček f97ac0e868 FEATURE: remove adding new template 2016-03-08 11:00:00 +01:00
Michal Kváček b8f8c75146 FIX: fixed template numbering.
This commit fixes numbering of edited templates.
2016-03-07 16:37:00 +01:00
Michal Kváček 6723381384 FIX: fix saving template created as copy
Copied templates are automatically stored *only* into custom directory. They cannot be under control of VCS (while they would need to be commited after creating) and therefore are stored only localy. Previous version contained bug, that "previous" template was taken from "original" destination.
2016-03-07 16:34:56 +01:00
Michal Kváček 6e6be7f790 FEATURE: add copying of templates 2016-03-07 16:27:00 +01:00
Michal Kváček fa97ccc032 FEATURE: add basic funcionality for template copies.
This commit contains only basic funcionality.
2016-02-29 18:02:22 +01:00
Michal Kváček 57e08b76a8 FEATURE #1431: add template edit 2016-02-19 15:10:39 +01:00
Michal Kváček 53395bc47a FEATURE #1454: add Ace editor 2016-02-19 15:09:45 +01:00
Michal Kváček d082cee7b5 FEATURE #1455: add template path overview 2016-02-18 18:19:52 +01:00
Michal Kváček f3dde68481 FIX: fix typos in registrating templates 2016-02-18 17:46:15 +01:00
Michal Kváček 66c9d7907a FEATURE #1453: add registration of templates 2016-02-18 16:28:32 +01:00
Michal Kváček 214cc9f3f9 FEATURE #1452: add parent id and name to template_paths table 2016-02-18 14:45:15 +01:00
Michal Kváček 2c95acfe76 FEATURE #1453: add model of template_paths table 2016-02-18 11:39:16 +01:00
Michal Kváček 4e85799403 FEATURE #1452: add table for template paths.
We will not store template directories along with the templates. Templates are now binded to their paths using ID of row in database
2016-02-18 11:35:09 +01:00
Michal Kváček ad457db740 FEATURE #1452: add database migration for adding templates into database 2016-02-17 16:14:26 +01:00
Michal Kváček 6a7402248a Merge branch 'homepage' into dev 2016-02-17 14:15:34 +01:00
Michal Kváček d7c7e642a4 FIX: fix namespace in template name 2016-02-17 14:15:21 +01:00
Michal Kváček 03086f7fd3 FEATURE: add handler for displaying static pages 2016-02-17 13:29:30 +01:00
Michal Kváček 37a698b631 FEATURE #1427: add homepage functionality.
Displaying homepage now depends on module handler
2016-02-17 13:24:16 +01:00
Michal Kváček 6d0e6e26f6 FEATURE #1427: add basic homepage support 2016-02-15 17:09:50 +01:00
Michal Kváček 36fc280f55 FEATURE #1428: add migration for adding flag "is_homepage" to contents 2016-02-15 16:54:08 +01:00
Michal Kváček 9269d8c0b9 Merge branch 'widgets' into dev 2016-02-15 14:30:33 +01:00
Michal Kváček c75a6bd364 FEATURE #1451: add logging to all actions in widget management 2016-02-15 14:30:00 +01:00
Michal Kváček 3b1ca7c1a7 Merge branch 'user_management' into dev 2016-02-15 12:26:44 +01:00
Michal Kváček b344c928b4 REFACTORING: minor changes in new lines and spaces 2016-02-15 12:26:12 +01:00
Michal Kváček b5b41a0888 FEATURE: add link to list of all widgets 2016-02-15 12:26:12 +01:00
Michal Kváček 81a0fc83b9 FEATURE: add widget and widget area preview into Blade template 2016-02-15 12:26:12 +01:00
Michal Kváček c1e65d5651 FEATURE: add events and listeners stubs 2016-02-15 12:26:12 +01:00
Michal Kváček e8f994ff5f FEATURE #1449: assign widget to some widget area 2016-02-15 12:26:12 +01:00
Michal Kváček 1d553d1a15 FEATURE #1450: add widget overview 2016-02-15 12:25:56 +01:00
Michal Kváček 8ba8a45938 FEATURE: add commands for creating new user and changing password of existing one.
This commit adds two new artisan commants user:new and user:change-password.
2016-02-15 12:24:23 +01:00
Michal Kváček ccc2d918c9 FEATURE: add functionality for creating new widget.
This commit adds functionality for creating widget of whatever type. Controller calls widget admin handler, which renders and handles input form.
2016-02-15 12:19:54 +01:00
Michal Kváček 043c842aef FEATURE #1446: add html code widget 2016-02-15 12:19:54 +01:00
Michal Kváček da3046c990 FEATURE #1422: prepare application for registering widgets 2016-02-15 12:19:40 +01:00
Michal Kváček 677acf3dcb FEATURE: add delete functionality for widget areas 2016-02-15 10:28:36 +01:00
Michal Kváček 88d9ca48a3 FEATURE #1420: add functionality for editing widget area 2016-02-15 10:27:33 +01:00
Michal Kváček b290fb3ff5 FEATURE #1421: add widget area overview 2016-02-15 10:27:21 +01:00
Michal Kváček 012b8b7588 FEATURE #1419: add admin for creating new widget area 2016-02-15 10:26:39 +01:00
Michal Kváček d7dbdf7fc5 FEATURE: add routes for widgets and widget areas 2016-02-15 10:26:02 +01:00
Michal Kváček 4a1ca1fcd8 FEATURE: tune a little bit composer.json
Enable optimizing autoloader and setup minimum stability to "dev"
2016-02-15 01:02:51 +01:00
Michal Kváček 2ab3896ee7 FEATURE #1426: add log of all users 2016-02-08 23:05:32 +01:00
Michal Kváček 9de95c24c8 FEATURE: #1425: add user log actions 2016-02-08 21:53:30 +01:00
Michal Kváček 39591c11c3 FIX #1440: fix translation string 2016-02-08 20:54:29 +01:00
Michal Kváček 5f38ad2e3a FEATURE: add icons to static page menu 2016-02-08 20:45:27 +01:00
Michal Kváček c73bc1452b Merge branch 'file_manager' into static_pages 2016-02-08 19:59:07 +01:00
Michal Kváček a5e8eb8fc4 FEATURE #1417: add working buttons.
Buttons for editing and deleting file works as expected. I have also added link to image preview.
2016-02-08 19:56:33 +01:00
Michal Kváček 1a8b07971e FEATURE #1442: add uploaded file detail
This commit adds functionality for editing keywords and description of selected file. This commit also includes JS library for syntax highlighting (https://highlighjs.org)
2016-02-08 19:55:09 +01:00
Michal Kváček 3e9477ddc3 FEATURE #1417: add filtering for file overview 2016-02-08 16:15:03 +01:00
Michal Kváček bd38e3fd98 FEATURE #1417: add uploaded files overview 2016-02-08 16:06:44 +01:00
Michal Kváček e98032a3e1 FEATURE: add file size to uploaded files 2016-02-08 14:50:44 +01:00
Michal Kváček eb28696d82 FEATURE #1442: add stubs for file edit 2016-02-08 14:37:38 +01:00
Michal Kváček df1e1390e7 FEATURE #1417: add stubs for file overview 2016-02-08 14:37:06 +01:00
Michal Kváček d414e53789 FEATURE #1337: add stubs for uploading images 2016-02-08 14:35:56 +01:00
Michal Kváček 24144f6aa4 FEATURE #1337: add file upload
This commit registers new items into admin menu and adds functionality for uploading files.
2016-02-08 14:27:43 +01:00
Michal Kváček 58a3386277 FEATURE #1377: add stubs for uploading files 2016-02-05 22:34:41 +01:00
Michal Kváček 8763a5da95 FEATURE #1413: static pages switched to Ckeditor.
Currently only the basic configuration is used.
2016-02-05 17:32:48 +01:00
Michal Kváček fc33c06613 FEATURE: optimize composer.json
This commit removed unneccessary packages. It also moves some of development packages into require-dev section.
2016-02-05 17:16:34 +01:00
Michal Kváček 1c14bdd390 FEATURE #1413: add Ckeditor 2016-02-05 17:15:43 +01:00
Michal Kváček 8fe0558374 Merge branch 'dev' into history 2016-02-05 17:03:22 +01:00
Michal Kváček 2e276335af FEATURE: module history handler is not called only for module_settings 2016-02-05 17:02:49 +01:00
Michal Kváček aeabe03911 FEATURE #1373: add link to history for static pages 2016-02-05 16:18:18 +01:00
Michal Kváček 620a5545d8 FEATURE #1373: add history of content
This commit contains only core funcionality of displaying history. Module settings must be implemented in each module.
2016-02-05 16:06:13 +01:00
Michal Kváček 0216d923d4 Merge branch 'dev' into user_management 2016-01-29 12:27:03 +01:00
Michal Kváček f262be1dcb FEATURE: allow user edit only for admin 2016-01-29 12:26:39 +01:00
Michal Kváček 780ee89d21 FEATURE #1387: divide routes into groups - one for admin, the rest for other users 2016-01-29 12:25:53 +01:00
Michal Kváček 270f77f451 Merge branch 'static_pages' into dev 2016-01-29 12:00:58 +01:00
Michal Kváček 3a0f7c7cd4 FEATURE: move menu registration into handler class. 2016-01-29 12:00:39 +01:00
Michal Kváček a880ab9e15 FEATURE #1401: add middleware for registering modules 2016-01-29 11:59:57 +01:00
Michal Kváček ee55715093 FEATURE #1374: add logging for static pages 2016-01-29 01:57:12 +01:00
Michal Kváček 593506c646 Merge branch 'user_management' into dev 2016-01-29 00:40:32 +01:00
Michal Kváček 3902a75b2c Merge branch 'static_pages' into dev 2016-01-29 00:40:23 +01:00
Michal Kváček b7d0258f06 Merge branch 'action_log' into dev 2016-01-29 00:40:17 +01:00
Michal Kváček b3c543f06c FEATURE: prepare logging for settings (once it will exist) 2016-01-29 00:37:45 +01:00
Michal Kváček 4a8facc046 FEATURE #1400: add logging for custom fields 2016-01-29 00:36:20 +01:00
Michal Kváček 7054ce53b6 FEATURE #1375: add logging for user edit and creating 2016-01-29 00:22:46 +01:00
Michal Kváček 5fabc08a99 FEATURE #1367: add log of login and logout 2016-01-29 00:20:40 +01:00
Michal Kváček 859d3ce753 FEATURE: add string id into seeder of action log types. 2016-01-28 22:44:03 +01:00
Michal Kváček 26873a2db4 FEATURE: add string id for action log types.
This string ID will be used in each logger for better readability (we will use string identifier except the "magical" integer constant)
2016-01-28 22:42:06 +01:00
Michal Kváček 527b482ab8 FEATURE: make users overview look less ugly 2016-01-28 21:25:13 +01:00
Michal Kváček da23bb4100 TESTING: add tests for writing into bootstrap/cache and storage directories 2016-01-28 20:51:35 +01:00
Michal Kváček 0c7a138e43 FEATURE: add seed and enumeration for action log types 2016-01-28 17:01:54 +01:00
Michal Kváček 703adfcb78 FEATURE #1386: catch CSRF token exception 2016-01-28 16:00:31 +01:00
Michal Kváček 73ff4e9331 FEATURE #1372: add feature for editing static pages.
User can edit static pages. The edit itself also stores history of changed columns.
2016-01-28 15:51:41 +01:00
Michal Kváček 1b2d7db8f3 FEATURE: add quick actions to static page overview 2016-01-28 13:38:30 +01:00
Michal Kváček 0f4ad90cd8 FEATURE: add overview to all static pages 2016-01-28 12:49:27 +01:00
Michal Kváček d9b678036a FEATURE: add overview to all static pages 2016-01-27 20:13:57 +01:00
Michal Kváček 8210eafad5 FEATURE: add displaying errors 2016-01-27 16:25:42 +01:00
Michal Kváček e63f78e67b FEATURE: add content status and wysiwyg editor 2016-01-27 16:07:30 +01:00
Michal Kváček ff80cbca4f Merge branch 'enumerations' into static_pages 2016-01-27 16:03:03 +01:00
Michal Kváček 4506b62387 FEATURE: add enumeration for content statuses 2016-01-27 16:02:45 +01:00
Michal Kváček 63c05ba6f9 Merge branch 'dev' into static_pages 2016-01-27 15:45:36 +01:00
Michal Kváček cac5b1dfb9 FEATURE: init trumbowyg editor 2016-01-27 15:45:14 +01:00
Michal Kváček 19ee504075 FEATURE: add translation for static page 2016-01-27 15:42:35 +01:00
Michal Kváček 5db999e3b1 FEATURE: move static page handler into config 2016-01-27 15:36:11 +01:00
Michal Kváček 35a93091ff FEATURE #1394: init static page module
Module is now installed and ready to be used
2016-01-27 15:28:41 +01:00
Michal Kváček 79d5277a13 Merge branch 'enumerations' into static_pages 2016-01-27 15:27:36 +01:00
Michal Kváček 686ce63ca7 FIX: fix enumerations - empty init caused error 2016-01-27 15:27:15 +01:00
Michal Kváček 76f865566e Merge branch 'enumerations' into static_pages 2016-01-27 15:17:08 +01:00
Michal Kváček c4dd6cc229 FIX: fix enumeration for modules.
Module does not have ID field. Instead, it has handler field.
2016-01-27 15:16:15 +01:00
Michal Kváček cc832d5249 FEATURE #1394: add modules enumeration class 2016-01-27 15:02:22 +01:00
Michal Kváček 195ba54005 FEATURE #1370: add form for creating new static page 2016-01-27 14:55:59 +01:00
Michal Kváček 0302de734b Merge branch 'user_management' into dev 2016-01-27 02:00:27 +01:00
Michal Kváček 452280a6fe FEATURE: remove @lang() from blade templates when translating enumerations.
Enumerations are translated right after inserting into collection, so there is no need to translate it again.
2016-01-27 01:58:57 +01:00
3482 changed files with 56265 additions and 1383 deletions
+11 -14
View File
@@ -1,23 +1,20 @@
APP_ENV=local APP_ENV=testing
APP_DEBUG=true APP_DEBUG=true
APP_KEY=SomeRandomString APP_KEY=ZKZAzM23wQ6BPji6zffBjaTzZ3yW7zKQ
DB_HOST=localhost DB_HOST=localhost
DB_DATABASE=homestead DB_DATABASE=
DB_USERNAME=homestead DB_USERNAME=
DB_PASSWORD=secret DB_PASSWORD=
CACHE_DRIVER=file CACHE_DRIVER=file
SESSION_DRIVER=file SESSION_DRIVER=file
QUEUE_DRIVER=sync QUEUE_DRIVER=sync
REDIS_HOST=localhost MAIL_USERNAME=@binarity.cz
REDIS_PASSWORD=null MAIL_PASSWORD=
REDIS_PORT=6379
MAIL_DRIVER=smtp SITE_URL=/
MAIL_HOST=mailtrap.io UPLOAD_URL=/public/uploads
MAIL_PORT=2525 THUMBNAILS_URL=/uploads/thumbnails
MAIL_USERNAME=null THEME=
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
+24 -5
View File
@@ -1,9 +1,28 @@
# published files from modules
/resources/views/modules
/public/modules
/resources/views/vendor /resources/views/vendor
!/resources/views/vendor/.gitkeep /public/assets
# directories with custom templates
**/views/**/custom/*
!**/views/**/custom/.gitkeep
# module config - generated in ModuleManager service provider
**/module.json
# uploaded files
/public/uploads/*
!/public/uploads/.gitkeep
# environment settings
/.env /.env
# dependecies - installed using Composer
/vendor /vendor
# PhpStorm project directory
/.idea /.idea
/node_modules
Homestead.yaml # meta information created by installer
Homestead.json .install
.env
+35
View File
@@ -0,0 +1,35 @@
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
RewriteCond %{REQUEST_URI} !(\.css|\.js|\.png|\.jpg|\.gif|\.woff|robots\.txt)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^/public/
RewriteRule ^(assets)/(.*)$ public/$1/$2 [L,NC]
# disable viewing all hiden files
RedirectMatch 403 /\..*$
# disable browsing other files in root
RedirectMatch 403 /composer.*
RedirectMatch 403 /artisan
RedirectMatch 403 /phpunit.xml
# disable browsing directories
# this should be solved also with Option -Indexes, however...
RedirectMatch 403 ^/app
RedirectMatch 403 ^/artisan
RedirectMatch 403 ^/bootstrap
RedirectMatch 403 ^/config
RedirectMatch 403 ^/database
RedirectMatch 403 ^/modules
RedirectMatch 403 ^/scripts
RedirectMatch 403 ^/storage
RedirectMatch 403 ^/tests
RedirectMatch 403 ^/vendor
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Hash;
class ChangePassword extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'user:change-password {userID} {newPassword}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Change password for user with given ID';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$id = $this->argument('userID');
$newPassword = $this->argument('newPassword');
try {
$user = User::findOrFail($id);
} catch (ModelNotFoundException $e) {
$this->error('Invalid user ID ' . $id . '. Please see table `users` for correct IDs.');
exit(1);
}
// set new password
$user->password = Hash::make($newPassword);
$user->save();
$this->info('Password successfully changed.');
}
}
@@ -0,0 +1,51 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class InitDatabaseSchema extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'db:init {schema.sql}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$schema = $this->argument('schema.sql');
if (!file_exists($schema)) throw new NotFoundHttpException('File '.$schema.' does not exist.');
DB::unprepared(file_get_contents($schema));
$this->line('Successfully imported');
}
}
-33
View File
@@ -1,33 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Foundation\Inspiring;
class Inspire extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'inspire';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Display an inspiring quote';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->comment(PHP_EOL.Inspiring::quote().PHP_EOL);
}
}
@@ -0,0 +1,54 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
class InstallAllModules extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'install-all-modules';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Crawl /modules directory and install all modules';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// crawl all subdirectories in modules path
$modules = File::directories(config('modules.paths.modules'));
foreach ($modules as $module) {
$moduleName = basename($module);
// try to install each module
try {
$this->call('install-module', ['name' => $moduleName]);
} catch (\Exception $e) {
$this->line('Module ' . $moduleName . ' already installed.');
}
}
}
}
+131
View File
@@ -0,0 +1,131 @@
<?php
namespace App\Console\Commands;
use App\Models\Module;
use Illuminate\Console\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
class InstallModule extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'install-module {name}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Custom installation of CMS module. Name given as directory name in /modules.';
protected $moduleName;
protected $modulesPath;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
$this->modulesPath = config('modules.paths.modules');
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->moduleName = $name = $this->argument('name');
// invalid module name provided
if (!is_dir($this->modulesPath . DIRECTORY_SEPARATOR . $name)) {
throw new InvalidArgumentException('Invalid module ' . $name . '. No directory under ' . $this->modulesPath . DIRECTORY_SEPARATOR . $name . ' found!');
}
// get config
$config = $this->loadConfig();
// check if it is valid
$this->checkMandatoryFields($config);
// all mandatory fields are present, we can write it into database and create modules.json
$this->installModule($config);
// inform user
$this->line('Module ' . $name . ' successfuly installed');
}
/**
* Load config from Config/config.php in module files. We cannot use config() because the file have not published
* yet.
*
* @return array
*/
private function loadConfig()
{
// we cannot rely on config() helper, because this module does not have to be published
$config = @include($this->modulesPath . DIRECTORY_SEPARATOR . $this->moduleName . DIRECTORY_SEPARATOR . 'Config' . DIRECTORY_SEPARATOR . 'config.php');
return $config;
}
/**
* Checks if config contains all mandatory entries.
*
* @param $config
*/
private function checkMandatoryFields($config)
{
$fields = ['providers', 'handler', 'name', 'files', 'alias'];
foreach ($fields as $field) {
if (!isset($config[$field])) {
throw new MissingMandatoryParametersException('Missing *' . $field . '* in config file! Cannot install ' . $this->moduleName);
}
}
}
/**
* Installs module into database.
*
* This method calls Module::install, which handles specific installation of module. In this way we should be able
* to install any module even with some other database structures.
*
* @param $config
*
* @return Module
* @throws \ErrorException
* @throws \Exception
*/
private function installModule($config)
{
$name = isset($config['translatedName']) ? $config['translatedName'] : $config['name'];
$description = isset($config['translatedDescription']) ? $config['translatedDescription'] : null;
// check if module is not installed yet
$exists = Module::where('handler', $config['handler'])
->exists();
if ($exists) {
throw new \Exception('Module ' . $config['name'] . ' already exists in database.');
}
$settings = [
'staticName' => $this->moduleName,
'providers' => $config['providers'],
'aliases' => isset($config['aliases']) ? $config['aliases'] : [],
'order' => isset($config['order']) ? $config['order'] : 0,
'files' => $config['files']
];
$module = Module::install($name, $config['alias'], $description, $config['handler'], $settings);
return $module;
}
}
+52
View File
@@ -0,0 +1,52 @@
<?php
namespace App\Console\Commands;
use App\Enumerations\UserRoles;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;
use Symfony\Component\Console\Exception\InvalidArgumentException;
class NewUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'user:new {email} {password} {role}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Creates new user';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$email = $this->argument('email');
$password = $this->argument('password');
$role = $this->argument('role');
// check if given role is valid
$roles = UserRoles::getSimple();
if (!in_array($role, $roles)) {
throw new InvalidArgumentException('Invalid role specified. valid roles are: ' . implode(', ', $roles));
}
// create new user
$user = new User();
$user->username = $user->email = $email;
$user->password = Hash::make($password);
$user->role = $role;
$user->save();
$this->info('User ' . $email . ' successfully created.');
}
}
+70
View File
@@ -0,0 +1,70 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class SetTheme extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'theme:set {theme_name}';
/**
* The console command description.
* @var string
*/
protected $description = 'Set theme for visitor area';
/**
* Create a new command instance.
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
* @return mixed
*/
public function handle()
{
$theme = $this->argument('theme_name');
if (!is_dir(resource_path('views/visitor/' . $theme))) {
throw new NotFoundHttpException('Invalid theme ' . $theme . '!');
}
// load .env file
$envFile = base_path('.env');
$env = file_get_contents($envFile);
if (!Str::contains($env, 'THEME=')) {
$env = sprintf("%s\nTHEME=%s\n", $env, $theme);
} else {
$env = preg_replace('/THEME=(.*)/i', 'THEME=' . $theme, $env, -1, $cnt);
}
// try to write content
$bytesWritten = file_put_contents($envFile, $env);
// check if write was successfull
if (!$bytesWritten) {
throw new \Exception('Cannot write to ' . base_path('.env') . '. Add THEME=' . $theme . ' to your .env file manualy.');
}
// theme written
$this->line('Theme successfully setup.');
$this->line('');
$this->line(' ** PUBLISHING ASSETS AND VIEWS **');
// publish assets and views for module and theme
$this->call('vendor:publish', ['--tag' => ['public-assets'], '--force' => true]);
$this->call('vendor:publish', ['--tag' => ['module-views'], '--force' => true]);
$this->call('vendor:publish');
}
}
+65
View File
@@ -0,0 +1,65 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class SetupDatabase extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'db:setup {host} {user} {password} {database}';
/**
* The console command description.
* @var string
*/
protected $description = 'Setup database credentials';
/**
* Create a new command instance.
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
* @return mixed
*/
public function handle()
{
echo "zpracovavam";
$host = $this->argument('host');
$user = $this->argument('user');
$password = $this->argument('password');
$database = $this->argument('database');
// try to connect with this settings
// @todo add credentials verification
// if pass, proceed to creating .env file
$parameters = [
'DB_HOST' => $host,
'DB_USERNAME' => $user,
'DB_PASSWORD' => $password,
'DB_DATABASE' => $database
];
$envPath = base_path('.env');
$env = file_get_contents($envPath);
if (!file_exists($envPath))
$env = file_get_contents($envPath.'.example');
foreach ($parameters as $parameter => $value) {
$env = preg_replace('/'.$parameter.'=(.*)/i', $parameter.'='.$value, $env);
}
file_put_contents($envPath, $env);
}
}
+9 -2
View File
@@ -13,13 +13,20 @@ class Kernel extends ConsoleKernel
* @var array * @var array
*/ */
protected $commands = [ protected $commands = [
// Commands\Inspire::class, Commands\NewUser::class,
Commands\ChangePassword::class,
Commands\InstallModule::class,
Commands\InstallAllModules::class,
// Commands\SetupDatabase::class,
Commands\InitDatabaseSchema::class,
Commands\SetTheme::class,
]; ];
/** /**
* Define the application's command schedule. * Define the application's command schedule.
* *
* @param \Illuminate\Console\Scheduling\Schedule $schedule * @param \Illuminate\Console\Scheduling\Schedule $schedule
*
* @return void * @return void
*/ */
protected function schedule(Schedule $schedule) protected function schedule(Schedule $schedule)
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Enumerations;
use App\Models\ActionLogType;
class ActionLogTypes extends BaseEnumeration
{
/**
* Init list of all action log types
*
* @throws Exceptions\EnumerationExistsException
*/
protected static function init()
{
$types = ActionLogType::all(['id', 'name']);
foreach ($types as $type) {
self::push($type->id, $type->name);
}
}
}
@@ -0,0 +1,16 @@
<?php
namespace App\Enumerations;
use App\Models\ActionLogType;
class ActionLogTypesForLogger extends BaseEnumeration
{
protected static function init()
{
$types = ActionLogType::all(['string_id', 'id']);
foreach ($types as $type) {
self::push($type->string_id, $type->id);
}
}
}
@@ -0,0 +1,18 @@
<?php
namespace App\Enumerations;
use App\Models\Content;
class ActiveContentStatuses extends BaseEnumeration
{
protected static function init()
{
foreach (ContentStatuses::getWithTranslations() as $key => $value) {
if ($key == Content::STATUS_DELETED) {
continue;
}
self::push($key, $value);
}
}
}
+5
View File
@@ -26,6 +26,11 @@ abstract class BaseEnumeration
$className::init(); $className::init();
} }
// it can happen that even after init no enumerations are available
if (empty(self::$items[$className])) {
self::$items[$className] = [];
}
self::$initiliazed[] = $className; self::$initiliazed[] = $className;
} }
} }
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Enumerations;
use App\Models\Content;
class ContentStatuses extends BaseEnumeration
{
protected static function init()
{
$roles = [
Content::STATUS_DRAFT => 'admin/contents.status_' . Content::STATUS_DRAFT,
Content::STATUS_DELETED => 'admin/contents.status_' . Content::STATUS_DELETED,
Content::STATUS_PROTECTED => 'admin/contents.status_' . Content::STATUS_PROTECTED,
Content::STATUS_PUBLIC => 'admin/contents.status_' . Content::STATUS_PUBLIC
];
foreach ($roles as $role => $translation) {
self::push($role, $translation);
}
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Enumerations;
use App\Models\Module;
class ModuleNamesWithIds extends BaseEnumeration
{
/**
* Init list of all installed modules
*
* @throws Exceptions\EnumerationExistsException
*/
protected static function init()
{
$modules = Module::all(['id', 'name']);
foreach ($modules as $module) {
self::push($module->id, $module->name);
}
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Enumerations;
use App\Models\Module;
class Modules extends BaseEnumeration
{
/**
* Init list of all installed modules
*
* @throws Exceptions\EnumerationExistsException
*/
protected static function init()
{
$modules = Module::all(['handler', 'name']);
foreach ($modules as $module) {
self::push($module->handler, $module->name);
}
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Enumerations;
use App\Models\Module;
class ModulesHandlerToId extends BaseEnumeration
{
/**
* Init list of all installed modules
*
* @throws Exceptions\EnumerationExistsException
*/
protected static function init()
{
$modules = Module::all(['handler', 'id']);
foreach ($modules as $module) {
self::push($module->handler, $module->id);
}
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
/**
* Created by PhpStorm.
* User: michal
* Date: 18.2.16
* Time: 10:33
*/
namespace App\Enumerations;
use App\Models\TemplatePath;
class TemplatePaths extends BaseEnumeration
{
protected static function init()
{
$paths = TemplatePath::all(['id', 'path']);
foreach ($paths as $path) {
self::push($path->id, $path->path);
}
}
}
@@ -0,0 +1,23 @@
<?php
/**
* Created by PhpStorm.
* User: michal
* Date: 18.2.16
* Time: 10:33
*/
namespace App\Enumerations;
use App\Models\TemplatePath;
class TemplatePathsHumanReadable extends BaseEnumeration
{
protected static function init()
{
$paths = TemplatePath::all(['id', 'name']);
foreach ($paths as $path) {
self::push($path->id, $path->name);
}
}
}
@@ -0,0 +1,25 @@
<?php
/**
* Created by PhpStorm.
* User: michal
* Date: 18.2.16
* Time: 10:33
*/
namespace App\Enumerations;
use App\Models\TemplatePath;
class TemplatePathsHumanReadableRootOnly extends BaseEnumeration
{
protected static function init()
{
$paths = TemplatePath::where('parent_id', null)
->select(['id', 'name'])
->get();
foreach ($paths as $path) {
self::push($path->id, $path->name);
}
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
/**
* Created by PhpStorm.
* User: michal
* Date: 18.2.16
* Time: 15:50
*/
namespace App\Enumerations;
use App\Models\Template;
class Templates extends BaseEnumeration
{
protected static function init()
{
$templates = Template::all(['id', 'template_name']);
foreach ($templates as $template) {
self::push($template->id, $template->template_name);
}
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Enumerations;
use App\Models\WidgetType;
class WidgetTypes extends BaseEnumeration
{
/**
* Init list of all installed modules
*
* @throws Exceptions\EnumerationExistsException
*/
protected static function init()
{
$widgets = WidgetType::all(['id', 'name']);
foreach ($widgets as $widget) {
self::push($widget->id, $widget->name);
}
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Enumerations;
use App\Models\WidgetType;
class WidgetTypesWithHandlers extends BaseEnumeration
{
/**
* Init list of all installed modules
*
* @throws Exceptions\EnumerationExistsException
*/
protected static function init()
{
$modules = WidgetType::all(['handler', 'name']);
foreach ($modules as $module) {
self::push($module->handler, $module->name);
}
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Events;
use App\Models\Widget;
use App\Models\WidgetArea;
use Illuminate\Queue\SerializesModels;
class AssignWidget extends Event
{
use SerializesModels;
/**
* @var Widget
*/
public $widget;
/**
* @var WidgetArea
*/
public $widgetArea;
/**
* Create a new event instance.
*
* @param Widget $widget
* @param WidgetArea $widgetArea
*/
public function __construct(Widget $widget, WidgetArea $widgetArea)
{
$this->widget = $widget;
$this->widgetArea = $widgetArea;
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Events;
use Illuminate\Queue\SerializesModels;
class AttemptToEditInvalidContent extends Event
{
use SerializesModels;
/**
* @var int
*/
public $contentId;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($contentId)
{
$this->contentId = $contentId;
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ChangeSettings extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Events;
use App\Events\Event;
use App\Models\Content;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class CreateNewContent extends Event
{
use SerializesModels;
/**
* @var Content
*/
public $page;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Content $page)
{
$this->page = $page;
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Events;
use App\Events\Event;
use App\Models\CustomField;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class CreateNewCustomField extends Event
{
use SerializesModels;
/**
* @var CustomField
*/
public $customField;
/**
* Create a new event instance.
*
* @param CustomField $customField
*/
public function __construct(CustomField $customField)
{
$this->customField = $customField;
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Events;
use App\Events\Event;
use App\Models\User;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class CreateNewUser extends Event
{
use SerializesModels;
/**
* @var User
*/
public $user;
/**
* Create a new event instance.
*
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Events;
use App\Models\Widget;
use Illuminate\Queue\SerializesModels;
class CreateNewWidget extends Event
{
use SerializesModels;
/**
* @var Widget
*/
public $widget;
/**
* Create a new event instance.
*
* @param Widget $widget
*/
public function __construct(Widget $widget)
{
//
$this->widget = $widget;
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\Events;
use App\Models\WidgetArea;
use Illuminate\Queue\SerializesModels;
class CreateNewWidgetArea extends Event
{
use SerializesModels;
/**
* @var WidgetArea
*/
public $widgetArea;
/**
* Create a new event instance.
*
* @param WidgetArea $widgetArea
*/
public function __construct(WidgetArea $widgetArea)
{
$this->widgetArea = $widgetArea;
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php
namespace App\Events;
use App\Models\Content;
use Illuminate\Queue\SerializesModels;
class DeleteContent extends Event
{
use SerializesModels;
/**
* @var Content
*/
public $page;
public $revision;
/**
* Create a new event instance.
*
* @param Content $page
* @param $revision
*/
public function __construct(Content $page, $revision)
{
$this->page = $page;
$this->revision = $revision;
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Events;
use App\Events\Event;
use App\Models\CustomField;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class DeleteCustomField extends Event
{
use SerializesModels;
/**
* @var CustomField
*/
public $customField;
/**
* Create a new event instance.
*
* @param CustomField $customField
*/
public function __construct(CustomField $customField)
{
$this->customField = $customField;
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Events;
use App\Models\WidgetArea;
use Illuminate\Queue\SerializesModels;
class DeleteWidgetArea extends Event
{
use SerializesModels;
/**
* @var WidgetArea
*/
public $widgetArea;
/**
* Create a new event instance.
*
* @param WidgetArea $widgetArea
*/
public function __construct(WidgetArea $widgetArea)
{
//
$this->widgetArea = $widgetArea;
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace App\Events;
use App\Models\Content;
use Illuminate\Queue\SerializesModels;
class EditContent extends Event
{
use SerializesModels;
/**
* @var Content
*/
public $page;
public $revision;
/**
* Create a new event instance.
*
* @param Content $page
* @param $revision
*/
public function __construct(Content $page, $revision)
{
$this->page = $page;
$this->revision = $revision;
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Events;
use App\Events\Event;
use App\Models\CustomField;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class EditCustomField extends Event
{
use SerializesModels;
/**
* @var CustomField
*/
public $customField;
/**
* Create a new event instance.
*
* @param CustomField $customField
*/
public function __construct(CustomField $customField)
{
$this->customField = $customField;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace App\Events;
use App\Events\Event;
use App\Models\File;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class EditFile extends Event
{
use SerializesModels;
/**
* @var File
*/
public $file;
/**
* Create a new event instance.
*
* @param File $file
*/
public function __construct(File $file)
{
//
$this->file = $file;
}
/**
* Get the channels the event should be broadcast on.
*
* @return array
*/
public function broadcastOn()
{
return [];
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Queue\SerializesModels;
class EditUser extends Event
{
use SerializesModels;
/**
* @var User
*/
public $user;
/**
* Create a new event instance.
*
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\Events;
use App\Models\Widget;
use Illuminate\Queue\SerializesModels;
class EditWidget extends Event
{
use SerializesModels;
/**
* @var Widget
*/
public $widget;
/**
* Create a new event instance.
*
* @param Widget $widget
*/
public function __construct(Widget $widget)
{
$this->widget = $widget;
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace App\Events;
use App\Events\Event;
use App\Models\WidgetArea;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class EditWidgetArea extends Event
{
use SerializesModels;
/**
* @var WidgetArea
*/
public $widgetArea;
/**
* Create a new event instance.
*
* @param WidgetArea $widgetArea
*/
public function __construct(WidgetArea $widgetArea)
{
$this->widgetArea = $widgetArea;
}
/**
* Get the channels the event should be broadcast on.
*
* @return array
*/
public function broadcastOn()
{
return [];
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace App\Events;
use App\Models\Content;
use Illuminate\Queue\SerializesModels;
class MakeDraftFromContent extends Event
{
use SerializesModels;
/**
* @var Content
*/
public $page;
/**
* @var string
*/
public $revision;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Content $page, $revision)
{
$this->page = $page;
$this->revision = $revision;
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Events;
use App\Models\Content;
use Illuminate\Queue\SerializesModels;
class PublishContent extends Event
{
use SerializesModels;
/**
* @var Content
*/
public $page;
public $revision;
public function __construct(Content $page, $revision)
{
$this->page = $page;
$this->revision = $revision;
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Events;
use App\Models\Widget;
use App\Models\WidgetArea;
use Illuminate\Queue\SerializesModels;
class RemoveWidgetFromArea extends Event
{
use SerializesModels;
/**
* @var Widget
*/
public $widget;
/**
* @var WidgetArea
*/
public $widgetArea;
/**
* Create a new event instance.
*
* @param Widget $widget
* @param WidgetArea $widgetArea
*/
public function __construct(Widget $widget, WidgetArea $widgetArea)
{
$this->widget = $widget;
$this->widgetArea = $widgetArea;
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace App\Events;
use App\Events\Event;
use App\Models\Content;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class SetHomepage extends Event
{
use SerializesModels;
/**
* @var Content
*/
public $page;
public $revision;
/**
* Create a new event instance.
*
* @param Content $page
* @param $revision
*/
public function __construct(Content $page, $revision)
{
$this->page = $page;
$this->revision = $revision;
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Events;
use Illuminate\Queue\SerializesModels;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class UploadFile extends Event
{
use SerializesModels;
/**
* @var UploadedFile
*/
private $uploadedFile;
/**
* @var
*/
private $id;
/**
* Create a new event instance.
*
* @param File $uploadedFile
* @param $id
*/
public function __construct(File $uploadedFile, $id)
{
$this->uploadedFile = $uploadedFile;
$this->id = $id;
}
/**
* Get the channels the event should be broadcast on.
*
* @return array
*/
public function broadcastOn()
{
return [];
}
}
+6
View File
@@ -3,6 +3,7 @@
namespace App\Exceptions; namespace App\Exceptions;
use Exception; use Exception;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
@@ -45,6 +46,11 @@ class Handler extends ExceptionHandler
*/ */
public function render($request, Exception $e) public function render($request, Exception $e)
{ {
if ($e instanceof TokenMismatchException){
//redirect to form an example of how I handle mine
return redirect($request->fullUrl())->with('error', trans('validation.csrf'));
}
return parent::render($request, $e); return parent::render($request, $e);
} }
} }
+117
View File
@@ -0,0 +1,117 @@
<?php
namespace App\Handlers\Contracts;
use App\Http\Requests\Request;
use App\Models\Content;
use App\Models\User;
interface AppHandler
{
/**
* Render given module into visitor area.
*
* @param Content $content DB model from table contents
* @param array $parameters parameters used for modifications/custom settings of given model
*
* @return mixed
*/
public function render(Content $content, $parameters);
public static function getHistoryHandler();
/**
* Load some extra data for content management form?
*
* @param Content $content
*
* @return mixed
*/
public static function loadExtraData(Content $content);
/**
* Save module-specific values into database
*
* @param Content $content
* @param Request $request
*
* @return mixed
* @internal param Widget $widget
*/
public static function createNew(Content &$content, Request $request);
/**
* Method used for editing existing content page.
*
* Reason why it is separated from createNew() method is simple - we need to save history of changes.
*
* @param Content $content
* @param Request $request
*
* @param $revisionID string ID of revision used
*
* @return int number of edited fields
*/
public static function edit(Content &$content, Request $request, $revisionID);
/**
* Method called right after content page is marked as deleted
*
* This method is supposed to clean after "deleted" page.
*
* @param Content $content
*
* @return mixed
*/
public static function delete(Content $content);
/**
* Does given module manage content? Or is it just module with widgets/something internal/something absolutely else?
*
* @return bool
*/
public static function managesContent();
public static function getModuleId();
/**
* Getter for section names in creating/editing content resource
*
* @return mixed
*/
public static function getExtendedFormSections();
/**
* Getter for views used in extended part of form for creating new content
*
* This method should return pairs <section, view-name>. View is returned only as name in plain text
*
* @return array of views/templates/html codes divided into section
*/
public static function getExtendedFormInputsCreate();
/**
* Getter for extended part of form for editing existing content
*
* Basically, this method may be
*
* @return array of views/templates/html codes divided into section
*/
public static function getExtendedFormInputsEdit();
/**
* Register admin menu (or multiple ones)
*
* This cannot be in ServiceProvider because Session is started at middleware. And ServiceProvider is called before
* starting any middleware..
*
* @param User $user model of logged user
*/
public static function registerAdminMenu(User $user);
/**
* Install module
*
* @return mixed
*/
public static function install();
}
@@ -0,0 +1,9 @@
<?php
namespace App\Handlers\Contracts;
interface HistoryHandler
{
public static function parseColumnName($name);
public static function parseChangedValue($changeset);
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace App\Handlers\Contracts;
interface SearchHandler {
public function getId();
public function getName();
/**
* Search for given patttern/term
*
* @param string $term searched word
*
* @return array list of found objects
*/
public function search($term);
}
@@ -0,0 +1,14 @@
<?php
namespace App\Handlers\Contracts;
interface SearchPresenterHandler
{
/**
* Method for rendering list of found results
*
* @param $foundItems
*
* @return mixed
*/
public function render($foundItems);
}
+149
View File
@@ -0,0 +1,149 @@
<?php
namespace App\Handlers;
use App\Enumerations\ModuleNamesWithIds;
use App\Enumerations\TemplatePathsHumanReadableRootOnly;
use App\Enumerations\WidgetTypes;
use App\Handlers\Contracts\AppHandler;
use App\Models\Content;
use App\Models\User;
/**
* Class Handler
*
* Handler is a class which handles module-specific behaviour which cannot be done by module itself, resp. cannot be
* done by some abstract magic.
*
* @package App\Handlers
*/
abstract class Handler implements AppHandler
{
public static function getHistoryHandler()
{
return History::class;
}
public static function getExtendedFormSections()
{
return [
'basicInfo' => trans('admin/contents.basicInfo'),
'meta' => trans('admin/contents.metaOptions'),
'publication' => trans('admin/contents.publicationOptions'),
'appearance' => trans('admin/contents.appearance')
];
}
public static function getExtendedFormInputsCreate()
{
return [
'basicInfo' => 'admin.content.formParts.basicInformation',
'meta' => 'admin.content.formParts.metaInformation',
'publication' => 'admin.content.formParts.publicationSetup',
'appearance' => 'admin.content.formParts.appearance',
];
}
public static function delete(Content $content)
{
// temporarily nothing to do
}
public static function getExtendedFormInputsEdit()
{
return self::getExtendedFormInputsCreate();
}
/**
* Register admin menu (or multiple ones)
*
* This cannot be in ServiceProvider because Session is started at middleware. And ServiceProvider is called before
* starting any middleware..
*
* @param User $user model of logged user
*/
public static function registerAdminMenu(User $user)
{
$menu = \Menu::instance('mainMenu');
if (!is_null($menu)) {
// menus were already defined
return;
}
// create instance of main menu
\Menu::create('mainMenu', function ($menu) {
// $menu->route('admin.dashboard', trans('admin/mainMenu.dashboard'), [], 10, ['icon' => 'fa fa-dashboard']);
$menu->dropdown(trans('admin/mainMenu.userManagement'), function ($sub) {
$sub->route('users.new', trans('admin/mainMenu.newUser'), [], 10, ['icon' => 'fa fa-user-plus']);
$sub->route('users.detail', trans('admin/mainMenu.userDetail'), [], 20, ['icon' => 'fa fa-user']);
$sub->route('users.overview', trans('admin/mainMenu.usersOverview'), [], 30, ['icon' => 'fa fa-users']);
}, 20, ['icon' => 'fa fa-users']);
$menu->dropdown(trans('admin/mainMenu.contentPages'), function ($sub) {
$modules = \App\Models\Module::all();
if (!empty($modules)) {
$sub->dropdown(trans('admin/mainMenu.newContentPage'), function ($sub) use ($modules) {
$i = 1;
foreach ($modules as $module) {
// display only list of all modules, which manages content
if (!call_user_func([$module->handler, 'managesContent'])) {
continue;
}
$sub->route('content.new', trans($module->name), ['moduleId' => $module->id], $i++);
}
}, 10, ['icon' => 'fa fa-plus']);
}
$sub->route('content.overview', trans('admin/mainMenu.contentPageOverview'), [], 20, ['icon' => 'fa fa-list']);
}, 15, ['icon' => 'fa fa-database']);
$menu->route('upload.overview', trans('admin/mainMenu.fileManager'), [], 30, ['icon' => 'fa fa-folder']);
$menu->dropdown(trans('admin/mainMenu.widgets'), function ($sub) {
// create list of all widget types
$widgets = WidgetTypes::getWithTranslations();
if (!empty($widgets)) {
$sub->dropdown(trans('admin/mainMenu.newWidget'), function ($sub) use ($widgets) {
$i = 1;
foreach ($widgets as $type => $name) {
$sub->route('widgets.new', $name, ['type' => $type], $i++);
}
}, 10, ['icon' => 'fa fa-plus']);
}
$sub->route('widgets.overview', trans('admin/mainMenu.widgetsOverview'), [], 20, ['icon' => 'fa fa-list']);
// menu for widget areas
$sub->dropdown(trans('admin/mainMenu.widgetAreas'), function ($sub) {
$sub->route('widgetareas.new', trans('admin/mainMenu.newWidgetArea'), [], 1, ['icon' => 'fa fa-plus']);
$sub->route('widgetareas.overview', trans('admin/mainMenu.widgetAreaOverview'), [], 2, ['icon' => 'fa fa-list']);
}, 50, ['icon' => 'fa fa-object-group']);
}, 28, ['icon' => 'fa fa-gears']);
$templatePaths = TemplatePathsHumanReadableRootOnly::getWithTranslations();
if (!empty($templatePaths)) {
$menu->dropdown(trans('admin/mainMenu.templates'), function ($sub) use ($templatePaths) {
$i = 1;
foreach ($templatePaths as $id => $name) {
$sub->route('templates.overview', $name, ['id' => $id], $i++);
}
}, 29, ['icon' => 'fa fa-folder-open']);
}
// $menu->dropdown(trans('admin/mainMenu.customFields'), function ($sub) {
// $sub->route('customfields.new', trans('admin/mainMenu.customFieldsNew'), [], 10, ['icon' => 'fa fa-code']);
// $sub->route('customfields.overview', trans('admin/mainMenu.customFieldsOverview'), [], 50, ['icon' => 'fa fa-code-fork']);
// }, 30, ['icon' => 'fa fa-code']);
$menu->route('log.overview', trans('admin/mainMenu.actionLog'), [], 40, ['icon' => 'fa fa-history']);
$menu->route('settings.overview', trans('admin/mainMenu.settings'), [], 50, ['icon' => 'fa fa-gear']);
});
// order
// create menu with user profile
\Menu::create('profileMenu', function ($menu) {
$menu->route('users.detail', trans('admin/userManagement.profile'));
$menu->route('logout', trans('admin/common.logout'));
});
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace App\Handlers;
use App\Enumerations\ContentStatuses;
use App\Handlers\Contracts\HistoryHandler;
use App\Helpers\Differ;
class History implements HistoryHandler
{
public static function parseColumnName($column)
{
return trans('admin/history.column' . ucfirst($column));
}
public static function parseChangedValue($changeset)
{
switch ($changeset->column) {
case 'pageContent':
$route = route('history.diff', [
'revision' => $changeset->edit_batch,
'id' => $changeset->id
]);
return "(<a href='" . $route . "'>" . trans('admin/history.diff') . "</a>)";
break;
case 'metaDescription':
return Differ::htmlDiff($changeset->old_value, $changeset->new_value);
break;
case 'status':
$statuses = ContentStatuses::getWithTranslations();
return trans('admin/history.changedFromTo', [
'from' => $statuses[$changeset->old_value],
'to' => $statuses[$changeset->new_value]
]);
break;
case 'is_homepage':
return trans('admin/history.setupAsHomepage');
break;
default:
return trans('admin/history.changedFromTo', [
'from' => is_null($changeset->old_value) ? trans('admin/history.emptyValue') : $changeset->old_value,
'to' => is_null($changeset->new_value) ? trans('admin/history.emptyValue') : $changeset->new_value,
]);
break;
}
}
}
@@ -0,0 +1,56 @@
<?php
namespace App\Handlers\Registrators\Items;
class SettingExtension
{
/**
* @var string human readable ID of settings section (used e.g. as ID parameter in html)
*/
protected $id;
/**
* @var string translations string used for describing briefly settings section
*/
protected $name;
/**
* @var string view used for rendering given settings part
*/
protected $view;
/**
* SettingExtension constructor.
*
* @param string $id
* @param string $name
* @param string $view
*/
public function __construct($id, $name, $view)
{
$this->id = $id;
$this->name = $name;
$this->view = $view;
}
/**
* @return string
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getView()
{
return $this->view;
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Handlers\Registrators;
use App\Widgets\Contracts\MenuExtensionHandler;
class MenuExtensionRegistrator {
protected $menuExtensions;
/**
* @param MenuExtensionHandler $handler
*/
public function register(MenuExtensionHandler $handler) {
$this->menuExtensions[] = $handler;
}
public function get(){
return $this->menuExtensions;
}
}
@@ -0,0 +1,72 @@
<?php
namespace App\Handlers\Registrators;
use App\Enumerations\Exceptions\EnumerationExistsException;
use App\Handlers\Contracts\SearchHandler;
use App\Handlers\Contracts\SearchPresenterHandler;
use App\Handlers\Registrators\Items\SearchEngine;
use Symfony\Component\Process\Exception\InvalidArgumentException;
class SearchEngineRegistrator
{
const ADMIN = 'admin';
const VISITOR = 'visitor';
protected $searchEngines;
function __construct($app)
{
$this->searchEngines = [
self::ADMIN => [],
self::VISITOR => []
];
}
/**
* Method for registering new settings extensions/parts
*
* @param SearchHandler $search
* @param SearchPresenterHandler $presenter
*
* @param $type
*
* @throws EnumerationExistsException
*/
public function register(SearchHandler $search, SearchPresenterHandler $presenter, $type)
{
$this->checkIfRegistered($type, $search->getId());
// register new extension
$this->searchEngines[$type][$search->getId()] = [$search, $presenter];
}
/**
* Getter for all registered extensions
*
* @param $type
*
* @return array
*/
public function get($type)
{
if (!isset($this->searchEngines[$type])) {
throw new InvalidArgumentException('Invalid type ' . $type);
}
return $this->searchEngines[$type];
}
/**
* Checks if this section is not already defined
*
* @param $type
* @param $id
*
* @throws EnumerationExistsException
*/
private function checkIfRegistered($type, $id)
{
if (isset($this->searchEngines[$type][$id])) {
throw new EnumerationExistsException('Already existing search engine ' . $id . ' in ' . $type);
}
}
}
@@ -0,0 +1,71 @@
<?php
namespace App\Handlers\Registrators;
use App\Enumerations\Exceptions\EnumerationExistsException;
use App\Handlers\Registrators\Items\SettingExtension;
class SettingsExtensionRegistrator
{
protected $settingsExtensions;
function __construct($app)
{
$this->settingsExtensions = [];
}
/**
* Method for registering new settings extensions/parts
*
* @param $sectionId
* @param $sectionName
* @param $sectionView
*
* @throws EnumerationExistsException
*/
public function register($sectionId, $sectionName, $sectionView)
{
$this->checkIfRegistered($sectionId);
// register new extension
$this->settingsExtensions[$sectionId] = new SettingExtension($sectionId, $sectionName, $sectionView);
}
/**
* Registers new setting part - only as SettingExtension directly
*
* @param SettingExtension $extension
*/
public function registerObject(SettingExtension $extension)
{
$this->checkIfRegistered($extension->getId());
$this->settingsExtensions[$extension->getId()] = $extension;
}
/**
* Getter for all registered extensions
*
* @return array
*/
public function get()
{
// sort registered extensions by key
ksort($this->settingsExtensions);
return $this->settingsExtensions;
}
/**
* Checks if this section is not already defined
*
* @param $sectionId
*
* @throws EnumerationExistsException
*/
private function checkIfRegistered($sectionId)
{
if (isset($this->settingsExtensions[$sectionId])) {
throw new EnumerationExistsException('Already existing key ' . $sectionId);
}
}
}
@@ -0,0 +1,279 @@
<?php
namespace App\Handlers\Registrators;
use App\Enumerations\TemplatePaths;
use App\Enumerations\Templates;
use App\Models\Template;
use App\Models\TemplatePath;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Symfony\Component\Process\Exception\InvalidArgumentException;
class TemplateRegistrator
{
/**
* @var string absolute path to base directory of registered template paths
*/
protected $baseDirectory;
/**
* @var string namespace of registered templates
*/
protected $namespace;
/**
* @var string absolute path to currently registered directory
* This variable is set in register() method as $baseDirectory/$path
*/
protected $registeredPath;
/**
* @var int ID of module
*/
protected $moduleId;
/**
* Set base path
*
* @param mixed $baseDirectory
*/
public function setBaseDirectory($baseDirectory)
{
$baseDirectory = str_replace('/', DIRECTORY_SEPARATOR, $baseDirectory);
$baseDirectory = base_path($baseDirectory);
$baseDirectory = rtrim($baseDirectory, DIRECTORY_SEPARATOR);
if (!is_dir($baseDirectory)) {
throw new InvalidArgumentException('Invalid path ' . $baseDirectory);
}
$this->baseDirectory = $baseDirectory;
}
/**
* Set module ID for registered path
*
* @param int $moduleId
*/
public function setModuleId($moduleId)
{
$this->moduleId = $moduleId;
}
/**
* Set namespace for registered template path
*
* @param string $namespace
*/
public function setNamespace($namespace)
{
$this->namespace = $namespace . '::';
}
/**
* Resets namespace
*/
public function unsetNamespace()
{
$this->namespace = null;
}
/**
* Registers new template path.
* This method registeres given path itself with all subdirectories
*
* @param string $path path relatively to root of the project
* @param string $name human readable identification of given template path
*
* @throws \Exception
*/
public function register($path, $name)
{
// check if base directory was set
if (!$this->baseDirectory || !is_dir($this->baseDirectory)) {
throw new \Exception('Set $baseDirectory before registering template path.');
}
$this->registeredPath = $this->baseDirectory . DIRECTORY_SEPARATOR . $path;
// register path
$this->registerPath($this->registeredPath, $name);
}
/**
* Get relative path to project root
*
* @param $directory
*
* @return string
*/
protected function relativePath($directory)
{
return trim(str_replace(base_path(), '', $directory), '/');
}
/**
* Crawl subdirectories and register them
*
* @param string $directory path relative to $baseDirectory variable
* @param string $name name of parent directory
*/
protected function scanForSubdirectories($directory, $name)
{
$directories = File::directories($directory);
foreach ($directories as $dir) {
$base = basename($dir);
$name = preg_replace('/\.(.+)/', '.' . $base, $name);
$this->registerPath($dir, $name, $directory);
}
}
/**
* Registers template path and templates into system
*
* @param string $path relative path to $baseDirectory variable
* @param string $name human readable name of this path (used in overview)
* @param null|string $parent path to parent directory
*/
protected function registerPath($path, $name, $parent = null)
{
// skip custom directories (contains updated templates only)
$dirName = basename($path);
$ignoredDirectories = [
Template::EDITED_TEMPLATES_DIRECTORY,
Template::ASSETS_DIRECTORY,
Template::MODULES_DIRECTORY
];
if (in_array($dirName, $ignoredDirectories)) {
return;
}
// save template path into database
$templatePathId = $this->saveTemplatePath($path, $name, $parent);
// save all templates into database
$this->registerTemplates($path, $templatePathId);
// try to find some subdirectories and other templates
$this->scanForSubdirectories($path, $name);
}
/**
* Registers all templates
* This method takes all templates in given directory and registers them into database. Templates registered in
* this way may be used for further manipulation.
*
* @param $path
* @param $templatePathId
*
* @throws \App\Enumerations\Exceptions\EnumerationExistsException
*/
protected function registerTemplates($path, $templatePathId)
{
$templates = File::files($path);
foreach ($templates as $template) {
// skip all non-template files - we assume that every file with suffix ".blade.php" is Blade template
if (!Str::endsWith($template, Template::TEMPLATE_SUFFIX)) {
continue;
}
// get all templates and template name (path/to/template.blade.php -> path.to.template)
$templateName = $this->getTemplateName($template);
$registeredTemplates = Templates::getWithTranslations();
if (!in_array($templateName, $registeredTemplates)) {
$params = [
'template_name' => $templateName,
'name' => $templateName,
'path' => $templatePathId,
'module_id' => $this->moduleId,
'description' => '',
'editable' => 1
];
// save template into database
$newTemplate = Template::create($params);
// push template into enumeration - so it will not be registered again
Templates::push($newTemplate->id, $templateName);
}
}
}
/**
* Save template into database and return its ID
*
* @param $path
* @param $name
* @param null $parent
*
* @return mixed|null
* @throws \App\Enumerations\Exceptions\EnumerationExistsException
*/
protected function saveTemplatePath($path, $name, $parent = null)
{
$registeredPaths = TemplatePaths::getWithTranslations();
$relativePath = $this->relativePath($path);
if (!in_array($relativePath, $registeredPaths)) {
$parentId = $this->getId($this->relativePath($parent));
$params = [
'path' => $relativePath,
'name' => $name,
'namespace' => $this->namespace,
'parent_id' => $parentId
];
// save into database
$path = TemplatePath::create($params);
// add to enumeration
TemplatePaths::push($path->id, $relativePath);
return $path->id;
}
return $this->getId($relativePath);
}
/**
* Get ID of registered template
*
* @param $path
*
* @return null|int null when parent not found, ID of parent otherwise
*/
private function getId($path)
{
// get registered paths
$paths = TemplatePaths::getWithTranslations();
$paths = array_flip($paths);
if (is_null($path) || !isset($paths[$path])) {
return null;
}
return $paths[$path];
}
/**
* Get template name
* Converts path to template to corresponding name
*
* @param $template
*
* @return string
*/
private function getTemplateName($template)
{
$templateName = str_replace($this->registeredPath . DIRECTORY_SEPARATOR, '', $template);
$templateName = str_replace(DIRECTORY_SEPARATOR, '.', $templateName);
$templateName = str_replace(Template::TEMPLATE_SUFFIX, '', $templateName);
return $this->namespace . $templateName;
}
}
@@ -0,0 +1,46 @@
<?php
namespace App\Handlers\Registrators;
use App\Enumerations\WidgetTypesWithHandlers;
use App\Models\WidgetType;
use App\Widgets\Contracts\PublicWidget;
use Symfony\Component\Process\Exception\InvalidArgumentException;
class WidgetRegistrator
{
protected $widgets;
function __construct()
{
$this->widgets = WidgetTypesWithHandlers::getSimple();
}
/**
* Method used for registering new widgets
*
* @param $classname
*/
public function register($classname)
{
$class = new $classname;
if (!$class instanceof PublicWidget) {
throw new InvalidArgumentException($class . ' must implement PublicWidget interface.');
}
// register widget as new widget type
if (!in_array($classname, $this->widgets)) {
$widgetName = call_user_func($classname . '::getName');
$widgetDescription = call_user_func($classname . '::getDescription');
// create row in widget types
WidgetType::create([
'handler' => $classname,
'name' => $widgetName,
'description' => $widgetDescription
]);
// install widget (if neccessary)
call_user_func($classname . '::install');
}
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace App\Handlers\Search;
use App\Models\Content as ContentModel;
class Content extends Search
{
/**
* Search for given patttern/term
*
* @param string $term searched word
*
* @return array list of found objects
*/
public function search($term)
{
$token = $this->tokenize($term);
return ContentModel::where('content', 'LIKE', $token)
->orWhere('meta_description', 'LIKE', $token)
->orWhere('meta_keywords', 'LIKE', $token)
->orWhere('title', 'LIKE', $token)
->orWhere('url', 'LIKE', $token)
->get();
}
public function getId()
{
return 'content';
}
public function getName()
{
return trans('search.content');
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace App\Handlers\Search;
use App\Models\File;
class Files extends Search
{
public function getId()
{
return "files";
}
public function getName()
{
return trans('search.files');
}
/**
* Search for given patttern/term
*
* @param string $term searched word
*
* @return array list of found objects
*/
public function search($term)
{
$token = $this->tokenize($term);
return File::where('original_filename', 'LIKE', $token)
->orWhere('keywords', 'LIKE', $token)
->orWhere('description', 'LIKE', $token)
->orWhere('mime_type', 'LIKE', $token)
->get();
}
}
@@ -0,0 +1,12 @@
<?php
namespace App\Handlers\Search\Presenters;
use App\Handlers\Contracts\SearchPresenterHandler;
class AdminContent implements SearchPresenterHandler
{
public function render($foundItems)
{
return view('admin.content.overviewTiles', ['pages' => $foundItems, 'tileClass' => 'large-4']);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Handlers\Search\Presenters;
use App\Handlers\Contracts\SearchPresenterHandler;
class AdminFiles implements SearchPresenterHandler
{
/**
* Method for rendering list of found results
*
* @param $foundItems
*
* @return mixed
*/
public function render($foundItems)
{
return view('admin.fileManager.filesTiles', ['files' => $foundItems]);
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Handlers\Search;
use App\Handlers\Contracts\SearchHandler;
use Symfony\Component\Process\Exception\InvalidArgumentException;
abstract class Search implements SearchHandler
{
/**
* Tokenize string for usage in LIKE clausules
*
* @param $term
*
* @return string
*/
protected function tokenize($term)
{
$term = trim($term);
if (empty($term)) {
throw new InvalidArgumentException(trans('search.emptyString'));
}
return '%' . str_replace(' ', '%', $term) . '%';
}
}
+64
View File
@@ -0,0 +1,64 @@
<?php
namespace App\Helpers;
/*
Paul's Simple Differ Algorithm v 0.1
(C) Paul Butler 2007 <http://www.paulbutler.org/>
May be used and distributed under the zlib/libpng license.
This code is intended for learning purposes; it was written with short
code taking priority over performance. It could be used in a practical
application, but there are a few ways it could be optimized.
Given two arrays, the function diff will return an array of the changes.
I won't describe the format of the array, but it will be obvious
if you use print_r() on the result of a diff on some test data.
htmlDiff is a wrapper for the diff command, it takes two strings and
returns the differences in HTML. The tags used are <ins> and <del>,
which can easily be styled with CSS.
@url https://github.com/paulgb/simplediff/blob/master/php/simplediff.php
Sorry for this kind of magic, I have no idea how this works.. :(
*/
class Differ
{
public static function diff($old, $new)
{
$matrix = [];
$maxlen = 0;
foreach ($old as $oindex => $ovalue) {
$nkeys = array_keys($new, $ovalue);
foreach ($nkeys as $nindex) {
$matrix[$oindex][$nindex] = isset($matrix[$oindex - 1][$nindex - 1]) ? $matrix[$oindex - 1][$nindex - 1] + 1 : 1;
if ($matrix[$oindex][$nindex] > $maxlen) {
$maxlen = $matrix[$oindex][$nindex];
$omax = $oindex + 1 - $maxlen;
$nmax = $nindex + 1 - $maxlen;
}
}
}
if ($maxlen == 0) {
return [['d' => $old, 'i' => $new]];
}
return array_merge(self::diff(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), array_slice($new, $nmax, $maxlen), self::diff(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)));
}
public static function htmlDiff($old, $new)
{
$ret = '';
$diff = self::diff(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new));
foreach ($diff as $k) {
if (is_array($k)) {
$ret .= (!empty($k['d']) ? "<del>" . implode(' ', $k['d']) . "</del> " : '') . (!empty($k['i']) ? "<ins>" . implode(' ', $k['i']) . "</ins> " : '');
} else {
$ret .= $k . ' ';
}
}
return $ret;
}
}
+140
View File
@@ -0,0 +1,140 @@
<?php
namespace App\Helpers;
use App\Models\File;
class FileManager
{
/**
* @param File $file
*
* @return \Illuminate\Contracts\Routing\UrlGenerator|string
*/
public static function getPreview(File $file)
{
list($type, $subtype) = explode('/', $file->mime_type);
switch ($type) {
case 'image':
// try to check if file have thumbnail
if (file_exists(config('app.thumbnail_url') . '/' . $file->filename)) {
$url = config('app.thumbnail_url') . '/' . $file->filename;
} else {
$url = config('app.upload_url') . '/' . $file->filename;
}
return '<img src="' . $url . '" alt="' . $file->description . '" />';
break;
case 'text':
return '<i class="fa fa-file-text-o"></i>';
break;
case 'application':
switch ($subtype) {
case 'pdf':
return '<i class="fa fa-file-pdf-o"></i>';
break;
default:
return '<i class="fa fa-newspaper-o"></i>';
break;
}
break;
default:
return '<i class="fa fa-question"></i>';
break;
}
}
/**
*
*
* @param File $file
*
* @return string
*/
public static function getFormattedSize(File $file)
{
$bytes = $file->file_size;
$label = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
for ($i = 0; $bytes >= 1024 && $i < (count($label) - 1); $bytes /= 1024, $i++) {
;
}
return (round($bytes, 2) . " " . $label[$i]);
}
/**
* Get preview for file detail
*
* @param File $file
*
* @return \Illuminate\Contracts\Routing\UrlGenerator|string
*/
public static function getLargePreview(File $file)
{
list($type, $subtype) = explode('/', $file->mime_type);
$url = config('app.upload_url') . '/' . $file->filename;
$path = config('app.upload_path') . DIRECTORY_SEPARATOR . $file->filename;
switch ($type) {
case 'image':
return '<img src="' . $url . '" alt="' . $file->description . '" />';
break;
case 'text':
$string = '<pre><code>';
$string .= htmlspecialchars(file_get_contents($path));
$string .= '</pre></code>';
return $string;
break;
case 'application':
switch ($subtype) {
case 'pdf':
return '<i class="fa fa-file-pdf-o"></i>';
break;
default:
return '<i class="fa fa-newspaper-o"></i>';
break;
}
break;
default:
return self::getPreview($file);
break;
}
}
/**
* @param File $file
*
* @return array
*/
public static function getAdditionalInfo(File $file)
{
list($type, $subtype) = explode('/', $file->mime_type);
$path = config('app.upload_path') . DIRECTORY_SEPARATOR . $file->filename;
switch ($type) {
case 'text':
return [
trans('admin/fileManager.encoding') => mb_detect_encoding(file_get_contents($path))
];
break;
case 'image':
list ($width, $height) = getimagesize($path);
return [
trans('admin/fileManager.resolution') => $height . ' x ' . $width,
];
break;
}
return [];
}
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Helpers;
class Gravatar
{
public static function img($email, $size = 50)
{
return "http://www.gravatar.com/avatar/" . md5(strtolower(trim($email))) . "?s=" . $size;
}
}
+77
View File
@@ -0,0 +1,77 @@
<?php
namespace App\Helpers;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Process\Exception\InvalidArgumentException;
class Template
{
/**
* Getter for real template name
*
* @param $template
*
* @return null|string
*/
public static function name($template)
{
$namespace = null;
if (strpos($template, '::')) {
list($namespace, $template) = explode('::', $template);
$namespace .= '::';
}
$theme = config('app.theme');
// list of prefixes
$prefixes = [$theme . '.custom.', $theme . '.', ''];
$view = null;
foreach ($prefixes as $prefix) {
if (view()->exists($namespace . 'visitor.' . $prefix . $template)) {
$view = $namespace . 'visitor.' . $prefix . $template;
break;
}
}
if (is_null($view)) {
throw new InvalidArgumentException('Cannot find template for ' . $namespace . $template);
}
return $view;
}
/**
* Get URL to uploaded file
*
* @param $filename
*
* @return string
*/
public static function upload($filename)
{
// for debug environment check if file exists
if (env('APP_DEBUG') && !file_exists(config('app.upload_path') . '/' . $filename)) {
throw new NotFoundHttpException('File ' . $filename . ' cannot be found in ' . config('app.upload_path') . '.');
}
// return url to uploaded file
return config('app.upload_url') . '/' . $filename;
}
public static function asset($path)
{
if (env('APP_DEBUG')) {
if (empty($path)) {
throw new InvalidArgumentException('No asset name defined!');
}
// check if asset exists and is file
if (!file_exists(public_path('assets/' . config('app.theme') . '/' . $path))) {
throw new NotFoundHttpException('Cannot find any asset in ' . public_path('assets/' . config('app.theme') . '/' . $path) . '. Try to check your paths.');
}
}
return config('app.url') . '/assets/' . config('app.theme') . '/' . $path;
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace App\Helpers;
use App\Models\WidgetArea;
class WidgetAreas
{
/**
* @var array list of inicialized widget areas
*/
protected static $widgetAreas = [];
/**
* Renderer for whole widget area.
*
* @param $uniqueCode
*
* @return mixed
*/
public static function render($uniqueCode)
{
if (isset(self::$widgetAreas[$uniqueCode])) {
echo self::$widgetAreas[$uniqueCode];
return;
}
$widgetArea = new WidgetArea();
$widgets = $widgetArea->getWidgets($uniqueCode)
->get();
$content = '';
foreach ($widgets as $widget) {
$handler = $widget->widget_type_handler;
$presenter = call_user_func([$handler, 'getPresenter']);
$content .= call_user_func([$presenter, 'render'], json_decode($widget->settings));
}
// cache this widget area
self::$widgetAreas[$uniqueCode] = $content;
echo $content;
}
}
+14
View File
@@ -0,0 +1,14 @@
<?php
/**
* Define function for escaping characters.
*
* This funcion prevents of creating build-in function, which escapes also accents...
*
* @param $value
*
* @return string
*/
function e($value)
{
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
@@ -0,0 +1,35 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\ActionLog;
class ActionLogOverview extends Controller
{
/**
* @var ActionLog
*/
private $log;
/**
* ActionLog constructor.
*
* @param ActionLog $log
*/
public function __construct(ActionLog $log)
{
$this->log = $log;
}
public function getOverview()
{
$actions = $this->log->getLogActionsQuery(true)
->paginate(25);
$this->log->translateLogMessages($actions);
return view('admin.actionLog.overview', ['actions' => $actions]);
}
}
@@ -0,0 +1,74 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Events\AssignWidget;
use App\Events\RemoveWidgetFromArea;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\Widget;
use App\Models\WidgetArea;
use App\Models\WidgetInWidgetArea;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Event;
class AssociateWidget extends Controller
{
public function getList($widgetArea)
{
$area = WidgetArea::findOrFail($widgetArea);
$associatedWidgetIds = WidgetInWidgetArea::getWidgetIdsFromArea($area->id);
$widgets = Widget::paginate(25);
return view('admin.widgets.association', [
'widgetArea' => $area,
'widgets' => $widgets,
'associatedWidgetIds' => $associatedWidgetIds
]);
}
public function makeAssociation($widgetId, $widgetAreaId)
{
// check if given values are valid
$widget = Widget::findOrFail($widgetId);
$widgetArea = WidgetArea::findOrFail($widgetAreaId);
try {
WidgetInWidgetArea::create(['widget_id' => $widgetId, 'widget_area_id' => $widgetAreaId]);
} catch (QueryException $e) {
return redirect()
->route('widgets.associate', ['widgetArea' => $widgetAreaId])
->with('error', trans('admin/widgets.associationExists'));
}
Event::fire(new AssignWidget($widget, $widgetArea));
return redirect()
->route('widgets.associate', ['widgetArea' => $widgetAreaId])
->with('success', trans('admin/widgets.successfullyAssociated'));
}
public function deleteAssociation($widgetId, $widgetAreaId)
{
// check if given values are valid
$widget = Widget::findOrFail($widgetId);
$widgetArea = WidgetArea::findOrFail($widgetAreaId);
$widgetInArea = WidgetInWidgetArea::where('widget_id', $widgetId)
->where('widget_area_id', $widgetAreaId);
if ($widgetInArea->count() == 0) {
return redirect()
->route('widgets.associate', ['widgetArea' => $widgetAreaId])
->with('error', trans('admin/widgets.associationDoesNotExists'));
}
$widgetInArea->delete();
Event::fire(new RemoveWidgetFromArea($widget, $widgetArea));
return redirect()
->route('widgets.associate', ['widgetArea' => $widgetAreaId])
->with('success', trans('admin/widgets.successfullyDeassociated'));
}
}
@@ -0,0 +1,50 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Content;
use App\Models\Module;
use Illuminate\Support\Facades\Input;
class ContentOverview extends Controller
{
/**
* @var Content
*/
private $content;
public function __construct(Content $content)
{
parent::__construct();
$this->content = $content;
}
/**
* Overview for all content pages.
*
* @param bool|false $moduleId
* @param null $status
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getOverview($moduleId = false, $status = null)
{
$moduleFilterHandler = false;
$perPage = Input::get('perPage') ? Input::get('perPage') : 20;
// does user want to filter results using module?
if (is_numeric($moduleId)) {
$module = Module::findOrFail($moduleId);
$moduleFilterHandler = $module->handler;
}
// get pages for overview
$pages = $this->content->getOverview($moduleFilterHandler, $status, true, true)
->paginate($perPage);
// get homepage - for checking if homepage is set and available
$homepage = $this->content->getHomepage();
return view('admin.content.overview', ['pages' => $pages, 'homepage' => $homepage]);
}
}
+118
View File
@@ -0,0 +1,118 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\CopyTemplateRequest;
use App\Models\Template;
use Illuminate\Http\Request;
class CopyTemplate extends Controller
{
/**
* Method for copying given template.
*
* This method is supposed to be called by POST method.
*
* @param CopyTemplateRequest $request
*
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
public function createCopy(CopyTemplateRequest $request)
{
// get variables from request
$newName = preg_replace('/[^a-z0-9_]/i', '', $request->newName);
$oldTemplateId = $request->templateId;
// get template path
$template = Template::findOrFail($oldTemplateId);
// @todo add check for uniqueness of template_name
// get template path
$template = Template::findOrFail($oldTemplateId);
$namespace = null;
if (strpos($template->template_name, '::')) {
list($namespace) = explode('::', $template->template_name);
$namespace .= '::';
}
// get template absolute paths
$realTemplatePath = $template->getPathToTemplate();
$customTemplatePath = $template->getPathToTemplate(Template::CUSTOM_EDIT_DIRECTORY);
$path = dirname($customTemplatePath);
// create file copy
$data = file_get_contents($realTemplatePath);
$written = file_put_contents($path . DIRECTORY_SEPARATOR . $newName . Template::TEMPLATE_SUFFIX, $data);
// were data written?
if ($written === false) {
return $this->copyFailed($request, $template);
}
// insert record into database (**custom paths are not crawled)
$newTemplate = Template::create([
'template_name' => $namespace . $newName,
'name' => $newName,
'path' => $template->path,
'module_id' => $template->module_id,
'description' => $template->description,
'editable' => 1
]);
// inform user about successfull copying
return $this->copySuccessfull($request, $newTemplate);
}
/**
* Handle failed template copying
*
* @param CopyTemplateRequest $request
* @param Template $template
*
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*
*/
private function copyFailed(CopyTemplateRequest $request, Template $template)
{
$message = trans('admin/templates.copyFailed', ['name' => $template->name]);
if ($request->ajax()) {
return response()->json([
'status' => 'fail',
'redirectUrl' => route('templates.overview', ['path' => $template->path]),
'message' => $message
]);
} else {
return redirect()
->route('templates.overview', ['path' => $template->path])
->with('error', $message);
}
}
/**
* Handle (redirect/send response) successfully copied template
*
* @param CopyTemplateRequest $request
* @param Template $newTemplate
*
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
private function copySuccessfull(CopyTemplateRequest $request, Template $newTemplate)
{
if ($request->ajax()) {
return response()->json([
'status' => 'success',
'redirectUrl' => route('templates.overview', ['path' => $newTemplate->path]),
'message' => trans('admin/templates.copySuccessfull', ['name' => $newTemplate->name])
]);
} else {
return redirect()
->route(route('templates.overview', ['path' => $newTemplate->path]))
->with('success', trans('admin/templates.copySuccessfull', ['name' => $newTemplate->name]));
}
}
}
@@ -0,0 +1,123 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Enumerations\ActiveContentStatuses;
use App\Events\CreateNewContent as CreateNewContentEvent;
use App\Http\Requests\CreateNewContentRequest;
use App\Models\Content;
use App\Models\File;
use App\Models\Module;
use App\Models\Template;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class CreateNewContent extends Controller
{
/**
* @var File
*/
private $file;
/**
* @var Content
*/
private $content;
public function __construct(File $file, Content $content)
{
parent::__construct();
$this->file = $file;
$this->content = $content;
}
/**
* Display form for new content page
*
* @param $moduleId
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getNew($moduleId)
{
$module = Module::findOrFail($moduleId);
$statuses = ActiveContentStatuses::getWithTranslations();
$templates = Template::where('module_id', $moduleId)
->select(['template_name', 'name', 'description'])
->get();
// create default content object
$this->content->status = Content::STATUS_DRAFT;
// render view
return view('admin.content.new', [
'contentStatuses' => $statuses,
'templates' => $templates,
'moduleId' => $moduleId,
'page' => $this->content,
'rootPages' => $this->content->getOverview()->get(),
'moduleName' => trans($module->name),
'extraData' => call_user_func([$module->handler, 'loadExtraData'], $this->content),
'formSectionNames' => call_user_func([$module->handler, 'getExtendedFormSections']),
'formSections' => call_user_func([$module->handler, 'getExtendedFormInputsCreate']),
]);
}
/**
* Save new content page
*
* @param CreateNewContentRequest $request
* @param $moduleId
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postNew(CreateNewContentRequest $request, $moduleId)
{
$page = new Content();
try {
$module = Module::findOrFail($moduleId);
} catch (NotFoundHttpException $e) {
return redirect()
->route('content.overview')
->withInput()
->with('error', trans('admin/contents.invalidModule'));
}
// setup basic info
$page->user_id = \Auth::user()->id;
$page->title = $request->title;
$page->url = Str::slug($request->url);
$page->published_from = $request->publishedFrom;
$page->published_to = $request->publishedTo;
$page->meta_keywords = $request->metaKeywords;
$page->meta_description = $request->metaDescription;
$page->content = $request->pageContent;
$page->status = $request->status;
$page->template = $request->template;
$page->module_handler = $module->handler;
if ($request->parentPage) {
$page->parent_id = $request->parentPage;
}
// upload file - if provided
if ($request->hasFile('titlePhoto')) {
$file = $this->file->upload($request->file('titlePhoto'), $request);
$page->title_photo = $file['filename'];
}
// save module-specific stuff
call_user_func_array([$module->handler, 'createNew'], [&$page, $request]);
$page->save();
// fire event about creating new content page
Event::fire(new CreateNewContentEvent($page));
return redirect()
->route('content.overview')
->with('success', trans('admin/contents.successfullyCreated'));
}
}
@@ -4,8 +4,10 @@ namespace App\Http\Controllers\Admin;
use App\Enumerations\CustomFieldResources; use App\Enumerations\CustomFieldResources;
use App\Enumerations\CustomFieldTypes; use App\Enumerations\CustomFieldTypes;
use App\Events\CreateNewCustomField as CreateNewCustomFieldEvent;
use App\Http\Requests\NewCustomFieldRequest; use App\Http\Requests\NewCustomFieldRequest;
use App\Models\CustomField; use App\Models\CustomField;
use Illuminate\Support\Facades\Event;
class CreateNewCustomField extends Controller class CreateNewCustomField extends Controller
{ {
@@ -59,6 +61,9 @@ class CreateNewCustomField extends Controller
$customField->save(); $customField->save();
// fire event about creating new custom field
Event::fire(new CreateNewCustomFieldEvent($customField));
return redirect() return redirect()
->route('customfields.new') ->route('customfields.new')
->with('success', trans('admin/customFields.successfullyCreated')); ->with('success', trans('admin/customFields.successfullyCreated'));
@@ -0,0 +1,62 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\Directory;
class CreateNewDirectory extends Controller
{
/**
* Create new directory
*
* @param Requests\CreateNewDirectoryRequest $request
*
* @return $this|\Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
public function postNew(Requests\CreateNewDirectoryRequest $request)
{
// check if created folder does not exist in current directory
$exists = Directory::where('name', $request->name)
->where('parent_id', $request->parentDirectory)
->exists();
if ($exists) {
if ($request->ajax()) {
return response()->json([
'status' => 'failed',
'message' => trans('admin/fileManager.subdirectoryExists')
]);
} else {
return redirect()
->route('upload.overview', ['id' => $request->parentDirectory])
->with('error', trans('admin/fileManager.subdirectoryExists'))
->withInput();
}
}
// create new database entry
$directory = new Directory();
$directory->name = $request->name;
$directory->parent_id = $request->parentDirectory;
$directory->user_id = \Auth::user()->id;
$directory->description = $request->description;
$directory->save();
$message = trans('admin/fileManager.newDirectorySuccess');
if (!$request->ajax()) {
return redirect()
->route('upload.overview', ['id' => $request->parentDirectory])
->with('success', $message);
} else {
$payload = [
'status' => 'success',
'message' => $message,
'parentDirectory' => $request->parentDirectory
];
return response()->json($payload);
}
}
}
+6 -2
View File
@@ -3,11 +3,12 @@
namespace App\Http\Controllers\Admin; namespace App\Http\Controllers\Admin;
use App\Enumerations\UserRoles; use App\Enumerations\UserRoles;
use App\Events\CreateNewUser as CreateNewUserEvent;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests; use App\Http\Requests;
use App\Http\Requests\CreateNewUserRequest; use App\Http\Requests\CreateNewUserRequest;
use App\Models\User; use App\Models\User;
use Illuminate\Http\Request; use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
class CreateNewUser extends Controller class CreateNewUser extends Controller
@@ -23,7 +24,7 @@ class CreateNewUser extends Controller
$roles = UserRoles::getWithTranslations(); $roles = UserRoles::getWithTranslations();
// render view // render view
return $this->view('admin.userManagement.new', ['roles' => $roles]); return view('admin.userManagement.new', ['roles' => $roles]);
} }
/** /**
@@ -51,6 +52,9 @@ class CreateNewUser extends Controller
// store user into database // store user into database
$user->save(); $user->save();
// fire event
Event::fire(new CreateNewUserEvent($user));
// refresh page with information about successfull registration // refresh page with information about successfull registration
return redirect() return redirect()
->route('users.new') ->route('users.new')
@@ -0,0 +1,78 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\NewWidgetRequest;
use App\Models\Widget;
use App\Models\WidgetType;
use App\Widgets\Exceptions\MissingParameterException;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Event;
class CreateNewWidget extends Controller
{
/**
* @var Widget
*/
private $widget;
public function __construct(Widget $widget)
{
$this->widget = $widget;
}
/**
* Form for new widget area
*
* @param $type
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getNew($type)
{
$widgetType = WidgetType::findOrFail($type);
$presenter = call_user_func([$widgetType->handler, 'getPresenter']);
return call_user_func([$presenter, 'renderAddForm'], $widgetType);
}
/**
* Create new instance of given widget type
*
* @param NewWidgetRequest $request
* @param $type
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postNew(NewWidgetRequest $request, $type)
{
$widgetType = WidgetType::findOrFail($type);
// try to save this widget
try {
$this->widget->createNew($widgetType, $request->all());
} catch (MissingParameterException $e) {
// user omitted some value
return $this->invalidWidget($type, $e->getMessage());
} catch (\Exception $e) {
// something went wrong
return $this->invalidWidget($type, trans('admin/widgets.cannotSave', ['exception' => $e->getMessage()]));
}
// redirect with success notification
return redirect()
->route('widgets.new', ['type' => $type])
->with('success', trans('admin/widgets.successfullyCreated'));
}
private function invalidWidget($widgetType, $error)
{
return redirect()
->route('widgets.new', ['type' => $widgetType])
->withInput()
->with('error', $error);
}
}
@@ -0,0 +1,46 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\NewWidgetAreaRequest;
use App\Models\WidgetArea;
use Illuminate\Support\Facades\Event;
class CreateNewWidgetArea extends Controller
{
/**
* Form for new widget area
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getNew()
{
return view('admin.widgets.area.new');
}
/**
* @param NewWidgetAreaRequest $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postNew(NewWidgetAreaRequest $request)
{
$parameters = [
'code' => $request->code,
'name' => $request->name,
'description' => $request->description
];
$area = WidgetArea::create($parameters);
// fire event with new widget area
Event::fire(new \App\Events\CreateNewWidgetArea($area));
// redirect with success notification
return redirect()
->route('widgetareas.overview')
->with('success', trans('admin/widgetAreas.successfullyCreated'));
}
}
+4 -1
View File
@@ -9,6 +9,9 @@ use Illuminate\Support\Facades\Session;
class Dashboard extends Controller class Dashboard extends Controller
{ {
public function getIndex(Request $request) { public function getIndex(Request $request) {
return view('admin.dashboard');
return redirect()->route('content.overview');
// return view('admin.dashboard');
} }
} }
+319
View File
@@ -0,0 +1,319 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Enumerations\ContentStatuses;
use App\Enumerations\ModulesHandlerToId;
use App\Events\AttemptToEditInvalidContent;
use App\Events\DeleteContent;
use App\Events\EditContent as EditContentEvent;
use App\Events\MakeDraftFromContent;
use App\Events\PublishContent;
use App\Events\SetHomepage;
use App\Http\Requests\EditContentRequest;
use App\Http\Requests\Request;
use App\Models\Content;
use App\Models\ContentHistory;
use App\Models\File;
use App\Models\Template;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class EditContent extends Controller
{
/**
* @var ContentHistory
*/
private $history;
/**
* @var File
*/
private $file;
public function __construct(ContentHistory $history, File $file)
{
$this->history = $history;
$this->file = $file;
}
/**
* Display form for editing static page
*
* @param $id
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getEdit($id)
{
// select all content statuses
$statuses = ContentStatuses::getWithTranslations();
// try to find requested page
$page = Content::findOrFail($id);
$page->module_settings = json_decode($page->module_settings);
$allModules = ModulesHandlerToId::getWithTranslations();
$moduleId = $allModules[$page->module_handler];
$templates = Template::where('module_id', $moduleId)
->select(['template_name', 'name', 'description'])
->get();
$history = $this->history->getStructuredHistoryOf($page);
// render view
return view('admin.content.edit', [
'contentStatuses' => $statuses,
'page' => $page,
'rootPages' => $page->getOverview()
->where('contents.id', '!=', $page->id)
->get(),
'templates' => $templates,
'extraData' => call_user_func([$page->module_handler, 'loadExtraData'], $page),
'formSectionNames' => call_user_func([$page->module_handler, 'getExtendedFormSections']),
'formSections' => call_user_func([$page->module_handler, 'getExtendedFormInputsEdit']),
'historySize' => count($history['changesets'])
]);
}
/**
* Edit static page and save changes into history.
*
* @param EditContentRequest $request
* @param $id
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postEdit(EditContentRequest $request, $id)
{
try {
$page = Content::findOrFail($id);
} catch (NotFoundHttpException $e) {
// log attempt of invalid edit
Event::fire(new AttemptToEditInvalidContent($id));
// page for editing not found
return redirect()
->route('content.overview')
->with('error', trans('admin/contents.invalidPage'));
}
$request->url = Str::slug($request->url);
$request->parentPage = $request->parentPage ? $request->parentPage : null;
$request->titlePhotoFilename = $page->title_photo;
// upload file - if provided
if ($request->hasFile('titlePhoto')) {
$file = $this->file->upload($request->file('titlePhoto'), $request);
$request->titlePhotoFilename = $file['filename'];
}
// array of fields in database and fields from request
$fields = [
'title' => 'title',
'url' => 'url',
'template' => 'template',
'published_from' => 'publishedFrom',
'published_to' => 'publishedTo',
'meta_keywords' => 'metaKeywords',
'meta_description' => 'metaDescription',
'content' => 'pageContent',
'parent_id' => 'parentPage',
'status' => 'status',
'title_photo' => 'titlePhotoFilename'
];
// save new values with history
$data = self::getFields($request, $fields);
list($revision, $changedColumns) = $page->updateWithHistory($fields, $data);
$changedColumns += call_user_func_array([$page->module_handler, 'edit'], [&$page, $request, $revision]);
// was something changed?
if ($changedColumns == 0) {
return redirect()
->route('content.edit', ['id' => $page->id])
->with('error', trans('admin/contents.nothingToEdit'));
}
// fire event with
Event::fire(new EditContentEvent($page, $revision));
// something was changed, inform user
return redirect()
->route('content.edit', ['id' => $page->id])
->with('success', trans('admin/contents.successfullyEdited'));
}
/**
* Method for changing page status
* This method is called in static page overview from quick actions. It checks if status is valid, if page exists
* and updates status.
*
* @param $id
* @param $status
*
* @return \Illuminate\Http\RedirectResponse
*/
public function changeStatus($id, $status)
{
// get possible statuses
$statuses = ContentStatuses::getWithTranslations();
unset($statuses[Content::STATUS_DELETED]);
// check if given status is valid
if (!isset($statuses[$status])) {
return redirect()
->route('content.overview')
->with('error', trans('admin/contents.invalidStatus'));
}
try {
// try to find this page
$page = Content::findOrFail($id);
} catch (NotFoundHttpException $e) {
// page not found
return redirect()
->route('content.overview')
->with('error', trans('admin/contents.invalidPage'));
}
// try to change the page
list ($revision, $changedColumns) = $page->updateWithHistory(['status' => 'status'], ['status' => $status]);
// was something changed?
if ($changedColumns == 0) {
return redirect()
->route('content.edit', ['id' => $page->id])
->with('error', trans('admin/contents.nothingToEdit'));
}
// fire events
if ($status != Content::STATUS_DRAFT) {
Event::fire(new PublishContent($page, $revision));
} else {
Event::fire(new MakeDraftFromContent($page, $revision));
}
// redirect back to overview with info for user
return redirect()
->route('content.overview')
->with('success', trans('admin/contents.statusChanged'));
}
/**
* Delete page
*
* @param $id
*
* @return \Illuminate\Http\RedirectResponse
*/
public function deletePage($id)
{
try {
// try to find this page
$page = Content::findOrFail($id);
} catch (NotFoundHttpException $e) {
// page not found
return redirect()
->route('content.overview')
->with('error', trans('admin/contents.invalidPage'));
}
// change url to something unique
$oldURL = $page->url;
$page->url = uniqid($page->url.'_deleted');
$page->save();
list ($revision, $changedColumns) = $page->updateWithHistory(['status' => 'status'], ['status' => Content::STATUS_DELETED]);
// let module to delete some extra content created during page's life
call_user_func([$page->module_handler, 'delete'], $page);
// was something changed?
if ($changedColumns == 0) {
return redirect()
->route('content.edit', ['id' => $page->id])
->with('error', trans('admin/contents.nothingToEdit'));
}
// trigger delete event
Event::fire(new DeleteContent($page, $revision));
// redirect back to overview with info for user
return redirect()
->route('content.overview')
->with('success', trans('admin/contents.pageDeleted', [
'name' => $page->title,
'url' => $oldURL
]));
}
/**
* Sets page as homepage
*
* @param $id
*
* @return \Illuminate\Http\RedirectResponse
*/
public function setHomepage($id)
{
try {
// try to find this page
/**
* @var $page Content
*/
$page = Content::findOrFail($id);
} catch (NotFoundHttpException $e) {
// page not found
return redirect()
->route('content.overview')
->with('error', trans('admin/contents.invalidPage'));
}
// disable any other existing homepage
Content::where('is_homepage', 1)
->update(['is_homepage' => 0]);
// set new homepage
list ($revision, $changedColumns) = $page->updateWithHistory(['is_homepage' => 'is_homepage'], ['is_homepage' => 1]);
// was something changed?
if ($changedColumns == 0) {
return redirect()
->route('content.overview')
->with('error', trans('admin/contents.nothingToEdit'));
}
// trigger delete event
Event::fire(new SetHomepage($page, $revision));
// redirect back to overview with info for user
return redirect()
->route('content.overview')
->with('success', trans('admin/contents.homepageSetup', [
'name' => $page->title,
'url' => $page->url
]));
}
/**
* Convert object of all request data into array of only wanted fields
*
* @param Request $request
* @param $fields
*
* @return array
*/
public static function getFields(Request $request, $fields)
{
$requestData = [];
foreach ($fields as $field) {
$requestData[$field] = $request->$field;
}
return $requestData;
}
}
@@ -4,10 +4,13 @@ namespace App\Http\Controllers\Admin;
use App\Enumerations\CustomFieldResources; use App\Enumerations\CustomFieldResources;
use App\Enumerations\CustomFieldTypes; use App\Enumerations\CustomFieldTypes;
use App\Events\DeleteCustomField;
use App\Events\EditCustomField as EditCustomFieldEvent;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests; use App\Http\Requests;
use App\Http\Requests\EditCustomFieldRequest; use App\Http\Requests\EditCustomFieldRequest;
use App\Models\CustomField; use App\Models\CustomField;
use Illuminate\Support\Facades\Event;
class EditCustomField extends Controller class EditCustomField extends Controller
{ {
@@ -60,6 +63,9 @@ class EditCustomField extends Controller
// save changes into database // save changes into database
$customField->save(); $customField->save();
// fire event about editing custom field
Event::fire(new EditCustomFieldEvent($customField));
return redirect() return redirect()
->route('customfields.edit', ['id' => $id]) ->route('customfields.edit', ['id' => $id])
->with('success', trans('admin/customFields.successfullyEdited')); ->with('success', trans('admin/customFields.successfullyEdited'));
@@ -89,6 +95,9 @@ class EditCustomField extends Controller
// delete item // delete item
$field->delete(); $field->delete();
// fire event about editing custom field
Event::fire(new DeleteCustomField($field));
// redirect back to overview // redirect back to overview
return redirect() return redirect()
->route('customfields.overview') ->route('customfields.overview')
@@ -0,0 +1,61 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\Directory;
class EditDirectory extends Controller
{
/**
* @param Requests\EditDirectoryRequest $request
* @param $directoryId
*
* @return $this|\Illuminate\Http\JsonResponse
*/
public function postEdit(Requests\EditDirectoryRequest $request, $directoryId)
{
$directory = Directory::findOrFail($directoryId);
// check if given name is not used in parent directory
$exists = Directory::where('parent_id', $directory->parent_id)
->where('name', $request->name)
->where('id', '!=', $directoryId)
->exists();
if ($exists) {
if ($request->ajax()) {
return response()->json([
'status' => 'failed',
'message' => trans('admin/fileManager.subdirectoryExists')
]);
} else {
return redirect()
->route('upload.overview', ['id' => $directoryId])
->with('error', trans('admin/fileManager.subdirectoryExists'))
->withInput();
}
}
$directory->name = $request->name;
$directory->description = $request->description;
$directory->save();
$message = trans('admin/fileManager.editDirectorySuccess');
if (!$request->ajax()) {
return redirect()
->route('upload.overview', ['id' => $directory->id])
->with('success', $message);
} else {
$payload = [
'status' => 'success',
'message' => $message
];
return response()->json($payload);
}
}
}
+184
View File
@@ -0,0 +1,184 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\EditTemplateRequest;
use App\Models\Template;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
class EditTemplate extends Controller
{
/**
* Render form for editing template
*
* @param $template
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getEdit($template)
{
$template = Template::findOrFail($template);
$path = $template->getPath();
// load template content
$absolutePath = $template->getPathToTemplate();
$content = @file_get_contents($absolutePath);
return view('admin.templates.edit', [
'template' => $template,
'templateContent' => $content,
'isWritable' => is_writable(dirname($absolutePath)),
'path' => $path,
]);
}
/**
* Save meta information about template and edited content
*
* @param EditTemplateRequest $request
* @param $templateId
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postEdit(EditTemplateRequest $request, $templateId)
{
// find template
$template = Template::findOrFail($templateId);
// setup meta information
$template->name = $request->name;
if ($request->description) {
$template->description = $request->description;
}
// save meta information into database
$template->save();
// try to save content
return $this->saveContent($template, $request);
}
/**
* Save physical content of given template
*
* @param Template $template
* @param EditTemplateRequest $request
*
* @return \Illuminate\Http\RedirectResponse
*/
private function saveContent(Template $template, EditTemplateRequest $request)
{
// get templates with paths
$originalTemplate = $template->getPathToTemplate();
$customTemplate = $template->getPathToTemplate(Template::CUSTOM_EDIT_DIRECTORY);
// get paths
$originalDir = dirname($originalTemplate);
$customDir = dirname($customTemplate);
// try to save content
if (!is_writable($customDir) && !is_writable($originalDir)) {
return redirect()
->route('templates.edit', ['id' => $request->id])
->withInput()
->with('error', trans('admin/templates.cannotWriteContent'));
}
// save new content only if something was changed
if ($this->isContentDifferent($originalTemplate, $customTemplate, $request->templateContent)) {
// create directory for custom updates
if (!is_dir($customDir)) {
File::makeDirectory($customDir);
}
// make copy of existing template (if exists)
$this->backupTemplates($customTemplate);
// save content
File::put($customTemplate, $request->templateContent);
}
return redirect()
->route('templates.overview', ['id' => $template->path])
->with('success', trans('admin/templates.editSuccessfull'));
}
/**
* Get last "revision" of edited template.
*
* Template changes are not discarded, however new file is created. Last template is renamed to
* <template>.blade.php.<num>, where <num> is result of this method.
*
* @param $template
*
* @return int
*/
private function getNewRevisionNumber($template)
{
// nothing to backup - no template in custom directory exists
if (!File::exists($template)) {
return null;
}
$number = 0;
while (File::exists($template . '.' . $number)) {
$number++;
}
return $number;
}
/**
* If exists previously edited template, rename it to <template>.blade.php.<number>
*
* @param $template
*/
private function backupTemplates($template)
{
// get last sequence number
$number = $this->getNewRevisionNumber($template);
// nothing to backup
if (is_null($number)) {
return;
}
// rename template
File::move($template, $template . '.' . $number);
}
/**
* Compare data from previous/original template
*
* @param $originalTemplate
* @param $customTemplate
* @param $currentContent
*
* @return bool
*/
private function isContentDifferent($originalTemplate, $customTemplate, $currentContent)
{
/**
* get last revision of template - we need to substract 1 from result from getNewRevisionNumber(),
* because this method returns number of first non-existing template
*/
$lastRevision = $this->getNewRevisionNumber($customTemplate) - 1;
// select compared file
if ($lastRevision < 0) {
$diffFile = $originalTemplate;
} else {
$diffFile = $customTemplate . '.' . $lastRevision;
}
// get content
$originalContent = file_get_contents($diffFile);
return $originalContent != $currentContent;
}
}
@@ -0,0 +1,104 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Events\EditFile;
use App\Helpers\FileManager;
use App\Http\Controllers\Controller;
use App\Http\Requests\EditUploadedFileRequest;
use App\Models\File;
use Illuminate\Support\Facades\Event;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class EditUploadedFile extends Controller
{
/**
* Edit form
*
* Render edit form for displaying details and updating given file
*
* @param int $id file id
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/
public function getDetail($id)
{
try {
$file = File::findOrFail($id);
} catch (NotFoundHttpException $e) {
return $this->fileNotFound();
}
return view('admin.fileManager.edit', [
'file' => $file,
'extraInfo' => FileManager::getAdditionalInfo($file)
]);
}
/**
* Updates file
*
* User can change only keywords, original filename and description. Mime type, hash and other fields remain
* unchanged
*
* @param EditUploadedFileRequest $request
* @param $id
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postEdit(EditUploadedFileRequest $request, $id)
{
try {
$file = File::findOrFail($id);
} catch (NotFoundHttpException $e) {
return $this->fileNotFound();
}
// set values from form
$file->name = $request->name;
$file->keywords = $request->keywords;
$file->description = $request->description;
$file->save();
// fire action
Event::fire(new EditFile($file));
// update successfull
return redirect()
->route('upload.detail', ['id' => $id])
->with('success', trans('admin/fileManager.successfullyChanged'));
}
/**
* Deletes file
*
* @param $id
*/
public function deleteFile($id)
{
try {
$file = File::findOrFail($id);
} catch (NotFoundHttpException $e) {
return $this->fileNotFound();
}
$directoryId = $file->directory_id;
$file->delete();
return redirect()
->route('upload.overview', ['id' => $directoryId])
->with('success', trans('admin/fileManager.fileDeleted'));
}
/**
* Redirects user to files overview
*
* @return \Illuminate\Http\RedirectResponse
*/
private function fileNotFound()
{
return redirect()
->route('upload.overview')
->with('error', trans('admin/fileManager.fileNotFound'));
}
}
+22 -10
View File
@@ -4,11 +4,13 @@ namespace App\Http\Controllers\Admin;
use App\Enumerations\UserRoles; use App\Enumerations\UserRoles;
use App\Enumerations\UserStates; use App\Enumerations\UserStates;
use App\Events\EditUser as EditUserEvent;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests; use App\Http\Requests;
use App\Http\Requests\EditUserRequest; use App\Http\Requests\EditUserRequest;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
class EditUser extends Controller class EditUser extends Controller
@@ -44,8 +46,17 @@ class EditUser extends Controller
*/ */
public function postEdit(EditUserRequest $request, $id) public function postEdit(EditUserRequest $request, $id)
{ {
$loggedUser = Auth::user();
$user = User::findOrFail($id); $user = User::findOrFail($id);
// non-admin user is trying to edit someone else
if ($loggedUser->role != User::ROLE_ADMIN && $id != $loggedUser->id) {
return redirect()
->back()
->with('error', trans('auth.accessDenied'));
}
// update username if set // update username if set
if (isset($request->username)) { if (isset($request->username)) {
$user->username = $request->username; $user->username = $request->username;
@@ -56,24 +67,25 @@ class EditUser extends Controller
$user->name = $request->name; $user->name = $request->name;
} }
if (Auth::user()->role == User::ROLE_ADMIN) { if (isset($request->role)) {
if (isset($request->role)) { $user->role = $request->role;
$user->role = $request->role; }
}
if (isset($request->status)) { if (isset($request->status)) {
$user->status = $request->status; $user->status = $request->status;
} }
if (isset($request->password)) { if (isset($request->password)) {
$user->password = Hash::make($request->password); $user->password = Hash::make($request->password);
}
} }
$user->email = $request->email; $user->email = $request->email;
$user->save(); $user->save();
// fire event about editing user
Event::fire(new EditUserEvent($user));
return redirect() return redirect()
->route('users.detail', ['id' => $id]) ->route('users.detail', ['id' => $id])
->with('success', trans('admin/userManagement.userSuccessfullyEdited')); ->with('success', trans('admin/userManagement.userSuccessfullyEdited'));
+63
View File
@@ -0,0 +1,63 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Requests\EditWidgetRequest;
use App\Models\Widget;
use App\Widgets\Exceptions\MissingParameterException;
use Illuminate\Support\Facades\Event;
class EditWidget extends Controller
{
public function getEdit($id)
{
$widget = Widget::findOrFail($id);
$presenter = call_user_func([$widget->widget_type_handler, 'getPresenter']);
return call_user_func([$presenter, 'renderEditForm'], $widget);
}
public function postEdit(EditWidgetRequest $request, $widget)
{
// create new widget
$widget = Widget::findOrFail($widget);
// update name
$widget->name = $request->name;
// save description if available
if (isset($request->description)) {
$widget->description = $request->description;
}
// try to save this widget
try {
$widget = call_user_func([$widget->widget_type_handler, 'save'], $widget, (object)$request->all());
} catch (MissingParameterException $e) {
// user omitted some value
return $this->invalidWidget($e->getMessage());
} catch (\Exception $e) {
// something went wrong
return $this->invalidWidget(trans('admin/widgets.cannotSave', ['exception' => $e->getMessage()]));
}
// save into database
$widget->save();
// fire event with editing widget
Event::fire(new \App\Events\EditWidget($widget));
// redirect with success notification
return redirect()
->route('widgets.overview')
->with('success', trans('admin/widgets.successfullyEdited'));
}
private function invalidWidget($error)
{
return redirect()
->route('widgets.overview')
->withInput()
->with('error', $error);
}
}
@@ -0,0 +1,81 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\EditWidgetAreaRequest;
use App\Models\WidgetArea;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Event;
class EditWidgetArea extends Controller
{
public function getEdit($id)
{
$area = WidgetArea::findOrFail($id);
return view('admin.widgets.area.edit', ['area' => $area]);
}
public function postEdit(EditWidgetAreaRequest $request, $id)
{
try {
$area = WidgetArea::findOrFail($id);
} catch (ModelNotFoundException $e) {
return $this->invalidArea();
}
$area->name = $request->name;
$area->description = $request->description;
$area->save();
// fire event with new widget area
Event::fire(new \App\Events\EditWidgetArea($area));
return redirect()
->route('widgetareas.edit', ['id' => $id])
->with('success', trans('admin/widgetAreas.editSuccessfull'));
}
/**
* Hard deletes widget area
*
* @param $id
*
* @return \Illuminate\Http\RedirectResponse
*/
public function deleteArea($id)
{
// try to find area
try {
$area = WidgetArea::findOrFail($id);
} catch (ModelNotFoundException $e) {
return $this->invalidArea();
}
// delete area
$area->delete();
// fire event with new widget area
Event::fire(new \App\Events\DeleteWidgetArea($area));
// redirect and inform user
return redirect()
->route('widgetareas.overview')
->with('success', trans('admin/widgetAreas.successfullyDeleted'));
}
/**
* Redirect user to overview with message about invalid widget area
*
* @return \Illuminate\Http\RedirectResponse
*/
private function invalidArea()
{
return redirect()
->route('widgetareas.overview')
->with('error', trans('admin/widgetAreas.invalidArea'));
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Content;
use App\Models\ContentHistory;
class History extends Controller
{
/**
* @var ContentHistory
*/
private $history;
public function __construct(ContentHistory $history)
{
parent::__construct();
$this->history = $history;
}
/**
* @param $id
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getOverview($id)
{
// test if given content id is static page and if exists
$content = Content::findOrFail($id);
$history = $this->history->getStructuredHistoryOf($content);
return view('admin/history.overview', [
'history' => $history,
'page' => $content
]);
}
public function getDiff($revision, $id)
{
$change = $this->history->findOrFail($id);
$diff = $this->history->getDiff($change);
return view('admin/history.diff', [
'change' => $change,
'columnName' => 'Page content',
'diff' => $diff
]);
}
}
+76
View File
@@ -0,0 +1,76 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Handlers\Contracts\SearchHandler;
use App\Handlers\Contracts\SearchPresenterHandler;
use App\Handlers\Registrators\SearchEngineRegistrator;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Input;
use Symfony\Component\Process\Exception\InvalidArgumentException;
class Search extends Controller
{
/**
* Create form for searching
*
* @return $this|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getSearch()
{
$results = [];
$term = Input::get('search');
if (!is_null($term)) {
try {
$results = $this->performSearch($term);
} catch (InvalidArgumentException $e) {
// user entered empty string (or something like empty string)
return redirect()
->route('search')
->with('error', $e->getMessage());
}
}
return view('admin.search.page', ['search' => $term, 'results' => $results]);
}
/**
* Method used for performing search.
*
* This method iterates over all registered search engines and returns results for each engine apart.
*
* @param string $term search text
*
* @return array array of results. One item per each engine
*/
protected function performSearch($term)
{
$engines = App::make('registerSearchEngine')
->get(SearchEngineRegistrator::ADMIN);
$resultsParts = [];
foreach ($engines as $engine) {
/**
* @var SearchHandler $search
* @var SearchPresenterHandler $presenter
*/
list ($search, $presenter) = $engine;
// try to find given term
$results = $search->search($term);
// create result object
$resultsParts[$search->getId()] = [
'name' => $search->getName(),
'content' => $presenter->render($results),
'count' => count($results)
];
}
return $resultsParts;
}
}
+69
View File
@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use Illuminate\Support\Facades\App;
class Settings extends Controller
{
/**
* @var \App\Models\Settings
*/
protected $settings;
/**
* Settings constructor.
*
* @param \App\Models\Settings $settings
*/
public function __construct(\App\Models\Settings $settings)
{
$this->settings = $settings;
}
public function getOverview()
{
$sections = App::make('registerSettingsExtension')
->get();
$settings = $this->settings->getAll();
return view('admin.settings.overview', [
'formSections' => $sections,
'settings' => $settings
]);
}
public function saveSettings(Requests\SaveSettingsRequest $request)
{
$data = $request->all();
// remove CSRF token field
unset($data['_token']);
$settings = $this->settings->getAll();
$updated = 0;
foreach ($data as $key => $value) {
if (isset($settings->$key)) {
if ($settings->$key != $value) {
$updated++;
\App\Models\Settings::where('key', $key)
->update(['value' => $value]);
}
} else {
\App\Models\Settings::create(['key' => $key, 'value' => $value]);
$updated++;
}
}
if ($updated > 0) {
return redirect()
->route('settings.overview')
->with('success', trans('admin/settings.successfullySaved'));
} else {
return redirect()
->route('settings.overview')
->with('error', trans('admin/settings.nothingToSave'));
}
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\TemplatePath;
use Illuminate\Http\Request;
class TemplateOverview extends Controller
{
public function getPath($path)
{
$path = TemplatePath::findOrFail($path);
return view('admin.templates.list', [
'directory' => $path,
'isWritable' => is_writable(base_path($path->path)),
'templates' => $path->templates()
->get(),
'subdirectories' => $path->subdirectories()
->get()
]);
}
}
+79
View File
@@ -0,0 +1,79 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Requests\UploadFileRequest;
use App\Models\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
class UploadFile extends Controller
{
/**
* @var File
*/
private $file;
function __construct(File $file)
{
parent::__construct();
$this->file = $file;
}
/**
* Uploads any file
*
* @param UploadFileRequest $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postFile(UploadFileRequest $request)
{
if (!$request->hasFile('file')) {
return $this->invalidUpload('noFileSpecified');
}
try {
$uploadedFile = $this->file->upload($request->file('file'), $request);
// we do not want to redirect
if ($request->ajax()) {
return $this->jsonResponse($uploadedFile);
}
// upload was not performed via ajax, redirect user
return redirect()
->route('upload.overview', ['directory' => $request->directoryId])
->with('success', trans('admin/fileManager.uploadSuccessfull'));
} catch (FileException $e) {
return $this->invalidUpload('invalidFile');
}
}
protected function invalidUpload($message)
{
return redirect()
->route('upload.file')
->with('error', trans('admin/fileManager.' . $message));
}
/**
* Send response about uploaded file as JSON
*
* @param $uploadedFile
*
* @return \Illuminate\Http\JsonResponse
*/
private function jsonResponse($uploadedFile)
{
$filename = $uploadedFile['file']->getFilename();
$url = config('app.upload_path') . DIRECTORY_SEPARATOR . $filename;
$data = [
'filename' => $filename,
'url' => $url,
'id' => $uploadedFile['id']
];
return response()->json($data);
}
}
@@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\Directory;
use App\Models\File;
use Illuminate\Support\Facades\Input;
class UploadedFilesOverview extends Controller
{
/**
* List of all files and directories
*
* @param null $directoryId
* @param null $fileType
* @param null $fileSubtype
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getOverview($directoryId = null, $fileType = null, $fileSubtype = null)
{
// get directory information
$directory = is_null($directoryId) ? new Directory() : Directory::findOrFail($directoryId);
// get all files in this directory
$files = File::orderBy('updated_at', 'DESC')
->where('directory_id', $directory->id);
// try to filter by given type
if (!is_null($fileType)) {
if (is_null($fileSubtype)) {
$files = $files->where('mime_type', 'LIKE', $fileType . '%');
} else {
$files = $files->where('mime_type', $fileType . '/' . $fileSubtype);
}
}
// include hidden directories?
$includeHidden = Input::get('hidden');
return view('admin.fileManager.overview', [
'directory' => $directory,
'subdirectories' => $directory->subdirectories($includeHidden),
'files' => $files->get()
]);
}
}
+15 -1
View File
@@ -6,11 +6,22 @@ use App\Enumerations\UserRoles;
use App\Enumerations\UserStates; use App\Enumerations\UserStates;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests; use App\Http\Requests;
use App\Models\ActionLog;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
class UserDetail extends Controller class UserDetail extends Controller
{ {
/**
* @var ActionLog
*/
private $log;
function __construct(ActionLog $log)
{
$this->log = $log;
}
public function getDetail($id = null) public function getDetail($id = null)
{ {
// when no user specified, lets assume we want to edit "me" // when no user specified, lets assume we want to edit "me"
@@ -21,13 +32,16 @@ class UserDetail extends Controller
// try to find given user // try to find given user
$user = User::findOrFail($id); $user = User::findOrFail($id);
$actions = $this->log->getUserActions($id);
$roles = UserRoles::getWithTranslations(); $roles = UserRoles::getWithTranslations();
$states = UserStates::getWithTranslations(); $states = UserStates::getWithTranslations();
return view('admin.userManagement.detail', [ return view('admin.userManagement.detail', [
'user' => $user, 'user' => $user,
'states' => $states, 'states' => $states,
'roles' => $roles 'roles' => $roles,
'actions' => $actions
]); ]);
} }
} }
+21 -3
View File
@@ -2,19 +2,37 @@
namespace App\Http\Controllers\Admin; namespace App\Http\Controllers\Admin;
use App\Enumerations\UserRoles;
use App\Enumerations\UserStates;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests; use App\Http\Requests;
use App\Models\User; use App\Models\User;
class UsersOverview extends Controller class UsersOverview extends Controller
{ {
public function getOverview($perPage = 12, $state = null) public function getOverview($status = null, $perPage = 12)
{ {
$users = User::where('role', '!=', User::STATE_DELETED)->orderBy('id', 'desc'); $users = User::where('status', '<>', User::STATE_DELETED)
->orderBy('id', 'desc');
// get statuses
$statuses = UserStates::getWithTranslations();
$statuses[''] = trans('admin/userManagement.allStatuses');
unset($statuses[User::STATE_DELETED]);
// filter using status
if (!is_null($status) && isset($statuses[$status])) {
$users = $users->where('status', $status);
}
// setup pagination
$users = $users->paginate($perPage); $users = $users->paginate($perPage);
return view('admin.userManagement.overview', ['users' => $users]); return view('admin.userManagement.overview', [
'users' => $users,
'roles' => UserRoles::getWithTranslations(),
'statuses' => $statuses,
'currentStatus' => $status
]);
} }
} }
@@ -0,0 +1,24 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\WidgetArea;
class WidgetAreaOverview extends Controller
{
/**
* List of all widget area. Displayed paginated
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getOverview()
{
// get widget areas ordered by created_at
$areas = WidgetArea::orderBy('created_at', 'DESC')
->paginate(25);
return view('admin.widgets.area.overview', ['areas' => $areas]);
}
}

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