Compare commits

...

257 Commits

Author SHA1 Message Date
KodeStar
3a043e0165 Update app.php 2022-03-25 15:02:35 +00:00
KodeStar
ac37c60e1f Merge pull request #800 from xiazeyu/baidu
added Baidu and sort order by alphabet
2022-03-25 15:01:22 +00:00
S4kura0ne
937e576520 move tiles to the first 2022-03-25 01:00:07 +08:00
KodeStar
9086e9bd75 Merge pull request #794 from xiazeyu/2.x
Latest Chinese translation combined #789 and #617
2022-03-24 13:21:07 +00:00
s4kura0ne
4c90d8c87e added Baidu and sort order by alphabet 2022-03-24 09:25:30 +08:00
s4kura0ne
a4cceb3ae0 remove Baidu in searchprovides.yaml 2022-03-24 09:20:46 +08:00
s4kura0ne
90c21d700d merged old 'zh' translation, improved translation 2022-03-24 00:33:36 +08:00
s4kura0ne
15b1f3234b added translation for baidu 2022-03-24 00:23:08 +08:00
s4kura0ne
a116345d60 remove unused translation 2022-03-24 00:21:47 +08:00
s4kura0ne
2b4e6d372c remove changes in outdated SettingsSeeder.php 2022-03-24 00:19:43 +08:00
s4kura0ne
d370f2c3ee finished chinese translation 2022-03-23 10:09:18 +08:00
S4kura0ne
ade09f3b1c Merge pull request #3 from xiazeyu/master
https://github.com/xiazeyu/Heimdall/pull/2
2022-03-23 09:31:58 +08:00
s4kura0ne
80aa120086 solved Russian readme conflict 2022-03-23 09:28:39 +08:00
S4kura0ne
a5cbcaca03 Merge pull request #1 from anerg2046/2.x
Merge Chinese translate from anerg2046
2022-03-23 09:24:33 +08:00
Kode
f2bfc26c5e Update app.php 2022-03-21 21:37:44 +00:00
Kode
9f0abb6f4d Strip out invalid characters from tile background 2022-03-21 21:37:14 +00:00
KodeStar
9ca2078e7d Add app version to asset url to bust cache 2022-03-21 06:42:59 +00:00
罗翀
9e4a06999b Chinese translate
add baidu search
2022-03-21 00:53:28 +08:00
KodeStar
8b72ff0a0d Merge pull request #787 from KodeStar/2.x
Laravel shift and update defaults
2022-03-19 15:07:11 +00:00
Kode
51ddaccc16 Update defaults 2022-03-19 15:04:26 +00:00
KodeStar
4ff1a4aec4 Merge pull request #1 from KodeStar/shift-58933
Upgrade Checker
2022-03-19 14:27:44 +00:00
KodeStar
d5bd614cc6 Update Application.php 2022-03-19 14:05:01 +00:00
Shift
0f498eca75 Remove explicit deleted_at date cast 2022-03-19 13:54:34 +00:00
Shift
3dac9828c8 Convert to new helper methods
Laravel 5 added several new helper functions, including:

- `view()`
- `response()`
- `redirect()`
- `config()`
- `abort()`

Review the [helpers][1] documentation for more details.

[1]: https://laravel.com/docs/5.0/helpers
2022-03-19 13:54:34 +00:00
Shift
297c2bb30f Shift bindings
PHP 5.5.9+ adds the new static `class` property which provides the fully qualified class name. This is preferred over using strings for class names since the `class` property references are checked by PHP.
2022-03-19 13:54:33 +00:00
Shift
b1dc4d4a41 Apply Laravel coding style
Shift automatically applies the Laravel coding style - which uses the PSR-2 coding style as a base with some minor additions.

You may customize the adopted coding style by adding a [PHP CS Fixer][1] or [PHP CodeSniffer][2] config to your project root. Feel free to use [Shift's Laravel ruleset][3] to help you get started.

For more information on customizing the code style applied by Shift, [watch this short video][4].

[1]: https://github.com/FriendsOfPHP/PHP-CS-Fixer
[2]: https://github.com/squizlabs/PHP_CodeSniffer
[3]: https://gist.github.com/laravel-shift/cab527923ed2a109dda047b97d53c200
[4]: https://laravelshift.com/videos/shift-code-style
2022-03-19 13:54:32 +00:00
KodeStar
0fe6565346 Update app.php 2022-03-19 07:06:02 +00:00
KodeStar
85c68c1f46 Merge pull request #783 from xavier-GitHub76/2.x
Update app.php (French translations Fix) + version app (2.4.4)
2022-03-18 16:40:10 +00:00
Kode
fc2191b8db Fix preview image 2022-03-18 16:36:05 +00:00
xavier-GitHub76
ee36a0cfae Update app.php
Update version app to 2.4.4
2022-03-18 14:32:15 +01:00
Kode
a868a6cac1 Fix for creating tags not setting home dashboard as default 2022-03-18 10:10:00 +00:00
xavier-GitHub76
574756b236 Update app.php
French translate fix
2022-03-17 22:43:05 +01:00
Kode
f9599079e5 Update app.php 2022-03-17 19:04:39 +00:00
Kode
10afffb71d Fix test button 2022-03-17 19:03:06 +00:00
KodeStar
79d53af339 Update app.php 2022-03-17 13:42:07 +00:00
KodeStar
8cc6a9cc63 Pull missing apps on update apps list 2022-03-17 13:41:50 +00:00
KodeStar
18001fbdd0 Get app regardless of if it's enhanced (might be a search provider) 2022-03-17 12:56:51 +00:00
KodeStar
398df75865 Merge branch '2.x' 2022-03-17 11:01:43 +00:00
KodeStar
41c2983312 Add warning about http being needed in url 2022-03-17 10:55:52 +00:00
KodeStar
bd3b882b3a Squashed commit of the following:
commit e52bc9c6b2
Author: KodeStar <kodestar@gmail.com>
Date:   Thu Mar 17 10:23:15 2022 +0000

    Update supportedapps.json

commit a16233ee10
Author: KodeStar <kodestar@gmail.com>
Date:   Thu Mar 17 10:21:24 2022 +0000

    Fix for displaying svg icons correctly
2022-03-17 10:24:31 +00:00
KodeStar
e52bc9c6b2 Update supportedapps.json 2022-03-17 10:23:15 +00:00
KodeStar
a16233ee10 Fix for displaying svg icons correctly 2022-03-17 10:21:24 +00:00
Kode
5b177f1127 Merge branch '2.3' into 2.x 2022-03-16 20:16:04 +00:00
Kode
f7633b6a5f Update mix-manifest.json 2022-03-16 20:15:22 +00:00
Kode
d58e6cb560 Fix for #774 2022-03-16 20:13:16 +00:00
Kode
87fe9c1771 Move setLocale out of vie composer so it's available everywhere
Fixes #776
2022-03-16 20:07:43 +00:00
Kode
95d9e9edb9 Update app.php 2022-03-16 19:43:03 +00:00
Kode
f7b2c51f9d Fix for old apps and icon selector 2022-03-16 19:41:01 +00:00
Kode
72c70e27f2 Remove refresh button for now as update code isn't ready yet 2022-03-16 18:39:47 +00:00
Kode
becbe5ab96 More work on apps 2022-03-16 18:35:40 +00:00
Kode
f5bce95808 Add missing lang string, fixed #773 2022-03-16 18:34:48 +00:00
KodeStar
1e2b807e05 Lots of work on apps 2022-03-16 15:49:44 +00:00
Kode
ed3dbf2f14 More work on enhanced apps 2022-03-15 20:09:22 +00:00
Kode
1e35f83fed Changes to the tooltips 2022-03-15 19:08:10 +00:00
KodeStar
8499d100ff More work on apps 2022-03-15 18:19:01 +00:00
KodeStar
bdeae6a722 Add missing files 2022-03-15 11:30:21 +00:00
Kode
4c63b66dbf Initial start of replacing apps list to use github generated list 2022-03-14 15:56:36 +00:00
Kode
371f52f92e Fixes #469 2022-03-14 12:25:20 +00:00
KodeStar
6daaf94974 Add details for search providers 2022-03-14 10:34:37 +00:00
Kode
b8e5a22648 Update app.php 2022-03-14 07:56:41 +00:00
Kode
e821edf01a Fix tags url
Fixes #763
2022-03-14 07:56:02 +00:00
Kode
188316df47 Fix search using incorrect value
fixes #764
2022-03-14 07:55:26 +00:00
Kode
dd14ce8738 Update app.php 2022-03-13 19:31:30 +00:00
Kode
d8e4053ce4 Merge branch 'master' of https://github.com/linuxserver/Heimdall 2022-03-13 19:30:27 +00:00
Kode
f73b78f292 Add search providers as an editable yaml file + allow searching tiles 2022-03-13 19:30:24 +00:00
Kode
96ec1e0b08 Fixes #435 2022-03-13 16:13:36 +00:00
KodeStar
1904d9d910 Merge pull request #731 from linuxserver/dependabot/npm_and_yarn/lodash-4.17.21
Bump lodash from 4.17.11 to 4.17.21
2022-03-13 12:21:14 +00:00
KodeStar
beb2851f4a Add noopener noreferrer to link 2022-03-13 09:20:58 +00:00
dependabot[bot]
645a0bc7fe Bump lodash from 4.17.11 to 4.17.21
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.21)

---
updated-dependencies:
- dependency-name: lodash
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-13 08:53:35 +00:00
Kode
ef73918098 Update jquery 2022-03-12 23:27:11 +00:00
Kode
06a23c70af Should fix #379 2022-03-12 13:09:50 +00:00
Kode
323a6e17c7 Update database.php 2022-03-12 13:09:03 +00:00
Kode
0ca07c9698 Update composer.json 2022-03-12 12:55:42 +00:00
Kode
fbb21d2885 update redis config 2022-03-12 12:54:15 +00:00
Kode
b6741c8ff0 Update readme.md 2022-03-12 11:55:06 +00:00
Kode
7fdca02af7 Allow numbers in apps 2022-03-12 10:45:37 +00:00
Kode
271100c25b Update app.php 2022-03-12 09:38:19 +00:00
KodeStar
cfecce6100 Create SECURITY.md 2022-03-12 09:37:36 +00:00
Kode
d71341df7a Update app.blade.php 2022-03-11 23:20:18 +00:00
Kode
ac851f5a02 Update manifest.json 2022-03-11 23:15:55 +00:00
Kode
d2a8b7af48 Update app.blade.php 2022-03-11 23:10:47 +00:00
Kode
4d7a86fbf7 Update .env.example 2022-03-11 22:53:25 +00:00
KodeStar
87a3af3dbf Merge pull request #654 from NoahNxT/master
Translation correction NL
2022-03-11 20:30:16 +00:00
KodeStar
79c76b9f50 Merge pull request #648 from angrystar170/master
Add korean language files
2022-03-11 20:29:52 +00:00
KodeStar
d7742df802 Merge pull request #644 from OllieJC/custom
Add custom CSS and JS settings
2022-03-11 20:28:28 +00:00
KodeStar
736222e173 Merge pull request #614 from risiko79/fix/#507
FIX: #507 Tag URLs do not respect APP_URL
2022-03-11 20:23:34 +00:00
KodeStar
047ffb0b55 Merge pull request #581 from rtzra/feature/RussianLanguage
added Russian translation
2022-03-11 20:22:32 +00:00
KodeStar
505d17cf57 Merge pull request #561 from mattycourtney/master
Updated link to letsencrypt image to point to SWAG
2022-03-11 20:22:10 +00:00
KodeStar
71c2da160d Merge pull request #522 from bence192/patch-3
Create pagination.php
2022-03-11 20:17:58 +00:00
KodeStar
3487b9e479 Merge pull request #521 from bence192/patch-4
Create passwords.php
2022-03-11 20:17:39 +00:00
KodeStar
7cdf315d78 Merge pull request #512 from Babasile/master
Lang fr update
2022-03-11 20:17:18 +00:00
KodeStar
a1812a962c Merge pull request #506 from Forceu/master
Added info about updating
2022-03-11 20:16:49 +00:00
KodeStar
b97cab34b0 Merge pull request #492 from crazychatting/lang_de_update
Lang de update
2022-03-11 20:16:24 +00:00
KodeStar
3426450b3c Merge pull request #475 from e7jonas/patch-1
Fixed some spelling errors.
2022-03-11 20:15:53 +00:00
KodeStar
75804f4624 Merge pull request #457 from skay-zhang/patch-1
Creat new language
2022-03-11 20:15:21 +00:00
KodeStar
23f757e06f Merge pull request #454 from shaohao/Fix-password-issue
Update FormBuilder.php
2022-03-11 20:13:51 +00:00
KodeStar
fabd704bab Merge pull request #520 from bence192/patch-1
Hungarian lang added
2022-03-11 20:13:01 +00:00
KodeStar
c16fbae963 Merge pull request #523 from bence192/patch-2
Create auth.php
2022-03-11 20:12:45 +00:00
Kode
348759b9ad update logging 2022-03-11 19:38:08 +00:00
Kode
d961aeb19b more urls with double slashes 2022-03-11 19:06:29 +00:00
Kode
987a9c03b0 fix for double slash on views 2022-03-11 19:03:03 +00:00
Kode
d17fb04983 fix fa in pseudo classes 2022-03-11 10:40:47 +00:00
Kode
b07918d751 changes to lv7 to maybe fix the symlink issues? 2022-03-11 10:07:42 +00:00
KodeStar
f9a19fce91 Update to laravel 7 2022-03-10 11:54:29 +00:00
Noah Gillard
1b71e80d52 Translation correction NL 2022-02-08 22:58:07 +01:00
angrystar170
9fac11cb77 Update passwords.php 2022-01-23 23:30:53 +09:00
angrystar170
a94fb108fa Add korean language files 2022-01-23 23:24:54 +09:00
OllieJC
f51893b2d6 Use pre for textarea settings 2022-01-22 13:30:50 +00:00
OllieJC
a4b32dcafd Add textarea option 2022-01-18 22:59:40 +00:00
OllieJC
862f870303 Add settings.advanced/custom_css/custom_js 2022-01-18 22:42:53 +00:00
OllieJC
869cfd34ab Add custom CSS and JS options 2022-01-18 22:40:09 +00:00
OllieJC
9e67b7c72e Add custom_css and custom_js advance settings 2022-01-18 22:33:21 +00:00
risiko79
a5b7f10809 FIX: #507 Tag URLs do not respect APP_URL
see https://github.com/linuxserver/Heimdall/issues/507
2021-08-29 19:58:50 +02:00
Evgeny Cheremnykh
698665176c added Russian translation 2021-05-01 18:56:27 +03:00
Matty Courtney
1bd65222e4 Updated link to letsencrypt image to point to SWAG 2021-02-21 10:13:48 +08:00
KodeStar
61a5a1a8b0 Merge pull request #530 from jhaveDK/master
Danish translation
2020-12-07 12:39:14 +00:00
Jesper Have
e51cdd7f7a Danish translation update 2020-12-06 18:58:05 +01:00
Jesper Have
a626222ff3 Opdateret 2020-12-06 18:50:32 +01:00
Jesper Have
af68a45a3d . 2020-12-06 18:40:37 +01:00
Jesper Have
7969df9344 Danish translation 2020-12-06 16:36:55 +01:00
bence192
67bc656325 Create passwords.php 2020-11-29 20:02:49 +01:00
bence192
b5baf0d606 Create pagination.php 2020-11-29 20:01:48 +01:00
bence192
32964e9045 Create auth.php 2020-11-29 20:00:29 +01:00
bence192
27a667675a Create app.php 2020-11-29 19:57:27 +01:00
Babasile
9a221f47bf Lang fr update 2020-10-24 11:19:57 +02:00
Marc Ole Bulling
8d2fbc5599 Added info about updating 2020-09-25 13:37:31 +02:00
Robin Loose
84ebe6587d added admin-account-needed in language 2020-08-03 00:45:36 +02:00
Robin Loose
89a71a18da updated and corrected language de 2020-08-01 02:12:01 +02:00
e7jonas
05dd7a090b Fixed some spelling errors. 2020-05-14 13:40:18 +01:00
KodeStar
3a9bdd2c43 Merge pull request #458 from AndyTempel/slovenian-translation
added Slovenian translation
2020-03-22 19:20:42 +00:00
AndrazKorenc
0292e9976e added Slovenian translation 2020-03-15 09:50:17 +01:00
sKai
365de9512f Creat new language
Creat simplified chinese , apply to china
2020-03-09 20:57:31 +08:00
Shao Hao
e857023903 Update FormBuilder.php
Make she the value is passed to password input.
2020-03-03 14:11:51 +08:00
KodeStar
c058e1a452 Merge pull request #446 from vinanrra/patch-1
Update app.php
2020-02-10 09:10:34 +00:00
vinanrra
7f42967b67 Update app.php
Added Jackett
2020-02-10 09:58:26 +01:00
KodeStar
994961de54 Merge pull request #438 from LeoShivas/patch-1
Make background image relative
2020-02-10 08:57:53 +00:00
KodeStar
049d20536c Merge pull request #397 from scottt732/search-app-fixes
Improved custom search handling
2020-02-10 08:56:29 +00:00
LeoShivas
c9c8171a52 Make background image relative
I use Heimdall in a subfolder so that I access to it threw www.mydomain.com/heimdall/.
Custom background image doesn't load because Heimdall generate an absolute link (ie : www.mydomain.com/storage/backgrounds/mycustomimage.jpeg).
The link expected is www.mydomain.com/heimdall/storage/backgrounds/mycustomimage.jpeg.
To fix this, you have to make the path relative by replace in the code "/storage" by "storage" or "./storage".
2020-02-04 11:41:53 +01:00
KodeStar
e7a6ac5a75 Merge pull request #412 from vincentbitter/remote_user-login
Fix auto-login using REMOTE_USER variable
2020-01-06 08:44:06 +00:00
KodeStar
3a372107ba Merge pull request #405 from vorpalhex/feature/#376/upload_icon_text
Update 'upload a file' to 'upload an icon'
2020-01-06 08:42:29 +00:00
KodeStar
493374de65 Merge pull request #404 from panigrc/feature-greek-translation
Greek translation
2020-01-06 08:40:49 +00:00
Vincent Bitter
c43fc929f7 Do not try to login if user was not found 2019-11-15 21:30:10 +01:00
Vincent Bitter
895d5f2ebe Check if variables are empty since they always exist 2019-11-15 21:29:15 +01:00
VorpalHex
cb4768e2cf Update 'upload a file' to 'upload an icon' 2019-10-12 18:11:23 -05:00
panigrc
6ca4bfb9ee Add greek language to the SettingsSeeder 2019-10-06 14:44:18 +02:00
panigrc
1f7de03d90 Add greek language files 2019-10-06 14:43:34 +02:00
Scott Holodak
861d287750 Improved custom search handling 2019-09-11 13:42:33 -04:00
KodeStar
e2cc32fd0a Merge pull request #392 from auanasgheps/patch-1
Update Italian app.php
2019-08-29 14:58:19 +01:00
KodeStar
762df25c45 Merge pull request #393 from auanasgheps/patch-2
Create Italian auth.php
2019-08-29 14:56:39 +01:00
KodeStar
0b114e7dc1 Merge pull request #394 from auanasgheps/patch-3
Create pagination.php
2019-08-29 14:56:13 +01:00
Oliver Cervera
981876c43c Create pagination.php
File was missing.
Translated.
2019-08-28 18:56:46 +02:00
Oliver Cervera
7fe9c477e3 Create Italian auth.php
File was missing.
Translated.
2019-08-28 18:55:56 +02:00
Oliver Cervera
5b3a7f4e02 Update Italian app.php
- Added and translated missing strings
- Reworked existing strings
2019-08-28 18:53:15 +02:00
Kode
60e20c4023 fix route typo when restoring trash 2019-07-14 09:46:10 +01:00
Chris
9e1bb6c075 Update composer min php version 2019-07-11 15:01:07 +01:00
KodeStar
9c05d0d803 Update readme.md 2019-07-03 12:59:27 +01:00
KodeStar
3d1393c0b3 Merge pull request #370 from scodx/patch-1
some minor spanish translations fixes
2019-06-25 08:27:46 +01:00
KodeStar
9914fdb111 Merge pull request #373 from alxlaxv/patch-1
New translation for new SearchInterface
2019-06-25 08:27:07 +01:00
alxlaxv
9b24c9f1b5 New translation for new SearchInterface 2019-06-24 23:36:19 +02:00
Oscar Sánchez
81b8c646d2 some minor spanish translations fixes 2019-06-24 12:15:55 -05:00
Chris
f734832e0f remove url() from around app link 2019-06-24 08:38:50 +01:00
KodeStar
1bde11b30b Update readme.md 2019-06-23 18:42:51 +01:00
Kode
9e80c3fe40 2.2.2 hasn't been released yet 2019-06-22 17:05:05 +01:00
Kode
f272dd13ce Fix for tags not showing 2019-06-22 17:03:01 +01:00
Chris
9f26de89a4 add remember user and missing check icon 2019-06-19 12:11:55 +01:00
Chris
e23964ebad set session and remember user when logged in via remote means 2019-06-19 12:01:17 +01:00
Chris
d0584ac941 Update app version ready for next release 2019-06-19 11:49:17 +01:00
Chris
1410c41f48 Add REMOTE_USER auth 2019-06-19 11:32:41 +01:00
Chris
5f524563cf Merge branch 'master' of https://github.com/linuxserver/Heimdall 2019-06-18 13:41:06 +01:00
Chris
3d181623c3 fix small issue 2019-06-18 13:41:02 +01:00
KodeStar
1919dbfd96 Update readme.md 2019-06-18 13:22:14 +01:00
Chris
8e1615ac5f fix search tab behaviour and tag link in subfolder 2019-06-18 12:25:05 +01:00
Chris
7966f07fdb update scripts + add home dash as default tag 2019-06-18 11:51:07 +01:00
Chris
ac8fe7012b remove false from routes 2019-06-18 10:51:51 +01:00
Chris
51d89dae82 Possible fix for folder based RP 2019-06-18 08:46:57 +01:00
KodeStar
ef21ac0fe7 Merge pull request #359 from pahakalle/patch-1
Fix typo in Finnish translation
2019-06-13 19:10:04 +01:00
KodeStar
02697687cc Merge pull request #364 from linuxserver/hometags
Allow apps to be tagged to the homepage
2019-06-13 19:09:19 +01:00
Kode
fd2f7f27a6 Make home tag translatable 2019-06-13 19:07:38 +01:00
Kode
21b1ef5e4b fix pin toggle and get homepage dash working 2019-06-13 18:59:01 +01:00
Chris
e452d3b5f6 add seed 2019-06-13 15:57:54 +01:00
Chris
1419882455 initial 2019-06-13 15:40:26 +01:00
KodeStar
d79202ed87 Update readme.md 2019-06-12 11:02:19 +01:00
KodeStar
aa05c947a9 Remove url validation 2019-06-11 14:11:13 +01:00
Chris
eb69ea05fa Update package-lock.json 2019-06-11 12:35:48 +01:00
Chris
244b0998f9 update bootstrap-sass 2019-06-11 12:34:28 +01:00
Chris
1f608b1c21 Update composer dependencies 2019-06-11 12:29:32 +01:00
Chris
7d6df3843b update node deps 2019-06-11 12:20:04 +01:00
Kalle Laine
dd4b94ba71 Fix typo in Finnish translation 2019-06-11 14:18:08 +03:00
Chris
edb9397a47 Add startpage back in 2019-06-11 12:02:18 +01:00
KodeStar
66815a8487 readd startpage 2019-06-11 11:45:13 +01:00
KodeStar
5ee19bceb6 Merge pull request #357 from Agurato/master
Add Qwant as search engine
2019-06-11 11:32:31 +01:00
KodeStar
deba7d0279 Merge branch 'master' into master 2019-06-11 11:32:11 +01:00
KodeStar
38e93d33f1 remove startpage 2019-06-11 11:30:33 +01:00
KodeStar
f182f305fc remove startpage 2019-06-11 11:30:17 +01:00
KodeStar
03c675ed57 remove startpage 2019-06-11 11:29:54 +01:00
KodeStar
3916b2d4dc remove startpage 2019-06-11 11:29:38 +01:00
KodeStar
698a7a9bbc remove startpage 2019-06-11 11:28:07 +01:00
KodeStar
9954d1b6bf Merge pull request #342 from dmbekker/master
Dutch Translation update
2019-06-11 11:04:52 +01:00
KodeStar
a98b981efe Merge pull request #348 from Aerion/toggle-livestats-refresh-active-tab
turn off livestats update when the tab isn't active
2019-06-11 11:03:14 +01:00
KodeStar
dd2ca62eaf Add private subnets to trusted proxies for reverse proxy use 2019-06-11 11:00:44 +01:00
Agurato
dc2a42ad6d Add Qwant as search engine 2019-06-08 13:02:12 +02:00
Guillaume Taquet Gasperini
b5b25458db turn off livestats update when the tab isn't active
Fixes #330: Turning off the updating when the tab isn't active

When the tab is not visible from the user, the livestats refresh are
stopped. As soon as its visibility changes (from visibilitychange
API), the livestats are refreshed as usual.

This will prevent unnecessary calls to the different services when the
tab is hidden from the user.
2019-05-20 21:58:03 +02:00
David
ac4bbceb2f New Translations, Fixes for current translation
Added new translations

Minor language-issues fixed
- Changed 'Toepassing' to 'Applicatie' (Both Acronyms were used)
- Changed 'Reeks' to 'Tekenreeks'
2019-04-22 16:38:07 +02:00
Kode
4980bfab12 fix not protocol breaking adding for some reason 2019-03-30 23:10:00 +00:00
Chris
63e0d07d50 remove unused storeSearchProvider 2019-02-04 08:51:49 +00:00
Kode
2b76520e3a change version number and update lang value 2019-01-18 18:42:17 +00:00
Kode
6631b8a23b update dev npm deps 2019-01-18 18:37:51 +00:00
Kode
04d34017c1 Composer deps update 2019-01-18 18:33:28 +00:00
KodeStar
6dcbcb452e Merge pull request #316 from linuxserver/search-enhancements
Search enhancements
2019-01-18 18:27:19 +00:00
Kode
7c74b3bb13 update manifest 2019-01-18 18:26:07 +00:00
Kode
b76a9ee118 Merge branch 'master' into search-enhancements 2019-01-18 18:25:00 +00:00
Kode
40da649b10 Changes to search 2019-01-18 18:21:44 +00:00
Chris
cd64d762e7 additions to search 2019-01-18 15:21:50 +00:00
Chris
b91c52820a replace fontawesome with js version 2019-01-18 14:07:17 +00:00
KodeStar
1204ffd306 Update app.php 2019-01-16 17:24:31 +00:00
Chris
978267dd14 Update Search.php 2019-01-16 15:00:42 +00:00
Chris
f935fd94c6 initial work on seach changes 2019-01-16 14:47:32 +00:00
Chris
fb2428e21b fixes #109 2019-01-16 14:20:33 +00:00
Chris
e36a126c01 fixes #286 2019-01-16 12:02:38 +00:00
Chris
b186978624 fixes #299 2019-01-16 11:39:39 +00:00
Chris
49773d7654 Fixes #302 2019-01-16 10:37:25 +00:00
Chris
53c03751a1 ignore supported apps folder 2019-01-16 10:35:55 +00:00
Chris
9d2908449a Merge branch 'master' of https://github.com/linuxserver/Heimdall 2019-01-15 15:27:29 +00:00
KodeStar
caf92bcf6d check for gitignore in public storage and symlink if missing 2019-01-15 15:25:53 +00:00
KodeStar
cbef469e02 Update AppServiceProvider.php 2019-01-15 15:23:10 +00:00
Chris
a6bfc1d76c ignore .env 2019-01-15 14:27:19 +00:00
KodeStar
0446a74de9 Merge pull request #308 from openseabrus/master
Portuguese (PT-PT) translation.
2019-01-07 08:27:46 +00:00
KodeStar
1a14079b39 add APP_KEY 2019-01-04 14:00:15 +00:00
KodeStar
d9c1919ddc Merge pull request #313 from linuxserver/Fix-default-appkey
Update .env.example
2019-01-04 11:52:07 +00:00
KodeStar
f42ac0c5ba if .env is missing copy example and generate key 2019-01-04 10:38:07 +00:00
KodeStar
c073929895 Delete .env 2019-01-04 10:36:04 +00:00
KodeStar
02df7844a4 Update .env.example 2019-01-04 10:34:12 +00:00
l1904l
e43aba0111 Portuguese (PT-PT) translation. 2018-12-26 15:56:34 +00:00
Kode
ac7446ffe6 update version 2018-11-14 18:14:23 +00:00
Kode
e45d3ca6ec remove apps 2018-11-14 18:10:55 +00:00
Chris
603550a453 autofocus password 2018-11-13 12:38:19 +00:00
Kode
4463ef4a9a add right to livestats 2018-11-10 21:37:21 +00:00
Kode
49b8dc0079 Update version number 2018-11-10 18:05:19 +00:00
Kode
ab83c3a551 Small changes
Copy icon if missing on new app add.
Change order of create symlink and load apps
2018-11-09 23:07:01 +00:00
Chris
98c6093674 Check url isn't missing when testing 2018-11-07 11:24:26 +00:00
Chris
e1f51521bf Update version 2018-11-07 08:57:18 +00:00
Chris
e85bc98dcc Fix ProcessJobs not working if folder is empty but table isn't 2018-11-07 08:54:00 +00:00
Chris
4ba52baa5c Remove old code from tags form 2018-11-06 15:44:09 +00:00
Chris
a82077b4de Update version 2018-11-06 15:15:55 +00:00
Chris
b8f04f3d11 Fix preview and config not retaining values 2018-11-06 14:52:45 +00:00
Chris
e91f65f833 Ignore copy errors 2018-11-06 11:53:25 +00:00
Chris
575ab9be2d update version 2018-11-06 11:29:33 +00:00
Chris
64071bb60f Add migration and change path 2018-11-06 11:28:22 +00:00
Chris
44621a1a61 Change version + replace supported with icons 2018-11-06 09:48:03 +00:00
Chris
c56043e1f9 Add default value to null rather than not set 2018-11-06 09:20:53 +00:00
Kode
e8e4cbfd41 Change sort order for applist 2018-11-05 21:03:42 +00:00
Kode
4b2bbe0614 update version 2018-11-05 19:03:26 +00:00
Kode
9adfa14e62 fix light colour livestats 2018-11-05 19:02:19 +00:00
Kode
067f82b632 fix copy failing 2018-11-05 18:47:56 +00:00
Chris
e24e7979be update version number 2018-11-05 15:28:17 +00:00
Chris
c7c2b6e6f2 change location of icons so it's persistant 2018-11-05 15:27:29 +00:00
Chris
96798963d6 Update register app to allow all 2018-11-05 12:31:43 +00:00
7200 changed files with 340117 additions and 255793 deletions

31
.env
View File

@@ -1,31 +0,0 @@
APP_NAME=Heimdall
APP_ENV=local
APP_KEY=base64:I206O8ibx+GQyRE7BeOxDobn04Mfmyyc5Ptzns/C0mY=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost
DB_CONNECTION=sqlite
DB_DATABASE=app.sqlite
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

View File

@@ -1,19 +1,17 @@
APP_NAME=Laravel
APP_NAME=Heimdall
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_DEBUG=false
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
LOG_CHANNEL=daily
DB_CONNECTION=sqlite
DB_DATABASE=app.sqlite
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync
@@ -22,14 +20,24 @@ REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

2
.gitignore vendored
View File

@@ -1,3 +1,4 @@
/app/SupportedApps
/node_modules
/public/hot
/public/storage
@@ -25,3 +26,4 @@ yarn-error.log
.Trashes
.VolumeIcon.icns
storage/app/public/avatars/*
.env

14
SECURITY.md Normal file
View File

@@ -0,0 +1,14 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 2.3.x | :white_check_mark: |
| < 2.3 | :x: |
## Reporting a Vulnerability
You can report any vulnerabilities on our discord server by DM-ing a team member, or asking a team member to DM you.
https://discord.com/invite/YWrKVTn

View File

@@ -13,6 +13,13 @@ class Application extends Model
//
public function icon()
{
if (! file_exists(storage_path('app/public/'.$this->icon))) {
$img_src = app_path('SupportedApps/'.$this->name.'/'.str_replace('icons/', '', $this->icon));
$img_dest = storage_path('app/public/'.$this->icon);
//die("i: ".$img_src);
@copy($img_src, $img_dest);
}
return $this->icon;
}
@@ -24,32 +31,103 @@ class Application extends Model
public function defaultColour()
{
// check if light or dark
if($this->tile_background == 'light') return '#fafbfc';
if ($this->tile_background == 'light') {
return '#fafbfc';
}
return '#161b1f';
}
public function class()
{
$name = $this->name;
$name = preg_replace('/\PL/u', '', $name);
$name = preg_replace('/[^\p{L}\p{N}]/u', '', $name);
$class = '\App\SupportedApps\\'.$name.'\\'.$name;
return $class;
}
public static function classFromName($name)
{
$name = preg_replace('/[^\p{L}\p{N}]/u', '', $name);
$class = '\App\SupportedApps\\'.$name.'\\'.$name;
return $class;
}
public static function apps()
{
$json = json_decode(file_get_contents(storage_path('app/supportedapps.json'))) ?? [];
$apps = collect($json->apps);
$sorted = $apps->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE);
return $sorted;
}
public static function autocomplete()
{
$apps = self::apps();
$list = [];
foreach ($apps as $app) {
$list[] = (object) [
'label' => $app->name,
'value' => $app->appid,
];
}
return $list;
}
public static function getApp($appid)
{
$localapp = self::where('appid', $appid)->first();
$app = self::single($appid);
$application = ($localapp) ? $localapp : new self;
if (! file_exists(app_path('SupportedApps/'.className($app->name)))) {
SupportedApps::getFiles($app);
SupportedApps::saveApp($app, $application);
} else {
// check if there has been an update for this app
if ($localapp) {
if ($localapp->sha !== $app->sha) {
SupportedApps::getFiles($app);
$app = SupportedApps::saveApp($app, $application);
}
} else {
SupportedApps::getFiles($app);
$app = SupportedApps::saveApp($app, $application);
}
}
return $app;
}
public static function single($appid)
{
$apps = self::apps();
$app = $apps->where('appid', $appid)->first();
if ($app === null) {
return null;
}
$classname = preg_replace('/[^\p{L}\p{N}]/u', '', $app->name);
$app->class = '\App\SupportedApps\\'.$classname.'\\'.$classname;
return $app;
}
public static function applist()
{
$list = [];
$all = self::orderBy('name')->get();
$list['null'] = 'None';
foreach($all as $app) {
$name = $app->name;
$name = preg_replace('/\PL/u', '', $name);
$list['\App\SupportedApps\\'.$name.'\\'.$name] = $app->name;
$apps = self::apps();
foreach ($apps as $app) {
$list[$app->appid] = $app->name;
}
return $list;
}
}

View File

@@ -2,9 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Application;
use App\SupportedApps;
use Illuminate\Console\Command;
class RegisterApp extends Command
{
@@ -40,22 +40,38 @@ class RegisterApp extends Command
public function handle()
{
$folder = $this->argument('folder');
$json = app_path('SupportedApps/'.$folder.'/app.json');
if(file_exists($json)) {
$app = json_decode(file_get_contents($json));
$exists = Application::find($app->appid);
if($exists) {
$this->error('This app is already registered');
exit;
if ($folder == 'all') {
$apps = scandir(app_path('SupportedApps'));
foreach ($apps as $folder) {
if ($folder == '.' || $folder == '..') {
continue;
}
$this->addApp($folder);
}
} else {
$this->addApp($folder);
}
}
public function addApp($folder)
{
$json = app_path('SupportedApps/'.$folder.'/app.json');
if (file_exists($json)) {
$app = json_decode(file_get_contents($json));
if (isset($app->appid)) {
$exists = Application::find($app->appid);
if ($exists) {
$this->error('Application already registered - '.$exists->name.' - '.$exists->appid);
} else {
// Doesn't exist so add it
SupportedApps::saveApp($app, new Application);
$this->info('Application Added - '.$app->name.' - '.$app->appid);
}
} else {
$this->error('No App ID for - '.$folder);
}
// Doesn't exist so add it
SupportedApps::saveApp($app, new Application);
$this->info("Application Added - ".$app->name." - ".$app->appid);
} else {
$this->error('Could not find '.$json);
}
}
}

View File

@@ -1,12 +1,15 @@
<?php namespace App;
<?php
namespace App;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
interface EnhancedApps
{
public function test();
public function livestats();
public function url($endpoint);
}
public function livestats();
public function url($endpoint);
}

View File

@@ -2,8 +2,8 @@
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
@@ -22,32 +22,20 @@ class Handler extends ExceptionHandler
* @var array
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Report or log an exception.
* Register the exception handling callbacks for the application.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @return void
*/
public function report(Exception $exception)
public function register()
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
$this->reportable(function (Throwable $e) {
//
});
}
}

View File

@@ -1,44 +1,84 @@
<?php
use Illuminate\Support\Str;
function format_bytes($bytes, $is_drive_size = true, $beforeunit = '', $afterunit = '')
{
$btype = ($is_drive_size === true) ? 1000 : 1024;
$labels = array('B','KB','MB','GB','TB');
for($x = 0; $bytes >= $btype && $x < (count($labels) - 1); $bytes /= $btype, $x++); // use 1000 rather than 1024 to simulate HD size not real size
if($labels[$x] == "TB") return(round($bytes, 3).$beforeunit.$labels[$x].$afterunit);
elseif($labels[$x] == "GB") return(round($bytes, 2).$beforeunit.$labels[$x].$afterunit);
elseif($labels[$x] == "MB") return(round($bytes, 2).$beforeunit.$labels[$x].$afterunit);
else return(round($bytes, 0).$beforeunit.$labels[$x].$afterunit);
$btype = ($is_drive_size === true) ? 1000 : 1024;
$labels = ['B', 'KB', 'MB', 'GB', 'TB'];
for ($x = 0; $bytes >= $btype && $x < (count($labels) - 1); $bytes /= $btype, $x++); // use 1000 rather than 1024 to simulate HD size not real size
if ($labels[$x] == 'TB') {
return round($bytes, 3).$beforeunit.$labels[$x].$afterunit;
} elseif ($labels[$x] == 'GB') {
return round($bytes, 2).$beforeunit.$labels[$x].$afterunit;
} elseif ($labels[$x] == 'MB') {
return round($bytes, 2).$beforeunit.$labels[$x].$afterunit;
} else {
return round($bytes, 0).$beforeunit.$labels[$x].$afterunit;
}
}
function get_brightness($hex) {
function str_slug($title, $separator = '-', $language = 'en')
{
return Str::slug($title, $separator, $language);
}
if (! function_exists('str_is')) {
/**
* Determine if a given string matches a given pattern.
*
* @param string|array $pattern
* @param string $value
* @return bool
*
* @deprecated Str::is() should be used directly instead. Will be removed in Laravel 6.0.
*/
function str_is($pattern, $value)
{
return Str::is($pattern, $value);
}
}
function get_brightness($hex)
{
// returns brightness value from 0 to 255
// strip off any leading #
$hex = str_replace('#', '', $hex);
if(strlen($hex) == 3) {
// $hex = str_replace('#', '', $hex);
$hex = preg_replace("/[^0-9A-Fa-f]/", '', $hex);
if (strlen($hex) == 3) {
$hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
}
$c_r = hexdec(substr($hex, 0, 2));
$c_g = hexdec(substr($hex, 2, 2));
$c_b = hexdec(substr($hex, 4, 2));
return (($c_r * 299) + ($c_g * 587) + ($c_b * 114)) / 1000;
}
function title_color($hex)
{
if(get_brightness($hex) > 130) {
if (get_brightness($hex) > 130) {
return ' black';
} else {
return ' white';
}
}
function getLinkTargetAttribute()
{
$target = \App\Setting::fetch('window_target');
if ($target === 'current') {
return '';
} else {
return ' target="'.$target.'"';
}
}
function className($name)
{
$name = preg_replace('/\PL/u', '', $name);
$name = preg_replace('/[^\p{L}\p{N}]/u', '', $name);
return $name;
}

View File

@@ -3,8 +3,8 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use App\User;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
@@ -59,7 +59,7 @@ class LoginController extends Controller
public function login(Request $request)
{
$current_user = User::currentUser();
$request->merge(['username' => $current_user->username]);
$request->merge(['username' => $current_user->username, 'remember' => true]);
//die(print_r($request->all()));
$this->validateLogin($request);
@@ -92,14 +92,16 @@ class LoginController extends Controller
{
Auth::logout();
session(['current_user' => $user]);
return redirect()->route('dash');
}
public function autologin($uuid)
{
$user = User::where('autologin', $uuid)->first();
Auth::login($user);
Auth::login($user, true);
session(['current_user' => $user]);
return redirect()->route('dash');
}
@@ -122,5 +124,4 @@ class LoginController extends Controller
{
return Session::get('url.intended') ? Session::get('url.intended') : $this->redirectTo;
}
}

View File

@@ -2,10 +2,10 @@
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use App\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{

View File

@@ -2,12 +2,12 @@
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth;
use App\User;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Auth;
class Controller extends BaseController
{
@@ -22,7 +22,6 @@ class Controller extends BaseController
//print_r($this->user);
return $next($request);
});
}
public function user()

View File

@@ -2,16 +2,21 @@
namespace App\Http\Controllers;
use Artisan;
use App\Application;
use App\Item;
use App\Setting;
use App\User;
use GrahamCampbell\GitHub\Facades\GitHub;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\SupportedApps;
use App\Jobs\ProcessApps;
use App\Search;
use App\Setting;
use App\SupportedApps;
use App\User;
use Artisan;
use GrahamCampbell\GitHub\Facades\GitHub;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
class ItemController extends Controller
{
@@ -19,19 +24,28 @@ class ItemController extends Controller
{
$this->middleware('allowed');
}
/**
/**
* Display a listing of the resource on the dashboard.
*
* @return \Illuminate\Http\Response
*/
public function dash()
{
$data['apps'] = Item::doesntHave('parents')->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::doesntHave('parents')->get();
$data['apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere('type', 1)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere('type', 1)->orderBy('order', 'asc')->get();
//$data['all_apps'] = Item::doesntHave('parents')->get();
//die(print_r($data['apps']));
return view('welcome', $data);
}
/**
/**
* Set order on the dashboard.
*
* @return \Illuminate\Http\Response
@@ -39,7 +53,7 @@ class ItemController extends Controller
public function setOrder(Request $request)
{
$order = array_filter($request->input('order'));
foreach($order as $o => $id) {
foreach ($order as $o => $id) {
$item = Item::find($id);
$item->order = $o;
$item->save();
@@ -56,11 +70,12 @@ class ItemController extends Controller
$item = Item::findOrFail($id);
$item->pinned = true;
$item->save();
$route = route('dash', [], false);
$route = route('dash', []);
return redirect($route);
}
/**
/**
* Unpin item on the dashboard.
*
* @return \Illuminate\Http\Response
@@ -70,32 +85,39 @@ class ItemController extends Controller
$item = Item::findOrFail($id);
$item->pinned = false;
$item->save();
$route = route('dash', [], false);
$route = route('dash', []);
return redirect($route);
}
/**
/**
* Unpin item on the dashboard.
*
* @return \Illuminate\Http\Response
*/
public function pinToggle($id, $ajax=false)
public function pinToggle($id, $ajax = false, $tag = false)
{
$item = Item::findOrFail($id);
$new = ((bool)$item->pinned === true) ? false : true;
$new = ((bool) $item->pinned === true) ? false : true;
$item->pinned = $new;
$item->save();
if($ajax) {
$data['apps'] = Item::pinned()->get();
if ($ajax) {
if (is_numeric($tag) && $tag > 0) {
$item = Item::whereId($tag)->first();
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
} else {
$data['apps'] = Item::pinned()->orderBy('order', 'asc')->get();
}
$data['ajax'] = true;
return view('sortable', $data);
} else {
$route = route('dash', [], false);
$route = route('dash', []);
return redirect($route);
}
}
}
/**
* Display a listing of the resource.
*
@@ -103,18 +125,17 @@ class ItemController extends Controller
*/
public function index(Request $request)
{
$trash = (bool)$request->input('trash');
$trash = (bool) $request->input('trash');
$data['apps'] = Item::ofType('item')->orderBy('title', 'asc')->get();
$data['trash'] = Item::ofType('item')->onlyTrashed()->get();
if($trash) {
if ($trash) {
return view('items.trash', $data);
} else {
return view('items.list', $data);
}
}
/**
* Show the form for creating a new resource.
*
@@ -124,9 +145,94 @@ class ItemController extends Controller
{
//
$data['tags'] = Item::ofType('tag')->orderBy('title', 'asc')->pluck('title', 'id');
$data['current_tags'] = [];
return view('items.create', $data);
$data['tags']->prepend(__('app.dashboard'), 0);
$data['current_tags'] = '0';
return view('items.create', $data);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
// Get the item
$item = Item::find($id);
if ($item->appid === null && $item->class !== null) { // old apps wont have an app id so set it
$app = Application::where('class', $item->class)->first();
if ($app) {
$item->appid = $app->appid;
}
}
$data['item'] = $item;
$data['tags'] = Item::ofType('tag')->orderBy('title', 'asc')->pluck('title', 'id');
$data['tags']->prepend(__('app.dashboard'), 0);
$data['current_tags'] = $data['item']->tags();
//$data['current_tags'] = $data['item']->parent;
//die(print_r($data['current_tags']));
// show the edit form and pass the nerd
return view('items.edit', $data);
}
public function storelogic($request, $id = null)
{
$application = Application::single($request->input('appid'));
$validatedData = $request->validate([
'title' => 'required|max:255',
'url' => 'required',
]);
if ($request->hasFile('file')) {
$path = $request->file('file')->store('icons');
$request->merge([
'icon' => $path,
]);
} elseif (strpos($request->input('icon'), 'http') === 0) {
$contents = file_get_contents($request->input('icon'));
if ($application) {
$icon = $application->icon;
} else {
$file = $request->input('icon');
$path_parts = pathinfo($file);
$icon = md5($contents);
$icon .= '.'.$path_parts['extension'];
}
$path = 'icons/'.$icon;
Storage::disk('public')->put($path, $contents);
$request->merge([
'icon' => $path,
]);
}
$config = Item::checkConfig($request->input('config'));
$current_user = User::currentUser();
$request->merge([
'description' => $config,
'user_id' => $current_user->id,
]);
if ($request->input('appid') === 'null') {
$request->merge([
'class' => null,
]);
} else {
$request->merge([
'class' => Application::classFromName($application->name),
]);
}
if ($id === null) {
$item = Item::create($request->all());
} else {
$item = Item::find($id);
$item->update($request->all());
}
$item->parents()->sync($request->tags);
}
/**
@@ -137,40 +243,10 @@ class ItemController extends Controller
*/
public function store(Request $request)
{
//
$validatedData = $request->validate([
'title' => 'required|max:255',
'url' => 'required|url',
]);
$this->storelogic($request);
if($request->hasFile('file')) {
$path = $request->file('file')->store('icons');
$request->merge([
'icon' => $path
]);
}
$route = route('dash', []);
$config = Item::checkConfig($request->input('config'));
$current_user = User::currentUser();
$request->merge([
'description' => $config,
'user_id' => $current_user->id
]);
if($request->input('class') === 'null') {
$request->merge([
'class' => null,
]);
}
//die(print_r($request->input('config')));
$item = Item::create($request->all());
$item->parents()->sync($request->tags);
$route = route('dash', [], false);
return redirect($route)
->with('success', __('app.alert.success.item_created'));
}
@@ -186,23 +262,6 @@ class ItemController extends Controller
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
// Get the item
$data['item'] = Item::find($id);
$data['tags'] = Item::ofType('tag')->orderBy('title', 'asc')->pluck('title', 'id');
$data['current_tags'] = $data['item']->parents;
// show the edit form and pass the nerd
return view('items.edit', $data);
}
/**
* Update the specified resource in storage.
*
@@ -212,40 +271,11 @@ class ItemController extends Controller
*/
public function update(Request $request, $id)
{
$validatedData = $request->validate([
'title' => 'required|max:255',
'url' => 'required|url',
]);
//die(print_r($request->all()));
if($request->hasFile('file')) {
$path = $request->file('file')->store('icons');
$request->merge([
'icon' => $path
]);
}
$config = Item::checkConfig($request->input('config'));
$current_user = User::currentUser();
$request->merge([
'description' => $config,
'user_id' => $current_user->id
]);
$this->storelogic($request, $id);
$route = route('dash', []);
if($request->input('class') === 'null') {
$request->merge([
'class' => null,
]);
}
$item = Item::find($id);
$item->update($request->all());
$item->parents()->sync($request->tags);
$route = route('dash', [], false);
return redirect($route)
->with('success',__('app.alert.success.item_updated'));
->with('success', __('app.alert.success.item_updated'));
}
/**
@@ -257,8 +287,8 @@ class ItemController extends Controller
public function destroy(Request $request, $id)
{
//
$force = (bool)$request->input('force');
if($force) {
$force = (bool) $request->input('force');
if ($force) {
Item::withTrashed()
->where('id', $id)
->forceDelete();
@@ -266,9 +296,10 @@ class ItemController extends Controller
Item::find($id)->delete();
}
$route = route('items.index', [], false);
return redirect($route)
->with('success',__('app.alert.success.item_deleted'));
$route = route('items.index', []);
return redirect($route)
->with('success', __('app.alert.success.item_deleted'));
}
/**
@@ -282,11 +313,12 @@ class ItemController extends Controller
//
Item::withTrashed()
->where('id', $id)
->restore();
$route = route('items.inded', [], false);
->restore();
$route = route('items.index', []);
return redirect($route)
->with('success',__('app.alert.success.item_restored'));
->with('success', __('app.alert.success.item_restored'));
}
/**
@@ -297,7 +329,12 @@ class ItemController extends Controller
public function appload(Request $request)
{
$output = [];
$appname = $request->input('app');
$appid = $request->input('app');
if ($appid === 'null') {
return null;
}
/*$appname = $request->input('app');
//die($appname);
$app_details = Application::where('name', $appname)->firstOrFail();
@@ -316,8 +353,25 @@ class ItemController extends Controller
$output['config'] = className($app_details->name).'.config';
} else {
$output['config'] = null;
}*/
$output['config'] = null;
$output['custom'] = null;
$app = Application::single($appid);
$output = (array) $app;
$appdetails = Application::getApp($appid);
if ((bool) $app->enhanced === true) {
// if(!isset($app->config)) { // class based config
$output['custom'] = className($appdetails->name).'.config';
// }
}
$output['colour'] = ($app->tile_background == 'light') ? '#fafbfc' : '#161b1f';
$output['iconview'] = config('app.appsource').'icons/'.$app->icon;
return json_encode($output);
}
@@ -325,39 +379,68 @@ class ItemController extends Controller
{
$data = $request->input('data');
//$url = $data[array_search('url', array_column($data, 'name'))]['value'];
$app = $data['type'];
$single = Application::single($data['type']);
$app = $single->class;
$app_details = new $app();
$app_details->config = (object)$data;
$app_details->config = (object) $data;
$app_details->test();
}
public function execute($url, $attrs = [], $overridevars = false)
{
$res = null;
$vars = ($overridevars !== false) ?
$overridevars : [
'http_errors' => false,
'timeout' => 15,
'connect_timeout' => 15,
'verify' => false,
];
$client = new Client($vars);
$method = 'GET';
try {
return $client->request($method, $url, $attrs);
} catch (\GuzzleHttp\Exception\ConnectException $e) {
Log::error('Connection refused');
Log::debug($e->getMessage());
} catch (\GuzzleHttp\Exception\ServerException $e) {
Log::debug($e->getMessage());
}
return $res;
}
public function websitelookup($url)
{
$url = \base64_decode($url);
$data = $this->execute($url);
return $data->getBody();
}
public function getStats($id)
{
$item = Item::find($id);
$config = $item->getconfig();
if(isset($item->class)) {
if (isset($item->class)) {
$application = new $item->class;
$application->config = $config;
echo $application->livestats();
}
}
public function checkAppList()
{
ProcessApps::dispatch();
$route = route('items.index');
return redirect($route)
->with('success', __('app.alert.success.updating'));
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Search;
use Illuminate\Http\Request;
class SearchController extends Controller
{
public function index(Request $request)
{
$requestprovider = $request->input('provider');
$query = $request->input('q');
$provider = Search::providerDetails($requestprovider);
if ($provider->type == 'standard') {
return redirect($provider->url.'?'.$provider->query.'='.urlencode($query));
} elseif ($provider->type == 'external') {
$class = new $provider->class;
//print_r($provider);
return $class->getResults($query, $provider);
}
//print_r($provider);
}
}

View File

@@ -2,12 +2,12 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Setting;
use App\SettingGroup;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
class SettingsController extends Controller
{
@@ -40,15 +40,18 @@ class SettingsController extends Controller
$setting = Setting::find($id);
//die("s: ".$setting->label);
if((bool)$setting->system === true) return abort(404);
if ((bool) $setting->system === true) {
return abort(404);
}
if (!is_null($setting)) {
if (! is_null($setting)) {
return view('settings.edit')->with([
'setting' => $setting,
]);
} else {
$route = route('settings.list', [], false);
return redirect($route)
$route = route('settings.list', []);
return redirect($route)
->with([
'error' => __('app.alert.error.not_exist'),
]);
@@ -65,37 +68,39 @@ class SettingsController extends Controller
$setting = Setting::find($id);
$user = $this->user();
if (!is_null($setting)) {
$data = Setting::getInput();
if (! is_null($setting)) {
$data = Setting::getInput($request);
$setting_value = null;
if ($setting->type == 'image') {
if($request->hasFile('value')) {
if ($request->hasFile('value')) {
$path = $request->file('value')->store('backgrounds');
$setting_value = $path;
}
} else {
$setting_value = $data->value;
}
$user->settings()->detach($setting->id);
$user->settings()->save($setting, ['uservalue' => $setting_value]);
$route = route('settings.index', [], false);
return redirect($route)
$route = route('settings.index', []);
return redirect($route)
->with([
'success' => __('app.alert.success.setting_updated'),
]);
} else {
$route = route('settings.index', [], false);
return redirect($route)
$route = route('settings.index', []);
return redirect($route)
->with([
'error' => __('app.alert.error.not_exist'),
]);
}
}
/**
* @param int $id
*
@@ -105,15 +110,19 @@ class SettingsController extends Controller
{
$user = $this->user();
$setting = Setting::find($id);
if((bool)$setting->system !== true) {
if ((bool) $setting->system !== true) {
$user->settings()->detach($setting->id);
$user->settings()->save($setting, ['uservalue' => '']);
}
$route = route('settings.index', [], false);
return redirect($route)
$route = route('settings.index', []);
return redirect($route)
->with([
'success' => __('app.alert.success.setting_updated'),
]);
}
public function search(Request $request)
{
}
}

View File

@@ -2,10 +2,10 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Item;
use App\User;
use DB;
use Illuminate\Http\Request;
class TagController extends Controller
{
@@ -13,6 +13,7 @@ class TagController extends Controller
{
$this->middleware('allowed');
}
/**
* Display a listing of the resource.
*
@@ -20,11 +21,11 @@ class TagController extends Controller
*/
public function index(Request $request)
{
$trash = (bool)$request->input('trash');
$trash = (bool) $request->input('trash');
$data['apps'] = Item::ofType('tag')->orderBy('title', 'asc')->get();
$data['trash'] = Item::ofType('tag')->onlyTrashed()->get();
if($trash) {
$data['apps'] = Item::ofType('tag')->where('id', '>', 0)->orderBy('title', 'asc')->get();
$data['trash'] = Item::ofType('tag')->where('id', '>', 0)->onlyTrashed()->get();
if ($trash) {
return view('tags.trash', $data);
} else {
return view('tags.list', $data);
@@ -39,6 +40,7 @@ class TagController extends Controller
public function create()
{
$data = [];
return view('tags.create', $data);
}
@@ -54,10 +56,10 @@ class TagController extends Controller
'title' => 'required|max:255',
]);
if($request->hasFile('file')) {
if ($request->hasFile('file')) {
$path = $request->file('file')->store('icons');
$request->merge([
'icon' => $path
'icon' => $path,
]);
}
@@ -69,12 +71,13 @@ class TagController extends Controller
$request->merge([
'type' => '1',
'url' => $slug,
'user_id' => $current_user->id
'user_id' => $current_user->id,
]);
//die(print_r($request->all()));
Item::create($request->all());
$route = route('dash', [], false);
$route = route('dash', []);
return redirect($route)
->with('success', __('app.alert.success.tag_created'));
}
@@ -90,7 +93,9 @@ class TagController extends Controller
$item = Item::whereUrl($slug)->first();
//print_r($item);
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
$data['tag'] = $item->id;
$data['all_apps'] = $item->children;
return view('welcome', $data);
}
@@ -107,7 +112,7 @@ class TagController extends Controller
// show the edit form and pass the nerd
return view('tags.edit')
->with('item', $item);
->with('item', $item);
}
/**
@@ -123,24 +128,25 @@ class TagController extends Controller
'title' => 'required|max:255',
]);
if($request->hasFile('file')) {
if ($request->hasFile('file')) {
$path = $request->file('file')->store('icons');
$request->merge([
'icon' => $path
'icon' => $path,
]);
}
$slug = str_slug($request->title, '-');
// set item type to tag
$request->merge([
'url' => $slug
'url' => $slug,
]);
Item::find($id)->update($request->all());
$route = route('dash', [], false);
$route = route('dash', []);
return redirect($route)
->with('success',__('app.alert.success.tag_updated'));
->with('success', __('app.alert.success.tag_updated'));
}
/**
@@ -152,18 +158,19 @@ class TagController extends Controller
public function destroy(Request $request, $id)
{
//
$force = (bool)$request->input('force');
if($force) {
$force = (bool) $request->input('force');
if ($force) {
Item::withTrashed()
->where('id', $id)
->forceDelete();
} else {
Item::find($id)->delete();
}
$route = route('tags.index', [], false);
$route = route('tags.index', []);
return redirect($route)
->with('success',__('app.alert.success.item_deleted'));
->with('success', __('app.alert.success.item_deleted'));
}
/**
@@ -177,10 +184,11 @@ class TagController extends Controller
//
Item::withTrashed()
->where('id', $id)
->restore();
$route = route('tags.index', [], false);
->restore();
$route = route('tags.index', []);
return redirect($route)
->with('success',__('app.alert.success.item_restored'));
->with('success', __('app.alert.success.item_restored'));
}
public function add($tag, $item)
@@ -188,14 +196,15 @@ class TagController extends Controller
$output = 0;
$tag = Item::find($tag);
$item = Item::find($item);
if($tag && $item) {
if ($tag && $item) {
// only add items, not cats
if((int)$item->type === 0) {
if ((int) $item->type === 0) {
$tag->children()->attach($item);
return 1;
}
}
return $output;
}
}

View File

@@ -2,11 +2,11 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class UserController extends Controller
{
@@ -14,6 +14,7 @@ class UserController extends Controller
{
$this->middleware('allowed')->except(['selectUser']);
}
/**
* Display a listing of the resource.
*
@@ -22,6 +23,7 @@ class UserController extends Controller
public function index()
{
$data['users'] = User::all();
return view('users.index', $data);
}
@@ -33,6 +35,7 @@ class UserController extends Controller
public function create()
{
$data = [];
return view('users.create', $data);
}
@@ -40,8 +43,8 @@ class UserController extends Controller
{
Auth::logout();
$data['users'] = User::all();
return view('userselect', $data);
return view('userselect', $data);
}
/**
@@ -56,7 +59,7 @@ class UserController extends Controller
'username' => 'required|max:255|unique:users',
'email' => 'required|email',
'password' => 'nullable|confirmed',
'password_confirmation' => 'nullable'
'password_confirmation' => 'nullable',
]);
$user = new User;
@@ -65,24 +68,25 @@ class UserController extends Controller
$user->public_front = $request->input('public_front');
$password = $request->input('password');
if(!empty($password)) {
if (! empty($password)) {
$user->password = bcrypt($password);
}
if($request->hasFile('file')) {
if ($request->hasFile('file')) {
$path = $request->file('file')->store('avatars');
$user->avatar = $path;
}
if ((bool)$request->input('autologin_allow') === true) {
$user->autologin = (string)Str::uuid();
if ((bool) $request->input('autologin_allow') === true) {
$user->autologin = (string) Str::uuid();
}
$user->save();
$route = route('dash', [], false);
$route = route('dash', []);
return redirect($route)
->with('success',__('app.alert.success.user_updated'));
->with('success', __('app.alert.success.user_updated'));
}
/**
@@ -105,8 +109,8 @@ class UserController extends Controller
public function edit(User $user)
{
$data['user'] = $user;
return view('users.edit', $data);
return view('users.edit', $data);
}
/**
@@ -122,38 +126,38 @@ class UserController extends Controller
'username' => 'required|max:255|unique:users,username,'.$user->id,
'email' => 'required|email',
'password' => 'nullable|confirmed',
'password_confirmation' => 'nullable'
'password_confirmation' => 'nullable',
]);
//die(print_r($request->all()));
//die(print_r($request->all()));
$user->username = $request->input('username');
$user->email = $request->input('email');
$user->public_front = $request->input('public_front');
$password = $request->input('password');
if(!empty($password)) {
if (! empty($password)) {
$user->password = bcrypt($password);
} elseif($password == 'null') {
} elseif ($password == 'null') {
$user->password = null;
}
if($request->hasFile('file')) {
if ($request->hasFile('file')) {
$path = $request->file('file')->store('avatars');
$user->avatar = $path;
}
if ((bool)$request->input('autologin_allow') === true) {
$user->autologin = (is_null($user->autologin)) ? (string)Str::uuid() : $user->autologin;
if ((bool) $request->input('autologin_allow') === true) {
$user->autologin = (is_null($user->autologin)) ? (string) Str::uuid() : $user->autologin;
} else {
$user->autologin = null;
}
$user->save();
$route = route('dash', [], false);
return redirect($route)
->with('success',__('app.alert.success.user_updated'));
$route = route('dash', []);
return redirect($route)
->with('success', __('app.alert.success.user_updated'));
}
/**
@@ -164,12 +168,12 @@ class UserController extends Controller
*/
public function destroy(User $user)
{
if($user->id !== 1) {
if ($user->id !== 1) {
$user->delete();
$route = route('dash', [], false);
return redirect($route)
->with('success',__('app.alert.success.user_deleted'));
$route = route('dash', []);
return redirect($route)
->with('success', __('app.alert.success.user_deleted'));
}
}
}

View File

@@ -2,9 +2,9 @@
namespace App\Http\Middleware;
use App\User;
use Closure;
use Illuminate\Support\Facades\Auth;
use App\User;
use Illuminate\Support\Facades\Route;
use Session;
@@ -22,27 +22,32 @@ class CheckAllowed
$route = Route::currentRouteName();
$current_user = User::currentUser();
if(str_is('users*', $route)) {
if($current_user->id !== 1) {
if (str_is('users*', $route)) {
if ($current_user->id !== 1) {
return redirect()->route('dash');
}
}
if($route == 'dash') {
if ($route == 'dash') {
//print_r(User::all());
//die("here".var_dump($current_user->password));
if((bool)$current_user->public_front === true) return $next($request);
if ((bool) $current_user->public_front === true) {
return $next($request);
}
}
if(empty($current_user->password)) return $next($request);
if (empty($current_user->password)) {
return $next($request);
}
// Check if user is logged in as $current_user
if (Auth::check()) {
$loggedin_user = Auth::user();
if($loggedin_user->id === $current_user->id) return $next($request);
if ($loggedin_user->id === $current_user->id) {
return $next($request);
}
}
return Auth::authenticate();
}
}

View File

@@ -2,8 +2,8 @@
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
@@ -12,7 +12,7 @@ class TrustProxies extends Middleware
*
* @var array
*/
protected $proxies;
protected $proxies = ['192.168.0.0/16', '172.16.0.0/12', '10.0.0.0/8', '127.0.0.1'];
/**
* The current proxy header mappings.

View File

@@ -3,6 +3,7 @@
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
use Symfony\Component\HttpFoundation\Cookie;
class VerifyCsrfToken extends Middleware
{
@@ -18,4 +19,39 @@ class VerifyCsrfToken extends Middleware
'test_config',
//'get_stats'
];
/**
* Add the CSRF token to the response cookies.
*
* @param \Illuminate\Http\Request $request
* @param \Symfony\Component\HttpFoundation\Response $response
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function addCookieToResponse($request, $response)
{
$config = config('session');
if ($response instanceof Responsable) {
$response = $response->toResponse($request);
}
$response->headers->setCookie(
new Cookie(
'HEIMDALL-XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']),
$config['path'], $config['domain'], $config['secure'], false, false, $config['same_site'] ?? null
)
);
return $response;
}
/**
* Determine if the cookie contents should be serialized.
*
* @return bool
*/
public static function serialized()
{
return EncryptCookies::serialized('HEIMDALL-XSRF-TOKEN');
}
}

View File

@@ -2,11 +2,13 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use Symfony\Component\ClassLoader\ClassMapGenerator;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;
use App\Application;
use App\ItemTag;
use App\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\ClassLoader\ClassMapGenerator;
class Item extends Model
{
@@ -18,21 +20,20 @@ class Item extends Model
static::addGlobalScope('user_id', function (Builder $builder) {
$current_user = User::currentUser();
$builder->where('user_id', $current_user->id);
if ($current_user) {
$builder->where('user_id', $current_user->id)->orWhere('user_id', 0);
} else {
$builder->where('user_id', 0);
}
});
}
//
protected $fillable = [
'title', 'url', 'colour', 'icon', 'description', 'pinned', 'order', 'type', 'class', 'user_id'
'title', 'url', 'colour', 'icon', 'appdescription', 'description', 'pinned', 'order', 'type', 'class', 'user_id', 'appid',
];
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['deleted_at'];
/**
* Scope a query to only include pinned items.
@@ -47,41 +48,49 @@ class Item extends Model
public static function checkConfig($config)
{
if(empty($config)) {
// die(print_r($config));
if (empty($config)) {
$config = null;
} else {
$store = false;
//die(var_dump($config));
foreach($config as $key => $check) {
if($key == 'type') continue;
if($key == 'dataonly') continue;
if(!empty($check) && $check != '0') {
$store = true;
break;
}
}
//die(var_dump($store))
$config['enabled'] = ($store) ? true : false;
$config = json_encode($config);
}
return $config;
return $config;
}
public function tags()
{
$id = $this->id;
$tags = ItemTag::select('tag_id')->where('item_id', $id)->pluck('tag_id')->toArray();
$tagdetails = self::select('id', 'title', 'url', 'pinned')->whereIn('id', $tags)->get();
//print_r($tags);
if (in_array(0, $tags)) {
$details = new self([
'id' => 0,
'title' => __('app.dashboard'),
'url' => '',
'pinned' => 0,
]);
$tagdetails->prepend($details);
}
return $tagdetails;
}
public function parents()
{
return $this->belongsToMany('App\Item', 'item_tag', 'item_id', 'tag_id');
return $this->belongsToMany(\App\Item::class, 'item_tag', 'item_id', 'tag_id');
}
public function children()
{
return $this->belongsToMany('App\Item', 'item_tag', 'tag_id', 'item_id');
return $this->belongsToMany(\App\Item::class, 'item_tag', 'tag_id', 'item_id');
}
public function getLinkAttribute()
{
if((int)$this->type === 1) {
return '/tag/'.$this->url;
if ((int) $this->type === 1) {
return url('tag/'.$this->url);
} else {
return $this->url;
}
@@ -89,7 +98,7 @@ class Item extends Model
public function getDroppableAttribute()
{
if((int)$this->type === 1) {
if ((int) $this->type === 1) {
return ' droppable';
} else {
return '';
@@ -100,33 +109,42 @@ class Item extends Model
{
$target = Setting::fetch('window_target');
if((int)$this->type === 1 || $target === 'current') {
if ((int) $this->type === 1 || $target === 'current') {
return '';
} else {
return ' target="' . $target . '"';
return ' target="'.$target.'"';
}
}
public function getLinkIconAttribute()
{
if((int)$this->type === 1) {
if ((int) $this->type === 1) {
return 'fa-tag';
} else {
return 'fa-arrow-alt-to-right';
}
}
public function getLinkTypeAttribute()
{
if((int)$this->type === 1) {
if ((int) $this->type === 1) {
return 'tags';
} else {
return 'items';
}
}
public static function nameFromClass($class)
{
$explode = explode('\\', $class);
$name = end($explode);
return $name;
}
public function scopeOfType($query, $type)
{
switch($type) {
switch ($type) {
case 'item':
$typeid = 0;
break;
@@ -140,61 +158,100 @@ class Item extends Model
public function enhanced()
{
if(isset($this->class) && !empty($this->class)) {
/*if(isset($this->class) && !empty($this->class)) {
$app = new $this->class;
} else {
return false;
}
return (bool)($app instanceof \App\EnhancedApps);
return (bool)($app instanceof \App\EnhancedApps);*/
return $this->description !== null;
}
public static function isEnhanced($class)
{
if ($class === null || $class === 'null') {
return false;
}
$app = new $class;
return (bool) ($app instanceof \App\EnhancedApps);
}
public static function isSearchProvider($class)
{
$app = new $class;
return ((bool) ($app instanceof \App\SearchInterface)) ? $app : false;
}
public function enabled()
{
if($this->enhanced()) {
if ($this->enhanced()) {
$config = $this->getconfig();
if($config) {
if ($config) {
return (bool) $config->enabled;
}
}
return false;
}
public function getconfig()
{
$explode = explode('\\', $this->class);
// $explode = explode('\\', $this->class);
if(!isset($this->description) || empty($this->description)) {
if (! isset($this->description) || empty($this->description)) {
$config = new \stdClass;
$config->name = end($explode);
// $config->name = end($explode);
$config->enabled = false;
$config->override_url = null;
$config->apikey = null;
return $config;
}
$config = json_decode($this->description);
$config->name = end($explode);
// $config->name = end($explode);
$config->url = $this->url;
if(isset($config->override_url) && !empty($config->override_url)) {
if (isset($config->override_url) && ! empty($config->override_url)) {
$config->url = $config->override_url;
} else {
$config->override_url = null;
}
return $config;
}
public static function applicationDetails($class)
{
if (! empty($class)) {
$name = self::nameFromClass($class);
$application = Application::where('name', $name)->first();
if ($application) {
return $application;
}
}
return false;
}
public static function getApplicationDescription($class)
{
$details = self::applicationDetails($class);
if ($details !== false) {
return $details->description.' - '.$details->license;
}
return '';
}
/**
* Get the user that owns the item.
*/
public function user()
{
return $this->belongsTo('App\User');
}
return $this->belongsTo(\App\User::class);
}
}

9
app/ItemTag.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class ItemTag extends Pivot
{
}

View File

@@ -2,13 +2,15 @@
namespace App\Jobs;
use App\Application;
use App\Item;
use App\SupportedApps;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Application;
use App\SupportedApps;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
class ProcessApps implements ShouldQueue
{
@@ -31,33 +33,22 @@ class ProcessApps implements ShouldQueue
*/
public function handle()
{
$localapps = Application::all();
$list = json_decode(SupportedApps::getList()->getBody());
$validapps = [];
foreach($list->apps as $app) {
$validapps[] = $app->appid;
if(!file_exists(app_path('SupportedApps/'.className($app->name)))) {
SupportedApps::getFiles($app);
$application = new Application;
SupportedApps::saveApp($app, $application);
} else {
// check if there has been an update for this app
$localapp = $localapps->where('appid', $app->appid)->first();
if($localapp) {
if($localapp->sha !== $app->sha) {
SupportedApps::getFiles($app);
SupportedApps::saveApp($app, $localapp);
}
} else {
SupportedApps::getFiles($app);
$application = new Application;
SupportedApps::saveApp($app, $application);
}
$localapps = Application::whereNull('class')->get();
$json = SupportedApps::getList()->getBody();
Storage::disk('local')->put('supportedapps.json', $json);
foreach ($localapps as $app) {
$app->class = $app->class();
$app->save();
}
$items = Item::whereNotNull('class')->get();
foreach ($items as $item) {
if (! file_exists(app_path('SupportedApps/'.Item::nameFromClass($item->class)))) {
$app = Application::where('class', $item->class)->first();
Application::getApp($app->appid);
}
}
//$delete = Application::whereNotIn('appid', $validapps)->delete(); // delete any apps not in list
// removed the delete so local apps can be added
}
}

View File

@@ -2,13 +2,13 @@
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Artisan;
use Schema;
use App\Setting;
use App\User;
use App\Application;
use App\Jobs\ProcessApps;
use App\Setting;
use App\User;
use Artisan;
use Illuminate\Support\ServiceProvider;
use Schema;
class AppServiceProvider extends ServiceProvider
{
@@ -19,102 +19,111 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot()
{
if(!is_file(base_path('.env'))) {
touch(base_path('.env'));
Artisan::call('key:generate');
if (! is_file(base_path('.env'))) {
copy(base_path('.env.example'), base_path('.env'));
}
if(!is_file(database_path('app.sqlite'))) {
$this->genKey();
if (! is_file(database_path('app.sqlite'))) {
// first time setup
touch(database_path('app.sqlite'));
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
Artisan::call('migrate', ['--path' => 'database/migrations', '--force' => true, '--seed' => true]);
//Cache
//Artisan::call('config:cache');
//Artisan::call('route:cache');
}
if(is_file(database_path('app.sqlite'))) {
if(Schema::hasTable('settings')) {
if (is_file(database_path('app.sqlite'))) {
if (Schema::hasTable('settings')) {
// check version to see if an upgrade is needed
$db_version = Setting::_fetch('version');
$app_version = config('app.version');
if(version_compare($app_version, $db_version) == 1) { // app is higher than db, so need to run migrations etc
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
if (version_compare($app_version, $db_version) == 1) { // app is higher than db, so need to run migrations etc
Artisan::call('migrate', ['--path' => 'database/migrations', '--force' => true, '--seed' => true]);
}
} else {
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
Artisan::call('migrate', ['--path' => 'database/migrations', '--force' => true, '--seed' => true]);
}
}
$applications = Application::all();
if($applications->count() <= 0) {
if (class_exists('ZipArchive')) {
ProcessApps::dispatch();
} else {
die("You are missing php-zip");
}
}
if(!is_file(public_path('storage'))) {
if (! is_file(public_path('storage/.gitignore'))) {
Artisan::call('storage:link');
\Session::put('current_user', null);
}
// User specific settings need to go here as session isn't available at this point in the app
view()->composer('*', function ($view)
{
$lang = Setting::fetch('language');
\App::setLocale($lang);
if(isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
$applications = Application::all();
if ($applications->count() <= 0) {
if (class_exists('ZipArchive')) {
ProcessApps::dispatch();
} else {
die('You are missing php-zip');
}
}
// User specific settings need to go here as session isn't available at this point in the app
view()->composer('*', function ($view) {
if (isset($_SERVER['HTTP_AUTHORIZATION']) && ! empty($_SERVER['HTTP_AUTHORIZATION'])) {
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
}
if(!\Auth::check()) {
if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
if (! \Auth::check()) {
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])
&& ! empty($_SERVER['PHP_AUTH_USER']) && ! empty($_SERVER['PHP_AUTH_PW'])) {
$credentials = ['username' => $_SERVER['PHP_AUTH_USER'], 'password' => $_SERVER['PHP_AUTH_PW']];
if (\Auth::attempt($credentials)) {
if (\Auth::attempt($credentials, true)) {
// Authentication passed...
$user = \Auth::user();
//\Session::put('current_user', $user);
session(['current_user' => $user]);
session(['current_user' => $user]);
}
} elseif (isset($_SERVER['REMOTE_USER']) && ! empty($_SERVER['REMOTE_USER'])) {
$user = User::where('username', $_SERVER['REMOTE_USER'])->first();
if ($user) {
\Auth::login($user, true);
session(['current_user' => $user]);
}
}
}
$alt_bg = '';
if($bg_image = Setting::fetch('background_image')) {
$alt_bg = ' style="background-image: url(/storage/'.$bg_image.')"';
if ($bg_image = Setting::fetch('background_image')) {
$alt_bg = ' style="background-image: url(storage/'.$bg_image.')"';
}
$lang = Setting::fetch('language');
\App::setLocale($lang);
$allusers = User::all();
$current_user = User::currentUser();
$view->with('alt_bg', $alt_bg );
$view->with('allusers', $allusers );
$view->with('current_user', $current_user );
});
$view->with('alt_bg', $alt_bg);
$view->with('allusers', $allusers);
$view->with('current_user', $current_user);
});
$this->app['view']->addNamespace('SupportedApps', app_path('SupportedApps'));
if (env('FORCE_HTTPS') === true) {
\URL::forceScheme('https');
}
if(env('APP_URL') != 'http://localhost') {
if (env('APP_URL') != 'http://localhost') {
\URL::forceRootUrl(env('APP_URL'));
}
}
/**
* Generate app key if missing and .env exists
*
* @return void
*/
public function genKey()
{
if (is_file(base_path('.env'))) {
if (empty(env('APP_KEY'))) {
Artisan::call('key:generate', ['--force' => true, '--no-interaction' => true]);
}
}
}
/**

View File

@@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{

View File

@@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{

View File

@@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{

View File

@@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{

138
app/Search.php Normal file
View File

@@ -0,0 +1,138 @@
<?php
namespace App;
use App\Item;
use App\Setting;
use Cache;
use Form;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Yaml;
abstract class Search
{
/**
* List of all search providers
*
* @return array
*/
public static function providers()
{
$providers = self::standardProviders();
$providers = $providers + self::appProviders();
return collect($providers);
}
/**
* Gets details for a single provider
*
* @return object
*/
public static function providerDetails($provider)
{
$providers = self::providers();
if (! isset($providers[$provider])) {
return false;
}
return (object) $providers[$provider] ?? false;
}
/**
* Array of the standard providers
*
* @return array
*/
public static function standardProviders()
{
// $providers = json_decode(file_get_contents(storage_path('app/searchproviders.json')));
// print_r($providers);
$providers = Yaml::parseFile(storage_path('app/searchproviders.yaml'));
$all = [];
foreach ($providers as $key => $provider) {
$all[$key] = $provider;
$all[$key]['type'] = 'standard';
}
return $all;
}
/**
* Loops through users apps to see if app is a search provider, might be worth
* looking into caching this at some point
*
* @return array
*/
public static function appProviders()
{
$providers = [];
$userapps = Item::all();
foreach ($userapps as $app) {
if (empty($app->class)) {
continue;
}
if (($provider = Item::isSearchProvider($app->class)) !== false) {
$name = Item::nameFromClass($app->class);
$providers[$app->id] = [
'id' => $app->id,
'type' => $provider->type,
'class' => $app->class,
'url' => $app->url,
'name' => $app->title,
'colour' => $app->colour,
'icon' => $app->icon,
'description' => $app->description,
];
}
}
return $providers;
}
/**
* Outputs the search form
*
* @return html
*/
public static function form()
{
$output = '';
$homepage_search = Setting::fetch('homepage_search');
$search_provider = Setting::where('key', '=', 'search_provider')->first();
$user_search_provider = Setting::fetch('search_provider');
//die(print_r($search_provider));
//die(var_dump($user_search_provider));
// return early if search isn't applicable
if ((bool) $homepage_search !== true) {
return $output;
}
$user_search_provider = $user_search_provider ?? 'none';
if ((bool) $homepage_search && (bool) $search_provider) {
if ((bool) $user_search_provider) {
$name = 'app.options.'.$user_search_provider;
$provider = self::providerDetails($user_search_provider);
$output .= '<div class="searchform">';
$output .= '<form action="'.url('search').'"'.getLinkTargetAttribute().' method="get">';
$output .= '<div id="search-container" class="input-container">';
$output .= '<select name="provider">';
foreach (self::providers() as $key => $searchprovider) {
$selected = ((string) $key === (string) $user_search_provider) ? ' selected="selected"' : '';
$output .= '<option value="'.$key.'"'.$selected.'>'.$searchprovider['name'].'</option>';
}
$output .= '</select>';
$output .= Form::text('q', null, ['class' => 'homesearch', 'autofocus' => 'autofocus', 'placeholder' => __('app.settings.search').'...']);
$output .= '<button type="submit">'.ucwords(__('app.settings.search')).'</button>';
$output .= '</div>';
$output .= '</form>';
$output .= '</div>';
}
}
return $output;
}
}

11
app/SearchInterface.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
namespace App;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
interface SearchInterface
{
public function getResults($query, $providerdetails);
}

View File

@@ -2,11 +2,13 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Input;
use Form;
use Illuminate\Support\Facades\Auth;
use App\Search;
use App\User;
use Form;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
class Setting extends Model
{
@@ -18,7 +20,7 @@ class Setting extends Model
protected $table = 'settings';
protected $fillable = [
'id', 'group_id', 'key', 'type', 'options', 'label', 'value', 'order', 'system'
'id', 'group_id', 'key', 'type', 'options', 'label', 'value', 'order', 'system',
];
/**
@@ -38,44 +40,47 @@ class Setting extends Model
/**
* @return array
*/
public static function getInput()
public static function getInput(Request $request)
{
return (object) [
'value' => Input::get('value'),
'image' => Input::file('value'),
'value' => $request->input('value'),
'image' => $request->file('value'),
];
}
public function getListValueAttribute()
{
if((bool)$this->system === true) {
if ((bool) $this->system === true) {
$value = self::_fetch($this->key);
} else {
$value = self::fetch($this->key);
}
$this->value = $value;
switch($this->type) {
switch ($this->type) {
case 'image':
if(!empty($this->value)) {
if (! empty($this->value)) {
$value = '<a href="'.asset('storage/'.$this->value).'" title="'.__('app.settings.view').'" target="_blank">'.__('app.settings.view').'</a>';
} else {
$value = __('app.options.none');
}
}
break;
case 'boolean':
if((bool)$this->value === true) {
if ((bool) $this->value === true) {
$value = __('app.options.yes');
} else {
$value = __('app.options.no');
}
}
break;
case 'select':
if(!empty($this->value) && $this->value !== 'none') {
$options = (array)json_decode($this->options);
if (! empty($this->value) && $this->value !== 'none') {
$options = (array) json_decode($this->options);
if ($this->key === 'search_provider') {
$options = Search::providers()->pluck('name', 'id')->toArray();
}
$value = __($options[$this->value]);
} else {
$value = __('app.options.none');
}
}
break;
default:
$value = __($this->value);
@@ -83,32 +88,33 @@ class Setting extends Model
}
return $value;
}
public function getEditValueAttribute()
{
if((bool)$this->system === true) {
if ((bool) $this->system === true) {
$value = self::_fetch($this->key);
} else {
$value = self::fetch($this->key);
}
$this->value = $value;
switch($this->type) {
switch ($this->type) {
case 'image':
$value = '';
if(isset($this->value) && !empty($this->value)) {
if (isset($this->value) && ! empty($this->value)) {
$value .= '<a class="setting-view-image" href="'.asset('storage/'.$this->value).'" title="'.__('app.settings.view').'" target="_blank"><img src="'.asset('storage/'.$this->value).'" /></a>';
}
$value .= Form::file('value', ['class' => 'form-control']);
if(isset($this->value) && !empty($this->value)) {
if (isset($this->value) && ! empty($this->value)) {
$value .= '<a class="settinglink" href="'.route('settings.clear', $this->id).'" title="'.__('app.settings.remove').'">'.__('app.settings.reset').'</a>';
}
break;
case 'boolean':
$checked = false;
if(isset($this->value) && (bool)$this->value === true) $checked = true;
if (isset($this->value) && (bool) $this->value === true) {
$checked = true;
}
$set_checked = ($checked) ? ' checked="checked"' : '';
$value = '
<input type="hidden" name="value" value="0" />
@@ -120,26 +126,30 @@ class Setting extends Model
break;
case 'select':
$options = json_decode($this->options);
foreach($options as $key => $opt) {
if ($this->key === 'search_provider') {
$options = Search::providers()->pluck('name', 'id');
}
foreach ($options as $key => $opt) {
$options->$key = __($opt);
}
$value = Form::select('value', $options, null, ['class' => 'form-control']);
break;
case 'textarea':
$value = Form::textarea('value', null, ['class' => 'form-control', 'cols' => '44', 'rows' => '15']);
break;
default:
$value = Form::text('value', null, ['class' => 'form-control']);
break;
}
return $value;
}
public function group()
{
return $this->belongsTo('App\SettingGroup', 'group_id');
return $this->belongsTo(\App\SettingGroup::class, 'group_id');
}
/**
* @param string $key
*
@@ -148,53 +158,54 @@ class Setting extends Model
public static function fetch($key)
{
$user = self::user();
return self::_fetch($key, $user);
}
/**
* @param string $key
*
* @return mixed
*/
public static function _fetch($key, $user=null)
public static function _fetch($key, $user = null)
{
#$cachekey = ($user === null) ? $key : $key.'-'.$user->id;
#if (Setting::cached($cachekey)) {
# return Setting::$cache[$cachekey];
#} else {
$find = self::where('key', '=', $key)->first();
//$cachekey = ($user === null) ? $key : $key.'-'.$user->id;
//if (Setting::cached($cachekey)) {
// return Setting::$cache[$cachekey];
//} else {
$find = self::where('key', '=', $key)->first();
if (!is_null($find)) {
if((bool)$find->system === true) { // if system variable use global value
if (! is_null($find)) {
if ((bool) $find->system === true) { // if system variable use global value
$value = $find->value;
} else { // not system variable so use user specific value
// check if user specified value has been set
//print_r($user);
$usersetting = $user->settings()->where('id', $find->id)->first();
//print_r($user->settings);
//die(var_dump($usersetting));
//->pivot->value;
//echo "user: ".$user->id." --- ".$usersettings;
if (isset($usersetting) && ! empty($usersetting)) {
$value = $usersetting->pivot->uservalue;
} else { // if not get default from base setting
//$user->settings()->save($find, ['value' => $find->value]);
//$has_setting = $user->settings()->where('id', $find->id)->exists();
//if($has_setting) {
// $user->settings()->updateExistingPivot($find->id, ['uservalue' => (string)$find->value]);
//} else {
// $user->settings()->save($find, ['uservalue' => (string)$find->value]);
//}
$value = $find->value;
} else { // not system variable so use user specific value
// check if user specified value has been set
//print_r($user);
$usersetting = $user->settings()->where('id', $find->id)->first();
//print_r($user->settings);
//die(var_dump($usersetting));
//->pivot->value;
//echo "user: ".$user->id." --- ".$usersettings;
if(isset($usersetting) && !empty($usersetting)) {
$value = $usersetting->pivot->uservalue;
} else { // if not get default from base setting
//$user->settings()->save($find, ['value' => $find->value]);
#$has_setting = $user->settings()->where('id', $find->id)->exists();
#if($has_setting) {
# $user->settings()->updateExistingPivot($find->id, ['uservalue' => (string)$find->value]);
#} else {
# $user->settings()->save($find, ['uservalue' => (string)$find->value]);
#}
$value = $find->value;
}
}
#Setting::add($cachekey, $value);
return $value;
} else {
return false;
}
#}
//Setting::add($cachekey, $value);
return $value;
} else {
return false;
}
//}
}
/**
@@ -203,7 +214,7 @@ class Setting extends Model
*/
public static function add($key, $value)
{
Setting::$cache[$key] = $value;
self::$cache[$key] = $value;
}
/**
@@ -213,61 +224,7 @@ class Setting extends Model
*/
public static function cached($key)
{
return array_key_exists($key, Setting::$cache);
}
/**
* @return html
*/
public static function search()
{
$output = '';
$homepage_search = self::fetch('homepage_search');
$search_provider = self::where('key', '=', 'search_provider')->first();
$user_search_provider = self::fetch('search_provider');
//die(print_r($search_provider));
//die(var_dump($user_search_provider));
// return early if search isn't applicable
if((bool)$homepage_search !== true) return $output;
if($user_search_provider === 'none') return $output;
if(empty($user_search_provider)) return $output;
if(is_null($user_search_provider)) return $output;
if((bool)$homepage_search && (bool)$search_provider) {
$options = (array)json_decode($search_provider->options);
$name = $options[$user_search_provider];
if((bool)$user_search_provider) {
switch($user_search_provider) {
case 'google':
$url = 'https://www.google.com/search';
$var = 'q';
break;
case 'ddg':
$url = 'https://duckduckgo.com/';
$var = 'q';
break;
case 'bing':
$url = 'https://www.bing.com/search';
$var = 'q';
break;
case 'startpage':
$url = 'https://www.startpage.com/';
$var = 'q';
}
$output .= '<div class="searchform">';
$output .= Form::open(['url' => $url, 'method' => 'get']);
$output .= '<div class="input-container">';
$output .= Form::text($var, null, ['class' => 'homesearch', 'autofocus' => 'autofocus', 'placeholder' => __($name).' '.__('app.settings.search').'...']);
$output .= '<button type="submit">'.ucwords(__('app.settings.search')).'</button>';
$output .= '</div>';
$output .= Form::close();
$output .= '</div>';
}
}
return $output;
return array_key_exists($key, self::$cache);
}
/**
@@ -275,13 +232,11 @@ class Setting extends Model
*/
public function users()
{
return $this->belongsToMany('App\User')->using('App\SettingUser')->withPivot('uservalue');
return $this->belongsToMany(\App\User::class)->using(\App\SettingUser::class)->withPivot('uservalue');
}
public static function user()
{
return User::currentUser();
}
}

View File

@@ -22,6 +22,6 @@ class SettingGroup extends Model
public function settings()
{
return $this->hasMany('App\Setting', 'group_id');
return $this->hasMany(\App\Setting::class, 'group_id');
}
}

View File

@@ -1,27 +1,37 @@
<?php namespace App;
<?php
namespace App;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;
abstract class SupportedApps
{
protected $jar = false;
protected $method = 'GET';
protected $error;
public function appTest($url, $attrs = [], $overridevars=false)
public function appTest($url, $attrs = [], $overridevars = false)
{
if (empty($this->config->url)) {
return (object) [
'code' => 404,
'status' => 'No URL has been specified',
'response' => 'No URL has been specified',
];
}
$res = $this->execute($url, $attrs);
if($res == null) {
return (object)[
if ($res == null) {
return (object) [
'code' => null,
'status' => $this->error,
'response' => 'Connection failed',
];
}
switch($res->getStatusCode()) {
switch ($res->getStatusCode()) {
case 200:
$status = 'Successfully communicated with the API';
break;
@@ -35,21 +45,22 @@ abstract class SupportedApps
$status = 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
return (object)[
return (object) [
'code' => $res->getStatusCode(),
'status' => $status,
'response' => $res->getBody(),
];
}
public function execute($url, $attrs = [], $overridevars=false, $overridemethod=false)
public function execute($url, $attrs = [], $overridevars = false, $overridemethod = false)
{
$res = null;
$vars = ($overridevars !== false) ?
$overridevars : [
'http_errors' => false,
'timeout' => 15,
'http_errors' => false,
'timeout' => 15,
'connect_timeout' => 15,
];
@@ -58,35 +69,34 @@ abstract class SupportedApps
$method = ($overridemethod !== false) ? $overridemethod : $this->method;
try {
return $client->request($method, $url, $attrs);
return $client->request($method, $url, $attrs);
} catch (\GuzzleHttp\Exception\ConnectException $e) {
Log::error("Connection refused");
Log::error('Connection refused');
Log::debug($e->getMessage());
$this->error = "Connection refused - ".(string) $e->getMessage();
$this->error = 'Connection refused - '.(string) $e->getMessage();
} catch (\GuzzleHttp\Exception\ServerException $e) {
Log::debug($e->getMessage());
$this->error = (string) $e->getResponse()->getBody();
}
$this->error = 'General error connecting with API';
return $res;
}
public function login()
{
}
public function normaliseurl($url, $addslash=true)
public function normaliseurl($url, $addslash = true)
{
$url = rtrim($url, '/');
if($addslash) $url .= '/';
if ($addslash) {
$url .= '/';
}
return $url;
}
public function getLiveStats($status, $data)
{
$className = get_class($this);
@@ -94,24 +104,37 @@ abstract class SupportedApps
$name = end($explode);
$html = view('SupportedApps::'.$name.'.livestats', $data)->with('data', $data)->render();
return json_encode(['status' => $status, 'html' => $html]);
//return
//return
}
public static function getList()
{
$list_url = 'https://apps.heimdall.site/list';
// $list_url = 'https://apps.heimdall.site/list';
$list_url = config('app.appsource').'list.json';
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
return $client->request('GET', $list_url);
}
public static function configValue($item = null, $key = null)
{
if (isset($item) && ! empty($item)) {
return $item->getconfig()->$key;
} else {
return null;
}
}
public static function getFiles($app)
{
$zipurl = $app->files;
$zipurl = config('app.appsource').'files/'.$app->sha.'.zip';
$client = new Client(['http_errors' => false, 'timeout' => 60, 'connect_timeout' => 15]);
$res = $client->request('GET', $zipurl);
if(!file_exists(app_path('SupportedApps'))) {
if (! file_exists(app_path('SupportedApps'))) {
mkdir(app_path('SupportedApps'), 0777, true);
}
@@ -124,31 +147,28 @@ abstract class SupportedApps
$zip->extractTo(app_path('SupportedApps')); // place in the directory with same name
$zip->close();
unlink($src); //Deleting the Zipped file
} else {
var_dump($x);
}
}
public static function saveApp($details, $app)
{
$img_src = app_path('SupportedApps/'.className($details->name).'/'.$details->icon);
$img_dest = public_path('storage/supportedapps/'.$details->icon);
//die("i: ".$img_src);
copy($img_src, $img_dest);
$app->appid = $details->appid;
$app->name = $details->name;
$app->sha = $details->sha ?? null;
$app->icon = 'supportedapps/'.$details->icon;
$app->icon = 'icons/'.$details->icon;
$app->website = $details->website;
$app->license = $details->license;
$app->description = $details->description;
$appclass = $app->class();
$application = new $appclass;
$enhanced = (bool)($application instanceof \App\EnhancedApps);
$enhanced = (bool) ($application instanceof \App\EnhancedApps);
$app->class = $appclass;
$app->enhanced = $enhanced;
$app->tile_background = $details->tile_background;
$app->save();
}
}
return $app;
}
}

View File

@@ -2,8 +2,8 @@
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
@@ -32,7 +32,7 @@ class User extends Authenticatable
*/
public function items()
{
return $this->hasMany('App\Item');
return $this->hasMany(\App\Item::class);
}
/**
@@ -40,7 +40,7 @@ class User extends Authenticatable
*/
public function settings()
{
return $this->belongsToMany('App\Setting')->withPivot('uservalue');
return $this->belongsToMany(\App\Setting::class)->withPivot('uservalue');
}
public static function currentUser()
@@ -49,15 +49,13 @@ class User extends Authenticatable
if ($current_user) { // if logged in, set this user
return $current_user;
} else { // not logged in, get first user
$user = User::where('public_front',true)->first();
if(!$user) {
$user = User::first();
$user = self::where('public_front', true)->first();
if (! $user) {
$user = self::first();
}
session(['current_user' => $user]);
return $user;
}
}
}

View File

@@ -12,7 +12,7 @@
*/
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
/*

View File

@@ -5,14 +5,15 @@
"license": "MIT",
"type": "project",
"require": {
"php": ">=7.0.0",
"php": ">=7.2.5",
"fideloper/proxy": "^4.0",
"graham-campbell/github": "^7.5",
"guzzlehttp/guzzle": "^6.3",
"laravel/framework": "5.7.*",
"laravel/tinker": "~1.0",
"laravelcollective/html": "^5.5",
"php-http/guzzle6-adapter": "^1.1"
"graham-campbell/github": "^10.5",
"guzzlehttp/guzzle": "^7.4",
"laravel/framework": "^7.0",
"laravel/tinker": "^2.0",
"laravel/ui": "^2.4",
"laravelcollective/html": "^6.0",
"symfony/yaml": "^5.4"
},
"require-dev": {
"filp/whoops": "~2.0",
@@ -59,6 +60,10 @@
"config": {
"preferred-install": "dist",
"sort-packages": true,
"optimize-autoloader": true
"optimize-autoloader": true,
"allow-plugins": {
"kylekatarnls/update-helper": true,
"symfony/thanks": true
}
}
}

5424
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -13,8 +13,8 @@ return [
|
*/
'name' => env('APP_NAME', 'Heimdall'),
'version' => '2.1.4',
'name' => env('APP_NAME', 'Heimdall'),
'version' => '2.4.7',
/*
|--------------------------------------------------------------------------
@@ -40,7 +40,7 @@ return [
|
*/
'debug' => env('APP_DEBUG', false),
'debug' => (bool) env('APP_DEBUG', false),
/*
|--------------------------------------------------------------------------
@@ -55,6 +55,9 @@ return [
'url' => env('APP_URL', 'http://localhost'),
'asset_url' => env('ASSET_URL', null),
'appsource' => env('APP_SOURCE', 'https://appslist.heimdall.site/'),
/*
|--------------------------------------------------------------------------
| Application Timezone
@@ -94,6 +97,19 @@ return [
'fallback_locale' => 'en',
/*
|--------------------------------------------------------------------------
| Faker Locale
|--------------------------------------------------------------------------
|
| This locale will be used by the Faker PHP library when generating fake
| data for your database seeds. For example, this will be used to get
| localized telephone numbers, street address information and more.
|
*/
'faker_locale' => 'en_US',
/*
|--------------------------------------------------------------------------
| Encryption Key
@@ -109,23 +125,6 @@ return [
'cipher' => 'AES-256-CBC',
/*
|--------------------------------------------------------------------------
| Logging Configuration
|--------------------------------------------------------------------------
|
| Here you may configure the log settings for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Settings: "single", "daily", "syslog", "errorlog"
|
*/
'log' => env('APP_LOG', 'single'),
'log_level' => env('APP_LOG_LEVEL', 'debug'),
/*
|--------------------------------------------------------------------------
| Autoloaded Service Providers
@@ -194,6 +193,7 @@ return [
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
'Arr' => Illuminate\Support\Arr::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class,
'Auth' => Illuminate\Support\Facades\Auth::class,
'Blade' => Illuminate\Support\Facades\Blade::class,
@@ -211,6 +211,7 @@ return [
'Gate' => Illuminate\Support\Facades\Gate::class,
'Hash' => Illuminate\Support\Facades\Hash::class,
'Html' => Collective\Html\HtmlFacade::class,
'Http' => Illuminate\Support\Facades\Http::class,
'Lang' => Illuminate\Support\Facades\Lang::class,
'Log' => Illuminate\Support\Facades\Log::class,
'Mail' => Illuminate\Support\Facades\Mail::class,
@@ -225,9 +226,11 @@ return [
'Schema' => Illuminate\Support\Facades\Schema::class,
'Session' => Illuminate\Support\Facades\Session::class,
'Storage' => Illuminate\Support\Facades\Storage::class,
'Str' => Illuminate\Support\Str::class,
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Yaml' => Symfony\Component\Yaml\Yaml::class,
'SupportedApps' => App\SupportedApps::class,
'EnhancedApps' => App\EnhancedApps::class,

View File

@@ -44,6 +44,7 @@ return [
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
@@ -96,7 +97,21 @@ return [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];

View File

@@ -37,7 +37,7 @@ return [
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => true,
'useTLS' => true,
],
],

View File

@@ -1,5 +1,7 @@
<?php
use Illuminate\Support\Str;
return [
/*
@@ -36,6 +38,7 @@ return [
'array' => [
'driver' => 'array',
'serialize' => false,
],
'database' => [
@@ -73,6 +76,15 @@ return [
'connection' => 'default',
],
'dynamodb' => [
'driver' => 'dynamodb',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
'endpoint' => env('DYNAMODB_ENDPOINT'),
],
],
/*
@@ -86,9 +98,6 @@ return [
|
*/
'prefix' => env(
'CACHE_PREFIX',
str_slug(env('APP_NAME', 'laravel'), '_').'_cache'
),
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
];

View File

@@ -1,5 +1,7 @@
<?php
use Illuminate\Support\Str;
return [
/*
@@ -42,6 +44,7 @@ return [
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
@@ -51,12 +54,17 @@ return [
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'pgsql' => [
'driver' => 'pgsql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
@@ -64,12 +72,14 @@ return [
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '1433'),
'database' => env('DB_DATABASE', 'forge'),
@@ -77,8 +87,9 @@ return [
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
],
],
/*
@@ -107,13 +118,27 @@ return [
'redis' => [
'client' => 'predis',
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
],

View File

@@ -61,8 +61,10 @@ return [
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
],
],
];

52
config/hashing.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Hash Driver
|--------------------------------------------------------------------------
|
| This option controls the default hash driver that will be used to hash
| passwords for your application. By default, the bcrypt algorithm is
| used; however, you remain free to modify this option if you wish.
|
| Supported: "bcrypt", "argon", "argon2id"
|
*/
'driver' => 'bcrypt',
/*
|--------------------------------------------------------------------------
| Bcrypt Options
|--------------------------------------------------------------------------
|
| Here you may specify the configuration options that should be used when
| passwords are hashed using the Bcrypt algorithm. This will allow you
| to control the amount of time it takes to hash the given password.
|
*/
'bcrypt' => [
'rounds' => env('BCRYPT_ROUNDS', 10),
],
/*
|--------------------------------------------------------------------------
| Argon Options
|--------------------------------------------------------------------------
|
| Here you may specify the configuration options that should be used when
| passwords are hashed using the Argon algorithm. These will allow you
| to control the amount of time it takes to hash the given password.
|
*/
'argon' => [
'memory' => 1024,
'threads' => 2,
'time' => 2,
],
];

104
config/logging.php Normal file
View File

@@ -0,0 +1,104 @@
<?php
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
return [
/*
|--------------------------------------------------------------------------
| Default Log Channel
|--------------------------------------------------------------------------
|
| This option defines the default log channel that gets used when writing
| messages to the logs. The name specified in this option should match
| one of the channels defined in the "channels" configuration array.
|
*/
'default' => env('LOG_CHANNEL', 'stack'),
/*
|--------------------------------------------------------------------------
| Log Channels
|--------------------------------------------------------------------------
|
| Here you may configure the log channels for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Drivers: "single", "daily", "slack", "syslog",
| "errorlog", "monolog",
| "custom", "stack"
|
*/
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single'],
'ignore_exceptions' => false,
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
'days' => 14,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Laravel Log',
'emoji' => ':boom:',
'level' => 'critical',
],
'papertrail' => [
'driver' => 'monolog',
'level' => 'debug',
'handler' => SyslogUdpHandler::class,
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
],
],
'stderr' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => [
'stream' => 'php://stderr',
],
],
'syslog' => [
'driver' => 'syslog',
'level' => 'debug',
],
'errorlog' => [
'driver' => 'errorlog',
'level' => 'debug',
],
'null' => [
'driver' => 'monolog',
'handler' => NullHandler::class,
],
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
],
];

View File

@@ -4,18 +4,16 @@ return [
/*
|--------------------------------------------------------------------------
| Default Queue Driver
| Default Queue Connection Name
|--------------------------------------------------------------------------
|
| Laravel's queue API supports an assortment of back-ends via a single
| API, giving you convenient access to each back-end using the same
| syntax for each one. Here you may set the default queue driver.
|
| Supported: "sync", "database", "beanstalkd", "sqs", "redis", "null"
| syntax for every one. Here you may define a default connection.
|
*/
'default' => env('QUEUE_DRIVER', 'sync'),
'default' => env('QUEUE_CONNECTION', 'sync'),
/*
|--------------------------------------------------------------------------
@@ -26,6 +24,8 @@ return [
| is used by your application. A default configuration has been added
| for each back-end shipped with Laravel. You are free to add more.
|
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
*/
'connections' => [
@@ -46,22 +46,25 @@ return [
'host' => 'localhost',
'queue' => 'default',
'retry_after' => 90,
'block_for' => 0,
],
'sqs' => [
'driver' => 'sqs',
'key' => env('SQS_KEY', 'your-public-key'),
'secret' => env('SQS_SECRET', 'your-secret-key'),
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', 'your-queue-name'),
'region' => env('SQS_REGION', 'us-east-1'),
'suffix' => env('SQS_SUFFIX'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
],
],
@@ -78,6 +81,7 @@ return [
*/
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database'),
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'failed_jobs',
],

View File

@@ -8,31 +8,26 @@ return [
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Stripe, Mailgun, SparkPost and others. This file provides a sane
| default location for this type of information, allowing packages
| to have a conventional place to find your various credentials.
| as Mailgun, Postmark, AWS and more. This file provides the de facto
| location for this type of information, allowing packages to have
| a conventional file to locate the various service credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
],
'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],
'ses' => [
'key' => env('SES_KEY'),
'secret' => env('SES_SECRET'),
'region' => 'us-east-1',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'sparkpost' => [
'secret' => env('SPARKPOST_SECRET'),
],
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
];

View File

@@ -1,5 +1,7 @@
<?php
use Illuminate\Support\Str;
return [
/*
@@ -70,7 +72,7 @@ return [
|
*/
'connection' => null,
'connection' => env('SESSION_CONNECTION', null),
/*
|--------------------------------------------------------------------------
@@ -96,7 +98,7 @@ return [
|
*/
'store' => null,
'store' => env('SESSION_STORE', null),
/*
|--------------------------------------------------------------------------
@@ -124,7 +126,7 @@ return [
'cookie' => env(
'SESSION_COOKIE',
str_slug(env('APP_NAME', 'laravel'), '_').'_session'
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
/*
@@ -164,7 +166,7 @@ return [
|
*/
'secure' => env('SESSION_SECURE_COOKIE', false),
'secure' => env('SESSION_SECURE_COOKIE'),
/*
|--------------------------------------------------------------------------

View File

@@ -28,6 +28,9 @@ return [
|
*/
'compiled' => realpath(storage_path('framework/views')),
'compiled' => env(
'VIEW_COMPILED_PATH',
realpath(storage_path('framework/views'))
),
];
];

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateItemsTable extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateSettingsTable extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateSettingGroupsTable extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddColumnsToItemsForGroups extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ItemTag extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePasswordResetsTable extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddUserIdToItemsTable extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateSettingUserPivotTable extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateApplicationsTable extends Migration
{
@@ -14,7 +14,6 @@ class CreateApplicationsTable extends Migration
public function up()
{
Schema::create('applications', function (Blueprint $table) {
$table->string('appid')->unique();
$table->string('name')->unique();
$table->string('sha')->unique()->nullable();

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddClassToItemsTable extends Migration
{

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateJobsTable extends Migration
{

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateFailedJobsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('failed_jobs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('failed_jobs');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddAppidToItems extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('items', function (Blueprint $table) {
$table->string('appid')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('items', function (Blueprint $table) {
$table->dropColumn(['appid']);
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddClassToApplication extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('applications', function (Blueprint $table) {
$table->string('class')->nullable()->index();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('applications', function (Blueprint $table) {
$table->dropColumn(['class']);
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddAppDescriptionToItems extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('items', function (Blueprint $table) {
$table->text('appdescription')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('items', function (Blueprint $table) {
//
});
}
}

View File

@@ -1,8 +1,8 @@
<?php
use Illuminate\Database\Seeder;
use App\Setting;
use App\SettingGroup;
use Illuminate\Database\Seeder;
class SettingsSeeder extends Seeder
{
@@ -14,7 +14,7 @@ class SettingsSeeder extends Seeder
public function run()
{
// Groups
if(!$setting_group = SettingGroup::find(1)) {
if (! $setting_group = SettingGroup::find(1)) {
$setting_group = new SettingGroup;
$setting_group->id = 1;
$setting_group->title = 'app.settings.system';
@@ -24,7 +24,7 @@ class SettingsSeeder extends Seeder
$setting_group->title = 'app.settings.system';
$setting_group->save();
}
if(!$setting_group = SettingGroup::find(2)) {
if (! $setting_group = SettingGroup::find(2)) {
$setting_group = new SettingGroup;
$setting_group->id = 2;
$setting_group->title = 'app.settings.appearance';
@@ -34,7 +34,7 @@ class SettingsSeeder extends Seeder
$setting_group->title = 'app.settings.appearance';
$setting_group->save();
}
if(!$setting_group = SettingGroup::find(3)) {
if (! $setting_group = SettingGroup::find(3)) {
$setting_group = new SettingGroup;
$setting_group->id = 3;
$setting_group->title = 'app.settings.miscellaneous';
@@ -44,8 +44,18 @@ class SettingsSeeder extends Seeder
$setting_group->title = 'app.settings.miscellaneous';
$setting_group->save();
}
if (! $setting_group = SettingGroup::find(4)) {
$setting_group = new SettingGroup;
$setting_group->id = 4;
$setting_group->title = 'app.settings.advanced';
$setting_group->order = 3;
$setting_group->save();
} else {
$setting_group->title = 'app.settings.advanced';
$setting_group->save();
}
if($version = Setting::find(1)) {
if ($version = Setting::find(1)) {
$version->label = 'app.settings.version';
$version->value = config('app.version');
$version->save();
@@ -61,7 +71,7 @@ class SettingsSeeder extends Seeder
$setting->save();
}
if(!$setting = Setting::find(2)) {
if (! $setting = Setting::find(2)) {
$setting = new Setting;
$setting->id = 2;
$setting->group_id = 2;
@@ -73,7 +83,7 @@ class SettingsSeeder extends Seeder
$setting->label = 'app.settings.background_image';
$setting->save();
}
if(!$setting = Setting::find(3)) {
if (! $setting = Setting::find(3)) {
$setting = new Setting;
$setting->id = 3;
$setting->group_id = 3;
@@ -90,12 +100,12 @@ class SettingsSeeder extends Seeder
'none' => 'app.options.none',
'google' => 'app.options.google',
'ddg' => 'app.options.ddg',
'qwant' => 'app.options.qwant',
'bing' => 'app.options.bing',
'startpage' => 'app.options.startpage',
]);
if(!$setting = Setting::find(4)) {
if (! $setting = Setting::find(4)) {
$setting = new Setting;
$setting->id = 4;
$setting->group_id = 3;
@@ -110,20 +120,21 @@ class SettingsSeeder extends Seeder
$setting->save();
}
$language_options = json_encode([
'de' => 'Deutsch (German)',
'en' => 'English',
'cn' => '简体中文 (Simplified Chinese)',
'fi' => 'Suomi (Finnish)',
'fr' => 'Français (French)',
'el' => 'Ελληνικά (Greek)',
'it' => 'Italiano (Italian)',
'no' => 'Norsk (Norwegian)',
'pl' => 'Polski (Polish)',
'no' => 'Norsk (Norwegian)',
'pl' => 'Polski (Polish)',
'sv' => 'Svenska (Swedish)',
'es' => 'Español (Spanish)',
'tr' => 'Türkçe (Turkish)',
]);
if($languages = Setting::find(5)) {
if ($languages = Setting::find(5)) {
$languages->options = $language_options;
$languages->save();
} else {
@@ -144,8 +155,7 @@ class SettingsSeeder extends Seeder
'_blank' => 'app.settings.window_target.new',
]);
if(!$setting = Setting::find(7)) {
if (! $setting = Setting::find(7)) {
$setting = new Setting;
$setting->id = 7;
$setting->group_id = 3;
@@ -161,7 +171,7 @@ class SettingsSeeder extends Seeder
$setting->save();
}
if($support = Setting::find(8)) {
if ($support = Setting::find(8)) {
$support->label = 'app.settings.support';
$support->value = '<a rel="noopener" target="_blank" href="https://discord.gg/CCjHKn4">Discord</a> | <a rel="noopener" target="_blank" href="https://github.com/linuxserver/Heimdall">Github</a> | <a rel="noopener" target="_blank" href="https://blog.heimdall.site/">Blog</a>';
$support->save();
@@ -177,7 +187,7 @@ class SettingsSeeder extends Seeder
$setting->save();
}
if($donate = Setting::find(9)) {
if ($donate = Setting::find(9)) {
$donate->label = 'app.settings.donate';
$donate->value = '<a rel="noopener" target="_blank" href="https://www.paypal.me/heimdall">Paypal</a>';
$donate->save();
@@ -193,5 +203,55 @@ class SettingsSeeder extends Seeder
$setting->save();
}
if (! $setting = Setting::find(10)) {
$setting = new Setting;
$setting->id = 10;
$setting->group_id = 4;
$setting->key = 'custom_css';
$setting->type = 'textarea';
$setting->label = 'app.settings.custom_css';
$setting->value = '';
$setting->save();
} else {
$setting->type = 'textarea';
$setting->group_id = 4;
$setting->label = 'app.settings.custom_css';
$setting->save();
}
if (! $setting = Setting::find(11)) {
$setting = new Setting;
$setting->id = 11;
$setting->group_id = 4;
$setting->key = 'custom_js';
$setting->type = 'textarea';
$setting->label = 'app.settings.custom_js';
$setting->value = '';
$setting->save();
} else {
$setting->type = 'textarea';
$setting->group_id = 4;
$setting->label = 'app.settings.custom_js';
$setting->save();
}
if (! $home_tag = \App\Item::find(0)) {
$home_tag = new \App\Item;
$home_tag->id = 0;
$home_tag->title = 'app.dashboard';
$home_tag->pinned = 0;
$home_tag->url = '';
$home_tag->type = 1;
$home_tag->user_id = 0;
$home_tag->save();
$homeapps = \App\Item::withoutGlobalScope('user_id')->doesntHave('parents')->get();
foreach ($homeapps as $app) {
if ($app->id === 0) {
continue;
}
$app->parents()->attach(0);
}
}
}
}

View File

@@ -1,7 +1,7 @@
<?php
use Illuminate\Database\Seeder;
use App\User;
use Illuminate\Database\Seeder;
class UsersSeeder extends Seeder
{
@@ -13,7 +13,7 @@ class UsersSeeder extends Seeder
public function run()
{
// Groups
if(!$user = User::find(1)) {
if (! $user = User::find(1)) {
$user = new User;
$user->id = 1;
$user->username = 'admin';

9975
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,12 +10,14 @@
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"bootstrap-sass": "^3.3.7",
"bootstrap-sass": "^3.4.1",
"cross-env": "^5.2.0",
"jquery": "^3.2",
"laravel-mix": "^2.1.14"
"jquery": "^3.4.1",
"laravel-mix": "^4.0.16",
"sass": "^1.21.0",
"sass-loader": "7.*"
},
"dependencies": {
"select2": "^4.0.6-rc.1"
"select2": "^4.0.7"
}
}

View File

@@ -1,21 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
>
<testsuites>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
@@ -23,9 +18,14 @@
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<!-- <server name="DB_CONNECTION" value="sqlite"/> -->
<!-- <server name="DB_DATABASE" value=":memory:"/> -->
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>
</phpunit>

5
public/css/all.min.css vendored Normal file
View File

@@ -0,0 +1,5 @@
/*!
* Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
*/
.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-ban:before{content:"\f05e"}.fa-check:before{content:"\f00c"}.fa-cloud-download:before{content:"\f0ed"}.fa-cogs:before{content:"\f085"}.fa-edit:before{content:"\f044"}.fa-exchange:before{content:"\f0ec"}.fa-list:before{content:"\f03a"}.fa-pencil:before{content:"\f040"}.fa-plus:before{content:"\f067"}.fa-save:before{content:"\f0c7"}.fa-tag:before{content:"\f02b"}.fa-th:before{content:"\f00a"}.fa-thumbtack:before{content:"\f08d"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-user:before{content:"\f007"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Pro";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Pro";font-weight:900}

4766
public/css/app.css vendored

File diff suppressed because it is too large Load Diff

843
public/js/app.js vendored

File diff suppressed because one or more lines are too long

2482
public/js/fontawesome.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
public/js/jquery-3.6.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
public/manifest.json generated
View File

@@ -1,5 +1,5 @@
{
"name": "App",
"name": "Heimdall",
"icons": [
{
"src": "\/android-icon-36x36.png",

View File

@@ -1,4 +1,4 @@
{
"/css/app.css": "/css/app.css?id=fb2cfb67b5f04db8beee",
"/js/app.js": "/js/app.js?id=8dc4a6ea723d0df7469d"
}
"/css/app.css": "/css/app.css?id=ad45b1705b7f7906db0b",
"/js/app.js": "/js/app.js?id=5446aeb4aa754e641c77"
}

View File

@@ -34,16 +34,36 @@ Supported applications are recognized by the title of the application as entered
[![foundationapps](https://img.shields.io/badge/dynamic/json.svg?label=Foundation%20Apps&url=https%3A%2F%2Fapps.heimdall.site%2Fstats&query=foundation_apps&colorB=3f8483&style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAjCAMAAACw/5reAAAAnFBMVEUAAADu7u7u7u7u7u7u7u7x8fHu7u7u7u7u7u7u7u7u7u7u7u7r6+vu7u7v7+/u7u7t7e3v7+/v7+/u7u7u7u7u7u7u7u7u7u7u7u7u7u7v7+/u7u7p6ent7e3v7+/v7+/v7+/u7u7u7u7u7u7u7u7t7e3////u7u7u7u7u7u7u7u7w8PDw8PDt7e3u7u7t7e3s7Ozu7u7t7e3u7u4TnCP6AAAAM3RSTlMA+9n3phHw3czC088M5Y5zG6mflWdJFumyfj4sB2NeTi7hiWlDOQPGt5lsMiG9hFQntpFqxQJtAAABnElEQVQoz2WRh3KrQAxFtYWO6ZhucItrynv6/3/LFnA24c6wurpnYBkJZvXduNix6+GXTo8qWnxUPU4m2w0O1ktTozPsftiZpejGlm7C2MWUnRcWOohIo36+PaKyDZdLUOgDXvqQfaT9kwkfvP3AN18E7Kl8hkJHMHSXSSadxaTtTNjJhMkfjFHKMqGlolg4T7mtCbcq8gBCotxkwklFLIQSlQoTHnVWQqzNxYQuzpfmqGVMc5ijHK5yAuIhxbZ5p/S92RZkjv5BKs6aosSIr0JrcXBo1FtICVINKRKK6u0GnraoN84O5KbhjRwYzxCJnQCMtotkdNxjq2F7dJ2RoGuXIBTvc3ROthdmat6hZ7cOyfcxKGV+wTxBkxQxTQTzWOFny/7qS2nzx37T7nbtZj9xu7zUr/323nVy0sQnhwMJktSZrl5v7CjgSQmWi+haUCY8sH4tyc/FGSKGouS+WqBJm8U2NIE/+nLu2tzpF/xVNGy02QzRClafC/ysVpDzQJuA8xXsKl8bv+pgpXz57H9Yy3J1lQNY62wUrW+mdzrylWS0QwAAAABJRU5ErkJggg==)](https://apps.heimdall.site/applications/foundation)
## Installing
Apart from the Laravel dependencies, namely PHP >= 7.1.3, OpenSSL PHP Extension, PDO PHP Extension, Mbstring PHP Extension, Tokenizer PHP Extension, XML PHP Extension, Ctype PHP Extension and JSON PHP Extension, the only other thing Heimdall needs is sqlite support and zip support (php-zip).
Apart from the Laravel dependencies, namely PHP >= 7.2.5, BCMath PHP Extension, Ctype PHP Extension, Fileinfo PHP extension, JSON PHP Extension, Mbstring PHP Extension, OpenSSL PHP Extension, PDO PHP Extension, Tokenizer PHP Extension, XML PHP Extension, the only other thing Heimdall needs is sqlite support and zip support (php-zip).
If you find you can't change the background make sure `php_fileinfo` is enabled in your php.ini. I believe it should be by default, but one user came across the issue on a windows system.
Installation is as simple as cloning the repository somewhere, or downloading and extracting the zip/tar and pointing your httpd document root to the `/public` folder. For simple testing you could just go to the folder and type `php artisan serve`
Installation is as simple as cloning the repository somewhere, or downloading and extracting the zip/tar and pointing your httpd document root to the `/public` folder then creating the .env file and generating an encryption key (this is all taken care of for you with the docker).
```
cd /path/to/heimdall
cp .env.example .env
php artisan key:generate
```
For simple testing you could just go to the folder and type `php artisan serve`
There is also a multi-arch Docker which supports x86-64, armhf and arm64, instructions on how to use them at
- https://hub.docker.com/r/linuxserver/heimdall/
## Updating
To update your instance, simply clone this repository or download the zip/tar file with the new version and copy it over the old installation.
## Search Providers
v2.3.0 added the ability for users to customise the search options.
Options are stored in `/storage/app/searchproviders.yaml` (`/config/www/searchproviders.yaml` on docker installs), feel free to rearrange the options, add new ones, delete ones you don't use, etc.
Consider contributing to https://github.com/linuxserver/Heimdall/discussions/categories/search-providers to help others add new ones.
The item at the top of the list `Tiles` allows you to search for apps on your dashboard by name, helpful when you have lots of icons.
## New background image not being set
If you are using the docker image or a default php install you may find images over 2MB wont get set as the background image, you just need to change the `upload_max_filesize` in the php.ini.
@@ -70,12 +90,15 @@ Currently added languages are
- Swedish
- Spanish
- Turkish
- Russian
- Chinese
## Web Server Configuration
### Apache
A `.htaccess` file ships with the app, however, a lot of apache installations disallow `.htaccess` files by default.
You will notice this due to some links not working like `/settings`.
In addition mod-rewrite needs to be enabled if it isn't already.
#### Fixes & work around options
##### - Apache global allow .htaccess
@@ -120,7 +143,7 @@ location /webfonts {
If there are any other locations which might interfere with any of the folders in the `/public` folder, you might have to do the same for those as well, but it's a super fringe case.
### Reverse proxy
If you'd like to reverse proxy this app, we recommend using our letsencrypt/nginx docker image: [Letsencrypt/Nginx](https://hub.docker.com/r/linuxserver/letsencrypt/)
If you'd like to reverse proxy this app, we recommend using our letsencrypt/nginx docker image: [SWAG - Secure Web Application Gateway](https://hub.docker.com/r/linuxserver/swag)
You can either reverse proxy from the root location, or from a subdomain (subfolder method is currently not supported). For HTTPS proxy, make sure you use the HTTPS port of Heimdall webserver, otherwise some links may break. You can add security through `.htpasswd`
```
@@ -128,12 +151,11 @@ location / {
auth_basic "Restricted";
auth_basic_user_file /config/nginx/.htpasswd;
include /config/nginx/proxy.conf;
proxy_pass https://heimdall:443;
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://heimdall;
}
```
If you are using HTTPS and things aren't working try adding `FORCE_HTTPS=true` to the end of your `.env` file or proxy to the https version of the app.
### Self-signed certificates and local CAs
Per default Heimdall uses the standard certificate bundle file (`ca-certificates.crt`) to verify HTTPS sites and will ignore additional certificates placed in `/etc/ssl/certs`. If you wish to use enhanced apps with HTTPS sites that use a self-signed certificate or certs signed with your own local CA, you can override the default bundle:

View File

@@ -1,5 +1,7 @@
$.when( $.ready ).then(function() {
var base = (document.querySelector('base') || {}).href;
if($('.message-container').length) {
setTimeout(
function()
@@ -8,17 +10,57 @@ $.when( $.ready ).then(function() {
}, 3500);
}
if($('.livestats-container').length) {
$('.livestats-container').each(function(index){
// from https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange;
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
var livestatsRefreshTimeouts = [];
var livestatsFuncs = [];
var livestatsContainers = $('.livestats-container');
function stopLivestatsRefresh() {
for (var timeoutId of livestatsRefreshTimeouts) {
window.clearTimeout(timeoutId);
}
}
function startLivestatsRefresh() {
for (var fun of livestatsFuncs) {
fun();
}
}
if (livestatsContainers.length > 0) {
if (typeof document.addEventListener === "undefined" || hidden === undefined) {
console.log("This browser does not support visibilityChange");
} else {
document.addEventListener(visibilityChange, function() {
if (document[hidden]) {
stopLivestatsRefresh();
} else {
startLivestatsRefresh();
}
}, false);
}
livestatsContainers.each(function(index){
var id = $(this).data('id');
var dataonly = $(this).data('dataonly');
var increaseby = (dataonly == 1) ? 20000 : 1000;
var container = $(this);
var max_timer = 30000;
var timer = 5000;
(function worker() {
var fun = function worker() {
$.ajax({
url: '/get_stats/'+id,
url: base+'get_stats/'+id,
dataType: 'json',
success: function(data) {
container.html(data.html);
@@ -29,10 +71,12 @@ $.when( $.ready ).then(function() {
},
complete: function() {
// Schedule the next request when the current one's complete
setTimeout(worker, timer);
livestatsRefreshTimeouts[index] = window.setTimeout(worker, timer);
}
});
})();
};
livestatsFuncs[index] = fun;
fun();
});
}
@@ -76,7 +120,7 @@ $.when( $.ready ).then(function() {
attribute: 'data-id'
});
$.post(
'/order',
base+'order',
{ order:idsInOrder }
);
}
@@ -84,7 +128,49 @@ $.when( $.ready ).then(function() {
});
$('#sortable').sortable('disable');
$('#sortable').on('mouseenter', '.item', function () {
$(this).siblings('.tooltip').addClass('active')
$('.refresh', this).addClass('active')
}).on('mouseleave', '.item', function () {
$(this).siblings('.tooltip').removeClass('active')
$('.refresh', this).removeClass('active')
})
$('#search-container').on('input', 'input[name=q]', function () {
const search = this.value
const items = $('#sortable').children('.item-container')
if($('#search-container select[name=provider]').val() === 'tiles') {
if(search.length > 0) {
items.hide()
items.filter(function () {
const name = $(this).data('name').toLowerCase();
return name.includes(search.toLowerCase())
}).show()
} else {
items.show()
}
} else {
items.show()
}
}).on('change', 'select[name=provider]', function () {
const items = $('#sortable').children('.item-container')
if($(this).val() === 'tiles') {
$('#search-container button').hide()
const search = $('#search-container input[name=q]').val()
if(search.length > 0) {
items.hide()
items.filter(function () {
const name = $(this).data('name').toLowerCase();
return name.includes(search.toLowerCase())
}).show()
} else {
items.show()
}
} else {
$('#search-container button').show()
items.show()
}
})
$('#app').on('click', '#config-button', function(e) {
e.preventDefault();
@@ -119,7 +205,7 @@ $.when( $.ready ).then(function() {
e.preventDefault();
var apiurl = $('#create input[name=url]').val();
var override_url = $('#create input[name="config[override_url]"]').val();
var override_url = $('#sapconfig input[name="config[override_url]"]').val();
if(override_url.length && override_url != '') {
apiurl = override_url;
}
@@ -131,7 +217,7 @@ $.when( $.ready ).then(function() {
data[config] = $(this).val();
});
$.post('/test_config', { data: data }, function(data) {
$.post(base+'test_config', { data: data }, function(data) {
alert(data);
});
@@ -140,7 +226,8 @@ $.when( $.ready ).then(function() {
e.preventDefault();
var current = $(this);
var id = current.data('id');
$.get('items/pintoggle/'+id+'/true', function(data) {
var tag = current.data('tag');
$.get(base+'items/pintoggle/'+id+'/true/'+tag, function(data) {
var inner = $(data).filter('#sortable').html();
$('#sortable').html(inner);
current.toggleClass('active');

View File

@@ -47,6 +47,66 @@ body {
}
}
}
#tile-preview {
align-items: center;
}
.create {
.textarea {
width: 100%;
margin: 0px 20px;
textarea{
width: 100%;
border: 1px solid #dedfe2;
padding: 15px;
border-radius: 6px;
height: 100px;
font-size: 14px;
}
label:not(.switch) {
width: 100%;
font-size: 13px;
color: lighten($app-text, 40%);
margin-bottom: 15px;
display: block;
font-weight: 300;
}
}
}
.appoptions {
display: flex;
flex-direction: column;
padding: 20px;
gap: 5px;
.optdetails {
display: flex;
.input {
margin: 0 20px;
width: 200px;
}
}
.optvalue {
display: flex;
align-items: center;
opacity: 0;
width: 0;
height: 0;
overflow: hidden;
&.active {
opacity: 1;
width: auto;
height: auto;
overflow: visible;
}
}
button.dark {
background: #1b1b1b;
border: none;
padding: 12px 15px;
border-radius: 4px;
color: white;
min-width: 240px;
}
}
#app {
display: flex;
min-height: 100vh;
@@ -200,6 +260,59 @@ body {
text-align: center;
line-height: 30px;
display: none;
z-index: 1;
}
.tooltip {
padding: 25px;
border-radius: 5px;
background: #000000c8;
color: white;
position: absolute;
bottom: 120px;
left: 0;
right: 0;
font-size: 13px;
backdrop-filter: blur(8px);
z-index: 0;
opacity: 0;
transform: translateY(-20px);
transition: all 0.3s;
&.active {
transform: translateY(0);
opacity: 1;
z-index: 4;
}
}
}
.tile-actions {
position: absolute;
top: 0px;
left: 0;
padding: 7px;
background: #000000d9;
font-size: 12px;
line-height: 1;
border-radius: 6px;
width: 80px;
height: 90px;
display: flex;
opacity: 0;
align-items: center;
justify-content: center;
transition: all 0.3s;
flex-direction: column;
text-align: center;
cursor: pointer;
&.active {
opacity: 1;
}
}
.refresh {
z-index: 3;
.icon {
font-size: 20px;
margin-bottom: 5px;
}
}
.black {
@@ -434,6 +547,8 @@ body {
padding: 20px 25px;
font-size: 13px;
color: $app-text;
max-width: 500px;
word-break: break-word;
&.form-error {
background: #e69191;
color: white;
@@ -509,6 +624,15 @@ body {
}
}
}
.input {
position: relative;
.help {
position: absolute;
bottom: -22px;
left: 10px;
color: #c00;
}
}
div.create {
padding: 30px 15px;
display: flex;
@@ -532,10 +656,19 @@ div.create {
}
}
}
.app-icon-container {
width: 60px;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 15px;
flex: 0 0 60px;
}
.app-icon {
max-width: 60px;
margin-right: 15px;
display: block;
max-height: 60px;
}
.sidenav {
@@ -574,6 +707,41 @@ div.create {
color: #91a1b3;
margin-left: 20px;
}
#websiteiconoptions {
display: flex;
flex-direction: column;
padding: 20px;
.results {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
padding: 10px 0;
}
.selectclose {
cursor: pointer;
}
}
.iconbutton {
width: 160px;
height: 160px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
border-radius: 4px;
cursor: pointer;
}
.selecticon {
max-width: 120px;
height: auto;
}
.switch {
position: relative;
@@ -691,7 +859,9 @@ div.create {
border-bottom: 1px solid rgba(255,255,255,0.35);
position: relative;
width: 100%;
max-width: 500px;
max-width: 620px;
position: relative;
z-index: 4;
form {
width: 100%;
}
@@ -701,6 +871,8 @@ div.create {
box-shadow: 0px 0px 5px 0 rgba(0,0,0,0.4);
overflow: hidden;
position: relative;
display: flex;
}
input {
padding: 17px 15px;
@@ -724,6 +896,12 @@ div.create {
text-transform: uppercase;
background: $app-red;
}
select {
padding: 0 10px;
background: #f5f5f5;
border: none;
border-right: 1px solid #ddd;
}
}
.ui-autocomplete {
@@ -774,7 +952,7 @@ div.create {
#appimage {
img {
max-width: 95px;
width: 95px;
}
}
@@ -866,11 +1044,6 @@ hr {
justify-content: space-between;
width: 100%;
li {
text-align: center;
margin: 0;
line-height: 1;
}
span {
display: block;
text-transform: uppercase;
@@ -893,11 +1066,30 @@ hr {
margin-left: 4px;
}
}
li {
text-align: center;
margin: 0;
line-height: 1;
&.right {
text-align: right;
span {
justify-content: flex-end;
}
}
}
&.flexcolumn {
flex-direction: column;
}
}
&.black {
.livestats {
strong {
color: #000;
}
}
}
}
input:-webkit-autofill,

View File

@@ -15,9 +15,5 @@
// Huebee
@import "huebee";
// fontawesome
@import "fontawesome/fontawesome";
@import "fontawesome/fa-solid";
@import "select2";

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,20 +0,0 @@
// Animated Icons
// --------------------------
.#{$fa-css-prefix}-spin {
animation: fa-spin 2s infinite linear;
}
.#{$fa-css-prefix}-pulse {
animation: fa-spin 1s infinite steps(8);
}
@keyframes fa-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

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