Compare commits

...

234 Commits

Author SHA1 Message Date
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
Chris
75508a81ef Update version 2018-11-05 09:44:11 +00:00
Chris
f7f4efadb7 Change html comment to php comment 2018-11-05 09:40:44 +00:00
Kode
4cc80b98db inconsequential update to try and fix broken build 2018-11-04 22:33:44 +00:00
Kode
b07efaa7d0 Merge branch 'master' of https://github.com/linuxserver/ifai 2018-11-04 21:43:16 +00:00
Kode
7ba8ea6dd4 die if missing php-zip 2018-11-04 21:43:12 +00:00
KodeStar
479461821f Update readme to use shields for apps 2018-11-04 18:30:27 +00:00
Kode
d25aea38fb update app version to correct number 2018-11-04 16:26:08 +00:00
Kode
0067502b37 Initial application process 2018-11-04 16:20:12 +00:00
Kode
d321af6085 update app type via dropdown 2018-11-04 16:03:55 +00:00
Kode
b30f1730e4 order applist in dropdown by name 2018-11-04 15:27:57 +00:00
KodeStar
7a02986982 Merge pull request #282 from linuxserver/2.1.0
2.1.0
2018-11-04 14:54:13 +00:00
Kode
a4107cba25 Fix tags 2018-11-04 14:33:39 +00:00
KodeStar
ba187aa345 Merge pull request #281 from BiohZn/master
Finnish and Swedish translation
2018-11-04 13:24:39 +00:00
Conny Sjöblom
b400cef734 Update Finnish translation 2018-11-04 15:20:53 +02:00
Conny Sjöblom
03b72b8d2e Update Swedish translation 2018-11-04 15:19:48 +02:00
Conny Sjöblom
0c7e20dee0 Finnish translation 2018-11-04 15:06:38 +02:00
Conny Sjöblom
aa42c71a06 Swedish translation 2018-11-04 14:53:20 +02:00
Kode
041c0b81a3 updates 2018-11-01 08:55:21 +00:00
Chris
fe6776ee9d Some changes to SupportedApps.php 2018-10-31 15:42:34 +00:00
Chris
125b9f4160 Some fixes and changes to run css 2018-10-30 14:58:45 +00:00
Kode
488fee7b4b fixes 2018-10-29 19:43:08 +00:00
Kode
4fba596909 add enable button 2018-10-29 19:01:25 +00:00
Chris
af04781830 remove class name from icon name 2018-10-29 15:24:47 +00:00
Chris
2507cda94c Normalise classname to remove non alpha chars 2018-10-29 15:12:47 +00:00
Kode
21c1401859 fixes 2018-10-28 20:41:46 +00:00
Kode
4351f55225 updates 2018-10-28 10:59:59 +00:00
Kode
d1956c4e88 updates 2018-10-26 19:55:40 +01:00
Chris
d76d056ed1 changes 2018-10-25 14:42:14 +01:00
Chris
e081cc31a2 small update 2018-10-25 12:14:18 +01:00
Chris
88153b0e32 Redo app form page 2018-10-25 09:44:40 +01:00
Chris
2b2d51cb6f changes 2018-10-23 15:53:56 +01:00
Kode
abd8c7227d Merge branch 'master' into 2.1.0 2018-10-21 14:09:39 +01:00
Kode
50d6dc7b71 change to find first user with public front 2018-10-21 13:47:03 +01:00
Kode
b4a1ecc305 update EnhancedApps 2018-10-21 13:32:58 +01:00
Kode
540bead0db Fix test button 2018-10-21 13:23:23 +01:00
Kode
6e9f25d680 Fixes 2018-10-21 12:39:12 +01:00
Kode
268afe7006 Get working 2018-10-21 00:17:36 +01:00
Kode
7b9d3f0ec6 replace text input with password input and swap input for Form::password 2018-10-20 20:08:36 +01:00
Kode
de116030bc change password field on nzbget blade 2018-10-20 13:55:56 +01:00
Chris
4fb59385b7 work on applications 2018-10-19 15:10:05 +01:00
Chris
40d6808067 Merge branch 'master' into 2.1.0 2018-10-19 08:47:58 +01:00
Chris
3572bd8068 update laravel requirements 2018-10-19 08:13:00 +01:00
Chris
380a0e8623 changes 2018-10-18 15:59:38 +01:00
Chris
4f6a0cb7c6 Move current apps out 2018-10-18 10:37:18 +01:00
Chris
56cce8233b Replace svgs 2018-10-18 09:53:13 +01:00
KodeStar
af8afcf931 Update readme.md 2018-10-18 08:41:13 +01:00
Kode
7f997d60cd Update version 2018-10-17 22:17:27 +01:00
Kode
d45f5a805e wrap asset() round root assets 2018-10-17 22:16:23 +01:00
Kode
fc9c624509 update donate link 2018-10-17 19:53:27 +01:00
KodeStar
33372509eb Merge pull request #266 from linuxserver/Multi-user
v2.0.0
2018-10-17 18:41:51 +01:00
Kode
bca0b02925 update version number to 2.0.0 2018-10-17 18:37:22 +01:00
Kode
24995135e6 update dependency 2018-10-17 18:35:09 +01:00
Chris
c1e4103edd Add support for pinned tabs in safari (potentially) 2018-10-17 11:31:42 +01:00
Chris
6eda423156 Added mailcow, webmin and virtualmin 2018-10-17 10:27:05 +01:00
Chris
7dc72d3519 style switch user icon same as user list page 2018-10-17 09:59:39 +01:00
Chris
907c22179b rearrange order 2018-10-17 09:49:23 +01:00
Chris
cdafbab7b1 possible fix for basic auth 2018-10-17 09:41:20 +01:00
Chris
e0064504e7 Merge branch 'master' into Multi-user 2018-10-17 08:39:10 +01:00
KodeStar
b22117dd01 Add missing override url 2018-10-17 08:36:06 +01:00
KodeStar
c88efa8dbc Fix broken config 2018-10-17 08:33:42 +01:00
Kode
7d060ff803 Merge branch 'master' into Multi-user 2018-10-16 19:05:04 +01:00
KodeStar
d5f8b6aae0 Merge pull request #257 from ABOTlegacy/Monica
Monica
2018-10-16 19:01:52 +01:00
KodeStar
2416993c5e Merge pull request #258 from ABOTlegacy/Bitwarden
Added Bitwarden to foundation apps.
2018-10-16 19:01:10 +01:00
KodeStar
494165a03a Merge pull request #259 from dgw/readme-polishing
readme: formatting, typo fixes, spit & polish
2018-10-16 19:00:20 +01:00
KodeStar
88e607533c Change to multiarch docker 2018-10-16 18:58:33 +01:00
KodeStar
035d2f9209 Merge pull request #265 from alxlaxv/master
Updating french translations
2018-10-16 18:53:05 +01:00
alxlaxv
53903daa87 Update app.php 2018-10-16 19:32:37 +02:00
alxlaxv
567994be1a Merge pull request #1 from alxlaxv/patch-1
Update app.php
2018-10-16 19:21:03 +02:00
alxlaxv
32fa27337a Update app.php
French translations improved
2018-10-16 17:27:53 +02:00
Chris
e1bb7646ac small fixes 2018-10-16 15:44:23 +01:00
KodeStar
108b636def Merge pull request #260 from keranoz/patch-1
Update app.php
2018-10-16 15:20:03 +01:00
keranoz
4abb14bf54 Update app.php
Improved some translations that seemed machine translated and added missing entries.
2018-10-16 14:08:19 +00:00
Chris
f8f96593c1 Update userseeder 2018-10-16 15:04:53 +01:00
Chris
cb21b0f8f1 add basic auth support and put username in switch user section 2018-10-16 14:57:21 +01:00
Chris
4c8c5fa27f Replace name for username in list view 2018-10-16 14:28:12 +01:00
Chris
6093119dde Change name to username 2018-10-16 14:14:14 +01:00
Chris
15755a3fd1 move all assets locally 2018-10-16 12:58:56 +01:00
Chris
0213c81e0d muted the switch user button until it's hovered over 2018-10-16 11:24:21 +01:00
Chris
c47f296f17 Change location of switch user 2018-10-16 10:59:35 +01:00
Chris
75133474f7 Added support and br translation 2018-10-16 09:33:24 +01:00
Kode
ddbe171f3a minor change to user avatar size to cut down whitespace a bit 2018-10-15 20:43:27 +01:00
Kode
12e109f82c add unique validation for name and don't fail validation when already the owner of data 2018-10-15 20:34:21 +01:00
Kode
e095589172 fix validation on email 2018-10-15 20:25:21 +01:00
Kode
d0293c785b Get settings working and autologin 2018-10-15 19:56:45 +01:00
Chris
aa351e31bf trying to get session settings to work 2018-10-15 16:00:20 +01:00
Chris
aceed3d13b fix settings edit not working 2018-10-15 14:35:14 +01:00
Chris
10b70d4a09 changes 2018-10-15 13:02:16 +01:00
Chris
cb9e014cf3 Autologin togles working 2018-10-15 09:52:36 +01:00
Chris
99017d834e Merge branch 'master' into Multi-user 2018-10-15 09:08:42 +01:00
Chris
fb73f5ca24 Attempt to allow changing root URL 2018-10-15 09:03:54 +01:00
dgw
4369f1aeda readme: formatting, typo fixes, spit & polish
Includes making inter-sentence spaces consistent, `pre-formatting`
values where it seemed appropriate, correcting typos, and other
miscellaneous niceties to help the readme make a good first impression.
2018-10-14 17:38:05 -05:00
Kode
6501aacb1b update to laravel 5.7 and try getting autologin saved 2018-10-14 20:50:32 +01:00
Kode
c3da17befc User specific items 2018-10-14 17:27:28 +01:00
Kode
46bb073001 Working on multi user 2018-10-14 16:17:55 +01:00
Kode
e8b47776ce Merge branch 'master' into Multi-user 2018-10-13 15:52:42 +01:00
Kode
6941fd3e2d Fixes for folder installs 2018-10-13 15:32:15 +01:00
Andy Bottom
f5937879df Added Bitwarden to foundation apps. 2018-10-12 14:59:19 -05:00
Andy Bottom
93877b7025 Fixed spaces vs tabs. 2018-10-12 14:35:59 -05:00
Andy Bottom
6612631cc3 Added Monica to foundation apps. 2018-10-12 14:32:34 -05:00
Chris
30c3079a90 added setting user many to many relationship 2018-10-12 15:10:40 +01:00
Chris
e86e681c53 Initial commit of multi user 2018-10-12 14:57:46 +01:00
Chris
48f72652da Merge branch 'master' of https://github.com/linuxserver/Heimdall 2018-10-12 11:33:43 +01:00
Chris
a3f7bafedb change css and js links to asset links 2018-10-12 11:33:39 +01:00
KodeStar
d30d610042 Update readme.md 2018-10-12 11:13:51 +01:00
Kode
882e406266 remove var dump 2018-09-30 15:47:44 +01:00
Kode
45d421256c Update readme and remove addition to .env as not necessary for everyone 2018-09-30 11:52:54 +01:00
Kode
a2f20fc18f allow forcing https for reverse proxy use 2018-09-30 11:45:08 +01:00
KodeStar
988364cb7c Merge pull request #246 from CHBMB/Bazarr
Bazarr
2018-09-13 13:40:12 +01:00
chbmb
a3816ed8a1 Update readme.md 2018-09-13 08:44:05 +01:00
chbmb
d48805ee2c Update Item.php 2018-09-13 08:43:21 +01:00
chbmb
e820b81259 Add files via upload 2018-09-13 08:42:26 +01:00
chbmb
8b1046ce17 Create Bazarr.php 2018-09-13 08:41:57 +01:00
chbmb
a138b65842 Merge pull request #1 from linuxserver/master
Rebase
2018-09-13 08:36:04 +01:00
KodeStar
c344de3f04 Merge pull request #244 from CHBMB/patch-3
Better logo and colour scheme for Unraid
2018-09-03 12:55:25 +01:00
chbmb
427659a897 Add files via upload 2018-08-30 11:42:02 +01:00
chbmb
a6543970e7 Update Unraid.php 2018-08-30 11:40:55 +01:00
KodeStar
399ea088dc Merge pull request #243 from CHBMB/patch-2
Update Unraid Icon & Colour Scheme
2018-08-29 17:37:18 +01:00
chbmb
3f87833e52 Add files via upload 2018-08-29 15:56:02 +01:00
chbmb
6dcb77023c Update Unraid colour in line with new logo 2018-08-29 15:54:19 +01:00
KodeStar
4d37135bdf Merge pull request #233 from CHBMB/freshrss
Freshrss
2018-07-19 21:49:13 +01:00
KodeStar
d109047fa5 Merge pull request #232 from CHBMB/bookstack
BookStack
2018-07-19 21:48:51 +01:00
KodeStar
b6112501e2 Merge pull request #231 from CHBMB/tvheadend
Add TVheadend to foundation apps
2018-07-19 21:47:16 +01:00
KodeStar
0663e236b4 Merge pull request #230 from CHBMB/patch-1
PfSense update
2018-07-19 21:46:30 +01:00
chbmb
f25cea1749 Add FreshRSS logo 2018-07-19 19:57:26 +01:00
chbmb
03e16415aa Create FreshRSS.php 2018-07-19 19:56:39 +01:00
chbmb
9a55e05943 Add FreshRSS 2018-07-19 19:55:21 +01:00
chbmb
c06fa4eab6 Update readme.md 2018-07-19 19:54:24 +01:00
chbmb
5575b082ea Update and rename Bookstack.php to BookStack.php 2018-07-18 21:18:19 +01:00
chbmb
1c6da858bc Update Item.php 2018-07-18 21:17:33 +01:00
chbmb
f0a14641c1 Update readme.md 2018-07-18 21:17:03 +01:00
chbmb
c6d07cd8a4 Update readme.md 2018-07-18 21:15:48 +01:00
chbmb
df9f07faf4 Add files via upload 2018-07-18 21:15:14 +01:00
chbmb
a3dcc278d7 Create Bookstack.php 2018-07-18 21:13:53 +01:00
chbmb
5de473fa44 Add bookstack 2018-07-18 21:00:36 +01:00
chbmb
763c1545a6 Update readme.md 2018-07-18 20:47:25 +01:00
chbmb
ecde7a0f32 Update readme.md 2018-07-18 20:46:27 +01:00
chbmb
7fc5e0abb5 Add TVheadend 2018-07-18 20:45:40 +01:00
chbmb
06a655ac0c Create TVheadend.php 2018-07-18 20:43:36 +01:00
chbmb
875ddaa834 Add TVheadend logo 2018-07-18 20:30:30 +01:00
chbmb
030fccbb50 Change pfSense logo to 250 x 250 2018-07-18 16:06:47 +01:00
chbmb
908f70d90a Update pfsense logo to new version 2018-07-18 16:02:11 +01:00
chbmb
8724ced531 pfSense New Logo/Colour 2018-07-18 16:00:30 +01:00
KodeStar
aa1a3a95ca Merge pull request #227 from MindTooth/update_package_json
Cleaned up package.json
2018-07-09 12:54:35 +01:00
Birger J. Nordølum
0767dc075e Cleaned up package.json
And updated some dependencies.
2018-07-09 13:08:02 +02:00
KodeStar
c8a6c89036 Merge pull request #225 from linuxserver/revert-217-fix_reported_errors
Revert "Changed from variable assignment to comparison"
2018-06-22 11:37:34 +01:00
KodeStar
cafe386cc4 Revert "Changed from variable assignment to comparison" 2018-06-22 11:36:58 +01:00
KodeStar
0184c9695b Merge pull request #218 from MindTooth/new_view
Cleaned of variable population in scripts.blade.php
2018-06-22 11:15:26 +01:00
KodeStar
19536edf28 Merge pull request #222 from MindTooth/add_info_to_files
Clarified _rune.scss file
2018-06-22 11:09:37 +01:00
KodeStar
045e4a20fa Merge pull request #213 from MindTooth/tweak_readme
Readme style tweaks
2018-06-22 11:09:13 +01:00
Birger J. Nordølum
6cb8487a52 Clarified _rune.scss file 2018-06-21 17:41:04 +02:00
Birger J. Nordølum
c39e9aa13f Trim variable in script view for create/edit.blade
Removed the large logic to populate the varible in page specific view.
2018-06-20 23:42:31 +02:00
KodeStar
0203440b06 Merge pull request #217 from MindTooth/fix_reported_errors
Changed from variable assignment to comparison
2018-06-20 21:20:12 +01:00
Birger J. Nordølum
7f7bf60456 Changed from variable assignment to comparison
Issue reported by CodeFactor:
https://www.codefactor.io/repository/github/mindtooth/heimdall/file/master/database/seeds/SettingsSeeder.php
2018-06-18 00:34:05 +02:00
KodeStar
e8673634bc Merge pull request #216 from MindTooth/fix_error
Fixes compile error with webpack.mix.js and app.js
2018-06-17 22:33:33 +01:00
KodeStar
53e52c93ee Merge pull request #214 from MindTooth/up_node_packages
Up packages.json to reflect upstream Laravel 5.5
2018-06-17 22:32:17 +01:00
Birger J. Nordølum
c239c0ea5a Compiled new source for fix 2018-06-17 23:19:45 +02:00
Birger J. Nordølum
7142f755f5 Fixes error thrown by UglifyJS 2018-06-17 23:17:35 +02:00
Birger J. Nordølum
9fbc8dc1f9 Fix missing bracket in app.js 2018-06-17 23:17:35 +02:00
Birger J. Nordølum
d3819a6a88 Last fix for Huebee issue.
After some major debugging once again, I've concluded that the previous
webpack.mix.js worked fine, but threw an error when minifying the app.js
file.  The culprit is because the current app.js contains some newer
ECMAScript code that needs to be translated.  However, with the current
inclusion of huebee.js into the samme command, it seems to mess things
up.

Just as a potensial fix for now is to just ignore the issue, and have a
stab at it at a later date.  This reverts the "fixes" I've made before.
2018-06-16 15:15:00 +02:00
Birger J. Nordølum
6e93ed8e5f Up packages.json to reflect upstream Laravel 5.5
This updates laravel-mix to 2.0.  Removed node-sass,
as it's already pulled by laravel-mix.
2018-06-16 14:56:45 +02:00
Birger J. Nordølum
98543d49a9 Readme style tweaks 2018-06-16 14:11:48 +02:00
KodeStar
9195eead27 Merge pull request #208 from MindTooth/fix_huebee
Fixes bug introduced in #203
2018-06-16 12:06:04 +01:00
KodeStar
e5b384736d Merge pull request #209 from dansoaress/master
Brazilian Portuguese translation
2018-06-15 14:14:48 +01:00
Daniel Soares
4def720d1a spell checking 2018-06-14 14:06:59 -03:00
Daniel Soares
2a0404ea17 Brazilian Portuguese translation 2018-06-14 07:02:14 -03:00
Birger J. Nordølum
6d22c4f02e Fixes bug introduced in #203
Needs to import the library when using webpack.mix.js.
Will also be the case for future libraries.
2018-06-14 00:20:42 +02:00
KodeStar
24ac12da65 Merge pull request #207 from MindTooth/fix_app_js
Fix issue with using override_url and running a test
2018-06-13 22:39:44 +01:00
Birger J. Nordølum
3f19882df8 All the other tweaks 2018-06-13 22:35:51 +02:00
Birger J. Nordølum
dd54c16c1f Fixed test when using override_url 2018-06-13 22:35:51 +02:00
Kode
223e9289dc include arrow in text color fix 2018-06-13 20:11:28 +01:00
Kode
2e301bdd51 This closes #184, closes #126 2018-06-13 20:03:26 +01:00
Kode
e3ec7de23a Dependency updates and update version number 2018-06-13 19:35:28 +01:00
KodeStar
18ec208381 Merge pull request #205 from MindTooth/add_gitattribute
.gitattributes: More settings added
2018-06-13 15:22:04 +01:00
KodeStar
8666daa07d Merge pull request #197 from finish06/master
Add App - Flood
2018-06-13 15:20:24 +01:00
KodeStar
926a9bdb03 Merge pull request #190 from ullbergm/app-Mylar
Foundation App: Mylar
2018-06-13 15:18:41 +01:00
Birger J. Nordølum
fc2d837a2c .gitattributes: More settings added 2018-06-13 16:15:38 +02:00
KodeStar
3f69ccab99 Merge pull request #192 from ullbergm/app-Headphones
Foundation App: Headphones
2018-06-13 15:09:58 +01:00
KodeStar
b6ee82ee52 Merge pull request #201 from shuaiscott/master
Enhanced App: Deluge
2018-06-13 15:09:25 +01:00
KodeStar
da1eb859a9 Merge pull request #202 from MindTooth/enhanced_traefik
Enhanced App: Traefik
2018-06-13 15:08:11 +01:00
KodeStar
2b5269b823 Merge pull request #203 from MindTooth/fix_webpack
Fixes typo in webpack.mix.js
2018-06-13 15:07:19 +01:00
ullbergm
6c8eeb0ced Merge branch 'master' into app-Mylar 2018-06-10 07:39:37 -04:00
Magnus Ullberg
c5e0f3abc8 Revert "Merge branch 'master' into app-Mylar"
This reverts commit 586941ece7, reversing
changes made to 263a4578d4.
2018-06-10 07:34:48 -04:00
Birger J. Nordølum
c6dbe22c57 Fixes typo in webpack.mix.js 2018-06-10 13:20:46 +02:00
KodeStar
51776e2aa3 Merge pull request #200 from ullbergm/Add-option-to-open-links-in-current-window-or-new-tab
WIP: Add option to open links in current window or new tab
2018-06-10 09:01:25 +01:00
KodeStar
c9d24607f6 Merge pull request #199 from MindTooth/tweak_names
lang_en: Reworded some strings, and removed whitespace
2018-06-10 08:53:37 +01:00
KodeStar
46f7a3d4f3 Merge pull request #198 from MindTooth/transmission_url
Transmission: Added custom URL
2018-06-10 08:50:33 +01:00
KodeStar
56cf450c89 Merge pull request #195 from ullbergm/app-MusicBrainz
Foundation App: MusicBrainz
2018-06-10 08:36:33 +01:00
KodeStar
38c350b020 Merge pull request #194 from ullbergm/app-LibreNMS
Foundation App: LibreNMS
2018-06-10 08:30:09 +01:00
KodeStar
1f46040f1b Merge pull request #193 from ullbergm/app-LazyLibrarian
Foundation App: LazyLibrarian
2018-06-10 08:29:03 +01:00
KodeStar
63b95319cd Merge pull request #191 from ullbergm/app-Booksonic
Foundation App: Booksonic
2018-06-10 08:25:17 +01:00
Birger J. Nordølum
a25d92be9e Traefik: enhanced conversion 2018-06-09 18:20:36 +02:00
Scott Carlson
a161210a4a Moving Deluge to Enhanced List 2018-06-08 15:39:57 -05:00
shuaiscott
24469eb2fa Adding Enhanced Deluge 2018-06-08 13:58:17 -06:00
ullbergm
a93fb49875 Update Item.php 2018-06-07 17:35:01 -04:00
ullbergm
08d7cdf95b Update SettingsSeeder.php 2018-06-07 12:34:35 -04:00
ullbergm
a9334bc247 Update Item.php 2018-06-07 12:33:40 -04:00
ullbergm
2357d0c466 Update app.php 2018-06-07 12:33:14 -04:00
ullbergm
b003d51276 Update SettingsSeeder.php 2018-06-07 12:32:45 -04:00
ullbergm
503cbf9830 Update SettingsSeeder.php 2018-06-07 12:32:08 -04:00
ullbergm
2466058c5a Update Item.php 2018-06-07 12:31:26 -04:00
Magnus Ullberg
6b1f422456 Initial stab at allowing you to select how links open. 2018-06-07 12:17:08 -04:00
Birger J. Nordølum
1d16d67733 lang_en: Reworded some strings, and removed whitespace 2018-06-07 10:49:35 +02:00
Birger J. Nordølum
6f9d15aed8 Transmission: Added custom URL 2018-06-07 10:42:02 +02:00
ullbergm
8725f974da Update readme.md 2018-06-06 19:09:42 -04:00
ullbergm
2551c949ae Update Item.php 2018-06-06 19:08:51 -04:00
ullbergm
30c6020ce7 Delete LazyLibrarian.php 2018-06-06 19:08:32 -04:00
ullbergm
d00b1ce1a1 Delete lazylibrarian.png 2018-06-06 19:08:12 -04:00
Caleb Dunn
2c43d79585 Add Flood class 2018-06-05 11:18:49 -05:00
Caleb Dunn
3e4aacb2b0 Add Flood 2018-06-05 11:17:17 -05:00
KodeStar
67cd22371b Merge pull request #189 from ullbergm/app-Rancher
Foundation App: Rancher
2018-06-05 11:59:24 +01:00
ullbergm
586941ece7 Merge branch 'master' into app-Mylar 2018-06-04 21:41:52 -04:00
ullbergm
32a57cbfa6 Merge pull request #5 from ullbergm/app-Headphones
Added Headphones support.
2018-06-04 21:41:04 -04:00
ullbergm
1837a69b3e Merge pull request #4 from ullbergm/app-Booksonic
Added Booksonic support.
2018-06-04 21:40:38 -04:00
ullbergm
aa8bfcfd92 Merge pull request #3 from ullbergm/app-MusicBrainz
Added MusicBrainz support.
2018-06-04 21:40:00 -04:00
ullbergm
9e0c658470 Merge pull request #2 from ullbergm/app-LibreNMS
Added LibreNMS support.
2018-06-04 19:20:01 -04:00
ullbergm
66aefff4f3 Merge branch 'master' into app-LibreNMS 2018-06-04 19:19:41 -04:00
ullbergm
bd0fdeecee Merge pull request #1 from ullbergm/app-LazyLibrarian
Added LazyLibrarian support.
2018-06-04 19:18:25 -04:00
Magnus Ullberg
1055eeb01b Added Rancher support. 2018-06-04 19:13:30 -04:00
Magnus Ullberg
263a4578d4 Added Mylar support. 2018-06-04 19:13:08 -04:00
Magnus Ullberg
c446b8a5af Added MusicBrainz support. 2018-06-04 19:12:24 -04:00
Magnus Ullberg
847b34cdcb Added LibreNMS support. 2018-06-04 19:12:02 -04:00
Magnus Ullberg
5a57f90b8f Added LazyLibrarian support. 2018-06-04 19:11:36 -04:00
Magnus Ullberg
f8eb9f5bd0 Added Headphones support. 2018-06-04 19:11:11 -04:00
Magnus Ullberg
c8c336b574 Added Booksonic support. 2018-06-04 19:10:22 -04:00
KodeStar
43f1410974 added fileinfo note to installing section 2018-05-25 09:12:32 +01:00
3750 changed files with 157033 additions and 62750 deletions

2
.env
View File

@@ -28,4 +28,4 @@ MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
PUSHER_APP_CLUSTER=mt1

44
.gitattributes vendored
View File

@@ -1,5 +1,49 @@
# Configuration file for Git attributes
# Core Settings {{{
# .gitattributes
.gitattributes !filter !diff
# Line Endings
* text=auto
# Set binary to none-text files
*.png -text
# }}}
# GitHub Linguist {{{
# Exclude files/folder from being detected by the GitHub linguist
# statistic.
node_modules/* linguist-vendored
public/* linguist-generated=true
vendor/* linguist-vendored
# Remove Vue as it's currently not used in the project.
resources/assets/js/components/ExampleComponent.vue linguist-vendored
# System Wide
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
# Include user generated files that's removed bu the setting above.
resources/assets/js/app.js linguist-vendored=false
resources/assets/sass/_app.scss linguist-vendored=false
resources/assets/sass/_rune.scss linguist-vendored=false
resources/assets/sass/_variables.scss linguist-vendored=false
# }}}
# Archive Exlude {{{
# Exclude files/folders from being exported when creating an archive.
.gitattributes export-ignore
.gitignore export-ignore
.travis.yml export-ignore
CHANGELOG.md export-ignore
# }}}

3
.gitignore vendored
View File

@@ -23,4 +23,5 @@ yarn-error.log
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.VolumeIcon.icns
storage/app/public/avatars/*

55
app/Application.php Normal file
View File

@@ -0,0 +1,55 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Application extends Model
{
public $incrementing = false;
protected $primaryKey = 'appid';
//
public function icon()
{
return $this->icon;
}
public function iconView()
{
return asset('storage/'.$this->icon);
}
public function defaultColour()
{
// check if light or dark
if($this->tile_background == 'light') return '#fafbfc';
return '#161b1f';
}
public function class()
{
$name = $this->name;
$name = preg_replace('/\PL/u', '', $name);
$class = '\App\SupportedApps\\'.$name.'\\'.$name;
return $class;
}
public static function applist()
{
$list = [];
$all = self::orderBy('name')->get()->sortBy('name', SORT_NATURAL|SORT_FLAG_CASE);
$list['null'] = 'None';
foreach($all as $app) {
$name = $app->name;
$name = preg_replace('/\PL/u', '', $name);
$list['\App\SupportedApps\\'.$name.'\\'.$name] = $app->name;
}
return $list;
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Application;
use App\SupportedApps;
class RegisterApp extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'register:app {folder}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Add a local app to the registry';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$folder = $this->argument('folder');
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);
}
} else {
$this->error('Could not find '.$json);
}
}
}

12
app/EnhancedApps.php Normal file
View File

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

View File

@@ -10,3 +10,35 @@ function format_bytes($bytes, $is_drive_size = true, $beforeunit = '', $afteruni
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) {
// returns brightness value from 0 to 255
// strip off any leading #
$hex = str_replace('#', '', $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) {
return ' black';
} else {
return ' white';
}
}
function className($name)
{
$name = preg_replace('/\PL/u', '', $name);
return $name;
}

View File

@@ -4,6 +4,11 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\URL;
class LoginController extends Controller
{
@@ -25,7 +30,7 @@ class LoginController extends Controller
*
* @var string
*/
protected $redirectTo = '/home';
protected $redirectTo = '/';
/**
* Create a new controller instance.
@@ -34,6 +39,88 @@ class LoginController extends Controller
*/
public function __construct()
{
Session::put('backUrl', URL::previous());
$this->middleware('guest')->except('logout');
}
public function username()
{
return 'username';
}
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function login(Request $request)
{
$current_user = User::currentUser();
$request->merge(['username' => $current_user->username]);
//die(print_r($request->all()));
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
public function index()
{
}
public function setUser(User $user)
{
Auth::logout();
session(['current_user' => $user]);
return redirect()->route('dash');
}
public function autologin($uuid)
{
$user = User::where('autologin', $uuid)->first();
Auth::login($user);
session(['current_user' => $user]);
return redirect()->route('dash');
}
/**
* Show the application's login form.
*
* @return \Illuminate\Http\Response
*/
public function showLoginForm()
{
return view('auth.login');
}
protected function authenticated(Request $request, $user)
{
return back();
}
public function redirectTo()
{
return Session::get('url.intended') ? Session::get('url.intended') : $this->redirectTo;
}
}

View File

@@ -27,7 +27,7 @@ class RegisterController extends Controller
*
* @var string
*/
protected $redirectTo = '/home';
protected $redirectTo = '/';
/**
* Create a new controller instance.

View File

@@ -25,7 +25,7 @@ class ResetPasswordController extends Controller
*
* @var string
*/
protected $redirectTo = '/home';
protected $redirectTo = '/';
/**
* Create a new controller instance.

View File

@@ -6,8 +6,27 @@ 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;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
protected $user;
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->user = $this->user();
//print_r($this->user);
return $next($request);
});
}
public function user()
{
return User::currentUser();
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return redirect()->route('dash');
}
}

View File

@@ -2,15 +2,23 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Artisan;
use App\Application;
use App\Item;
use App\Setting;
use App\SupportedApps\Nzbget;
use App\User;
use GrahamCampbell\GitHub\Facades\GitHub;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\SupportedApps;
use App\Jobs\ProcessApps;
class ItemController extends Controller
{
public function __construct()
{
$this->middleware('allowed');
}
/**
* Display a listing of the resource on the dashboard.
*
@@ -37,9 +45,8 @@ class ItemController extends Controller
$item->save();
}
}
/**
/**
* Pin item on the dashboard.
*
* @return \Illuminate\Http\Response
@@ -144,10 +151,19 @@ class ItemController extends Controller
}
$config = Item::checkConfig($request->input('config'));
$current_user = User::currentUser();
$request->merge([
'description' => $config
'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());
@@ -209,10 +225,19 @@ class ItemController extends Controller
}
$config = Item::checkConfig($request->input('config'));
$current_user = User::currentUser();
$request->merge([
'description' => $config
'description' => $config,
'user_id' => $current_user->id
]);
if($request->input('class') === 'null') {
$request->merge([
'class' => null,
]);
}
$item = Item::find($id);
$item->update($request->all());
@@ -264,16 +289,6 @@ class ItemController extends Controller
->with('success',__('app.alert.success.item_restored'));
}
public function isSupportedAppByKey($app)
{
$output = false;
$all_supported = Item::supportedList();
if(array_key_exists($app, $all_supported)) {
$output = new $all_supported[$app];
}
return $output;
}
/**
* Return details for supported apps
*
@@ -282,19 +297,25 @@ class ItemController extends Controller
public function appload(Request $request)
{
$output = [];
$app = $request->input('app');
$appname = $request->input('app');
//die($appname);
if(($app_details = $this->isSupportedAppByKey($app)) !== false) {
// basic details
$output['icon'] = $app_details->icon();
$output['colour'] = $app_details->defaultColour();
$app_details = Application::where('name', $appname)->firstOrFail();
$appclass = $app_details->class();
$app = new $appclass;
// live details
if($app_details instanceof \App\SupportedApps\Contracts\Livestats) {
$output['config'] = $app_details->configDetails();
} else {
$output['config'] = null;
}
// basic details
$output['icon'] = $app_details->icon();
$output['name'] = $app_details->name;
$output['iconview'] = $app_details->iconView();
$output['colour'] = $app_details->defaultColour();
$output['class'] = $appclass;
// live details
if($app instanceof \App\EnhancedApps) {
$output['config'] = className($app_details->name).'.config';
} else {
$output['config'] = null;
}
return json_encode($output);
@@ -309,25 +330,34 @@ class ItemController extends Controller
$app_details = new $app();
$app_details->config = (object)$data;
$app_details->testConfig();
$app_details->test();
}
public function getStats($id)
{
$item = Item::find($id);
$config = json_decode($item->description);
if(isset($config->type)) {
$config->url = $item->url;
if(isset($config->override_url) && !empty($config->override_url)) {
$config->url = $config->override_url;
}
$app_details = new $config->type;
$app_details->config = $config;
echo $app_details->executeConfig();
$config = $item->getconfig();
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

@@ -5,10 +5,17 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Setting;
use App\SettingGroup;
use App\User;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
class SettingsController extends Controller
{
public function __construct()
{
$this->middleware('allowed');
}
/**
* @return \Illuminate\View\View
*/
@@ -31,6 +38,7 @@ class SettingsController extends Controller
public function edit($id)
{
$setting = Setting::find($id);
//die("s: ".$setting->label);
if((bool)$setting->system === true) return abort(404);
@@ -55,26 +63,28 @@ class SettingsController extends Controller
public function update(Request $request, $id)
{
$setting = Setting::find($id);
$user = $this->user();
if (!is_null($setting)) {
$data = Setting::getInput();
$setting_value = null;
if ($setting->type == 'image') {
if($request->hasFile('value')) {
$path = $request->file('value')->store('backgrounds');
$setting->value = $path;
$setting_value = $path;
}
} else {
$setting->value = $data->value;
$setting_value = $data->value;
}
$setting->save();
$user->settings()->detach($setting->id);
$user->settings()->save($setting, ['uservalue' => $setting_value]);
$route = route('settings.index', [], false);
return redirect($route)
->with([
@@ -95,10 +105,11 @@ class SettingsController extends Controller
*/
public function clear($id)
{
$user = $this->user();
$setting = Setting::find($id);
if((bool)$setting->system !== true) {
$setting->value = '';
$setting->save();
$user->settings()->detach($setting->id);
$user->settings()->save($setting, ['uservalue' => '']);
}
$route = route('settings.index', [], false);
return redirect($route)

View File

@@ -4,10 +4,15 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Item;
use App\User;
use DB;
class TagController extends Controller
{
public function __construct()
{
$this->middleware('allowed');
}
/**
* Display a listing of the resource.
*
@@ -58,10 +63,13 @@ class TagController extends Controller
$slug = str_slug($request->title, '-');
$current_user = User::currentUser();
// set item type to tag
$request->merge([
'type' => '1',
'url' => $slug
'url' => $slug,
'user_id' => $current_user->id
]);
//die(print_r($request->all()));
Item::create($request->all());

View File

@@ -0,0 +1,175 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
class UserController extends Controller
{
public function __construct()
{
$this->middleware('allowed')->except(['selectUser']);
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$data['users'] = User::all();
return view('users.index', $data);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
$data = [];
return view('users.create', $data);
}
public function selectUser()
{
Auth::logout();
$data['users'] = User::all();
return view('userselect', $data);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'username' => 'required|max:255|unique:users',
'email' => 'required|email',
'password' => 'nullable|confirmed',
'password_confirmation' => 'nullable'
]);
$user = new User;
$user->username = $request->input('username');
$user->email = $request->input('email');
$user->public_front = $request->input('public_front');
$password = $request->input('password');
if(!empty($password)) {
$user->password = bcrypt($password);
}
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();
}
$user->save();
$route = route('dash', [], false);
return redirect($route)
->with('success',__('app.alert.success.user_updated'));
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit(User $user)
{
$data['user'] = $user;
return view('users.edit', $data);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, User $user)
{
$validatedData = $request->validate([
'username' => 'required|max:255|unique:users,username,'.$user->id,
'email' => 'required|email',
'password' => 'nullable|confirmed',
'password_confirmation' => 'nullable'
]);
//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)) {
$user->password = bcrypt($password);
} elseif($password == 'null') {
$user->password = null;
}
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;
} else {
$user->autologin = null;
}
$user->save();
$route = route('dash', [], false);
return redirect($route)
->with('success',__('app.alert.success.user_updated'));
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(User $user)
{
if($user->id !== 1) {
$user->delete();
$route = route('dash', [], false);
return redirect($route)
->with('success',__('app.alert.success.user_deleted'));
}
}
}

View File

@@ -51,6 +51,7 @@ class Kernel extends HttpKernel
* @var array
*/
protected $routeMiddleware = [
'allowed' => \App\Http\Middleware\CheckAllowed::class,
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use App\User;
use Illuminate\Support\Facades\Route;
use Session;
class CheckAllowed
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$route = Route::currentRouteName();
$current_user = User::currentUser();
if(str_is('users*', $route)) {
if($current_user->id !== 1) {
return redirect()->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(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);
}
return Auth::authenticate();
}
}

View File

@@ -18,7 +18,7 @@ class RedirectIfAuthenticated
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/home');
return redirect()->intended();
}
return $next($request);

View File

@@ -19,11 +19,5 @@ class TrustProxies extends Middleware
*
* @var array
*/
protected $headers = [
Request::HEADER_FORWARDED => 'FORWARDED',
Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
];
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}

View File

@@ -5,15 +5,26 @@ namespace App;
use Illuminate\Database\Eloquent\Model;
use Symfony\Component\ClassLoader\ClassMapGenerator;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;
use App\User;
class Item extends Model
{
use SoftDeletes;
protected static function boot()
{
parent::boot();
static::addGlobalScope('user_id', function (Builder $builder) {
$current_user = User::currentUser();
$builder->where('user_id', $current_user->id);
});
}
//
protected $fillable = [
'title', 'url', 'colour', 'icon', 'description', 'pinned', 'order', 'type'
'title', 'url', 'colour', 'icon', 'description', 'pinned', 'order', 'type', 'class', 'user_id'
];
/**
@@ -23,66 +34,6 @@ class Item extends Model
*/
protected $dates = ['deleted_at'];
public static function supportedList()
{
return [
'AirSonic' => \App\SupportedApps\AirSonic::class,
'Cardigann' => \App\SupportedApps\Cardigann::class,
'CouchPotato' => \App\SupportedApps\CouchPotato::class,
'Deluge' => \App\SupportedApps\Deluge::class,
'Dokuwiki' => \App\SupportedApps\Dokuwiki::class,
'Duplicati' => \App\SupportedApps\Duplicati::class,
'Emby' => \App\SupportedApps\Emby::class,
'Gitea' => \App\SupportedApps\Gitea::class,
'Glances' => \App\SupportedApps\Glances::class,
'Grafana' => \App\SupportedApps\Grafana::class,
'Graylog' => \App\SupportedApps\Graylog::class,
'Home Assistant' => \App\SupportedApps\HomeAssistant::class,
'Jackett' => \App\SupportedApps\Jackett::class,
'Jdownloader' => \App\SupportedApps\Jdownloader::class,
'Krusader' => \App\SupportedApps\Krusader::class,
'Lidarr' => \App\SupportedApps\Lidarr::class,
'Mcmyadmin' => \App\SupportedApps\Mcmyadmin::class,
'Medusa' => \App\SupportedApps\Medusa::class,
'NZBGet' => \App\SupportedApps\Nzbget::class,
'Netdata' => \App\SupportedApps\Netdata::class,
'Nextcloud' => \App\SupportedApps\Nextcloud::class,
'Now Showing' => \App\SupportedApps\NowShowing::class,
'Nzbhydra' => \App\SupportedApps\Nzbhydra::class,
'OPNSense' => \App\SupportedApps\Opnsense::class,
'Ombi' => \App\SupportedApps\Ombi::class,
'Openhab' => \App\SupportedApps\Openhab::class,
'OpenMediaVault' => \App\SupportedApps\OpenMediaVault::class,
'Pihole' => \App\SupportedApps\Pihole::class,
'Plex' => \App\SupportedApps\Plex::class,
'Plexpy' => \App\SupportedApps\Plexpy::class,
'Plexrequests' => \App\SupportedApps\Plexrequests::class,
'Portainer' => \App\SupportedApps\Portainer::class,
'Proxmox' => \App\SupportedApps\Proxmox::class,
'Radarr' => \App\SupportedApps\Radarr::class,
'Runeaudio' => \App\SupportedApps\Runeaudio::class,
'Sabnzbd' => \App\SupportedApps\Sabnzbd::class,
'Sickrage' => \App\SupportedApps\Sickrage::class,
'Sonarr' => \App\SupportedApps\Sonarr::class,
'Syncthing' => \App\SupportedApps\Syncthing::class,
'Tautulli' => \App\SupportedApps\Tautulli::class,
'Transmission' => \App\SupportedApps\Transmission::class,
'Traefik' => \App\SupportedApps\Traefik::class,
'tt-rss' => \App\SupportedApps\Ttrss::class,
'UniFi' => \App\SupportedApps\Unifi::class,
'unRAID' => \App\SupportedApps\Unraid::class,
'pfSense' => \App\SupportedApps\Pfsense::class,
'pyLoad' => \App\SupportedApps\pyLoad::class,
'ruTorrent' => \App\SupportedApps\ruTorrent::class,
'Watcher3' => \App\SupportedApps\Watcher3::class,
'WebTools' => \App\SupportedApps\WebTools::class,
];
}
public static function supportedOptions()
{
return array_keys(self::supportedList());
}
/**
* Scope a query to only include pinned items.
*
@@ -94,24 +45,6 @@ class Item extends Model
return $query->where('pinned', 1);
}
public function getConfigAttribute()
{
$output = null;
$view = null;
if(isset($this->description) && !empty($this->description)){
$output = json_decode($this->description);
$output = is_object($output) ? $output : new \stdClass();
if(isset($output->type) && !empty($output->type)) {
$class = $output->type;
$sap = new $class();
$view = $sap->configDetails();
$output->view = $view;
}
if(!isset($output->dataonly)) $output->dataonly = '0';
}
return (object)$output;
}
public static function checkConfig($config)
{
if(empty($config)) {
@@ -128,7 +61,7 @@ class Item extends Model
}
}
//die(var_dump($store))
$config['enabled'] = ($store) ? true : false;
$config = json_encode($config);
}
@@ -165,10 +98,12 @@ class Item extends Model
public function getLinkTargetAttribute()
{
if((int)$this->type === 1) {
$target = Setting::fetch('window_target');
if((int)$this->type === 1 || $target === 'current') {
return '';
} else {
return ' target="heimdallapp"';
return ' target="' . $target . '"';
}
}
@@ -203,5 +138,63 @@ class Item extends Model
return $query->where('type', $typeid);
}
public function enhanced()
{
if(isset($this->class) && !empty($this->class)) {
$app = new $this->class;
} else {
return false;
}
return (bool)($app instanceof \App\EnhancedApps);
}
public function enabled()
{
if($this->enhanced()) {
$config = $this->getconfig();
if($config) {
return (bool) $config->enabled;
}
}
return false;
}
public function getconfig()
{
$explode = explode('\\', $this->class);
if(!isset($this->description) || empty($this->description)) {
$config = new \stdClass;
$config->name = end($explode);
$config->enabled = false;
return $config;
}
$config = json_decode($this->description);
$config->name = end($explode);
$config->url = $this->url;
if(isset($config->override_url) && !empty($config->override_url)) {
$config->url = $config->override_url;
}
return $config;
}
/**
* Get the user that owns the item.
*/
public function user()
{
return $this->belongsTo('App\User');
}
}

63
app/Jobs/ProcessApps.php Normal file
View File

@@ -0,0 +1,63 @@
<?php
namespace App\Jobs;
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;
class ProcessApps implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* @return void
*/
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);
}
}
}
//$delete = Application::whereNotIn('appid', $validapps)->delete(); // delete any apps not in list
// removed the delete so local apps can be added
}
}

View File

@@ -6,6 +6,9 @@ use Illuminate\Support\ServiceProvider;
use Artisan;
use Schema;
use App\Setting;
use App\User;
use App\Application;
use App\Jobs\ProcessApps;
class AppServiceProvider extends ServiceProvider
{
@@ -16,7 +19,6 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot()
{
$alt_bg = '';
if(!is_file(base_path('.env'))) {
touch(base_path('.env'));
@@ -32,27 +34,86 @@ class AppServiceProvider extends ServiceProvider
}
if(is_file(database_path('app.sqlite'))) {
if(Schema::hasTable('settings')) {
if($bg_image = Setting::fetch('background_image')) {
$alt_bg = ' style="background-image: url(/storage/'.$bg_image.')"';
}
// check version to see if an upgrade is needed
$db_version = Setting::fetch('version');
$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));
}
} else {
Artisan::call('migrate', array('--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'))) {
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)
{
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'])) {
$credentials = ['username' => $_SERVER['PHP_AUTH_USER'], 'password' => $_SERVER['PHP_AUTH_PW']];
if (\Auth::attempt($credentials)) {
// Authentication passed...
$user = \Auth::user();
//\Session::put('current_user', $user);
session(['current_user' => $user]);
}
}
}
$alt_bg = '';
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 );
});
$this->app['view']->addNamespace('SupportedApps', app_path('SupportedApps'));
if (env('FORCE_HTTPS') === true) {
\URL::forceScheme('https');
}
if(!is_file(public_path('storage'))) {
Artisan::call('storage:link');
if(env('APP_URL') != 'http://localhost') {
\URL::forceRootUrl(env('APP_URL'));
}
view()->share('alt_bg', $alt_bg);
}

View File

@@ -5,6 +5,8 @@ namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Input;
use Form;
use Illuminate\Support\Facades\Auth;
use App\User;
class Setting extends Model
{
@@ -46,6 +48,12 @@ class Setting extends Model
public function getListValueAttribute()
{
if((bool)$this->system === true) {
$value = self::_fetch($this->key);
} else {
$value = self::fetch($this->key);
}
$this->value = $value;
switch($this->type) {
case 'image':
if(!empty($this->value)) {
@@ -80,6 +88,12 @@ class Setting extends Model
public function getEditValueAttribute()
{
if((bool)$this->system === true) {
$value = self::_fetch($this->key);
} else {
$value = self::fetch($this->key);
}
$this->value = $value;
switch($this->type) {
case 'image':
$value = '';
@@ -125,6 +139,7 @@ class Setting extends Model
return $this->belongsTo('App\SettingGroup', 'group_id');
}
/**
* @param string $key
*
@@ -132,20 +147,54 @@ class Setting extends Model
*/
public static function fetch($key)
{
if (Setting::cached($key)) {
return Setting::$cache[$key];
} else {
$user = self::user();
return self::_fetch($key, $user);
}
/**
* @param string $key
*
* @return mixed
*/
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();
if (!is_null($find)) {
$value = $find->value;
Setting::add($key, $value);
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;
}
}
#Setting::add($cachekey, $value);
return $value;
} else {
return false;
}
}
#}
}
/**
@@ -175,21 +224,23 @@ class Setting extends Model
$output = '';
$homepage_search = self::fetch('homepage_search');
$search_provider = self::where('key', '=', 'search_provider')->first();
//die(var_dump($search_provider->value));
$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($search_provider->value === 'none') return $output;
if(empty($search_provider->value)) return $output;
if(is_null($search_provider->value)) 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[$search_provider->value];
if((bool)$search_provider->value) {
switch($search_provider->value) {
$name = $options[$user_search_provider];
if((bool)$user_search_provider) {
switch($user_search_provider) {
case 'google':
$url = 'https://www.google.com/search';
$var = 'q';
@@ -218,4 +269,19 @@ class Setting extends Model
}
return $output;
}
/**
* The users that belong to the setting.
*/
public function users()
{
return $this->belongsToMany('App\User')->using('App\SettingUser')->withPivot('uservalue');
}
public static function user()
{
return User::currentUser();
}
}

10
app/SettingUser.php Normal file
View File

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

158
app/SupportedApps.php Normal file
View File

@@ -0,0 +1,158 @@
<?php namespace App;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
abstract class SupportedApps
{
protected $jar = false;
protected $method = 'GET';
protected $error;
public function appTest($url, $attrs = [], $overridevars=false)
{
$res = $this->execute($url, $attrs);
if($res == null) {
return (object)[
'code' => null,
'status' => $this->error,
'response' => 'Connection failed',
];
}
switch($res->getStatusCode()) {
case 200:
$status = 'Successfully communicated with the API';
break;
case 401:
$status = 'Failed: Invalid credentials';
break;
case 404:
$status = 'Failed: Please make sure your URL is correct and that there is a trailing slash';
break;
default:
$status = 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
return (object)[
'code' => $res->getStatusCode(),
'status' => $status,
'response' => $res->getBody(),
];
}
public function execute($url, $attrs = [], $overridevars=false, $overridemethod=false)
{
$res = null;
$vars = ($overridevars !== false) ?
$overridevars : [
'http_errors' => false,
'timeout' => 15,
'connect_timeout' => 15,
];
$client = new Client($vars);
$method = ($overridemethod !== false) ? $overridemethod : $this->method;
try {
return $client->request($method, $url, $attrs);
} catch (\GuzzleHttp\Exception\ConnectException $e) {
Log::error("Connection refused");
Log::debug($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)
{
$url = rtrim($url, '/');
if($addslash) $url .= '/';
return $url;
}
public function getLiveStats($status, $data)
{
$className = get_class($this);
$explode = explode('\\', $className);
$name = end($explode);
$html = view('SupportedApps::'.$name.'.livestats', $data)->with('data', $data)->render();
return json_encode(['status' => $status, 'html' => $html]);
//return
}
public static function getList()
{
$list_url = 'https://apps.heimdall.site/list';
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
return $client->request('GET', $list_url);
}
public static function getFiles($app)
{
$zipurl = $app->files;
$client = new Client(['http_errors' => false, 'timeout' => 60, 'connect_timeout' => 15]);
$res = $client->request('GET', $zipurl);
if(!file_exists(app_path('SupportedApps'))) {
mkdir(app_path('SupportedApps'), 0777, true);
}
$src = app_path('SupportedApps/'.className($app->name).'.zip');
file_put_contents($src, $res->getBody());
$zip = new \ZipArchive();
$x = $zip->open($src); // open the zip file to extract
if ($x === true) {
$zip->extractTo(app_path('SupportedApps')); // place in the directory with same name
$zip->close();
unlink($src); //Deleting the Zipped file
}
}
public static function saveApp($details, $app)
{
if(!file_exists(public_path('storage/icons'))) {
mkdir(public_path('storage/icons'), 0777, true);
}
$img_src = app_path('SupportedApps/'.className($details->name).'/'.$details->icon);
$img_dest = public_path('storage/icons/'.$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 = '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);
$app->enhanced = $enhanced;
$app->tile_background = $details->tile_background;
$app->save();
}
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps;
class AirSonic implements Contracts\Applications {
public function defaultColour()
{
return '#08F';
}
public function icon()
{
return 'supportedapps/airsonic.png';
}
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps;
class Cardigann implements Contracts\Applications {
public function defaultColour()
{
return '#753';
}
public function icon()
{
return 'supportedapps/cardigann.png';
}
}

View File

@@ -1,9 +0,0 @@
<?php namespace App\SupportedApps\Contracts;
interface Applications {
public function defaultColour();
public function icon();
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps\Contracts;
interface Livestats {
public function configDetails();
public function testConfig();
public function executeConfig();
}

View File

@@ -1,122 +0,0 @@
<?php namespace App\SupportedApps;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
class CouchPotato implements Contracts\Applications, Contracts\Livestats
{
private $_client;
public function __construct()
{
$this->_client = new Client(
['http_errors' => false,
'timeout' => 10]
);
}
public function defaultColour()
{
return '#363840';
}
public function icon()
{
return 'supportedapps/couchpotato.png';
}
public function configDetails()
{
return 'couchpotato';
}
public function testConfig()
{
$res = $this->sendRequest();
if ($res == null) {
echo 'CouchPotato connection failed';
return;
}
switch($res->getStatusCode()) {
case 200:
echo "Successfully connected to CouchPotato";
break;
case 401:
echo 'Failed: Invalid credentials';
break;
case 404:
echo 'Failed: Please make sure your URL is correct and includes the port';
break;
case 409:
echo 'Failed: Incorrect session id';
break;
default:
echo 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
}
public function executeConfig()
{
$html = '';
$res = $this->sendRequest();
if ($res == null) {
Log::debug('CouchPotato connection failed');
return '';
}
$data = json_decode($res->getBody());
if (! isset($data->movies)) {
Log::debug('Failed to fetch data from CouchPotato');
return '';
}
$movies = $data->movies;
$wantedMovies = $availableMovies = 0;
foreach ($movies as $v) {
switch ($v->status) {
case 'active':
$wantedMovies++;
break;
case 'done':
$availableMovies++;
break;
default:
Log::warning('Unexpected CouchPotato status received: '.$v['status']);
break;
}
}
$html = '
<ul class="livestats">
<li><span class="title">Wanted</span><sub>'.$wantedMovies.'</sub></li>
<li><span class="title">Available</span><sub>'.$availableMovies.'</sub></li>
</ul>
';
return json_encode(['status' => 'inactive', 'html' => $html]);
}
private function sendRequest()
{
$res = null;
try{
$res = $this->_client->request(
'GET',
$this->getApiUrl()
);
}catch(\GuzzleHttp\Exception\BadResponseException $e){
Log::error("Connection to {$e->getRequest()->getUrl()} failed");
Log::debug($e->getMessage());
$res = $e->getRequest();
}catch(\GuzzleHttp\Exception\ConnectException $e) {
Log::error("CouchPotato connection refused");
Log::debug($e->getMessage());
}
return $res;
}
private function getApiUrl()
{
$url = $this->config->url;
$url = rtrim($url, '/');
$apiUrl = $url.'/api/'.$this->config->apikey.'/movie.list';
return $apiUrl;
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Deluge implements Contracts\Applications {
public function defaultColour()
{
return '#357';
}
public function icon()
{
return 'supportedapps/deluge.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Dokuwiki implements Contracts\Applications {
public function defaultColour()
{
return '#9d7056';
}
public function icon()
{
return 'supportedapps/dokuwiki.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Duplicati implements Contracts\Applications {
public function defaultColour()
{
return '#2c3744';
}
public function icon()
{
return 'supportedapps/duplicati.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Emby implements Contracts\Applications {
public function defaultColour()
{
return '#222';
}
public function icon()
{
return 'supportedapps/emby.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Gitea implements Contracts\Applications {
public function defaultColour()
{
return '#585e52';
}
public function icon()
{
return 'supportedapps/gitea.png';
}
}

View File

@@ -1,14 +0,0 @@
<?php namespace App\SupportedApps;
class Glances implements Contracts\Applications {
public function defaultColour()
{
return '#2c363f';
}
public function icon()
{
return 'supportedapps/glances.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Grafana implements Contracts\Applications {
public function defaultColour()
{
return '#a56e4d';
}
public function icon()
{
return 'supportedapps/grafana.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Graylog implements Contracts\Applications {
public function defaultColour()
{
return '#158';
}
public function icon()
{
return 'supportedapps/graylog.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class HomeAssistant implements Contracts\Applications {
public function defaultColour()
{
return '#073c52';
}
public function icon()
{
return 'supportedapps/homeassistant.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Jackett implements Contracts\Applications {
public function defaultColour()
{
return '#484814';
}
public function icon()
{
return 'supportedapps/jackett.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Jdownloader implements Contracts\Applications {
public function defaultColour()
{
return '#2b494f';
}
public function icon()
{
return 'supportedapps/jdownloader.png';
}
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps;
class Krusader implements Contracts\Applications {
public function defaultColour()
{
return '#5A5';
}
public function icon()
{
return 'supportedapps/krusader.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Lidarr implements Contracts\Applications {
public function defaultColour()
{
return '#183c18';
}
public function icon()
{
return 'supportedapps/lidarr.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Mcmyadmin implements Contracts\Applications {
public function defaultColour()
{
return '#30404b';
}
public function icon()
{
return 'supportedapps/mcmyadmin.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Medusa implements Contracts\Applications {
public function defaultColour()
{
return '#4b5e55';
}
public function icon()
{
return 'supportedapps/medusa.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Netdata implements Contracts\Applications {
public function defaultColour()
{
return '#543737';
}
public function icon()
{
return 'supportedapps/netdata.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Nextcloud implements Contracts\Applications {
public function defaultColour()
{
return '#0e2c3e';
}
public function icon()
{
return 'supportedapps/nextcloud.png';
}
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps;
class NowShowing implements Contracts\Applications {
public function defaultColour()
{
return '#690000';
}
public function icon()
{
return 'supportedapps/nowshowing.png';
}
}

View File

@@ -1,84 +0,0 @@
<?php namespace App\SupportedApps;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
class Nzbget implements Contracts\Applications, Contracts\Livestats {
public $config;
public function defaultColour()
{
return '#253827';
}
public function icon()
{
return 'supportedapps/nzbget.png';
}
public function configDetails()
{
return 'nzbget';
}
public function testConfig()
{
$res = $this->buildRequest('status');
switch($res->getStatusCode()) {
case 200:
echo 'Successfully connected to the API';
break;
case 401:
echo 'Failed: Invalid credentials';
break;
case 404:
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
break;
default:
echo 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
}
public function executeConfig()
{
$html = '';
$active = 'inactive';
$res = $this->buildRequest('status');
$data = json_decode($res->getBody());
//$data->result->RemainingSizeMB = '10000000';
//$data->result->DownloadRate = '100000000';
if($data) {
$size = $data->result->RemainingSizeMB;
$rate = $data->result->DownloadRate;
$queue_size = format_bytes($size*1000*1000, false, ' <span>', '</span>');
$current_speed = format_bytes($rate, false, ' <span>');
$active = ($size > 0 || $rate > 0) ? 'active' : 'inactive';
$html = '
<ul class="livestats">
<li><span class="title">Queue</span><strong>'.$queue_size.'</strong></li>
<li><span class="title">Speed</span><strong>'.$current_speed.'/s</span></strong></li>
</ul>
';
}
return json_encode(['status' => $active, 'html' => $html]);
}
public function buildRequest($endpoint)
{
$config = $this->config;
$url = $config->url;
$username = $config->username;
$password = $config->password;
$rebuild_url = str_replace('http://', 'http://'.$username.':'.$password.'@', $url);
$rebuild_url = str_replace('https://', 'https://'.$username.':'.$password.'@', $rebuild_url);
$rebuild_url = rtrim($rebuild_url, '/');
$api_url = $rebuild_url.'/jsonrpc/'.$endpoint;
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
$res = $client->request('GET', $api_url);
return $res;
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Nzbhydra implements Contracts\Applications {
public function defaultColour()
{
return '#53644d';
}
public function icon()
{
return 'supportedapps/nzbhydra.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Ombi implements Contracts\Applications {
public function defaultColour()
{
return '#150f09';
}
public function icon()
{
return 'supportedapps/ombi.png';
}
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps;
class OpenMediaVault implements Contracts\Applications {
public function defaultColour()
{
return '#5AF';
}
public function icon()
{
return 'supportedapps/openmediavault.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Openhab implements Contracts\Applications {
public function defaultColour()
{
return '#2b2525';
}
public function icon()
{
return 'supportedapps/openhab.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Opnsense implements Contracts\Applications {
public function defaultColour()
{
return '#211914';
}
public function icon()
{
return 'supportedapps/opnsense.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Pfsense implements Contracts\Applications {
public function defaultColour()
{
return '#4e4742';
}
public function icon()
{
return 'supportedapps/pfsense.png';
}
}

View File

@@ -1,73 +0,0 @@
<?php namespace App\SupportedApps;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
class Pihole implements Contracts\Applications, Contracts\Livestats {
public function defaultColour()
{
return '#352222';
}
public function icon()
{
return 'supportedapps/pihole.png';
}
public function configDetails()
{
return 'pihole';
}
public function testConfig()
{
$res = $this->buildRequest();
switch($res->getStatusCode()) {
case 200:
echo 'Successfully connected to the API';
break;
case 401:
echo 'Failed: Invalid credentials';
break;
case 404:
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
break;
default:
echo 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
}
public function executeConfig()
{
$html = '';
$active = 'active';
$res = $this->buildRequest();
$data = json_decode($res->getBody());
$html = '
<ul class="livestats">
<li><span class="title">Domains<br />Blocked</span><strong>'.$data->domains_being_blocked.'</strong></li>
<li><span class="title">Blocked<br />Today</span><strong>'.$data->ads_blocked_today.'</span></strong></li>
</ul>
';
return json_encode(['status' => $active, 'html' => $html]);
}
public function buildRequest()
{
$config = $this->config;
$url = $config->url;
$url = rtrim($url, '/');
$api_url = $url.'/api.php';
//die( $api_url.' --- ');
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
$res = $client->request('GET', $api_url);
return $res;
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Plex implements Contracts\Applications {
public function defaultColour()
{
return '#222';
}
public function icon()
{
return 'supportedapps/plex.png';
}
}

View File

@@ -1,77 +0,0 @@
<?php namespace App\SupportedApps;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
class Plexpy implements Contracts\Applications, Contracts\Livestats {
public $config;
public function defaultColour()
{
return '#2d2208';
}
public function icon()
{
return 'supportedapps/plexpy.png';
}
public function configDetails()
{
return 'plexpy';
}
public function testConfig()
{
$res = $this->buildRequest('arnold');
switch($res->getStatusCode()) {
case 200:
$data = json_decode($res->getBody());
if(isset($data->error) && !empty($data->error)) {
echo 'Failed: '.$data->error;
} else {
echo 'Successfully connected to the API';
}
break;
case 401:
echo 'Failed: Invalid credentials';
break;
case 404:
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
break;
default:
echo 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
}
public function executeConfig()
{
$html = '';
$active = 'active';
$res = $this->buildRequest('get_activity');
$data = json_decode($res->getBody());
$stream_count = $data->response->data->stream_count;
$html = '
<ul class="livestats">
<li><span class="title">Stream Count</span><strong>'.$stream_count.'</strong></li>
</ul>
';
return json_encode(['status' => $active, 'html' => $html]);
}
public function buildRequest($endpoint)
{
$config = $this->config;
$url = $config->url;
$apikey = $config->apikey;
$url = rtrim($url, '/');
$api_url = $url.'/api/v2?apikey='.$apikey.'&cmd='.$endpoint;
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
$res = $client->request('GET', $api_url);
return $res;
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Plexrequests implements Contracts\Applications {
public function defaultColour()
{
return '#3c2d1c';
}
public function icon()
{
return 'supportedapps/plexrequests.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Portainer implements Contracts\Applications {
public function defaultColour()
{
return '#283f44';
}
public function icon()
{
return 'supportedapps/portainer.png';
}
}

View File

@@ -1,80 +0,0 @@
<?php namespace App\SupportedApps;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
class Proxmox implements Contracts\Applications, Contracts\Livestats {
public function defaultColour()
{
return '#542e0a';
}
public function icon()
{
return 'supportedapps/proxmox.png';
}
public function configDetails()
{
//return 'proxmox';
return null;
}
public function testConfig()
{
/*$res = $this->buildRequest();
switch($res->getStatusCode()) {
case 200:
echo 'Successfully connected to the API';
break;
case 401:
echo 'Failed: Invalid credentials';
break;
case 404:
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
break;
default:
echo 'Something went wrong... Code: '.$res->getStatusCode();
break;
}*/
return null;
}
public function executeConfig()
{
/*
$output = '';
$res = $this->buildRequest();
$data = json_decode($res->getBody());
$output = '
<ul class="livestats">
<li><span class="title">Domains<br />Blocked</span><strong>'.$data->domains_being_blocked.'</strong></li>
<li><span class="title">Blocked<br />Today</span><strong>'.$data->ads_blocked_today.'</span></strong></li>
</ul>
';
return $output;
*/
return null;
}
public function buildRequest($endpoint='')
{
$config = $this->config;
$username = $config->username;
$password = $config->password;
$url = $config->url;
$url = rtrim($url, '/');
$api_url = $url.'/api2/json/'.$endpoint.'?username='.$username.'&password='.$password;
//die( $api_url.' --- ');
$client = new Client(['http_errors' => false, 'verify' => false ]);
$res = $client->request('GET', $api_url);
return $res;
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Radarr implements Contracts\Applications {
public function defaultColour()
{
return '#3e3726';
}
public function icon()
{
return 'supportedapps/radarr.png';
}
}

View File

@@ -1,95 +0,0 @@
<?php namespace App\SupportedApps;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
class Runeaudio implements Contracts\Applications, Contracts\Livestats {
public function defaultColour()
{
return '#05A';
}
public function icon()
{
return 'supportedapps/runeaudio.png';
}
public function configDetails()
{
return 'runeaudio';
}
public function testConfig()
{
$res = $this->buildRequest('status');
switch($res->getStatusCode()) {
case 200:
echo 'Successfully connected to the API';
break;
case 401:
echo 'Failed: Invalid credentials';
break;
case 404:
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
break;
default:
echo 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
}
public function executeConfig()
{
$output = '';
$active = 'active';
$artist = '';
$song_title = '';
$res = $this->buildRequest('currentsong');
$array = explode("\n", $res->getBody());
foreach($array as $item) {
$item_array = explode(": ", $item);
if ($item_array[0] == 'Artist') {
$artist = $item_array[1];
} elseif ($item_array[0] == 'Title') {
$song_title = $item_array[1];
}
}
$output = '<ul class="livestats">';
if (strlen($artist) > 12) {
$output = $output.'<li><span class="title-marquee"><span>'.$artist.'</span></span></li>';
} else {
$output = $output.'<li><span class="title">'.$artist.'</span></li>';
}
$output = $output.'</ul><ul class="livestats">';
if (strlen($song_title) > 12) {
$output = $output.'<li><span class="title-marquee"><span>'.$song_title.'</span></span></li>';
} else {
$output = $output.'<li><span class="title">'.$song_title.'</span></li>';
}
$output = $output.'</ul>';
return json_encode(['status' => $active, 'html' => $output]);
}
public function buildRequest($endpoint)
{
$config = $this->config;
$url = $config->url;
$url = rtrim($url, '/');
$api_url = $url.'/command/?cmd='.$endpoint;
//die( $api_url.' --- ');
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
$res = $client->request('GET', $api_url);
return $res;
}
}

View File

@@ -1,89 +0,0 @@
<?php namespace App\SupportedApps;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
class Sabnzbd implements Contracts\Applications, Contracts\Livestats {
public $config;
public function defaultColour()
{
return '#3e3924';
}
public function icon()
{
return 'supportedapps/sabnzbd.png';
}
public function configDetails()
{
return 'sabnzbd';
}
public function testConfig()
{
$res = $this->buildRequest('queue');
switch($res->getStatusCode()) {
case 200:
$data = json_decode($res->getBody());
if(isset($data->error) && !empty($data->error)) {
echo 'Failed: '.$data->error;
} else {
echo 'Successfully connected to the API';
}
break;
case 401:
echo 'Failed: Invalid credentials';
break;
case 404:
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
break;
default:
echo 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
}
public function executeConfig()
{
$html = '';
$active = 'inactive';
$res = $this->buildRequest('queue');
$data = json_decode($res->getBody());
//$data->result->RemainingSizeMB = '10000000';
//$data->result->DownloadRate = '100000000';
if($data) {
$size = $data->queue->mbleft;
$rate = $data->queue->kbpersec;
$queue_size = format_bytes($size*1000*1000, false, ' <span>', '</span>');
$current_speed = format_bytes($rate*1000, false, ' <span>');
$active = ($size > 0 || $rate > 0) ? 'active' : 'inactive';
$html = '
<ul class="livestats">
<li><span class="title">Queue</span><strong>'.$queue_size.'</strong></li>
<li><span class="title">Speed</span><strong>'.$current_speed.'/s</span></strong></li>
</ul>
';
}
return json_encode(['status' => $active, 'html' => $html]);
}
public function buildRequest($endpoint)
{
$config = $this->config;
$url = $config->url;
$apikey = $config->apikey;
//print_r($config);
//die();
$url = rtrim($url, '/');
$api_url = $url.'/api?output=json&apikey='.$apikey.'&mode='.$endpoint;
//die( $api_url.' --- ');
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
$res = $client->request('GET', $api_url);
return $res;
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Sickrage implements Contracts\Applications {
public function defaultColour()
{
return '#6185a6';
}
public function icon()
{
return 'supportedapps/sickrage.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Sonarr implements Contracts\Applications {
public function defaultColour()
{
return '#163740';
}
public function icon()
{
return 'supportedapps/sonarr.png';
}
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps;
class Syncthing implements Contracts\Applications {
public function defaultColour()
{
return '#888';
}
public function icon()
{
return 'supportedapps/syncthing.png';
}
}

View File

@@ -1,77 +0,0 @@
<?php namespace App\SupportedApps;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
class Tautulli implements Contracts\Applications, Contracts\Livestats {
public $config;
public function defaultColour()
{
return '#2d2208';
}
public function icon()
{
return 'supportedapps/tautulli.png';
}
public function configDetails()
{
return 'tautulli';
}
public function testConfig()
{
$res = $this->buildRequest('arnold');
switch($res->getStatusCode()) {
case 200:
$data = json_decode($res->getBody());
if(isset($data->error) && !empty($data->error)) {
echo 'Failed: '.$data->error;
} else {
echo 'Successfully connected to the API';
}
break;
case 401:
echo 'Failed: Invalid credentials';
break;
case 404:
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
break;
default:
echo 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
}
public function executeConfig()
{
$html = '';
$active = 'active';
$res = $this->buildRequest('get_activity');
$data = json_decode($res->getBody());
$stream_count = $data->response->data->stream_count;
$html = '
<ul class="livestats">
<li><span class="title">Stream Count</span><strong>'.$stream_count.'</strong></li>
</ul>
';
return json_encode(['status' => $active, 'html' => $html]);
}
public function buildRequest($endpoint)
{
$config = $this->config;
$url = $config->url;
$apikey = $config->apikey;
$url = rtrim($url, '/');
$api_url = $url.'/api/v2?apikey='.$apikey.'&cmd='.$endpoint;
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
$res = $client->request('GET', $api_url);
return $res;
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Traefik implements Contracts\Applications {
public function defaultColour()
{
return '#28434a';
}
public function icon()
{
return 'supportedapps/traefik.png';
}
}

View File

@@ -1,166 +0,0 @@
<?php namespace App\SupportedApps;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
class Transmission implements Contracts\Applications, Contracts\Livestats
{
private $_client;
private $_clientOptions = array();
public function __construct()
{
$body = array();
$body["method"] = "torrent-get";
$body["arguments"] = array("fields" => ["percentDone","status","rateDownload","rateUpload"]);
$this->_client = new Client(
['http_errors' => false,
'timeout' => 10,
'body' => json_encode($body)]
);
}
public function defaultColour()
{
return '#950003';
}
public function icon()
{
return 'supportedapps/transmission.png';
}
public function configDetails()
{
return 'transmission';
}
public function testConfig()
{
$res = $this->sendRequest();
if ($res == null) {
echo 'Transmission connection failed';
return;
}
switch($res->getStatusCode()) {
case 200:
$data = json_decode($res->getBody());
echo "Successfully connected with status: ".$data->result."\n";
break;
case 401:
echo 'Failed: Invalid credentials';
break;
case 404:
echo 'Failed: Please make sure your URL is correct and includes the port';
break;
case 409:
echo 'Failed: Incorrect session id';
break;
default:
echo 'Something went wrong... Code: '.$res->getStatusCode();
break;
}
}
public function executeConfig()
{
$html = '';
$active = 'active';
$res = $this->sendRequest();
if ($res == null) {
Log::debug('Transmission connection failed');
return '';
}
$data = json_decode($res->getBody());
if (! isset($data->arguments)) {
Log::debug('Failed to fetch data from Transmission');
return '';
}
$torrents = $data->arguments->torrents;
$torrentCount = count($torrents);
$rateDownload = $rateUpload = $completedTorrents = 0;
foreach ($torrents as $thisTorrent) {
$rateDownload += $thisTorrent->rateDownload;
$rateUpload += $thisTorrent->rateUpload;
if ($thisTorrent->percentDone == 1) {
$completedTorrents += 1;
}
}
if ($torrentCount - $completedTorrents == 0) {
// Don't poll as frequently if we don't have any active torrents
$active = 'inactive';
}
$html = '
<ul class="livestats">
<li><span class="title">Done</span><sub>'.$completedTorrents.' / '.$torrentCount.'</sub></li>
<li><span class="title">Down</span><sub>'.format_bytes($rateDownload).'</sub></li>
<li><span class="title">Up</span><sub>'.format_bytes($rateUpload).'</sub></li>
</ul>
';
return json_encode(['status' => $active, 'html' => $html]);;
}
private function sendRequest()
{
$optionsSet = $this->setClientOptions();
if (! $optionsSet) {
// Pass the failed response back up the chain
return null;
}
$res = $this->torrentGet();
if ($res->getStatusCode() == 409) {
$this->setClientOptions();
$res = $this->torrentGet();
}
return $res;
}
private function torrentGet()
{
$res = null;
try{
$res = $this->_client->request(
'POST',
$this->getApiUrl(),
$this->_clientOptions
);
}catch(\GuzzleHttp\Exception\BadResponseException $e){
Log::error("Connection to {$e->getRequest()->getUrl()} failed");
Log::debug($e->getMessage());
$res = $e->getRequest();
}catch(\GuzzleHttp\Exception\ConnectException $e) {
Log::error("Transmission connection refused");
Log::debug($e->getMessage());
}
return $res;
}
private function setClientOptions()
{
if ($this->config->username != '' || $this->config->password != '') {
$this->_clientOptions = ['auth'=> [$this->config->username, $this->config->password, 'Basic']];
}
try{
$res = $this->_client->request('HEAD', $this->getApiUrl(), $this->_clientOptions);
$xtId = $res->getHeaderLine('X-Transmission-Session-Id');
if ($xtId != null) {
$this->_clientOptions['headers'] = ['X-Transmission-Session-Id' => $xtId];
} else {
Log::error("Unable to get Transmission session information");
Log::debug("Status Code: ".$res->getStatusCode());
}
}catch(\GuzzleHttp\Exception\ConnectException $e){
Log::error("Failed connection to Transmission");
return false;
}
return true;
}
private function getApiUrl()
{
$url = $this->config->url;
$url = rtrim($url, '/');
$apiUrl = $url.'/transmission/rpc';
return $apiUrl;
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Ttrss implements Contracts\Applications {
public function defaultColour()
{
return '#9d704c';
}
public function icon()
{
return 'supportedapps/tt-rss.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Unifi implements Contracts\Applications {
public function defaultColour()
{
return '#363840';
}
public function icon()
{
return 'supportedapps/unifi.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class Unraid implements Contracts\Applications {
public function defaultColour()
{
return '#3B5E1F';
}
public function icon()
{
return 'supportedapps/unraid.png';
}
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps;
class Watcher3 implements Contracts\Applications {
public function defaultColour()
{
return '#500';
}
public function icon()
{
return 'supportedapps/watcher3.png';
}
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps;
class WebTools implements Contracts\Applications {
public function defaultColour()
{
return '#555';
}
public function icon()
{
return 'supportedapps/webtools.png';
}
}

View File

@@ -1,11 +0,0 @@
<?php namespace App\SupportedApps;
class pyLoad implements Contracts\Applications {
public function defaultColour()
{
return '#881';
}
public function icon()
{
return 'supportedapps/pyload.png';
}
}

View File

@@ -1,12 +0,0 @@
<?php namespace App\SupportedApps;
class ruTorrent implements Contracts\Applications {
public function defaultColour()
{
return '#004';
}
public function icon()
{
return 'supportedapps/rutorrent.png';
}
}

View File

@@ -15,7 +15,7 @@ class User extends Authenticatable
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
'username', 'email', 'password',
];
/**
@@ -26,4 +26,38 @@ class User extends Authenticatable
protected $hidden = [
'password', 'remember_token',
];
/**
* Get the items for the user.
*/
public function items()
{
return $this->hasMany('App\Item');
}
/**
* The settings that belong to the user.
*/
public function settings()
{
return $this->belongsToMany('App\Setting')->withPivot('uservalue');
}
public static function currentUser()
{
$current_user = session('current_user');
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();
}
session(['current_user' => $user]);
return $user;
}
}
}

View File

@@ -6,11 +6,13 @@
"type": "project",
"require": {
"php": ">=7.0.0",
"fideloper/proxy": "~3.3",
"fideloper/proxy": "^4.0",
"graham-campbell/github": "^7.5",
"guzzlehttp/guzzle": "^6.3",
"laravel/framework": "5.5.*",
"laravel/framework": "5.7.*",
"laravel/tinker": "~1.0",
"laravelcollective/html": "^5.5"
"laravelcollective/html": "^5.5",
"php-http/guzzle6-adapter": "^1.1"
},
"require-dev": {
"filp/whoops": "~2.0",

2049
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@ return [
*/
'name' => env('APP_NAME', 'Heimdall'),
'version' => '1.4.13',
'version' => '2.1.7',
/*
|--------------------------------------------------------------------------
@@ -229,6 +229,9 @@ return [
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'SupportedApps' => App\SupportedApps::class,
'EnhancedApps' => App\EnhancedApps::class,
],
];

91
config/github.php Normal file
View File

@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
/*
* This file is part of Laravel GitHub.
*
* (c) Graham Campbell <graham@alt-three.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
/*
|--------------------------------------------------------------------------
| Default Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the connections below you wish to use as
| your default connection for all work. Of course, you may use many
| connections at once using the manager class.
|
*/
'default' => 'main',
/*
|--------------------------------------------------------------------------
| GitHub Connections
|--------------------------------------------------------------------------
|
| Here are each of the connections setup for your application. Example
| configuration has been included, but you may add as many connections as
| you would like. Note that the 5 supported authentication methods are:
| "application", "jwt", "none", "password", and "token".
|
*/
'connections' => [
'main' => [
'token' => 'your-token',
'method' => 'token',
// 'backoff' => false,
// 'cache' => false,
// 'version' => 'v3',
// 'enterprise' => false,
],
'app' => [
'clientId' => 'your-client-id',
'clientSecret' => 'your-client-secret',
'method' => 'application',
// 'backoff' => false,
// 'cache' => false,
// 'version' => 'v3',
// 'enterprise' => false,
],
'jwt' => [
'token' => 'your-jwt-token',
'method' => 'jwt',
// 'backoff' => false,
// 'cache' => false,
// 'version' => 'v3',
// 'enterprise' => false,
],
'other' => [
'username' => 'your-username',
'password' => 'your-password',
'method' => 'password',
// 'backoff' => false,
// 'cache' => false,
// 'version' => 'v3',
// 'enterprise' => false,
],
'none' => [
'method' => 'none',
// 'backoff' => false,
// 'cache' => false,
// 'version' => 'v3',
// 'enterprise' => false,
],
],
];

View File

@@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('username')->unique();
$table->string('email');
$table->string('avatar')->nullable();
$table->string('password')->nullable();
$table->string('autologin')->nullable()->index();
$table->boolean('public_front')->default(false);
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePasswordResetsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('password_resets', function (Blueprint $table) {
$table->string('email')->index();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('password_resets');
}
}

View File

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

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSettingUserPivotTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('setting_user', function (Blueprint $table) {
$table->integer('setting_id')->unsigned()->index();
$table->foreign('setting_id')->references('id')->on('settings')->onDelete('cascade');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->primary(['setting_id', 'user_id']);
$table->string('uservalue')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('setting_user');
}
}

View File

@@ -0,0 +1,41 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateApplicationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('applications', function (Blueprint $table) {
$table->string('appid')->unique();
$table->string('name')->unique();
$table->string('sha')->unique()->nullable();
$table->string('icon')->nullable();
$table->string('website')->nullable();
$table->string('license')->nullable();
$table->mediumText('description')->nullable();
$table->boolean('enhanced')->default(false);
$table->string('tile_background')->default('dark');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('applications');
}
}

View File

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

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateJobsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('jobs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('queue')->index();
$table->longText('payload');
$table->unsignedTinyInteger('attempts');
$table->unsignedInteger('reserved_at')->nullable();
$table->unsignedInteger('available_at');
$table->unsignedInteger('created_at');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('jobs');
}
}

View File

@@ -12,5 +12,6 @@ class DatabaseSeeder extends Seeder
public function run()
{
$this->call(SettingsSeeder::class);
$this->call(UsersSeeder::class);
}
}

View File

@@ -138,6 +138,60 @@ class SettingsSeeder extends Seeder
$setting->save();
}
$window_target_options = json_encode([
'current' => 'app.settings.window_target.current',
'heimdall' => 'app.settings.window_target.one',
'_blank' => 'app.settings.window_target.new',
]);
if(!$setting = Setting::find(7)) {
$setting = new Setting;
$setting->id = 7;
$setting->group_id = 3;
$setting->key = 'window_target';
$setting->type = 'select';
$setting->options = $window_target_options;
$setting->label = 'app.settings.window_target';
$setting->value = 'heimdall';
$setting->save();
} else {
$setting->options = $window_target_options;
$setting->label = 'app.settings.window_target';
$setting->save();
}
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();
} else {
$setting = new Setting;
$setting->id = 8;
$setting->group_id = 1;
$setting->key = 'support';
$setting->type = 'text';
$setting->label = 'app.settings.support';
$setting->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>';
$setting->system = true;
$setting->save();
}
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();
} else {
$setting = new Setting;
$setting->id = 9;
$setting->group_id = 1;
$setting->key = 'donate';
$setting->type = 'text';
$setting->label = 'app.settings.donate';
$setting->value = '<a rel="noopener" target="_blank" href="https://www.paypal.me/heimdall">Paypal</a>';
$setting->system = true;
$setting->save();
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Seeder;
use App\User;
class UsersSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// Groups
if(!$user = User::find(1)) {
$user = new User;
$user->id = 1;
$user->username = 'admin';
$user->email = 'admin@test.com';
$user->password = null;
$user->save();
} else {
//$user->save();
}
}
}

10454
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,16 +10,12 @@
"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": {
"axios": "^0.17",
"bootstrap-sass": "^3.3.7",
"cross-env": "^5.1.3",
"cross-env": "^5.2.0",
"jquery": "^3.2",
"laravel-mix": "^1.0",
"lodash": "^4.17.4",
"vue": "^2.5.7"
"laravel-mix": "^2.1.14"
},
"dependencies": {
"node-sass": "^4.7.2",
"select2": "^4.0.6-rc.1"
}
}

282
public/css/app.css vendored
View File

@@ -1,5 +1,4 @@
@import url(https://fonts.googleapis.com/css?family=Raleway:300,400,600);/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
html {
font-family: sans-serif;
-ms-text-size-adjust: 100%;
@@ -225,9 +224,7 @@ html {
box-sizing: border-box;
}
*,
*:before,
*:after {
*, *:before, *:after {
-webkit-box-sizing: inherit;
box-sizing: inherit;
}
@@ -236,6 +233,61 @@ body {
background: #cfd2d4;
}
#switchuser {
background: rgba(0, 0, 0, 0.5);
position: absolute;
padding: 10px;
color: white;
text-align: center;
bottom: 0;
left: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
border-top: 2px solid rgba(255, 255, 255, 0.15);
border-right: 2px solid rgba(255, 255, 255, 0.15);
-webkit-box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
border-radius: 0 9px 0 0;
line-height: 1.5;
font-size: 14px;
}
#switchuser img {
width: 50px;
margin-bottom: 5px;
border-radius: 50%;
}
#switchuser .btn {
font-size: 13px;
color: white;
text-decoration: none;
margin-left: -10px;
margin-right: -10px;
margin-bottom: -10px;
margin-top: 8px;
border-radius: 0;
width: calc(100% + 22px);
background: rgba(255, 255, 255, 0.15);
-webkit-transition: all .35s ease-in-out;
transition: all .35s ease-in-out;
}
#switchuser .btn:hover {
background: #d64d55;
}
#app {
display: -webkit-box;
display: -ms-flexbox;
@@ -245,7 +297,7 @@ body {
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
background-image: url("/img/bg1.jpg");
background-image: url("../img/bg1.jpg");
background-repeat: no-repeat;
background-size: cover;
background-position: bottom center;
@@ -325,9 +377,8 @@ body {
flex-direction: column;
}
#app main,
#app #sortable {
padding: 10px;
#app main, #app #sortable {
padding: 30px 10px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
@@ -378,6 +429,68 @@ body {
margin-top: 12px;
}
.userlist {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.userlist .user {
background: rgba(0, 0, 0, 0.5);
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding: 15px;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
margin: 20px;
color: white;
text-decoration: none;
border-radius: 15px;
border: 5px solid rgba(255, 255, 255, 0.7);
-webkit-box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
}
.userlist .user-img {
width: 130px;
height: 130px;
margin-bottom: 20px;
border-radius: 50%;
margin: 10px 10px 15px;
}
.userlist #password {
color: #2f313a;
width: 100%;
padding: 5px 10px;
margin: 15px -5px;
}
.userlist .btn {
width: 100%;
}
.userlist .forgot {
color: white;
font-size: 12px;
margin-top: 25px;
}
.item-container {
position: relative;
}
@@ -396,6 +509,14 @@ body {
display: none;
}
.black {
color: #000 !important;
}
.white {
color: #fff !important;
}
.message-container {
width: 100%;
padding: 10px 20px;
@@ -423,13 +544,11 @@ body {
box-shadow: 0 0 15px 3px rgba(0, 0, 0, 0.3);
}
.alert.alert-success,
.alert.alert-danger {
.alert.alert-success, .alert.alert-danger {
position: relative;
}
.alert.alert-success:before,
.alert.alert-danger:before {
.alert.alert-success:before, .alert.alert-danger:before {
content: "\F00C";
font-family: 'Font Awesome 5 Pro';
font-weight: 900;
@@ -463,8 +582,7 @@ body {
color: #91a1b3;
}
#app.header .item,
#app.header .add-item {
#app.header .item, #app.header .add-item {
-webkit-transform: scale(0.9);
transform: scale(0.9);
opacity: 0.8;
@@ -585,10 +703,11 @@ body {
max-width: 1000px;
width: 100%;
margin: 10px 40px;
border-radius: 5px;
overflow: hidden;
}
.module-container header,
.module-container footer {
.module-container header, .module-container footer {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
@@ -606,8 +725,7 @@ body {
position: relative;
}
.module-container header .section-title,
.module-container footer .section-title {
.module-container header .section-title, .module-container footer .section-title {
font-size: 18px;
color: #5b5b5b;
margin-left: 25px;
@@ -671,6 +789,26 @@ body {
height: 51px;
}
.toggleinput {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: reverse;
-ms-flex-direction: column-reverse;
flex-direction: column-reverse;
line-height: 1;
font-size: 9px;
font-weight: 400;
text-transform: uppercase;
color: #ababab;
padding: 0 20px;
}
.toggleinput label.name {
margin-top: 6px;
}
.module-actions {
display: -webkit-box;
display: -ms-flexbox;
@@ -756,8 +894,7 @@ div.create .input label:not(.switch) {
font-weight: 300;
}
div.create .input input,
div.create .input select {
div.create .input input, div.create .input select {
width: 100%;
border: 1px solid #dedfe2;
padding: 10px;
@@ -825,13 +962,11 @@ div.create .input select {
}
/* Hide default HTML checkbox */
.switch input {
display: none;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
@@ -871,7 +1006,6 @@ input:checked + .slider:before {
}
/* Rounded sliders */
.slider.round {
border-radius: 20px;
}
@@ -1025,23 +1159,23 @@ a.settinglink {
text-decoration: none;
}
.ui-state-hover,
.ui-state-active {
.ui-state-hover, .ui-state-active {
font-weight: 700;
}
#appimage img {
max-width: 150px;
max-width: 95px;
}
#sapconfig {
#sapconfig, .newblock {
display: none;
width: 100%;
}
#sapconfig h2 {
#sapconfig h2, .newblock h2 {
background: #f2f3f6;
padding: 18px 25px;
padding: 2px 25px;
height: 60px;
margin-left: -15px;
width: calc(100% + 30px);
/* margin-right: -30px; */
@@ -1050,9 +1184,18 @@ a.settinglink {
font-size: 18px;
color: #5b5b5b;
font-weight: 500;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
#sapconfig .items {
#sapconfig .items, .newblock .items {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
@@ -1119,7 +1262,7 @@ hr {
}
.livestats-container .livestats {
margin: 5px 0px -5px;
margin: 5px 0px 0px;
padding: 0;
display: -webkit-box;
display: -ms-flexbox;
@@ -1144,11 +1287,39 @@ hr {
font-weight: 500;
opacity: 0.5;
line-height: 1;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
text-align: left;
}
.livestats-container .livestats strong {
display: block;
line-height: 1;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
color: white;
font-size: 12px;
line-height: 1.2;
}
.livestats-container .livestats strong span {
margin-left: 4px;
}
.livestats-container .livestats.flexcolumn {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.livestats-container.black .livestats strong {
color: #000;
}
input:-webkit-autofill,
@@ -1172,9 +1343,16 @@ select:-webkit-autofill:focus {
.title-marquee {
width: 125px;
overflow: hidden;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
margin-top: 2px;
}
.title-marquee span {
.title-marquee > span, .title-marquee > strong {
white-space: nowrap;
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
@@ -1182,22 +1360,27 @@ select:-webkit-autofill:focus {
animation: marquee 8s linear;
}
.title-marquee .title {
margin-right: 4px;
}
.no-marquee .title {
margin-right: 4px;
}
@-webkit-keyframes marquee {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
20% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
95% {
-webkit-transform: translate(-200%, 0);
transform: translate(-200%, 0);
}
100% {
-webkit-transform: translate(-200%, 0);
transform: translate(-200%, 0);
@@ -1209,17 +1392,14 @@ select:-webkit-autofill:focus {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
20% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
95% {
-webkit-transform: translate(-200%, 0);
transform: translate(-200%, 0);
}
100% {
-webkit-transform: translate(-200%, 0);
transform: translate(-200%, 0);
@@ -1229,7 +1409,6 @@ select:-webkit-autofill:focus {
/*! Huebee v2.0.0
http://huebee.buzz
---------------------------------------------- */
.huebee {
position: absolute;
z-index: 1;
@@ -1324,7 +1503,6 @@ http://huebee.buzz
* Font Awesome Pro 5.0.2 by @fontawesome - http://fontawesome.com
* License - http://fontawesome.com/license (Commercial License)
*/
.fa,
.fas,
.far,
@@ -1461,7 +1639,6 @@ http://huebee.buzz
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
@@ -1473,7 +1650,6 @@ http://huebee.buzz
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
@@ -1556,7 +1732,6 @@ http://huebee.buzz
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
readers do not read off random characters that represent icons */
.fa-500px:before {
content: "\F26E";
}
@@ -5340,8 +5515,7 @@ readers do not read off random characters that represent icons */
width: 1px;
}
.sr-only-focusable:active,
.sr-only-focusable:focus {
.sr-only-focusable:active, .sr-only-focusable:focus {
clip: auto;
height: auto;
margin: 0;
@@ -5354,13 +5528,12 @@ readers do not read off random characters that represent icons */
* Font Awesome Pro 5.0.2 by @fontawesome - http://fontawesome.com
* License - http://fontawesome.com/license (Commercial License)
*/
@font-face {
font-family: 'Font Awesome 5 Pro';
font-style: normal;
font-weight: 900;
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");
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,
@@ -5671,9 +5844,7 @@ readers do not read off random characters that represent icons */
color: #333;
}
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder,
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
float: right;
}
@@ -5701,14 +5872,12 @@ readers do not read off random characters that represent icons */
display: none;
}
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,
.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,
.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
@@ -6019,4 +6188,3 @@ readers do not read off random characters that represent icons */
.select2-container--classic.select2-container--open .select2-dropdown {
border-color: #5897fb;
}

View File

@@ -0,0 +1,14 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="780" height="619" viewBox="0 0 780 619">
<metadata><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""/>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?></metadata>
<path class="cls-1" d="M440.227,415.119V390.2l8.552-26.577C508.647,304.3,555.686,248.776,564,231.691l-10.215,3.56s9.5-11.864,8.552-18.51c-7.6-116.273-73.17-176.862-91.226-191.732,26.607,31.955,19.326,42.4,19.326,42.4C478.714,45.576,454.64,24.377,449.888,19l-5.7,33.853c22.806,13.289,16.79,20.882,16.79,20.882C455.591,66.141,441.021,59.5,441.021,59.5l-1.586,9.491c6.973,3.165,38.327,22.149,38.565,70.872,0,59.323-33.735,74.985-39.674,77.357-19.718-11.865-41.1-11.627-46.326-12.1-5.226.474-26.608,0.236-46.324,12.1C339.735,214.844,306,199.182,306,139.859c0.238-48.723,31.6-67.707,38.564-70.872L342.983,59.5s-14.574,6.644-19.955,14.238c0,0-6.022-7.593,16.786-20.882L334.112,19c-4.752,5.378-28.824,26.577-40.543,48.407,0,0-7.288-10.443,19.32-42.4-18.054,14.87-83.625,75.459-91.226,191.732-0.95,6.646,8.554,18.51,8.554,18.51L220,231.691c8.316,17.085,55.355,72.612,115.221,131.935l8.554,26.577v24.916l-7.6-26.577L318.83,360.067v28.95C325.957,409.186,353.751,450,353.751,450V365.525L247.32,249.488s66.52,54.1,85.526,73.56l9.978-10.2c-12.355-8.78-66.045-62.646-70.8-110.1,40.388,85.426,79.111,96.1,107.62,129.325V340.2h24.707v-8.131c28.508-33.221,67.233-43.9,107.619-129.325-4.75,47.459-58.442,101.325-70.8,110.1l9.976,10.2c19.006-19.458,85.526-73.56,85.526-73.56L430.249,365.525V450s27.8-40.815,34.923-60.984v-28.95l-17.343,28.475ZM392,313.083c-17.818-11.865-63.668-39.629-82.672-83.053a314.117,314.117,0,0,0,34.447,34.882s-1.189-30.61,1.186-37.255c4.276,36.781,13.068,52.442,47.039,71.9,33.973-19.458,42.763-35.119,47.039-71.9,2.375,6.645,1.188,37.255,1.188,37.255a314.117,314.117,0,0,0,34.447-34.882C455.668,273.454,409.818,301.218,392,313.083Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16pt" height="16pt" viewBox="0 0 16 16" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 9.777344 14.660156 L 9.777344 13.738281 L 10.09375 12.761719 C 12.300781 10.574219 14.035156 8.527344 14.339844 7.894531 L 13.964844 8.027344 C 13.964844 8.027344 14.316406 7.589844 14.28125 7.34375 C 14 3.058594 11.582031 0.824219 10.917969 0.277344 C 11.898438 1.453125 11.628906 1.839844 11.628906 1.839844 C 11.195312 1.035156 10.308594 0.253906 10.132812 0.0546875 L 9.925781 1.304688 C 10.765625 1.792969 10.542969 2.074219 10.542969 2.074219 C 10.34375 1.792969 9.808594 1.546875 9.808594 1.546875 L 9.75 1.898438 C 10.003906 2.015625 11.160156 2.714844 11.171875 4.511719 C 11.171875 6.699219 9.925781 7.277344 9.707031 7.363281 C 8.980469 6.925781 8.191406 6.933594 8 6.917969 C 7.808594 6.933594 7.019531 6.925781 6.292969 7.363281 C 6.074219 7.273438 4.828125 6.699219 4.828125 4.511719 C 4.839844 2.714844 5.996094 2.015625 6.25 1.898438 L 6.191406 1.546875 C 6.191406 1.546875 5.65625 1.792969 5.457031 2.074219 C 5.457031 2.074219 5.234375 1.792969 6.074219 1.304688 L 5.867188 0.0546875 C 5.691406 0.253906 4.804688 1.035156 4.371094 1.839844 C 4.371094 1.839844 4.101562 1.453125 5.082031 0.277344 C 4.417969 0.824219 2 3.058594 1.71875 7.34375 C 1.683594 7.589844 2.035156 8.027344 2.035156 8.027344 L 1.660156 7.894531 C 1.964844 8.527344 3.699219 10.574219 5.90625 12.761719 L 6.222656 13.738281 L 6.222656 14.660156 L 5.941406 13.679688 L 5.300781 12.628906 L 5.300781 13.695312 C 5.566406 14.441406 6.589844 15.945312 6.589844 15.945312 L 6.589844 12.832031 L 2.667969 8.550781 C 2.667969 8.550781 5.117188 10.546875 5.820312 11.265625 L 6.1875 10.886719 C 5.730469 10.566406 3.753906 8.578125 3.578125 6.828125 C 5.066406 9.980469 6.492188 10.371094 7.542969 11.597656 L 7.542969 11.898438 L 8.457031 11.898438 L 8.457031 11.597656 C 9.507812 10.371094 10.933594 9.980469 12.421875 6.828125 C 12.246094 8.578125 10.269531 10.566406 9.8125 10.886719 L 10.179688 11.265625 C 10.882812 10.546875 13.332031 8.550781 13.332031 8.550781 L 9.410156 12.832031 L 9.410156 15.945312 C 9.410156 15.945312 10.433594 14.441406 10.699219 13.695312 L 10.699219 12.628906 L 10.058594 13.679688 Z M 8 10.898438 C 7.34375 10.460938 5.652344 9.4375 4.953125 7.835938 C 5.339844 8.296875 5.765625 8.726562 6.222656 9.121094 C 6.222656 9.121094 6.179688 7.992188 6.265625 7.746094 C 6.421875 9.105469 6.746094 9.679688 8 10.398438 C 9.253906 9.679688 9.578125 9.105469 9.734375 7.746094 C 9.820312 7.992188 9.777344 9.121094 9.777344 9.121094 C 10.234375 8.726562 10.660156 8.296875 11.046875 7.835938 C 10.347656 9.4375 8.65625 10.460938 8 10.898438 Z M 8 10.898438 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,11 @@
<svg width="434" height="434" xmlns="http://www.w3.org/2000/svg">
<g>
<title>background</title>
<rect fill="none" id="canvas_background" height="436" width="436" y="-1" x="-1"/>
</g>
<g>
<title>Layer 1</title>
<path id="svg_1" d="m265.227,397.619l0,-24.919l8.552,-26.577c59.868,-59.323 106.907,-114.847 115.221,-131.932l-10.215,3.56s9.5,-11.864 8.552,-18.51c-7.6,-116.273 -73.17,-176.862 -91.226,-191.732c26.607,31.955 19.326,42.4 19.326,42.4c-11.723,-21.833 -35.797,-43.032 -40.549,-48.409l-5.7,33.853c22.806,13.289 16.79,20.882 16.79,20.882c-5.387,-7.594 -19.957,-14.235 -19.957,-14.235l-1.586,9.491c6.973,3.165 38.327,22.149 38.565,70.872c0,59.323 -33.735,74.985 -39.674,77.357c-19.718,-11.865 -41.1,-11.627 -46.326,-12.1c-5.226,0.474 -26.608,0.236 -46.324,12.1c-5.941,-2.376 -39.676,-18.038 -39.676,-77.361c0.238,-48.723 31.6,-67.707 38.564,-70.872l-1.581,-9.487s-14.574,6.644 -19.955,14.238c0,0 -6.022,-7.593 16.786,-20.882l-5.702,-33.856c-4.752,5.378 -28.824,26.577 -40.543,48.407c0,0 -7.288,-10.443 19.32,-42.4c-18.054,14.87 -83.625,75.459 -91.226,191.732c-0.95,6.646 8.554,18.51 8.554,18.51l-10.217,-3.558c8.316,17.085 55.355,72.612 115.221,131.935l8.554,26.577l0,24.916l-7.6,-26.577l-17.345,-28.475l0,28.95c7.127,20.169 34.921,60.983 34.921,60.983l0,-84.475l-106.431,-116.037s66.52,54.1 85.526,73.56l9.978,-10.2c-12.355,-8.78 -66.045,-62.646 -70.8,-110.1c40.388,85.426 79.111,96.1 107.62,129.325l0,8.127l24.707,0l0,-8.131c28.508,-33.221 67.233,-43.9 107.619,-129.325c-4.75,47.459 -58.442,101.325 -70.8,110.1l9.976,10.2c19.006,-19.458 85.526,-73.56 85.526,-73.56l-106.423,116.041l0,84.475s27.8,-40.815 34.923,-60.984l0,-28.95l-17.343,28.475l-7.602,26.578zm-48.227,-102.036c-17.818,-11.865 -63.668,-39.629 -82.672,-83.053a314.117,314.117 0 0 0 34.447,34.882s-1.189,-30.61 1.186,-37.255c4.276,36.781 13.068,52.442 47.039,71.9c33.973,-19.458 42.763,-35.119 47.039,-71.9c2.375,6.645 1.188,37.255 1.188,37.255a314.117,314.117 0 0 0 34.447,-34.882c-19.006,43.424 -64.856,71.188 -82.674,83.053z" class="cls-1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,11 @@
<svg width="346" height="434" xmlns="http://www.w3.org/2000/svg">
<g>
<title>background</title>
<rect fill="none" id="canvas_background" height="436" width="348" y="-1" x="-1"/>
</g>
<g>
<title>Layer 1</title>
<path id="svg_1" d="m221.227,397.119l0,-24.919l8.552,-26.577c59.868,-59.323 106.907,-114.847 115.221,-131.932l-10.215,3.56s9.5,-11.864 8.552,-18.51c-7.6,-116.273 -73.17,-176.862 -91.226,-191.732c26.607,31.955 19.326,42.4 19.326,42.4c-11.723,-21.833 -35.797,-43.032 -40.549,-48.409l-5.7,33.853c22.806,13.289 16.79,20.882 16.79,20.882c-5.387,-7.594 -19.957,-14.235 -19.957,-14.235l-1.586,9.491c6.973,3.165 38.327,22.149 38.565,70.872c0,59.323 -33.735,74.985 -39.674,77.357c-19.718,-11.865 -41.1,-11.627 -46.326,-12.1c-5.226,0.474 -26.608,0.236 -46.324,12.1c-5.941,-2.376 -39.676,-18.038 -39.676,-77.361c0.238,-48.723 31.6,-67.707 38.564,-70.872l-1.581,-9.487s-14.574,6.644 -19.955,14.238c0,0 -6.022,-7.593 16.786,-20.882l-5.702,-33.856c-4.752,5.378 -28.824,26.577 -40.543,48.407c0,0 -7.288,-10.443 19.32,-42.4c-18.054,14.87 -83.625,75.459 -91.226,191.732c-0.95,6.646 8.554,18.51 8.554,18.51l-10.217,-3.558c8.316,17.085 55.355,72.612 115.221,131.935l8.554,26.577l0,24.916l-7.6,-26.577l-17.345,-28.475l0,28.95c7.127,20.169 34.921,60.983 34.921,60.983l0,-84.475l-106.431,-116.037s66.52,54.1 85.526,73.56l9.978,-10.2c-12.355,-8.78 -66.045,-62.646 -70.8,-110.1c40.388,85.426 79.111,96.1 107.62,129.325l0,8.127l24.707,0l0,-8.131c28.508,-33.221 67.233,-43.9 107.619,-129.325c-4.75,47.459 -58.442,101.325 -70.8,110.1l9.976,10.2c19.006,-19.458 85.526,-73.56 85.526,-73.56l-106.423,116.041l0,84.475s27.8,-40.815 34.923,-60.984l0,-28.95l-17.343,28.475l-7.602,26.578zm-48.227,-102.036c-17.818,-11.865 -63.668,-39.629 -82.672,-83.053a314.117,314.117 0 0 0 34.447,34.882s-1.189,-30.61 1.186,-37.255c4.276,36.781 13.068,52.442 47.039,71.9c33.973,-19.458 42.763,-35.119 47.039,-71.9c2.375,6.645 1.188,37.255 1.188,37.255a314.117,314.117 0 0 0 34.447,-34.882c-19.006,43.424 -64.856,71.188 -82.674,83.053z" class="cls-1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

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