mirror of
https://github.com/linuxserver/Heimdall.git
synced 2026-02-24 05:30:33 +09:00
Compare commits
287 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcc0f90b23 | ||
|
|
75014c8269 | ||
|
|
386e4c788b | ||
|
|
fe0109494e | ||
|
|
6907695c5d | ||
|
|
533af2dc49 | ||
|
|
1ac5eb6d23 | ||
|
|
e2ba89c80e | ||
|
|
bbae811cd8 | ||
|
|
589aa73a15 | ||
|
|
fc023401f5 | ||
|
|
02dfed0bc7 | ||
|
|
71d356935f | ||
|
|
e53bae2c69 | ||
|
|
3117b9c483 | ||
|
|
c5817c9b2e | ||
|
|
c403e8b2df | ||
|
|
758c174141 | ||
|
|
9bc9c48e06 | ||
|
|
9a6dd623db | ||
|
|
d1c6001fae | ||
|
|
74196a2bfa | ||
|
|
724110dad2 | ||
|
|
3a043e0165 | ||
|
|
ac37c60e1f | ||
|
|
937e576520 | ||
|
|
9086e9bd75 | ||
|
|
4c90d8c87e | ||
|
|
a4cceb3ae0 | ||
|
|
90c21d700d | ||
|
|
15b1f3234b | ||
|
|
a116345d60 | ||
|
|
2b4e6d372c | ||
|
|
d370f2c3ee | ||
|
|
ade09f3b1c | ||
|
|
80aa120086 | ||
|
|
a5cbcaca03 | ||
|
|
f2bfc26c5e | ||
|
|
9f0abb6f4d | ||
|
|
9ca2078e7d | ||
|
|
9e4a06999b | ||
|
|
8b72ff0a0d | ||
|
|
51ddaccc16 | ||
|
|
4ff1a4aec4 | ||
|
|
d5bd614cc6 | ||
|
|
0f498eca75 | ||
|
|
3dac9828c8 | ||
|
|
297c2bb30f | ||
|
|
b1dc4d4a41 | ||
|
|
0fe6565346 | ||
|
|
85c68c1f46 | ||
|
|
fc2191b8db | ||
|
|
ee36a0cfae | ||
|
|
a868a6cac1 | ||
|
|
574756b236 | ||
|
|
f9599079e5 | ||
|
|
10afffb71d | ||
|
|
79d53af339 | ||
|
|
8cc6a9cc63 | ||
|
|
18001fbdd0 | ||
|
|
398df75865 | ||
|
|
41c2983312 | ||
|
|
bd3b882b3a | ||
|
|
e52bc9c6b2 | ||
|
|
a16233ee10 | ||
|
|
5b177f1127 | ||
|
|
f7633b6a5f | ||
|
|
d58e6cb560 | ||
|
|
87fe9c1771 | ||
|
|
95d9e9edb9 | ||
|
|
f7b2c51f9d | ||
|
|
72c70e27f2 | ||
|
|
becbe5ab96 | ||
|
|
f5bce95808 | ||
|
|
1e2b807e05 | ||
|
|
ed3dbf2f14 | ||
|
|
1e35f83fed | ||
|
|
8499d100ff | ||
|
|
bdeae6a722 | ||
|
|
4c63b66dbf | ||
|
|
371f52f92e | ||
|
|
6daaf94974 | ||
|
|
b8e5a22648 | ||
|
|
e821edf01a | ||
|
|
188316df47 | ||
|
|
dd14ce8738 | ||
|
|
d8e4053ce4 | ||
|
|
f73b78f292 | ||
|
|
96ec1e0b08 | ||
|
|
1904d9d910 | ||
|
|
beb2851f4a | ||
|
|
645a0bc7fe | ||
|
|
ef73918098 | ||
|
|
06a23c70af | ||
|
|
323a6e17c7 | ||
|
|
0ca07c9698 | ||
|
|
fbb21d2885 | ||
|
|
b6741c8ff0 | ||
|
|
7fdca02af7 | ||
|
|
271100c25b | ||
|
|
cfecce6100 | ||
|
|
d71341df7a | ||
|
|
ac851f5a02 | ||
|
|
d2a8b7af48 | ||
|
|
4d7a86fbf7 | ||
|
|
87a3af3dbf | ||
|
|
79c76b9f50 | ||
|
|
d7742df802 | ||
|
|
736222e173 | ||
|
|
047ffb0b55 | ||
|
|
505d17cf57 | ||
|
|
71c2da160d | ||
|
|
3487b9e479 | ||
|
|
7cdf315d78 | ||
|
|
a1812a962c | ||
|
|
b97cab34b0 | ||
|
|
3426450b3c | ||
|
|
75804f4624 | ||
|
|
23f757e06f | ||
|
|
fabd704bab | ||
|
|
c16fbae963 | ||
|
|
348759b9ad | ||
|
|
d961aeb19b | ||
|
|
987a9c03b0 | ||
|
|
d17fb04983 | ||
|
|
b07918d751 | ||
|
|
f9a19fce91 | ||
|
|
1b71e80d52 | ||
|
|
9fac11cb77 | ||
|
|
a94fb108fa | ||
|
|
f51893b2d6 | ||
|
|
a4b32dcafd | ||
|
|
862f870303 | ||
|
|
869cfd34ab | ||
|
|
9e67b7c72e | ||
|
|
a5b7f10809 | ||
|
|
698665176c | ||
|
|
1bd65222e4 | ||
|
|
61a5a1a8b0 | ||
|
|
e51cdd7f7a | ||
|
|
a626222ff3 | ||
|
|
af68a45a3d | ||
|
|
7969df9344 | ||
|
|
67bc656325 | ||
|
|
b5baf0d606 | ||
|
|
32964e9045 | ||
|
|
27a667675a | ||
|
|
9a221f47bf | ||
|
|
8d2fbc5599 | ||
|
|
84ebe6587d | ||
|
|
89a71a18da | ||
|
|
05dd7a090b | ||
|
|
3a9bdd2c43 | ||
|
|
0292e9976e | ||
|
|
365de9512f | ||
|
|
e857023903 | ||
|
|
c058e1a452 | ||
|
|
7f42967b67 | ||
|
|
994961de54 | ||
|
|
049d20536c | ||
|
|
c9c8171a52 | ||
|
|
e7a6ac5a75 | ||
|
|
3a372107ba | ||
|
|
493374de65 | ||
|
|
c43fc929f7 | ||
|
|
895d5f2ebe | ||
|
|
cb4768e2cf | ||
|
|
6ca4bfb9ee | ||
|
|
1f7de03d90 | ||
|
|
861d287750 | ||
|
|
e2cc32fd0a | ||
|
|
762df25c45 | ||
|
|
0b114e7dc1 | ||
|
|
981876c43c | ||
|
|
7fe9c477e3 | ||
|
|
5b3a7f4e02 | ||
|
|
60e20c4023 | ||
|
|
9e1bb6c075 | ||
|
|
9c05d0d803 | ||
|
|
3d1393c0b3 | ||
|
|
9914fdb111 | ||
|
|
9b24c9f1b5 | ||
|
|
81b8c646d2 | ||
|
|
f734832e0f | ||
|
|
1bde11b30b | ||
|
|
9e80c3fe40 | ||
|
|
f272dd13ce | ||
|
|
9f26de89a4 | ||
|
|
e23964ebad | ||
|
|
d0584ac941 | ||
|
|
1410c41f48 | ||
|
|
5f524563cf | ||
|
|
3d181623c3 | ||
|
|
1919dbfd96 | ||
|
|
8e1615ac5f | ||
|
|
7966f07fdb | ||
|
|
ac8fe7012b | ||
|
|
51d89dae82 | ||
|
|
ef21ac0fe7 | ||
|
|
02697687cc | ||
|
|
fd2f7f27a6 | ||
|
|
21b1ef5e4b | ||
|
|
e452d3b5f6 | ||
|
|
1419882455 | ||
|
|
d79202ed87 | ||
|
|
aa05c947a9 | ||
|
|
eb69ea05fa | ||
|
|
244b0998f9 | ||
|
|
1f608b1c21 | ||
|
|
7d6df3843b | ||
|
|
dd4b94ba71 | ||
|
|
edb9397a47 | ||
|
|
66815a8487 | ||
|
|
5ee19bceb6 | ||
|
|
deba7d0279 | ||
|
|
38e93d33f1 | ||
|
|
f182f305fc | ||
|
|
03c675ed57 | ||
|
|
3916b2d4dc | ||
|
|
698a7a9bbc | ||
|
|
9954d1b6bf | ||
|
|
a98b981efe | ||
|
|
dd2ca62eaf | ||
|
|
dc2a42ad6d | ||
|
|
b5b25458db | ||
|
|
ac4bbceb2f | ||
|
|
4980bfab12 | ||
|
|
63e0d07d50 | ||
|
|
2b76520e3a | ||
|
|
6631b8a23b | ||
|
|
04d34017c1 | ||
|
|
6dcbcb452e | ||
|
|
7c74b3bb13 | ||
|
|
b76a9ee118 | ||
|
|
40da649b10 | ||
|
|
cd64d762e7 | ||
|
|
b91c52820a | ||
|
|
1204ffd306 | ||
|
|
978267dd14 | ||
|
|
f935fd94c6 | ||
|
|
fb2428e21b | ||
|
|
e36a126c01 | ||
|
|
b186978624 | ||
|
|
49773d7654 | ||
|
|
53c03751a1 | ||
|
|
9d2908449a | ||
|
|
caf92bcf6d | ||
|
|
cbef469e02 | ||
|
|
a6bfc1d76c | ||
|
|
0446a74de9 | ||
|
|
1a14079b39 | ||
|
|
d9c1919ddc | ||
|
|
f42ac0c5ba | ||
|
|
c073929895 | ||
|
|
02df7844a4 | ||
|
|
e43aba0111 | ||
|
|
ac7446ffe6 | ||
|
|
e45d3ca6ec | ||
|
|
603550a453 | ||
|
|
4463ef4a9a | ||
|
|
49b8dc0079 | ||
|
|
ab83c3a551 | ||
|
|
98c6093674 | ||
|
|
e1f51521bf | ||
|
|
e85bc98dcc | ||
|
|
4ba52baa5c | ||
|
|
a82077b4de | ||
|
|
b8f04f3d11 | ||
|
|
e91f65f833 | ||
|
|
575ab9be2d | ||
|
|
64071bb60f | ||
|
|
44621a1a61 | ||
|
|
c56043e1f9 | ||
|
|
e8e4cbfd41 | ||
|
|
4b2bbe0614 | ||
|
|
9adfa14e62 | ||
|
|
067f82b632 | ||
|
|
e24e7979be | ||
|
|
c7c2b6e6f2 | ||
|
|
96798963d6 | ||
|
|
75508a81ef | ||
|
|
f7f4efadb7 | ||
|
|
4cc80b98db | ||
|
|
b07efaa7d0 | ||
|
|
7ba8ea6dd4 | ||
|
|
479461821f | ||
|
|
d25aea38fb |
31
.env
31
.env
@@ -1,31 +0,0 @@
|
||||
APP_NAME=Heimdall
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:I206O8ibx+GQyRE7BeOxDobn04Mfmyyc5Ptzns/C0mY=
|
||||
APP_DEBUG=true
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_URL=http://localhost
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
DB_DATABASE=app.sqlite
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
QUEUE_DRIVER=sync
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
28
.env.example
28
.env.example
@@ -1,19 +1,17 @@
|
||||
APP_NAME=Laravel
|
||||
APP_NAME=Heimdall
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_DEBUG=false
|
||||
APP_URL=http://localhost
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=homestead
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
LOG_CHANNEL=daily
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
DB_DATABASE=app.sqlite
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
QUEUE_DRIVER=sync
|
||||
@@ -22,14 +20,24 @@ REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/app/SupportedApps
|
||||
/node_modules
|
||||
/public/hot
|
||||
/public/storage
|
||||
@@ -25,3 +26,4 @@ yarn-error.log
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
storage/app/public/avatars/*
|
||||
.env
|
||||
|
||||
14
SECURITY.md
Normal file
14
SECURITY.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 2.3.x | :white_check_mark: |
|
||||
| < 2.3 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
You can report any vulnerabilities on our discord server by DM-ing a team member, or asking a team member to DM you.
|
||||
|
||||
https://discord.com/invite/YWrKVTn
|
||||
@@ -13,6 +13,13 @@ class Application extends Model
|
||||
//
|
||||
public function icon()
|
||||
{
|
||||
if (! file_exists(storage_path('app/public/'.$this->icon))) {
|
||||
$img_src = app_path('SupportedApps/'.$this->name.'/'.str_replace('icons/', '', $this->icon));
|
||||
$img_dest = storage_path('app/public/'.$this->icon);
|
||||
//die("i: ".$img_src);
|
||||
@copy($img_src, $img_dest);
|
||||
}
|
||||
|
||||
return $this->icon;
|
||||
}
|
||||
|
||||
@@ -24,32 +31,119 @@ class Application extends Model
|
||||
public function defaultColour()
|
||||
{
|
||||
// check if light or dark
|
||||
if($this->tile_background == 'light') return '#fafbfc';
|
||||
if ($this->tile_background == 'light') {
|
||||
return '#fafbfc';
|
||||
}
|
||||
|
||||
return '#161b1f';
|
||||
}
|
||||
|
||||
public function class()
|
||||
{
|
||||
$name = $this->name;
|
||||
$name = preg_replace('/\PL/u', '', $name);
|
||||
$name = preg_replace('/[^\p{L}\p{N}]/u', '', $name);
|
||||
|
||||
$class = '\App\SupportedApps\\'.$name.'\\'.$name;
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
public static function classFromName($name)
|
||||
{
|
||||
$name = preg_replace('/[^\p{L}\p{N}]/u', '', $name);
|
||||
|
||||
$class = '\App\SupportedApps\\'.$name.'\\'.$name;
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
public static function apps()
|
||||
{
|
||||
$json = json_decode(file_get_contents(storage_path('app/supportedapps.json'))) ?? [];
|
||||
$apps = collect($json->apps);
|
||||
$sorted = $apps->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE);
|
||||
|
||||
return $sorted;
|
||||
}
|
||||
|
||||
public static function autocomplete()
|
||||
{
|
||||
$apps = self::apps();
|
||||
$list = [];
|
||||
foreach ($apps as $app) {
|
||||
$list[] = (object) [
|
||||
'label' => $app->name,
|
||||
'value' => $app->appid,
|
||||
];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function getApp($appid)
|
||||
{
|
||||
$localapp = self::where('appid', $appid)->first();
|
||||
$app = self::single($appid);
|
||||
|
||||
$application = ($localapp) ? $localapp : new self;
|
||||
|
||||
if (! file_exists(app_path('SupportedApps/'.className($app->name)))) {
|
||||
SupportedApps::getFiles($app);
|
||||
SupportedApps::saveApp($app, $application);
|
||||
} else {
|
||||
// check if there has been an update for this app
|
||||
if ($localapp) {
|
||||
if ($localapp->sha !== $app->sha) {
|
||||
SupportedApps::getFiles($app);
|
||||
$app = SupportedApps::saveApp($app, $application);
|
||||
}
|
||||
} else {
|
||||
SupportedApps::getFiles($app);
|
||||
$app = SupportedApps::saveApp($app, $application);
|
||||
}
|
||||
}
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
public static function single($appid)
|
||||
{
|
||||
$apps = self::apps();
|
||||
$app = $apps->where('appid', $appid)->first();
|
||||
|
||||
if ($app === null) {
|
||||
// Try in db for Private App
|
||||
$appModel = self::where('appid', $appid)->first();
|
||||
$app = json_decode($appModel->toJson());
|
||||
}
|
||||
|
||||
if ($app === null) {
|
||||
return null;
|
||||
}
|
||||
$classname = preg_replace('/[^\p{L}\p{N}]/u', '', $app->name);
|
||||
$app->class = '\App\SupportedApps\\'.$classname.'\\'.$classname;
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
public static function applist()
|
||||
{
|
||||
$list = [];
|
||||
$all = self::orderBy('name')->get();
|
||||
$list['null'] = 'None';
|
||||
foreach($all as $app) {
|
||||
$name = $app->name;
|
||||
$name = preg_replace('/\PL/u', '', $name);
|
||||
|
||||
$list['\App\SupportedApps\\'.$name.'\\'.$name] = $app->name;
|
||||
$apps = self::apps();
|
||||
foreach ($apps as $app) {
|
||||
$list[$app->appid] = $app->name;
|
||||
}
|
||||
|
||||
// Check for private apps in the db
|
||||
$appsListFromDB = self::all(['appid', 'name']);
|
||||
|
||||
foreach($appsListFromDB as $app) {
|
||||
// Already existing keys are overwritten,
|
||||
// only private apps should be added at the end
|
||||
$list[$app->appid] = $app->name;
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Application;
|
||||
use App\SupportedApps;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class RegisterApp extends Command
|
||||
{
|
||||
@@ -13,7 +14,7 @@ class RegisterApp extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'register:app {folder}';
|
||||
protected $signature = 'register:app {folder} {--remove}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@@ -40,22 +41,56 @@ class RegisterApp extends Command
|
||||
public function handle()
|
||||
{
|
||||
$folder = $this->argument('folder');
|
||||
$json = app_path('SupportedApps/'.$folder.'/app.json');
|
||||
if(file_exists($json)) {
|
||||
$app = json_decode(file_get_contents($json));
|
||||
$exists = Application::find($app->appid);
|
||||
if($exists) {
|
||||
$this->error('This app is already registered');
|
||||
exit;
|
||||
if ($folder == 'all') {
|
||||
$apps = scandir(app_path('SupportedApps'));
|
||||
foreach ($apps as $folder) {
|
||||
if ($folder == '.' || $folder == '..') {
|
||||
continue;
|
||||
}
|
||||
$this->addApp($folder);
|
||||
}
|
||||
// Doesn't exist so add it
|
||||
SupportedApps::saveApp($app, new Application);
|
||||
$this->info("Application Added - ".$app->name." - ".$app->appid);
|
||||
|
||||
} else {
|
||||
$this->error('Could not find '.$json);
|
||||
$this->addApp($folder, $this->option('remove'));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function addApp($folder, $remove = false)
|
||||
{
|
||||
$json = app_path('SupportedApps/'.$folder.'/app.json');
|
||||
|
||||
if (!file_exists($json)) {
|
||||
$this->error('Could not find ' . $json);
|
||||
return;
|
||||
}
|
||||
|
||||
$app = json_decode(file_get_contents($json));
|
||||
|
||||
if (!isset($app->appid)) {
|
||||
$this->error('No App ID for - ' . $folder);
|
||||
return;
|
||||
}
|
||||
|
||||
$exists = Application::find($app->appid);
|
||||
|
||||
if ($exists) {
|
||||
if ($remove) {
|
||||
$exists->delete();
|
||||
$this->info('Application Removed - ' . $app->name . ' - ' . $app->appid);
|
||||
return;
|
||||
}
|
||||
$this->error('Application already registered - ' . $exists->name . ' - ' . $exists->appid);
|
||||
return;
|
||||
}
|
||||
|
||||
// Doesn't exist so add it
|
||||
SupportedApps::saveApp($app, new Application);
|
||||
$this->saveIcon($folder, $app->icon);
|
||||
$this->info('Application Added - ' . $app->name . ' - ' . $app->appid);
|
||||
}
|
||||
|
||||
private function saveIcon($appFolder, $icon) {
|
||||
$iconPath = app_path('SupportedApps/' . $appFolder . '/' . $icon);
|
||||
$contents = file_get_contents($iconPath);
|
||||
Storage::disk('public')->put('icons/'.$icon, $contents);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
<?php namespace App;
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
interface EnhancedApps
|
||||
{
|
||||
public function test();
|
||||
public function livestats();
|
||||
public function url($endpoint);
|
||||
|
||||
}
|
||||
public function livestats();
|
||||
|
||||
public function url($endpoint);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Throwable;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
@@ -22,32 +22,20 @@ class Handler extends ExceptionHandler
|
||||
* @var array
|
||||
*/
|
||||
protected $dontFlash = [
|
||||
'current_password',
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
|
||||
/**
|
||||
* Report or log an exception.
|
||||
* Register the exception handling callbacks for the application.
|
||||
*
|
||||
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Exception $exception)
|
||||
public function register()
|
||||
{
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Exception $exception
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function render($request, Exception $exception)
|
||||
{
|
||||
return parent::render($request, $exception);
|
||||
$this->reportable(function (Throwable $e) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,84 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
function format_bytes($bytes, $is_drive_size = true, $beforeunit = '', $afterunit = '')
|
||||
{
|
||||
$btype = ($is_drive_size === true) ? 1000 : 1024;
|
||||
$labels = array('B','KB','MB','GB','TB');
|
||||
for($x = 0; $bytes >= $btype && $x < (count($labels) - 1); $bytes /= $btype, $x++); // use 1000 rather than 1024 to simulate HD size not real size
|
||||
if($labels[$x] == "TB") return(round($bytes, 3).$beforeunit.$labels[$x].$afterunit);
|
||||
elseif($labels[$x] == "GB") return(round($bytes, 2).$beforeunit.$labels[$x].$afterunit);
|
||||
elseif($labels[$x] == "MB") return(round($bytes, 2).$beforeunit.$labels[$x].$afterunit);
|
||||
else return(round($bytes, 0).$beforeunit.$labels[$x].$afterunit);
|
||||
$btype = ($is_drive_size === true) ? 1000 : 1024;
|
||||
$labels = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
for ($x = 0; $bytes >= $btype && $x < (count($labels) - 1); $bytes /= $btype, $x++); // use 1000 rather than 1024 to simulate HD size not real size
|
||||
if ($labels[$x] == 'TB') {
|
||||
return round($bytes, 3).$beforeunit.$labels[$x].$afterunit;
|
||||
} elseif ($labels[$x] == 'GB') {
|
||||
return round($bytes, 2).$beforeunit.$labels[$x].$afterunit;
|
||||
} elseif ($labels[$x] == 'MB') {
|
||||
return round($bytes, 2).$beforeunit.$labels[$x].$afterunit;
|
||||
} else {
|
||||
return round($bytes, 0).$beforeunit.$labels[$x].$afterunit;
|
||||
}
|
||||
}
|
||||
|
||||
function get_brightness($hex) {
|
||||
function str_slug($title, $separator = '-', $language = 'en')
|
||||
{
|
||||
return Str::slug($title, $separator, $language);
|
||||
}
|
||||
|
||||
if (! function_exists('str_is')) {
|
||||
/**
|
||||
* Determine if a given string matches a given pattern.
|
||||
*
|
||||
* @param string|array $pattern
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*
|
||||
* @deprecated Str::is() should be used directly instead. Will be removed in Laravel 6.0.
|
||||
*/
|
||||
function str_is($pattern, $value)
|
||||
{
|
||||
return Str::is($pattern, $value);
|
||||
}
|
||||
}
|
||||
|
||||
function get_brightness($hex)
|
||||
{
|
||||
// returns brightness value from 0 to 255
|
||||
// strip off any leading #
|
||||
$hex = str_replace('#', '', $hex);
|
||||
if(strlen($hex) == 3) {
|
||||
// $hex = str_replace('#', '', $hex);
|
||||
$hex = preg_replace("/[^0-9A-Fa-f]/", '', $hex);
|
||||
if (strlen($hex) == 3) {
|
||||
$hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
|
||||
}
|
||||
|
||||
|
||||
$c_r = hexdec(substr($hex, 0, 2));
|
||||
$c_g = hexdec(substr($hex, 2, 2));
|
||||
$c_b = hexdec(substr($hex, 4, 2));
|
||||
|
||||
|
||||
return (($c_r * 299) + ($c_g * 587) + ($c_b * 114)) / 1000;
|
||||
}
|
||||
|
||||
function title_color($hex)
|
||||
{
|
||||
if(get_brightness($hex) > 130) {
|
||||
if (get_brightness($hex) > 130) {
|
||||
return ' black';
|
||||
} else {
|
||||
return ' white';
|
||||
}
|
||||
}
|
||||
|
||||
function getLinkTargetAttribute()
|
||||
{
|
||||
$target = \App\Setting::fetch('window_target');
|
||||
|
||||
if ($target === 'current') {
|
||||
return '';
|
||||
} else {
|
||||
return ' target="'.$target.'"';
|
||||
}
|
||||
}
|
||||
|
||||
function className($name)
|
||||
{
|
||||
$name = preg_replace('/\PL/u', '', $name);
|
||||
$name = preg_replace('/[^\p{L}\p{N}]/u', '', $name);
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use App\User;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
@@ -59,7 +59,7 @@ class LoginController extends Controller
|
||||
public function login(Request $request)
|
||||
{
|
||||
$current_user = User::currentUser();
|
||||
$request->merge(['username' => $current_user->username]);
|
||||
$request->merge(['username' => $current_user->username, 'remember' => true]);
|
||||
//die(print_r($request->all()));
|
||||
$this->validateLogin($request);
|
||||
|
||||
@@ -92,14 +92,16 @@ class LoginController extends Controller
|
||||
{
|
||||
Auth::logout();
|
||||
session(['current_user' => $user]);
|
||||
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
|
||||
public function autologin($uuid)
|
||||
{
|
||||
$user = User::where('autologin', $uuid)->first();
|
||||
Auth::login($user);
|
||||
Auth::login($user, true);
|
||||
session(['current_user' => $user]);
|
||||
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
|
||||
@@ -122,5 +124,4 @@ class LoginController extends Controller
|
||||
{
|
||||
return Session::get('url.intended') ? Session::get('url.intended') : $this->redirectTo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\User;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\User;
|
||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\User;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
@@ -22,7 +22,6 @@ class Controller extends BaseController
|
||||
//print_r($this->user);
|
||||
return $next($request);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public function user()
|
||||
|
||||
@@ -2,16 +2,22 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Artisan;
|
||||
use App\Application;
|
||||
use App\Item;
|
||||
use App\Setting;
|
||||
use App\User;
|
||||
use GrahamCampbell\GitHub\Facades\GitHub;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\SupportedApps;
|
||||
use App\Jobs\ProcessApps;
|
||||
use App\Search;
|
||||
use App\Setting;
|
||||
use App\SupportedApps;
|
||||
use App\User;
|
||||
use Artisan;
|
||||
use GrahamCampbell\GitHub\Facades\GitHub;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
class ItemController extends Controller
|
||||
{
|
||||
@@ -19,19 +25,28 @@ class ItemController extends Controller
|
||||
{
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
/**
|
||||
|
||||
/**
|
||||
* Display a listing of the resource on the dashboard.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function dash()
|
||||
{
|
||||
$data['apps'] = Item::doesntHave('parents')->pinned()->orderBy('order', 'asc')->get();
|
||||
$data['all_apps'] = Item::doesntHave('parents')->get();
|
||||
$data['apps'] = Item::whereHas('parents', function ($query) {
|
||||
$query->where('id', 0);
|
||||
})->orWhere('type', 1)->pinned()->orderBy('order', 'asc')->get();
|
||||
|
||||
$data['all_apps'] = Item::whereHas('parents', function ($query) {
|
||||
$query->where('id', 0);
|
||||
})->orWhere('type', 1)->orderBy('order', 'asc')->get();
|
||||
|
||||
//$data['all_apps'] = Item::doesntHave('parents')->get();
|
||||
//die(print_r($data['apps']));
|
||||
return view('welcome', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Set order on the dashboard.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
@@ -39,7 +54,7 @@ class ItemController extends Controller
|
||||
public function setOrder(Request $request)
|
||||
{
|
||||
$order = array_filter($request->input('order'));
|
||||
foreach($order as $o => $id) {
|
||||
foreach ($order as $o => $id) {
|
||||
$item = Item::find($id);
|
||||
$item->order = $o;
|
||||
$item->save();
|
||||
@@ -56,11 +71,12 @@ class ItemController extends Controller
|
||||
$item = Item::findOrFail($id);
|
||||
$item->pinned = true;
|
||||
$item->save();
|
||||
$route = route('dash', [], false);
|
||||
$route = route('dash', []);
|
||||
|
||||
return redirect($route);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Unpin item on the dashboard.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
@@ -70,32 +86,39 @@ class ItemController extends Controller
|
||||
$item = Item::findOrFail($id);
|
||||
$item->pinned = false;
|
||||
$item->save();
|
||||
$route = route('dash', [], false);
|
||||
$route = route('dash', []);
|
||||
|
||||
return redirect($route);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Unpin item on the dashboard.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function pinToggle($id, $ajax=false)
|
||||
public function pinToggle($id, $ajax = false, $tag = false)
|
||||
{
|
||||
$item = Item::findOrFail($id);
|
||||
$new = ((bool)$item->pinned === true) ? false : true;
|
||||
$new = ((bool) $item->pinned === true) ? false : true;
|
||||
$item->pinned = $new;
|
||||
$item->save();
|
||||
if($ajax) {
|
||||
$data['apps'] = Item::pinned()->get();
|
||||
if ($ajax) {
|
||||
if (is_numeric($tag) && $tag > 0) {
|
||||
$item = Item::whereId($tag)->first();
|
||||
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
|
||||
} else {
|
||||
$data['apps'] = Item::pinned()->orderBy('order', 'asc')->get();
|
||||
}
|
||||
$data['ajax'] = true;
|
||||
|
||||
return view('sortable', $data);
|
||||
} else {
|
||||
$route = route('dash', [], false);
|
||||
$route = route('dash', []);
|
||||
|
||||
return redirect($route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
@@ -103,18 +126,17 @@ class ItemController extends Controller
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$trash = (bool)$request->input('trash');
|
||||
$trash = (bool) $request->input('trash');
|
||||
|
||||
$data['apps'] = Item::ofType('item')->orderBy('title', 'asc')->get();
|
||||
$data['trash'] = Item::ofType('item')->onlyTrashed()->get();
|
||||
if($trash) {
|
||||
if ($trash) {
|
||||
return view('items.trash', $data);
|
||||
} else {
|
||||
return view('items.list', $data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
@@ -124,9 +146,105 @@ class ItemController extends Controller
|
||||
{
|
||||
//
|
||||
$data['tags'] = Item::ofType('tag')->orderBy('title', 'asc')->pluck('title', 'id');
|
||||
$data['current_tags'] = [];
|
||||
return view('items.create', $data);
|
||||
$data['tags']->prepend(__('app.dashboard'), 0);
|
||||
$data['current_tags'] = '0';
|
||||
|
||||
return view('items.create', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
// Get the item
|
||||
$item = Item::find($id);
|
||||
if ($item->appid === null && $item->class !== null) { // old apps wont have an app id so set it
|
||||
$app = Application::where('class', $item->class)->first();
|
||||
if ($app) {
|
||||
$item->appid = $app->appid;
|
||||
}
|
||||
}
|
||||
$data['item'] = $item;
|
||||
$data['tags'] = Item::ofType('tag')->orderBy('title', 'asc')->pluck('title', 'id');
|
||||
$data['tags']->prepend(__('app.dashboard'), 0);
|
||||
$data['current_tags'] = $data['item']->tags();
|
||||
//$data['current_tags'] = $data['item']->parent;
|
||||
//die(print_r($data['current_tags']));
|
||||
// show the edit form and pass the nerd
|
||||
return view('items.edit', $data);
|
||||
}
|
||||
|
||||
public function storelogic($request, $id = null)
|
||||
{
|
||||
$application = Application::single($request->input('appid'));
|
||||
$validatedData = $request->validate([
|
||||
'title' => 'required|max:255',
|
||||
'url' => 'required',
|
||||
]);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path,
|
||||
]);
|
||||
} elseif (strpos($request->input('icon'), 'http') === 0) {
|
||||
$options=array(
|
||||
"ssl"=>array(
|
||||
"verify_peer"=>false,
|
||||
"verify_peer_name"=>false,
|
||||
),
|
||||
);
|
||||
$contents = file_get_contents($request->input('icon'), false, stream_context_create($options));
|
||||
|
||||
if ($application) {
|
||||
$icon = $application->icon;
|
||||
} else {
|
||||
$file = $request->input('icon');
|
||||
$path_parts = pathinfo($file);
|
||||
$icon = md5($contents);
|
||||
$icon .= '.'.$path_parts['extension'];
|
||||
}
|
||||
$path = 'icons/'.$icon;
|
||||
|
||||
// Private apps could have here duplicated icons folder
|
||||
if (strpos($path, 'icons/icons/') !== false) {
|
||||
$path = str_replace('icons/icons/','icons/',$path);
|
||||
}
|
||||
Storage::disk('public')->put($path, $contents);
|
||||
$request->merge([
|
||||
'icon' => $path,
|
||||
]);
|
||||
}
|
||||
|
||||
$config = Item::checkConfig($request->input('config'));
|
||||
$current_user = User::currentUser();
|
||||
$request->merge([
|
||||
'description' => $config,
|
||||
'user_id' => $current_user->id,
|
||||
]);
|
||||
|
||||
if ($request->input('appid') === 'null') {
|
||||
$request->merge([
|
||||
'class' => null,
|
||||
]);
|
||||
} else {
|
||||
$request->merge([
|
||||
'class' => Application::classFromName($application->name),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($id === null) {
|
||||
$item = Item::create($request->all());
|
||||
} else {
|
||||
$item = Item::find($id);
|
||||
$item->update($request->all());
|
||||
}
|
||||
|
||||
$item->parents()->sync($request->tags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,40 +255,10 @@ class ItemController extends Controller
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
$validatedData = $request->validate([
|
||||
'title' => 'required|max:255',
|
||||
'url' => 'required|url',
|
||||
]);
|
||||
$this->storelogic($request);
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
]);
|
||||
}
|
||||
$route = route('dash', []);
|
||||
|
||||
$config = Item::checkConfig($request->input('config'));
|
||||
$current_user = User::currentUser();
|
||||
$request->merge([
|
||||
'description' => $config,
|
||||
'user_id' => $current_user->id
|
||||
]);
|
||||
|
||||
if($request->input('class') === 'null') {
|
||||
$request->merge([
|
||||
'class' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
//die(print_r($request->input('config')));
|
||||
|
||||
$item = Item::create($request->all());
|
||||
|
||||
$item->parents()->sync($request->tags);
|
||||
|
||||
$route = route('dash', [], false);
|
||||
return redirect($route)
|
||||
->with('success', __('app.alert.success.item_created'));
|
||||
}
|
||||
@@ -186,23 +274,6 @@ class ItemController extends Controller
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
// Get the item
|
||||
$data['item'] = Item::find($id);
|
||||
$data['tags'] = Item::ofType('tag')->orderBy('title', 'asc')->pluck('title', 'id');
|
||||
$data['current_tags'] = $data['item']->parents;
|
||||
|
||||
// show the edit form and pass the nerd
|
||||
return view('items.edit', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
@@ -212,40 +283,11 @@ class ItemController extends Controller
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'title' => 'required|max:255',
|
||||
'url' => 'required|url',
|
||||
]);
|
||||
//die(print_r($request->all()));
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
]);
|
||||
}
|
||||
|
||||
$config = Item::checkConfig($request->input('config'));
|
||||
$current_user = User::currentUser();
|
||||
$request->merge([
|
||||
'description' => $config,
|
||||
'user_id' => $current_user->id
|
||||
]);
|
||||
$this->storelogic($request, $id);
|
||||
$route = route('dash', []);
|
||||
|
||||
if($request->input('class') === 'null') {
|
||||
$request->merge([
|
||||
'class' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
$item = Item::find($id);
|
||||
$item->update($request->all());
|
||||
|
||||
$item->parents()->sync($request->tags);
|
||||
|
||||
$route = route('dash', [], false);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_updated'));
|
||||
->with('success', __('app.alert.success.item_updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,8 +299,8 @@ class ItemController extends Controller
|
||||
public function destroy(Request $request, $id)
|
||||
{
|
||||
//
|
||||
$force = (bool)$request->input('force');
|
||||
if($force) {
|
||||
$force = (bool) $request->input('force');
|
||||
if ($force) {
|
||||
Item::withTrashed()
|
||||
->where('id', $id)
|
||||
->forceDelete();
|
||||
@@ -266,9 +308,10 @@ class ItemController extends Controller
|
||||
Item::find($id)->delete();
|
||||
}
|
||||
|
||||
$route = route('items.index', [], false);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_deleted'));
|
||||
$route = route('items.index', []);
|
||||
|
||||
return redirect($route)
|
||||
->with('success', __('app.alert.success.item_deleted'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,11 +325,12 @@ class ItemController extends Controller
|
||||
//
|
||||
Item::withTrashed()
|
||||
->where('id', $id)
|
||||
->restore();
|
||||
|
||||
$route = route('items.inded', [], false);
|
||||
->restore();
|
||||
|
||||
$route = route('items.index', []);
|
||||
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_restored'));
|
||||
->with('success', __('app.alert.success.item_restored'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,7 +341,12 @@ class ItemController extends Controller
|
||||
public function appload(Request $request)
|
||||
{
|
||||
$output = [];
|
||||
$appname = $request->input('app');
|
||||
$appid = $request->input('app');
|
||||
|
||||
if ($appid === 'null') {
|
||||
return null;
|
||||
}
|
||||
/*$appname = $request->input('app');
|
||||
//die($appname);
|
||||
|
||||
$app_details = Application::where('name', $appname)->firstOrFail();
|
||||
@@ -316,8 +365,35 @@ class ItemController extends Controller
|
||||
$output['config'] = className($app_details->name).'.config';
|
||||
} else {
|
||||
$output['config'] = null;
|
||||
}*/
|
||||
|
||||
$output['config'] = null;
|
||||
$output['custom'] = null;
|
||||
|
||||
$app = Application::single($appid);
|
||||
$output = (array) $app;
|
||||
|
||||
$appdetails = Application::getApp($appid);
|
||||
|
||||
if ((bool) $app->enhanced === true) {
|
||||
// if(!isset($app->config)) { // class based config
|
||||
$output['custom'] = className($appdetails->name).'.config';
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
$output['colour'] = ($app->tile_background == 'light') ? '#fafbfc' : '#161b1f';
|
||||
|
||||
if(strpos($app->icon, '://') !== false) {
|
||||
$output['iconview'] = $app->icon;
|
||||
} elseif(strpos($app->icon, 'icons/') !== false) {
|
||||
// Private apps have the icon locally
|
||||
$output['iconview'] = URL::to('/').'/storage/'.$app->icon;
|
||||
$output['icon'] = str_replace('icons/', '', $output['icon']);
|
||||
} else {
|
||||
$output['iconview'] = config('app.appsource').'icons/'.$app->icon;
|
||||
}
|
||||
|
||||
|
||||
return json_encode($output);
|
||||
}
|
||||
|
||||
@@ -325,39 +401,68 @@ class ItemController extends Controller
|
||||
{
|
||||
$data = $request->input('data');
|
||||
//$url = $data[array_search('url', array_column($data, 'name'))]['value'];
|
||||
|
||||
$app = $data['type'];
|
||||
$single = Application::single($data['type']);
|
||||
$app = $single->class;
|
||||
|
||||
$app_details = new $app();
|
||||
$app_details->config = (object)$data;
|
||||
$app_details->config = (object) $data;
|
||||
$app_details->test();
|
||||
}
|
||||
|
||||
public function execute($url, $attrs = [], $overridevars = false)
|
||||
{
|
||||
$res = null;
|
||||
|
||||
$vars = ($overridevars !== false) ?
|
||||
$overridevars : [
|
||||
'http_errors' => false,
|
||||
'timeout' => 15,
|
||||
'connect_timeout' => 15,
|
||||
'verify' => false,
|
||||
];
|
||||
|
||||
$client = new Client($vars);
|
||||
|
||||
$method = 'GET';
|
||||
|
||||
try {
|
||||
return $client->request($method, $url, $attrs);
|
||||
} catch (\GuzzleHttp\Exception\ConnectException $e) {
|
||||
Log::error('Connection refused');
|
||||
Log::debug($e->getMessage());
|
||||
} catch (\GuzzleHttp\Exception\ServerException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function websitelookup($url)
|
||||
{
|
||||
$url = \base64_decode($url);
|
||||
$data = $this->execute($url);
|
||||
|
||||
return $data->getBody();
|
||||
}
|
||||
|
||||
public function getStats($id)
|
||||
{
|
||||
$item = Item::find($id);
|
||||
|
||||
$config = $item->getconfig();
|
||||
if(isset($item->class)) {
|
||||
if (isset($item->class)) {
|
||||
$application = new $item->class;
|
||||
$application->config = $config;
|
||||
echo $application->livestats();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function checkAppList()
|
||||
{
|
||||
ProcessApps::dispatch();
|
||||
$route = route('items.index');
|
||||
|
||||
return redirect($route)
|
||||
->with('success', __('app.alert.success.updating'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
28
app/Http/Controllers/SearchController.php
Normal file
28
app/Http/Controllers/SearchController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Search;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$requestprovider = $request->input('provider');
|
||||
$query = $request->input('q');
|
||||
|
||||
$provider = Search::providerDetails($requestprovider);
|
||||
|
||||
if ($provider->type == 'standard') {
|
||||
return redirect($provider->url.'?'.$provider->query.'='.urlencode($query));
|
||||
} elseif ($provider->type == 'external') {
|
||||
$class = new $provider->class;
|
||||
//print_r($provider);
|
||||
return $class->getResults($query, $provider);
|
||||
}
|
||||
|
||||
//print_r($provider);
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Setting;
|
||||
use App\SettingGroup;
|
||||
use App\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
@@ -40,15 +40,18 @@ class SettingsController extends Controller
|
||||
$setting = Setting::find($id);
|
||||
//die("s: ".$setting->label);
|
||||
|
||||
if((bool)$setting->system === true) return abort(404);
|
||||
if ((bool) $setting->system === true) {
|
||||
return abort(404);
|
||||
}
|
||||
|
||||
if (!is_null($setting)) {
|
||||
if (! is_null($setting)) {
|
||||
return view('settings.edit')->with([
|
||||
'setting' => $setting,
|
||||
]);
|
||||
} else {
|
||||
$route = route('settings.list', [], false);
|
||||
return redirect($route)
|
||||
$route = route('settings.list', []);
|
||||
|
||||
return redirect($route)
|
||||
->with([
|
||||
'error' => __('app.alert.error.not_exist'),
|
||||
]);
|
||||
@@ -65,37 +68,39 @@ class SettingsController extends Controller
|
||||
$setting = Setting::find($id);
|
||||
$user = $this->user();
|
||||
|
||||
if (!is_null($setting)) {
|
||||
$data = Setting::getInput();
|
||||
if (! is_null($setting)) {
|
||||
$data = Setting::getInput($request);
|
||||
|
||||
$setting_value = null;
|
||||
|
||||
if ($setting->type == 'image') {
|
||||
|
||||
|
||||
if($request->hasFile('value')) {
|
||||
if ($request->hasFile('value')) {
|
||||
$path = $request->file('value')->store('backgrounds');
|
||||
$setting_value = $path;
|
||||
}
|
||||
|
||||
} else {
|
||||
$setting_value = $data->value;
|
||||
}
|
||||
|
||||
$user->settings()->detach($setting->id);
|
||||
$user->settings()->save($setting, ['uservalue' => $setting_value]);
|
||||
|
||||
$route = route('settings.index', [], false);
|
||||
return redirect($route)
|
||||
|
||||
$route = route('settings.index', []);
|
||||
|
||||
return redirect($route)
|
||||
->with([
|
||||
'success' => __('app.alert.success.setting_updated'),
|
||||
]);
|
||||
} else {
|
||||
$route = route('settings.index', [], false);
|
||||
return redirect($route)
|
||||
$route = route('settings.index', []);
|
||||
|
||||
return redirect($route)
|
||||
->with([
|
||||
'error' => __('app.alert.error.not_exist'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
@@ -105,15 +110,19 @@ class SettingsController extends Controller
|
||||
{
|
||||
$user = $this->user();
|
||||
$setting = Setting::find($id);
|
||||
if((bool)$setting->system !== true) {
|
||||
if ((bool) $setting->system !== true) {
|
||||
$user->settings()->detach($setting->id);
|
||||
$user->settings()->save($setting, ['uservalue' => '']);
|
||||
}
|
||||
$route = route('settings.index', [], false);
|
||||
return redirect($route)
|
||||
$route = route('settings.index', []);
|
||||
|
||||
return redirect($route)
|
||||
->with([
|
||||
'success' => __('app.alert.success.setting_updated'),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function search(Request $request)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Item;
|
||||
use App\User;
|
||||
use DB;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
@@ -13,6 +13,7 @@ class TagController extends Controller
|
||||
{
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
@@ -20,11 +21,11 @@ class TagController extends Controller
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$trash = (bool)$request->input('trash');
|
||||
$trash = (bool) $request->input('trash');
|
||||
|
||||
$data['apps'] = Item::ofType('tag')->orderBy('title', 'asc')->get();
|
||||
$data['trash'] = Item::ofType('tag')->onlyTrashed()->get();
|
||||
if($trash) {
|
||||
$data['apps'] = Item::ofType('tag')->where('id', '>', 0)->orderBy('title', 'asc')->get();
|
||||
$data['trash'] = Item::ofType('tag')->where('id', '>', 0)->onlyTrashed()->get();
|
||||
if ($trash) {
|
||||
return view('tags.trash', $data);
|
||||
} else {
|
||||
return view('tags.list', $data);
|
||||
@@ -39,6 +40,7 @@ class TagController extends Controller
|
||||
public function create()
|
||||
{
|
||||
$data = [];
|
||||
|
||||
return view('tags.create', $data);
|
||||
}
|
||||
|
||||
@@ -54,10 +56,10 @@ class TagController extends Controller
|
||||
'title' => 'required|max:255',
|
||||
]);
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
if ($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
'icon' => $path,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -69,12 +71,13 @@ class TagController extends Controller
|
||||
$request->merge([
|
||||
'type' => '1',
|
||||
'url' => $slug,
|
||||
'user_id' => $current_user->id
|
||||
'user_id' => $current_user->id,
|
||||
]);
|
||||
//die(print_r($request->all()));
|
||||
Item::create($request->all());
|
||||
|
||||
$route = route('dash', [], false);
|
||||
$route = route('dash', []);
|
||||
|
||||
return redirect($route)
|
||||
->with('success', __('app.alert.success.tag_created'));
|
||||
}
|
||||
@@ -90,7 +93,9 @@ class TagController extends Controller
|
||||
$item = Item::whereUrl($slug)->first();
|
||||
//print_r($item);
|
||||
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
|
||||
$data['tag'] = $item->id;
|
||||
$data['all_apps'] = $item->children;
|
||||
|
||||
return view('welcome', $data);
|
||||
}
|
||||
|
||||
@@ -107,7 +112,7 @@ class TagController extends Controller
|
||||
|
||||
// show the edit form and pass the nerd
|
||||
return view('tags.edit')
|
||||
->with('item', $item);
|
||||
->with('item', $item);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,24 +128,25 @@ class TagController extends Controller
|
||||
'title' => 'required|max:255',
|
||||
]);
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
if ($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
'icon' => $path,
|
||||
]);
|
||||
}
|
||||
|
||||
$slug = str_slug($request->title, '-');
|
||||
// set item type to tag
|
||||
$request->merge([
|
||||
'url' => $slug
|
||||
'url' => $slug,
|
||||
]);
|
||||
|
||||
Item::find($id)->update($request->all());
|
||||
|
||||
$route = route('dash', [], false);
|
||||
$route = route('dash', []);
|
||||
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.tag_updated'));
|
||||
->with('success', __('app.alert.success.tag_updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,18 +158,19 @@ class TagController extends Controller
|
||||
public function destroy(Request $request, $id)
|
||||
{
|
||||
//
|
||||
$force = (bool)$request->input('force');
|
||||
if($force) {
|
||||
$force = (bool) $request->input('force');
|
||||
if ($force) {
|
||||
Item::withTrashed()
|
||||
->where('id', $id)
|
||||
->forceDelete();
|
||||
} else {
|
||||
Item::find($id)->delete();
|
||||
}
|
||||
|
||||
$route = route('tags.index', [], false);
|
||||
|
||||
$route = route('tags.index', []);
|
||||
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_deleted'));
|
||||
->with('success', __('app.alert.success.item_deleted'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,10 +184,11 @@ class TagController extends Controller
|
||||
//
|
||||
Item::withTrashed()
|
||||
->where('id', $id)
|
||||
->restore();
|
||||
$route = route('tags.index', [], false);
|
||||
->restore();
|
||||
$route = route('tags.index', []);
|
||||
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_restored'));
|
||||
->with('success', __('app.alert.success.item_restored'));
|
||||
}
|
||||
|
||||
public function add($tag, $item)
|
||||
@@ -188,14 +196,15 @@ class TagController extends Controller
|
||||
$output = 0;
|
||||
$tag = Item::find($tag);
|
||||
$item = Item::find($item);
|
||||
if($tag && $item) {
|
||||
if ($tag && $item) {
|
||||
// only add items, not cats
|
||||
if((int)$item->type === 0) {
|
||||
if ((int) $item->type === 0) {
|
||||
$tag->children()->attach($item);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
@@ -14,6 +14,7 @@ class UserController extends Controller
|
||||
{
|
||||
$this->middleware('allowed')->except(['selectUser']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
@@ -22,6 +23,7 @@ class UserController extends Controller
|
||||
public function index()
|
||||
{
|
||||
$data['users'] = User::all();
|
||||
|
||||
return view('users.index', $data);
|
||||
}
|
||||
|
||||
@@ -33,6 +35,7 @@ class UserController extends Controller
|
||||
public function create()
|
||||
{
|
||||
$data = [];
|
||||
|
||||
return view('users.create', $data);
|
||||
}
|
||||
|
||||
@@ -40,8 +43,8 @@ class UserController extends Controller
|
||||
{
|
||||
Auth::logout();
|
||||
$data['users'] = User::all();
|
||||
return view('userselect', $data);
|
||||
|
||||
return view('userselect', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +59,7 @@ class UserController extends Controller
|
||||
'username' => 'required|max:255|unique:users',
|
||||
'email' => 'required|email',
|
||||
'password' => 'nullable|confirmed',
|
||||
'password_confirmation' => 'nullable'
|
||||
'password_confirmation' => 'nullable',
|
||||
|
||||
]);
|
||||
$user = new User;
|
||||
@@ -65,24 +68,25 @@ class UserController extends Controller
|
||||
$user->public_front = $request->input('public_front');
|
||||
|
||||
$password = $request->input('password');
|
||||
if(!empty($password)) {
|
||||
if (! empty($password)) {
|
||||
$user->password = bcrypt($password);
|
||||
}
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
if ($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('avatars');
|
||||
$user->avatar = $path;
|
||||
}
|
||||
|
||||
if ((bool)$request->input('autologin_allow') === true) {
|
||||
$user->autologin = (string)Str::uuid();
|
||||
if ((bool) $request->input('autologin_allow') === true) {
|
||||
$user->autologin = (string) Str::uuid();
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
$route = route('dash', [], false);
|
||||
|
||||
$route = route('dash', []);
|
||||
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.user_updated'));
|
||||
->with('success', __('app.alert.success.user_updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,8 +109,8 @@ class UserController extends Controller
|
||||
public function edit(User $user)
|
||||
{
|
||||
$data['user'] = $user;
|
||||
return view('users.edit', $data);
|
||||
|
||||
return view('users.edit', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,38 +126,38 @@ class UserController extends Controller
|
||||
'username' => 'required|max:255|unique:users,username,'.$user->id,
|
||||
'email' => 'required|email',
|
||||
'password' => 'nullable|confirmed',
|
||||
'password_confirmation' => 'nullable'
|
||||
'password_confirmation' => 'nullable',
|
||||
]);
|
||||
//die(print_r($request->all()));
|
||||
//die(print_r($request->all()));
|
||||
|
||||
$user->username = $request->input('username');
|
||||
$user->email = $request->input('email');
|
||||
$user->public_front = $request->input('public_front');
|
||||
|
||||
$password = $request->input('password');
|
||||
if(!empty($password)) {
|
||||
if (! empty($password)) {
|
||||
$user->password = bcrypt($password);
|
||||
} elseif($password == 'null') {
|
||||
} elseif ($password == 'null') {
|
||||
$user->password = null;
|
||||
}
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('avatars');
|
||||
$user->avatar = $path;
|
||||
}
|
||||
|
||||
if ((bool)$request->input('autologin_allow') === true) {
|
||||
$user->autologin = (is_null($user->autologin)) ? (string)Str::uuid() : $user->autologin;
|
||||
if ((bool) $request->input('autologin_allow') === true) {
|
||||
$user->autologin = (is_null($user->autologin)) ? (string) Str::uuid() : $user->autologin;
|
||||
} else {
|
||||
$user->autologin = null;
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
$route = route('dash', [], false);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.user_updated'));
|
||||
$route = route('dash', []);
|
||||
|
||||
return redirect($route)
|
||||
->with('success', __('app.alert.success.user_updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,12 +168,12 @@ class UserController extends Controller
|
||||
*/
|
||||
public function destroy(User $user)
|
||||
{
|
||||
if($user->id !== 1) {
|
||||
if ($user->id !== 1) {
|
||||
$user->delete();
|
||||
$route = route('dash', [], false);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.user_deleted'));
|
||||
$route = route('dash', []);
|
||||
|
||||
return redirect($route)
|
||||
->with('success', __('app.alert.success.user_deleted'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\User;
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Session;
|
||||
|
||||
@@ -22,27 +22,32 @@ class CheckAllowed
|
||||
$route = Route::currentRouteName();
|
||||
$current_user = User::currentUser();
|
||||
|
||||
if(str_is('users*', $route)) {
|
||||
if($current_user->id !== 1) {
|
||||
if (str_is('users*', $route)) {
|
||||
if ($current_user->id !== 1) {
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
}
|
||||
|
||||
if($route == 'dash') {
|
||||
if ($route == 'dash') {
|
||||
//print_r(User::all());
|
||||
//die("here".var_dump($current_user->password));
|
||||
if((bool)$current_user->public_front === true) return $next($request);
|
||||
if ((bool) $current_user->public_front === true) {
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($current_user->password)) return $next($request);
|
||||
if (empty($current_user->password)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
// Check if user is logged in as $current_user
|
||||
if (Auth::check()) {
|
||||
$loggedin_user = Auth::user();
|
||||
if($loggedin_user->id === $current_user->id) return $next($request);
|
||||
if ($loggedin_user->id === $current_user->id) {
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
return Auth::authenticate();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
@@ -12,7 +12,7 @@ class TrustProxies extends Middleware
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $proxies;
|
||||
protected $proxies = ['192.168.0.0/16', '172.16.0.0/12', '10.0.0.0/8', '127.0.0.1'];
|
||||
|
||||
/**
|
||||
* The current proxy header mappings.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
class VerifyCsrfToken extends Middleware
|
||||
{
|
||||
@@ -18,4 +19,5 @@ class VerifyCsrfToken extends Middleware
|
||||
'test_config',
|
||||
//'get_stats'
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
170
app/Item.php
170
app/Item.php
@@ -2,11 +2,13 @@
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Symfony\Component\ClassLoader\ClassMapGenerator;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use App\Application;
|
||||
use App\ItemTag;
|
||||
use App\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\ClassLoader\ClassMapGenerator;
|
||||
|
||||
class Item extends Model
|
||||
{
|
||||
@@ -18,21 +20,20 @@ class Item extends Model
|
||||
|
||||
static::addGlobalScope('user_id', function (Builder $builder) {
|
||||
$current_user = User::currentUser();
|
||||
$builder->where('user_id', $current_user->id);
|
||||
if ($current_user) {
|
||||
$builder->where('user_id', $current_user->id)->orWhere('user_id', 0);
|
||||
} else {
|
||||
$builder->where('user_id', 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
protected $fillable = [
|
||||
'title', 'url', 'colour', 'icon', 'description', 'pinned', 'order', 'type', 'class', 'user_id'
|
||||
'title', 'url', 'colour', 'icon', 'appdescription', 'description', 'pinned', 'order', 'type', 'class', 'user_id', 'tag_id', 'appid',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be mutated to dates.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
|
||||
/**
|
||||
* Scope a query to only include pinned items.
|
||||
@@ -47,41 +48,49 @@ class Item extends Model
|
||||
|
||||
public static function checkConfig($config)
|
||||
{
|
||||
if(empty($config)) {
|
||||
// die(print_r($config));
|
||||
if (empty($config)) {
|
||||
$config = null;
|
||||
} else {
|
||||
$store = false;
|
||||
//die(var_dump($config));
|
||||
foreach($config as $key => $check) {
|
||||
if($key == 'type') continue;
|
||||
if($key == 'dataonly') continue;
|
||||
if(!empty($check) && $check != '0') {
|
||||
$store = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//die(var_dump($store))
|
||||
|
||||
$config['enabled'] = ($store) ? true : false;
|
||||
$config = json_encode($config);
|
||||
}
|
||||
return $config;
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function tags()
|
||||
{
|
||||
$id = $this->id;
|
||||
$tags = ItemTag::select('tag_id')->where('item_id', $id)->pluck('tag_id')->toArray();
|
||||
$tagdetails = self::select('id', 'title', 'url', 'pinned')->whereIn('id', $tags)->get();
|
||||
//print_r($tags);
|
||||
if (in_array(0, $tags)) {
|
||||
$details = new self([
|
||||
'id' => 0,
|
||||
'title' => __('app.dashboard'),
|
||||
'url' => '',
|
||||
'pinned' => 0,
|
||||
]);
|
||||
$tagdetails->prepend($details);
|
||||
}
|
||||
|
||||
return $tagdetails;
|
||||
}
|
||||
|
||||
public function parents()
|
||||
{
|
||||
return $this->belongsToMany('App\Item', 'item_tag', 'item_id', 'tag_id');
|
||||
return $this->belongsToMany(\App\Item::class, 'item_tag', 'item_id', 'tag_id');
|
||||
}
|
||||
|
||||
public function children()
|
||||
{
|
||||
return $this->belongsToMany('App\Item', 'item_tag', 'tag_id', 'item_id');
|
||||
return $this->belongsToMany(\App\Item::class, 'item_tag', 'tag_id', 'item_id');
|
||||
}
|
||||
|
||||
public function getLinkAttribute()
|
||||
{
|
||||
if((int)$this->type === 1) {
|
||||
return '/tag/'.$this->url;
|
||||
if ((int) $this->type === 1) {
|
||||
return url('tag/'.$this->url);
|
||||
} else {
|
||||
return $this->url;
|
||||
}
|
||||
@@ -89,7 +98,7 @@ class Item extends Model
|
||||
|
||||
public function getDroppableAttribute()
|
||||
{
|
||||
if((int)$this->type === 1) {
|
||||
if ((int) $this->type === 1) {
|
||||
return ' droppable';
|
||||
} else {
|
||||
return '';
|
||||
@@ -100,33 +109,42 @@ class Item extends Model
|
||||
{
|
||||
$target = Setting::fetch('window_target');
|
||||
|
||||
if((int)$this->type === 1 || $target === 'current') {
|
||||
if ((int) $this->type === 1 || $target === 'current') {
|
||||
return '';
|
||||
} else {
|
||||
return ' target="' . $target . '"';
|
||||
return ' target="'.$target.'"';
|
||||
}
|
||||
}
|
||||
|
||||
public function getLinkIconAttribute()
|
||||
{
|
||||
if((int)$this->type === 1) {
|
||||
if ((int) $this->type === 1) {
|
||||
return 'fa-tag';
|
||||
} else {
|
||||
return 'fa-arrow-alt-to-right';
|
||||
}
|
||||
}
|
||||
|
||||
public function getLinkTypeAttribute()
|
||||
{
|
||||
if((int)$this->type === 1) {
|
||||
if ((int) $this->type === 1) {
|
||||
return 'tags';
|
||||
} else {
|
||||
return 'items';
|
||||
}
|
||||
}
|
||||
|
||||
public static function nameFromClass($class)
|
||||
{
|
||||
$explode = explode('\\', $class);
|
||||
$name = end($explode);
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function scopeOfType($query, $type)
|
||||
{
|
||||
switch($type) {
|
||||
switch ($type) {
|
||||
case 'item':
|
||||
$typeid = 0;
|
||||
break;
|
||||
@@ -140,61 +158,103 @@ class Item extends Model
|
||||
|
||||
public function enhanced()
|
||||
{
|
||||
if(isset($this->class) && !empty($this->class)) {
|
||||
/*if(isset($this->class) && !empty($this->class)) {
|
||||
$app = new $this->class;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return (bool)($app instanceof \App\EnhancedApps);
|
||||
return (bool)($app instanceof \App\EnhancedApps);*/
|
||||
return $this->description !== null;
|
||||
}
|
||||
|
||||
public static function isEnhanced($class)
|
||||
{
|
||||
if (!class_exists($class, false) || $class === null || $class === 'null') {
|
||||
return false;
|
||||
}
|
||||
$app = new $class;
|
||||
|
||||
return (bool) ($app instanceof \App\EnhancedApps);
|
||||
}
|
||||
|
||||
public static function isSearchProvider($class)
|
||||
{
|
||||
if (!class_exists($class, false) || $class === null || $class === 'null') {
|
||||
return false;
|
||||
}
|
||||
$app = new $class;
|
||||
|
||||
return ((bool) ($app instanceof \App\SearchInterface)) ? $app : false;
|
||||
}
|
||||
|
||||
public function enabled()
|
||||
{
|
||||
if($this->enhanced()) {
|
||||
if ($this->enhanced()) {
|
||||
$config = $this->getconfig();
|
||||
if($config) {
|
||||
if ($config) {
|
||||
return (bool) $config->enabled;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getconfig()
|
||||
{
|
||||
$explode = explode('\\', $this->class);
|
||||
|
||||
// $explode = explode('\\', $this->class);
|
||||
|
||||
if(!isset($this->description) || empty($this->description)) {
|
||||
if (! isset($this->description) || empty($this->description)) {
|
||||
$config = new \stdClass;
|
||||
$config->name = end($explode);
|
||||
// $config->name = end($explode);
|
||||
$config->enabled = false;
|
||||
$config->override_url = null;
|
||||
$config->apikey = null;
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$config = json_decode($this->description);
|
||||
|
||||
$config->name = end($explode);
|
||||
// $config->name = end($explode);
|
||||
|
||||
|
||||
$config->url = $this->url;
|
||||
if(isset($config->override_url) && !empty($config->override_url)) {
|
||||
if (isset($config->override_url) && ! empty($config->override_url)) {
|
||||
$config->url = $config->override_url;
|
||||
} else {
|
||||
$config->override_url = null;
|
||||
}
|
||||
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public static function applicationDetails($class)
|
||||
{
|
||||
if (! empty($class)) {
|
||||
$name = self::nameFromClass($class);
|
||||
$application = Application::where('name', $name)->first();
|
||||
if ($application) {
|
||||
return $application;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function getApplicationDescription($class)
|
||||
{
|
||||
$details = self::applicationDetails($class);
|
||||
if ($details !== false) {
|
||||
return $details->description.' - '.$details->license;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that owns the item.
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\User');
|
||||
}
|
||||
|
||||
|
||||
return $this->belongsTo(\App\User::class);
|
||||
}
|
||||
}
|
||||
|
||||
9
app/ItemTag.php
Normal file
9
app/ItemTag.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
class ItemTag extends Pivot
|
||||
{
|
||||
}
|
||||
@@ -2,13 +2,15 @@
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Application;
|
||||
use App\Item;
|
||||
use App\SupportedApps;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use App\Application;
|
||||
use App\SupportedApps;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ProcessApps implements ShouldQueue
|
||||
{
|
||||
@@ -31,33 +33,24 @@ class ProcessApps implements ShouldQueue
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$localapps = Application::all();
|
||||
$list = json_decode(SupportedApps::getList()->getBody());
|
||||
$validapps = [];
|
||||
foreach($list->apps as $app) {
|
||||
$validapps[] = $app->appid;
|
||||
if(!file_exists(app_path('SupportedApps/'.className($app->name)))) {
|
||||
SupportedApps::getFiles($app);
|
||||
$application = new Application;
|
||||
SupportedApps::saveApp($app, $application);
|
||||
} else {
|
||||
// check if there has been an update for this app
|
||||
$localapp = $localapps->where('appid', $app->appid)->first();
|
||||
if($localapp) {
|
||||
if($localapp->sha !== $app->sha) {
|
||||
SupportedApps::getFiles($app);
|
||||
SupportedApps::saveApp($app, $localapp);
|
||||
}
|
||||
} else {
|
||||
SupportedApps::getFiles($app);
|
||||
$application = new Application;
|
||||
SupportedApps::saveApp($app, $application);
|
||||
|
||||
$localapps = Application::whereNull('class')->get();
|
||||
$json = SupportedApps::getList()->getBody();
|
||||
|
||||
Storage::disk('local')->put('supportedapps.json', $json);
|
||||
|
||||
foreach ($localapps as $app) {
|
||||
$app->class = $app->class();
|
||||
$app->save();
|
||||
}
|
||||
|
||||
$items = Item::whereNotNull('class')->get();
|
||||
foreach ($items as $item) {
|
||||
if (! file_exists(app_path('SupportedApps/'.Item::nameFromClass($item->class)))) {
|
||||
$app = Application::where('class', $item->class)->first();
|
||||
if ($app) {
|
||||
Application::getApp($app->appid);
|
||||
}
|
||||
}
|
||||
}
|
||||
//$delete = Application::whereNotIn('appid', $validapps)->delete(); // delete any apps not in list
|
||||
// removed the delete so local apps can be added
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Artisan;
|
||||
use Schema;
|
||||
use App\Setting;
|
||||
use App\User;
|
||||
use App\Application;
|
||||
use App\Jobs\ProcessApps;
|
||||
use App\Setting;
|
||||
use App\User;
|
||||
use Artisan;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Schema;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -19,97 +19,112 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
|
||||
if(!is_file(base_path('.env'))) {
|
||||
touch(base_path('.env'));
|
||||
Artisan::call('key:generate');
|
||||
if (! is_file(base_path('.env'))) {
|
||||
copy(base_path('.env.example'), base_path('.env'));
|
||||
}
|
||||
if(!is_file(database_path('app.sqlite'))) {
|
||||
$this->genKey();
|
||||
if (! is_file(database_path('app.sqlite'))) {
|
||||
// first time setup
|
||||
touch(database_path('app.sqlite'));
|
||||
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
|
||||
Artisan::call('migrate', ['--path' => 'database/migrations', '--force' => true, '--seed' => true]);
|
||||
//Cache
|
||||
//Artisan::call('config:cache');
|
||||
//Artisan::call('route:cache');
|
||||
}
|
||||
if(is_file(database_path('app.sqlite'))) {
|
||||
if(Schema::hasTable('settings')) {
|
||||
if (is_file(database_path('app.sqlite'))) {
|
||||
if (Schema::hasTable('settings')) {
|
||||
|
||||
// check version to see if an upgrade is needed
|
||||
$db_version = Setting::_fetch('version');
|
||||
$app_version = config('app.version');
|
||||
if(version_compare($app_version, $db_version) == 1) { // app is higher than db, so need to run migrations etc
|
||||
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
|
||||
if (version_compare($app_version, $db_version) == 1) { // app is higher than db, so need to run migrations etc
|
||||
Artisan::call('migrate', ['--path' => 'database/migrations', '--force' => true, '--seed' => true]);
|
||||
ProcessApps::dispatch();
|
||||
}
|
||||
|
||||
} else {
|
||||
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
|
||||
Artisan::call('migrate', ['--path' => 'database/migrations', '--force' => true, '--seed' => true]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$applications = Application::all();
|
||||
if($applications->count() <= 0) {
|
||||
ProcessApps::dispatch();
|
||||
}
|
||||
|
||||
if(!is_file(public_path('storage'))) {
|
||||
if (! is_file(public_path('storage/.gitignore'))) {
|
||||
Artisan::call('storage:link');
|
||||
\Session::put('current_user', null);
|
||||
}
|
||||
|
||||
// User specific settings need to go here as session isn't available at this point in the app
|
||||
view()->composer('*', function ($view)
|
||||
{
|
||||
$lang = Setting::fetch('language');
|
||||
\App::setLocale($lang);
|
||||
|
||||
if(isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
|
||||
$applications = Application::all();
|
||||
if ($applications->count() <= 0) {
|
||||
if (class_exists('ZipArchive')) {
|
||||
ProcessApps::dispatch();
|
||||
} else {
|
||||
die('You are missing php-zip');
|
||||
}
|
||||
}
|
||||
|
||||
// User specific settings need to go here as session isn't available at this point in the app
|
||||
view()->composer('*', function ($view) {
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION']) && ! empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
|
||||
explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
|
||||
}
|
||||
if(!\Auth::check()) {
|
||||
if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
|
||||
if (! \Auth::check()) {
|
||||
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])
|
||||
&& ! empty($_SERVER['PHP_AUTH_USER']) && ! empty($_SERVER['PHP_AUTH_PW'])) {
|
||||
$credentials = ['username' => $_SERVER['PHP_AUTH_USER'], 'password' => $_SERVER['PHP_AUTH_PW']];
|
||||
|
||||
if (\Auth::attempt($credentials)) {
|
||||
|
||||
if (\Auth::attempt($credentials, true)) {
|
||||
// Authentication passed...
|
||||
$user = \Auth::user();
|
||||
//\Session::put('current_user', $user);
|
||||
session(['current_user' => $user]);
|
||||
session(['current_user' => $user]);
|
||||
}
|
||||
} elseif (isset($_SERVER['REMOTE_USER']) && ! empty($_SERVER['REMOTE_USER'])) {
|
||||
$user = User::where('username', $_SERVER['REMOTE_USER'])->first();
|
||||
if ($user) {
|
||||
\Auth::login($user, true);
|
||||
session(['current_user' => $user]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$alt_bg = '';
|
||||
if($bg_image = Setting::fetch('background_image')) {
|
||||
$alt_bg = ' style="background-image: url(/storage/'.$bg_image.')"';
|
||||
if ($bg_image = Setting::fetch('background_image')) {
|
||||
$alt_bg = ' style="background-image: url(storage/'.$bg_image.')"';
|
||||
}
|
||||
$lang = Setting::fetch('language');
|
||||
\App::setLocale($lang);
|
||||
|
||||
$allusers = User::all();
|
||||
$current_user = User::currentUser();
|
||||
|
||||
$view->with('alt_bg', $alt_bg );
|
||||
$view->with('allusers', $allusers );
|
||||
$view->with('current_user', $current_user );
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
$view->with('alt_bg', $alt_bg);
|
||||
$view->with('allusers', $allusers);
|
||||
$view->with('current_user', $current_user);
|
||||
});
|
||||
|
||||
$this->app['view']->addNamespace('SupportedApps', app_path('SupportedApps'));
|
||||
|
||||
|
||||
if (env('FORCE_HTTPS') === true) {
|
||||
\URL::forceScheme('https');
|
||||
}
|
||||
|
||||
if(env('APP_URL') != 'http://localhost') {
|
||||
if (env('APP_URL') != 'http://localhost') {
|
||||
\URL::forceRootUrl(env('APP_URL'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate app key if missing and .env exists
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function genKey()
|
||||
{
|
||||
if (is_file(base_path('.env'))) {
|
||||
if (empty(env('APP_KEY'))) {
|
||||
Artisan::call('key:generate', ['--force' => true, '--no-interaction' => true]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Facades\Broadcast;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class BroadcastServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
||||
138
app/Search.php
Normal file
138
app/Search.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Item;
|
||||
use App\Setting;
|
||||
use Cache;
|
||||
use Form;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Yaml;
|
||||
|
||||
abstract class Search
|
||||
{
|
||||
/**
|
||||
* List of all search providers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function providers()
|
||||
{
|
||||
$providers = self::standardProviders();
|
||||
$providers = $providers + self::appProviders();
|
||||
|
||||
return collect($providers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets details for a single provider
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public static function providerDetails($provider)
|
||||
{
|
||||
$providers = self::providers();
|
||||
if (! isset($providers[$provider])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (object) $providers[$provider] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of the standard providers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function standardProviders()
|
||||
{
|
||||
// $providers = json_decode(file_get_contents(storage_path('app/searchproviders.json')));
|
||||
// print_r($providers);
|
||||
$providers = Yaml::parseFile(storage_path('app/searchproviders.yaml'));
|
||||
$all = [];
|
||||
foreach ($providers as $key => $provider) {
|
||||
$all[$key] = $provider;
|
||||
$all[$key]['type'] = 'standard';
|
||||
}
|
||||
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through users apps to see if app is a search provider, might be worth
|
||||
* looking into caching this at some point
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function appProviders()
|
||||
{
|
||||
$providers = [];
|
||||
$userapps = Item::all();
|
||||
foreach ($userapps as $app) {
|
||||
if (empty($app->class)) {
|
||||
continue;
|
||||
}
|
||||
if (($provider = Item::isSearchProvider($app->class)) !== false) {
|
||||
$name = Item::nameFromClass($app->class);
|
||||
$providers[$app->id] = [
|
||||
'id' => $app->id,
|
||||
'type' => $provider->type,
|
||||
'class' => $app->class,
|
||||
'url' => $app->url,
|
||||
'name' => $app->title,
|
||||
'colour' => $app->colour,
|
||||
'icon' => $app->icon,
|
||||
'description' => $app->description,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the search form
|
||||
*
|
||||
* @return html
|
||||
*/
|
||||
public static function form()
|
||||
{
|
||||
$output = '';
|
||||
$homepage_search = Setting::fetch('homepage_search');
|
||||
$search_provider = Setting::where('key', '=', 'search_provider')->first();
|
||||
$user_search_provider = Setting::fetch('search_provider');
|
||||
//die(print_r($search_provider));
|
||||
|
||||
//die(var_dump($user_search_provider));
|
||||
// return early if search isn't applicable
|
||||
if ((bool) $homepage_search !== true) {
|
||||
return $output;
|
||||
}
|
||||
$user_search_provider = $user_search_provider ?? 'none';
|
||||
|
||||
if ((bool) $homepage_search && (bool) $search_provider) {
|
||||
if ((bool) $user_search_provider) {
|
||||
$name = 'app.options.'.$user_search_provider;
|
||||
$provider = self::providerDetails($user_search_provider);
|
||||
|
||||
$output .= '<div class="searchform">';
|
||||
$output .= '<form action="'.url('search').'"'.getLinkTargetAttribute().' method="get">';
|
||||
$output .= '<div id="search-container" class="input-container">';
|
||||
$output .= '<select name="provider">';
|
||||
foreach (self::providers() as $key => $searchprovider) {
|
||||
$selected = ((string) $key === (string) $user_search_provider) ? ' selected="selected"' : '';
|
||||
$output .= '<option value="'.$key.'"'.$selected.'>'.$searchprovider['name'].'</option>';
|
||||
}
|
||||
$output .= '</select>';
|
||||
$output .= Form::text('q', null, ['class' => 'homesearch', 'autofocus' => 'autofocus', 'placeholder' => __('app.settings.search').'...']);
|
||||
$output .= '<button type="submit">'.ucwords(__('app.settings.search')).'</button>';
|
||||
$output .= '</div>';
|
||||
$output .= '</form>';
|
||||
$output .= '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
11
app/SearchInterface.php
Normal file
11
app/SearchInterface.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
interface SearchInterface
|
||||
{
|
||||
public function getResults($query, $providerdetails);
|
||||
}
|
||||
199
app/Setting.php
199
app/Setting.php
@@ -2,11 +2,13 @@
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Form;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Search;
|
||||
use App\User;
|
||||
use Form;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
|
||||
class Setting extends Model
|
||||
{
|
||||
@@ -18,7 +20,7 @@ class Setting extends Model
|
||||
protected $table = 'settings';
|
||||
|
||||
protected $fillable = [
|
||||
'id', 'group_id', 'key', 'type', 'options', 'label', 'value', 'order', 'system'
|
||||
'id', 'group_id', 'key', 'type', 'options', 'label', 'value', 'order', 'system',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -38,44 +40,47 @@ class Setting extends Model
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getInput()
|
||||
public static function getInput(Request $request)
|
||||
{
|
||||
return (object) [
|
||||
'value' => Input::get('value'),
|
||||
'image' => Input::file('value'),
|
||||
'value' => $request->input('value'),
|
||||
'image' => $request->file('value'),
|
||||
];
|
||||
}
|
||||
|
||||
public function getListValueAttribute()
|
||||
{
|
||||
if((bool)$this->system === true) {
|
||||
if ((bool) $this->system === true) {
|
||||
$value = self::_fetch($this->key);
|
||||
} else {
|
||||
$value = self::fetch($this->key);
|
||||
}
|
||||
$this->value = $value;
|
||||
switch($this->type) {
|
||||
switch ($this->type) {
|
||||
case 'image':
|
||||
if(!empty($this->value)) {
|
||||
if (! empty($this->value)) {
|
||||
$value = '<a href="'.asset('storage/'.$this->value).'" title="'.__('app.settings.view').'" target="_blank">'.__('app.settings.view').'</a>';
|
||||
} else {
|
||||
$value = __('app.options.none');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
if((bool)$this->value === true) {
|
||||
if ((bool) $this->value === true) {
|
||||
$value = __('app.options.yes');
|
||||
} else {
|
||||
$value = __('app.options.no');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'select':
|
||||
if(!empty($this->value) && $this->value !== 'none') {
|
||||
$options = (array)json_decode($this->options);
|
||||
if (! empty($this->value) && $this->value !== 'none') {
|
||||
$options = (array) json_decode($this->options);
|
||||
if ($this->key === 'search_provider') {
|
||||
$options = Search::providers()->pluck('name', 'id')->toArray();
|
||||
}
|
||||
$value = __($options[$this->value]);
|
||||
} else {
|
||||
$value = __('app.options.none');
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$value = __($this->value);
|
||||
@@ -83,32 +88,33 @@ class Setting extends Model
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
public function getEditValueAttribute()
|
||||
{
|
||||
if((bool)$this->system === true) {
|
||||
if ((bool) $this->system === true) {
|
||||
$value = self::_fetch($this->key);
|
||||
} else {
|
||||
$value = self::fetch($this->key);
|
||||
}
|
||||
$this->value = $value;
|
||||
switch($this->type) {
|
||||
switch ($this->type) {
|
||||
case 'image':
|
||||
$value = '';
|
||||
if(isset($this->value) && !empty($this->value)) {
|
||||
if (isset($this->value) && ! empty($this->value)) {
|
||||
$value .= '<a class="setting-view-image" href="'.asset('storage/'.$this->value).'" title="'.__('app.settings.view').'" target="_blank"><img src="'.asset('storage/'.$this->value).'" /></a>';
|
||||
}
|
||||
$value .= Form::file('value', ['class' => 'form-control']);
|
||||
if(isset($this->value) && !empty($this->value)) {
|
||||
if (isset($this->value) && ! empty($this->value)) {
|
||||
$value .= '<a class="settinglink" href="'.route('settings.clear', $this->id).'" title="'.__('app.settings.remove').'">'.__('app.settings.reset').'</a>';
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
case 'boolean':
|
||||
$checked = false;
|
||||
if(isset($this->value) && (bool)$this->value === true) $checked = true;
|
||||
if (isset($this->value) && (bool) $this->value === true) {
|
||||
$checked = true;
|
||||
}
|
||||
$set_checked = ($checked) ? ' checked="checked"' : '';
|
||||
$value = '
|
||||
<input type="hidden" name="value" value="0" />
|
||||
@@ -120,26 +126,30 @@ class Setting extends Model
|
||||
break;
|
||||
case 'select':
|
||||
$options = json_decode($this->options);
|
||||
foreach($options as $key => $opt) {
|
||||
if ($this->key === 'search_provider') {
|
||||
$options = Search::providers()->pluck('name', 'id');
|
||||
}
|
||||
foreach ($options as $key => $opt) {
|
||||
$options->$key = __($opt);
|
||||
}
|
||||
$value = Form::select('value', $options, null, ['class' => 'form-control']);
|
||||
break;
|
||||
case 'textarea':
|
||||
$value = Form::textarea('value', null, ['class' => 'form-control', 'cols' => '44', 'rows' => '15']);
|
||||
break;
|
||||
default:
|
||||
$value = Form::text('value', null, ['class' => 'form-control']);
|
||||
break;
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
public function group()
|
||||
{
|
||||
return $this->belongsTo('App\SettingGroup', 'group_id');
|
||||
return $this->belongsTo(\App\SettingGroup::class, 'group_id');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
@@ -148,53 +158,54 @@ class Setting extends Model
|
||||
public static function fetch($key)
|
||||
{
|
||||
$user = self::user();
|
||||
|
||||
return self::_fetch($key, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function _fetch($key, $user=null)
|
||||
public static function _fetch($key, $user = null)
|
||||
{
|
||||
#$cachekey = ($user === null) ? $key : $key.'-'.$user->id;
|
||||
#if (Setting::cached($cachekey)) {
|
||||
# return Setting::$cache[$cachekey];
|
||||
#} else {
|
||||
$find = self::where('key', '=', $key)->first();
|
||||
//$cachekey = ($user === null) ? $key : $key.'-'.$user->id;
|
||||
//if (Setting::cached($cachekey)) {
|
||||
// return Setting::$cache[$cachekey];
|
||||
//} else {
|
||||
$find = self::where('key', '=', $key)->first();
|
||||
|
||||
if (!is_null($find)) {
|
||||
if((bool)$find->system === true) { // if system variable use global value
|
||||
if (! is_null($find)) {
|
||||
if ((bool) $find->system === true) { // if system variable use global value
|
||||
$value = $find->value;
|
||||
} else { // not system variable so use user specific value
|
||||
// check if user specified value has been set
|
||||
//print_r($user);
|
||||
$usersetting = $user->settings()->where('id', $find->id)->first();
|
||||
//print_r($user->settings);
|
||||
//die(var_dump($usersetting));
|
||||
//->pivot->value;
|
||||
//echo "user: ".$user->id." --- ".$usersettings;
|
||||
if (isset($usersetting) && ! empty($usersetting)) {
|
||||
$value = $usersetting->pivot->uservalue;
|
||||
} else { // if not get default from base setting
|
||||
//$user->settings()->save($find, ['value' => $find->value]);
|
||||
//$has_setting = $user->settings()->where('id', $find->id)->exists();
|
||||
//if($has_setting) {
|
||||
// $user->settings()->updateExistingPivot($find->id, ['uservalue' => (string)$find->value]);
|
||||
//} else {
|
||||
// $user->settings()->save($find, ['uservalue' => (string)$find->value]);
|
||||
//}
|
||||
$value = $find->value;
|
||||
} else { // not system variable so use user specific value
|
||||
// check if user specified value has been set
|
||||
//print_r($user);
|
||||
$usersetting = $user->settings()->where('id', $find->id)->first();
|
||||
//print_r($user->settings);
|
||||
//die(var_dump($usersetting));
|
||||
//->pivot->value;
|
||||
//echo "user: ".$user->id." --- ".$usersettings;
|
||||
if(isset($usersetting) && !empty($usersetting)) {
|
||||
$value = $usersetting->pivot->uservalue;
|
||||
} else { // if not get default from base setting
|
||||
//$user->settings()->save($find, ['value' => $find->value]);
|
||||
#$has_setting = $user->settings()->where('id', $find->id)->exists();
|
||||
#if($has_setting) {
|
||||
# $user->settings()->updateExistingPivot($find->id, ['uservalue' => (string)$find->value]);
|
||||
#} else {
|
||||
# $user->settings()->save($find, ['uservalue' => (string)$find->value]);
|
||||
#}
|
||||
$value = $find->value;
|
||||
}
|
||||
|
||||
}
|
||||
#Setting::add($cachekey, $value);
|
||||
|
||||
return $value;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#}
|
||||
//Setting::add($cachekey, $value);
|
||||
|
||||
return $value;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,7 +214,7 @@ class Setting extends Model
|
||||
*/
|
||||
public static function add($key, $value)
|
||||
{
|
||||
Setting::$cache[$key] = $value;
|
||||
self::$cache[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,61 +224,7 @@ class Setting extends Model
|
||||
*/
|
||||
public static function cached($key)
|
||||
{
|
||||
return array_key_exists($key, Setting::$cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return html
|
||||
*/
|
||||
public static function search()
|
||||
{
|
||||
$output = '';
|
||||
$homepage_search = self::fetch('homepage_search');
|
||||
$search_provider = self::where('key', '=', 'search_provider')->first();
|
||||
$user_search_provider = self::fetch('search_provider');
|
||||
//die(print_r($search_provider));
|
||||
|
||||
//die(var_dump($user_search_provider));
|
||||
// return early if search isn't applicable
|
||||
if((bool)$homepage_search !== true) return $output;
|
||||
if($user_search_provider === 'none') return $output;
|
||||
if(empty($user_search_provider)) return $output;
|
||||
if(is_null($user_search_provider)) return $output;
|
||||
|
||||
|
||||
if((bool)$homepage_search && (bool)$search_provider) {
|
||||
|
||||
$options = (array)json_decode($search_provider->options);
|
||||
$name = $options[$user_search_provider];
|
||||
if((bool)$user_search_provider) {
|
||||
switch($user_search_provider) {
|
||||
case 'google':
|
||||
$url = 'https://www.google.com/search';
|
||||
$var = 'q';
|
||||
break;
|
||||
case 'ddg':
|
||||
$url = 'https://duckduckgo.com/';
|
||||
$var = 'q';
|
||||
break;
|
||||
case 'bing':
|
||||
$url = 'https://www.bing.com/search';
|
||||
$var = 'q';
|
||||
break;
|
||||
case 'startpage':
|
||||
$url = 'https://www.startpage.com/';
|
||||
$var = 'q';
|
||||
}
|
||||
$output .= '<div class="searchform">';
|
||||
$output .= Form::open(['url' => $url, 'method' => 'get']);
|
||||
$output .= '<div class="input-container">';
|
||||
$output .= Form::text($var, null, ['class' => 'homesearch', 'autofocus' => 'autofocus', 'placeholder' => __($name).' '.__('app.settings.search').'...']);
|
||||
$output .= '<button type="submit">'.ucwords(__('app.settings.search')).'</button>';
|
||||
$output .= '</div>';
|
||||
$output .= Form::close();
|
||||
$output .= '</div>';
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
return array_key_exists($key, self::$cache);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,13 +232,11 @@ class Setting extends Model
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
return $this->belongsToMany('App\User')->using('App\SettingUser')->withPivot('uservalue');
|
||||
return $this->belongsToMany(\App\User::class)->using(\App\SettingUser::class)->withPivot('uservalue');
|
||||
}
|
||||
|
||||
public static function user()
|
||||
{
|
||||
return User::currentUser();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,6 @@ class SettingGroup extends Model
|
||||
|
||||
public function settings()
|
||||
{
|
||||
return $this->hasMany('App\Setting', 'group_id');
|
||||
return $this->hasMany(\App\Setting::class, 'group_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,37 @@
|
||||
<?php namespace App;
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
abstract class SupportedApps
|
||||
{
|
||||
|
||||
protected $jar = false;
|
||||
|
||||
protected $method = 'GET';
|
||||
|
||||
protected $error;
|
||||
|
||||
public function appTest($url, $attrs = [], $overridevars=false)
|
||||
public function appTest($url, $attrs = [], $overridevars = false)
|
||||
{
|
||||
if (empty($this->config->url)) {
|
||||
return (object) [
|
||||
'code' => 404,
|
||||
'status' => 'No URL has been specified',
|
||||
'response' => 'No URL has been specified',
|
||||
];
|
||||
}
|
||||
$res = $this->execute($url, $attrs);
|
||||
if($res == null) {
|
||||
return (object)[
|
||||
if ($res == null) {
|
||||
return (object) [
|
||||
'code' => null,
|
||||
'status' => $this->error,
|
||||
'response' => 'Connection failed',
|
||||
];
|
||||
}
|
||||
switch($res->getStatusCode()) {
|
||||
switch ($res->getStatusCode()) {
|
||||
case 200:
|
||||
$status = 'Successfully communicated with the API';
|
||||
break;
|
||||
@@ -35,21 +45,22 @@ abstract class SupportedApps
|
||||
$status = 'Something went wrong... Code: '.$res->getStatusCode();
|
||||
break;
|
||||
}
|
||||
return (object)[
|
||||
|
||||
return (object) [
|
||||
'code' => $res->getStatusCode(),
|
||||
'status' => $status,
|
||||
'response' => $res->getBody(),
|
||||
];
|
||||
}
|
||||
|
||||
public function execute($url, $attrs = [], $overridevars=false, $overridemethod=false)
|
||||
public function execute($url, $attrs = [], $overridevars = false, $overridemethod = false)
|
||||
{
|
||||
$res = null;
|
||||
|
||||
$vars = ($overridevars !== false) ?
|
||||
$overridevars : [
|
||||
'http_errors' => false,
|
||||
'timeout' => 15,
|
||||
'http_errors' => false,
|
||||
'timeout' => 15,
|
||||
'connect_timeout' => 15,
|
||||
];
|
||||
|
||||
@@ -58,35 +69,34 @@ abstract class SupportedApps
|
||||
$method = ($overridemethod !== false) ? $overridemethod : $this->method;
|
||||
|
||||
try {
|
||||
return $client->request($method, $url, $attrs);
|
||||
return $client->request($method, $url, $attrs);
|
||||
} catch (\GuzzleHttp\Exception\ConnectException $e) {
|
||||
Log::error("Connection refused");
|
||||
Log::error('Connection refused');
|
||||
Log::debug($e->getMessage());
|
||||
$this->error = "Connection refused - ".(string) $e->getMessage();
|
||||
$this->error = 'Connection refused - '.(string) $e->getMessage();
|
||||
} catch (\GuzzleHttp\Exception\ServerException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
$this->error = (string) $e->getResponse()->getBody();
|
||||
}
|
||||
$this->error = 'General error connecting with API';
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function login()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function normaliseurl($url, $addslash=true)
|
||||
public function normaliseurl($url, $addslash = true)
|
||||
{
|
||||
|
||||
$url = rtrim($url, '/');
|
||||
if($addslash) $url .= '/';
|
||||
if ($addslash) {
|
||||
$url .= '/';
|
||||
}
|
||||
|
||||
return $url;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function getLiveStats($status, $data)
|
||||
{
|
||||
$className = get_class($this);
|
||||
@@ -94,24 +104,37 @@ abstract class SupportedApps
|
||||
$name = end($explode);
|
||||
|
||||
$html = view('SupportedApps::'.$name.'.livestats', $data)->with('data', $data)->render();
|
||||
|
||||
return json_encode(['status' => $status, 'html' => $html]);
|
||||
//return
|
||||
//return
|
||||
}
|
||||
|
||||
public static function getList()
|
||||
{
|
||||
$list_url = 'https://apps.heimdall.site/list';
|
||||
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
|
||||
// $list_url = 'https://apps.heimdall.site/list';
|
||||
$list_url = config('app.appsource').'list.json';
|
||||
$client = new Client(['http_errors' => false, 'verify' => false, 'timeout' => 15, 'connect_timeout' => 15]);
|
||||
|
||||
return $client->request('GET', $list_url);
|
||||
}
|
||||
|
||||
public static function configValue($item = null, $key = null)
|
||||
{
|
||||
if (isset($item) && ! empty($item)) {
|
||||
return $item->getconfig()->$key;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getFiles($app)
|
||||
{
|
||||
$zipurl = $app->files;
|
||||
$client = new Client(['http_errors' => false, 'timeout' => 60, 'connect_timeout' => 15]);
|
||||
$zipurl = config('app.appsource').'files/'.$app->sha.'.zip';
|
||||
|
||||
$client = new Client(['http_errors' => false, 'timeout' => 60, 'connect_timeout' => 15, 'verify' => false]);
|
||||
$res = $client->request('GET', $zipurl);
|
||||
|
||||
if(!file_exists(app_path('SupportedApps'))) {
|
||||
if (! file_exists(app_path('SupportedApps'))) {
|
||||
mkdir(app_path('SupportedApps'), 0777, true);
|
||||
}
|
||||
|
||||
@@ -124,31 +147,28 @@ abstract class SupportedApps
|
||||
$zip->extractTo(app_path('SupportedApps')); // place in the directory with same name
|
||||
$zip->close();
|
||||
unlink($src); //Deleting the Zipped file
|
||||
} else {
|
||||
var_dump($x);
|
||||
}
|
||||
}
|
||||
|
||||
public static function saveApp($details, $app)
|
||||
{
|
||||
$img_src = app_path('SupportedApps/'.className($details->name).'/'.$details->icon);
|
||||
$img_dest = public_path('storage/supportedapps/'.$details->icon);
|
||||
//die("i: ".$img_src);
|
||||
copy($img_src, $img_dest);
|
||||
|
||||
$app->appid = $details->appid;
|
||||
$app->name = $details->name;
|
||||
$app->sha = $details->sha ?? null;
|
||||
$app->icon = 'supportedapps/'.$details->icon;
|
||||
$app->icon = 'icons/'.$details->icon;
|
||||
$app->website = $details->website;
|
||||
$app->license = $details->license;
|
||||
$app->description = $details->description;
|
||||
|
||||
$appclass = $app->class();
|
||||
$application = new $appclass;
|
||||
$enhanced = (bool)($application instanceof \App\EnhancedApps);
|
||||
|
||||
$enhanced = (bool) ($application instanceof \App\EnhancedApps);
|
||||
$app->class = $appclass;
|
||||
$app->enhanced = $enhanced;
|
||||
$app->tile_background = $details->tile_background;
|
||||
$app->save();
|
||||
}
|
||||
|
||||
}
|
||||
return $app;
|
||||
}
|
||||
}
|
||||
|
||||
16
app/User.php
16
app/User.php
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
@@ -32,7 +32,7 @@ class User extends Authenticatable
|
||||
*/
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany('App\Item');
|
||||
return $this->hasMany(\App\Item::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,7 +40,7 @@ class User extends Authenticatable
|
||||
*/
|
||||
public function settings()
|
||||
{
|
||||
return $this->belongsToMany('App\Setting')->withPivot('uservalue');
|
||||
return $this->belongsToMany(\App\Setting::class)->withPivot('uservalue');
|
||||
}
|
||||
|
||||
public static function currentUser()
|
||||
@@ -49,15 +49,13 @@ class User extends Authenticatable
|
||||
if ($current_user) { // if logged in, set this user
|
||||
return $current_user;
|
||||
} else { // not logged in, get first user
|
||||
$user = User::where('public_front',true)->first();
|
||||
if(!$user) {
|
||||
$user = User::first();
|
||||
$user = self::where('public_front', true)->first();
|
||||
if (! $user) {
|
||||
$user = self::first();
|
||||
}
|
||||
session(['current_user' => $user]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
$app = new Illuminate\Foundation\Application(
|
||||
realpath(__DIR__.'/../')
|
||||
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
|
||||
);
|
||||
|
||||
/*
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
"license": "MIT",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"php": ">=7.2.5",
|
||||
"fideloper/proxy": "^4.0",
|
||||
"graham-campbell/github": "^7.5",
|
||||
"guzzlehttp/guzzle": "^6.3",
|
||||
"laravel/framework": "5.7.*",
|
||||
"laravel/tinker": "~1.0",
|
||||
"laravelcollective/html": "^5.5",
|
||||
"php-http/guzzle6-adapter": "^1.1"
|
||||
"graham-campbell/github": "^10.5",
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"laravel/framework": "^7.0",
|
||||
"laravel/tinker": "^2.0",
|
||||
"laravel/ui": "^2.4",
|
||||
"laravelcollective/html": "^6.0",
|
||||
"symfony/yaml": "^5.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"filp/whoops": "~2.0",
|
||||
@@ -59,6 +60,10 @@
|
||||
"config": {
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"optimize-autoloader": true
|
||||
"optimize-autoloader": true,
|
||||
"allow-plugins": {
|
||||
"kylekatarnls/update-helper": true,
|
||||
"symfony/thanks": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5442
composer.lock
generated
5442
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,8 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'name' => env('APP_NAME', 'Heimdall'),
|
||||
'version' => '2.0.101',
|
||||
'name' => env('APP_NAME', 'Heimdall'),
|
||||
'version' => '2.4.13',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -40,7 +40,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'debug' => env('APP_DEBUG', false),
|
||||
'debug' => (bool) env('APP_DEBUG', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -55,6 +55,9 @@ return [
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
|
||||
'asset_url' => env('ASSET_URL', null),
|
||||
'appsource' => env('APP_SOURCE', 'https://appslist.heimdall.site/'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
@@ -94,6 +97,19 @@ return [
|
||||
|
||||
'fallback_locale' => 'en',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Faker Locale
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This locale will be used by the Faker PHP library when generating fake
|
||||
| data for your database seeds. For example, this will be used to get
|
||||
| localized telephone numbers, street address information and more.
|
||||
|
|
||||
*/
|
||||
|
||||
'faker_locale' => 'en_US',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption Key
|
||||
@@ -109,23 +125,6 @@ return [
|
||||
|
||||
'cipher' => 'AES-256-CBC',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Logging Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the log settings for your application. Out of
|
||||
| the box, Laravel uses the Monolog PHP logging library. This gives
|
||||
| you a variety of powerful log handlers / formatters to utilize.
|
||||
|
|
||||
| Available Settings: "single", "daily", "syslog", "errorlog"
|
||||
|
|
||||
*/
|
||||
|
||||
'log' => env('APP_LOG', 'single'),
|
||||
|
||||
'log_level' => env('APP_LOG_LEVEL', 'debug'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Autoloaded Service Providers
|
||||
@@ -194,6 +193,7 @@ return [
|
||||
'aliases' => [
|
||||
|
||||
'App' => Illuminate\Support\Facades\App::class,
|
||||
'Arr' => Illuminate\Support\Arr::class,
|
||||
'Artisan' => Illuminate\Support\Facades\Artisan::class,
|
||||
'Auth' => Illuminate\Support\Facades\Auth::class,
|
||||
'Blade' => Illuminate\Support\Facades\Blade::class,
|
||||
@@ -211,6 +211,7 @@ return [
|
||||
'Gate' => Illuminate\Support\Facades\Gate::class,
|
||||
'Hash' => Illuminate\Support\Facades\Hash::class,
|
||||
'Html' => Collective\Html\HtmlFacade::class,
|
||||
'Http' => Illuminate\Support\Facades\Http::class,
|
||||
'Lang' => Illuminate\Support\Facades\Lang::class,
|
||||
'Log' => Illuminate\Support\Facades\Log::class,
|
||||
'Mail' => Illuminate\Support\Facades\Mail::class,
|
||||
@@ -225,9 +226,11 @@ return [
|
||||
'Schema' => Illuminate\Support\Facades\Schema::class,
|
||||
'Session' => Illuminate\Support\Facades\Session::class,
|
||||
'Storage' => Illuminate\Support\Facades\Storage::class,
|
||||
'Str' => Illuminate\Support\Str::class,
|
||||
'URL' => Illuminate\Support\Facades\URL::class,
|
||||
'Validator' => Illuminate\Support\Facades\Validator::class,
|
||||
'View' => Illuminate\Support\Facades\View::class,
|
||||
'Yaml' => Symfony\Component\Yaml\Yaml::class,
|
||||
|
||||
'SupportedApps' => App\SupportedApps::class,
|
||||
'EnhancedApps' => App\EnhancedApps::class,
|
||||
|
||||
@@ -44,6 +44,7 @@ return [
|
||||
'api' => [
|
||||
'driver' => 'token',
|
||||
'provider' => 'users',
|
||||
'hash' => false,
|
||||
],
|
||||
],
|
||||
|
||||
@@ -96,7 +97,21 @@ return [
|
||||
'provider' => 'users',
|
||||
'table' => 'password_resets',
|
||||
'expire' => 60,
|
||||
'throttle' => 60,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Confirmation Timeout
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define the amount of seconds before a password confirmation
|
||||
| times out and the user is prompted to re-enter their password via the
|
||||
| confirmation screen. By default, the timeout lasts for three hours.
|
||||
|
|
||||
*/
|
||||
|
||||
'password_timeout' => 10800,
|
||||
|
||||
];
|
||||
|
||||
@@ -37,7 +37,7 @@ return [
|
||||
'app_id' => env('PUSHER_APP_ID'),
|
||||
'options' => [
|
||||
'cluster' => env('PUSHER_APP_CLUSTER'),
|
||||
'encrypted' => true,
|
||||
'useTLS' => true,
|
||||
],
|
||||
],
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@@ -36,6 +38,7 @@ return [
|
||||
|
||||
'array' => [
|
||||
'driver' => 'array',
|
||||
'serialize' => false,
|
||||
],
|
||||
|
||||
'database' => [
|
||||
@@ -73,6 +76,15 @@ return [
|
||||
'connection' => 'default',
|
||||
],
|
||||
|
||||
'dynamodb' => [
|
||||
'driver' => 'dynamodb',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
|
||||
'endpoint' => env('DYNAMODB_ENDPOINT'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -86,9 +98,6 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env(
|
||||
'CACHE_PREFIX',
|
||||
str_slug(env('APP_NAME', 'laravel'), '_').'_cache'
|
||||
),
|
||||
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
|
||||
|
||||
];
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@@ -42,6 +44,7 @@ return [
|
||||
|
||||
'mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'forge'),
|
||||
@@ -51,12 +54,17 @@ return [
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '5432'),
|
||||
'database' => env('DB_DATABASE', 'forge'),
|
||||
@@ -64,12 +72,14 @@ return [
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => 'utf8',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'schema' => 'public',
|
||||
'sslmode' => 'prefer',
|
||||
],
|
||||
|
||||
'sqlsrv' => [
|
||||
'driver' => 'sqlsrv',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'host' => env('DB_HOST', 'localhost'),
|
||||
'port' => env('DB_PORT', '1433'),
|
||||
'database' => env('DB_DATABASE', 'forge'),
|
||||
@@ -77,8 +87,9 @@ return [
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => 'utf8',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
],
|
||||
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -107,13 +118,27 @@ return [
|
||||
|
||||
'redis' => [
|
||||
|
||||
'client' => 'predis',
|
||||
'client' => env('REDIS_CLIENT', 'phpredis'),
|
||||
|
||||
'options' => [
|
||||
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
|
||||
],
|
||||
|
||||
'default' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'port' => env('REDIS_PORT', 6379),
|
||||
'database' => 0,
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_DB', '0'),
|
||||
],
|
||||
|
||||
'cache' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_CACHE_DB', '1'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
@@ -61,8 +61,10 @@ return [
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION'),
|
||||
'bucket' => env('AWS_BUCKET'),
|
||||
'url' => env('AWS_URL'),
|
||||
'endpoint' => env('AWS_ENDPOINT'),
|
||||
],
|
||||
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
52
config/hashing.php
Normal file
52
config/hashing.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Hash Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default hash driver that will be used to hash
|
||||
| passwords for your application. By default, the bcrypt algorithm is
|
||||
| used; however, you remain free to modify this option if you wish.
|
||||
|
|
||||
| Supported: "bcrypt", "argon", "argon2id"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => 'bcrypt',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Bcrypt Options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the configuration options that should be used when
|
||||
| passwords are hashed using the Bcrypt algorithm. This will allow you
|
||||
| to control the amount of time it takes to hash the given password.
|
||||
|
|
||||
*/
|
||||
|
||||
'bcrypt' => [
|
||||
'rounds' => env('BCRYPT_ROUNDS', 10),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Argon Options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the configuration options that should be used when
|
||||
| passwords are hashed using the Argon algorithm. These will allow you
|
||||
| to control the amount of time it takes to hash the given password.
|
||||
|
|
||||
*/
|
||||
|
||||
'argon' => [
|
||||
'memory' => 1024,
|
||||
'threads' => 2,
|
||||
'time' => 2,
|
||||
],
|
||||
|
||||
];
|
||||
104
config/logging.php
Normal file
104
config/logging.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\SyslogUdpHandler;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default log channel that gets used when writing
|
||||
| messages to the logs. The name specified in this option should match
|
||||
| one of the channels defined in the "channels" configuration array.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('LOG_CHANNEL', 'stack'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log Channels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the log channels for your application. Out of
|
||||
| the box, Laravel uses the Monolog PHP logging library. This gives
|
||||
| you a variety of powerful log handlers / formatters to utilize.
|
||||
|
|
||||
| Available Drivers: "single", "daily", "slack", "syslog",
|
||||
| "errorlog", "monolog",
|
||||
| "custom", "stack"
|
||||
|
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => ['single'],
|
||||
'ignore_exceptions' => false,
|
||||
],
|
||||
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => 'debug',
|
||||
],
|
||||
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => 'debug',
|
||||
'days' => 14,
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'driver' => 'slack',
|
||||
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||
'username' => 'Laravel Log',
|
||||
'emoji' => ':boom:',
|
||||
'level' => 'critical',
|
||||
],
|
||||
|
||||
'papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => 'debug',
|
||||
'handler' => SyslogUdpHandler::class,
|
||||
'handler_with' => [
|
||||
'host' => env('PAPERTRAIL_URL'),
|
||||
'port' => env('PAPERTRAIL_PORT'),
|
||||
],
|
||||
],
|
||||
|
||||
'stderr' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => StreamHandler::class,
|
||||
'formatter' => env('LOG_STDERR_FORMATTER'),
|
||||
'with' => [
|
||||
'stream' => 'php://stderr',
|
||||
],
|
||||
],
|
||||
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => 'debug',
|
||||
],
|
||||
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => 'debug',
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => NullHandler::class,
|
||||
],
|
||||
|
||||
'emergency' => [
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
@@ -4,18 +4,16 @@ return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Queue Driver
|
||||
| Default Queue Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Laravel's queue API supports an assortment of back-ends via a single
|
||||
| API, giving you convenient access to each back-end using the same
|
||||
| syntax for each one. Here you may set the default queue driver.
|
||||
|
|
||||
| Supported: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
||||
| syntax for every one. Here you may define a default connection.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('QUEUE_DRIVER', 'sync'),
|
||||
'default' => env('QUEUE_CONNECTION', 'sync'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -26,6 +24,8 @@ return [
|
||||
| is used by your application. A default configuration has been added
|
||||
| for each back-end shipped with Laravel. You are free to add more.
|
||||
|
|
||||
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
@@ -46,22 +46,25 @@ return [
|
||||
'host' => 'localhost',
|
||||
'queue' => 'default',
|
||||
'retry_after' => 90,
|
||||
'block_for' => 0,
|
||||
],
|
||||
|
||||
'sqs' => [
|
||||
'driver' => 'sqs',
|
||||
'key' => env('SQS_KEY', 'your-public-key'),
|
||||
'secret' => env('SQS_SECRET', 'your-secret-key'),
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
|
||||
'queue' => env('SQS_QUEUE', 'your-queue-name'),
|
||||
'region' => env('SQS_REGION', 'us-east-1'),
|
||||
'suffix' => env('SQS_SUFFIX'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => 'default',
|
||||
'queue' => 'default',
|
||||
'queue' => env('REDIS_QUEUE', 'default'),
|
||||
'retry_after' => 90,
|
||||
'block_for' => null,
|
||||
],
|
||||
|
||||
],
|
||||
@@ -78,6 +81,7 @@ return [
|
||||
*/
|
||||
|
||||
'failed' => [
|
||||
'driver' => env('QUEUE_FAILED_DRIVER', 'database'),
|
||||
'database' => env('DB_CONNECTION', 'mysql'),
|
||||
'table' => 'failed_jobs',
|
||||
],
|
||||
|
||||
@@ -8,31 +8,26 @@ return [
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is for storing the credentials for third party services such
|
||||
| as Stripe, Mailgun, SparkPost and others. This file provides a sane
|
||||
| default location for this type of information, allowing packages
|
||||
| to have a conventional place to find your various credentials.
|
||||
| as Mailgun, Postmark, AWS and more. This file provides the de facto
|
||||
| location for this type of information, allowing packages to have
|
||||
| a conventional file to locate the various service credentials.
|
||||
|
|
||||
*/
|
||||
|
||||
'mailgun' => [
|
||||
'domain' => env('MAILGUN_DOMAIN'),
|
||||
'secret' => env('MAILGUN_SECRET'),
|
||||
'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
|
||||
],
|
||||
|
||||
'postmark' => [
|
||||
'token' => env('POSTMARK_TOKEN'),
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'key' => env('SES_KEY'),
|
||||
'secret' => env('SES_SECRET'),
|
||||
'region' => 'us-east-1',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
'sparkpost' => [
|
||||
'secret' => env('SPARKPOST_SECRET'),
|
||||
],
|
||||
|
||||
'stripe' => [
|
||||
'model' => App\User::class,
|
||||
'key' => env('STRIPE_KEY'),
|
||||
'secret' => env('STRIPE_SECRET'),
|
||||
],
|
||||
|
||||
|
||||
];
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@@ -70,7 +72,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'connection' => null,
|
||||
'connection' => env('SESSION_CONNECTION', null),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -96,7 +98,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'store' => null,
|
||||
'store' => env('SESSION_STORE', null),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -124,7 +126,7 @@ return [
|
||||
|
||||
'cookie' => env(
|
||||
'SESSION_COOKIE',
|
||||
str_slug(env('APP_NAME', 'laravel'), '_').'_session'
|
||||
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
|
||||
),
|
||||
|
||||
/*
|
||||
@@ -164,7 +166,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'secure' => env('SESSION_SECURE_COOKIE', false),
|
||||
'secure' => env('SESSION_SECURE_COOKIE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
@@ -28,6 +28,9 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'compiled' => realpath(storage_path('framework/views')),
|
||||
'compiled' => env(
|
||||
'VIEW_COMPILED_PATH',
|
||||
realpath(storage_path('framework/views'))
|
||||
),
|
||||
|
||||
];
|
||||
];
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateItemsTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateSettingsTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateSettingGroupsTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddColumnsToItemsForGroups extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ItemTag extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateUsersTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreatePasswordResetsTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddUserIdToItemsTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateSettingUserPivotTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateApplicationsTable extends Migration
|
||||
{
|
||||
@@ -14,7 +14,6 @@ class CreateApplicationsTable extends Migration
|
||||
public function up()
|
||||
{
|
||||
Schema::create('applications', function (Blueprint $table) {
|
||||
|
||||
$table->string('appid')->unique();
|
||||
$table->string('name')->unique();
|
||||
$table->string('sha')->unique()->nullable();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddClassToItemsTable extends Migration
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateJobsTable extends Migration
|
||||
{
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateFailedJobsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
}
|
||||
32
database/migrations/2022_03_15_140911_add_appid_to_items.php
Normal file
32
database/migrations/2022_03_15_140911_add_appid_to_items.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddAppidToItems extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->string('appid')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->dropColumn(['appid']);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddClassToApplication extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('applications', function (Blueprint $table) {
|
||||
$table->string('class')->nullable()->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('applications', function (Blueprint $table) {
|
||||
$table->dropColumn(['class']);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddAppDescriptionToItems extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->text('appdescription')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Setting;
|
||||
use App\SettingGroup;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class SettingsSeeder extends Seeder
|
||||
{
|
||||
@@ -14,7 +14,7 @@ class SettingsSeeder extends Seeder
|
||||
public function run()
|
||||
{
|
||||
// Groups
|
||||
if(!$setting_group = SettingGroup::find(1)) {
|
||||
if (! $setting_group = SettingGroup::find(1)) {
|
||||
$setting_group = new SettingGroup;
|
||||
$setting_group->id = 1;
|
||||
$setting_group->title = 'app.settings.system';
|
||||
@@ -24,7 +24,7 @@ class SettingsSeeder extends Seeder
|
||||
$setting_group->title = 'app.settings.system';
|
||||
$setting_group->save();
|
||||
}
|
||||
if(!$setting_group = SettingGroup::find(2)) {
|
||||
if (! $setting_group = SettingGroup::find(2)) {
|
||||
$setting_group = new SettingGroup;
|
||||
$setting_group->id = 2;
|
||||
$setting_group->title = 'app.settings.appearance';
|
||||
@@ -34,7 +34,7 @@ class SettingsSeeder extends Seeder
|
||||
$setting_group->title = 'app.settings.appearance';
|
||||
$setting_group->save();
|
||||
}
|
||||
if(!$setting_group = SettingGroup::find(3)) {
|
||||
if (! $setting_group = SettingGroup::find(3)) {
|
||||
$setting_group = new SettingGroup;
|
||||
$setting_group->id = 3;
|
||||
$setting_group->title = 'app.settings.miscellaneous';
|
||||
@@ -44,8 +44,18 @@ class SettingsSeeder extends Seeder
|
||||
$setting_group->title = 'app.settings.miscellaneous';
|
||||
$setting_group->save();
|
||||
}
|
||||
if (! $setting_group = SettingGroup::find(4)) {
|
||||
$setting_group = new SettingGroup;
|
||||
$setting_group->id = 4;
|
||||
$setting_group->title = 'app.settings.advanced';
|
||||
$setting_group->order = 3;
|
||||
$setting_group->save();
|
||||
} else {
|
||||
$setting_group->title = 'app.settings.advanced';
|
||||
$setting_group->save();
|
||||
}
|
||||
|
||||
if($version = Setting::find(1)) {
|
||||
if ($version = Setting::find(1)) {
|
||||
$version->label = 'app.settings.version';
|
||||
$version->value = config('app.version');
|
||||
$version->save();
|
||||
@@ -61,7 +71,7 @@ class SettingsSeeder extends Seeder
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if(!$setting = Setting::find(2)) {
|
||||
if (! $setting = Setting::find(2)) {
|
||||
$setting = new Setting;
|
||||
$setting->id = 2;
|
||||
$setting->group_id = 2;
|
||||
@@ -73,7 +83,7 @@ class SettingsSeeder extends Seeder
|
||||
$setting->label = 'app.settings.background_image';
|
||||
$setting->save();
|
||||
}
|
||||
if(!$setting = Setting::find(3)) {
|
||||
if (! $setting = Setting::find(3)) {
|
||||
$setting = new Setting;
|
||||
$setting->id = 3;
|
||||
$setting->group_id = 3;
|
||||
@@ -90,12 +100,12 @@ class SettingsSeeder extends Seeder
|
||||
'none' => 'app.options.none',
|
||||
'google' => 'app.options.google',
|
||||
'ddg' => 'app.options.ddg',
|
||||
'qwant' => 'app.options.qwant',
|
||||
'bing' => 'app.options.bing',
|
||||
'startpage' => 'app.options.startpage',
|
||||
]);
|
||||
|
||||
if(!$setting = Setting::find(4)) {
|
||||
|
||||
if (! $setting = Setting::find(4)) {
|
||||
$setting = new Setting;
|
||||
$setting->id = 4;
|
||||
$setting->group_id = 3;
|
||||
@@ -110,20 +120,21 @@ class SettingsSeeder extends Seeder
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
|
||||
$language_options = json_encode([
|
||||
'de' => 'Deutsch (German)',
|
||||
'en' => 'English',
|
||||
'cn' => '简体中文 (Simplified Chinese)',
|
||||
'fi' => 'Suomi (Finnish)',
|
||||
'fr' => 'Français (French)',
|
||||
'el' => 'Ελληνικά (Greek)',
|
||||
'it' => 'Italiano (Italian)',
|
||||
'no' => 'Norsk (Norwegian)',
|
||||
'pl' => 'Polski (Polish)',
|
||||
'no' => 'Norsk (Norwegian)',
|
||||
'pl' => 'Polski (Polish)',
|
||||
'sv' => 'Svenska (Swedish)',
|
||||
'es' => 'Español (Spanish)',
|
||||
'tr' => 'Türkçe (Turkish)',
|
||||
]);
|
||||
if($languages = Setting::find(5)) {
|
||||
if ($languages = Setting::find(5)) {
|
||||
$languages->options = $language_options;
|
||||
$languages->save();
|
||||
} else {
|
||||
@@ -144,8 +155,7 @@ class SettingsSeeder extends Seeder
|
||||
'_blank' => 'app.settings.window_target.new',
|
||||
]);
|
||||
|
||||
if(!$setting = Setting::find(7)) {
|
||||
|
||||
if (! $setting = Setting::find(7)) {
|
||||
$setting = new Setting;
|
||||
$setting->id = 7;
|
||||
$setting->group_id = 3;
|
||||
@@ -161,7 +171,7 @@ class SettingsSeeder extends Seeder
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if($support = Setting::find(8)) {
|
||||
if ($support = Setting::find(8)) {
|
||||
$support->label = 'app.settings.support';
|
||||
$support->value = '<a rel="noopener" target="_blank" href="https://discord.gg/CCjHKn4">Discord</a> | <a rel="noopener" target="_blank" href="https://github.com/linuxserver/Heimdall">Github</a> | <a rel="noopener" target="_blank" href="https://blog.heimdall.site/">Blog</a>';
|
||||
$support->save();
|
||||
@@ -177,7 +187,7 @@ class SettingsSeeder extends Seeder
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if($donate = Setting::find(9)) {
|
||||
if ($donate = Setting::find(9)) {
|
||||
$donate->label = 'app.settings.donate';
|
||||
$donate->value = '<a rel="noopener" target="_blank" href="https://www.paypal.me/heimdall">Paypal</a>';
|
||||
$donate->save();
|
||||
@@ -193,5 +203,55 @@ class SettingsSeeder extends Seeder
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if (! $setting = Setting::find(10)) {
|
||||
$setting = new Setting;
|
||||
$setting->id = 10;
|
||||
$setting->group_id = 4;
|
||||
$setting->key = 'custom_css';
|
||||
$setting->type = 'textarea';
|
||||
$setting->label = 'app.settings.custom_css';
|
||||
$setting->value = '';
|
||||
$setting->save();
|
||||
} else {
|
||||
$setting->type = 'textarea';
|
||||
$setting->group_id = 4;
|
||||
$setting->label = 'app.settings.custom_css';
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if (! $setting = Setting::find(11)) {
|
||||
$setting = new Setting;
|
||||
$setting->id = 11;
|
||||
$setting->group_id = 4;
|
||||
$setting->key = 'custom_js';
|
||||
$setting->type = 'textarea';
|
||||
$setting->label = 'app.settings.custom_js';
|
||||
$setting->value = '';
|
||||
$setting->save();
|
||||
} else {
|
||||
$setting->type = 'textarea';
|
||||
$setting->group_id = 4;
|
||||
$setting->label = 'app.settings.custom_js';
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if (! $home_tag = \App\Item::find(0)) {
|
||||
$home_tag = new \App\Item;
|
||||
$home_tag->id = 0;
|
||||
$home_tag->title = 'app.dashboard';
|
||||
$home_tag->pinned = 0;
|
||||
$home_tag->url = '';
|
||||
$home_tag->type = 1;
|
||||
$home_tag->user_id = 0;
|
||||
$home_tag->save();
|
||||
|
||||
$homeapps = \App\Item::withoutGlobalScope('user_id')->doesntHave('parents')->get();
|
||||
foreach ($homeapps as $app) {
|
||||
if ($app->id === 0) {
|
||||
continue;
|
||||
}
|
||||
$app->parents()->attach(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class UsersSeeder extends Seeder
|
||||
{
|
||||
@@ -13,7 +13,7 @@ class UsersSeeder extends Seeder
|
||||
public function run()
|
||||
{
|
||||
// Groups
|
||||
if(!$user = User::find(1)) {
|
||||
if (! $user = User::find(1)) {
|
||||
$user = new User;
|
||||
$user->id = 1;
|
||||
$user->username = 'admin';
|
||||
|
||||
9975
package-lock.json
generated
9975
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@@ -10,12 +10,14 @@
|
||||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bootstrap-sass": "^3.3.7",
|
||||
"bootstrap-sass": "^3.4.1",
|
||||
"cross-env": "^5.2.0",
|
||||
"jquery": "^3.2",
|
||||
"laravel-mix": "^2.1.14"
|
||||
"jquery": "^3.4.1",
|
||||
"laravel-mix": "^4.0.16",
|
||||
"sass": "^1.21.0",
|
||||
"sass-loader": "7.*"
|
||||
},
|
||||
"dependencies": {
|
||||
"select2": "^4.0.6-rc.1"
|
||||
"select2": "^4.0.7"
|
||||
}
|
||||
}
|
||||
|
||||
32
phpunit.xml
32
phpunit.xml
@@ -1,21 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false">
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Feature">
|
||||
<directory suffix="Test.php">./tests/Feature</directory>
|
||||
</testsuite>
|
||||
|
||||
<testsuite name="Unit">
|
||||
<directory suffix="Test.php">./tests/Unit</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Feature">
|
||||
<directory suffix="Test.php">./tests/Feature</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
@@ -23,9 +18,14 @@
|
||||
</whitelist>
|
||||
</filter>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="CACHE_DRIVER" value="array"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
<env name="QUEUE_DRIVER" value="sync"/>
|
||||
<server name="APP_ENV" value="testing"/>
|
||||
<server name="BCRYPT_ROUNDS" value="4"/>
|
||||
<server name="CACHE_DRIVER" value="array"/>
|
||||
<!-- <server name="DB_CONNECTION" value="sqlite"/> -->
|
||||
<!-- <server name="DB_DATABASE" value=":memory:"/> -->
|
||||
<server name="MAIL_MAILER" value="array"/>
|
||||
<server name="QUEUE_CONNECTION" value="sync"/>
|
||||
<server name="SESSION_DRIVER" value="array"/>
|
||||
<server name="TELESCOPE_ENABLED" value="false"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
</phpunit>
|
||||
5
public/css/all.min.css
vendored
Normal file
5
public/css/all.min.css
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/*!
|
||||
* Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license (Commercial License)
|
||||
*/
|
||||
.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-ban:before{content:"\f05e"}.fa-check:before{content:"\f00c"}.fa-cloud-download:before{content:"\f0ed"}.fa-cogs:before{content:"\f085"}.fa-edit:before{content:"\f044"}.fa-exchange:before{content:"\f0ec"}.fa-list:before{content:"\f03a"}.fa-pencil:before{content:"\f040"}.fa-plus:before{content:"\f067"}.fa-save:before{content:"\f0c7"}.fa-tag:before{content:"\f02b"}.fa-th:before{content:"\f00a"}.fa-thumbtack:before{content:"\f08d"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-user:before{content:"\f007"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Pro";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Pro";font-weight:900}
|
||||
4766
public/css/app.css
vendored
4766
public/css/app.css
vendored
File diff suppressed because it is too large
Load Diff
843
public/js/app.js
vendored
843
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
2482
public/js/fontawesome.js
vendored
Normal file
2482
public/js/fontawesome.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/jquery-3.3.1.min.js
vendored
2
public/js/jquery-3.3.1.min.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/jquery-3.6.0.min.js
vendored
Normal file
2
public/js/jquery-3.6.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/manifest.json
generated
2
public/manifest.json
generated
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "App",
|
||||
"name": "Heimdall",
|
||||
"icons": [
|
||||
{
|
||||
"src": "\/android-icon-36x36.png",
|
||||
|
||||
6
public/mix-manifest.json
generated
6
public/mix-manifest.json
generated
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"/css/app.css": "/css/app.css?id=fb2cfb67b5f04db8beee",
|
||||
"/js/app.js": "/js/app.js?id=8dc4a6ea723d0df7469d"
|
||||
}
|
||||
"/css/app.css": "/css/app.css?id=ad45b1705b7f7906db0b",
|
||||
"/js/app.js": "/js/app.js?id=5446aeb4aa754e641c77"
|
||||
}
|
||||
|
||||
99
readme.md
99
readme.md
@@ -29,82 +29,41 @@ You can use the app to link to any site or application, but Foundation apps will
|
||||
|
||||
Supported applications are recognized by the title of the application as entered in the title field when adding an application. For example, to add a link to pfSense, begin by typing "p" in the title field and then select "pfSense" from the list of supported applications.
|
||||
|
||||
**Enhanced**
|
||||
- CouchPotato
|
||||
- Deluge
|
||||
- NZBGet
|
||||
- Pihole
|
||||
- PlexPy
|
||||
- Proxmox
|
||||
- Runeaudio
|
||||
- Sabnzbd
|
||||
- Tautulli
|
||||
- Traefik
|
||||
- Transmission
|
||||
[](https://apps.heimdall.site/applications/enhanced)
|
||||
|
||||
**Foundation**
|
||||
- AirSonic
|
||||
- Bazarr
|
||||
- Bitwarden
|
||||
- Booksonic
|
||||
- BookStack
|
||||
- Cardigann
|
||||
- DokuWiki
|
||||
- Duplicati
|
||||
- Emby
|
||||
- FreshRSS
|
||||
- Gitea
|
||||
- Grafana
|
||||
- Graylog
|
||||
- Headphones
|
||||
- Jdownloader
|
||||
- Krusader
|
||||
- LibreNMS
|
||||
- Lidarr
|
||||
- Mailcow
|
||||
- McMyAdmin
|
||||
- Medusa
|
||||
- Monica
|
||||
- MusicBrainz
|
||||
- Mylar
|
||||
- NZBhydra & NZBhydra2
|
||||
- Netdata
|
||||
- Nextcloud
|
||||
- Ombi
|
||||
- OpenHAB
|
||||
- OpenMediaVault
|
||||
- Plex
|
||||
- Plexrequests
|
||||
- Portainer
|
||||
- Radarr
|
||||
- Rancher
|
||||
- SickRage
|
||||
- Sonarr
|
||||
- TT-RSS
|
||||
- TVheadend
|
||||
- UniFI
|
||||
- unRAID
|
||||
- pfSense
|
||||
- pyLoad
|
||||
- rTorrent/Flood
|
||||
- rTorrent/ruTorrent
|
||||
- Syncthing
|
||||
- Virtualmin
|
||||
- Watcher3
|
||||
- Webmin
|
||||
- WebTools
|
||||
[](https://apps.heimdall.site/applications/foundation)
|
||||
|
||||
## Installing
|
||||
Apart from the Laravel dependencies, namely PHP >= 7.1.3, OpenSSL PHP Extension, PDO PHP Extension, Mbstring PHP Extension, Tokenizer PHP Extension, XML PHP Extension, Ctype PHP Extension and JSON PHP Extension, the only other thing Heimdall needs is sqlite support.
|
||||
Apart from the Laravel dependencies, namely PHP >= 7.2.5, BCMath PHP Extension, Ctype PHP Extension, Fileinfo PHP extension, JSON PHP Extension, Mbstring PHP Extension, OpenSSL PHP Extension, PDO PHP Extension, Tokenizer PHP Extension, XML PHP Extension, the only other thing Heimdall needs is sqlite support and zip support (php-zip).
|
||||
|
||||
If you find you can't change the background make sure `php_fileinfo` is enabled in your php.ini. I believe it should be by default, but one user came across the issue on a windows system.
|
||||
|
||||
Installation is as simple as cloning the repository somewhere, or downloading and extracting the zip/tar and pointing your httpd document root to the `/public` folder. For simple testing you could just go to the folder and type `php artisan serve`
|
||||
Installation is as simple as cloning the repository somewhere, or downloading and extracting the zip/tar and pointing your httpd document root to the `/public` folder then creating the .env file and generating an encryption key (this is all taken care of for you with the docker).
|
||||
|
||||
```
|
||||
cd /path/to/heimdall
|
||||
cp .env.example .env
|
||||
php artisan key:generate
|
||||
```
|
||||
|
||||
For simple testing you could just go to the folder and type `php artisan serve`
|
||||
|
||||
There is also a multi-arch Docker which supports x86-64, armhf and arm64, instructions on how to use them at
|
||||
|
||||
- https://hub.docker.com/r/linuxserver/heimdall/
|
||||
|
||||
## Updating
|
||||
To update your instance, simply clone this repository or download the zip/tar file with the new version and copy it over the old installation.
|
||||
|
||||
## Search Providers
|
||||
v2.3.0 added the ability for users to customise the search options.
|
||||
|
||||
Options are stored in `/storage/app/searchproviders.yaml` (`/config/www/searchproviders.yaml` on docker installs), feel free to rearrange the options, add new ones, delete ones you don't use, etc.
|
||||
|
||||
Consider contributing to https://github.com/linuxserver/Heimdall/discussions/categories/search-providers to help others add new ones.
|
||||
|
||||
The item at the top of the list `Tiles` allows you to search for apps on your dashboard by name, helpful when you have lots of icons.
|
||||
|
||||
## New background image not being set
|
||||
If you are using the docker image or a default php install you may find images over 2MB wont get set as the background image, you just need to change the `upload_max_filesize` in the php.ini.
|
||||
|
||||
@@ -131,12 +90,15 @@ Currently added languages are
|
||||
- Swedish
|
||||
- Spanish
|
||||
- Turkish
|
||||
- Russian
|
||||
- Chinese
|
||||
|
||||
## Web Server Configuration
|
||||
|
||||
### Apache
|
||||
A `.htaccess` file ships with the app, however, a lot of apache installations disallow `.htaccess` files by default.
|
||||
You will notice this due to some links not working like `/settings`.
|
||||
In addition mod-rewrite needs to be enabled if it isn't already.
|
||||
|
||||
#### Fixes & work around options
|
||||
##### - Apache global allow .htaccess
|
||||
@@ -181,7 +143,7 @@ location /webfonts {
|
||||
If there are any other locations which might interfere with any of the folders in the `/public` folder, you might have to do the same for those as well, but it's a super fringe case.
|
||||
|
||||
### Reverse proxy
|
||||
If you'd like to reverse proxy this app, we recommend using our letsencrypt/nginx docker image: [Letsencrypt/Nginx](https://hub.docker.com/r/linuxserver/letsencrypt/)
|
||||
If you'd like to reverse proxy this app, we recommend using our letsencrypt/nginx docker image: [SWAG - Secure Web Application Gateway](https://hub.docker.com/r/linuxserver/swag)
|
||||
You can either reverse proxy from the root location, or from a subdomain (subfolder method is currently not supported). For HTTPS proxy, make sure you use the HTTPS port of Heimdall webserver, otherwise some links may break. You can add security through `.htpasswd`
|
||||
|
||||
```
|
||||
@@ -189,12 +151,11 @@ location / {
|
||||
auth_basic "Restricted";
|
||||
auth_basic_user_file /config/nginx/.htpasswd;
|
||||
include /config/nginx/proxy.conf;
|
||||
proxy_pass https://heimdall:443;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_pass http://heimdall;
|
||||
}
|
||||
```
|
||||
|
||||
If you are using HTTPS and things aren't working try adding `FORCE_HTTPS=true` to the end of your `.env` file or proxy to the https version of the app.
|
||||
|
||||
### Self-signed certificates and local CAs
|
||||
Per default Heimdall uses the standard certificate bundle file (`ca-certificates.crt`) to verify HTTPS sites and will ignore additional certificates placed in `/etc/ssl/certs`. If you wish to use enhanced apps with HTTPS sites that use a self-signed certificate or certs signed with your own local CA, you can override the default bundle:
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
$.when( $.ready ).then(function() {
|
||||
|
||||
var base = (document.querySelector('base') || {}).href;
|
||||
|
||||
if($('.message-container').length) {
|
||||
setTimeout(
|
||||
function()
|
||||
@@ -8,17 +10,57 @@ $.when( $.ready ).then(function() {
|
||||
}, 3500);
|
||||
}
|
||||
|
||||
if($('.livestats-container').length) {
|
||||
$('.livestats-container').each(function(index){
|
||||
// from https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
|
||||
// Set the name of the hidden property and the change event for visibility
|
||||
var hidden, visibilityChange;
|
||||
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
|
||||
hidden = "hidden";
|
||||
visibilityChange = "visibilitychange";
|
||||
} else if (typeof document.msHidden !== "undefined") {
|
||||
hidden = "msHidden";
|
||||
visibilityChange = "msvisibilitychange";
|
||||
} else if (typeof document.webkitHidden !== "undefined") {
|
||||
hidden = "webkitHidden";
|
||||
visibilityChange = "webkitvisibilitychange";
|
||||
}
|
||||
|
||||
var livestatsRefreshTimeouts = [];
|
||||
var livestatsFuncs = [];
|
||||
var livestatsContainers = $('.livestats-container');
|
||||
function stopLivestatsRefresh() {
|
||||
for (var timeoutId of livestatsRefreshTimeouts) {
|
||||
window.clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
function startLivestatsRefresh() {
|
||||
for (var fun of livestatsFuncs) {
|
||||
fun();
|
||||
}
|
||||
}
|
||||
|
||||
if (livestatsContainers.length > 0) {
|
||||
if (typeof document.addEventListener === "undefined" || hidden === undefined) {
|
||||
console.log("This browser does not support visibilityChange");
|
||||
} else {
|
||||
document.addEventListener(visibilityChange, function() {
|
||||
if (document[hidden]) {
|
||||
stopLivestatsRefresh();
|
||||
} else {
|
||||
startLivestatsRefresh();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
livestatsContainers.each(function(index){
|
||||
var id = $(this).data('id');
|
||||
var dataonly = $(this).data('dataonly');
|
||||
var increaseby = (dataonly == 1) ? 20000 : 1000;
|
||||
var container = $(this);
|
||||
var max_timer = 30000;
|
||||
var timer = 5000;
|
||||
(function worker() {
|
||||
var fun = function worker() {
|
||||
$.ajax({
|
||||
url: '/get_stats/'+id,
|
||||
url: base+'get_stats/'+id,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
container.html(data.html);
|
||||
@@ -29,10 +71,12 @@ $.when( $.ready ).then(function() {
|
||||
},
|
||||
complete: function() {
|
||||
// Schedule the next request when the current one's complete
|
||||
setTimeout(worker, timer);
|
||||
livestatsRefreshTimeouts[index] = window.setTimeout(worker, timer);
|
||||
}
|
||||
});
|
||||
})();
|
||||
};
|
||||
livestatsFuncs[index] = fun;
|
||||
fun();
|
||||
});
|
||||
|
||||
}
|
||||
@@ -76,7 +120,7 @@ $.when( $.ready ).then(function() {
|
||||
attribute: 'data-id'
|
||||
});
|
||||
$.post(
|
||||
'/order',
|
||||
base+'order',
|
||||
{ order:idsInOrder }
|
||||
);
|
||||
}
|
||||
@@ -84,7 +128,49 @@ $.when( $.ready ).then(function() {
|
||||
});
|
||||
$('#sortable').sortable('disable');
|
||||
|
||||
$('#sortable').on('mouseenter', '.item', function () {
|
||||
$(this).siblings('.tooltip').addClass('active')
|
||||
$('.refresh', this).addClass('active')
|
||||
}).on('mouseleave', '.item', function () {
|
||||
$(this).siblings('.tooltip').removeClass('active')
|
||||
$('.refresh', this).removeClass('active')
|
||||
})
|
||||
|
||||
$('#search-container').on('input', 'input[name=q]', function () {
|
||||
const search = this.value
|
||||
const items = $('#sortable').children('.item-container')
|
||||
if($('#search-container select[name=provider]').val() === 'tiles') {
|
||||
if(search.length > 0) {
|
||||
items.hide()
|
||||
items.filter(function () {
|
||||
const name = $(this).data('name').toLowerCase();
|
||||
return name.includes(search.toLowerCase())
|
||||
}).show()
|
||||
} else {
|
||||
items.show()
|
||||
}
|
||||
} else {
|
||||
items.show()
|
||||
}
|
||||
}).on('change', 'select[name=provider]', function () {
|
||||
const items = $('#sortable').children('.item-container')
|
||||
if($(this).val() === 'tiles') {
|
||||
$('#search-container button').hide()
|
||||
const search = $('#search-container input[name=q]').val()
|
||||
if(search.length > 0) {
|
||||
items.hide()
|
||||
items.filter(function () {
|
||||
const name = $(this).data('name').toLowerCase();
|
||||
return name.includes(search.toLowerCase())
|
||||
}).show()
|
||||
} else {
|
||||
items.show()
|
||||
}
|
||||
} else {
|
||||
$('#search-container button').show()
|
||||
items.show()
|
||||
}
|
||||
})
|
||||
|
||||
$('#app').on('click', '#config-button', function(e) {
|
||||
e.preventDefault();
|
||||
@@ -119,7 +205,7 @@ $.when( $.ready ).then(function() {
|
||||
e.preventDefault();
|
||||
var apiurl = $('#create input[name=url]').val();
|
||||
|
||||
var override_url = $('#create input[name="config[override_url]"]').val();
|
||||
var override_url = $('#sapconfig input[name="config[override_url]"]').val();
|
||||
if(override_url.length && override_url != '') {
|
||||
apiurl = override_url;
|
||||
}
|
||||
@@ -131,7 +217,7 @@ $.when( $.ready ).then(function() {
|
||||
data[config] = $(this).val();
|
||||
});
|
||||
|
||||
$.post('/test_config', { data: data }, function(data) {
|
||||
$.post(base+'test_config', { data: data }, function(data) {
|
||||
alert(data);
|
||||
});
|
||||
|
||||
@@ -140,7 +226,8 @@ $.when( $.ready ).then(function() {
|
||||
e.preventDefault();
|
||||
var current = $(this);
|
||||
var id = current.data('id');
|
||||
$.get('items/pintoggle/'+id+'/true', function(data) {
|
||||
var tag = current.data('tag');
|
||||
$.get(base+'items/pintoggle/'+id+'/true/'+tag, function(data) {
|
||||
var inner = $(data).filter('#sortable').html();
|
||||
$('#sortable').html(inner);
|
||||
current.toggleClass('active');
|
||||
|
||||
@@ -47,6 +47,66 @@ body {
|
||||
}
|
||||
}
|
||||
}
|
||||
#tile-preview {
|
||||
align-items: center;
|
||||
}
|
||||
.create {
|
||||
.textarea {
|
||||
width: 100%;
|
||||
margin: 0px 20px;
|
||||
textarea{
|
||||
width: 100%;
|
||||
border: 1px solid #dedfe2;
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
height: 100px;
|
||||
font-size: 14px;
|
||||
}
|
||||
label:not(.switch) {
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
color: lighten($app-text, 40%);
|
||||
margin-bottom: 15px;
|
||||
display: block;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
.appoptions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
gap: 5px;
|
||||
.optdetails {
|
||||
display: flex;
|
||||
.input {
|
||||
margin: 0 20px;
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
.optvalue {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
&.active {
|
||||
opacity: 1;
|
||||
width: auto;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
button.dark {
|
||||
background: #1b1b1b;
|
||||
border: none;
|
||||
padding: 12px 15px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
min-width: 240px;
|
||||
}
|
||||
}
|
||||
#app {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
@@ -200,6 +260,59 @@ body {
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
display: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
padding: 25px;
|
||||
border-radius: 5px;
|
||||
background: #000000c8;
|
||||
color: white;
|
||||
position: absolute;
|
||||
bottom: 120px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
font-size: 13px;
|
||||
backdrop-filter: blur(8px);
|
||||
z-index: 0;
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
transition: all 0.3s;
|
||||
&.active {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
z-index: 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tile-actions {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0;
|
||||
padding: 7px;
|
||||
background: #000000d9;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
border-radius: 6px;
|
||||
width: 80px;
|
||||
height: 90px;
|
||||
display: flex;
|
||||
opacity: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.refresh {
|
||||
z-index: 3;
|
||||
.icon {
|
||||
font-size: 20px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
.black {
|
||||
@@ -434,6 +547,8 @@ body {
|
||||
padding: 20px 25px;
|
||||
font-size: 13px;
|
||||
color: $app-text;
|
||||
max-width: 500px;
|
||||
word-break: break-word;
|
||||
&.form-error {
|
||||
background: #e69191;
|
||||
color: white;
|
||||
@@ -509,6 +624,15 @@ body {
|
||||
}
|
||||
}
|
||||
}
|
||||
.input {
|
||||
position: relative;
|
||||
.help {
|
||||
position: absolute;
|
||||
bottom: -22px;
|
||||
left: 10px;
|
||||
color: #c00;
|
||||
}
|
||||
}
|
||||
div.create {
|
||||
padding: 30px 15px;
|
||||
display: flex;
|
||||
@@ -532,10 +656,19 @@ div.create {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app-icon-container {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 15px;
|
||||
flex: 0 0 60px;
|
||||
}
|
||||
.app-icon {
|
||||
max-width: 60px;
|
||||
margin-right: 15px;
|
||||
display: block;
|
||||
max-height: 60px;
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
@@ -574,6 +707,41 @@ div.create {
|
||||
color: #91a1b3;
|
||||
margin-left: 20px;
|
||||
}
|
||||
#websiteiconoptions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
.results {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.selectclose {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.iconbutton {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.selecticon {
|
||||
max-width: 120px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
@@ -691,7 +859,9 @@ div.create {
|
||||
border-bottom: 1px solid rgba(255,255,255,0.35);
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
max-width: 620px;
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
form {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -701,6 +871,8 @@ div.create {
|
||||
box-shadow: 0px 0px 5px 0 rgba(0,0,0,0.4);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
}
|
||||
input {
|
||||
padding: 17px 15px;
|
||||
@@ -724,6 +896,12 @@ div.create {
|
||||
text-transform: uppercase;
|
||||
background: $app-red;
|
||||
}
|
||||
select {
|
||||
padding: 0 10px;
|
||||
background: #f5f5f5;
|
||||
border: none;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-autocomplete {
|
||||
@@ -774,7 +952,7 @@ div.create {
|
||||
|
||||
#appimage {
|
||||
img {
|
||||
max-width: 95px;
|
||||
width: 95px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -866,11 +1044,6 @@ hr {
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
||||
li {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
span {
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
@@ -893,11 +1066,30 @@ hr {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
li {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
&.right {
|
||||
text-align: right;
|
||||
span {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.flexcolumn {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
}
|
||||
&.black {
|
||||
.livestats {
|
||||
strong {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input:-webkit-autofill,
|
||||
|
||||
4
resources/assets/sass/app.scss
vendored
4
resources/assets/sass/app.scss
vendored
@@ -15,9 +15,5 @@
|
||||
// Huebee
|
||||
@import "huebee";
|
||||
|
||||
// fontawesome
|
||||
@import "fontawesome/fontawesome";
|
||||
@import "fontawesome/fa-solid";
|
||||
|
||||
@import "select2";
|
||||
|
||||
|
||||
BIN
resources/assets/sass/fontawesome/.__animated.scss
vendored
BIN
resources/assets/sass/fontawesome/.__animated.scss
vendored
Binary file not shown.
Binary file not shown.
BIN
resources/assets/sass/fontawesome/.__core.scss
vendored
BIN
resources/assets/sass/fontawesome/.__core.scss
vendored
Binary file not shown.
Binary file not shown.
BIN
resources/assets/sass/fontawesome/.__icons.scss
vendored
BIN
resources/assets/sass/fontawesome/.__icons.scss
vendored
Binary file not shown.
BIN
resources/assets/sass/fontawesome/.__larger.scss
vendored
BIN
resources/assets/sass/fontawesome/.__larger.scss
vendored
Binary file not shown.
BIN
resources/assets/sass/fontawesome/.__list.scss
vendored
BIN
resources/assets/sass/fontawesome/.__list.scss
vendored
Binary file not shown.
BIN
resources/assets/sass/fontawesome/.__mixins.scss
vendored
BIN
resources/assets/sass/fontawesome/.__mixins.scss
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
resources/assets/sass/fontawesome/.__stacked.scss
vendored
BIN
resources/assets/sass/fontawesome/.__stacked.scss
vendored
Binary file not shown.
BIN
resources/assets/sass/fontawesome/.__variables.scss
vendored
BIN
resources/assets/sass/fontawesome/.__variables.scss
vendored
Binary file not shown.
BIN
resources/assets/sass/fontawesome/._fa-brands.scss
vendored
BIN
resources/assets/sass/fontawesome/._fa-brands.scss
vendored
Binary file not shown.
BIN
resources/assets/sass/fontawesome/._fa-light.scss
vendored
BIN
resources/assets/sass/fontawesome/._fa-light.scss
vendored
Binary file not shown.
BIN
resources/assets/sass/fontawesome/._fa-regular.scss
vendored
BIN
resources/assets/sass/fontawesome/._fa-regular.scss
vendored
Binary file not shown.
BIN
resources/assets/sass/fontawesome/._fa-solid.scss
vendored
BIN
resources/assets/sass/fontawesome/._fa-solid.scss
vendored
Binary file not shown.
BIN
resources/assets/sass/fontawesome/._fontawesome.scss
vendored
BIN
resources/assets/sass/fontawesome/._fontawesome.scss
vendored
Binary file not shown.
20
resources/assets/sass/fontawesome/_animated.scss
vendored
20
resources/assets/sass/fontawesome/_animated.scss
vendored
@@ -1,20 +0,0 @@
|
||||
// Animated Icons
|
||||
// --------------------------
|
||||
|
||||
.#{$fa-css-prefix}-spin {
|
||||
animation: fa-spin 2s infinite linear;
|
||||
}
|
||||
|
||||
.#{$fa-css-prefix}-pulse {
|
||||
animation: fa-spin 1s infinite steps(8);
|
||||
}
|
||||
|
||||
@keyframes fa-spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user