Author SHA1 Message Date
Michal Kváček f51dd9458c FEATURE: change default email template 2017-10-29 21:45:01 +01:00
Michal Kváček 962225080d FEATURE: make intro text white 2017-10-29 21:38:43 +01:00
Michal Kváček deb094b5c9 FEATURE: add uploader into CKEditor 2016-10-12 18:22:12 +02:00
Michal Kváček d425133cae REFACTORING: refactor module service providers to reduce amoount of duplicated code 2016-10-12 17:38:06 +02:00
Michal Kváček 9b6ae9f9f8 FIX: fix saving published_from and published_to fields 2016-10-12 17:15:58 +02:00
Michal Kváček 4a95a9692d FIX: fix saving new widget without container ID 2016-10-12 16:33:07 +02:00
Michal Kváček 06439bc9a0 Merge branch 'dev' into dobrotyzpece.cz 2016-10-12 16:09:44 +02:00
Michal Kváček 12683df0ab FIX: fix error when rendering not-existing widget area 2016-10-12 16:09:39 +02:00
Michal Kváček 0cb53b2d80 FEATURE: add template for widget with contact form 2016-10-12 16:01:05 +02:00
Michal Kváček 5fd9b1871f FIX: fix editing widget with container ID 2016-10-12 16:00:39 +02:00
Michal Kváček fb51ae80ac FEATURE: add widget for displaying contact form 2016-10-12 15:36:24 +02:00
Michal Kváček b9d141c4f1 FEATURE: add widget with address block 2016-10-12 15:12:42 +02:00
Michal Kváček af4edac469 FEATURE: json_decode widget settings before calling handler 2016-10-12 15:12:18 +02:00
Michal Kváček 0451f9942c FIX: fix error when trying to render widget preview with json_decoded settings 2016-10-12 15:11:55 +02:00
Michal Kváček 657c030033 DOC: add phpdoc 2016-10-12 15:11:29 +02:00
Michal Kváček d761914786 Merge branch 'dev' into binarity.cz 2016-10-11 19:12:18 +02:00
Michal Kváček 625bdbb2e2 FEATURE: add functionality for rendering widgets via shortcode [widget] 2016-10-11 19:10:03 +02:00
Michal Kváček d5f9e1fc2b Merge branch 'dobrotyzpece.cz' into dev 2016-10-11 16:38:05 +02:00
Michal Kváček ce058ae824 FEATURE: include commont parts of widget forms 2016-10-11 16:24:16 +02:00
Michal Kváček dee5060a24 FEATURE: add unique code to widgets 2016-10-11 16:16:16 +02:00
Michal Kváček c70e8a6b0d FEATURE: minor changes in template for dobrotyzpece.cz 2016-10-11 15:57:29 +02:00
Michal Kváček cb9b96c861 FIX: fix one page menu 2016-10-11 15:40:42 +02:00
Michal Kváček 4bd5a61fde FEATURE: add artisan shortcut for publishing assets and views 2016-10-11 15:32:06 +02:00
Michal Kváček 46ff310b01 FIX: fix meta information in header 2016-10-10 23:42:23 +02:00
Michal Kváček 96b05a7b25 FEATURE: add meta robots into head 2016-10-10 23:40:21 +02:00
Michal Kváček 563528cdc6 FEATURE: add meta author into head 2016-10-10 23:37:10 +02:00
Michal Kváček efa3289491 FEATURE: make list of directories nicer 2016-10-10 23:19:13 +02:00
Michal Kváček 3460f607b5 FEATURE: make history overview nicer 2016-10-10 23:09:38 +02:00
Michal Kváček 0384fab421 FIX: fix published_from and published_to 2016-10-10 21:45:31 +02:00
Michal Kváček b3ac9b9eec Merge branch 'binarity.cz' of binarity.cz:/opt/git/internal/cms/minicms into binarity.cz 2016-10-10 21:42:03 +02:00
Michal Kváček bfa0685f2e FIX: display only published pages - respect published_* settings 2016-10-10 21:41:32 +02:00
Peter Hrdlica 59226dbdc4 FEATURE: more changes to article and article list 2016-10-10 21:36:55 +02:00
Peter Hrdlica 446e8352b5 FEATURE: changed graphics of articles 2016-10-10 21:04:25 +02:00
Michal Kváček 190ca25b2a FIX: fix published_from and published_to fields 2016-10-10 20:31:59 +02:00
Michal Kváček f121ee356b Merge branch 'dobrotyzpece.cz' into binarity.cz 2016-10-10 20:25:17 +02:00
Michal Kváček b3d59fc182 FIX: fix date in articles 2016-10-10 20:19:00 +02:00
Michal Kváček 20f6295f84 "FEATURE: add categories into article detail and article list"
This reverts commit 08e97fe2cb.
2016-10-10 20:15:10 +02:00
Michal Kváček 2c36203690 FEATURE: check translation for lockUrl 2016-10-10 20:13:03 +02:00
Michal Kváček 458d8ec61c FIX: fix translations for template paths in blog 2016-10-10 19:08:59 +02:00
Michal Kváček 284dfa3fe8 Merge branch 'dev' into binarity.cz 2016-10-10 19:03:55 +02:00
Michal Kváček 08e97fe2cb Revert "FEATURE: add categories into article detail and article list"
This reverts commit bceef69a72.
2016-10-10 19:03:32 +02:00
Michal Kváček 7e63047313 FEATURE: swap created_at and published_from in template for blog 2016-10-10 19:00:42 +02:00
Michal Kváček d9834fe068 REFACTORING: split ArticleList::render into few smaller methods 2016-10-10 18:29:37 +02:00
Michal Kváček dc43a9503d FEATURE: add basic template for dobrotyzpece.cz 2016-10-10 01:25:36 +02:00
Michal Kváček a75425ca12 Merge branch 'dev' into dobrotyzpece.cz 2016-10-09 23:20:13 +02:00
Michal Kváček 8c20654280 Merge branch 'dev' into dobrotyzpece.cz 2016-10-09 23:18:11 +02:00
Michal Kváček bceef69a72 FEATURE: add categories into article detail and article list 2016-10-07 10:32:46 +02:00
Michal Kváček 1e310f0da5 FIX: add with methods to selecting comments and content pages 2016-10-04 13:14:21 +02:00
Michal Kváček ab90b907f8 FIX: hide protected pages from menu widget 2016-10-04 13:09:32 +02:00
Michal Kváček f1aacf8008 FEATURE: style little bit comments 2016-10-04 13:04:24 +02:00
Michal Kváček ce82b67c47 FEATURE: hide comments when article does not allow them 2016-10-04 12:58:42 +02:00
Michal Kváček 3024ae8b23 FEATURE: turn website off and on during update 2016-10-04 12:40:31 +02:00
Michal Kváček 7dcb8e280c FIX: fix exception when accessing protected page 2016-10-04 11:33:38 +02:00
Michal Kváček f9dfe076a0 Merge branch 'dev' into binarity.cz 2016-10-04 11:27:55 +02:00
Michal Kváček db88079f26 FIX: fix template loading for article list 2016-10-04 11:27:49 +02:00
Michal Kváček 3f1ae0f5a1 Merge branch 'dev' into binarity.cz 2016-10-04 11:16:59 +02:00
Michal Kváček f699d2c569 FIX: fix minor bugs in blog module 2016-10-04 11:16:04 +02:00
Michal Kváček fdb63fcd8a FEATURE: minor updates in binarity template 2016-10-04 11:14:17 +02:00
Michal Kváček 52fb27b4fe FEATURE: style comments and comments form 2016-10-04 06:59:46 +02:00
Michal Kváček 7234fa0810 Merge branch 'dev' into binarity.cz 2016-10-04 00:44:40 +02:00
Michal Kváček 581e32e98b FEATURE: add new helper Date 2016-10-04 00:44:36 +02:00
Michal Kváček 06780015d4 FEATURE: create model for articles 2016-10-04 00:44:24 +02:00
Michal Kváček 35bdd38f4c FEATURE: add new macros for date manipulation 2016-10-04 00:43:59 +02:00
Michal Kváček eacba1bec3 FIX: fix logging creating comments 2016-10-04 00:43:28 +02:00
Michal Kváček 975cc50272 FIX: fix routes namespaces 2016-10-04 00:43:04 +02:00
Michal Kváček 52b0ec7c72 FEATURE: add template for blog 2016-10-04 00:42:20 +02:00
Michal Kváček de02944d0d FIX: check if method is callable before calling it 2016-10-03 03:09:04 +02:00
Michal Kváček da1c8652e6 FEATURE: prepare support for blog 2016-10-03 03:04:03 +02:00
Michal Kváček 012ba1fd36 Merge branch 'dev' into binarity.cz 2016-10-03 02:41:57 +02:00
Michal Kváček cbfc5fcee5 DELETE: do some cleanup of repository 2016-10-03 02:37:19 +02:00
Michal Kváček 232e1d5ec9 Merge branch 'dev' into binarity.cz 2016-10-03 01:40:09 +02:00
Michal Kváček aca3c778e0 FEATURE: add same height to all templates 2016-10-03 01:40:04 +02:00
Michal Kváček 88a2463d13 FIX: render menu link to index when page is set as homepage 2016-10-03 01:36:52 +02:00
Michal Kváček f3e797a59a FIX: minor fixes in styles 2016-10-03 01:25:11 +02:00
Michal Kváček 0869ac7c24 Merge branch 'dev' into binarity.cz 2016-10-03 01:09:53 +02:00
Michal Kváček 304518fbe7 FEATURE: make bigger line-height in .off-canvas-content div 2016-10-03 01:09:51 +02:00
Michal Kváček 49577a7e1a FEATURE: add warning before leaving form with unsaved changes 2016-10-03 01:04:31 +02:00
Michal Kváček 606ee2016d FEATURE: add translations for emails dir in contact form templates 2016-10-03 00:34:07 +02:00
Michal Kváček 8608a2d67b Merge branch 'dev' into binarity.cz 2016-10-03 00:07:50 +02:00
Michal Kváček 3bac8dc09b FEATURE: add missing translations 2016-10-03 00:07:46 +02:00
Michal Kváček f61b8a7bcc Merge branch 'dev' into binarity.cz 2016-10-02 23:58:55 +02:00
Michal Kváček b6d3daaa35 FEATURE: add settings for linkedIn profile 2016-10-02 23:58:50 +02:00
Michal Kváček 33a928febb Merge branch 'dev' into binarity.cz 2016-10-02 23:33:53 +02:00
Michal Kváček 06c84867ec FEATURE: add error pages 2016-10-02 23:33:43 +02:00
Michal Kváček 8a9543cd2d FIX: fix gravatar http/https path 2016-10-02 23:11:30 +02:00
Michal Kváček 4f67b69984 FIX: fix creating new menu 2016-10-02 22:41:20 +02:00
Michal Kváček 28df8681e4 FEATURE: change default image for og:image 2016-10-02 22:21:49 +02:00
Michal Kváček 4222dbc243 Merge branch 'dev' into doucovanineratovice.cz 2016-10-02 22:16:33 +02:00
Michal Kváček 2f27e7f5c9 Merge branch 'dev' into binarity.cz 2016-10-02 22:16:21 +02:00
Michal Kváček c5fb951546 FIX: fix warning in update script 2016-10-02 22:16:16 +02:00
Michal Kváček ecd7aa27f0 Merge branch 'dev' into binarity.cz 2016-10-02 22:14:48 +02:00
Michal Kváček ecd01e1396 FIX: fix saving menu widget 2016-10-02 22:14:41 +02:00
Michal Kváček 76b226629f FEATURE: display references in descending order 2016-10-02 22:14:28 +02:00
Michal Kváček 97fae9bf9d FIX: fix selecting pages - exclude pages from disabled modules 2016-10-02 21:58:56 +02:00
Michal Kváček 5621b5acba FEATURE: add error message and meta information into contact form template 2016-10-02 21:24:51 +02:00
Michal Kváček ff237599a8 FEATURE: add meta information to all static pages 2016-10-02 21:22:47 +02:00
Michal Kváček 679ca91fc9 FEATURE: make homepage and default static page templates HTML5 valid 2016-10-02 21:16:41 +02:00
Michal Kváček 1dea234cb7 Merge branch 'dev' into binarity.cz 2016-10-02 20:47:27 +02:00
Michal Kváček e42d06904e FEATURE: add current URL into all views 2016-10-02 20:47:22 +02:00
Michal Kváček cb2fa84ade FEATURE: few mostly minor fixes in layout 2016-10-02 20:47:00 +02:00
Michal Kváček 0a0b0e7518 Merge branch 'dev' into binarity.cz 2016-10-02 20:16:06 +02:00
Michal Kváček 65dc4fd37e FIX: allow using same url after page was deleted 2016-10-02 20:15:02 +02:00
Michal Kváček b13f6bbea9 Merge branch 'dev' into binarity.cz 2016-10-02 20:03:23 +02:00
Michal Kváček 10e463b8b4 Merge branch 'dev' into doucovanineratovice.cz 2016-10-02 20:03:16 +02:00
Michal Kváček 316f7a9a16 FIX: fix sending status after sending e-mail from contact form 2016-10-02 20:03:09 +02:00
Michal Kváček 5e79d0208a FEATURE: add error message to contact form 2016-10-02 20:02:49 +02:00
Michal Kváček 5cdca60cce FIX: fix success message after sending e-mail 2016-10-02 20:00:05 +02:00
Michal Kváček 86a2d277f6 FEATURE: change colors 2016-10-02 19:51:00 +02:00
Michal Kváček ad59bc0adc FEATURE: change color of title page and navbar 2016-10-02 19:01:20 +02:00
Michal Kváček 556d863b45 FEATURE: add page title into tab header 2016-10-02 18:46:33 +02:00
Michal Kváček 673531ae22 FEATURE: add missing templates 2016-10-02 16:28:37 +02:00
Michal Kváček a9d5c0de28 Merge branch 'dev' into binarity.cz 2016-10-02 16:28:24 +02:00
Michal Kváček b43e37fa83 FEATURE: add support for shortcodes 2016-10-02 16:28:12 +02:00
Michal Kváček 6c4b30f1f7 FETURE: add default template for static pages 2016-10-02 15:14:18 +02:00
Michal Kváček c4a4354aff Merge branch 'dev' into binarity.cz 2016-10-02 14:49:43 +02:00
Michal Kváček ad77de0424 Merge branch 'dev' into binarity.cz 2016-10-02 14:49:13 +02:00
Michal Kváček c4d4ac2bfe FEATURE: add notification after sending mail from contact form 2016-10-02 14:46:54 +02:00
Michal Kváček 0718772740 FIX: delete mainMenu widget area when uninstalling template 2016-10-02 14:31:57 +02:00
Michal Kváček 0ace8c9cb6 FIX: fix template installation 2016-10-02 14:31:24 +02:00
Michal Kváček 0482121441 Merge branch 'dev' of binarity.cz:/opt/git/internal/cms/minicms into dev 2016-10-02 13:50:33 +02:00
Michal Kvacek 0df8eaa2e3 Merge branch 'master' into dev 2016-10-01 22:06:13 +02:00
Michal Kvacek 66a570bbf7 FIX fix redirect after sending message 2016-10-01 22:05:17 +02:00
Michal Kváček 0badc52f17 Merge branch 'dev' into binarity.cz 2016-10-01 14:18:10 +02:00
Peter Hrdlica 4cf1fedc61 FEATURE: more translations 2016-09-29 23:11:42 +02:00
Peter Hrdlica 341b5dc9ec FEATURE: translations 2016-09-29 23:04:26 +02:00
Michal Kváček f5e2aec818 REFORMATTING: reformatted whitespaces in contactform template 2016-09-29 00:13:02 +02:00
Michal Kváček 77a65b71a2 FIX: remove duplicated CSS rules 2016-09-29 00:11:40 +02:00
Michal Kváček 5f1cf06e36 FEATURE: add template for contact 2016-09-28 23:53:43 +02:00
Michal Kváček b734c3de18 FEATURE: add 'load more references' button into reference list 2016-09-28 23:27:59 +02:00
Michal Kváček 808bb0eb86 FEATURE: add template for reference detail 2016-09-28 23:07:34 +02:00
Michal Kváček 682f3b75bf FEATURE: add binarity template - currently only homepage 2016-09-28 22:12:58 +02:00
Michal Kváček 5b9b5c0d38 FIX: fix template path registrator 2016-09-28 00:14:18 +02:00
Michal Kváček 3a0a132701 FEATURE: add tag to homepage in overview 2016-09-27 23:39:44 +02:00
Michal Kváček 60c3582947 FEATURE: add filter to action log 2016-09-27 23:24:03 +02:00
Michal Kváček 9039334138 FEATURE: add widgets for assigning into area into edit form 2016-09-27 23:13:21 +02:00
Michal Kváček 5ee403ab28 FEATURE: hide language selection when only one language is installed 2016-09-27 23:05:09 +02:00
Michal Kváček fdf44e8b4a Merge branch 'dev' into doucovanineratovice.cz 2016-09-27 22:52:57 +02:00
Michal Kváček 91cdbec3af FIX: fix template install and other minor bugs 2016-09-27 22:52:55 +02:00
Michal Kváček 45354a3192 FEATURE: move installing widget into base template 2016-09-27 22:52:40 +02:00
Michal Kváček 846cfef1b8 FEATURE: add reset() method to CurrentTemplate helper 2016-09-27 22:27:53 +02:00
Michal Kváček 80dba6d9b7 FEATURE: add missing czech translations 2016-09-27 22:10:33 +02:00
Michal Kváček bf615f8494 FIX: fix contact e-mail saving in contact form 2016-09-27 22:08:24 +02:00
Michal Kváček 4c67d442d6 FIX: fix searching in name and overflowin of no-data message 2016-09-27 22:04:09 +02:00
Michal Kváček 36615aac21 FEATURE: add missing translation for actionLog.createUser 2016-09-27 22:00:42 +02:00
Michal Kváček 4e6fc7c074 FEATURE: add translatable titles to static pages and contact form modules 2016-09-27 21:57:25 +02:00
Michal Kváček e0357d0003 FEATURE: fix redirecting after edit to be more logical 2016-09-27 21:48:06 +02:00
Michal Kváček 8533c8cdc6 FEATURE: make template not mandatory in content editor 2016-09-27 21:34:39 +02:00
Michal Kváček bb3d000e5e FEATURE: display page status as tag in overview 2016-09-27 21:31:32 +02:00
Michal Kváček 842b54d879 FEATURE: add missing czech translations 2016-09-26 21:29:51 +02:00
Michal Kváček 256e24c5a4 FIX: fix typo in Blade macro 2016-09-26 21:01:05 +02:00
Michal Kváček 07df49c481 FEATURE: use thumbnails in content overview and Appearance tab 2016-09-26 20:58:59 +02:00
Michal Kváček a11a29de19 Merge branch 'doucovanineratovice.cz' into dev 2016-09-26 16:54:34 +02:00
Michal Kváček 044eb7e532 FIX: fix order of pages on homepage 2016-09-26 16:54:27 +02:00
Michal Kváček 7f93a5035c FIX: register also /resources/views/visitor 2016-09-26 16:33:43 +02:00
Michal Kváček 358027a8e0 FIX: fix duplicate :: in template names 2016-09-26 16:31:49 +02:00
Michal Kváček 98fe43e12c FIX: hopefully fix broken foreign keys management in migrations 2016-09-26 16:20:22 +02:00
Michal Kváček c096a30b81 Merge branch 'dev' into doucovanineratovice.cz 2016-09-26 15:36:07 +02:00
Michal Kváček 02157f332e FIX: remove on update current_timestamp from content column updated_at 2016-09-26 15:29:49 +02:00
Michal Kváček cd28625309 FEATURE: make thumbnails from uploaded image 2016-09-26 15:21:30 +02:00
Michal Kváček 6868af609f FIX: fix removing image after resaving page 2016-09-26 14:20:06 +02:00
Michal Kváček 445f369ff2 FEATURE: add ViewerJS to preview pdf and odf files in file manager 2016-09-26 12:17:53 +02:00
Michal Kváček 2a1ffb4259 FIX: fix page colors 2016-09-26 11:38:29 +02:00
Michal Kváček 4876cb631e FEATURE: make file overview nicer 2016-09-25 17:33:58 +02:00
Michal Kváček 4c35d95a73 FEATURE: simplify routes 2016-09-25 13:48:12 +02:00
Michal Kváček 8f4e6268a4 FEATURE: move widget and template dir installation into middleware, optimize middleware groups 2016-09-25 12:42:26 +02:00
Michal Kváček d7b60690b2 FEATURE: finish template 2016-09-25 02:52:20 +02:00
Michal Kváček 4de93f9fd9 FEATURE: add basics of template 2016-09-25 02:02:59 +02:00
Michal Kváček f26c384257 Merge branch 'template_support' into doucovanineratovice.cz 2016-09-25 02:01:43 +02:00
Michal Kváček 78213e6f41 Merge branch 'dev' into template_support 2016-09-25 02:01:31 +02:00
Michal Kváček a188c707d8 FEATURE: ignore errors on pages during rendering, display error message for logged user 2016-09-25 02:01:24 +02:00
Michal Kváček ff4585327e FEATURE: add helper function asset_path() 2016-09-25 02:00:50 +02:00
Michal Kváček fa1d302ea6 Merge branch 'dev' into doucovanineratovice.cz 2016-09-25 02:00:18 +02:00
Michal Kváček 52394c6289 FEATURE: add widget association in new admin layout - hopefully last try of doing this 2016-09-25 01:57:45 +02:00
Michal Kváček 76fa76a5af Merge branch 'template_support' into dev 2016-09-25 01:37:24 +02:00
Michal Kváček d6a441cb96 FEATURE: add template_id and module_id into in WidgetType model 2016-09-25 01:36:18 +02:00
Michal Kváček 85bbc384a7 FEATURE: add getJson method to Settings helper 2016-09-25 01:35:52 +02:00
Michal Kváček 80105c857e FEATURE: extend registering widgets by setting template and module ID 2016-09-25 01:35:39 +02:00
Michal Kváček 09151e97d1 FEATURE: prepare widget for displaying menu on onepage templates 2016-09-25 01:35:03 +02:00
Michal Kváček 9802161af1 FIX: add deletable fields into in widgets and widget area models 2016-09-25 00:21:18 +02:00
Michal Kváček 00d7bd562c FEATURE: make user id not mandatory in widgets table 2016-09-25 00:19:20 +02:00
Michal Kváček 124ad2f061 Merge branch 'template_support' into doucovanineratovice.cz 2016-09-24 23:00:57 +02:00
Michal Kváček a37767c2e8 Merge branch 'dev' into template_support 2016-09-24 23:00:44 +02:00
Michal Kváček d5950d9cd7 FEATURE: add removing settings into uninstall method for template 2016-09-24 20:29:07 +02:00
Michal Kváček 82283e65be FEATURE: add translations for comment logged events 2016-09-24 20:19:21 +02:00
Michal Kváček 2f760fd56d FEATURE: minor UI tweaks in template settings + add events into OnePage base template 2016-09-24 19:48:39 +02:00
Michal Kváček 939610cf9d FIX: fix homepage settings for one-page template when no template is set 2016-09-24 03:23:35 +02:00
Michal Kváček 6d107d0881 FEATURE: add customizable settings for create/edit/overview of content pages 2016-09-24 02:55:51 +02:00
Michal Kváček b7434d0a0b FIX: fix translating submodules 2016-09-24 02:55:01 +02:00
Michal Kváček 55ef5e4af1 FEATURE: add testing template files into testing template Jednostrankovka 2016-09-24 02:10:10 +02:00
Michal Kváček dc289723a9 FIX: fix contact form edit 2016-09-24 02:09:07 +02:00
Michal Kváček b15bbae037 FEATURE: add base support for displaying multiple pages on one-page template 2016-09-24 01:53:43 +02:00
Michal Kváček 7cd084e621 FIX: fix setting homepage pages - omitted file for one of previous commits 2016-09-24 00:00:30 +02:00
Michal Kváček 0857b4efd9 FEATURE: add template parameters into rendering page in visitor area 2016-09-23 23:59:39 +02:00
Michal Kváček 0c01b35188 FEATURE: make snippet for bootstrap cards 2016-09-23 23:58:59 +02:00
Michal Kváček 9d33ae6d49 FEATURE: move default Handler::render() into parent class 2016-09-23 23:57:23 +02:00
Michal Kváček a9aaf797cd FEATURE: add few czech translations 2016-09-23 23:41:22 +02:00
Michal Kváček 4b6f0b14ad FEATURE: make shortcut for getting currently installed template 2016-09-23 23:28:04 +02:00
Michal Kváček a111b67c53 DOC: add link to improvement 2016-09-23 22:55:18 +02:00
Michal Kváček 91ef424bd0 FEATURE: extend translation command for translating also templates 2016-09-23 22:54:46 +02:00
Michal Kváček 7589051216 FEATURE: add homepage settings for base of one page pages 2016-09-23 22:27:58 +02:00
Michal Kváček fbb59277b9 FEATURE: add events to comments 2016-09-23 00:41:38 +02:00
Michal Kváček 0d8e927b08 FIX: fix localization in categories 2016-09-23 00:08:53 +02:00
Michal Kváček 72f7b9a047 FIX: fix localization of comments 2016-09-23 00:02:25 +02:00
Michal Kváček 139373145a FEATURE: split controllers/admin into more smaller directories 2016-09-22 23:35:53 +02:00
Michal Kváček 0357417163 FEATURE: add soft deletes to users 2016-09-22 22:13:15 +02:00
Michal Kváček d5d4216a80 FEATURE: add soft deletes to content pages 2016-09-22 21:57:45 +02:00
Michal Kváček b982831fbf FEATURE: make settings accessible only using helper class/function 2016-09-22 21:09:48 +02:00
Peter Hrdlica 75c4a4a649 #1573: added full slovakian localization, some fixes in czech one. 2016-09-21 15:59:35 +02:00
Michal Kváček fb977ce1b9 FEATURE: few mostly minor UI tweaks in admin 2016-09-21 01:15:32 +02:00
Michal Kváček 7d051d1f6a FEATURE: make templates not-editable 2016-09-21 00:58:03 +02:00
Michal Kváček f5e1e24df8 FIX: minor fixed in chmod 2016-09-20 23:44:11 +02:00
Michal Kváček 5ddb31b57b FIX: do not prevent running ModuleManager in CLI mode 2016-09-20 23:37:32 +02:00
Michal Kváček 01a28fc65a FIX: minor fixes in installation 2016-09-20 23:25:45 +02:00
Michal Kváček 67cd7fb36f FEATURE: make installation working again 2016-09-20 23:06:42 +02:00
Michal Kváček 5f8dab0068 FIX: remove Article module from template 2016-09-20 20:59:47 +02:00
Michal Kváček 40949eaa90 FIX: fix update from migrations 2016-09-20 20:58:52 +02:00
Michal Kváček f25ef4ab1b Merge branch 'template_support' into dev 2016-09-20 20:17:06 +02:00
Michal Kváček f3873ed61c FEATURE: add functionality for modifying content page on template level 2016-09-20 20:14:02 +02:00
Michal Kváček bbffbd5616 Merge branch 'module_blog' into dev 2016-09-20 15:34:44 +02:00
Michal Kváček d9feb92612 FEATURE: add template into page rendering 2016-09-20 15:25:18 +02:00
Michal Kváček 5662dc7cf7 FIX: fix determination of invalid template 2016-09-20 15:23:07 +02:00
Michal Kváček 39279a1633 FEATURE: delete all template paths from template_path table on template uninstall 2016-09-20 14:54:43 +02:00
Michal Kváček e8b91db6f2 FEATURE: add template check on content overview 2016-09-20 14:47:38 +02:00
Michal Kváček df9ff7b259 REFACTORING: reformatt code 2016-09-20 14:30:11 +02:00
Michal Kváček a0f3409f82 FEATURE: make widgets not deletable 2016-09-20 14:24:40 +02:00
Michal Kváček 694724945d FEATURE: make widget areas not deletable 2016-09-20 14:16:33 +02:00
Michal Kváček 5cbe19064b FEATURE: delete commented-out sections with template registration 2016-09-20 12:09:37 +02:00
Michal Kváček 4ac084139c DELETE: delete old admin templates 2016-09-20 11:57:17 +02:00
Michal Kváček f92c1d0089 FEATURE: simplify template handler - move un/install and registerAdminMenu into base class 2016-09-20 11:54:23 +02:00
Michal Kváček bcd19058ea DELETE: remove views/visitor/cwbs -- will be converted into template 2016-09-20 11:51:16 +02:00
Michal Kváček d43073a011 FEATURE: add blade template registration into templates 2016-09-20 11:50:41 +02:00
Michal Kváček 8bd30d0301 FEATURE: add number of views in page 2016-09-20 01:04:23 +02:00
Michal Kváček f087da1b43 FEATURE: prepare for installing templates 2016-09-20 00:46:32 +02:00
Michal Kváček 7a681fd7f7 FEATURE: remove modularAdmin logo from login and layout 2016-09-19 20:43:23 +02:00
Michal Kváček 2e483c7598 FEATURE: add html template 2016-09-19 20:35:59 +02:00
Michal Kváček f98065e849 FEATURE: delete unnecessary templates 2016-09-17 19:47:46 +02:00
Michal Kváček 48294842bf FEATURE: rewrite widgets management into new layout 2016-09-15 23:52:01 +02:00
Michal Kváček 65e9ca1c32 FEATURE: minor change in icon (remove->trash) 2016-09-14 20:29:25 +02:00
Peter Hrdlica 233f2007b0 Initial Dobroty z pece 2016-09-14 09:34:57 +02:00
Michal Kváček 5b29082ca6 Merge branch 'dev' into module_blog 2016-09-13 03:53:29 +02:00
Michal Kváček 48c0abbe89 FEATURE: add few czech translations 2016-09-13 03:52:44 +02:00
Michal Kváček 8476d5fbd7 FEATURE: add working confirm dialog 2016-09-13 03:51:50 +02:00
Michal Kváček ea5aa8d873 FEATURE: make content pages list responsive 2016-09-13 03:51:34 +02:00
Michal Kváček 3229a84ee5 FEATURE: make user list vertical 2016-09-13 02:57:42 +02:00
Michal Kváček f8127f3ed6 FEATURE: add article list -- advanced options 2016-09-07 02:21:30 +02:00
Michal Kváček 44677aea78 FEATURE: add basic article list 2016-09-07 00:47:57 +02:00
Michal Kváček 5b7b81ff4d FIX: remove echo from TemplateRegistrator 2016-09-07 00:28:03 +02:00
Michal Kváček 68d37e87f6 FIX: fix module installator to skip Database directory in subdmodules 2016-09-07 00:06:44 +02:00
Michal Kváček 51d6850cd6 FEATURE: add selecting comments into template in visitors area 2016-09-06 12:47:54 +02:00
Michal Kváček 8f66a96ec0 FEATURE: add comments management 2016-09-05 16:05:14 +02:00
Michal Kváček 9ce9f62a45 FEATURE: add creating comments 2016-09-05 12:50:04 +02:00
Michal Kváček a33023a4aa FEATURE: remove not used templates 2016-09-05 12:49:44 +02:00
Michal Kváček d2d0a48e9c FEATURE: add czech translation to article submodule 2016-09-05 00:10:46 +02:00
Michal Kváček e55672bdcd FEATURE: support submodules in translation helper command 2016-09-05 00:10:31 +02:00
Michal Kváček 5ef2630810 FEATURE: make title in contents overview translatable and modifiable by module 2016-09-05 00:00:52 +02:00
Michal Kváček 8c4b1ad69b FIX: fix saving title photo in content pages 2016-09-04 23:33:56 +02:00
Michal Kváček 59dede6049 FEATURE: add comments into articles 2016-09-04 23:20:07 +02:00
Michal Kváček f304ef0141 FEATURE: add nice checkbox into settings 2016-09-04 21:47:22 +02:00
Michal Kváček 3cfadc380d FIX: fix default settings for language 2016-09-04 21:41:22 +02:00
Michal Kváček b73b575b71 FEATURE: make user management nicer 2016-09-04 21:31:56 +02:00
Michal Kváček 9b64b54d7b FEATURE: update project dependencies 2016-09-04 05:04:26 +02:00
Michal Kváček e826b474b8 FEATURE: tweak a little bit footer 2016-09-04 04:23:49 +02:00
Michal Kváček 9d63c8d8b0 FEATURE: add link to index page and move template management into system submenu 2016-09-04 04:16:46 +02:00
Michal Kváček aa4161e451 FEATURE: add search 2016-09-04 03:56:35 +02:00
Michal Kváček 9029f14523 FEATURE: add file detail/edit form in file manager 2016-09-04 03:40:45 +02:00
Michal Kváček 98c8313475 FIX: fix active state in sidebar menu 2016-09-04 03:40:32 +02:00
Michal Kváček 8351137206 FEATURE: add settings 2016-09-04 03:31:07 +02:00
Michal Kváček 79ec8e1d2e FEATURE: add action log in bootstrap 2016-09-04 03:08:58 +02:00
Michal Kváček 418d9ac4ca FEATURE: style templates management 2016-09-04 02:42:55 +02:00
Michal Kváček d0be4d1e49 FEATURE: style categories 2016-09-04 02:28:06 +02:00
Michal Kváček 4cfd93161b FIX: fix rendering dividers in submenus 2016-09-04 02:21:58 +02:00
Michal Kváček 05efb6b9f2 FEATURE: add divider before list of all content pages 2016-09-04 02:21:44 +02:00
Michal Kváček 66caf7ce05 FEATURE: ugly commit - rewritten widgets, menu made more compact, added profile menu, few bugfixes etc. Sorry.. 2016-09-04 01:52:17 +02:00
Michal Kváček 9c02c63704 FEATURE: style user management 2016-08-28 00:24:38 +02:00
Michal Kváček 8458622e32 FEATURE: redirect to last page when session has expired 2016-08-25 01:03:35 +02:00
Michal Kváček f1121107c5 FEATURE: add users overview 2016-08-23 23:36:54 +02:00
Michal Kváček d954743e8b FIX: fix route to user edit 2016-08-23 23:36:36 +02:00
Michal Kváček 0a6528a845 FEATURE: style file manager 2016-08-23 23:07:44 +02:00
Michal Kváček f744ca81ca FEATURE: add login form title 2016-08-23 23:06:52 +02:00
Michal Kváček 3a82696d62 FEATURE: rewrite contact form admin into new theme 2016-08-23 00:34:01 +02:00
Michal Kváček cd6f1b4cfa FEATURE: style buttons in content edit 2016-08-23 00:14:17 +02:00
Michal Kváček 28478ba165 FEATURE: add templates for content history 2016-08-23 00:14:06 +02:00
Michal Kváček d746d5b52b FEATURE: add content page overview 2016-08-22 23:29:04 +02:00
Michal Kváček f6fd924cbd FEATURE #1435: few smaller UI tweaks in creating new content page 2016-08-19 13:20:16 +02:00
Michal Kváček 0d1d692c45 Merge branch 'module_blog' into admin_theme 2016-08-19 13:19:14 +02:00
Michal Kváček 6f6497d540 FEATURE #1435: add base of content overview and creating new content 2016-08-18 13:21:35 +02:00
Michal Kváček 7889548a7e FEATURE #1435: small changes in layout 2016-08-18 13:21:05 +02:00
Michal Kváček fc1141184c FEATURE #1435: add login and layout of new admin theme 2016-08-16 16:07:14 +02:00
Michal Kváček 0993d812cb FIX: fix routes to writing new blog and blog post overview 2016-08-16 13:20:30 +02:00
Michal Kváček be81834aad FEATURE: add stub of module for comments 2016-08-16 13:20:07 +02:00
Michal Kváček e389760204 Merge branch 'dev' into module_blog 2016-08-16 00:53:35 +02:00
Michal Kváček 6f799f00bb FEATURE: add support for writing blog posts 2016-08-16 00:52:09 +02:00
Michal Kváček debe80a314 FEATURE: implement loadExtraData as empty function in Handler 2016-08-16 00:51:17 +02:00
Michal Kváček af3db57b29 FEATURE: add translation for history.columnCategory 2016-08-16 00:50:37 +02:00
Michal Kváček 8edde44c0d FIX: fix saving new content without category 2016-08-16 00:50:00 +02:00
Michal Kváček cd369c327f FEATURE: add templates to blog/article 2016-08-15 23:16:06 +02:00
Michal Kváček 206e5201b8 FIX: reset namespace and module ID after each registered path 2016-08-15 22:24:23 +02:00
Michal Kváček aa462c2454 FIX: make artisan install-module really work with submodules 2016-08-15 21:39:18 +02:00
Michal Kváček ae1123ba39 FEATURE: add blog module stub 2016-08-15 20:49:12 +02:00
Michal Kváček bd06797c24 FEATURE: do not use Module::enabled() in registering admin menu 2016-08-15 20:48:17 +02:00
Michal Kváček 5b79fd4323 FIX: ignore enumeration duplicities with null as key 2016-08-15 20:47:52 +02:00
Michal Kváček 53d532da82 FEATURE: make artisan command for installing work with submodules 2016-08-15 20:47:34 +02:00
Michal Kváček fa21c407b4 FEATURE: add support for submodules 2016-08-15 20:46:54 +02:00
Michal Kváček d54f160d6a FIX: fix showing/hiding categories when categories module is not enabled 2016-08-14 17:13:20 +02:00
Michal Kváček 5df5fa8480 FIX: fix module install - manages_content field 2016-08-13 20:35:57 +02:00
Michal Kváček ddd3530993 Merge branch 'module_categories' into dev 2016-08-13 19:03:16 +02:00
Michal Kváček befb95a4ac FEATURE: add relationship methods to categories and content 2016-08-13 19:02:58 +02:00
Michal Kváček dc185bdc2e FEATURE: log not writable module.json in modules 2016-08-13 18:59:14 +02:00
Michal Kváček 42967e72cd Merge branch 'module_categories' into dev 2016-08-13 17:55:23 +02:00
Michal Kváček 85e10b5631 Merge branch 'module_static_pages' into dev 2016-08-13 17:55:16 +02:00
Michal Kváček 54e5927bb1 FEATURE: add support for categories into content save/edit 2016-08-13 17:48:44 +02:00
Michal Kváček 9517d07692 REFACTORING: delete not used files 2016-08-13 16:58:37 +02:00
Michal Kváček 93abfd2485 REFATORING: delete not used files 2016-08-13 16:57:16 +02:00
Michal Kváček 5aec27478a FEATURE: add translations and more friendly look to categories 2016-08-13 16:51:53 +02:00
Michal Kváček 9f955d4544 FEATURE: add category edit and overview 2016-08-11 23:47:24 +02:00
Michal Kváček 597d161a38 FEATURE: add tree view into creating new category 2016-08-11 00:49:05 +02:00
Michal Kváček 48d301330f FEATURE: add basic form for adding new category 2016-08-11 00:27:22 +02:00
Michal Kváček 03f0d71dbb FEATURE: add structure for categories 2016-08-11 00:26:52 +02:00
Michal Kváček 778c87ffa3 FEATURE: install franzose/closure-tables 2016-08-11 00:26:06 +02:00
Michal Kváček ed0b35f9d7 FEATURE: initial commit of module for categories 2016-08-09 01:14:02 +02:00
Michal Kváček cfc3a148e7 FEATURE: prepare handlers for categories 2016-08-09 01:13:44 +02:00
Michal Kváček a698d7a7db FEATURE: add marks for modules 2016-08-09 01:04:03 +02:00
Michal Kváček ba107184e1 FIX: fix missing FK in contents->templates 2016-08-08 23:00:24 +02:00
Michal Kváček 7abd60e785 FEATURE: change collation of all non-utf8_unicode_ci tables 2016-08-01 23:19:13 +02:00
Michal Kváček 0d5e6d4133 FEATURE: add possibilityy to upload and assign files to content pages 2016-07-29 01:22:49 +02:00
Michal Kváček 790cc772a9 FIX: fix missing settings in login form 2016-07-28 15:14:43 +02:00
Michal Kváček 0d8148f22d FEATURE: allow multiple uploads 2016-07-26 15:31:01 +02:00
Michal Kváček bef37a5cce FIX: fix saving content pages - typo in save method 2016-07-26 14:39:48 +02:00
Michal Kváček be4a136476 FEATURE: add lock to URL 2016-07-26 14:39:27 +02:00
Michal Kváček 5fc4393729 FEATURE: add rest of missing czech translations 2016-07-26 12:55:06 +02:00
Michal Kváček 097d76de93 FEATURE: first few czech translations 2016-07-24 00:12:17 +02:00
Michal Kváček 0076cfba2e FIX: use LaravelLocalizationServiceProvider in CLI, but do not throw exceptions when table languages is missing 2016-07-23 23:54:57 +02:00
Michal Kváček 6b24c8a461 FIX: do not use localization service provider in CLI 2016-07-23 22:28:54 +02:00
Michal Kváček 3733d24da8 Merge branch 'multilanguage' into dev 2016-07-23 21:56:30 +02:00
Michal Kváček b2b8084cfe DOC: add few comments 2016-07-23 21:51:59 +02:00
Michal Kváček ab3d8eab41 FEATURE: make settings translatable 2016-07-23 21:47:20 +02:00
Michal Kváček b89941b909 FIX: fix saving and displaying menu with non-existing pages 2016-07-22 16:30:20 +02:00
Michal Kváček bce98e6eaf FEATURE: Add language into widgets 2016-07-22 15:30:03 +02:00
Michal Kváček f90aee4108 FEATURE: add language to content pages 2016-07-22 14:55:51 +02:00
Michal Kváček 2189bbed5e FEATURE: language switch works - changes translations 2016-07-22 11:57:13 +02:00
Michal Kváček ebc7330717 FEATURE: show diff as escaped HTML 2016-07-22 01:01:38 +02:00
Michal Kváček bab897f01e FEATURE: add language selector in admin 2016-07-22 00:44:40 +02:00
Michal Kváček fb2c705ac4 FEATURE: add service provider for registering languages 2016-07-22 00:44:27 +02:00
Michal Kváček 6021f1ea9a FEATURE: add fields for languages 2016-07-22 00:43:52 +02:00
Michal Kváček 181e1fb721 FEATURE: create directory for translations if not exist 2016-07-22 00:42:45 +02:00
Michal Kváček 5b54f6d45f FEATURE: install laravel-localization 2016-07-21 23:47:19 +02:00
Michal Kváček 15a29de894 UPDATE: update dependencies 2016-07-21 23:22:26 +02:00
Michal Kváček db912c4c91 FEATURE: add language table 2016-07-21 23:11:05 +02:00
Michal Kváček 949b1f7c61 FEATURE: add translation command into Artisan 2016-07-21 22:46:48 +02:00
731 changed files with 210218 additions and 8790 deletions
+5 -6
View File
@@ -1,8 +1,8 @@
APP_ENV=testing
APP_DEBUG=true
APP_KEY=ZKZAzM23wQ6BPji6zffBjaTzZ3yW7zKQ
APP_KEY=
APP_ENV=
APP_DEBUG=
DB_HOST=localhost
DB_HOST=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
@@ -16,5 +16,4 @@ MAIL_PASSWORD=
SITE_URL=/
UPLOAD_URL=/public/uploads
THUMBNAILS_URL=/uploads/thumbnails
THEME=
THUMBNAILS_URL=/uploads/thumbnails
+3 -2
View File
@@ -1,8 +1,9 @@
# published files from modules
/resources/views/modules
/public/modules
/resources/views/vendor
/public/assets
/resources/views/modules
/resources/views/visitor
/resources/views/vendor
# directories with custom templates
**/views/**/custom/*
+62
View File
@@ -0,0 +1,62 @@
<?php
namespace App\Console\Commands;
use App\Models\Language;
use Illuminate\Console\Command;
class AddLanguage extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'language:add {code} {translation} {native} {script?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Insert new language into database';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$code = $this->argument('code');
$translation = $this->argument('translation');
$native = $this->argument('native');
$script = $this->argument('script');
// check if language does not exist
$exist = Language::find($code);
if ($exist) {
$this->error('Language ' . $code . ' already exists!');
return;
}
Language::create([
'code' => $code,
'name' => $translation,
'native' => $native,
'script' => $script ? $script : 'Latn'
]);
$this->line('Successfully installed.');
}
}
+74 -17
View File
@@ -4,6 +4,8 @@ namespace App\Console\Commands;
use App\Models\Module;
use Illuminate\Console\Command;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Support\Facades\File;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
@@ -14,7 +16,7 @@ class InstallModule extends Command
*
* @var string
*/
protected $signature = 'install-module {name}';
protected $signature = 'install-module {name} {parentModuleId?}';
/**
* The console command description.
*
@@ -22,6 +24,7 @@ class InstallModule extends Command
*/
protected $description = 'Custom installation of CMS module. Name given as directory name in /modules.';
protected $moduleName;
protected $parentModuleId;
protected $modulesPath;
/**
@@ -37,12 +40,11 @@ class InstallModule extends Command
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->moduleName = $name = $this->argument('name');
$this->parentModuleId = $this->argument('parentModuleId');
// invalid module name provided
if (!is_dir($this->modulesPath . DIRECTORY_SEPARATOR . $name)) {
@@ -52,6 +54,9 @@ class InstallModule extends Command
// get config
$config = $this->loadConfig();
if (empty($config))
return;
// check if it is valid
$this->checkMandatoryFields($config);
@@ -67,11 +72,28 @@ class InstallModule extends Command
* yet.
*
* @return array
* @throws FileNotFoundException
*/
private function loadConfig()
{
$basePath = $this->modulesPath . DIRECTORY_SEPARATOR . $this->moduleName . DIRECTORY_SEPARATOR;
$path = $basePath . 'Config' . DIRECTORY_SEPARATOR . 'config.php';
if (basename($basePath) == 'Database')
return [];
// check if module has Config/config.php file
if (!file_exists($path)) {
$path = $basePath . 'info.php';
// does module has info.php? If not, throw error, because we have no info about this module
if (!file_exists($path)) {
throw new FileNotFoundException('Missing config file. Create /Config/config.php or /info.php (for module with submodules) in ' . $basePath);
}
}
// 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');
$config = @include($path);
return $config;
}
@@ -83,7 +105,7 @@ class InstallModule extends Command
*/
private function checkMandatoryFields($config)
{
$fields = ['providers', 'handler', 'name', 'files', 'alias'];
$fields = ['name'];
foreach ($fields as $field) {
if (!isset($config[$field])) {
throw new MissingMandatoryParametersException('Missing *' . $field . '* in config file! Cannot install ' . $this->moduleName);
@@ -107,25 +129,60 @@ class InstallModule extends Command
{
$name = isset($config['translatedName']) ? $config['translatedName'] : $config['name'];
$description = isset($config['translatedDescription']) ? $config['translatedDescription'] : null;
$alias = isset($config['alias']) ? $config['alias'] : null;
$handler = isset($config['handler']) ? $config['handler'] : null;
$providers = isset($config['providers']) ? $config['providers'] : [];
// check if module is not installed yet
$exists = Module::where('handler', $config['handler'])
->exists();
$module = Module::where('name', $name);
if ($exists) {
if ($handler) {
$module = $module->where('handler', $handler);
}
$module = $module->first();
if ($module && (!isset($config['hasSubmodules']) || !$config['hasSubmodules'])) {
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']
if (!$module) {
// insert module into database
$settings = [
'staticName' => $this->moduleName,
'providers' => $providers,
'aliases' => isset($config['aliases']) ? $config['aliases'] : [],
'order' => isset($config['order']) ? $config['order'] : 0,
'files' => isset($config['files']) ? $config['files'] : []
];
];
$module = Module::install($name, $config['alias'], $description, $config['handler'], $settings);
$module = Module::install($name, $alias, $description, $handler, $this->parentModuleId, $settings);
}
return $module;
// try to install submodules
if (isset($config['hasSubmodules']) && $config['hasSubmodules']) {
$this->installSubmodules($this->modulesPath . DIRECTORY_SEPARATOR . $this->moduleName, $module);
}
}
/**
* Crawl all subdirectories in module and try to install submodules
*
* @param $path string path to module base directory
* @param $parentModule
*/
private function installSubmodules($path, Module $parentModule)
{
$submodules = File::directories($path);
foreach ($submodules as $submodulePath) {
$submodule = str_replace($this->modulesPath . DIRECTORY_SEPARATOR, '', $submodulePath);
try {
$this->call('install-module', ['name' => $submodule, 'parentModuleId' => $parentModule->id]);
} catch (\Exception $e) {
$this->error($e->getMessage());
}
}
}
}
@@ -0,0 +1,33 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class PublishTemplateResources extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'template:publish';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Publish assets and views for currently set template';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->call('vendor:publish', ['--tag' => 'module-views', '--force' => true]);
$this->call('vendor:publish', ['--tag' => 'public-assets', '--force' => true]);
}
}
+73
View File
@@ -0,0 +1,73 @@
<?php
namespace App\Console\Commands;
use App\Models\Module;
use Illuminate\Console\Command;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class SetTemplate extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'template:set {template} {publish?}';
/**
* The console command description.
* @var string
*/
protected $description = 'Install template';
/**
* Execute the console command.
* @return mixed
*/
public function handle()
{
$template = $this->argument('template');
$publish = $this->argument('publish') !== 'no-publish';
$templatePath = app_path('../templates/' . $template);
if (!is_dir($templatePath) || !file_exists($templatePath . '/config.php')) {
throw new NotFoundHttpException('Invalid template ' . $template . '!');
}
// try to find currently installed template
$current = Module::where('is_template', true)
->first();
// install template
$config = @include $templatePath . '/config.php';
$config['staticName'] = $template;
if ($current) {
$info = json_decode($current->module_settings);
$this->line('Template is already installed. Currently using template ' . trans($current->name) . ' located in /templates/' . $info->staticName . '.');
$confirm = $this->confirm('Uninstall it and install *' . trans($config['name']) . '*? All data associated with installed template will be lost!');
if ($confirm) {
$this->line('Uninstalling ' . $current->name . '.');
$current->uninstall();
} else {
$this->line('Aborting installation.');
return;
}
}
try {
Module::install($config['name'], $config['alias'], $config['description'], $config['handler'], false, $config);
} catch (\Exception $e) {
$this->error('Cannot install template ' . $template . '. Message: ' . $e->getMessage());
return;
}
// theme written
$this->line('Template successfully set up.');
// run again artisan for publishing resources
// it cannot be done using $this->call, because we need to load different template into service providers
exec('php artisan vendor:publish');
}
}
-70
View File
@@ -1,70 +0,0 @@
<?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');
}
}
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
class TranslateAll extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'translate:all';
/**
* The console command description.
* @var string
*/
protected $description = 'Checks for missing translations in all modules.';
/**
* Create a new command instance.
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle()
{
$this->call('translate:dir', ['dir' => 'resources/lang']);
$this->crawlDirectory('modules');
$this->crawlDirectory('templates', ['templates/Base']);
$this->crawlDirectory('templates/Base');
}
/**
* Crawl directories and search for directories with translations
*
* @param $directory
* @param array $ignoredDirectories
*/
protected function crawlDirectory($directory, $ignoredDirectories = [])
{
$directories = File::directories($directory);
foreach ($directories as $dir) {
if (in_array($dir, $ignoredDirectories)) {
continue;
}
$this->call('translate:dir', ['dir' => $dir . '/Resources/lang']);
}
}
}
+216
View File
@@ -0,0 +1,216 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
class TranslateDirectory extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'translate:dir {dir}';
/**
* The console command description.
* @var string
*/
protected $description = 'Checks for missing translations in given directory.';
/**
* @var array All translations
*/
protected $translations = [];
/**
* Execute the console command.
*/
public function handle()
{
$dir = rtrim($this->argument('dir'), '/');
$defaultLocales = config('app.fallback_locale');
$currentLocales = config('app.locale');
$defaultLocalesDir = base_path($dir . '/' . $defaultLocales);
$currentLocalesDir = base_path($dir . '/' . $currentLocales);
if (!is_dir($defaultLocalesDir)) {
// this is the place for checking for submodules
$modulePath = dirname(dirname($dir));
// does exist directory with translations?
if (is_dir(base_path($modulePath . '/Resources/lang')) || file_exists(base_path($modulePath.DIRECTORY_SEPARATOR.'info.php'))) {
$modules = File::directories($modulePath);
foreach ($modules as $module) {
$this->call('translate:dir', ['dir' => $module . '/Resources/lang']);
}
}
return;
}
if (!is_dir($currentLocalesDir)) {
File::makeDirectory($currentLocalesDir);
}
$this->compareTranslationsInDirectory($defaultLocalesDir, $currentLocalesDir);
}
/**
* Crawl given defaul directory and compare all files in default and current directory.
*
* @param $defaultDir string path to directory with default (fallback) locales
* @param $currentDir string path to directory with currently selected localse
*/
private function compareTranslationsInDirectory($defaultDir, $currentDir)
{
$files = File::files($defaultDir);
foreach ($files as $file) {
if (!Str::endsWith($file, '.php')) {
continue;
}
$fileName = basename($file);
$default = include($file);
$checked = file_exists($currentDir . '/' . $fileName) ? include $currentDir . '/' . $fileName : [];
$this->translations = &$checked;
$this->checkForMissingTranslations($default, $checked, $currentDir, $fileName);
}
// iterate over directories
$this->crawlSubdirectories($defaultDir, $currentDir);
}
/**
* Check translations and ask for missing ones.
*
* @param $default
* @param $checked
* @param $currentLocalesDir
* @param $fileName
*/
private function checkForMissingTranslations($default, &$checked, $currentLocalesDir, $fileName)
{
foreach ($default as $key => $translation) {
if (!isset($checked[$key])) {
// translate only plain text fields
if (is_array($default[$key])) {
if (!isset($checked[$key])) {
$checked[$key] = [];
}
$this->checkForMissingTranslations($default[$key], $checked[$key], $currentLocalesDir, $fileName);
continue;
}
$this->info($fileName . ':' . $key);
$this->line($translation);
$newTranslation = $this->ask('Translate');
$checked[$key] = $newTranslation;
$this->saveTranslation($currentLocalesDir, $fileName);
}
}
}
/**
* Create new/reset file and fill it with translations
*
* @param $checked
* @param $dir
* @param $fileName
*/
private function saveTranslation($dir, $fileName)
{
$file = $dir . '/' . $fileName;
$this->resetFile($file);
$this->writeRow('<?php', null, $file, false);
$this->writeRow('return [', null, $file, false);
// write real translation data
$this->writeTranslations($this->translations, $dir, $fileName);
$this->writeRow('];', '', $file, false);
}
/**
* Write translation as PHP array
*
* @param $checked
* @param $dir
* @param $fileName
*/
private function writeTranslations($checked, $dir, $fileName)
{
$file = $dir . '/' . $fileName;
ksort($checked);
foreach ($checked as $key => $value) {
if (is_array($value)) {
$this->writeRow($key, '[', $file, false);
$this->writeTranslations($value, $dir, $fileName);
$this->writeRow('],', null, $file, false);
} else {
$this->writeRow($key, $value, $file);
}
}
}
/**
* Resets content of given file
*
* @param $file
*/
private function resetFile($file)
{
file_put_contents($file, '');
}
/**
* Write row with translations
*
* @param $key
* @param $value
* @param $file
* @param bool $arrayItem
*/
private function writeRow($key, $value, $file, $arrayItem = true)
{
if ($value != null) {
if ($arrayItem) {
$value = strpos($value, '"') !== false ? '\'' . $value . '\'' : '"' . $value . '"';
$value .= ",\n";
}
file_put_contents($file, '"' . $key . '" => ' . $value, FILE_APPEND);
} else {
file_put_contents($file, $key . "\n", FILE_APPEND);
}
}
/**
* Crawl subdirectories and compare translations there
*
* @param $defaultDir
* @param $currentDir
*/
private function crawlSubdirectories($defaultDir, $currentDir)
{
$directories = File::directories($defaultDir);
foreach ($directories as $directory) {
$dirname = basename($directory);
if (!is_dir($currentDir . '/' . $dirname)) {
File::makeDirectory($currentDir . '/' . $dirname);
}
$this->compareTranslationsInDirectory($directory, $currentDir . '/' . $dirname);
}
}
}
+6 -2
View File
@@ -2,6 +2,7 @@
namespace App\Console;
use App\Console\Commands\PublishTemplateResources;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -17,9 +18,12 @@ class Kernel extends ConsoleKernel
Commands\ChangePassword::class,
Commands\InstallModule::class,
Commands\InstallAllModules::class,
// Commands\SetupDatabase::class,
Commands\TranslateDirectory::class,
Commands\TranslateAll::class,
Commands\InitDatabaseSchema::class,
Commands\SetTheme::class,
Commands\SetTemplate::class,
Commands\AddLanguage::class,
PublishTemplateResources::class
];
/**
@@ -1,18 +0,0 @@
<?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);
}
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ abstract class BaseEnumeration
public static function push($key, $translation, $overwrite = false)
{
// item exists and we do not want to overwrite items
if (!$overwrite && isset(self::$items[get_called_class()][$key])) {
if (!$overwrite && !is_null($key) && isset(self::$items[get_called_class()][$key])) {
throw new EnumerationExistsException(get_called_class() . ': ' . $key . ' already in ' . $translation);
}
-1
View File
@@ -9,7 +9,6 @@ class ContentStatuses extends BaseEnumeration
{
$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
];
-1
View File
@@ -15,7 +15,6 @@ class UserStates extends BaseEnumeration
public static function init()
{
$items = [
User::STATE_DELETED => 'admin/userManagement.status_' . User::STATE_DELETED,
User::STATE_BLOCKED => 'admin/userManagement.status_' . User::STATE_BLOCKED,
User::STATE_ACTIVE => 'admin/userManagement.status_' . User::STATE_ACTIVE
];
+1 -3
View File
@@ -12,7 +12,6 @@ class DeleteContent extends Event
* @var Content
*/
public $page;
public $revision;
/**
* Create a new event instance.
@@ -20,9 +19,8 @@ class DeleteContent extends Event
* @param Content $page
* @param $revision
*/
public function __construct(Content $page, $revision)
public function __construct(Content $page)
{
$this->page = $page;
$this->revision = $revision;
}
}
+123
View File
@@ -0,0 +1,123 @@
<?php
namespace App\Handlers;
use App\Enumerations\TemplatePathsHumanReadableRootOnly;
use App\Enumerations\WidgetTypes;
use App\Handlers\Contracts\AppHandler;
use App\Handlers\Contracts\BaseModuleHandler;
use App\Models\User;
abstract class BaseHandler implements BaseModuleHandler
{
/**
* 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-fw fa-dashboard']);
/**
* Content pages
*
* Submenus can be registered later
*/
$menu->dropdown(trans('admin/mainMenu.contentPages'), function ($sub) {
$sub->addDivider(9999);
$sub->route('content.overview', trans('admin/mainMenu.contentPageOverview'), [], 10000, ['icon' => 'fa fa-fw fa-list']);
}, 20, ['icon' => 'fa fa-fw fa-database']);
/**
* File manager
*/
$menu->route('upload.overview', trans('admin/mainMenu.fileManager'), [], 40, ['icon' => 'fa fa-fw fa-folder']);
/**
* Widgets and widget areas
*/
$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-fw fa-plus']);
}
$sub->route('widgets.overview', trans('admin/mainMenu.widgetsOverview'), [], 20, ['icon' => 'fa fa-fw 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-fw fa-plus']);
$sub->route('widgetareas.overview', trans('admin/mainMenu.widgetAreaOverview'), [], 2, ['icon' => 'fa fa-fw fa-list']);
}, 50, ['icon' => 'fa fa-fw fa-object-group']);
}, 50, ['icon' => 'fa fa-fw fa-puzzle-piece']);
/**
* Divide system entries and other links in menu
*/
$menu->addDivider(9999);
$menu->dropdown(trans('admin/mainMenu.system'), function ($sub) {
/**
* User management
*/
$sub->dropdown(trans('admin/mainMenu.userManagement'), function ($sub) {
$sub->route('users.new', trans('admin/mainMenu.newUser'), [], 10, ['icon' => 'fa fa-fw fa-user-plus']);
$sub->route('users.overview', trans('admin/mainMenu.usersOverview'), [], 30, ['icon' => 'fa fa-fw fa-users']);
}, 20, ['icon' => 'fa fa-fw fa-users']);
/**
* Templates
*/
$templatePaths = TemplatePathsHumanReadableRootOnly::getWithTranslations();
if (!empty($templatePaths)) {
$sub->dropdown(trans('admin/mainMenu.templates'), function ($sub) use ($templatePaths) {
$i = 1;
foreach ($templatePaths as $id => $name) {
$sub->route('templates.overview', $name, ['id' => $id], $i++);
}
}, 60, ['icon' => 'fa fa-fw fa-file-code-o']);
}
// $menu->dropdown(trans('admin/mainMenu.customFields'), function ($sub) {
// $sub->route('customfields.new', trans('admin/mainMenu.customFieldsNew'), [], 10, ['icon' => 'fa fa-fw fa-code']);
// $sub->route('customfields.overview', trans('admin/mainMenu.customFieldsOverview'), [], 50, ['icon' => 'fa fa-fw fa-code-fork']);
// }, 30, ['icon' => 'fa fa-fw fa-code']);
$sub->route('log.overview', trans('admin/mainMenu.actionLog'), [], 70, ['icon' => 'fa fa-fw fa-history']);
$sub->route('settings.overview', trans('admin/mainMenu.settings'), [], 80, ['icon' => 'fa fa-fw fa-gear']);
}, 10000, ['icon' => 'fa fa-fw fa-gears']);
});
// order
// create menu with user profile
\Menu::create('profileMenu', function ($menu) {
$menu->route('users.detail', trans('admin/userManagement.profile'), [], 10, ['icon' => 'fa fa-fw fa-user icon']);
$menu->addDivider(999);
$menu->route('logout', trans('admin/common.logout'), [], 1000, ['icon' => 'fa fa-fw fa-power-off icon']);
});
}
}
+8 -28
View File
@@ -3,9 +3,8 @@ namespace App\Handlers\Contracts;
use App\Http\Requests\Request;
use App\Models\Content;
use App\Models\User;
interface AppHandler
interface AppHandler extends BaseModuleHandler
{
/**
* Render given module into visitor area.
@@ -21,13 +20,13 @@ interface AppHandler
/**
* 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
*
@@ -55,23 +54,14 @@ interface AppHandler
/**
* 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
@@ -99,19 +89,9 @@ interface AppHandler
public static function getExtendedFormInputsEdit();
/**
* Register admin menu (or multiple ones)
* Does this module support categories?
*
* 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
* @return boolean
*/
public static function registerAdminMenu(User $user);
/**
* Install module
*
* @return mixed
*/
public static function install();
public static function supportCategories();
}
@@ -0,0 +1,25 @@
<?php
namespace App\Handlers\Contracts;
use App\Models\User;
interface BaseModuleHandler
{
/**
* 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.
*
* This method is called after inserting info about module into database. It can be called only using Artisan in
* CLI.
*/
public static function install();
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App\Handlers\Contracts;
use App\Models\Content;
/**
* Interface ContentTitles
*
* Classes which implement this interface get the ability to rewrite default text on edit/create/overview of content
* page.
*
* @package App\Handlers\Contracts
*/
interface ContentTitles
{
/**
* Get translated title for pages overview of given type.
*
* This value is used for rendering list of all content pages of given type in administration.
*
* @return string
*/
public static function getOverviewTitle();
/**
* Title displayed above for for creating new content page
*
* @return string
*/
public static function getCreateNewTitle();
/**
* Title for form displayed for editin content page
*
* @param Content $content
*
* @return mixed
*/
public static function getEditTitle(Content $content);
}
@@ -0,0 +1,64 @@
<?php
namespace App\Handlers\Contracts;
use App\Http\Requests\Request;
use App\Models\Content;
use App\Models\Module;
/**
* Interface TemplateHandler
*
* Inerface used for registering template into CMS core.
*
* @package App\Handlers\Contracts
*/
interface TemplateHandler extends BaseModuleHandler
{
/**
* Uninstall template
*
* Delete some items in database, delete files etc.
*
* @param Module $template
*/
public static function uninstall(Module $template);
/**
* Get list of registered templates and supported modules.
*
* Returned array is expected to be array of arrays with following items: module, namespace and templateName.
* Example:
* return [
* ['module' => 'Article', 'templateName' => 'article::template.name']
* ];
*
* When no "namespace" is specified, value strtolower(module) is used instaed.
*
* @return array
*/
public static function getPublicTemplatePaths();
/**
* Prepare Content object to be rendered using Blade template
*
* @param Content $content
*/
public static function beforeRender(Content & $content);
/**
* Modify input data into format which can be understood by edit template
*
* @param Content $content
*/
public static function beforePopulatingEditForm(Content & $content);
/**
* Slightly modify Content object before saving into database.
*
* This way we can do almost whatever we want - even in template
*
* @param Content $content
* @param Request $request
*/
public static function beforeSave(Content & $content, Request $request);
}
+32 -100
View File
@@ -1,12 +1,9 @@
<?php
namespace App\Handlers;
use App\Enumerations\ModuleNamesWithIds;
use App\Enumerations\TemplatePathsHumanReadableRootOnly;
use App\Enumerations\WidgetTypes;
use App\Handlers\Contracts\AppHandler;
use App\Http\Controllers\Controller;
use App\Models\Content;
use App\Models\User;
/**
* Class Handler
@@ -16,20 +13,44 @@ use App\Models\User;
*
* @package App\Handlers
*/
abstract class Handler implements AppHandler
abstract class Handler extends BaseHandler implements AppHandler
{
/**
* todo: Temporary method, will be implemented for each Handler
*
* @return bool
*/
public static function supportCategories()
{
return true;
}
public static function getHistoryHandler()
{
return History::class;
}
/**
* 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)
{
return Controller::VisitorsView($content->template, ['page' => $content, 'extra' => $parameters]);
}
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')
'appearance' => trans('admin/contents.appearance'),
'files' => trans('admin/contents.files')
];
}
@@ -40,6 +61,7 @@ abstract class Handler implements AppHandler
'meta' => 'admin.content.formParts.metaInformation',
'publication' => 'admin.content.formParts.publicationSetup',
'appearance' => 'admin.content.formParts.appearance',
'files' => 'admin.content.formParts.files'
];
}
@@ -48,102 +70,12 @@ abstract class Handler implements AppHandler
// temporarily nothing to do
}
public static function loadExtraData(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'));
});
}
}
+9
View File
@@ -25,6 +25,15 @@ class History implements HistoryHandler
break;
case 'metaDescription':
return Differ::htmlDiff($changeset->old_value, $changeset->new_value);
break;
case 'file':
if (!$changeset->old_value) {
// old value is null -> new file was uploaded
return trans('admin/history.uploadedFile', ['file' => $changeset->new_value]);
} else {
return trans('admin/history.deletedFile', ['file' => $changeset->old_value]);
}
break;
case 'status':
$statuses = ContentStatuses::getWithTranslations();
@@ -28,6 +28,10 @@ class TemplateRegistrator
* @var int ID of module
*/
protected $moduleId;
/**
* @var array list of all registered template paths
*/
protected $paths = [];
/**
* Set base path
@@ -64,7 +68,7 @@ class TemplateRegistrator
*/
public function setNamespace($namespace)
{
$this->namespace = $namespace . '::';
$this->namespace = $namespace;
}
/**
@@ -73,28 +77,52 @@ class TemplateRegistrator
public function unsetNamespace()
{
$this->namespace = null;
$this->setModuleId(null);
}
/**
* Registers new template path.
* This method registeres given path itself with all subdirectories
*
* @param $baseDirectory
* @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)
public function register($baseDirectory, $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->paths[] = [
'namespace' => $this->namespace,
'moduleId' => $this->moduleId,
'baseDirectory' => $baseDirectory,
'path' => $this->baseDirectory . DIRECTORY_SEPARATOR . $path,
'name' => $name
];
$this->unsetNamespace();
}
/**
* Save templates into database
*/
public function saveTemplates()
{
if (!is_array($this->paths) || empty($this->paths)) {
return;
}
$this->registeredPath = $this->baseDirectory . DIRECTORY_SEPARATOR . $path;
foreach ($this->paths as $path) {
if (!empty($path['namespace'])) {
$this->setNamespace($path['namespace'] . '::');
}
$this->setModuleId($path['moduleId']);
$this->setBaseDirectory($path['baseDirectory']);
// register path
$this->registerPath($this->registeredPath, $name);
$this->registeredPath = $this->baseDirectory . DIRECTORY_SEPARATOR . $path['path'];
// register path
$this->registerPath($this->registeredPath, $path['name']);
$this->unsetNamespace();
}
}
/**
@@ -143,7 +171,7 @@ class TemplateRegistrator
Template::ASSETS_DIRECTORY,
Template::MODULES_DIRECTORY
];
if (in_array($dirName, $ignoredDirectories)) {
return;
}
@@ -184,7 +212,6 @@ class TemplateRegistrator
$registeredTemplates = Templates::getWithTranslations();
if (!in_array($templateName, $registeredTemplates)) {
$params = [
'template_name' => $templateName,
'name' => $templateName,
+37 -25
View File
@@ -3,44 +3,56 @@ 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;
protected $registeredWidgets = [];
function __construct()
{
$this->widgets = WidgetTypesWithHandlers::getSimple();
}
/**
* Method used for registering new widgets
*
* @param $classname
* @param $classname
* @param null $templateId
* @param null $moduleId
*/
public function register($classname)
public function register($classname, $templateId = null, $moduleId = null)
{
$class = new $classname;
if (!$class instanceof PublicWidget) {
throw new InvalidArgumentException($class . ' must implement PublicWidget interface.');
}
$this->registeredWidgets[] = [
'class' => $classname,
'templateId' => $templateId,
'moduleId' => $moduleId
];
}
// register widget as new widget type
if (!in_array($classname, $this->widgets)) {
$widgetName = call_user_func($classname . '::getName');
$widgetDescription = call_user_func($classname . '::getDescription');
/**
* Install all non-installed widgets
*/
public function installWidgets()
{
$installed = WidgetTypesWithHandlers::getSimple();
foreach ($this->registeredWidgets as $registeredWidget) {
$classname = $registeredWidget['class'];
$templateId = $registeredWidget['templateId'];
$moduleId = $registeredWidget['moduleId'];
// create row in widget types
WidgetType::create([
'handler' => $classname,
'name' => $widgetName,
'description' => $widgetDescription
]);
// register widget as new widget type
if (!in_array($classname, $installed)) {
$widgetName = call_user_func($classname . '::getName');
$widgetDescription = call_user_func($classname . '::getDescription');
// install widget (if neccessary)
call_user_func($classname . '::install');
// create row in widget types
WidgetType::create([
'handler' => $classname,
'name' => $widgetName,
'module_id' => $moduleId,
'template_id' => $templateId,
'description' => $widgetDescription
]);
// install widget (if neccessary)
call_user_func($classname . '::install');
}
}
}
}
+1
View File
@@ -27,6 +27,7 @@ class Files extends Search
$token = $this->tokenize($term);
return File::where('original_filename', 'LIKE', $token)
->orWhere('name', 'LIKE', $token)
->orWhere('keywords', 'LIKE', $token)
->orWhere('description', 'LIKE', $token)
->orWhere('mime_type', 'LIKE', $token)
@@ -1,12 +1,16 @@
<?php
namespace App\Handlers\Search\Presenters;
use App\Enumerations\ContentStatuses;
use App\Handlers\Contracts\SearchPresenterHandler;
class AdminContent implements SearchPresenterHandler
{
public function render($foundItems)
{
return view('admin.content.overviewTiles', ['pages' => $foundItems, 'tileClass' => 'large-4']);
return view('admin.search.results.content', [
'pages' => $foundItems,
'statuses' => ContentStatuses::getWithTranslations(),
]);
}
}
@@ -14,6 +14,6 @@ class AdminFiles implements SearchPresenterHandler
*/
public function render($foundItems)
{
return view('admin.fileManager.filesTiles', ['files' => $foundItems]);
return view('admin.fileManager.filesTiles', ['files' => $foundItems, 'hideDelete' => true]);
}
}
+63
View File
@@ -0,0 +1,63 @@
<?php
namespace App\Helpers;
use App\Models\Module;
use DebugBar\Bridge\MonologCollector;
use Illuminate\Database\QueryException;
use Monolog\Logger;
class CurrentTemplate
{
protected static $template;
protected static $initialized = false;
/**
* Getter for currently set template
* @return Module
* @throws \ErrorException
*/
public static function get()
{
if (!self::$initialized) {
try {
self::$template = Module::where('is_template', true)
->where('enabled', true)
->first();
} catch (QueryException $e) {
throw new \ErrorException('DB not migrated, please, do so!');
}
if (self::$template) {
self::$template->module_settings = json_decode(self::$template->module_settings);
}
self::$initialized = true;
}
return self::$template;
}
/**
* Shortcut for getting template handler
*
* @return string
* @throws \ErrorException
*/
public static function handler()
{
$template = self::get();
if (!$template) {
throw new \ErrorException('No template selected, no handler available!');
}
return $template->handler;
}
/**
* Reset currently set template and load another one on next call of get() method.
*/
public static function reset()
{
self::$initialized = false;
}
}
+64
View File
@@ -0,0 +1,64 @@
<?php
namespace App\Helpers;
class Date
{
/**
* Print date in configured format
*
* @param $datestamp
* @param bool $withTime
*
* @return false|string
*/
public static function date($datestamp, $withTime = true)
{
$timestamp = strtotime($datestamp);
if ($timestamp <= 0) {
return '';
}
$format = $withTime ? config('app.datetime_format') : config('app.date_format');
return date($format, $timestamp);
}
public static function dateFormatted($format, $datestamp)
{
$timestamp = strtotime($datestamp);
if ($timestamp <= 0) {
return '';
}
return date($format, $timestamp);
}
public static function monthName($datestamp) {
$timestamp = strtotime($datestamp);
if ($timestamp <= 0) {
return '';
}
$months = [
trans('common.months.january'),
trans('common.months.february'),
trans('common.months.march'),
trans('common.months.april'),
trans('common.months.may'),
trans('common.months.june'),
trans('common.months.july'),
trans('common.months.august'),
trans('common.months.semptember'),
trans('common.months.october'),
trans('common.months.november'),
trans('common.months.december'),
];
$monthNumber = date('n', $timestamp);
return $months[$monthNumber - 1];
}
}
+22 -29
View File
@@ -17,34 +17,42 @@ class FileManager
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;
}
$url = Template::thumbnail($file->filename);
return '<img src="' . $url . '" alt="' . $file->description . '" />';
break;
case 'text':
return '<i class="fa fa-file-text-o"></i>';
return self::getIcon($file, 'fa-file-text-o');
break;
case 'application':
switch ($subtype) {
case 'pdf':
return '<i class="fa fa-file-pdf-o"></i>';
return self::getIcon($file, 'fa-file-pdf-o');
break;
default:
return '<i class="fa fa-newspaper-o"></i>';
return self::getIcon($file, 'fa-newspaper-o');
break;
}
break;
default:
return '<i class="fa fa-question"></i>';
return self::getIcon($file, 'fa-question');
break;
}
}
/**
* Shortcut for displaying icons
*
* @param $file
* @param $icon
*
* @return string
*/
protected static function getIcon($file, $icon)
{
return '<p><i class="fa fa-2x ' . $icon . '"></i><br /><span>' . e(str_limit($file->original_filename, 15)) . '</span></p>';
}
/**
*
*
@@ -83,7 +91,6 @@ class FileManager
return '<img src="' . $url . '" alt="' . $file->description . '" />';
break;
case 'text':
$string = '<pre><code>';
$string .= htmlspecialchars(file_get_contents($path));
$string .= '</pre></code>';
@@ -91,15 +98,8 @@ class FileManager
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;
return '<iframe src = "'.asset('resources/assets/admin/js/viewerJs/').'/#'.Template::upload($file->filename).'" style="width: 100%; height: 50em" allowfullscreen webkitallowfullscreen></iframe>';
break;
default:
return self::getPreview($file);
break;
@@ -119,19 +119,12 @@ class FileManager
switch ($type) {
case 'text':
return [
trans('admin/fileManager.encoding') => mb_detect_encoding(file_get_contents($path))
];
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,
];
return [trans('admin/fileManager.resolution') => $height . ' x ' . $width,];
break;
}
+1 -1
View File
@@ -5,6 +5,6 @@ class Gravatar
{
public static function img($email, $size = 50)
{
return "http://www.gravatar.com/avatar/" . md5(strtolower(trim($email))) . "?s=" . $size;
return "//www.gravatar.com/avatar/" . md5(strtolower(trim($email))) . "?s=" . $size;
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
namespace App\Helpers;
use App\Handlers\Contracts\AppHandler;
use App\Models\Content;
use Webwizo\Shortcodes\Facades\Shortcode;
/**
* Class PageRenderer
*
* Simple class for rendering page for visitor
*
* @package App\Helpers
*/
class PageRenderer
{
/**
* Render page
*
* @param Content $page
*
* @return mixed
*/
public static function render(Content $page)
{
// decode module settings
$page->module_settings = json_decode($page->module_settings);
// do something template-specific
$parameters = call_user_func_array([CurrentTemplate::handler(), 'beforeRender'], [&$page]);
/**
* @var $handler AppHandler
*/
// get handler
$handler = new $page->module_handler;
$page->content = Shortcode::compile($page->content);
// render page
return $handler->render($page, $parameters);
}
}
+83
View File
@@ -0,0 +1,83 @@
<?php
namespace App\Helpers;
use App\Models\Settings as SettingsModel;
/**
* Class Settings
*
* Helper class for easier obtaining system settings
*
* @package App\Helpers
*/
class Settings
{
/**
* @var array List of all used settings
*/
protected static $settings;
/**
* @var bool Are data already initialized?
*/
protected static $initialized = false;
/**
* Getter for settings determined with key.
*
* @param string $key settings key
* @param string|null $default default value, which will be returned when given key does not exist
*
* @param null $exists
*
* @return null|string
*/
public static function get($key, $default = null, & $exists = null)
{
self::init();
if (isset(self::$settings->$key)) {
$exists = true;
self::$initialized = true;
return self::$settings->$key;
}
$exists = false;
return $default;
}
/**
* Shortcut for obtaining settings saved as JSON
*
* @param $key
*
* @return mixed
*/
public static function getJson($key)
{
return json_decode(self::get($key, '{}'));
}
/**
* Get all settings
*
* @return array
*/
public static function all()
{
self::init();
return self::$settings;
}
/**
* Initialize settings array
*/
private static function init()
{
if (!self::$initialized) {
$model = new SettingsModel();
self::$settings = $model->getAll();
}
}
}
+47 -5
View File
@@ -13,7 +13,7 @@ class Template
*
* @return null|string
*/
public static function name($template)
public static function name($template, $throwExceptions = true)
{
$namespace = null;
if (strpos($template, '::')) {
@@ -21,10 +21,8 @@ class Template
$namespace .= '::';
}
$theme = config('app.theme');
// list of prefixes
$prefixes = [$theme . '.custom.', $theme . '.', ''];
$prefixes = ['custom.', ''];
$view = null;
foreach ($prefixes as $prefix) {
@@ -35,7 +33,11 @@ class Template
}
if (is_null($view)) {
throw new InvalidArgumentException('Cannot find template for ' . $namespace . $template);
if ($throwExceptions) {
throw new InvalidArgumentException('Cannot find template for ' . $namespace . $template);
} else {
return false;
}
}
return $view;
@@ -59,6 +61,25 @@ class Template
return config('app.upload_url') . '/' . $filename;
}
public static function thumbnail($filename)
{
// try to check if file have thumbnail
if (file_exists(config('app.thumbnail_path') . '/' . $filename)) {
$url = config('app.thumbnail_url') . '/' . $filename;
} else {
$url = self::upload($filename);
}
return $url;
}
/**
* Get path to given asset
*
* @param $path
*
* @return string
*/
public static function asset($path)
{
if (env('APP_DEBUG')) {
@@ -74,4 +95,25 @@ class Template
return config('app.url') . '/assets/' . config('app.theme') . '/' . $path;
}
/**
* Print date in configured format
*
* @param $datestamp
* @param bool $withTime
*
* @return false|string
*/
public static function date($datestamp, $withTime = true)
{
$timestamp = strtotime($datestamp);
if ($timestamp <= 0) {
return '';
}
$format = $withTime ? config('app.datetime_format') : config('app.date_format');
return date($format, $timestamp);
}
}
+45 -17
View File
@@ -9,6 +9,46 @@ class WidgetAreas
* @var array list of inicialized widget areas
*/
protected static $widgetAreas = [];
protected static $initialized = false;
protected static function saveRenderedWidgetArea($widgets)
{
foreach ($widgets as $widget) {
if (!isset(self::$widgetAreas[$widget->widget_area_code]))
self::$widgetAreas[$widget->widget_area_code] = '';
$handler = $widget->widget_type_handler;
$widget->settings = json_decode($widget->settings);
$presenter = call_user_func([$handler, 'getPresenter']);
self::$widgetAreas[$widget->widget_area_code] .= call_user_func([$presenter, 'render'], $widget);
}
}
protected static function loadWidgetArea($uniqueCode)
{
$widgetArea = new WidgetArea();
$widgets = $widgetArea->getWidgets($uniqueCode)
->get();
WidgetArea::where('code', $uniqueCode)
->increment('viewed');
self::saveRenderedWidgetArea($widgets);
}
protected static function initWidgetAreas()
{
if (self::$initialized)
return;
$widgetArea = new WidgetArea();
$widgets = $widgetArea->getWidgets()
->get();
self::saveRenderedWidgetArea($widgets);
self::$initialized = true;
}
/**
* Renderer for whole widget area.
@@ -19,26 +59,14 @@ class WidgetAreas
*/
public static function render($uniqueCode)
{
if (isset(self::$widgetAreas[$uniqueCode])) {
echo self::$widgetAreas[$uniqueCode];
return;
if (!self::$initialized) {
self::initWidgetAreas();
}
$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));
if (!isset(self::$widgetAreas[$uniqueCode])) {
self::loadWidgetArea($uniqueCode);
}
// cache this widget area
self::$widgetAreas[$uniqueCode] = $content;
echo $content;
echo isset(self::$widgetAreas[$uniqueCode]) ? self::$widgetAreas[$uniqueCode] : null;
}
}
+16
View File
@@ -11,4 +11,20 @@
function e($value)
{
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
/**
* Shortcut for \App\Helpers\Settings::get()
*
* @param $key
* @param null $default
*
* @return null|string
*/
function setting($key, $default = null) {
return \App\Helpers\Settings::get($key, $default);
}
function asset_path($path) {
return env('SITE_URL').'/assets/'.$path;
}
@@ -0,0 +1,51 @@
<?php
namespace App\Http\Controllers\Admin\ActionLog;
use App\Http\Controllers\Admin\Controller;
use App\Models\ActionLog;
use App\Models\User;
use Illuminate\Support\Facades\Input;
class Overview extends Controller
{
/**
* @var ActionLog
*/
private $log;
/**
* ActionLog constructor.
*
* @param ActionLog $log
*/
public function __construct(ActionLog $log)
{
parent::__construct();
$this->log = $log;
}
/**
* Get overview of logged actions
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getOverview()
{
$user = null;
$userId = Input::get('userId');
$actions = $this->log->getLogActionsQuery(true);
if ($userId) {
$user = User::findOrFail($userId);
$actions->where('users.id', $userId);
}
$actions = $actions->paginate(25);
$this->log->translateLogMessages($actions);
return view('admin.actionLog.overview', ['actions' => $actions, 'user' => $user]);
}
}
@@ -1,35 +0,0 @@
<?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]);
}
}
@@ -1,6 +1,8 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Contents;
use App\Enumerations\ContentStatuses;
use App\Http\Controllers\Admin\Controller;
use App\Models\Content;
use App\Models\Module;
use Illuminate\Support\Facades\Input;
@@ -31,11 +33,16 @@ class ContentOverview extends Controller
{
$moduleFilterHandler = false;
$perPage = Input::get('perPage') ? Input::get('perPage') : 20;
$pageHeading = 'admin/contents.overview';
// does user want to filter results using module?
if (is_numeric($moduleId)) {
$module = Module::findOrFail($moduleId);
$moduleFilterHandler = $module->handler;
if (is_callable([$module->handler, 'getOverviewTitle'])) {
$pageHeading = call_user_func([$module->handler, 'getOverviewTitle']);
}
}
// get pages for overview
@@ -45,6 +52,12 @@ class ContentOverview extends Controller
// get homepage - for checking if homepage is set and available
$homepage = $this->content->getHomepage();
return view('admin.content.overview', ['pages' => $pages, 'homepage' => $homepage]);
return view('admin.content.overview', [
'pages' => $pages,
'homepage' => $homepage,
'pageHeading' => $pageHeading,
'statuses' => ContentStatuses::getWithTranslations(),
'module' => isset($module) ? $module : null
]);
}
}
@@ -1,8 +1,10 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Contents;
use App\Enumerations\ActiveContentStatuses;
use App\Enumerations\ContentStatuses;
use App\Events\CreateNewContent as CreateNewContentEvent;
use App\Helpers\CurrentTemplate;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\CreateNewContentRequest;
use App\Models\Content;
use App\Models\File;
@@ -10,8 +12,18 @@ use App\Models\Module;
use App\Models\Template;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Modules\Categories\Entities\Category;
use Pingpong\Modules\Facades\Module as ModuleInstance;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class CreateNewContent
*
* Controller for creating new content page.
*
* @package App\Http\Controllers\Admin\Contents
*/
class CreateNewContent extends Controller
{
/**
@@ -23,6 +35,14 @@ class CreateNewContent extends Controller
*/
private $content;
/**
* CreateNewContent constructor.
*
* Sets File and Content models into class variables
*
* @param File $file
* @param Content $content
*/
public function __construct(File $file, Content $content)
{
parent::__construct();
@@ -39,24 +59,42 @@ class CreateNewContent extends Controller
*/
public function getNew($moduleId)
{
$module = Module::findOrFail($moduleId);
$statuses = ActiveContentStatuses::getWithTranslations();
$statuses = ContentStatuses::getWithTranslations();
// set default page title
$pageHeading = trans('admin/contents.new', ['name' => trans($module->name)]);
if (is_callable([$module->handler, 'getCreateNewTitle'])) {
$pageHeading = call_user_func([$module->handler, 'getCreateNewTitle']);
}
// get list of usable templates
$templates = Template::where('module_id', $moduleId)
->select(['template_name', 'name', 'description'])
->get();
// add categories, if supported
$categoryModule = ModuleInstance::get('categories');
$categories = [];
if ($module->support_categories && !is_null($categoryModule) && $categoryModule->enabled()) {
$categories = Category::where('module_id', $moduleId)
->get();
}
// create default content object
$this->content->status = Content::STATUS_DRAFT;
// render view
return view('admin.content.new', [
'pageHeading' => $pageHeading,
'contentStatuses' => $statuses,
'templates' => $templates,
'moduleId' => $moduleId,
'module' => $module,
'categories' => $categories,
'page' => $this->content,
'rootPages' => $this->content->getOverview()->get(),
'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']),
@@ -74,7 +112,6 @@ class CreateNewContent extends Controller
*/
public function postNew(CreateNewContentRequest $request, $moduleId)
{
$page = new Content();
try {
$module = Module::findOrFail($moduleId);
} catch (NotFoundHttpException $e) {
@@ -84,35 +121,46 @@ class CreateNewContent extends Controller
->with('error', trans('admin/contents.invalidModule'));
}
// create new page
$page = new Content();
$page->template = $request->template;
// setup basic info
$page->user_id = \Auth::user()->id;
$page->language = LaravelLocalization::getCurrentLocale();
$page->title = $request->title;
$page->url = Str::slug($request->url);
$page->published_from = $request->publishedFrom;
$page->published_to = $request->publishedTo;
$page->published_from = empty($request->publishedFrom) ? null : $request->publishedFrom;
$page->published_to = empty($request->publishedTo) ? null : $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;
$page->category_id = (int)$request->category > 0 ? $request->category : null;
// is any parent page specified?
if ($request->parentPage) {
$page->parent_id = $request->parentPage;
}
// upload file - if provided
if ($request->hasFile('titlePhoto')) {
$file = $this->file->upload($request->file('titlePhoto'), $request);
$file = $page->uploadTitlePhoto($request);
$page->title_photo = $file['filename'];
}
$page->title_photo = $file ? $file['filename'] : null;
// save module-specific stuff
call_user_func_array([$module->handler, 'createNew'], [&$page, $request]);
// let template to modify request and content page
call_user_func_array([CurrentTemplate::handler(), 'beforeSave'], [&$page, $request]);
// save content of page before (possible) uploading related files
$page->save();
// upload files assigned to content page
$page->uploadRelatedFiles($request);
// fire event about creating new content page
Event::fire(new CreateNewContentEvent($page));
@@ -1,22 +1,27 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Contents;
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\Helpers\CurrentTemplate;
use App\Http\Controllers\Admin\Controller;
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\Module;
use App\Models\Template;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Modules\Categories\Entities\Category;
use Pingpong\Modules\Facades\Module as ModuleInstance;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class EditContent extends Controller
@@ -30,6 +35,14 @@ class EditContent extends Controller
*/
private $file;
/**
* EditContent constructor.
*
* Load ContentHistory and File into this controller
*
* @param ContentHistory $history
* @param File $file
*/
public function __construct(ContentHistory $history, File $file)
{
$this->history = $history;
@@ -52,21 +65,45 @@ class EditContent extends Controller
$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)
// get module ID
$module = Module::where('handler', $page->module_handler)
->firstOrFail();
$pageHeading = trans('admin/contents.edit', ['name' => e($page->title)]);
if (is_callable([$module->handler, 'getCreateNewTitle'])) {
$pageHeading = call_user_func([$module->handler, 'getEditTitle'], $page);
}
// get all Blade templates for rendering page
$templates = Template::where('module_id', $module->id)
->select(['template_name', 'name', 'description'])
->get();
// get module for Categories - PingPong module
$categoryModule = ModuleInstance::get('categories');
// add categories, if supported
$categories = [];
if ($module->support_categories && !is_null($categoryModule) && $categoryModule->enabled()) {
$categories = Category::where('module_id', $module->id)
->get();
}
// modify data for edit form according to installed template
call_user_func_array([CurrentTemplate::handler(), 'beforePopulatingEditForm'], [&$page]);
$history = $this->history->getStructuredHistoryOf($page);
// render view
return view('admin.content.edit', [
'pageHeading' => $pageHeading,
'contentStatuses' => $statuses,
'page' => $page,
'module' => $module,
'categories' => $categories,
'rootPages' => $page->getOverview()
->where('contents.id', '!=', $page->id)
->get(),
->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']),
@@ -86,6 +123,9 @@ class EditContent extends Controller
public function postEdit(EditContentRequest $request, $id)
{
try {
/**
* @var $page Content
*/
$page = Content::findOrFail($id);
} catch (NotFoundHttpException $e) {
@@ -98,14 +138,21 @@ class EditContent extends Controller
->with('error', trans('admin/contents.invalidPage'));
}
// upload file - if provided
$file = $page->uploadTitlePhoto($request);
// let template to modify request and content page
call_user_func_array([CurrentTemplate::handler(), 'beforeSave'], [&$page, $request]);
$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->publishedFrom = empty($request->publishedFrom) ? null : $request->publishedFrom;
$request->publishedTo = empty($request->publishedTo) ? null : $request->publishedTo;
if (!$file) {
$request->titlePhotoFilename = empty($request->existingTitlePhoto) ? null : $request->existingTitlePhoto;
} else {
$request->titlePhotoFilename = $file['filename'];
}
@@ -121,14 +168,17 @@ class EditContent extends Controller
'content' => 'pageContent',
'parent_id' => 'parentPage',
'status' => 'status',
'title_photo' => 'titlePhotoFilename'
'title_photo' => 'titlePhotoFilename',
'category_id' => 'category'
];
// save new values with history
$data = self::getFields($request, $fields);
$data = self::getFields($request, array_values($fields));
list($revision, $changedColumns) = $page->updateWithHistory($fields, $data);
$changedColumns += call_user_func_array([$page->module_handler, 'edit'], [&$page, $request, $revision]);
$changedColumns += $page->uploadRelatedFiles($request, $revision);
// was something changed?
if ($changedColumns == 0) {
@@ -142,7 +192,7 @@ class EditContent extends Controller
// something was changed, inform user
return redirect()
->route('content.edit', ['id' => $page->id])
->route('content.overview')
->with('success', trans('admin/contents.successfullyEdited'));
}
@@ -160,7 +210,6 @@ class EditContent extends Controller
{
// get possible statuses
$statuses = ContentStatuses::getWithTranslations();
unset($statuses[Content::STATUS_DELETED]);
// check if given status is valid
if (!isset($statuses[$status])) {
@@ -223,23 +272,17 @@ class EditContent extends Controller
// change url to something unique
$oldURL = $page->url;
$page->url = uniqid($page->url.'_deleted');
$page->url .= uniqid('deleted_');
$page->save();
list ($revision, $changedColumns) = $page->updateWithHistory(['status' => 'status'], ['status' => Content::STATUS_DELETED]);
// delete page
$page->delete();
// 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));
Event::fire(new DeleteContent($page));
// redirect back to overview with info for user
return redirect()
@@ -268,12 +311,13 @@ class EditContent extends Controller
} catch (NotFoundHttpException $e) {
// page not found
return redirect()
->route('content.overview')
->back()
->with('error', trans('admin/contents.invalidPage'));
}
// disable any other existing homepage
Content::where('is_homepage', 1)
->where('language', LaravelLocalization::getCurrentLocale())
->update(['is_homepage' => 0]);
// set new homepage
@@ -282,7 +326,7 @@ class EditContent extends Controller
// was something changed?
if ($changedColumns == 0) {
return redirect()
->route('content.overview')
->back()
->with('error', trans('admin/contents.nothingToEdit'));
}
@@ -291,7 +335,7 @@ class EditContent extends Controller
// redirect back to overview with info for user
return redirect()
->route('content.overview')
->back()
->with('success', trans('admin/contents.homepageSetup', [
'name' => $page->title,
'url' => $page->url
@@ -1,6 +1,7 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Contents;
use App\Http\Controllers\Admin\Controller;
use App\Models\Content;
use App\Models\ContentHistory;
@@ -1,10 +1,11 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\CustomFields;
use App\Enumerations\CustomFieldResources;
use App\Enumerations\CustomFieldTypes;
use App\Events\CreateNewCustomField as CreateNewCustomFieldEvent;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\NewCustomFieldRequest;
use App\Models\CustomField;
use Illuminate\Support\Facades\Event;
@@ -1,11 +1,10 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\CustomFields;
use App\Enumerations\CustomFieldResources;
use App\Enumerations\CustomFieldTypes;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Models\CustomField;
class CustomFieldsOverview extends Controller
@@ -1,13 +1,12 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\CustomFields;
use App\Enumerations\CustomFieldResources;
use App\Enumerations\CustomFieldTypes;
use App\Events\DeleteCustomField;
use App\Events\EditCustomField as EditCustomFieldEvent;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\EditCustomFieldRequest;
use App\Models\CustomField;
use Illuminate\Support\Facades\Event;
-17
View File
@@ -1,17 +0,0 @@
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Requests;
use Illuminate\Support\Facades\Session;
class Dashboard extends Controller
{
public function getIndex(Request $request) {
return redirect()->route('content.overview');
// return view('admin.dashboard');
}
}
@@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Admin\Dashboard;
use App\Http\Controllers\Admin\Controller;
use Illuminate\Http\Request;
class Dashboard extends Controller
{
public function getIndex(Request $request)
{
return redirect()->route('content.overview');
}
}
@@ -1,8 +1,8 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\FileManager;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests;
use App\Models\Directory;
@@ -30,8 +30,8 @@ class CreateNewDirectory extends Controller
} else {
return redirect()
->route('upload.overview', ['id' => $request->parentDirectory])
->with('error', trans('admin/fileManager.subdirectoryExists'))
->withInput();
->withInput()
->with('error', trans('admin/fileManager.subdirectoryExists'));
}
}
@@ -1,8 +1,8 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\FileManager;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests;
use App\Models\Directory;
@@ -12,7 +12,7 @@ class EditDirectory extends Controller
* @param Requests\EditDirectoryRequest $request
* @param $directoryId
*
* @return $this|\Illuminate\Http\JsonResponse
* @return $this|\Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
public function postEdit(Requests\EditDirectoryRequest $request, $directoryId)
{
@@ -34,8 +34,8 @@ class EditDirectory extends Controller
} else {
return redirect()
->route('upload.overview', ['id' => $directoryId])
->with('error', trans('admin/fileManager.subdirectoryExists'))
->withInput();
->withInput()
->with('error', trans('admin/fileManager.subdirectoryExists'));
}
}
@@ -1,10 +1,10 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\FileManager;
use App\Events\EditFile;
use App\Helpers\FileManager;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\EditUploadedFileRequest;
use App\Models\File;
use Illuminate\Support\Facades\Event;
@@ -0,0 +1,102 @@
<?php
namespace App\Http\Controllers\Admin\FileManager;
use App\Helpers\Template;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\Request;
use App\Models\File;
use Illuminate\Support\Facades\Input;
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 Request $request
*
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
public function postFile(Request $request)
{
if (Input::get('CKEditor')) {
return $this->ckEditorUpload($request);
} else {
return $this->internalUpload($request);
}
}
/**
* Upload file using internal file uploader
*
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse
*/
private function internalUpload(Request $request)
{
try {
$uploadedFiles = [];
$files = $request->all()['files'];
$successfullUploads = 0;
foreach ($files as $file) {
$uploadedFile = $this->file->upload($file, $request);
$successfullUploads++;
$uploadedFiles[] = $uploadedFile;
}
return redirect()
->back()
->with('success', trans_choice('admin/fileManager.uploadSuccessfull', $successfullUploads));
} catch (FileException $e) {
return $this->invalidUpload('invalidFile');
}
}
/**
* Upload file using CKEditor
*
* @param Request $request
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
private function ckEditorUpload(Request $request)
{
$file = $request->file('upload');
$uploadedFile = $this->file->upload($file, $request);
return view('admin.snippets.ckEditorUploaded', [
'ckEditor' => Input::get('CKEditor'),
'funcNumber' => Input::get('CKEditorFuncNum'),
'fileUrl' => Template::upload($uploadedFile['filename'])
]);
}
/**
* Send message and redirect to upload.overview when upload failed
*
* @param $message
*
* @return \Illuminate\Http\RedirectResponse
*/
protected function invalidUpload($message)
{
return redirect()
->route('upload.overview')
->with('error', trans('admin/fileManager.' . $message));
}
}
@@ -1,9 +1,7 @@
<?php
namespace App\Http\Controllers\Admin\FileManager;
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Models\Directory;
use App\Models\File;
use Illuminate\Support\Facades\Input;
+30 -4
View File
@@ -3,13 +3,10 @@
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\LoginRequest;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Session;
/**
* Class Login
@@ -20,6 +17,16 @@ use Illuminate\Support\Facades\Session;
*/
class Login extends Controller
{
/**
* Display login form
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getLogin()
{
return view('admin.loginForm');
}
/**
* Login handler
*
@@ -45,13 +52,32 @@ class Login extends Controller
if (Hash::check($request->password, $user->password)) {
Auth::login($user);
return redirect()->intended(route('admin.dashboard'));
$redirect = $request->redirectTo ? $request->redirectTo : route('admin.dashboard');
return redirect()->intended($redirect);
}
// login invalid, redirect and inform the user
return $this->loginFailed();
}
/**
* Logs out user
*
* @return \Illuminate\Http\RedirectResponse
*/
public function logout()
{
// remove user information
\Auth::logout();
// redirect to login form with info about successfull logout
return redirect()
->route('login')
->with('success', trans('admin/common.logoutSuccessfull'));
}
private function loginFailed()
{
return redirect()
-1
View File
@@ -57,7 +57,6 @@ class Search extends Controller
* @var SearchHandler $search
* @var SearchPresenterHandler $presenter
*/
list ($search, $presenter) = $engine;
// try to find given term
+38 -25
View File
@@ -4,30 +4,39 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\Settings as SettingsModel;
use Illuminate\Support\Facades\App;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class Settings extends Controller
{
/**
* @var \App\Models\Settings
* @var SettingsModel
*/
protected $settings;
/**
* Settings constructor.
*
* @param \App\Models\Settings $settings
* @param SettingsModel $settings
*/
public function __construct(\App\Models\Settings $settings)
public function __construct(SettingsModel $settings)
{
$this->settings = $settings;
}
/**
* Get overview (with form) for editing settings
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getOverview()
{
$sections = App::make('registerSettingsExtension')
->get();
$settings = $this->settings->getAll();
// load all settings with language info
$settings = $this->settings->getAllWithLanguage();
return view('admin.settings.overview', [
'formSections' => $sections,
@@ -35,35 +44,39 @@ class Settings extends Controller
]);
}
/**
* Save all settings (ignore empty ones)
*
* When settings used to be non-empty string and user deletes it, key is also deleted from database
*
* @param Requests\SaveSettingsRequest $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function saveSettings(Requests\SaveSettingsRequest $request)
{
$data = $request->all();
$commonSettings = isset($data['commonSettings']) ? $data['commonSettings'] : [];
// remove CSRF token field
unset($data['_token']);
unset($data['_token'], $data['commonSettings']);
$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++;
// select language for this setting key
$language = isset($commonSettings[$key]) ? null : LaravelLocalization::getCurrentLocale();
$setting = SettingsModel::firstOrNew(['language' => $language, 'key' => $key]);
if ($setting->value == $value) {
continue;
}
// set value and save or delete
$setting->value = $value;
empty($value) ? $setting->delete() : $setting->save();
}
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'));
}
return redirect()
->route('settings.overview')
->with('success', trans('admin/settings.successfullySaved'));
}
}
@@ -1,12 +1,10 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Templates;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\CopyTemplateRequest;
use App\Models\Template;
use Illuminate\Http\Request;
class CopyTemplate extends Controller
{
@@ -28,11 +26,6 @@ class CopyTemplate extends Controller
// 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);
@@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Templates;
use App\Http\Controllers\Controller;
use App\Http\Requests;
@@ -20,6 +20,9 @@ class EditTemplate extends Controller
*/
public function getEdit($template)
{
/**
* @var $template Template
*/
$template = Template::findOrFail($template);
$path = $template->getPath();
@@ -85,11 +88,11 @@ class EditTemplate extends Controller
return redirect()
->route('templates.edit', ['id' => $request->id])
->withInput()
->with('error', trans('admin/templates.cannotWriteContent'));
->with('warning', trans('admin/templates.cannotWriteContent'));
}
// save new content only if something was changed
if ($this->isContentDifferent($originalTemplate, $customTemplate, $request->templateContent)) {
if ($template->editable && $this->isContentDifferent($originalTemplate, $customTemplate, $request->templateContent)) {
// create directory for custom updates
if (!is_dir($customDir)) {
@@ -1,11 +1,9 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Templates;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Models\TemplatePath;
use Illuminate\Http\Request;
class TemplateOverview extends Controller
{
-79
View File
@@ -1,79 +0,0 @@
<?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);
}
}
@@ -1,14 +0,0 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\CreateNewUserRequest;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class UserProfile extends Controller {
}
@@ -1,11 +1,10 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Users;
use App\Enumerations\UserRoles;
use App\Events\CreateNewUser as CreateNewUserEvent;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\CreateNewUserRequest;
use App\Models\User;
use Illuminate\Support\Facades\Event;
@@ -1,12 +1,11 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Users;
use App\Enumerations\UserRoles;
use App\Enumerations\UserStates;
use App\Events\EditUser as EditUserEvent;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\EditUserRequest;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
@@ -22,11 +21,8 @@ class EditUser extends Controller
$id = Auth::user()->id;
}
// @todo add some authorization (e.g. via can/cannot methods)
// try to find given user
$user = User::where('status', '!=', User::STATE_DELETED)
->findOrFail($id);
$user = User::findOrFail($id);
$states = UserStates::getWithTranslations();
$roles = UserRoles::getWithTranslations();
@@ -87,7 +83,7 @@ class EditUser extends Controller
Event::fire(new EditUserEvent($user));
return redirect()
->route('users.detail', ['id' => $id])
->back()
->with('success', trans('admin/userManagement.userSuccessfullyEdited'));
}
}
@@ -1,10 +1,10 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Users;
use App\Enumerations\UserRoles;
use App\Enumerations\UserStates;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests;
use App\Models\ActionLog;
use App\Models\User;
@@ -32,14 +32,14 @@ class UserDetail extends Controller
// try to find given user
$user = User::findOrFail($id);
$actions = $this->log->getUserActions($id);
$actions = $this->log->getUserActions($id, 10);
$roles = UserRoles::getWithTranslations();
$states = UserStates::getWithTranslations();
return view('admin.userManagement.detail', [
'user' => $user,
'states' => $states,
'statuses' => $states,
'roles' => $roles,
'actions' => $actions
]);
@@ -1,24 +1,21 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Users;
use App\Enumerations\UserRoles;
use App\Enumerations\UserStates;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Models\User;
class UsersOverview extends Controller
{
public function getOverview($status = null, $perPage = 12)
{
$users = User::where('status', '<>', User::STATE_DELETED)
->orderBy('id', 'desc');
$users = User::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])) {
@@ -29,9 +26,9 @@ class UsersOverview extends Controller
$users = $users->paginate($perPage);
return view('admin.userManagement.overview', [
'users' => $users,
'roles' => UserRoles::getWithTranslations(),
'statuses' => $statuses,
'users' => $users,
'roles' => UserRoles::getWithTranslations(),
'statuses' => $statuses,
'currentStatus' => $status
]);
}
@@ -1,9 +1,8 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Widgets\Areas;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\NewWidgetAreaRequest;
use App\Models\WidgetArea;
use Illuminate\Support\Facades\Event;
@@ -17,7 +16,7 @@ class CreateNewWidgetArea extends Controller
*/
public function getNew()
{
return view('admin.widgets.area.new');
return view('admin.widgets.area.new', ['area' => new WidgetArea()]);
}
/**
@@ -1,23 +1,45 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Widgets\Areas;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\EditWidgetAreaRequest;
use App\Models\Widget;
use App\Models\WidgetArea;
use App\Models\WidgetInWidgetArea;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Event;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class EditWidgetArea extends Controller
{
/**
* Display form for editing given widget area
*
* @param $id
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getEdit($id)
{
$area = WidgetArea::findOrFail($id);
$associatedWidgetIds = WidgetInWidgetArea::getWidgetIdsFromArea($area->id);
$widgets = Widget::where('language', LaravelLocalization::getCurrentLocale())
->paginate(25);
return view('admin.widgets.area.edit', ['area' => $area]);
return view('admin.widgets.area.edit', [
'area' => $area,
'widgets' => $widgets,
'associatedWidgetIds' => $associatedWidgetIds
]);
}
/**
* @param EditWidgetAreaRequest $request
* @param $id
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postEdit(EditWidgetAreaRequest $request, $id)
{
try {
@@ -29,13 +51,14 @@ class EditWidgetArea extends Controller
$area->name = $request->name;
$area->description = $request->description;
$area->timestamps = true;
$area->save();
// fire event with new widget area
Event::fire(new \App\Events\EditWidgetArea($area));
return redirect()
->route('widgetareas.edit', ['id' => $id])
->route('widgetareas.overview')
->with('success', trans('admin/widgetAreas.editSuccessfull'));
}
@@ -55,6 +78,13 @@ class EditWidgetArea extends Controller
return $this->invalidArea();
}
// check if widget area is deletable
if (!$area->deletable) {
return redirect()
->back()
->with('error', trans('admin/widgetAreas.notDeletableArea'));
}
// delete area
$area->delete();
@@ -1,8 +1,8 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Widgets\Areas;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests;
use App\Models\WidgetArea;
@@ -1,16 +1,16 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Widgets;
use App\Events\AssignWidget;
use App\Events\RemoveWidgetFromArea;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
use App\Models\Widget;
use App\Models\WidgetArea;
use App\Models\WidgetInWidgetArea;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Event;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class AssociateWidget extends Controller
{
@@ -18,7 +18,8 @@ class AssociateWidget extends Controller
{
$area = WidgetArea::findOrFail($widgetArea);
$associatedWidgetIds = WidgetInWidgetArea::getWidgetIdsFromArea($area->id);
$widgets = Widget::paginate(25);
$widgets = Widget::where('language', LaravelLocalization::getCurrentLocale())
->paginate(25);
return view('admin.widgets.association', [
'widgetArea' => $area,
@@ -44,7 +45,7 @@ class AssociateWidget extends Controller
Event::fire(new AssignWidget($widget, $widgetArea));
return redirect()
->route('widgets.associate', ['widgetArea' => $widgetAreaId])
->back()
->with('success', trans('admin/widgets.successfullyAssociated'));
}
@@ -1,15 +1,12 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Widgets;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Controllers\Admin\Controller;
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
{
@@ -64,7 +61,7 @@ class CreateNewWidget extends Controller
// redirect with success notification
return redirect()
->route('widgets.new', ['type' => $type])
->route('widgets.overview')
->with('success', trans('admin/widgets.successfullyCreated'));
}
@@ -1,6 +1,7 @@
<?php
namespace App\Http\Controllers\Admin;
namespace App\Http\Controllers\Admin\Widgets;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\EditWidgetRequest;
use App\Models\Widget;
use App\Widgets\Exceptions\MissingParameterException;
@@ -8,15 +9,31 @@ use Illuminate\Support\Facades\Event;
class EditWidget extends Controller
{
/**
* Render edit form
*
* @param $id
*
* @return mixed
*/
public function getEdit($id)
{
$widget = Widget::findOrFail($id);
$widget->settings = json_decode($widget->settings);
$presenter = call_user_func([$widget->widget_type_handler, 'getPresenter']);
return call_user_func([$presenter, 'renderEditForm'], $widget);
}
/**
* Save changes into database
*
* @param EditWidgetRequest $request
* @param $widget
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postEdit(EditWidgetRequest $request, $widget)
{
// create new widget
@@ -24,11 +41,9 @@ class EditWidget extends Controller
// update name
$widget->name = $request->name;
// save description if available
if (isset($request->description)) {
$widget->description = $request->description;
}
$widget->container_class = $request->containerClass;
$widget->container_id = empty($request->containerId) ? null : $request->containerId;
$widget->description = $request->description;
// try to save this widget
try {
@@ -53,6 +68,33 @@ class EditWidget extends Controller
->with('success', trans('admin/widgets.successfullyEdited'));
}
/**
* Deletes widget
*
* @param $id
*
* @return \Illuminate\Http\RedirectResponse
*/
public function deleteWidget($id)
{
// create new widget
$widget = Widget::findOrFail($id);
// check if widget area is deletable
if (!$widget->deletable) {
return redirect()
->back()
->with('error', trans('admin/widgets.notDeletable'));
}
$widget->delete();
// redirect with success notification
return redirect()
->route('widgets.overview')
->with('success', trans('admin/widgets.successfullyDeleted'));
}
private function invalidWidget($error)
{
return redirect()
@@ -0,0 +1,17 @@
<?php
namespace App\Http\Controllers\Admin\Widgets;
use App\Http\Controllers\Admin\Controller;
use App\Models\Widget;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class WidgetsOverview extends Controller
{
public function getOverview()
{
$widgets = Widget::where('language', LaravelLocalization::getCurrentLocale())
->paginate(25);
return view('admin.widgets.overview', ['widgets' => $widgets]);
}
}
@@ -1,14 +0,0 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Widget;
class WidgetsOverview extends Controller
{
public function getOverview()
{
$widgets = Widget::paginate(25);
return view('admin.widgets.overview', ['widgets' => $widgets]);
}
}
+6 -6
View File
@@ -2,8 +2,8 @@
namespace App\Http\Controllers\Visitor;
use App\Helpers\PageRenderer;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\Content;
use Illuminate\Support\Facades\Auth;
@@ -47,13 +47,13 @@ class ContentPage extends Controller
{
// test if loaded page is visible or not
if ($page->status == Content::STATUS_PROTECTED && !Auth::user()) {
throw new \Exception('Cannot access protected resources');
// throw new \Exception('Cannot access protected resources');
abort(404);
}
// get handler
$handler = new $page->module_handler;
// add one new "view" for page
$page->view();
// render page
return $handler->render($page, '');
return PageRenderer::render($page);
}
}
+4 -4
View File
@@ -17,10 +17,10 @@ class Homepage extends ContentPage
}
// render page
try {
// try {
return $this->renderPage($page);
} catch (\Exception $e) {
return view('errors.homepageNotAvailable', ['exception' => $e, 'reason' => 'exception']);
}
// } catch (\Exception $e) {
// return view('errors.homepageNotAvailable', ['exception' => $e, 'reason' => 'exception']);
// }
}
}
+32 -13
View File
@@ -2,7 +2,16 @@
namespace App\Http;
use App\Http\Middleware\TemplatePathInstaller;
use App\Http\Middleware\WidgetInstaller;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRedirectFilter;
use Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRoutes;
use Mcamara\LaravelLocalization\Middleware\LocaleSessionRedirect;
class Kernel extends HttpKernel
{
@@ -14,7 +23,12 @@ class Kernel extends HttpKernel
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
LocaleSessionRedirect::class,
LaravelLocalizationRedirectFilter::class,
Middleware\EncryptCookies::class,
StartSession::class,
ShareErrorsFromSession::class,
Middleware\VerifyCsrfToken::class
];
/**
* The application's route middleware groups.
@@ -22,14 +36,16 @@ class Kernel extends HttpKernel
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
'web' => [
CheckForMaintenanceMode::class,
],
'api' => [
'admin' => [
Middleware\Authenticate::class,
Middleware\AdminMenuRegistrator::class,
TemplatePathInstaller::class,
WidgetInstaller::class,
],
'api' => [
'throttle:60,1',
],
];
@@ -41,10 +57,13 @@ class Kernel extends HttpKernel
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'onlyAdmin' => \App\Http\Middleware\RequireAdminRole::class,
'adminMenu' => \App\Http\Middleware\AdminMenuRegistrator::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'auth' => Middleware\Authenticate::class,
'onlyAdmin' => Middleware\RequireAdminRole::class,
'adminMenu' => Middleware\AdminMenuRegistrator::class,
'guest' => Middleware\RedirectIfAuthenticated::class,
'throttle' => ThrottleRequests::class,
'localize' => LaravelLocalizationRoutes::class,
'localizationRedirect' => LaravelLocalizationRedirectFilter::class,
'localeSessionRedirect' => LocaleSessionRedirect::class
];
}
+13 -4
View File
@@ -3,7 +3,9 @@
namespace App\Http\Middleware;
use App\Handlers\Handler;
use App\Models\Module;
use Closure;
use Illuminate\Support\Facades\Log;
class AdminMenuRegistrator
{
@@ -19,20 +21,27 @@ class AdminMenuRegistrator
{
// register menu only of logged users
if (!\Auth::check()) {
return;
return $next($request);
}
// create menu
$user = \Auth::user();
Handler::registerAdminMenu($user);
$modules = \Module::enabled();
$modules = Module::where('enabled', true)
->get();
// iterate over all enabled modules
foreach ($modules as $key => $module) {
$handler = config($module->getName() . '.handler');
if (!is_callable([$module->handler, 'registerAdminMenu']))
continue;
// try to register menus
call_user_func([$handler, 'registerAdminMenu'], $user);
try {
call_user_func([$module->handler, 'registerAdminMenu'], $user);
} catch (\Exception $e) {
Log::debug('Error in ' . $module->handler . '::registerAdminMenu: ' . $e->getMessage());
}
}
return $next($request);
+3 -1
View File
@@ -23,7 +23,9 @@ class Authenticate
return response('Unauthorized.', 401);
}
return redirect()->route('login');
return redirect()
->route('login')
->with('redirectTo', $request->fullUrl());
}
return $next($request);
@@ -0,0 +1,31 @@
<?php
namespace App\Http\Middleware;
use App\Handlers\Registrators\TemplateRegistrator;
use Closure;
use Illuminate\Support\Facades\App;
class TemplatePathInstaller
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
/**
* @var $registator TemplateRegistrator
*/
$registator = App::make('registerTemplateDir');
// install registered widgets
$registator->saveTemplates();
return $next($request);
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace App\Http\Middleware;
use App\Handlers\Registrators\WidgetRegistrator;
use Closure;
use Illuminate\Support\Facades\App;
class WidgetInstaller
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
/**
* @var $registator WidgetRegistrator
*/
$registator = App::make('registerWidget');
// install registered widgets
$registator->installWidgets();
return $next($request);
}
}
@@ -12,15 +12,14 @@ class CreateNewContentRequest extends Request
public function rules()
{
return [
'titlePhoto' => 'image',
'title' => 'required',
'url' => 'required|unique:contents,url',
'template' => 'required|exists:templates,template_name',
'status' => 'required|in:draft,protected,public',
'title_photo' => 'exists:files,id',
'parentPage' => 'exists:contents,id',
'published_from' => 'date',
'published_to' => 'date',
'titlePhoto' => 'image',
'title' => 'required',
'url' => 'required|unique:contents,url',
'status' => 'required|in:draft,protected,public',
'title_photo' => 'exists:files,id',
'parentPage' => 'exists:contents,id',
'publishedFrom' => 'date',
'publishedTo' => 'date',
];
}
}
+7 -8
View File
@@ -18,14 +18,13 @@ class EditContentRequest extends Request
$statuses = implode(',', $statuses);
return [
'title' => 'required',
'url' => 'required|unique:contents,url,' . $this->id,
'template' => 'required|exists:templates,template_name',
'published_from' => 'date',
'published_to' => 'date',
'title_photo' => 'exists:files,id',
'status' => 'required|in:' . $statuses,
'parentPage' => 'exists:contents,id'
'title' => 'required',
'url' => 'required|unique:contents,url,' . $this->id,
'publishedFrom' => 'date',
'publishedTo' => 'date',
'title_photo' => 'exists:files,id',
'status' => 'required|in:' . $statuses,
'parentPage' => 'exists:contents,id'
];
}
}
+1 -2
View File
@@ -12,8 +12,7 @@ class EditTemplateRequest extends Request
public function rules()
{
return [
'name' => 'required|max:128',
'templateContent' => 'required'
'name' => 'required|max:128',
];
}
}
+2 -1
View File
@@ -12,7 +12,8 @@ class EditWidgetRequest extends Request
public function rules()
{
return [
'name' => 'required'
'name' => 'required',
'containerId' => 'unique:widgets,container_id,'.$this->id
];
}
}
+2 -1
View File
@@ -12,7 +12,8 @@ class NewWidgetRequest extends Request
public function rules()
{
return [
'name' => 'required'
'name' => 'required',
'containerId' => 'unique:widgets,container_id'
];
}
}
+6 -2
View File
@@ -4,7 +4,7 @@ namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest
class Request extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
@@ -13,7 +13,11 @@ abstract class Request extends FormRequest
*/
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
}
-14
View File
@@ -1,14 +0,0 @@
<?php
namespace App\Http\Requests;
class UploadFileRequest extends UploadRequest
{
/**
* @internal param array $rules
*/
protected function setRules()
{
$this->rules = ['file' => 'required'];
}
}
+49 -249
View File
@@ -4,274 +4,74 @@
* This routing groups is used for routing along public part of website
*/
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
Route::pattern('id', '\d+');
Route::pattern('url', '[0-9\-a-z]+');
/*******************************************************************************/
/**
* This route group serves to handle request in admin
*/
Route::group([
'middleware' => ['web', 'auth', 'adminMenu'],
'namespace' => 'Admin',
'prefix' => 'admin'
'prefix' => LaravelLocalization::setLocale(),
], function () {
/**
* This route group serves to handle request in admin
*/
Route::group([
'middleware' => ['admin'],
'namespace' => 'Admin',
'prefix' => 'admin'
], function () {
// these routes are available only for user with role admin
Route::group(['middleware' => 'onlyAdmin'], function () {
// display form for creating new user
Route::get('users/new', 'CreateNewUser@getNewUser')
->name('users.new');
// include all routes in routes/admin subfolder
$files = ['contents', 'fileManager', 'settings', 'templates', 'users', 'widgets'];
foreach ($files as $file) {
require_once __DIR__ . DIRECTORY_SEPARATOR . 'routes' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR . $file . '.php';
}
// POST methods
// display form for creating new user
Route::post('users/new', 'CreateNewUser@postRegistration')
->name('users.newPost');
// display dashboard with some usefull information
Route::get('/', 'Dashboard\Dashboard@getIndex')
->name('admin.dashboard');
// display form for edit of existing user
Route::get('users/edit/{id}', 'EditUser@getEditExistingUser')
->name('users.edit');
// list of all actions
Route::get('actions', 'ActionLog\Overview@getOverview')
->name('log.overview');
// form for adding new custom field
Route::get('customfields/new', 'CreateNewCustomField@getNew')
->name('customfields.new');
// search form with results
Route::get('search', 'Search@getSearch')
->name('search');
// form for editing custom field
Route::get('customfields/edit/{id}', 'EditCustomField@getEditCustomField')
->name('customfields.edit');
// form for adding new custom field
Route::post('customfields/new', 'CreateNewCustomField@postNew')
->name('customfields.newPost');
// form for editing custom field
Route::post('customfields/edit/{id}', 'EditCustomField@postEditCustomField')
->name('customfields.editPost');
Route::get('customfields/delete/{id}', 'EditCustomField@deleteCustomField')
->name('customfields.delete');
Route::get('templates/overview/path/{id}', 'TemplateOverview@getPath')
->name('templates.overview');
Route::post('templates/copy', 'CopyTemplate@createCopy')
->name('templates.postCopy');
// Route::get('templates/new/{pathId}', 'TemplateOverview@getPath')
// ->name('templates.new');
Route::get('templates/edit/{id}', 'EditTemplate@getEdit')
->name('templates.edit');
Route::post('templates/edit/{id}', 'EditTemplate@postEdit')
->name('templates.postEdit');
// logout method
Route::get('logout', 'Login@logout')
->name('logout');
});
// list of all static pages
Route::get('content/overview/{moduleId?}/{status?}', 'ContentOverview@getOverview')
->name('content.overview');
/**************************************************************************************/
// form for creating new static page
Route::get('content/new/{moduleId}', 'CreateNewContent@getNew')
->name('content.new');
/**
* This section must be specified as last one
*/
// form for editing existing static page
Route::get('content/edit/{id}', 'EditContent@getEdit')
->name('content.edit');
Route::group(['middleware' => ['web']], function () {
// post method for creating new static page
Route::post('content/new/{moduleId}', 'CreateNewContent@postNew')
->name('content.newPost');
// Homepage
Route::get('/', 'Visitor\Homepage@getIndex')
->name('page.index');
// post method for creating new static page
Route::post('content/edit/{id}', 'EditContent@postEdit')
->name('content.editPost');
// display login form
Route::get('admin/login', 'Admin\Login@getLogin')
->name('loginForm');
// routes for quick actions
// handle login
Route::post('admin/login', 'Admin\Login@postLogin')
->name('login');
// change status of page (protected, public or draft)
Route::get('content/status/{id}/{status}', 'EditContent@changeStatus')
->name('content.changeStatus');
// route for sitemap
Route::get('sitemap.xml', 'Sitemap@getMap')
->name('sitemap');
// set homepage
Route::get('content/homepage/{id}', 'EditContent@setHomepage')
->name('content.setHomepage');
// delete page
Route::get('content/delete/{id}', 'EditContent@deletePage')
->name('content.delete');
// these routes are available for all logged (authenticated) users
// display dashboard with some usefull information
Route::get('/', 'Dashboard@getIndex')
->name('admin.dashboard');
// display user detail in admin
Route::get('users/detail/{id?}', 'UserDetail@getDetail')
->name('users.detail');
// method for saving edited data of user
Route::post('users/edit/{id}', 'EditUser@postEdit')
->name('users.editPost');
// display list of all users registered into our system
Route::get('users/overview/{state?}/{perPage?}', 'UsersOverview@getOverview')
->name('users.overview');
// history of changes for specified page
Route::get('history/{id}', 'History@getOverview')
->name('content.history');
// history of changes for specified page
Route::get('history/{revision}/{id}', 'History@getDiff')
->name('history.diff');
// list of all actions
Route::get('actions', 'ActionLogOverview@getOverview')
->name('log.overview');
// routes for widget areas
Route::get('widgets/areas/overview', 'WidgetAreaOverview@getOverview')
->name('widgetareas.overview');
// form for new widget area
Route::get('widgets/areas/new', 'CreateNewWidgetArea@getNew')
->name('widgetareas.new');
// form for new widget area
Route::post('widgets/areas/new', 'CreateNewWidgetArea@postNew')
->name('widgetareas.postNew');
// edit form for widget area
Route::get('widgets/areas/edit/{id}', 'EditWidgetArea@getEdit')
->name('widgetareas.edit');
Route::post('widgets/areas/edit/{id}', 'EditWidgetArea@postEdit')
->name('widgetareas.postEdit');
// edit form for widget area
Route::get('widgets/areas/delete/{id}', 'EditWidgetArea@deleteArea')
->name('widgetareas.delete');
// list of all installed widget types
Route::get('widgets/overview', 'WidgetsOverview@getOverview')
->name('widgets.overview');
// create new instance of widget of given type
Route::get('widgets/new/{type}', 'CreateNewWidget@getNew')
->name('widgets.new');
Route::post('widgets/new/{type}', 'CreateNewWidget@postNew')
->name('widgets.postNew');
// edit widget settings
Route::get('widgets/edit/{id}', 'EditWidget@getEdit')
->name('widgets.edit');
Route::post('widgets/edit/{id}', 'EditWidget@postEdit')
->name('widgets.postEdit');
// display form for association of widget and widget area
Route::get('widgets/associate/{widgetArea}', 'AssociateWidget@getList')
->name('widgets.associate');
Route::get('widgets/deassociate/{widgetId}/{widgetArea}', 'AssociateWidget@deleteAssociation')
->name('widgets.deleteAssociation');
Route::get('widgets/associate/{widgetId}/{widgetArea}', 'AssociateWidget@makeAssociation')
->name('widgets.makeAssociation');
// uploader methods
Route::get('directories/new/{id?}', 'CreateNewDirectory@getNew')
->name('upload.newDirectory');
Route::get('directories/edit/{id}', 'EditDirectory@getEdit')
->name('upload.editDirectory');
Route::post('directories/edit/{id}', 'EditDirectory@postEdit')
->name('upload.postEditDirectory');
Route::get('files/overview/{id?}/{type?}/{subtype?}', 'UploadedFilesOverview@getOverview')
->name('upload.overview');
route::post('directories/new', 'CreateNewDirectory@postNew')
->name('upload.postNewDirectory');
Route::get('upload/detail/{id}', 'EditUploadedFile@getDetail')
->name('upload.detail');
Route::post('upload/detail/{id}', 'EditUploadedFile@postEdit')
->name('upload.postEdit');
Route::get('upload/delete/{id}', 'EditUploadedFile@deleteFile')
->name('upload.delete');
// uploader methods
Route::post('upload/file', 'UploadFile@postFile')
->name('upload.postFile');
Route::post('upload/image', 'UploadFile@postImage')
->name('upload.postImage');
// form with settings
Route::get('settings', 'Settings@getOverview')
->name('settings.overview');
Route::post('settings', 'Settings@saveSettings')
->name('settings.save');
Route::get('search', 'Search@getSearch')
->name('search');
// custom fields
// ------------------------------
// list of all custom fields
Route::get('customfields/overview', 'CustomFieldsOverview@getOverview')
->name('customfields.overview');
// logout method
Route::get('logout', function () {
// remove user information
\Auth::logout();
// redirect to login form with info about successfull logout
return redirect()
->route('login')
->with('success', trans('admin/common.logoutSuccessfull'));
})
->name('logout');
});
/**************************************************************************************/
/**
* This section must be specified as last one
*/
Route::group(['middleware' => ['web']], function () {
Route::get('/', 'Visitor\Homepage@getIndex')
->name('page.index');
// display login form
Route::get('admin/login', function () {
return view('admin.loginForm.form');
})
->name('loginForm');
// handle login
Route::post('admin/login', 'Admin\Login@postLogin')
->name('login');
// route for sitemap
Route::get('sitemap.xml', 'Sitemap@getMap')
->name('sitemap');
// route for all content pages. This rule must be specified last (because it matches every route)
Route::get('{url}', 'Visitor\ContentPage@getPage')
->name('page.content');
// route for all content pages. This rule must be specified last (because it matches every route)
Route::get('{url}', 'Visitor\ContentPage@getPage')
->name('page.content');
});
});
+42
View File
@@ -0,0 +1,42 @@
<?php
Route::group(['namespace' => 'Contents'], function () {
// list of all static pages
Route::get('content/overview/{moduleId?}/{status?}', 'ContentOverview@getOverview')
->name('content.overview');
// form for creating new static page
Route::get('content/new/{moduleId}', 'CreateNewContent@getNew')
->name('content.new');
// form for editing existing static page
Route::get('content/edit/{id}', 'EditContent@getEdit')
->name('content.edit');
// post method for creating new static page
Route::post('content/new/{moduleId}', 'CreateNewContent@postNew')
->name('content.newPost');
// post method for creating new static page
Route::post('content/edit/{id}', 'EditContent@postEdit')
->name('content.editPost');
// change status of page (protected, public or draft)
Route::get('content/status/{id}/{status}', 'EditContent@changeStatus')
->name('content.changeStatus');
// set homepage
Route::get('content/homepage/{id}', 'EditContent@setHomepage')
->name('content.setHomepage');
// delete page
Route::get('content/delete/{id}', 'EditContent@deletePage')
->name('content.delete');
// history of changes for specified page
Route::get('history/{id}', 'History@getOverview')
->name('content.history');
// history of changes for specified page
Route::get('history/{revision}/{id}', 'History@getDiff')
->name('history.diff');
});
+32
View File
@@ -0,0 +1,32 @@
<?php
Route::group(['namespace' => 'FileManager'], function () {
Route::get('files/overview/{id?}/{type?}/{subtype?}', 'UploadedFilesOverview@getOverview')
->name('upload.overview');
// uploader methods
Route::get('directories/new/{id?}', 'CreateNewDirectory@getNew')
->name('upload.newDirectory');
Route::get('directories/edit/{id}', 'EditDirectory@getEdit')
->name('upload.editDirectory');
Route::post('directories/edit/{id}', 'EditDirectory@postEdit')
->name('upload.postEditDirectory');
route::post('directories/new', 'CreateNewDirectory@postNew')
->name('upload.postNewDirectory');
Route::get('upload/detail/{id}', 'EditUploadedFile@getDetail')
->name('upload.detail');
Route::post('upload/detail/{id}', 'EditUploadedFile@postEdit')
->name('upload.postEdit');
Route::get('upload/delete/{id}', 'EditUploadedFile@deleteFile')
->name('upload.delete');
// uploader methods
Route::post('upload', 'UploadFile@postFile')
->name('upload.postFile');
});
+7
View File
@@ -0,0 +1,7 @@
<?php
// form with settings
Route::get('settings', 'Settings@getOverview')
->name('settings.overview');
Route::post('settings', 'Settings@saveSettings')
->name('settings.save');
+15
View File
@@ -0,0 +1,15 @@
<?php
// these routes are available only for user with role admin
Route::group(['middleware' => 'onlyAdmin', 'namespace' => 'Templates'], function () {
Route::get('templates/overview/path/{id}', 'TemplateOverview@getPath')
->name('templates.overview');
Route::post('templates/copy', 'CopyTemplate@createCopy')
->name('templates.postCopy');
Route::get('templates/edit/{id}', 'EditTemplate@getEdit')
->name('templates.edit');
Route::post('templates/edit/{id}', 'EditTemplate@postEdit')
->name('templates.postEdit');
});
+27
View File
@@ -0,0 +1,27 @@
<?php
Route::group(['namespace' => 'Users'], function () {
// display form for creating new user
Route::get('users/new', 'CreateNewUser@getNewUser')
->name('users.new');
// POST methods
// display form for creating new user
Route::post('users/new', 'CreateNewUser@postRegistration')
->name('users.newPost');
// display form for edit of existing user
Route::get('users/edit/{id}', 'EditUser@getEditUser')
->name('users.edit');
// display user detail in admin
Route::get('users/detail/{id?}', 'UserDetail@getDetail')
->name('users.detail');
// method for saving edited data of user
Route::post('users/edit/{id}', 'EditUser@postEdit')
->name('users.editPost');
// display list of all users registered into our system
Route::get('users/overview/{state?}/{perPage?}', 'UsersOverview@getOverview')
->name('users.overview');
});
+60
View File
@@ -0,0 +1,60 @@
<?php
// routes for widget areas
Route::group(['namespace' => 'Widgets'], function () {
// list of all installed widget types
Route::get('widgets/overview', 'WidgetsOverview@getOverview')
->name('widgets.overview');
// create new instance of widget of given type
Route::get('widgets/new/{type}', 'CreateNewWidget@getNew')
->name('widgets.new');
Route::post('widgets/new/{type}', 'CreateNewWidget@postNew')
->name('widgets.postNew');
// edit widget settings
Route::get('widgets/edit/{id}', 'EditWidget@getEdit')
->name('widgets.edit');
// delete widget settings
Route::get('widgets/delete/{id}', 'EditWidget@deleteWidget')
->name('widgets.delete');
Route::post('widgets/edit/{id}', 'EditWidget@postEdit')
->name('widgets.postEdit');
// display form for association of widget and widget area
Route::get('widgets/associate/{widgetArea}', 'AssociateWidget@getList')
->name('widgets.associate');
Route::get('widgets/deassociate/{widgetId}/{widgetArea}', 'AssociateWidget@deleteAssociation')
->name('widgets.deleteAssociation');
Route::get('widgets/associate/{widgetId}/{widgetArea}', 'AssociateWidget@makeAssociation')
->name('widgets.makeAssociation');
Route::group(['namespace' => 'Areas'], function () {
Route::get('widgets/areas/overview', 'WidgetAreaOverview@getOverview')
->name('widgetareas.overview');
// form for new widget area
Route::get('widgets/areas/new', 'CreateNewWidgetArea@getNew')
->name('widgetareas.new');
// form for new widget area
Route::post('widgets/areas/new', 'CreateNewWidgetArea@postNew')
->name('widgetareas.postNew');
// edit form for widget area
Route::get('widgets/areas/edit/{id}', 'EditWidgetArea@getEdit')
->name('widgetareas.edit');
Route::post('widgets/areas/edit/{id}', 'EditWidgetArea@postEdit')
->name('widgetareas.postEdit');
// edit form for widget area
Route::get('widgets/areas/delete/{id}', 'EditWidgetArea@deleteArea')
->name('widgetareas.delete');
});
});
-1
View File
@@ -22,7 +22,6 @@ class LogDeleteContent extends Logger
'id' => $event->page->id,
'url' => $event->page->url,
'title' => $event->page->title,
'revision' => $event->revision
];
$this->saveLog($parameters);
+85
View File
@@ -0,0 +1,85 @@
<?php
namespace App\MenuPresenters;
use Pingpong\Menus\MenuItem;
use Pingpong\Menus\Presenters\Presenter;
class MetismenuPresenter extends Presenter
{
/**
* {@inheritdoc }
*/
public function getOpenTagWrapper()
{
return PHP_EOL . '<ul class="nav metismenu" id="sidebar-menu">' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getCloseTagWrapper()
{
return PHP_EOL . '</ul>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getMenuWithoutDropdownWrapper($item)
{
return '<li' . $this->getActiveState($item) . '><a href="' . $item->getUrl() . '">' . $item->getIcon() . ' ' . $item->title . '</a></li>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getActiveState(MenuItem $item)
{
if ($item->isDivider()) {
return null;
}
$active = ' class="active"';
if (empty($item->getChilds())) {
// for direct menu input return if page is active
return \Request::is($item->getRequest()) ? $active : null;
} else {
// on nested menu inputs loop over children and in case any of them is active, mark active also root level
foreach ($item->getChilds() as $child) {
if ($this->getActiveState($child)) {
return $active;
}
}
}
return null;
}
/**
* {@inheritdoc }
*/
public function getDividerWrapper()
{
return '<li class="divider"></li>' . PHP_EOL;
}
public function getMultiLevelDropdownWrapper($item)
{
return $this->getMenuWithDropDownWrapper($item);
}
/**
* {@inheritdoc }
*/
public function getMenuWithDropDownWrapper($item)
{
$active = $this->getActiveState($item);
return '<li' . $active . '>
<a href="#">' . $item->getIcon() . ' ' . $item->title . ' <i class="fa arrow"></i></a>
<ul>
' . $this->getChildMenuItems($item) . '
</ul>
</li>' . PHP_EOL;
}
}
@@ -0,0 +1,61 @@
<?php
namespace App\MenuPresenters;
use Pingpong\Menus\MenuItem;
use Pingpong\Menus\Presenters\Presenter;
class ProfileMenuPresenter extends Presenter
{
/**
* {@inheritdoc }
*/
public function getOpenTagWrapper()
{
return PHP_EOL . '<div class="dropdown-menu profile-dropdown-menu">' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getCloseTagWrapper()
{
return PHP_EOL . '</div>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getMenuWithoutDropdownWrapper($item)
{
return '<a href="' . $item->getUrl() . '" class="dropdown-item">' . $item->getIcon() . ' ' . $item->title . '</a>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getActiveState(MenuItem $item)
{
return null;
}
/**
* {@inheritdoc }
*/
public function getDividerWrapper()
{
return '<div class="dropdown-divider"></div>' . PHP_EOL;
}
public function getMultiLevelDropdownWrapper($item)
{
return null;//$this->getMenuWithDropDownWrapper($item);
}
/**
* {@inheritdoc }
*/
public function getMenuWithDropDownWrapper($item)
{
return null;
}
}
+198 -27
View File
@@ -3,18 +3,27 @@
namespace App\Models;
use App\Enumerations\ContentStatuses;
use App\Http\Requests\Request;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Modules\Categories\Entities\Category;
/**
* Class Content
*/
class Content extends Model
{
use SoftDeletes;
public $timestamps = true;
protected $fillable = [
'user_id',
'parent_id',
'category_id',
'language',
'module_handler',
'published_from',
'published_to',
@@ -30,20 +39,42 @@ class Content extends Model
'status'
];
protected $guarded = [];
protected $subpages = [];
protected $foundSubpages = [];
protected $subpagesInit = false;
const STATUS_DELETED = 'deleted';
const STATUS_DRAFT = 'draft';
const STATUS_PROTECTED = 'protected';
const STATUS_PUBLIC = 'public';
/**
* @var File
*/
private $file;
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->file = App::make(File::class);
}
/**
* Getter for query with setup filter for non-deleted and non-draft pages
*/
public function getPageQuery()
{
return Content::where('status', '!=', Content::STATUS_DELETED)
->where('status', '!=', Content::STATUS_DRAFT);
return Content::where('status', '!=', Content::STATUS_DRAFT)
->select('contents.*')
->with('author')
->join('modules', 'modules.handler', '=', 'contents.module_handler')
->where(function ($query) {
$query->where('published_from', '<', Carbon::now())
->orWhereNull('published_from');
})
->where(function ($query) {
$query->where('published_to', '>', Carbon::now())
->orWhereNull('published_to');
})
->where('language', LaravelLocalization::getCurrentLocale())
->where('modules.enabled', true);
}
/**
@@ -74,24 +105,33 @@ class Content extends Model
/**
* Get list of all subpages
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
* @param bool $orderBy
* @param bool $orderDirection
*
* @return array
*/
public function subpages()
public function subpages($orderBy = false, $orderDirection = false)
{
if (!$this->subpagesInit) {
$this->subpages = $this->getPageQuery()
->where('parent_id', $this->id)
->get();
$subpages = $this->getPageQuery()
->where('contents.parent_id', $this->id);
if ($orderBy) {
$subpages->orderBy($orderBy, $orderDirection ? $orderDirection : 'ASC');
}
$subpages = $subpages->get();
// convert JSON settings into stdClass
foreach ($this->subpages as $subpage) {
$subpage->module_settings = json_decode($subpage->module_settings);
foreach ($subpages as $i => $subpage) {
$subpages[$i]->module_settings = json_decode($subpage->module_settings);
}
$this->subpagesInit = true;
$this->foundSubpages = $subpages;
}
return $this->subpages;
return $this->foundSubpages;
}
/**
@@ -158,15 +198,18 @@ class Content extends Model
* @param bool $handler
* @param bool $status
* @param bool $joinAuthor
* @param bool $joinParent
*
* @return
*/
public function getOverview($handler = false, $status = false, $joinAuthor = false, $joinParent = false)
{
$query = DB::table('contents')
->select('contents.*', 'modules.name AS module_name')
->where('contents.status', '<>', self::STATUS_DELETED)
->select('contents.*', 'modules.name AS module_name', 'modules.id AS module_id')
->join('modules', 'modules.handler', '=', 'contents.module_handler')
->whereNull('contents.deleted_at')
->where('contents.language', LaravelLocalization::getCurrentLocale())
->where('modules.enabled', 1)
->orderBy('created_at', 'DESC');
// filter results using handler
@@ -202,7 +245,7 @@ class Content extends Model
* @param array $request
* @param string $revisionId
*
* @return int number of changed columns
* @return array revisionID and number of changed columns
*/
public function updateWithHistory(array $fields, array $request, $revisionId = null)
{
@@ -240,18 +283,7 @@ class Content extends Model
if (trim($fieldValue) != $request[$fieldRequest]) {
// setup history object
$history = [
'user_id' => \Auth::user()->id,
'content_id' => $this->id,
'edit_batch' => $revisionId,
'column' => $fieldRequest,
'old_value' => $fieldValue,
'new_value' => $request[$fieldRequest]
];
// save history
ContentHistory::create($history);
$this->saveHistory($revisionId, $fieldRequest, $fieldValue, $request);
// save change into database
if ($commonField) {
@@ -274,6 +306,99 @@ class Content extends Model
return [$revisionId, $changed];
}
/**
* Upload and set some image as title photo
*
* @param Request $request
*/
public function uploadTitlePhoto(Request $request)
{
if ($request->hasFile('titlePhoto')) {
return $this->file->upload($request->file('titlePhoto'), $request);
}
return null;
}
/**
* Upload and assign files to newly created content page
*
* @param Request $request
* @param null $revisionId
*
* @return int
*/
public function uploadRelatedFiles(Request $request, $revisionId = null)
{
$files = $request->all()['files'];
$changed = 0;
// check if any file was removed
if ($revisionId) {
$changed += $this->removeRelatedFiles($revisionId, $request);
}
// allow uploading only on created pages
if (!$this->id || !$files[0]) {
return $changed;
}
// find or create new directory for files assigned to content
$directory = Directory::firstOrCreate([
'name' => '.content_files',
'hidden' => true
]);
$request->directoryId = $directory->id;
foreach ($files as $file) {
if (!$file) {
continue;
}
$uploaded = $this->file->upload($file, $request);
// add assignement
ContentHasFile::create([
'file_id' => $uploaded['id'],
'content_id' => $this->id
]);
if ($revisionId) {
$this->saveHistory($revisionId, 'file', null, ['file' => $uploaded['file']->getClientOriginalName()]);
}
$changed++;
}
return $changed;
}
/**
* Delete files from association
*
* @param $revisionId
* @param $request
*
* @return int
*/
private function removeRelatedFiles($revisionId, $request)
{
$files = array_keys((array)$request->keepAssigned);
$allFiles = $this->files()
->whereNotIn('id', $files)
->get();
foreach ($allFiles as $file) {
$this->saveHistory($revisionId, 'file', $file->original_filename, ['file' => null]);
ContentHasFile::where('content_id', $this->id)
->where('file_id', $file->id)
->delete();
}
return count($allFiles);
}
/**
* Mark relationship with its historical records
*
@@ -293,4 +418,50 @@ class Content extends Model
{
return $this->belongsTo('App\Models\User', 'user_id');
}
/**
* Related files to content page
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function files()
{
return $this->belongsToMany(File::class, 'contents_has_files');
}
public function category()
{
return $this->belongsTo(Category::class);
}
/**
* Save history entry into database
*
* @param $revisionId
* @param $fieldRequest
* @param $fieldValue
* @param $request
*/
private function saveHistory($revisionId, $fieldRequest, $fieldValue, $request)
{ // setup history object
$history = [
'user_id' => \Auth::user()->id,
'content_id' => $this->id,
'edit_batch' => $revisionId,
'column' => $fieldRequest,
'old_value' => $fieldValue,
'new_value' => $request[$fieldRequest]
];
// save history
ContentHistory::create($history);
}
public function view()
{
$this->timestamps = false;
$this->viewed++;
$this->save();
$this->timestamps = true;
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ContentHasFile extends Model
{
public $timestamps = false;
public $table = 'contents_has_files';
protected $fillable = [
'content_id',
'file_id'
];
}
+1 -1
View File
@@ -95,6 +95,6 @@ class ContentHistory extends Model
public function getDiff($change)
{
return Differ::htmlDiff($change->old_value, $change->new_value);
return Differ::htmlDiff(e($change->old_value), e($change->new_value));
}
}
+36 -1
View File
@@ -4,9 +4,13 @@ namespace App\Models;
use App\Events\UploadFile;
use App\Http\Requests\Request;
use Franzose\ClosureTable\Extensions\Str;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\File as FileFacade;
use Intervention\Image\Constraint;
use Intervention\Image\Facades\Image;
use Symfony\Component\HttpFoundation\File\File as SymphonyFile;
use Symfony\Component\HttpFoundation\File\UploadedFile;
@@ -63,6 +67,12 @@ class File extends Model
// save file into physical location (local FS)
$uploadedFile = $file->move($destination, $filename);
// is uploaded file an image?
if (Str::startsWith($uploadedFile->getMimeType(), 'image')) {
// yes, create thumbnail
$this->createThumbnail($uploadedFile);
}
// insert record into database
$id = $this->saveIntoDatabase($uploadedFile, $request, $file->getClientOriginalName());
@@ -106,7 +116,7 @@ class File extends Model
// save optional fields
$optionalFields = ['name', 'description', 'keywords', 'directoryId'];
foreach ($optionalFields as $field) {
if ($request->has($field)) {
if (isset($request->{$field}) && !empty($request->{$field})) {
$snakeField = snake_case($field);
$newFile->$snakeField = $request->$field;
@@ -118,4 +128,29 @@ class File extends Model
return $newFile->id;
}
/**
* Create thumbnail of given image
*
* @param SymphonyFile $file
*/
private function createThumbnail(SymphonyFile $file)
{
// does thumbnail directory exist?
if (!is_dir(config('app.thumbnail_path'))) {
FileFacade::makeDirectory(config('app.thumbnail_path'));
}
// get image instance
$image = Image::make(config('app.upload_path') . DIRECTORY_SEPARATOR . $file->getFilename());
// resize image and keep aspect ration
$image->resize(env('THUMBNAIL_WIDTH', 300), null, function (Constraint $constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
// save thumbnail with lower quality
$image->save(config('app.thumbnail_path') . DIRECTORY_SEPARATOR . $file->getFilename(), 75);
}
}

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