mirror of
https://github.com/linuxserver/Heimdall.git
synced 2026-02-23 21:20:32 +09:00
Compare commits
194 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f997d60cd | ||
|
|
d45f5a805e | ||
|
|
fc9c624509 | ||
|
|
33372509eb | ||
|
|
bca0b02925 | ||
|
|
24995135e6 | ||
|
|
c1e4103edd | ||
|
|
6eda423156 | ||
|
|
7dc72d3519 | ||
|
|
907c22179b | ||
|
|
cdafbab7b1 | ||
|
|
e0064504e7 | ||
|
|
b22117dd01 | ||
|
|
c88efa8dbc | ||
|
|
7d060ff803 | ||
|
|
d5f8b6aae0 | ||
|
|
2416993c5e | ||
|
|
494165a03a | ||
|
|
88e607533c | ||
|
|
035d2f9209 | ||
|
|
53903daa87 | ||
|
|
567994be1a | ||
|
|
32fa27337a | ||
|
|
e1bb7646ac | ||
|
|
108b636def | ||
|
|
4abb14bf54 | ||
|
|
f8f96593c1 | ||
|
|
cb21b0f8f1 | ||
|
|
4c8c5fa27f | ||
|
|
6093119dde | ||
|
|
15755a3fd1 | ||
|
|
0213c81e0d | ||
|
|
c47f296f17 | ||
|
|
75133474f7 | ||
|
|
ddbe171f3a | ||
|
|
12e109f82c | ||
|
|
e095589172 | ||
|
|
d0293c785b | ||
|
|
aa351e31bf | ||
|
|
aceed3d13b | ||
|
|
10b70d4a09 | ||
|
|
cb9e014cf3 | ||
|
|
99017d834e | ||
|
|
fb73f5ca24 | ||
|
|
4369f1aeda | ||
|
|
6501aacb1b | ||
|
|
c3da17befc | ||
|
|
46bb073001 | ||
|
|
e8b47776ce | ||
|
|
6941fd3e2d | ||
|
|
f5937879df | ||
|
|
93877b7025 | ||
|
|
6612631cc3 | ||
|
|
30c3079a90 | ||
|
|
e86e681c53 | ||
|
|
48f72652da | ||
|
|
a3f7bafedb | ||
|
|
d30d610042 | ||
|
|
882e406266 | ||
|
|
45d421256c | ||
|
|
a2f20fc18f | ||
|
|
988364cb7c | ||
|
|
a3816ed8a1 | ||
|
|
d48805ee2c | ||
|
|
e820b81259 | ||
|
|
8b1046ce17 | ||
|
|
a138b65842 | ||
|
|
c344de3f04 | ||
|
|
427659a897 | ||
|
|
a6543970e7 | ||
|
|
399ea088dc | ||
|
|
3f87833e52 | ||
|
|
6dcb77023c | ||
|
|
4d37135bdf | ||
|
|
d109047fa5 | ||
|
|
b6112501e2 | ||
|
|
0663e236b4 | ||
|
|
f25cea1749 | ||
|
|
03e16415aa | ||
|
|
9a55e05943 | ||
|
|
c06fa4eab6 | ||
|
|
5575b082ea | ||
|
|
1c6da858bc | ||
|
|
f0a14641c1 | ||
|
|
c6d07cd8a4 | ||
|
|
df9f07faf4 | ||
|
|
a3dcc278d7 | ||
|
|
5de473fa44 | ||
|
|
763c1545a6 | ||
|
|
ecde7a0f32 | ||
|
|
7fc5e0abb5 | ||
|
|
06a655ac0c | ||
|
|
875ddaa834 | ||
|
|
030fccbb50 | ||
|
|
908f70d90a | ||
|
|
8724ced531 | ||
|
|
aa1a3a95ca | ||
|
|
0767dc075e | ||
|
|
c8a6c89036 | ||
|
|
cafe386cc4 | ||
|
|
0184c9695b | ||
|
|
19536edf28 | ||
|
|
045e4a20fa | ||
|
|
6cb8487a52 | ||
|
|
c39e9aa13f | ||
|
|
0203440b06 | ||
|
|
7f7bf60456 | ||
|
|
e8673634bc | ||
|
|
53e52c93ee | ||
|
|
c239c0ea5a | ||
|
|
7142f755f5 | ||
|
|
9fbc8dc1f9 | ||
|
|
d3819a6a88 | ||
|
|
6e93ed8e5f | ||
|
|
98543d49a9 | ||
|
|
9195eead27 | ||
|
|
e5b384736d | ||
|
|
4def720d1a | ||
|
|
2a0404ea17 | ||
|
|
6d22c4f02e | ||
|
|
24ac12da65 | ||
|
|
3f19882df8 | ||
|
|
dd54c16c1f | ||
|
|
223e9289dc | ||
|
|
2e301bdd51 | ||
|
|
e3ec7de23a | ||
|
|
18ec208381 | ||
|
|
8666daa07d | ||
|
|
926a9bdb03 | ||
|
|
fc2d837a2c | ||
|
|
3f69ccab99 | ||
|
|
b6ee82ee52 | ||
|
|
da1eb859a9 | ||
|
|
2b5269b823 | ||
|
|
6c8eeb0ced | ||
|
|
c5e0f3abc8 | ||
|
|
c6dbe22c57 | ||
|
|
51776e2aa3 | ||
|
|
c9d24607f6 | ||
|
|
46f7a3d4f3 | ||
|
|
56cf450c89 | ||
|
|
38c350b020 | ||
|
|
1f46040f1b | ||
|
|
63b95319cd | ||
|
|
a25d92be9e | ||
|
|
a161210a4a | ||
|
|
24469eb2fa | ||
|
|
a93fb49875 | ||
|
|
08d7cdf95b | ||
|
|
a9334bc247 | ||
|
|
2357d0c466 | ||
|
|
b003d51276 | ||
|
|
503cbf9830 | ||
|
|
2466058c5a | ||
|
|
6b1f422456 | ||
|
|
1d16d67733 | ||
|
|
6f9d15aed8 | ||
|
|
8725f974da | ||
|
|
2551c949ae | ||
|
|
30c6020ce7 | ||
|
|
d00b1ce1a1 | ||
|
|
2c43d79585 | ||
|
|
3e4aacb2b0 | ||
|
|
67cd22371b | ||
|
|
586941ece7 | ||
|
|
32a57cbfa6 | ||
|
|
1837a69b3e | ||
|
|
aa8bfcfd92 | ||
|
|
9e0c658470 | ||
|
|
66aefff4f3 | ||
|
|
bd0fdeecee | ||
|
|
1055eeb01b | ||
|
|
263a4578d4 | ||
|
|
c446b8a5af | ||
|
|
847b34cdcb | ||
|
|
5a57f90b8f | ||
|
|
f8eb9f5bd0 | ||
|
|
c8c336b574 | ||
|
|
43f1410974 | ||
|
|
1df110b3fb | ||
|
|
9bedce0df5 | ||
|
|
ae1d879e5a | ||
|
|
caab2e0952 | ||
|
|
a29d6517d3 | ||
|
|
dae2781818 | ||
|
|
c1de609b1a | ||
|
|
4e84807950 | ||
|
|
41c9cb45d6 | ||
|
|
2d72772f86 | ||
|
|
1cf1f0e04d | ||
|
|
324b88ec2b | ||
|
|
ec64c7ba0b | ||
|
|
67e0f8570e | ||
|
|
1745100705 |
2
.env
2
.env
@@ -28,4 +28,4 @@ MAIL_ENCRYPTION=null
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
44
.gitattributes
vendored
44
.gitattributes
vendored
@@ -1,5 +1,49 @@
|
||||
# Configuration file for Git attributes
|
||||
|
||||
# Core Settings {{{
|
||||
# .gitattributes
|
||||
.gitattributes !filter !diff
|
||||
|
||||
# Line Endings
|
||||
* text=auto
|
||||
|
||||
# Set binary to none-text files
|
||||
*.png -text
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
# GitHub Linguist {{{
|
||||
|
||||
# Exclude files/folder from being detected by the GitHub linguist
|
||||
# statistic.
|
||||
node_modules/* linguist-vendored
|
||||
public/* linguist-generated=true
|
||||
vendor/* linguist-vendored
|
||||
|
||||
# Remove Vue as it's currently not used in the project.
|
||||
resources/assets/js/components/ExampleComponent.vue linguist-vendored
|
||||
|
||||
# System Wide
|
||||
*.css linguist-vendored
|
||||
*.scss linguist-vendored
|
||||
*.js linguist-vendored
|
||||
|
||||
# Include user generated files that's removed bu the setting above.
|
||||
resources/assets/js/app.js linguist-vendored=false
|
||||
resources/assets/sass/_app.scss linguist-vendored=false
|
||||
resources/assets/sass/_rune.scss linguist-vendored=false
|
||||
resources/assets/sass/_variables.scss linguist-vendored=false
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
# Archive Exlude {{{
|
||||
# Exclude files/folders from being exported when creating an archive.
|
||||
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
.travis.yml export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
|
||||
# }}}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -23,4 +23,5 @@ yarn-error.log
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.VolumeIcon.icns
|
||||
storage/app/public/avatars/*
|
||||
|
||||
@@ -10,3 +10,27 @@ function format_bytes($bytes, $is_drive_size = true, $beforeunit = '', $afteruni
|
||||
elseif($labels[$x] == "MB") return(round($bytes, 2).$beforeunit.$labels[$x].$afterunit);
|
||||
else return(round($bytes, 0).$beforeunit.$labels[$x].$afterunit);
|
||||
}
|
||||
|
||||
function get_brightness($hex) {
|
||||
// returns brightness value from 0 to 255
|
||||
// strip off any leading #
|
||||
$hex = str_replace('#', '', $hex);
|
||||
if(strlen($hex) == 3) {
|
||||
$hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
|
||||
}
|
||||
|
||||
$c_r = hexdec(substr($hex, 0, 2));
|
||||
$c_g = hexdec(substr($hex, 2, 2));
|
||||
$c_b = hexdec(substr($hex, 4, 2));
|
||||
|
||||
return (($c_r * 299) + ($c_g * 587) + ($c_b * 114)) / 1000;
|
||||
}
|
||||
|
||||
function title_color($hex)
|
||||
{
|
||||
if(get_brightness($hex) > 130) {
|
||||
return ' black';
|
||||
} else {
|
||||
return ' white';
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,11 @@ namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use App\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
@@ -25,7 +30,7 @@ class LoginController extends Controller
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/home';
|
||||
protected $redirectTo = '/';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
@@ -34,6 +39,88 @@ class LoginController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
Session::put('backUrl', URL::previous());
|
||||
$this->middleware('guest')->except('logout');
|
||||
}
|
||||
|
||||
public function username()
|
||||
{
|
||||
return 'username';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a login request to the application.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function login(Request $request)
|
||||
{
|
||||
$current_user = User::currentUser();
|
||||
$request->merge(['username' => $current_user->username]);
|
||||
//die(print_r($request->all()));
|
||||
$this->validateLogin($request);
|
||||
|
||||
// If the class is using the ThrottlesLogins trait, we can automatically throttle
|
||||
// the login attempts for this application. We'll key this by the username and
|
||||
// the IP address of the client making these requests into this application.
|
||||
if ($this->hasTooManyLoginAttempts($request)) {
|
||||
$this->fireLockoutEvent($request);
|
||||
|
||||
return $this->sendLockoutResponse($request);
|
||||
}
|
||||
|
||||
if ($this->attemptLogin($request)) {
|
||||
return $this->sendLoginResponse($request);
|
||||
}
|
||||
|
||||
// If the login attempt was unsuccessful we will increment the number of attempts
|
||||
// to login and redirect the user back to the login form. Of course, when this
|
||||
// user surpasses their maximum number of attempts they will get locked out.
|
||||
$this->incrementLoginAttempts($request);
|
||||
|
||||
return $this->sendFailedLoginResponse($request);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
}
|
||||
|
||||
public function setUser(User $user)
|
||||
{
|
||||
Auth::logout();
|
||||
session(['current_user' => $user]);
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
|
||||
public function autologin($uuid)
|
||||
{
|
||||
$user = User::where('autologin', $uuid)->first();
|
||||
Auth::login($user);
|
||||
session(['current_user' => $user]);
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application's login form.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function showLoginForm()
|
||||
{
|
||||
return view('auth.login');
|
||||
}
|
||||
|
||||
protected function authenticated(Request $request, $user)
|
||||
{
|
||||
return back();
|
||||
}
|
||||
|
||||
public function redirectTo()
|
||||
{
|
||||
return Session::get('url.intended') ? Session::get('url.intended') : $this->redirectTo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class RegisterController extends Controller
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/home';
|
||||
protected $redirectTo = '/';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
|
||||
@@ -25,7 +25,7 @@ class ResetPasswordController extends Controller
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/home';
|
||||
protected $redirectTo = '/';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
|
||||
@@ -6,8 +6,27 @@ use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\User;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
|
||||
protected $user;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->user = $this->user();
|
||||
//print_r($this->user);
|
||||
return $next($request);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return User::currentUser();
|
||||
}
|
||||
}
|
||||
|
||||
28
app/Http/Controllers/HomeController.php
Normal file
28
app/Http/Controllers/HomeController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application dashboard.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,16 @@ namespace App\Http\Controllers;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Item;
|
||||
use App\Setting;
|
||||
use App\User;
|
||||
use App\SupportedApps\Nzbget;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ItemController extends Controller
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource on the dashboard.
|
||||
*
|
||||
@@ -144,10 +148,13 @@ class ItemController extends Controller
|
||||
}
|
||||
|
||||
$config = Item::checkConfig($request->input('config'));
|
||||
$current_user = User::currentUser();
|
||||
$request->merge([
|
||||
'description' => $config
|
||||
'description' => $config,
|
||||
'user_id' => $current_user->id
|
||||
]);
|
||||
|
||||
|
||||
//die(print_r($request->input('config')));
|
||||
|
||||
$item = Item::create($request->all());
|
||||
@@ -209,8 +216,10 @@ class ItemController extends Controller
|
||||
}
|
||||
|
||||
$config = Item::checkConfig($request->input('config'));
|
||||
$current_user = User::currentUser();
|
||||
$request->merge([
|
||||
'description' => $config
|
||||
'description' => $config,
|
||||
'user_id' => $current_user->id
|
||||
]);
|
||||
|
||||
$item = Item::find($id);
|
||||
|
||||
@@ -5,10 +5,17 @@ namespace App\Http\Controllers;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Setting;
|
||||
use App\SettingGroup;
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
@@ -31,6 +38,7 @@ class SettingsController extends Controller
|
||||
public function edit($id)
|
||||
{
|
||||
$setting = Setting::find($id);
|
||||
//die("s: ".$setting->label);
|
||||
|
||||
if((bool)$setting->system === true) return abort(404);
|
||||
|
||||
@@ -55,6 +63,7 @@ class SettingsController extends Controller
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$setting = Setting::find($id);
|
||||
$user = $this->user();
|
||||
|
||||
if (!is_null($setting)) {
|
||||
$data = Setting::getInput();
|
||||
@@ -64,17 +73,16 @@ class SettingsController extends Controller
|
||||
|
||||
if($request->hasFile('value')) {
|
||||
$path = $request->file('value')->store('backgrounds');
|
||||
$setting->value = $path;
|
||||
$setting_value = $path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
$setting->value = $data->value;
|
||||
$setting_value = $data->value;
|
||||
}
|
||||
|
||||
$setting->save();
|
||||
|
||||
$user->settings()->detach($setting->id);
|
||||
$user->settings()->save($setting, ['uservalue' => $setting_value]);
|
||||
|
||||
$route = route('settings.index', [], false);
|
||||
return redirect($route)
|
||||
->with([
|
||||
@@ -95,10 +103,11 @@ class SettingsController extends Controller
|
||||
*/
|
||||
public function clear($id)
|
||||
{
|
||||
$user = $this->user();
|
||||
$setting = Setting::find($id);
|
||||
if((bool)$setting->system !== true) {
|
||||
$setting->value = '';
|
||||
$setting->save();
|
||||
$user->settings()->detach($setting->id);
|
||||
$user->settings()->save($setting, ['uservalue' => '']);
|
||||
}
|
||||
$route = route('settings.index', [], false);
|
||||
return redirect($route)
|
||||
|
||||
@@ -8,6 +8,10 @@ use DB;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
|
||||
175
app/Http/Controllers/UserController.php
Normal file
175
app/Http/Controllers/UserController.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('allowed')->except(['selectUser']);
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data['users'] = User::all();
|
||||
return view('users.index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$data = [];
|
||||
return view('users.create', $data);
|
||||
}
|
||||
|
||||
public function selectUser()
|
||||
{
|
||||
Auth::logout();
|
||||
$data['users'] = User::all();
|
||||
return view('userselect', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'username' => 'required|max:255|unique:users',
|
||||
'email' => 'required|email',
|
||||
'password' => 'nullable|confirmed',
|
||||
'password_confirmation' => 'nullable'
|
||||
|
||||
]);
|
||||
$user = new User;
|
||||
$user->username = $request->input('username');
|
||||
$user->email = $request->input('email');
|
||||
$user->public_front = $request->input('public_front');
|
||||
|
||||
$password = $request->input('password');
|
||||
if(!empty($password)) {
|
||||
$user->password = bcrypt($password);
|
||||
}
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('avatars');
|
||||
$user->avatar = $path;
|
||||
}
|
||||
|
||||
if ((bool)$request->input('autologin_allow') === true) {
|
||||
$user->autologin = (string)Str::uuid();
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
$route = route('dash', [], false);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.user_updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(User $user)
|
||||
{
|
||||
$data['user'] = $user;
|
||||
return view('users.edit', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, User $user)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'username' => 'required|max:255|unique:users,username,'.$user->id,
|
||||
'email' => 'required|email',
|
||||
'password' => 'nullable|confirmed',
|
||||
'password_confirmation' => 'nullable'
|
||||
]);
|
||||
//die(print_r($request->all()));
|
||||
|
||||
$user->username = $request->input('username');
|
||||
$user->email = $request->input('email');
|
||||
$user->public_front = $request->input('public_front');
|
||||
|
||||
$password = $request->input('password');
|
||||
if(!empty($password)) {
|
||||
$user->password = bcrypt($password);
|
||||
} elseif($password == 'null') {
|
||||
$user->password = null;
|
||||
}
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('avatars');
|
||||
$user->avatar = $path;
|
||||
}
|
||||
|
||||
if ((bool)$request->input('autologin_allow') === true) {
|
||||
$user->autologin = (is_null($user->autologin)) ? (string)Str::uuid() : $user->autologin;
|
||||
} else {
|
||||
$user->autologin = null;
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
$route = route('dash', [], false);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.user_updated'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(User $user)
|
||||
{
|
||||
if($user->id !== 1) {
|
||||
$user->delete();
|
||||
$route = route('dash', [], false);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.user_deleted'));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ class Kernel extends HttpKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $routeMiddleware = [
|
||||
'allowed' => \App\Http\Middleware\CheckAllowed::class,
|
||||
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
|
||||
48
app/Http/Middleware/CheckAllowed.php
Normal file
48
app/Http/Middleware/CheckAllowed.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Session;
|
||||
|
||||
class CheckAllowed
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$route = Route::currentRouteName();
|
||||
$current_user = User::currentUser();
|
||||
|
||||
if(str_is('users*', $route)) {
|
||||
if($current_user->id !== 1) {
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
}
|
||||
|
||||
if($route == 'dash') {
|
||||
//print_r(User::all());
|
||||
//die("here".var_dump($current_user->password));
|
||||
if((bool)$current_user->public_front === true) return $next($request);
|
||||
}
|
||||
|
||||
if(empty($current_user->password)) return $next($request);
|
||||
|
||||
// Check if user is logged in as $current_user
|
||||
if (Auth::check()) {
|
||||
$loggedin_user = Auth::user();
|
||||
if($loggedin_user->id === $current_user->id) return $next($request);
|
||||
}
|
||||
|
||||
return Auth::authenticate();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class RedirectIfAuthenticated
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
{
|
||||
if (Auth::guard($guard)->check()) {
|
||||
return redirect('/home');
|
||||
return redirect()->intended();
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
||||
@@ -19,11 +19,5 @@ class TrustProxies extends Middleware
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $headers = [
|
||||
Request::HEADER_FORWARDED => 'FORWARDED',
|
||||
Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
|
||||
Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
|
||||
Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
|
||||
Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
|
||||
];
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
}
|
||||
|
||||
51
app/Item.php
51
app/Item.php
@@ -5,15 +5,26 @@ namespace App;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Symfony\Component\ClassLoader\ClassMapGenerator;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use App\User;
|
||||
|
||||
class Item extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::addGlobalScope('user_id', function (Builder $builder) {
|
||||
$current_user = User::currentUser();
|
||||
$builder->where('user_id', $current_user->id);
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
protected $fillable = [
|
||||
'title', 'url', 'colour', 'icon', 'description', 'pinned', 'order', 'type'
|
||||
'title', 'url', 'colour', 'icon', 'description', 'pinned', 'order', 'type', 'user_id'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -29,24 +40,37 @@ class Item extends Model
|
||||
'AirSonic' => \App\SupportedApps\AirSonic::class,
|
||||
'Cardigann' => \App\SupportedApps\Cardigann::class,
|
||||
'CouchPotato' => \App\SupportedApps\CouchPotato::class,
|
||||
'Bazarr' => \App\SupportedApps\Bazarr::class,
|
||||
'Bitwarden' => \App\SupportedApps\Bitwarden::class,
|
||||
'Booksonic' => \App\SupportedApps\Booksonic::class,
|
||||
'BookStack' => \App\SupportedApps\BookStack::class,
|
||||
'Deluge' => \App\SupportedApps\Deluge::class,
|
||||
'Dokuwiki' => \App\SupportedApps\Dokuwiki::class,
|
||||
'Duplicati' => \App\SupportedApps\Duplicati::class,
|
||||
'Emby' => \App\SupportedApps\Emby::class,
|
||||
'Flood' => \App\SupportedApps\Flood::class,
|
||||
'FreshRSS' => \App\SupportedApps\FreshRSS::class,
|
||||
'Gitea' => \App\SupportedApps\Gitea::class,
|
||||
'Glances' => \App\SupportedApps\Glances::class,
|
||||
'Grafana' => \App\SupportedApps\Grafana::class,
|
||||
'Graylog' => \App\SupportedApps\Graylog::class,
|
||||
'Headphones' => \App\SupportedApps\Headphones::class,
|
||||
'Home Assistant' => \App\SupportedApps\HomeAssistant::class,
|
||||
'Jackett' => \App\SupportedApps\Jackett::class,
|
||||
'Jdownloader' => \App\SupportedApps\Jdownloader::class,
|
||||
'Krusader' => \App\SupportedApps\Krusader::class,
|
||||
'LibreNMS' => \App\SupportedApps\LibreNMS::class,
|
||||
'Lidarr' => \App\SupportedApps\Lidarr::class,
|
||||
'Mailcow' => \App\SupportedApps\Mailcow::class,
|
||||
'Mcmyadmin' => \App\SupportedApps\Mcmyadmin::class,
|
||||
'Medusa' => \App\SupportedApps\Medusa::class,
|
||||
'Monica' => \App\SupportedApps\Monica::class,
|
||||
'MusicBrainz' => \App\SupportedApps\MusicBrainz::class,
|
||||
'Mylar' => \App\SupportedApps\Mylar::class,
|
||||
'NZBGet' => \App\SupportedApps\Nzbget::class,
|
||||
'Netdata' => \App\SupportedApps\Netdata::class,
|
||||
'Nextcloud' => \App\SupportedApps\Nextcloud::class,
|
||||
'Now Showing' => \App\SupportedApps\NowShowing::class,
|
||||
'Nzbhydra' => \App\SupportedApps\Nzbhydra::class,
|
||||
'OPNSense' => \App\SupportedApps\Opnsense::class,
|
||||
'Ombi' => \App\SupportedApps\Ombi::class,
|
||||
@@ -59,6 +83,7 @@ class Item extends Model
|
||||
'Portainer' => \App\SupportedApps\Portainer::class,
|
||||
'Proxmox' => \App\SupportedApps\Proxmox::class,
|
||||
'Radarr' => \App\SupportedApps\Radarr::class,
|
||||
'Rancher' => \App\SupportedApps\Rancher::class,
|
||||
'Runeaudio' => \App\SupportedApps\Runeaudio::class,
|
||||
'Sabnzbd' => \App\SupportedApps\Sabnzbd::class,
|
||||
'Sickrage' => \App\SupportedApps\Sickrage::class,
|
||||
@@ -68,11 +93,15 @@ class Item extends Model
|
||||
'Transmission' => \App\SupportedApps\Transmission::class,
|
||||
'Traefik' => \App\SupportedApps\Traefik::class,
|
||||
'tt-rss' => \App\SupportedApps\Ttrss::class,
|
||||
'TVheadend' => \App\SupportedApps\TVheadend::class,
|
||||
'UniFi' => \App\SupportedApps\Unifi::class,
|
||||
'unRAID' => \App\SupportedApps\Unraid::class,
|
||||
'pfSense' => \App\SupportedApps\Pfsense::class,
|
||||
'pyLoad' => \App\SupportedApps\pyLoad::class,
|
||||
'ruTorrent' => \App\SupportedApps\ruTorrent::class,
|
||||
'Virtualmin' => \App\SupportedApps\Virtualmin::class,
|
||||
'Watcher3' => \App\SupportedApps\Watcher3::class,
|
||||
'Webmin' => \App\SupportedApps\Webmin::class,
|
||||
'WebTools' => \App\SupportedApps\WebTools::class,
|
||||
];
|
||||
}
|
||||
@@ -106,7 +135,7 @@ class Item extends Model
|
||||
$output->view = $view;
|
||||
}
|
||||
if(!isset($output->dataonly)) $output->dataonly = '0';
|
||||
|
||||
|
||||
}
|
||||
return (object)$output;
|
||||
}
|
||||
@@ -126,7 +155,7 @@ class Item extends Model
|
||||
}
|
||||
}
|
||||
//die(var_dump($store))
|
||||
|
||||
|
||||
$config['enabled'] = ($store) ? true : false;
|
||||
$config = json_encode($config);
|
||||
}
|
||||
@@ -163,10 +192,12 @@ class Item extends Model
|
||||
|
||||
public function getLinkTargetAttribute()
|
||||
{
|
||||
if((int)$this->type === 1) {
|
||||
$target = Setting::fetch('window_target');
|
||||
|
||||
if((int)$this->type === 1 || $target === 'current') {
|
||||
return '';
|
||||
} else {
|
||||
return ' target="heimdallapp"';
|
||||
return ' target="' . $target . '"';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,5 +232,13 @@ class Item extends Model
|
||||
return $query->where('type', $typeid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that owns the item.
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\User');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use Illuminate\Support\ServiceProvider;
|
||||
use Artisan;
|
||||
use Schema;
|
||||
use App\Setting;
|
||||
use App\User;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -16,7 +17,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$alt_bg = '';
|
||||
|
||||
|
||||
if(!is_file(base_path('.env'))) {
|
||||
touch(base_path('.env'));
|
||||
@@ -32,12 +33,9 @@ class AppServiceProvider extends ServiceProvider
|
||||
}
|
||||
if(is_file(database_path('app.sqlite'))) {
|
||||
if(Schema::hasTable('settings')) {
|
||||
if($bg_image = Setting::fetch('background_image')) {
|
||||
$alt_bg = ' style="background-image: url(/storage/'.$bg_image.')"';
|
||||
}
|
||||
|
||||
// check version to see if an upgrade is needed
|
||||
$db_version = Setting::fetch('version');
|
||||
$db_version = Setting::_fetch('version');
|
||||
$app_version = config('app.version');
|
||||
if(version_compare($app_version, $db_version) == 1) { // app is higher than db, so need to run migrations etc
|
||||
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
|
||||
@@ -45,14 +43,62 @@ class AppServiceProvider extends ServiceProvider
|
||||
} else {
|
||||
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
|
||||
}
|
||||
$lang = Setting::fetch('language');
|
||||
\App::setLocale($lang);
|
||||
|
||||
}
|
||||
if(!is_file(public_path('storage'))) {
|
||||
Artisan::call('storage:link');
|
||||
\Session::put('current_user', null);
|
||||
}
|
||||
|
||||
// User specific settings need to go here as session isn't available at this point in the app
|
||||
view()->composer('*', function ($view)
|
||||
{
|
||||
|
||||
if(isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
|
||||
explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
|
||||
}
|
||||
if(!\Auth::check()) {
|
||||
if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
|
||||
$credentials = ['username' => $_SERVER['PHP_AUTH_USER'], 'password' => $_SERVER['PHP_AUTH_PW']];
|
||||
|
||||
if (\Auth::attempt($credentials)) {
|
||||
// Authentication passed...
|
||||
$user = \Auth::user();
|
||||
//\Session::put('current_user', $user);
|
||||
session(['current_user' => $user]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$alt_bg = '';
|
||||
if($bg_image = Setting::fetch('background_image')) {
|
||||
$alt_bg = ' style="background-image: url(/storage/'.$bg_image.')"';
|
||||
}
|
||||
$lang = Setting::fetch('language');
|
||||
\App::setLocale($lang);
|
||||
|
||||
$allusers = User::all();
|
||||
$current_user = User::currentUser();
|
||||
|
||||
$view->with('alt_bg', $alt_bg );
|
||||
$view->with('allusers', $allusers );
|
||||
$view->with('current_user', $current_user );
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
if (env('FORCE_HTTPS') === true) {
|
||||
\URL::forceScheme('https');
|
||||
}
|
||||
|
||||
if(env('APP_URL') != 'http://localhost') {
|
||||
\URL::forceRootUrl(env('APP_URL'));
|
||||
}
|
||||
view()->share('alt_bg', $alt_bg);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace App;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Form;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\User;
|
||||
|
||||
class Setting extends Model
|
||||
{
|
||||
@@ -46,6 +48,12 @@ class Setting extends Model
|
||||
|
||||
public function getListValueAttribute()
|
||||
{
|
||||
if((bool)$this->system === true) {
|
||||
$value = self::_fetch($this->key);
|
||||
} else {
|
||||
$value = self::fetch($this->key);
|
||||
}
|
||||
$this->value = $value;
|
||||
switch($this->type) {
|
||||
case 'image':
|
||||
if(!empty($this->value)) {
|
||||
@@ -80,6 +88,12 @@ class Setting extends Model
|
||||
|
||||
public function getEditValueAttribute()
|
||||
{
|
||||
if((bool)$this->system === true) {
|
||||
$value = self::_fetch($this->key);
|
||||
} else {
|
||||
$value = self::fetch($this->key);
|
||||
}
|
||||
$this->value = $value;
|
||||
switch($this->type) {
|
||||
case 'image':
|
||||
$value = '';
|
||||
@@ -125,6 +139,7 @@ class Setting extends Model
|
||||
return $this->belongsTo('App\SettingGroup', 'group_id');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
@@ -132,20 +147,54 @@ class Setting extends Model
|
||||
*/
|
||||
public static function fetch($key)
|
||||
{
|
||||
if (Setting::cached($key)) {
|
||||
return Setting::$cache[$key];
|
||||
} else {
|
||||
$user = self::user();
|
||||
return self::_fetch($key, $user);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function _fetch($key, $user=null)
|
||||
{
|
||||
#$cachekey = ($user === null) ? $key : $key.'-'.$user->id;
|
||||
#if (Setting::cached($cachekey)) {
|
||||
# return Setting::$cache[$cachekey];
|
||||
#} else {
|
||||
$find = self::where('key', '=', $key)->first();
|
||||
|
||||
if (!is_null($find)) {
|
||||
$value = $find->value;
|
||||
Setting::add($key, $value);
|
||||
if((bool)$find->system === true) { // if system variable use global value
|
||||
$value = $find->value;
|
||||
} else { // not system variable so use user specific value
|
||||
// check if user specified value has been set
|
||||
//print_r($user);
|
||||
$usersetting = $user->settings()->where('id', $find->id)->first();
|
||||
//print_r($user->settings);
|
||||
//die(var_dump($usersetting));
|
||||
//->pivot->value;
|
||||
//echo "user: ".$user->id." --- ".$usersettings;
|
||||
if(isset($usersetting) && !empty($usersetting)) {
|
||||
$value = $usersetting->pivot->uservalue;
|
||||
} else { // if not get default from base setting
|
||||
//$user->settings()->save($find, ['value' => $find->value]);
|
||||
#$has_setting = $user->settings()->where('id', $find->id)->exists();
|
||||
#if($has_setting) {
|
||||
# $user->settings()->updateExistingPivot($find->id, ['uservalue' => (string)$find->value]);
|
||||
#} else {
|
||||
# $user->settings()->save($find, ['uservalue' => (string)$find->value]);
|
||||
#}
|
||||
$value = $find->value;
|
||||
}
|
||||
|
||||
}
|
||||
#Setting::add($cachekey, $value);
|
||||
|
||||
return $value;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,21 +224,23 @@ class Setting extends Model
|
||||
$output = '';
|
||||
$homepage_search = self::fetch('homepage_search');
|
||||
$search_provider = self::where('key', '=', 'search_provider')->first();
|
||||
|
||||
//die(var_dump($search_provider->value));
|
||||
$user_search_provider = self::fetch('search_provider');
|
||||
//die(print_r($search_provider));
|
||||
|
||||
//die(var_dump($user_search_provider));
|
||||
// return early if search isn't applicable
|
||||
if((bool)$homepage_search !== true) return $output;
|
||||
if($search_provider->value === 'none') return $output;
|
||||
if(empty($search_provider->value)) return $output;
|
||||
if(is_null($search_provider->value)) return $output;
|
||||
if($user_search_provider === 'none') return $output;
|
||||
if(empty($user_search_provider)) return $output;
|
||||
if(is_null($user_search_provider)) return $output;
|
||||
|
||||
|
||||
if((bool)$homepage_search && (bool)$search_provider) {
|
||||
|
||||
$options = (array)json_decode($search_provider->options);
|
||||
$name = $options[$search_provider->value];
|
||||
if((bool)$search_provider->value) {
|
||||
switch($search_provider->value) {
|
||||
$name = $options[$user_search_provider];
|
||||
if((bool)$user_search_provider) {
|
||||
switch($user_search_provider) {
|
||||
case 'google':
|
||||
$url = 'https://www.google.com/search';
|
||||
$var = 'q';
|
||||
@@ -209,7 +260,7 @@ class Setting extends Model
|
||||
$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 .= 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();
|
||||
@@ -218,4 +269,19 @@ class Setting extends Model
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* The users that belong to the setting.
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
return $this->belongsToMany('App\User')->using('App\SettingUser')->withPivot('uservalue');
|
||||
}
|
||||
|
||||
public static function user()
|
||||
{
|
||||
return User::currentUser();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
10
app/SettingUser.php
Normal file
10
app/SettingUser.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
class SettingUser extends Pivot
|
||||
{
|
||||
//
|
||||
}
|
||||
14
app/SupportedApps/Bazarr.php
Normal file
14
app/SupportedApps/Bazarr.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Bazarr implements Contracts\Applications {
|
||||
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#222';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/bazarr.png';
|
||||
}
|
||||
|
||||
}
|
||||
12
app/SupportedApps/Bitwarden.php
Normal file
12
app/SupportedApps/Bitwarden.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Bitwarden implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#3c8dbc';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/bitwarden.png';
|
||||
}
|
||||
}
|
||||
14
app/SupportedApps/BookStack.php
Normal file
14
app/SupportedApps/BookStack.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class BookStack implements Contracts\Applications {
|
||||
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#02679E';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/bookstack.png';
|
||||
}
|
||||
|
||||
}
|
||||
12
app/SupportedApps/Booksonic.php
Normal file
12
app/SupportedApps/Booksonic.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Booksonic implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#58a';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/booksonic.png';
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Deluge implements Contracts\Applications {
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
class Deluge implements Contracts\Applications, Contracts\Livestats {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#357';
|
||||
@@ -9,4 +10,100 @@ class Deluge implements Contracts\Applications {
|
||||
{
|
||||
return 'supportedapps/deluge.png';
|
||||
}
|
||||
}
|
||||
|
||||
public function configDetails()
|
||||
{
|
||||
return 'deluge';
|
||||
}
|
||||
|
||||
public function testConfig()
|
||||
{
|
||||
$res = $this->login()[0];
|
||||
switch($res->getStatusCode()) {
|
||||
case 200:
|
||||
$data = json_decode($res->getBody());
|
||||
if(!isset($data->result) || is_null($data->result) || $data->result == false) {
|
||||
echo 'Failed: Invalid Credentials';
|
||||
} else {
|
||||
echo 'Successfully connected to the API';
|
||||
}
|
||||
break;
|
||||
case 401:
|
||||
echo 'Failed: Invalid credentials';
|
||||
break;
|
||||
case 404:
|
||||
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
|
||||
break;
|
||||
default:
|
||||
echo 'Something went wrong... Code: '.$res->getStatusCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
public function executeConfig()
|
||||
{
|
||||
$html = '';
|
||||
$active = 'active';
|
||||
$jar = $this->login()[1];
|
||||
$res = $this->getDetails($jar);
|
||||
$data = json_decode($res->getBody());
|
||||
$download_rate = $data->result->stats->download_rate;
|
||||
$upload_rate = $data->result->stats->upload_rate;
|
||||
$seed_count = $data->result->filters->state[2];
|
||||
$leech_count = $data->result->filters->state[1];
|
||||
$html = '
|
||||
<ul class="livestats">
|
||||
<li><span class="title"><i class="fas fa-arrow-down"></i> '.$this->formatBytes($download_rate).'</span></li>
|
||||
<li><span class="title"><i class="fas fa-arrow-up"></i> '.$this->formatBytes($upload_rate).'</span></li>
|
||||
</ul>
|
||||
<ul class="livestats">
|
||||
<li><span class="title">Leech: '.$leech_count[1].'</span></li>
|
||||
<li><span class="title">Seed: '.$seed_count[1].'</span></li>
|
||||
</ul>
|
||||
';
|
||||
return json_encode(['status' => $active, 'html' => $html]);
|
||||
}
|
||||
public function getDetails($jar)
|
||||
{
|
||||
$config = $this->config;
|
||||
$url = $config->url;
|
||||
$url = rtrim($url, '/');
|
||||
$api_url = $url.'/json';
|
||||
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
|
||||
$res = $client->request('POST', $api_url, [
|
||||
'body' => '{"method": "web.update_ui", "params": [["none"], {}], "id": 1}',
|
||||
'cookies' => $jar,
|
||||
'headers' => ['content-type' => 'application/json', 'Accept' => 'application/json']
|
||||
]);
|
||||
return $res;
|
||||
}
|
||||
public function login()
|
||||
{
|
||||
$config = $this->config;
|
||||
$url = $config->url;
|
||||
$password = $config->password;
|
||||
$url = rtrim($url, '/');
|
||||
$api_url = $url.'/json';
|
||||
$jar = new \GuzzleHttp\Cookie\CookieJar();
|
||||
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
|
||||
$res = $client->request('POST', $api_url, [
|
||||
'body' => '{"method": "auth.login", "params": ["'.$password.'"], "id": 1}',
|
||||
'cookies' => $jar,
|
||||
'headers' => ['content-type' => 'application/json', 'Accept' => 'application/json']
|
||||
]);
|
||||
return array($res,$jar);
|
||||
}
|
||||
|
||||
function formatBytes($bytes, $precision = 2) {
|
||||
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
||||
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
// Uncomment one of the following alternatives
|
||||
$bytes /= pow(1024, $pow);
|
||||
// $bytes /= (1 << (10 * $pow));
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$pow] . 'ps';
|
||||
}
|
||||
}
|
||||
|
||||
12
app/SupportedApps/Flood.php
Normal file
12
app/SupportedApps/Flood.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Flood implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '##00D091';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/Flood.png';
|
||||
}
|
||||
}
|
||||
11
app/SupportedApps/FreshRSS.php
Normal file
11
app/SupportedApps/FreshRSS.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
class FreshRSS implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#003B73';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/freshrss.png';
|
||||
}
|
||||
}
|
||||
12
app/SupportedApps/Headphones.php
Normal file
12
app/SupportedApps/Headphones.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Headphones implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#185';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/headphones.png';
|
||||
}
|
||||
}
|
||||
12
app/SupportedApps/Mailcow.php
Normal file
12
app/SupportedApps/Mailcow.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Mailcow implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#161b1f';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/mailcow.svg';
|
||||
}
|
||||
}
|
||||
12
app/SupportedApps/Monica.php
Normal file
12
app/SupportedApps/Monica.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Monica implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#fafbfc';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/monica.png';
|
||||
}
|
||||
}
|
||||
12
app/SupportedApps/MusicBrainz.php
Normal file
12
app/SupportedApps/MusicBrainz.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class MusicBrainz implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#a0a';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/musicbrainz.png';
|
||||
}
|
||||
}
|
||||
12
app/SupportedApps/Mylar.php
Normal file
12
app/SupportedApps/Mylar.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Mylar implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#aa0';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/mylar.png';
|
||||
}
|
||||
}
|
||||
11
app/SupportedApps/NowShowing.php
Normal file
11
app/SupportedApps/NowShowing.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
class NowShowing implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#690000';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/nowshowing.png';
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@
|
||||
class Pfsense implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#4e4742';
|
||||
return '#243699';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/pfsense.png';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
app/SupportedApps/Rancher.php
Normal file
12
app/SupportedApps/Rancher.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Rancher implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#78c9cf';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/rancher.png';
|
||||
}
|
||||
}
|
||||
14
app/SupportedApps/TVheadend.php
Normal file
14
app/SupportedApps/TVheadend.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class TVheadend implements Contracts\Applications {
|
||||
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#006080';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/tvheadend.png';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,78 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Traefik implements Contracts\Applications {
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
class Traefik implements Contracts\Applications, Contracts\Livestats
|
||||
{
|
||||
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#28434a';
|
||||
}
|
||||
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/traefik.png';
|
||||
}
|
||||
}
|
||||
|
||||
public function configDetails()
|
||||
{
|
||||
return 'traefik';
|
||||
}
|
||||
|
||||
public function testConfig()
|
||||
{
|
||||
$res = $this->sendRequest();
|
||||
if ($res == null) {
|
||||
echo 'Traefik connection failed';
|
||||
return;
|
||||
}
|
||||
switch($res->getStatusCode()) {
|
||||
case 200:
|
||||
$data = json_decode($res->getBody());
|
||||
echo "Successfully connected with status: ".$data->result."\n";
|
||||
break;
|
||||
case 404:
|
||||
echo 'Failed: Please make sure your URL is correct and includes the port';
|
||||
break;
|
||||
default:
|
||||
echo 'Something went wrong... Code: '.$res->getStatusCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function executeConfig()
|
||||
{
|
||||
$html = '';
|
||||
$active = 'inactive';
|
||||
$res = $this->sendRequest();
|
||||
$data = json_decode($res->getBody());
|
||||
if ($data) {
|
||||
$avg_response_time = $data->average_response_time_sec;
|
||||
$time = $avg_response_time*1000;
|
||||
$time_output = number_format($time, 2);
|
||||
$active = ($time > 0) ? 'active' : 'inactive';
|
||||
$html = '
|
||||
<ul class="livestats">
|
||||
<li><span class="title">Avg. Response Time</span><sub><i class="fas fa-heartbeat"></i> '.$time_output.' ms</sub></li>
|
||||
</ul>
|
||||
';
|
||||
}
|
||||
return json_encode(['status' => $active, 'html' => $html]);
|
||||
}
|
||||
|
||||
public function sendRequest()
|
||||
{
|
||||
$config = $this->config;
|
||||
$url = $config->url;
|
||||
|
||||
$url = rtrim($url, '/');
|
||||
$api_url = $url.'/health';
|
||||
|
||||
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
|
||||
$res = $client->request('GET', $api_url);
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,9 +158,12 @@ class Transmission implements Contracts\Applications, Contracts\Livestats
|
||||
|
||||
private function getApiUrl()
|
||||
{
|
||||
$url = $this->config->url;
|
||||
$config = $this->config;
|
||||
$url = $config->url;
|
||||
|
||||
$url = rtrim($url, '/');
|
||||
$apiUrl = $url.'/transmission/rpc';
|
||||
return $apiUrl;
|
||||
$api_url = $url.'/transmission/rpc';
|
||||
|
||||
return $api_url;
|
||||
}
|
||||
}
|
||||
|
||||
12
app/SupportedApps/Unraid.php
Normal file
12
app/SupportedApps/Unraid.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Unraid implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#A12624';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/unraid.png';
|
||||
}
|
||||
}
|
||||
12
app/SupportedApps/Virtualmin.php
Normal file
12
app/SupportedApps/Virtualmin.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Virtualmin implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#161b1f';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/virtualmin.svg';
|
||||
}
|
||||
}
|
||||
12
app/SupportedApps/Webmin.php
Normal file
12
app/SupportedApps/Webmin.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Webmin implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#161b1f';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/webmin.svg';
|
||||
}
|
||||
}
|
||||
33
app/User.php
33
app/User.php
@@ -15,7 +15,7 @@ class User extends Authenticatable
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name', 'email', 'password',
|
||||
'username', 'email', 'password',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -26,4 +26,35 @@ class User extends Authenticatable
|
||||
protected $hidden = [
|
||||
'password', 'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the items for the user.
|
||||
*/
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany('App\Item');
|
||||
}
|
||||
|
||||
/**
|
||||
* The settings that belong to the user.
|
||||
*/
|
||||
public function settings()
|
||||
{
|
||||
return $this->belongsToMany('App\Setting')->withPivot('uservalue');
|
||||
}
|
||||
|
||||
public static function currentUser()
|
||||
{
|
||||
$current_user = session('current_user');
|
||||
if ($current_user) { // if logged in, set this user
|
||||
return $current_user;
|
||||
} else { // not logged in, get first user
|
||||
$user = User::first();
|
||||
session(['current_user' => $user]);
|
||||
return $user;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
"type": "project",
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"fideloper/proxy": "~3.3",
|
||||
"fideloper/proxy": "^4.0",
|
||||
"guzzlehttp/guzzle": "^6.3",
|
||||
"laravel/framework": "5.5.*",
|
||||
"laravel/framework": "5.7.*",
|
||||
"laravel/tinker": "~1.0",
|
||||
"laravelcollective/html": "^5.5"
|
||||
},
|
||||
|
||||
1163
composer.lock
generated
1163
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ return [
|
||||
*/
|
||||
|
||||
'name' => env('APP_NAME', 'Heimdall'),
|
||||
'version' => '1.4.9',
|
||||
'version' => '2.0.2',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
38
database/migrations/2018_10_12_122907_create_users_table.php
Normal file
38
database/migrations/2018_10_12_122907_create_users_table.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateUsersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('username')->unique();
|
||||
$table->string('email');
|
||||
$table->string('avatar')->nullable();
|
||||
$table->string('password')->nullable();
|
||||
$table->string('autologin')->nullable()->index();
|
||||
$table->boolean('public_front')->default(false);
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreatePasswordResetsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('password_resets', function (Blueprint $table) {
|
||||
$table->string('email')->index();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('password_resets');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddUserIdToItemsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->integer('user_id')->default(1)->index(); // 0 = item, 1 = category
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->dropColumn(['user_id']);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateSettingUserPivotTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('setting_user', function (Blueprint $table) {
|
||||
$table->integer('setting_id')->unsigned()->index();
|
||||
$table->foreign('setting_id')->references('id')->on('settings')->onDelete('cascade');
|
||||
$table->integer('user_id')->unsigned()->index();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->primary(['setting_id', 'user_id']);
|
||||
$table->string('uservalue')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('setting_user');
|
||||
}
|
||||
}
|
||||
@@ -12,5 +12,6 @@ class DatabaseSeeder extends Seeder
|
||||
public function run()
|
||||
{
|
||||
$this->call(SettingsSeeder::class);
|
||||
$this->call(UsersSeeder::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +90,8 @@ class SettingsSeeder extends Seeder
|
||||
'none' => 'app.options.none',
|
||||
'google' => 'app.options.google',
|
||||
'ddg' => 'app.options.ddg',
|
||||
'bing' => 'app.options.bing'
|
||||
'startpage' => 'app.options.startpage'
|
||||
'bing' => 'app.options.bing',
|
||||
'startpage' => 'app.options.startpage',
|
||||
]);
|
||||
|
||||
if(!$setting = Setting::find(4)) {
|
||||
@@ -138,6 +138,60 @@ class SettingsSeeder extends Seeder
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
|
||||
$window_target_options = json_encode([
|
||||
'current' => 'app.settings.window_target.current',
|
||||
'heimdall' => 'app.settings.window_target.one',
|
||||
'_blank' => 'app.settings.window_target.new',
|
||||
]);
|
||||
|
||||
if(!$setting = Setting::find(7)) {
|
||||
|
||||
$setting = new Setting;
|
||||
$setting->id = 7;
|
||||
$setting->group_id = 3;
|
||||
$setting->key = 'window_target';
|
||||
$setting->type = 'select';
|
||||
$setting->options = $window_target_options;
|
||||
$setting->label = 'app.settings.window_target';
|
||||
$setting->value = 'heimdall';
|
||||
$setting->save();
|
||||
} else {
|
||||
$setting->options = $window_target_options;
|
||||
$setting->label = 'app.settings.window_target';
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if($support = Setting::find(8)) {
|
||||
$support->label = 'app.settings.support';
|
||||
$support->value = '<a rel="noopener" target="_blank" href="https://discord.gg/CCjHKn4">Discord</a> | <a rel="noopener" target="_blank" href="https://github.com/linuxserver/Heimdall">Github</a> | <a rel="noopener" target="_blank" href="https://blog.heimdall.site/">Blog</a>';
|
||||
$support->save();
|
||||
} else {
|
||||
$setting = new Setting;
|
||||
$setting->id = 8;
|
||||
$setting->group_id = 1;
|
||||
$setting->key = 'support';
|
||||
$setting->type = 'text';
|
||||
$setting->label = 'app.settings.support';
|
||||
$setting->value = '<a rel="noopener" target="_blank" href="https://discord.gg/CCjHKn4">Discord</a> | <a rel="noopener" target="_blank" href="https://github.com/linuxserver/Heimdall">Github</a> | <a rel="noopener" target="_blank" href="https://blog.heimdall.site/">Blog</a>';
|
||||
$setting->system = true;
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if($donate = Setting::find(9)) {
|
||||
$donate->label = 'app.settings.donate';
|
||||
$donate->value = '<a rel="noopener" target="_blank" href="https://www.paypal.me/heimdall">Paypal</a>';
|
||||
$donate->save();
|
||||
} else {
|
||||
$setting = new Setting;
|
||||
$setting->id = 9;
|
||||
$setting->group_id = 1;
|
||||
$setting->key = 'donate';
|
||||
$setting->type = 'text';
|
||||
$setting->label = 'app.settings.donate';
|
||||
$setting->value = '<a rel="noopener" target="_blank" href="https://www.paypal.me/heimdall">Paypal</a>';
|
||||
$setting->system = true;
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
27
database/seeds/UsersSeeder.php
Normal file
27
database/seeds/UsersSeeder.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\User;
|
||||
|
||||
class UsersSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// Groups
|
||||
if(!$user = User::find(1)) {
|
||||
$user = new User;
|
||||
$user->id = 1;
|
||||
$user->username = 'admin';
|
||||
$user->email = 'admin@test.com';
|
||||
$user->password = null;
|
||||
$user->save();
|
||||
} else {
|
||||
//$user->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
9553
package-lock.json
generated
9553
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,16 +10,12 @@
|
||||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.17",
|
||||
"bootstrap-sass": "^3.3.7",
|
||||
"cross-env": "^5.1.3",
|
||||
"cross-env": "^5.2.0",
|
||||
"jquery": "^3.2",
|
||||
"laravel-mix": "^1.0",
|
||||
"lodash": "^4.17.4",
|
||||
"vue": "^2.5.7"
|
||||
"laravel-mix": "^2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-sass": "^4.7.2",
|
||||
"select2": "^4.0.6-rc.1"
|
||||
}
|
||||
}
|
||||
|
||||
193
public/css/app.css
vendored
193
public/css/app.css
vendored
@@ -1,5 +1,4 @@
|
||||
@import url(https://fonts.googleapis.com/css?family=Raleway:300,400,600);/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
-ms-text-size-adjust: 100%;
|
||||
@@ -225,9 +224,7 @@ html {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
*, *:before, *:after {
|
||||
-webkit-box-sizing: inherit;
|
||||
box-sizing: inherit;
|
||||
}
|
||||
@@ -236,6 +233,61 @@ body {
|
||||
background: #cfd2d4;
|
||||
}
|
||||
|
||||
#switchuser {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
position: absolute;
|
||||
padding: 10px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
border-top: 2px solid rgba(255, 255, 255, 0.15);
|
||||
border-right: 2px solid rgba(255, 255, 255, 0.15);
|
||||
-webkit-box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
|
||||
box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
|
||||
border-radius: 0 9px 0 0;
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#switchuser img {
|
||||
width: 50px;
|
||||
margin-bottom: 5px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#switchuser .btn {
|
||||
font-size: 13px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
margin-bottom: -10px;
|
||||
margin-top: 8px;
|
||||
border-radius: 0;
|
||||
width: calc(100% + 22px);
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
-webkit-transition: all .35s ease-in-out;
|
||||
transition: all .35s ease-in-out;
|
||||
}
|
||||
|
||||
#switchuser .btn:hover {
|
||||
background: #d64d55;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
@@ -245,7 +297,7 @@ body {
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
background-image: url("/img/bg1.jpg");
|
||||
background-image: url("../img/bg1.jpg");
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: bottom center;
|
||||
@@ -325,9 +377,8 @@ body {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#app main,
|
||||
#app #sortable {
|
||||
padding: 10px;
|
||||
#app main, #app #sortable {
|
||||
padding: 30px 10px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
@@ -378,6 +429,68 @@ body {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.userlist {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.userlist .user {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin: 20px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 15px;
|
||||
border: 5px solid rgba(255, 255, 255, 0.7);
|
||||
-webkit-box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
|
||||
box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.userlist .user-img {
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 50%;
|
||||
margin: 10px 10px 15px;
|
||||
}
|
||||
|
||||
.userlist #password {
|
||||
color: #2f313a;
|
||||
width: 100%;
|
||||
padding: 5px 10px;
|
||||
margin: 15px -5px;
|
||||
}
|
||||
|
||||
.userlist .btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.userlist .forgot {
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.item-container {
|
||||
position: relative;
|
||||
}
|
||||
@@ -396,6 +509,14 @@ body {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.black {
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.white {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.message-container {
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
@@ -423,13 +544,11 @@ body {
|
||||
box-shadow: 0 0 15px 3px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.alert.alert-success,
|
||||
.alert.alert-danger {
|
||||
.alert.alert-success, .alert.alert-danger {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.alert.alert-success:before,
|
||||
.alert.alert-danger:before {
|
||||
.alert.alert-success:before, .alert.alert-danger:before {
|
||||
content: "\F00C";
|
||||
font-family: 'Font Awesome 5 Pro';
|
||||
font-weight: 900;
|
||||
@@ -463,8 +582,7 @@ body {
|
||||
color: #91a1b3;
|
||||
}
|
||||
|
||||
#app.header .item,
|
||||
#app.header .add-item {
|
||||
#app.header .item, #app.header .add-item {
|
||||
-webkit-transform: scale(0.9);
|
||||
transform: scale(0.9);
|
||||
opacity: 0.8;
|
||||
@@ -587,8 +705,7 @@ body {
|
||||
margin: 10px 40px;
|
||||
}
|
||||
|
||||
.module-container header,
|
||||
.module-container footer {
|
||||
.module-container header, .module-container footer {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
@@ -606,8 +723,7 @@ body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.module-container header .section-title,
|
||||
.module-container footer .section-title {
|
||||
.module-container header .section-title, .module-container footer .section-title {
|
||||
font-size: 18px;
|
||||
color: #5b5b5b;
|
||||
margin-left: 25px;
|
||||
@@ -756,8 +872,7 @@ div.create .input label:not(.switch) {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
div.create .input input,
|
||||
div.create .input select {
|
||||
div.create .input input, div.create .input select {
|
||||
width: 100%;
|
||||
border: 1px solid #dedfe2;
|
||||
padding: 10px;
|
||||
@@ -825,13 +940,11 @@ div.create .input select {
|
||||
}
|
||||
|
||||
/* Hide default HTML checkbox */
|
||||
|
||||
.switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The slider */
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
@@ -871,7 +984,6 @@ input:checked + .slider:before {
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
|
||||
.slider.round {
|
||||
border-radius: 20px;
|
||||
}
|
||||
@@ -1025,8 +1137,7 @@ a.settinglink {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ui-state-hover,
|
||||
.ui-state-active {
|
||||
.ui-state-hover, .ui-state-active {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@@ -1187,17 +1298,14 @@ select:-webkit-autofill:focus {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
20% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
95% {
|
||||
-webkit-transform: translate(-200%, 0);
|
||||
transform: translate(-200%, 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: translate(-200%, 0);
|
||||
transform: translate(-200%, 0);
|
||||
@@ -1209,17 +1317,14 @@ select:-webkit-autofill:focus {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
20% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
95% {
|
||||
-webkit-transform: translate(-200%, 0);
|
||||
transform: translate(-200%, 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: translate(-200%, 0);
|
||||
transform: translate(-200%, 0);
|
||||
@@ -1229,7 +1334,6 @@ select:-webkit-autofill:focus {
|
||||
/*! Huebee v2.0.0
|
||||
http://huebee.buzz
|
||||
---------------------------------------------- */
|
||||
|
||||
.huebee {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
@@ -1324,7 +1428,6 @@ http://huebee.buzz
|
||||
* Font Awesome Pro 5.0.2 by @fontawesome - http://fontawesome.com
|
||||
* License - http://fontawesome.com/license (Commercial License)
|
||||
*/
|
||||
|
||||
.fa,
|
||||
.fas,
|
||||
.far,
|
||||
@@ -1461,7 +1564,6 @@ http://huebee.buzz
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
@@ -1473,7 +1575,6 @@ http://huebee.buzz
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
@@ -1556,7 +1657,6 @@ http://huebee.buzz
|
||||
|
||||
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
|
||||
readers do not read off random characters that represent icons */
|
||||
|
||||
.fa-500px:before {
|
||||
content: "\F26E";
|
||||
}
|
||||
@@ -5340,8 +5440,7 @@ readers do not read off random characters that represent icons */
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.sr-only-focusable:active,
|
||||
.sr-only-focusable:focus {
|
||||
.sr-only-focusable:active, .sr-only-focusable:focus {
|
||||
clip: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
@@ -5354,13 +5453,12 @@ readers do not read off random characters that represent icons */
|
||||
* Font Awesome Pro 5.0.2 by @fontawesome - http://fontawesome.com
|
||||
* License - http://fontawesome.com/license (Commercial License)
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Pro';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url("/webfonts/fa-solid-900.eot");
|
||||
src: url("/webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("/webfonts/fa-solid-900.woff2") format("woff2"), url("/webfonts/fa-solid-900.woff") format("woff"), url("/webfonts/fa-solid-900.ttf") format("truetype"), url("/webfonts/fa-solid-900.svg#fontawesome") format("svg");
|
||||
src: url("../webfonts/fa-solid-900.eot");
|
||||
src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg");
|
||||
}
|
||||
|
||||
.fa,
|
||||
@@ -5671,9 +5769,7 @@ readers do not read off random characters that represent icons */
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder,
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
|
||||
float: right;
|
||||
}
|
||||
|
||||
@@ -5701,14 +5797,12 @@ readers do not read off random characters that represent icons */
|
||||
display: none;
|
||||
}
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,
|
||||
.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,
|
||||
.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
@@ -6019,4 +6113,3 @@ readers do not read off random characters that represent icons */
|
||||
.select2-container--classic.select2-container--open .select2-dropdown {
|
||||
border-color: #5897fb;
|
||||
}
|
||||
|
||||
|
||||
6
public/img/heimdall-logo-small.svg
Normal file
6
public/img/heimdall-logo-small.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15pt" height="12pt" viewBox="0 0 16 16" version="1.1">
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 8.464844 8.046875 L 8.464844 7.566406 L 8.628906 7.050781 C 9.78125 5.898438 10.6875 4.824219 10.847656 4.492188 L 10.648438 4.5625 C 10.648438 4.5625 10.832031 4.332031 10.8125 4.203125 C 10.667969 1.949219 9.40625 0.773438 9.058594 0.484375 C 9.570312 1.105469 9.429688 1.308594 9.429688 1.308594 C 9.207031 0.882812 8.742188 0.472656 8.652344 0.367188 L 8.542969 1.023438 C 8.980469 1.28125 8.863281 1.429688 8.863281 1.429688 C 8.761719 1.28125 8.480469 1.152344 8.480469 1.152344 L 8.449219 1.335938 C 8.585938 1.398438 9.1875 1.765625 9.191406 2.710938 C 9.191406 3.863281 8.542969 4.164062 8.429688 4.210938 C 8.050781 3.980469 7.640625 3.984375 7.539062 3.976562 C 7.4375 3.984375 7.027344 3.980469 6.648438 4.210938 C 6.535156 4.164062 5.882812 3.863281 5.882812 2.710938 C 5.890625 1.765625 6.492188 1.398438 6.625 1.335938 L 6.597656 1.152344 C 6.597656 1.152344 6.316406 1.28125 6.210938 1.429688 C 6.210938 1.429688 6.097656 1.28125 6.535156 1.023438 L 6.425781 0.367188 C 6.332031 0.472656 5.871094 0.882812 5.644531 1.308594 C 5.644531 1.308594 5.503906 1.105469 6.015625 0.484375 C 5.667969 0.773438 4.410156 1.949219 4.261719 4.203125 C 4.246094 4.332031 4.425781 4.5625 4.425781 4.5625 L 4.230469 4.492188 C 4.390625 4.824219 5.296875 5.898438 6.445312 7.050781 L 6.609375 7.566406 L 6.609375 8.046875 L 6.464844 7.53125 L 6.132812 6.980469 L 6.132812 7.542969 C 6.269531 7.933594 6.804688 8.722656 6.804688 8.722656 L 6.804688 7.085938 L 4.757812 4.835938 C 4.757812 4.835938 6.035156 5.886719 6.402344 6.261719 L 6.59375 6.066406 C 6.355469 5.894531 5.324219 4.851562 5.230469 3.929688 C 6.007812 5.585938 6.753906 5.792969 7.300781 6.4375 L 7.300781 6.59375 L 7.777344 6.59375 L 7.777344 6.4375 C 8.324219 5.792969 9.070312 5.585938 9.84375 3.929688 C 9.753906 4.851562 8.722656 5.894531 8.484375 6.066406 L 8.675781 6.261719 C 9.042969 5.886719 10.320312 4.835938 10.320312 4.835938 L 8.273438 7.085938 L 8.273438 8.722656 C 8.273438 8.722656 8.808594 7.933594 8.945312 7.542969 L 8.945312 6.980469 L 8.613281 7.53125 Z M 7.539062 6.070312 C 7.195312 5.839844 6.3125 5.300781 5.949219 4.460938 C 6.152344 4.703125 6.375 4.929688 6.609375 5.136719 C 6.609375 5.136719 6.589844 4.542969 6.632812 4.414062 C 6.714844 5.125 6.886719 5.429688 7.539062 5.808594 C 8.191406 5.429688 8.359375 5.125 8.441406 4.414062 C 8.488281 4.542969 8.464844 5.136719 8.464844 5.136719 C 8.703125 4.929688 8.925781 4.703125 9.128906 4.460938 C 8.761719 5.300781 7.882812 5.839844 7.539062 6.070312 Z M 7.539062 6.070312 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
14
public/img/heimdall-logo.svg
Normal file
14
public/img/heimdall-logo.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="780" height="619" viewBox="0 0 780 619">
|
||||
<metadata><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 ">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""/>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
|
||||
|
||||
|
||||
|
||||
<?xpacket end="w"?></metadata>
|
||||
<path class="cls-1" d="M440.227,415.119V390.2l8.552-26.577C508.647,304.3,555.686,248.776,564,231.691l-10.215,3.56s9.5-11.864,8.552-18.51c-7.6-116.273-73.17-176.862-91.226-191.732,26.607,31.955,19.326,42.4,19.326,42.4C478.714,45.576,454.64,24.377,449.888,19l-5.7,33.853c22.806,13.289,16.79,20.882,16.79,20.882C455.591,66.141,441.021,59.5,441.021,59.5l-1.586,9.491c6.973,3.165,38.327,22.149,38.565,70.872,0,59.323-33.735,74.985-39.674,77.357-19.718-11.865-41.1-11.627-46.326-12.1-5.226.474-26.608,0.236-46.324,12.1C339.735,214.844,306,199.182,306,139.859c0.238-48.723,31.6-67.707,38.564-70.872L342.983,59.5s-14.574,6.644-19.955,14.238c0,0-6.022-7.593,16.786-20.882L334.112,19c-4.752,5.378-28.824,26.577-40.543,48.407,0,0-7.288-10.443,19.32-42.4-18.054,14.87-83.625,75.459-91.226,191.732-0.95,6.646,8.554,18.51,8.554,18.51L220,231.691c8.316,17.085,55.355,72.612,115.221,131.935l8.554,26.577v24.916l-7.6-26.577L318.83,360.067v28.95C325.957,409.186,353.751,450,353.751,450V365.525L247.32,249.488s66.52,54.1,85.526,73.56l9.978-10.2c-12.355-8.78-66.045-62.646-70.8-110.1,40.388,85.426,79.111,96.1,107.62,129.325V340.2h24.707v-8.131c28.508-33.221,67.233-43.9,107.619-129.325-4.75,47.459-58.442,101.325-70.8,110.1l9.976,10.2c19.006-19.458,85.526-73.56,85.526-73.56L430.249,365.525V450s27.8-40.815,34.923-60.984v-28.95l-17.343,28.475ZM392,313.083c-17.818-11.865-63.668-39.629-82.672-83.053a314.117,314.117,0,0,0,34.447,34.882s-1.189-30.61,1.186-37.255c4.276,36.781,13.068,52.442,47.039,71.9,33.973-19.458,42.763-35.119,47.039-71.9,2.375,6.645,1.188,37.255,1.188,37.255a314.117,314.117,0,0,0,34.447-34.882C455.668,273.454,409.818,301.218,392,313.083Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
113
public/js/app.js
vendored
113
public/js/app.js
vendored
@@ -11,10 +11,10 @@ $.when( $.ready ).then(function() {
|
||||
|
||||
if($('.message-container').length) {
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
$('.message-container').fadeOut();
|
||||
}, 3500);
|
||||
function()
|
||||
{
|
||||
$('.message-container').fadeOut();
|
||||
}, 3500);
|
||||
}
|
||||
|
||||
if($('.livestats-container').length) {
|
||||
@@ -27,21 +27,21 @@ $.when( $.ready ).then(function() {
|
||||
var timer = 5000;
|
||||
(function worker() {
|
||||
$.ajax({
|
||||
url: '/get_stats/'+id,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
container.html(data.html);
|
||||
if(data.status == 'active') timer = increaseby;
|
||||
else {
|
||||
if(timer < max_timer) timer += 2000;
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
url: '/get_stats/'+id,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
container.html(data.html);
|
||||
if(data.status == 'active') timer = increaseby;
|
||||
else {
|
||||
if(timer < max_timer) timer += 2000;
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
// Schedule the next request when the current one's complete
|
||||
setTimeout(worker, timer);
|
||||
}
|
||||
setTimeout(worker, timer);
|
||||
}
|
||||
});
|
||||
})();
|
||||
})();
|
||||
});
|
||||
|
||||
}
|
||||
@@ -49,20 +49,20 @@ $.when( $.ready ).then(function() {
|
||||
function readURL(input) {
|
||||
|
||||
if (input.files && input.files[0]) {
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
$('#appimage img').attr('src', e.target.result);
|
||||
}
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
var reader = new FileReader();
|
||||
|
||||
$("#upload").change(function() {
|
||||
reader.onload = function(e) {
|
||||
$('#appimage img').attr('src', e.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$('#upload').change(function() {
|
||||
readURL(this);
|
||||
});
|
||||
/*$(".droppable").droppable({
|
||||
});
|
||||
/*$(".droppable").droppable({
|
||||
tolerance: "intersect",
|
||||
drop: function( event, ui ) {
|
||||
var tag = $( this ).data('id');
|
||||
@@ -75,13 +75,13 @@ $.when( $.ready ).then(function() {
|
||||
alert('not added');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
});*/
|
||||
|
||||
$( "#sortable" ).sortable({
|
||||
$( '#sortable' ).sortable({
|
||||
stop: function (event, ui) {
|
||||
var idsInOrder = $("#sortable").sortable('toArray', {
|
||||
var idsInOrder = $('#sortable').sortable('toArray', {
|
||||
attribute: 'data-id'
|
||||
});
|
||||
$.post(
|
||||
@@ -89,12 +89,12 @@ $.when( $.ready ).then(function() {
|
||||
{ order:idsInOrder }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
$("#sortable").sortable("disable");
|
||||
$('#sortable').sortable('disable');
|
||||
|
||||
|
||||
|
||||
|
||||
$('#app').on('click', '#config-button', function(e) {
|
||||
e.preventDefault();
|
||||
var app = $('#app');
|
||||
@@ -104,50 +104,45 @@ $.when( $.ready ).then(function() {
|
||||
$('.add-item').hide();
|
||||
$('.item-edit').hide();
|
||||
$('#app').removeClass('sidebar');
|
||||
$("#sortable").sortable("disable")
|
||||
$('#sortable').sortable('disable');
|
||||
} else {
|
||||
$("#sortable").sortable("enable")
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
$('.add-item').fadeIn();
|
||||
$('.item-edit').fadeIn();
|
||||
}, 350);
|
||||
|
||||
$('#sortable').sortable('enable');
|
||||
setTimeout(function() {
|
||||
$('.add-item').fadeIn();
|
||||
$('.item-edit').fadeIn();
|
||||
}, 350);
|
||||
|
||||
}
|
||||
}).on('click', '#add-item, #pin-item', function(e) {
|
||||
e.preventDefault();
|
||||
var app = $('#app');
|
||||
var active = (app.hasClass('sidebar'));
|
||||
app.toggleClass('sidebar');
|
||||
|
||||
|
||||
}).on('click', '.close-sidenav', function(e) {
|
||||
e.preventDefault();
|
||||
var app = $('#app');
|
||||
app.removeClass('sidebar');
|
||||
|
||||
|
||||
}).on('click', '#test_config', function(e) {
|
||||
e.preventDefault();
|
||||
var apiurl = $('#create input[name=url]').val();
|
||||
|
||||
|
||||
var override_url = $('#override_url');
|
||||
if(override_url.length && override_url.val() != '') {
|
||||
|
||||
var override_url = $('#create input[name="config[override_url]"]').val();
|
||||
if(override_url.length && override_url != '') {
|
||||
apiurl = override_url;
|
||||
}
|
||||
|
||||
var data = {};
|
||||
data['url'] = apiurl;
|
||||
$('input.config-item').each(function(index){
|
||||
var config = $(this).data('config');
|
||||
data[config] = $(this).val();
|
||||
})
|
||||
});
|
||||
|
||||
$.post(
|
||||
'/test_config',
|
||||
{ data }, function(data) {
|
||||
alert(data);
|
||||
}
|
||||
);
|
||||
$.post('/test_config', { data: data }, function(data) {
|
||||
alert(data);
|
||||
});
|
||||
|
||||
});
|
||||
$('#pinlist').on('click', 'a', function(e) {
|
||||
@@ -160,5 +155,5 @@ $.when( $.ready ).then(function() {
|
||||
current.toggleClass('active');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
13
public/js/jquery-ui.min.js
vendored
Normal file
13
public/js/jquery-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
public/mix-manifest.json
generated
6
public/mix-manifest.json
generated
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"/css/app.css": "/css/app.css?id=7e76b8c135b6dbd38363",
|
||||
"/js/app.js": "/js/app.js?id=24ea5e5c1fbea3461a14"
|
||||
}
|
||||
"/css/app.css": "/css/app.css?id=24e9bb4fa993b66f0572",
|
||||
"/js/app.js": "/js/app.js?id=f18d23b8fc7a094a2c66"
|
||||
}
|
||||
|
||||
106
readme.md
106
readme.md
@@ -1,36 +1,37 @@
|
||||

|
||||
# Heimdall
|
||||
|
||||
[](https://heimdall.site)
|
||||
|
||||
____
|
||||
[](https://discord.gg/CCjHKn4)
|
||||
[](https://hub.docker.com/r/linuxserver/heimdall/)
|
||||
[](http://www.firsttimersonly.com/)
|
||||
|
||||
[](https://paypal.me/pools/c/81ZR4dfBGo)
|
||||
[](https://www.firsttimersonly.com/)
|
||||
[](https://www.paypal.me/heimdall)
|
||||
|
||||
___
|
||||
|
||||
Visit the website - https://heimdall.site
|
||||
___
|
||||
|
||||
## About
|
||||
## About
|
||||
As the name suggests Heimdall Application Dashboard is a dashboard for all your web applications. It doesn't need to be limited to applications though, you can add links to anything you like.
|
||||
|
||||
Heimdall is an elegant solution to organise all your web applications. It’s dedicated to this purpose so you won’t lose your links in a sea of bookmarks.
|
||||
|
||||
Why not use it as your browser start page? It even has the ability to include a search bar using either Google, Bing or DuckDuckGo.
|
||||
Why not use it as your browser start page? It even has the ability to include a search bar using either Google, Bing or DuckDuckGo.
|
||||
|
||||

|
||||

|
||||
|
||||
## Video
|
||||
If you want to see a quick video of it in use, go to https://youtu.be/GXnnMAxPzMc
|
||||
|
||||
## Supported applications
|
||||
You can use the app to link to any site or application, but Foundation apps will auto fill in the icon for the app and supply a default color for the tile. In addition Enhanced apps allow you provide details to an apps API, allowing you to view live stats directly on the dashboad. For example, the NZBGet and Sabnzbd Enhanced apps will display the queue size and download speed while something is downloading.
|
||||
You can use the app to link to any site or application, but Foundation apps will auto fill in the icon for the app and supply a default color for the tile. In addition Enhanced apps allow you provide details to an apps API, allowing you to view live stats directly on the dashboad. For example, the NZBGet and Sabnzbd Enhanced apps will display the queue size and download speed while something is downloading.
|
||||
|
||||
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
|
||||
@@ -38,23 +39,34 @@ Supported applications are recognized by the title of the application as entered
|
||||
- Runeaudio
|
||||
- Sabnzbd
|
||||
- Tautulli
|
||||
- Traefik
|
||||
- Transmission
|
||||
|
||||
**Foundation**
|
||||
- AirSonic
|
||||
- Bazarr
|
||||
- Bitwarden
|
||||
- Booksonic
|
||||
- BookStack
|
||||
- Cardigann
|
||||
- Deluge
|
||||
- DokuWiki
|
||||
- Duplicati
|
||||
- Emby
|
||||
- FreshRSS
|
||||
- Gitea
|
||||
- Grafana
|
||||
- Graylog
|
||||
- Headphones
|
||||
- Jdownloader
|
||||
- Krusader
|
||||
- LibreNMS
|
||||
- Lidarr
|
||||
- Mailcow
|
||||
- McMyAdmin
|
||||
- Medusa
|
||||
- Monica
|
||||
- MusicBrainz
|
||||
- Mylar
|
||||
- NZBhydra & NZBhydra2
|
||||
- Netdata
|
||||
- Nextcloud
|
||||
@@ -65,30 +77,38 @@ Supported applications are recognized by the title of the application as entered
|
||||
- Plexrequests
|
||||
- Portainer
|
||||
- Radarr
|
||||
- Rancher
|
||||
- SickRage
|
||||
- Sonarr
|
||||
- TT-RSS
|
||||
- Traefik
|
||||
- TVheadend
|
||||
- UniFI
|
||||
- unRAID
|
||||
- pfSense
|
||||
- pyLoad
|
||||
- rTorrent/Flood
|
||||
- rTorrent/ruTorrent
|
||||
- Syncthing
|
||||
- Virtualmin
|
||||
- Watcher3
|
||||
- Webmin
|
||||
- WebTools
|
||||
|
||||
## Installing
|
||||
Apart from the Laravel dependencies, namely PHP >= 7.0.0, OpenSSL PHP Extension, PDO PHP Extension, Mbstring PHP Extension, Tokenizer PHP Extension and XML PHP Extension, the only other thing Heimdall needs is sqlite support.
|
||||
|
||||
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`
|
||||
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.
|
||||
|
||||
There are also dockers and instructions on how to use them at
|
||||
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`
|
||||
|
||||
for x86-64: https://hub.docker.com/r/linuxserver/heimdall/
|
||||
There is also a multi-arch Docker which supports x86-64, armhf and arm64, instructions on how to use them at
|
||||
|
||||
for armhf: https://hub.docker.com/r/lsioarmhf/heimdall/
|
||||
- https://hub.docker.com/r/linuxserver/heimdall/
|
||||
|
||||
and for arm64: https://hub.docker.com/r/lsioarmhf/heimdall-aarch64/
|
||||
## 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.
|
||||
|
||||
If you are using the linuxserver.io docker image simply edit `/path/to/config/php/php-local.ini` and add `upload_max_filesize = 30M` to the end.
|
||||
|
||||
## Docker and enhanced apps
|
||||
If you are running the docker and the EnhancedApps you are using are also in dockers, you may need to use the docker networking addresses to communicate with them.
|
||||
@@ -96,11 +116,11 @@ If you are running the docker and the EnhancedApps you are using are also in doc
|
||||
You can do this by using `http(s)://docker_name:port` in the config section. Instead of the name you can use the internal docker ip, this usually starts with `172.`
|
||||
|
||||
## Languages
|
||||
The app has been translated into several languages, however the quality of the translations could do with work, if you would like to improve them or help with other translations they are stored in /resources/lang/
|
||||
The app has been translated into several languages; however, the quality of the translations could do with work. If you would like to improve them, or help with other translations, they are stored in `/resources/lang/`.
|
||||
|
||||
To create a new one, create a new folder with the ISO 3166-1 alpha-2 code as the name, copy app.php from /resources/lang/en/app.php into your new folder and replace the english strings.
|
||||
To create a new language translation, make a new folder with the ISO 3166-1 alpha-2 code as the name, copy `app.php` from `/resources/lang/en/app.php` into your new folder and replace the English strings.
|
||||
|
||||
When you are finished create a pull request.
|
||||
When you are finished, create a pull request.
|
||||
|
||||
Currently added languages are
|
||||
|
||||
@@ -115,19 +135,19 @@ Currently added languages are
|
||||
## 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``.
|
||||
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`.
|
||||
|
||||
#### Fixes & work around options
|
||||
##### - Apache global allow .htaccess
|
||||
Find the ``AllowOverride None`` line in your apache configuration and change this to ``AllowOverride All``
|
||||
Find the `AllowOverride None` line in your apache configuration and change this to `AllowOverride All`
|
||||
|
||||
##### - Apache vhost configuration allow .htaccess
|
||||
In the apache vhost configuration in the ``<Directory />`` block add ``AllowOverride All``
|
||||
In the apache vhost configuration in the `<Directory />` block add `AllowOverride All`
|
||||
|
||||
##### - Add .htaccess content in apache configuration
|
||||
You can add the full .htaccess into your apache configuration, this way you do not need to allow .htaccess files.
|
||||
You can even shorten the content of the .htaccess when inserting it into the apache configuration to :
|
||||
You can add the full `.htaccess` into your apache configuration, this way you do not need to allow `.htaccess` files.
|
||||
You can even shorten the content of the `.htaccess` when inserting it into the apache configuration to:
|
||||
```
|
||||
Options +FollowSymLinks
|
||||
RewriteEngine On
|
||||
@@ -137,32 +157,32 @@ RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
```
|
||||
#### More info
|
||||
More info about AllowOverride can be found here :
|
||||
More info about `AllowOverride` can be found here:
|
||||
https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride
|
||||
|
||||
|
||||
|
||||
### Nginx
|
||||
If you are using Nginx, the following directive in your site configuration will direct all requests to the index.php front controller:
|
||||
If you are using Nginx, the following directive in your site configuration will direct all requests to the `index.php` front controller:
|
||||
|
||||
```
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
```
|
||||
Someone was using the same nginx setup to both run this and reverse proxy Plex, Plex is served from /web so their location was interferring with the /webfonts.
|
||||
Someone was using the same nginx setup to both run this and reverse proxy Plex, Plex is served from `/web` so their location was interfering with the `/webfonts`.
|
||||
|
||||
Therefore, if your fonts aren't showing because you have a location for /web add the following
|
||||
Therefore, if your fonts aren't showing because you have a location for `/web`, add the following
|
||||
```
|
||||
location /webfonts {
|
||||
try_files $uri $uri/;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
```
|
||||
If there are any other locations which might interefere 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.
|
||||
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/)
|
||||
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`
|
||||
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/)
|
||||
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`
|
||||
|
||||
```
|
||||
location / {
|
||||
@@ -173,12 +193,14 @@ location / {
|
||||
}
|
||||
```
|
||||
|
||||
### 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:
|
||||
If you are using HTTPS and things aren't working try adding `FORCE_HTTPS=true` to the end of your `.env` file
|
||||
|
||||
- Create a unified certificate .pem-file that contains all CAs and certificates that Heimdall has to verify. For example, if you use both LetsEncrypt and a local CA for your internal apps, concatenate the LetsEncrypt intermediate CA (export via browser) and your local CA cert.pem (or any number of self-signed certs) into one heimdall.pem file.
|
||||
- Place the heimdall.pem into the container (if you use Docker), for example by placing it in the path that you mapped to /config. Make sure that the Heimdall user has read access (chmod a+r).
|
||||
- Set the openssl.cafile setting in /config/php/php-local.ini to your cert bundle:
|
||||
### 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:
|
||||
|
||||
- Create a unified certificate `.pem` file that contains all CAs and certificates that Heimdall has to verify. For example, if you use both LetsEncrypt and a local CA for your internal apps, concatenate the LetsEncrypt intermediate CA (export via browser) and your local CA `cert.pem` (or any number of self-signed certs) into one `heimdall.pem` file.
|
||||
- Place the `heimdall.pem` into the container (if you use Docker), for example by placing it in the path that you mapped to `/config`. Make sure that the Heimdall user has read access (`chmod a+r`).
|
||||
- Set the `openssl.cafile` setting in `/config/php/php-local.ini` to your cert bundle:
|
||||
|
||||
```
|
||||
# /config/php/php-local.ini
|
||||
@@ -188,17 +210,17 @@ openssl.cafile = /config/heimdall.pem
|
||||
Restart the container and the enhanced apps should now be able to access your local HTTP websites. This configuration will survive updating or recreating the Heimdall container.
|
||||
|
||||
## Support
|
||||
https://discord.gg/CCjHKn4 or through Github issues
|
||||
https://discord.gg/CCjHKn4 or through GitHub issues
|
||||
|
||||
## Donate
|
||||
If you would like to show your appreciation, feel free to use the link below.
|
||||
|
||||
[](https://paypal.me/pools/c/81ZR4dfBGo)
|
||||
[](https://www.paypal.me/heimdall)
|
||||
|
||||
## Credits
|
||||
- PHP Framework - [Laravel](https://laravel.com/)
|
||||
- Icons - [FonteAwesome 5](https://fontawesome.com/)
|
||||
- Javascript - [jQuery](https://jquery.com/)
|
||||
- Icons - [FontAwesome 5](https://fontawesome.com/)
|
||||
- JavaScript - [jQuery](https://jquery.com/)
|
||||
- Colour picker - [Huebee](http://huebee.buzz/)
|
||||
- Background image - [pexels](https://www.pexels.com)
|
||||
- Everyone at Linuxserver.io that has helped with the app and let's not forget IronicBadger for the following question that started it all:
|
||||
|
||||
@@ -2,10 +2,10 @@ $.when( $.ready ).then(function() {
|
||||
|
||||
if($('.message-container').length) {
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
$('.message-container').fadeOut();
|
||||
}, 3500);
|
||||
function()
|
||||
{
|
||||
$('.message-container').fadeOut();
|
||||
}, 3500);
|
||||
}
|
||||
|
||||
if($('.livestats-container').length) {
|
||||
@@ -18,21 +18,21 @@ $.when( $.ready ).then(function() {
|
||||
var timer = 5000;
|
||||
(function worker() {
|
||||
$.ajax({
|
||||
url: '/get_stats/'+id,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
container.html(data.html);
|
||||
if(data.status == 'active') timer = increaseby;
|
||||
else {
|
||||
if(timer < max_timer) timer += 2000;
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
url: '/get_stats/'+id,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
container.html(data.html);
|
||||
if(data.status == 'active') timer = increaseby;
|
||||
else {
|
||||
if(timer < max_timer) timer += 2000;
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
// Schedule the next request when the current one's complete
|
||||
setTimeout(worker, timer);
|
||||
}
|
||||
setTimeout(worker, timer);
|
||||
}
|
||||
});
|
||||
})();
|
||||
})();
|
||||
});
|
||||
|
||||
}
|
||||
@@ -40,20 +40,20 @@ $.when( $.ready ).then(function() {
|
||||
function readURL(input) {
|
||||
|
||||
if (input.files && input.files[0]) {
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
$('#appimage img').attr('src', e.target.result);
|
||||
}
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
var reader = new FileReader();
|
||||
|
||||
$("#upload").change(function() {
|
||||
reader.onload = function(e) {
|
||||
$('#appimage img').attr('src', e.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$('#upload').change(function() {
|
||||
readURL(this);
|
||||
});
|
||||
/*$(".droppable").droppable({
|
||||
});
|
||||
/*$(".droppable").droppable({
|
||||
tolerance: "intersect",
|
||||
drop: function( event, ui ) {
|
||||
var tag = $( this ).data('id');
|
||||
@@ -66,13 +66,13 @@ $.when( $.ready ).then(function() {
|
||||
alert('not added');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
});*/
|
||||
|
||||
$( "#sortable" ).sortable({
|
||||
$( '#sortable' ).sortable({
|
||||
stop: function (event, ui) {
|
||||
var idsInOrder = $("#sortable").sortable('toArray', {
|
||||
var idsInOrder = $('#sortable').sortable('toArray', {
|
||||
attribute: 'data-id'
|
||||
});
|
||||
$.post(
|
||||
@@ -80,12 +80,12 @@ $.when( $.ready ).then(function() {
|
||||
{ order:idsInOrder }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
$("#sortable").sortable("disable");
|
||||
$('#sortable').sortable('disable');
|
||||
|
||||
|
||||
|
||||
|
||||
$('#app').on('click', '#config-button', function(e) {
|
||||
e.preventDefault();
|
||||
var app = $('#app');
|
||||
@@ -95,50 +95,45 @@ $.when( $.ready ).then(function() {
|
||||
$('.add-item').hide();
|
||||
$('.item-edit').hide();
|
||||
$('#app').removeClass('sidebar');
|
||||
$("#sortable").sortable("disable")
|
||||
$('#sortable').sortable('disable');
|
||||
} else {
|
||||
$("#sortable").sortable("enable")
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
$('.add-item').fadeIn();
|
||||
$('.item-edit').fadeIn();
|
||||
}, 350);
|
||||
|
||||
$('#sortable').sortable('enable');
|
||||
setTimeout(function() {
|
||||
$('.add-item').fadeIn();
|
||||
$('.item-edit').fadeIn();
|
||||
}, 350);
|
||||
|
||||
}
|
||||
}).on('click', '#add-item, #pin-item', function(e) {
|
||||
e.preventDefault();
|
||||
var app = $('#app');
|
||||
var active = (app.hasClass('sidebar'));
|
||||
app.toggleClass('sidebar');
|
||||
|
||||
|
||||
}).on('click', '.close-sidenav', function(e) {
|
||||
e.preventDefault();
|
||||
var app = $('#app');
|
||||
app.removeClass('sidebar');
|
||||
|
||||
|
||||
}).on('click', '#test_config', function(e) {
|
||||
e.preventDefault();
|
||||
var apiurl = $('#create input[name=url]').val();
|
||||
|
||||
|
||||
var override_url = $('#override_url');
|
||||
if(override_url.length && override_url.val() != '') {
|
||||
|
||||
var override_url = $('#create input[name="config[override_url]"]').val();
|
||||
if(override_url.length && override_url != '') {
|
||||
apiurl = override_url;
|
||||
}
|
||||
|
||||
var data = {};
|
||||
data['url'] = apiurl;
|
||||
$('input.config-item').each(function(index){
|
||||
var config = $(this).data('config');
|
||||
data[config] = $(this).val();
|
||||
})
|
||||
});
|
||||
|
||||
$.post(
|
||||
'/test_config',
|
||||
{ data }, function(data) {
|
||||
alert(data);
|
||||
}
|
||||
);
|
||||
$.post('/test_config', { data: data }, function(data) {
|
||||
alert(data);
|
||||
});
|
||||
|
||||
});
|
||||
$('#pinlist').on('click', 'a', function(e) {
|
||||
@@ -151,5 +146,5 @@ $.when( $.ready ).then(function() {
|
||||
current.toggleClass('active');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -7,12 +7,51 @@ html {
|
||||
body {
|
||||
background: $body-bg;
|
||||
}
|
||||
|
||||
#switchuser {
|
||||
background: rgba(0,0,0,0.5);
|
||||
position: absolute;
|
||||
padding: 10px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
bottom:0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-top: 2px solid rgba(255, 255, 255, 0.15);
|
||||
border-right: 2px solid rgba(255, 255, 255, 0.15);
|
||||
box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
|
||||
border-radius: 0 9px 0 0;
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
img {
|
||||
width: 50px;
|
||||
margin-bottom: 5px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.btn {
|
||||
font-size: 13px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
margin-bottom: -10px;
|
||||
margin-top: 8px;
|
||||
border-radius: 0;
|
||||
width: calc(100% + 22px);
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
transition: all .35s ease-in-out;
|
||||
&:hover {
|
||||
background: #d64d55;
|
||||
}
|
||||
}
|
||||
}
|
||||
#app {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
background-image: url('/img/bg1.jpg');
|
||||
background-image: url('../img/bg1.jpg');
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: bottom center;
|
||||
@@ -70,7 +109,7 @@ body {
|
||||
flex-direction: column;
|
||||
}
|
||||
main, #sortable {
|
||||
padding: 10px;
|
||||
padding: 30px 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -104,6 +143,47 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.userlist {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.user {
|
||||
background: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 20px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 15px;
|
||||
border: 5px solid rgba(255,255,255, 0.7);
|
||||
box-shadow: 0 0 10px 0px rgba(0,0,0,0.4);
|
||||
}
|
||||
.user-img {
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 50%;
|
||||
margin: 10px 10px 15px;
|
||||
}
|
||||
#password {
|
||||
color: $app-text;
|
||||
width: 100%;
|
||||
padding: 5px 10px;
|
||||
margin: 15px -5px;
|
||||
}
|
||||
.btn {
|
||||
width: 100%;
|
||||
}
|
||||
.forgot {
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.item-container {
|
||||
//width: 340px;
|
||||
//transition: width .35s ease-in-out;
|
||||
@@ -122,6 +202,13 @@ body {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.black {
|
||||
color: #000!important;
|
||||
}
|
||||
.white {
|
||||
color: #fff!important;
|
||||
}
|
||||
|
||||
.message-container {
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// This file were added as a supplement to RuneAudio application
|
||||
|
||||
.title-marquee {
|
||||
width: 125px;
|
||||
overflow: hidden;
|
||||
@@ -13,4 +15,4 @@
|
||||
20% { transform: translate(0, 0); }
|
||||
95% { transform: translate(-200%, 0); }
|
||||
100% { transform: translate(-200%, 0); }
|
||||
}
|
||||
}
|
||||
|
||||
2
resources/assets/sass/app.scss
vendored
2
resources/assets/sass/app.scss
vendored
@@ -1,6 +1,6 @@
|
||||
|
||||
// Fonts
|
||||
@import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600");
|
||||
//@import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600");
|
||||
|
||||
// Variables
|
||||
@import "variables";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Variables
|
||||
// --------------------------
|
||||
|
||||
$fa-font-path: "/webfonts" !default;
|
||||
$fa-font-path: "../webfonts" !default;
|
||||
$fa-font-size-base: 16px !default;
|
||||
$fa-css-prefix: fa !default;
|
||||
$fa-version: "5.0.2" !default;
|
||||
|
||||
110
resources/lang/br/app.php
Normal file
110
resources/lang/br/app.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| App Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
*/
|
||||
|
||||
'settings.system' => 'Sistema',
|
||||
'settings.appearance' => 'Aparência',
|
||||
'settings.miscellaneous' => 'Diversos',
|
||||
'settings.support' => 'Ajuda',
|
||||
'settings.donate' => 'Doar',
|
||||
|
||||
'settings.version' => 'Versão',
|
||||
'settings.background_image' => 'Imagem de fundo',
|
||||
'settings.window_target' => 'Link é aberto em',
|
||||
'settings.window_target.current' => 'Abra nesta aba',
|
||||
'settings.window_target.one' => 'Abra na mesma aba',
|
||||
'settings.window_target.new' => 'Abra em uma nova aba',
|
||||
'settings.homepage_search' => 'Pesquisa na página inicial',
|
||||
'settings.search_provider' => 'Provedor de pesquisa',
|
||||
'settings.language' => 'Idioma',
|
||||
'settings.reset' => 'Redefinir de volta ao padrão',
|
||||
'settings.remove' => 'Remover',
|
||||
'settings.search' => 'busca',
|
||||
'settings.no_items' => 'Nenhum item encontrado',
|
||||
|
||||
|
||||
'settings.label' => 'Rótulo',
|
||||
'settings.value' => 'Valor',
|
||||
'settings.edit' => 'Editar',
|
||||
'settings.view' => 'Ver',
|
||||
|
||||
'options.none' => '- não configurado -',
|
||||
'options.google' => 'Google',
|
||||
'options.ddg' => 'DuckDuckGo',
|
||||
'options.bing' => 'Bing',
|
||||
'options.startpage' => 'Página inicial',
|
||||
'options.yes' => 'Sim',
|
||||
'options.no' => 'Não',
|
||||
|
||||
'buttons.save' => 'Salvar',
|
||||
'buttons.cancel' => 'Cancelar',
|
||||
'buttons.add' => 'Adicionar',
|
||||
'buttons.upload' => 'Carregar um arquivo',
|
||||
|
||||
'dash.pin_item' => 'Fixar o item na dashboard',
|
||||
'dash.no_apps' => 'Atualmente não há aplicativos fixados, :link1 ou :link2',
|
||||
'dash.link1' => 'Adicionar um aplivativo aqui',
|
||||
'dash.link2' => 'Fixar um item na dashboard',
|
||||
'dash.pinned_items' => 'Itens fixados',
|
||||
|
||||
'apps.app_list' => 'Lista de aplicativos',
|
||||
'apps.view_trash' => 'Ver lixo',
|
||||
'apps.add_application' => 'Adicionar aplicativo',
|
||||
'apps.application_name' => 'Nome do aplicativo',
|
||||
'apps.colour' => 'Cor',
|
||||
'apps.icon' => 'Ícone',
|
||||
'apps.pinned' => 'Fixado',
|
||||
'apps.title' => 'Título',
|
||||
'apps.hex' => 'Cor hexadecimal',
|
||||
'apps.username' => 'Nome de usuário',
|
||||
'apps.password' => 'Senha',
|
||||
'apps.config' => 'Configuração',
|
||||
'apps.apikey' => 'API Key',
|
||||
'apps.enable' => 'Habilitar',
|
||||
'apps.tag_list' => 'Lista de tags',
|
||||
'apps.add_tag' => 'Adicionar tag',
|
||||
'apps.tag_name' => 'Nome da tag',
|
||||
'apps.tags' => 'Tags',
|
||||
'apps.override' => 'Se diferente do URL principal',
|
||||
|
||||
'user.user_list' => 'Comercial',
|
||||
'user.add_user' => 'Adicionar usuários',
|
||||
'user.username' => 'Nome de usuário',
|
||||
'user.avatar' => 'Avatar',
|
||||
'user.email' => 'O email',
|
||||
'user.password_confirm' => 'Confirme a Senha',
|
||||
'user.secure_front' => 'Permitir acesso público à frente - Aplicado apenas se uma senha for definida.',
|
||||
'user.autologin' => 'Permitir o login a partir de um URL específico. Qualquer pessoa com o link pode fazer o login.',
|
||||
|
||||
'url' => 'URL',
|
||||
'title' => 'Título',
|
||||
'delete' => 'Apagar',
|
||||
'optional' => 'Opcional',
|
||||
'restore' => 'Restaurar',
|
||||
|
||||
'alert.success.item_created' => 'Item criado com sucesso',
|
||||
'alert.success.item_updated' => 'Item atualizado com sucesso',
|
||||
'alert.success.item_deleted' => 'Item apagado com sucesso',
|
||||
'alert.success.item_restored' => 'Item restaurado com sucesso',
|
||||
|
||||
'alert.success.tag_created' => 'Tag criada com sucesso',
|
||||
'alert.success.tag_updated' => 'Tag atualizada com sucesso',
|
||||
'alert.success.tag_deleted' => 'Tag apagada com sucesso',
|
||||
'alert.success.tag_restored' => 'Tag restaurada com sucesso',
|
||||
|
||||
'alert.success.setting_updated' => 'Você editou com sucesso essa configuração',
|
||||
'alert.error.not_exist' => 'Essa configuração não existe.',
|
||||
|
||||
'alert.success.user_created' => 'Usuário criado com sucesso',
|
||||
'alert.success.user_updated' => 'Usuário atualizado com sucesso',
|
||||
'alert.success.user_deleted' => 'Usuário excluído com sucesso',
|
||||
'alert.success.user_restored' => 'Usuário restaurado com sucesso',
|
||||
|
||||
];
|
||||
@@ -12,9 +12,15 @@ return [
|
||||
'settings.system' => 'System',
|
||||
'settings.appearance' => 'Appearance',
|
||||
'settings.miscellaneous' => 'Miscellaneous',
|
||||
'settings.support' => 'Support',
|
||||
'settings.donate' => 'Donate',
|
||||
|
||||
'settings.version' => 'Version',
|
||||
'settings.background_image' => 'Background Image',
|
||||
'settings.window_target' => 'Link opens in',
|
||||
'settings.window_target.current' => 'Open in this tab',
|
||||
'settings.window_target.one' => 'Open in the same tab',
|
||||
'settings.window_target.new' => 'Open in a new tab',
|
||||
'settings.homepage_search' => 'Homepage Search',
|
||||
'settings.search_provider' => 'Search Provider',
|
||||
'settings.language' => 'Language',
|
||||
@@ -22,12 +28,12 @@ return [
|
||||
'settings.remove' => 'Remove',
|
||||
'settings.search' => 'search',
|
||||
'settings.no_items' => 'No items found',
|
||||
|
||||
|
||||
'settings.label' => 'Label',
|
||||
'settings.value' => 'Value',
|
||||
'settings.edit' => 'Edit',
|
||||
'settings.view' => 'View',
|
||||
|
||||
'settings.label' => 'Label',
|
||||
'settings.value' => 'Value',
|
||||
'settings.edit' => 'Edit',
|
||||
'settings.view' => 'View',
|
||||
|
||||
'options.none' => '- not set -',
|
||||
'options.google' => 'Google',
|
||||
@@ -60,7 +66,7 @@ return [
|
||||
'apps.username' => 'Username',
|
||||
'apps.password' => 'Password',
|
||||
'apps.config' => 'Config',
|
||||
'apps.apikey' => 'Api Key',
|
||||
'apps.apikey' => 'API Key',
|
||||
'apps.enable' => 'Enable',
|
||||
'apps.tag_list' => 'Tags list',
|
||||
'apps.add_tag' => 'Add tag',
|
||||
@@ -68,11 +74,20 @@ return [
|
||||
'apps.tags' => 'Tags',
|
||||
'apps.override' => 'If different to main url',
|
||||
|
||||
'url' => 'Url',
|
||||
'user.user_list' => 'Users',
|
||||
'user.add_user' => 'Add user',
|
||||
'user.username' => 'Username',
|
||||
'user.avatar' => 'Avatar',
|
||||
'user.email' => 'Email',
|
||||
'user.password_confirm' => 'Confirm Password',
|
||||
'user.secure_front' => 'Allow public access to front - Only enforced if a password is set.',
|
||||
'user.autologin' => 'Allow logging in from a specific URL. Anyone with the link can login.',
|
||||
|
||||
'url' => 'URL',
|
||||
'title' => 'Title',
|
||||
'delete' => 'Delete',
|
||||
'optional' => 'Optional',
|
||||
'restore' => 'Restore',
|
||||
'delete' => 'Delete',
|
||||
'optional' => 'Optional',
|
||||
'restore' => 'Restore',
|
||||
|
||||
'alert.success.item_created' => 'Item created successfully',
|
||||
'alert.success.item_updated' => 'Item updated successfully',
|
||||
@@ -84,8 +99,13 @@ return [
|
||||
'alert.success.tag_deleted' => 'Tag deleted successfully',
|
||||
'alert.success.tag_restored' => 'Tag restored successfully',
|
||||
|
||||
'alert.success.setting_updated' => 'You have successfully edited this Setting',
|
||||
'alert.error.not_exist' => 'This Setting does not exist.',
|
||||
'alert.success.setting_updated' => 'You have successfully edited this setting',
|
||||
'alert.error.not_exist' => 'This setting does not exist.',
|
||||
|
||||
'alert.success.user_created' => 'User created successfully',
|
||||
'alert.success.user_updated' => 'User updated successfully',
|
||||
'alert.success.user_deleted' => 'User deleted successfully',
|
||||
'alert.success.user_restored' => 'User restored successfully',
|
||||
|
||||
|
||||
];
|
||||
|
||||
@@ -4,55 +4,88 @@ return array (
|
||||
'settings.system' => 'Système',
|
||||
'settings.appearance' => 'Apparence',
|
||||
'settings.miscellaneous' => 'Divers',
|
||||
'settings.support' => 'Support',
|
||||
'settings.donate' => 'Contribuer',
|
||||
|
||||
'settings.version' => 'Version',
|
||||
'settings.background_image' => 'Image D\'Arrière-Plan',
|
||||
'settings.homepage_search' => 'La Page D\'Accueil De Recherche',
|
||||
'settings.search_provider' => 'Fournisseur de recherche',
|
||||
'settings.background_image' => 'Image d\'arrière-plan',
|
||||
'settings.window_target' => 'Ouverture des liens',
|
||||
'settings.window_target.current' => 'Dans l\'onglet courant',
|
||||
'settings.window_target.one' => 'Dans le même nouvel onglet',
|
||||
'settings.window_target.new' => 'Dans un nouvel onglet',
|
||||
'settings.homepage_search' => 'Barre de recherche',
|
||||
'settings.search_provider' => 'Moteur de recherche',
|
||||
'settings.language' => 'Langue',
|
||||
'settings.reset' => 'Réinitialiser aux valeurs par défaut',
|
||||
'settings.reset' => 'Réinitialiser les valeurs par défaut',
|
||||
'settings.remove' => 'Supprimer',
|
||||
'settings.search' => 'chercher',
|
||||
'settings.no_items' => 'Pas d\'articles trouvés',
|
||||
'settings.search' => 'Chercher',
|
||||
'settings.no_items' => 'Aucun élement trouvé',
|
||||
|
||||
'settings.label' => 'Étiquette',
|
||||
'settings.value' => 'Valeur',
|
||||
'settings.edit' => 'Modifier',
|
||||
'settings.view' => 'Vue',
|
||||
|
||||
'options.none' => '- non défini -',
|
||||
'options.google' => 'Google',
|
||||
'options.ddg' => 'DuckDuckGo',
|
||||
'options.bing' => 'Bing',
|
||||
'options.startpage' => 'Page d\'accueil',
|
||||
'options.yes' => 'Oui',
|
||||
'options.no' => 'Non',
|
||||
|
||||
'buttons.save' => 'Enregistrer',
|
||||
'buttons.cancel' => 'Annuler',
|
||||
'buttons.add' => 'Ajouter',
|
||||
'buttons.upload' => 'Télécharger un fichier',
|
||||
'dash.pin_item' => 'Épingler l\'élément au tableau de bord',
|
||||
'dash.no_apps' => 'Il n\'existe actuellement aucun épinglé applications :link1 ou :link2',
|
||||
'dash.link1' => 'Ajouter une application ici',
|
||||
'dash.link2' => 'Pin un élément au tableau de bord',
|
||||
'dash.pinned_items' => 'Éléments épinglés',
|
||||
'buttons.upload' => 'Choisir un fichier',
|
||||
|
||||
'dash.pin_item' => 'Épingler l\'application au tableau de bord',
|
||||
'dash.no_apps' => 'Il n\'existe actuellement aucune application épinglée :link1 ou :link2',
|
||||
'dash.link1' => 'Ajouter une application',
|
||||
'dash.link2' => 'Épingler une application au tableau de bord',
|
||||
'dash.pinned_items' => 'Applications épinglées',
|
||||
|
||||
'apps.app_list' => 'Liste des applications',
|
||||
'apps.view_trash' => 'Voir la corbeille',
|
||||
'apps.add_application' => 'Ajouter une application',
|
||||
'apps.application_name' => 'Nom de l\'application',
|
||||
'apps.colour' => 'Couleur',
|
||||
'apps.icon' => 'Icône',
|
||||
'apps.pinned' => 'Épinglé',
|
||||
'apps.pinned' => 'Épinglée',
|
||||
'apps.title' => 'Titre',
|
||||
'apps.hex' => 'Hexadécimal de la couleur',
|
||||
'apps.username' => 'Nom d\'utilisateur',
|
||||
'apps.password' => 'Mot de passe',
|
||||
'apps.config' => 'Config',
|
||||
'apps.enable' => 'Actif',
|
||||
'apps.tag_list' => 'Liste des labels',
|
||||
'apps.add_tag' => 'Ajouter un label',
|
||||
'apps.tag_name' => 'Nom du label',
|
||||
'apps.tags' => 'Labels',
|
||||
'apps.override' => 'Si différent de l\'url actuelle',
|
||||
|
||||
'url' => 'Url',
|
||||
'title' => 'Titre',
|
||||
'delete' => 'Effacer',
|
||||
'optional' => 'Optionnel',
|
||||
'restore' => 'Restaurer',
|
||||
'alert.success.item_created' => 'Élément créé avec succès',
|
||||
'alert.success.item_updated' => 'Article mis à jour avec succès',
|
||||
'alert.success.item_deleted' => 'Élément supprimé avec succès',
|
||||
'alert.success.item_restored' => 'Élément à restaurer avec succès',
|
||||
'alert.success.setting_updated' => 'Vous avez modifié ce paramètre avec succès',
|
||||
|
||||
'alert.success.item_created' => 'Application créée avec succès',
|
||||
'alert.success.item_updated' => 'Application mise à jour avec succès',
|
||||
'alert.success.item_deleted' => 'Application supprimée avec succès',
|
||||
'alert.success.item_restored' => 'Application restaurée avec succès',
|
||||
|
||||
'alert.success.tag_created' => 'Label crée avec succès',
|
||||
'alert.success.tag_updated' => 'Label mis à jour avec succès',
|
||||
'alert.success.tag_deleted' => 'Label supprimé avec succès',
|
||||
'alert.success.tag_restored' => 'Label restauré avec succès',
|
||||
|
||||
'alert.success.setting_updated' => 'Paramètre mis à jour avec succès',
|
||||
'alert.error.not_exist' => 'Ce paramètre n\'existe pas.',
|
||||
);
|
||||
|
||||
'alert.success.user_created' => 'Utilisateur crée avec succès',
|
||||
'alert.success.user_updated' => 'Utilisateur mis à jour avec succès',
|
||||
'alert.success.user_deleted' => 'Utilisateur supprimé avec succès',
|
||||
'alert.success.user_restored' => 'Utilisateur restoré avec succès',
|
||||
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ return [
|
||||
'settings.homepage_search' => 'Zoeken op thuispagina',
|
||||
'settings.search_provider' => 'Zoekaanbieder',
|
||||
'settings.language' => 'Taal',
|
||||
'settings.reset' => 'Op standaard instellen',
|
||||
'settings.reset' => 'Standaard instellingen herstellen',
|
||||
'settings.remove' => 'Verwijderen',
|
||||
'settings.search' => 'zoeken',
|
||||
'settings.no_items' => 'Geen items gevonden',
|
||||
@@ -39,21 +39,21 @@ return [
|
||||
'buttons.save' => 'Opslaan',
|
||||
'buttons.cancel' => 'Annuleren',
|
||||
'buttons.add' => 'Toevoegen',
|
||||
'buttons.upload' => 'Bestand uploaden',
|
||||
'buttons.upload' => 'Een bestand uploaden',
|
||||
|
||||
'dash.pin_item' => 'Item aan dashboard vastmaken',
|
||||
'dash.no_apps' => 'Er zijn momenteel geen vastgemaakte toepassingen, :link1 of :link2',
|
||||
'dash.pin_item' => 'Item aan dashboard vastpinnen',
|
||||
'dash.no_apps' => 'Er zijn momenteel geen vastgepinde toepassingen, :link1 of :link2',
|
||||
'dash.link1' => 'Voeg hier een toepassing toe',
|
||||
'dash.link2' => 'Een item aan het dashboard vastmaken',
|
||||
'dash.pinned_items' => 'Vastgemaakte Items',
|
||||
'dash.link2' => 'Een item aan het dashboard vastpinnen',
|
||||
'dash.pinned_items' => 'Vastgepinde Items',
|
||||
|
||||
'apps.app_list' => 'Lijst met toepassingen',
|
||||
'apps.app_list' => 'Applicatielijst',
|
||||
'apps.view_trash' => 'Prullenbak weergeven',
|
||||
'apps.add_application' => 'Toepassing toevoegen',
|
||||
'apps.application_name' => 'Naam van toepassing',
|
||||
'apps.add_application' => 'Applicatie toevoegen',
|
||||
'apps.application_name' => 'Applicatienaam',
|
||||
'apps.colour' => 'Kleur',
|
||||
'apps.icon' => 'Pictogram',
|
||||
'apps.pinned' => 'Vastgemaakt',
|
||||
'apps.pinned' => 'Vastgepind',
|
||||
'apps.title' => 'Titel',
|
||||
'apps.hex' => 'Hex-kleur',
|
||||
'apps.username' => 'Gebruikersnaam',
|
||||
@@ -61,10 +61,20 @@ return [
|
||||
'apps.config' => 'Configuratie',
|
||||
'apps.apikey' => 'API-sleutel',
|
||||
'apps.enable' => 'Inschakalen',
|
||||
'apps.tag_list' => 'Lijst met tags',
|
||||
'apps.tag_list' => 'Tags-lijst',
|
||||
'apps.add_tag' => 'Tag toevoegen',
|
||||
'apps.tag_name' => 'Naam van tag',
|
||||
'apps.tag_name' => 'Tag naam',
|
||||
'apps.tags' => 'Tags',
|
||||
'apps.override' => 'Indien anders dan hoofd-url',
|
||||
|
||||
'user.user_list' => 'Gebruikers',
|
||||
'user.add_user' => 'Gebruiker toevoegen',
|
||||
'user.username' => 'Gebruikersnaam',
|
||||
'user.avatar' => 'Avatar',
|
||||
'user.email' => 'Email',
|
||||
'user.password_confirm' => 'Bevestig wachtwoord',
|
||||
'user.secure_front' => 'Sta publieke toegang toe tot voorkant - Alleen geforceerd indien een wachtwoord is ingesteld.',
|
||||
'user.autologin' => 'Sta inloggen vanaf een specifieke URL toe. Iedereen met de link kan inloggen.',
|
||||
|
||||
'url' => 'URL',
|
||||
'title' => 'Titel',
|
||||
@@ -84,6 +94,11 @@ return [
|
||||
|
||||
'alert.success.setting_updated' => 'Deze instelling is met succes gewijzigd',
|
||||
'alert.error.not_exist' => 'Deze instelling bestaat niet.',
|
||||
|
||||
'alert.success.user_created' => 'Gebruiker met succes aangemaakt',
|
||||
'alert.success.user_updated' => 'Gebruiker met succes bewerkt',
|
||||
'alert.success.user_deleted' => 'Gebruiker met succes verwijderd',
|
||||
'alert.success.user_restored' => 'Gebruiker met succes hersteld',
|
||||
|
||||
|
||||
];
|
||||
|
||||
25
resources/views/auth/login.blade.php
Normal file
25
resources/views/auth/login.blade.php
Normal file
@@ -0,0 +1,25 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<?php
|
||||
$user = \App\User::currentUser();
|
||||
?>
|
||||
<form class="form-horizontal" method="POST" action="{{ route('login') }}">
|
||||
{{ csrf_field() }}
|
||||
<div class="userlist">
|
||||
|
||||
<div class="user" href="{{ route('user.set', [$user->id]) }}">
|
||||
@if($user->avatar)
|
||||
<img class="user-img" src="{{ asset('/storage/'.$user->avatar) }}" />
|
||||
@else
|
||||
<img class="user-img" src="{{ asset('/img/heimdall-icon-small.png') }}" />
|
||||
@endif
|
||||
{{ $user->username }}
|
||||
<input id="password" type="password" class="form-control" name="password" required>
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
@endsection
|
||||
47
resources/views/auth/passwords/email.blade.php
Normal file
47
resources/views/auth/passwords/email.blade.php
Normal file
@@ -0,0 +1,47 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Reset Password</div>
|
||||
|
||||
<div class="panel-body">
|
||||
@if (session('status'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form class="form-horizontal" method="POST" action="{{ route('password.email') }}">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
|
||||
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required>
|
||||
|
||||
@if ($errors->has('email'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('email') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-6 col-md-offset-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Send Password Reset Link
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
70
resources/views/auth/passwords/reset.blade.php
Normal file
70
resources/views/auth/passwords/reset.blade.php
Normal file
@@ -0,0 +1,70 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Reset Password</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="POST" action="{{ route('password.request') }}">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<input type="hidden" name="token" value="{{ $token }}">
|
||||
|
||||
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
|
||||
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control" name="email" value="{{ $email or old('email') }}" required autofocus>
|
||||
|
||||
@if ($errors->has('email'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('email') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
|
||||
<label for="password" class="col-md-4 control-label">Password</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control" name="password" required>
|
||||
|
||||
@if ($errors->has('password'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('password') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group{{ $errors->has('password_confirmation') ? ' has-error' : '' }}">
|
||||
<label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>
|
||||
<div class="col-md-6">
|
||||
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
|
||||
|
||||
@if ($errors->has('password_confirmation'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('password_confirmation') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-6 col-md-offset-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Reset Password
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
77
resources/views/auth/register.blade.php
Normal file
77
resources/views/auth/register.blade.php
Normal file
@@ -0,0 +1,77 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Register</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="POST" action="{{ route('register') }}">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
|
||||
<label for="name" class="col-md-4 control-label">Name</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}" required autofocus>
|
||||
|
||||
@if ($errors->has('name'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('name') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
|
||||
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required>
|
||||
|
||||
@if ($errors->has('email'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('email') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
|
||||
<label for="password" class="col-md-4 control-label">Password</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control" name="password" required>
|
||||
|
||||
@if ($errors->has('password'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('password') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-6 col-md-offset-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Register
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
23
resources/views/home.blade.php
Normal file
23
resources/views/home.blade.php
Normal file
@@ -0,0 +1,23 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Dashboard</div>
|
||||
|
||||
<div class="panel-body">
|
||||
@if (session('status'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
You are logged in!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -1,17 +1,17 @@
|
||||
<section class="item-container{{ $app->droppable }}" data-id="{{ $app->id }}">
|
||||
<div class="item" style="background-color: {{ $app->colour }}">
|
||||
@if($app->icon)
|
||||
<img class="app-icon" src="/storage/{{ $app->icon }}" />
|
||||
<img class="app-icon" src="{{ asset('/storage/'.$app->icon) }}" />
|
||||
@else
|
||||
<img class="app-icon" src="/img/heimdall-icon-small.png" />
|
||||
<img class="app-icon" src="{{ asset('/img/heimdall-icon-small.png') }}" />
|
||||
@endif
|
||||
<div class="details">
|
||||
<div class="title">{{ $app->title }}</div>
|
||||
<div class="title{{ title_color($app->colour) }}">{{ $app->title }}</div>
|
||||
@if(isset($app->config->enabled) && ((bool)$app->config->enabled === true))
|
||||
<div data-id="{{ $app->id }}" data-dataonly="{{ $app->config->dataonly or '0' }}" class="livestats-container"></div>
|
||||
@endif
|
||||
</div>
|
||||
<a class="link"{!! $app->link_target !!} href="{{ $app->link }}"><i class="fas {{ $app->link_icon }}"></i></a>
|
||||
<a class="link{{ title_color($app->colour) }}"{!! $app->link_target !!} href="{{ $app->link }}"><i class="fas {{ $app->link_icon }}"></i></a>
|
||||
</div>
|
||||
<a class="item-edit" href="{{ route($app->link_type.'.edit', [ $app->id ], false) }}"><i class="fas fa-pencil"></i></a>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<section class="module-container">
|
||||
|
||||
@@ -5,16 +5,10 @@
|
||||
var elem = $('.color-picker')[0];
|
||||
var hueb = new Huebee( elem, {
|
||||
// options
|
||||
});
|
||||
});
|
||||
|
||||
var availableTags = @json(App\Item::supportedOptions());
|
||||
|
||||
var availableTags = [
|
||||
<?php
|
||||
$supported = App\Item::supportedOptions();
|
||||
foreach($supported as $sapp) {
|
||||
echo '"'.$sapp.'",';
|
||||
}
|
||||
?>
|
||||
];
|
||||
$( "#appname" ).autocomplete({
|
||||
source: availableTags,
|
||||
select: function( event, ui ) {
|
||||
@@ -35,4 +29,4 @@
|
||||
$('.tags').select2();
|
||||
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<section class="module-container">
|
||||
|
||||
112
resources/views/layouts/app.blade.php
Normal file
112
resources/views/layouts/app.blade.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<!doctype html>
|
||||
<html lang="{{ app()->getLocale() }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>{{ config('app.name') }}</title>
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="{{ asset('apple-icon-57x57.png') }}">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="{{ asset('apple-icon-60x60.png') }}">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="{{ asset('apple-icon-72x72.png') }}">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="{{ asset('apple-icon-76x76.png') }}">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="{{ asset('apple-icon-114x114.png') }}">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="{{ asset('apple-icon-120x120.png') }}">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="{{ asset('apple-icon-144x144.png') }}">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="{{ asset('apple-icon-152x152.png') }}">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ asset('apple-icon-180x180.png') }}">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="{{ asset('android-icon-192x192.png') }}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicon-32x32.png') }}">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="{{ asset('favicon-96x96.png') }}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ asset('favicon-16x16.png') }}">
|
||||
<link rel="mask-icon" href="{{ asset('img/heimdall-logo-small.svg') }}" color="black">
|
||||
<link rel="manifest" href="{{ asset('manifest.json') }}">
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<meta name="msapplication-TileImage" content="{{ asset('ms-icon-144x144.png') }}">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link rel="stylesheet" href="{{ asset('css/app.css') }}" type="text/css" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"{!! $alt_bg !!}>
|
||||
<nav class="sidenav">
|
||||
<a class="close-sidenav" href=""><i class="fas fa-times-circle"></i></a>
|
||||
@if(isset($all_apps))
|
||||
<h2>{{ __('app.dash.pinned_items') }}</h2>
|
||||
<ul id="pinlist">
|
||||
@foreach($all_apps as $app)
|
||||
<?php
|
||||
$active = ((bool)$app->pinned === true) ? 'active' : '';
|
||||
?>
|
||||
<li>{{ $app->title }}<a class="{{ $active }}" data-id="{{ $app->id }}" href="{{ route('items.pintoggle', [$app->id], false) }}"><i class="fas fa-thumbtack"></i></a></li>
|
||||
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
</nav>
|
||||
<div class="content">
|
||||
<header class="appheader">
|
||||
<ul>
|
||||
<li><a href="{{ route('dash', [], false) }}">Dash</a></li><li>
|
||||
<a href="{{ route('items.index', [], false) }}">Items</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
<main>
|
||||
@if ($message = Session::get('success'))
|
||||
<div class="message-container">
|
||||
<div class="alert alert-success">
|
||||
<p>{{ $message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@if (count($errors) > 0)
|
||||
<div class="message-container">
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@if($allusers->count() > 1)
|
||||
<div id="switchuser">
|
||||
@if($current_user->avatar)
|
||||
<img class="user-img" src="{{ asset('/storage/'.$current_user->avatar) }}" />
|
||||
@else
|
||||
<img class="user-img" src="{{ asset('/img/heimdall-icon-small.png') }}" />
|
||||
@endif
|
||||
{{ $current_user->username }}
|
||||
<a class="btn" href="{{ route('user.select') }}">Switch User</a>
|
||||
</div>
|
||||
@endif
|
||||
@yield('content')
|
||||
<div id="config-buttons">
|
||||
|
||||
|
||||
@if(Route::is('dash') || Route::is('tags.show'))
|
||||
<a id="config-button" class="config" href=""><i class="fas fa-exchange"></i></a>
|
||||
@endif
|
||||
|
||||
<a id="dash" class="config" href="{{ route('dash', [], false) }}"><i class="fas fa-th"></i></a>
|
||||
@if($current_user->id === 1)
|
||||
<a id="users" class="config" href="{{ route('users.index', [], false) }}"><i class="fas fa-user"></i></a>
|
||||
@endif
|
||||
<a id="items" class="config" href="{{ route('items.index', [], false) }}"><i class="fas fa-list"></i></a>
|
||||
<a id="folder" class="config" href="{{ route('tags.index', [], false) }}"><i class="fas fa-tag"></i></a>
|
||||
<a id="settings" class="config" href="{{ route('settings.index', [], false) }}"><i class="fas fa-cogs"></i></a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{ asset('js/jquery-3.3.1.min.js') }}"></script>
|
||||
<script src="{{ asset('js/jquery-ui.min.js') }}"></script>
|
||||
<script src="{{ asset('js/app.js?v=2') }}"></script>
|
||||
@yield('scripts')
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -25,33 +25,12 @@
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link rel="stylesheet" href="{{ mix('css/app.css') }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ asset('css/app.css') }}" type="text/css" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"{!! $alt_bg !!}>
|
||||
<nav class="sidenav">
|
||||
<a class="close-sidenav" href=""><i class="fas fa-times-circle"></i></a>
|
||||
@if(isset($all_apps))
|
||||
<h2>{{ __('app.dash.pinned_items') }}</h2>
|
||||
<ul id="pinlist">
|
||||
@foreach($all_apps as $app)
|
||||
<?php
|
||||
$active = ((bool)$app->pinned === true) ? 'active' : '';
|
||||
?>
|
||||
<li>{{ $app->title }}<a class="{{ $active }}" data-id="{{ $app->id }}" href="{{ route('items.pintoggle', [$app->id], false) }}"><i class="fas fa-thumbtack"></i></a></li>
|
||||
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
</nav>
|
||||
<div class="content">
|
||||
<header class="appheader">
|
||||
<ul>
|
||||
<li><a href="{{ route('dash', [], false) }}">Dash</a></li><li>
|
||||
<a href="{{ route('items.index', [], false) }}">Items</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
<main>
|
||||
@if ($message = Session::get('success'))
|
||||
<div class="message-container">
|
||||
@@ -71,18 +50,7 @@
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@yield('content')
|
||||
<div id="config-buttons">
|
||||
@if(Route::is('dash') || Route::is('tags.show'))
|
||||
<a id="config-button" class="config" href=""><i class="fas fa-exchange"></i></a>
|
||||
@endif
|
||||
|
||||
<a id="dash" class="config" href="{{ route('dash', [], false) }}"><i class="fas fa-th"></i></a>
|
||||
<a id="items" class="config" href="{{ route('items.index', [], false) }}"><i class="fas fa-list"></i></a>
|
||||
<a id="folder" class="config" href="{{ route('tags.index', [], false) }}"><i class="fas fa-tag"></i></a>
|
||||
<a id="settings" class="config" href="{{ route('settings.index', [], false) }}"><i class="fas fa-cogs"></i></a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
@@ -90,7 +58,7 @@
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||
<script>!window.jQuery && document.write('<script src="/js/jquery-3.3.1.min.js"><\/script>')</script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
|
||||
<script src="/js/app.js?v=2"></script>
|
||||
<script src="{{ asset('js/app.js?v=2') }}"></script>
|
||||
@yield('scripts')
|
||||
|
||||
</body>
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
<input type="hidden" name="config[enabled]" value="1" />
|
||||
<input type="hidden" data-config="dataonly" class="config-item" name="config[dataonly]" value="1" />
|
||||
<input type="hidden" data-config="type" class="config-item" name="config[type]" value="\App\SupportedApps\CouchPotato" />
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', null, array('placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control')) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.apikey') }}</label>
|
||||
{!! Form::text('config[apikey]', null, array('placeholder' => __('app.apps.apikey'), 'data-config' => 'apikey', 'class' => 'form-control config-item')) !!}
|
||||
</div>
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
|
||||
20
resources/views/supportedapps/deluge.blade.php
Normal file
20
resources/views/supportedapps/deluge.blade.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }})</h2>
|
||||
<div class="items">
|
||||
<input type="hidden" name="config[enabled]" value="1" />
|
||||
<input type="hidden" data-config="type" class="config-item" name="config[type]" value="\App\SupportedApps\Deluge" />
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', null, array('placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control')) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.username') }}</label>
|
||||
{!! Form::text('config[username]', null, array('placeholder' => __('app.apps.username'), 'data-config' => 'username', 'class' => 'form-control config-item')) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.password') }}</label>
|
||||
{!! Form::text('config[password]', null, array('placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item')) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
11
resources/views/supportedapps/traefik.blade.php
Normal file
11
resources/views/supportedapps/traefik.blade.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }})</h2>
|
||||
<div class="items">
|
||||
<input type="hidden" data-config="type" class="config-item" name="config[type]" value="\App\SupportedApps\Traefik" />
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', null, array('placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control')) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2,6 +2,10 @@
|
||||
<div class="items">
|
||||
<input type="hidden" name="config[enabled]" value="1" />
|
||||
<input type="hidden" data-config="type" class="config-item" name="config[type]" value="\App\SupportedApps\Transmission" />
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', null, array('placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control')) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.username') }}</label>
|
||||
{!! Form::text('config[username]', null, array('placeholder' => __('app.apps.username'), 'data-config' => 'username', 'class' => 'form-control config-item')) !!}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<section class="module-container">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@extends('app')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<section class="module-container">
|
||||
|
||||
11
resources/views/users/create.blade.php
Normal file
11
resources/views/users/create.blade.php
Normal file
@@ -0,0 +1,11 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
{!! Form::open(array('route' => 'users.store', 'id' => 'userform', 'files' => true, 'method'=>'POST')) !!}
|
||||
@include('users.form')
|
||||
{!! Form::close() !!}
|
||||
|
||||
@endsection
|
||||
@section('scripts')
|
||||
@endsection
|
||||
11
resources/views/users/edit.blade.php
Normal file
11
resources/views/users/edit.blade.php
Normal file
@@ -0,0 +1,11 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
{!! Form::model($user, ['method' => 'PATCH', 'id' => 'userform', 'files' => true, 'route' => ['users.update', $user->id]]) !!}
|
||||
@include('users.form')
|
||||
{!! Form::close() !!}
|
||||
|
||||
@endsection
|
||||
@section('scripts')
|
||||
@endsection
|
||||
97
resources/views/users/form.blade.php
Normal file
97
resources/views/users/form.blade.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<section class="module-container">
|
||||
<header>
|
||||
<div class="section-title">{{ __('app.user.add_user') }}</div>
|
||||
<div class="module-actions">
|
||||
<button type="submit"class="button"><i class="fa fa-save"></i><span>{{ __('app.buttons.save') }}</span></button>
|
||||
<a href="{{ route('users.index', [], false) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
|
||||
</div>
|
||||
</header>
|
||||
<div id="create" class="create">
|
||||
{!! csrf_field() !!}
|
||||
|
||||
<div class="input">
|
||||
<label>{{ __('app.user.username') }} *</label>
|
||||
{!! Form::text('username', null, array('placeholder' => __('app.user.username'), 'id' => 'appname', 'class' => 'form-control')) !!}
|
||||
<hr />
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.user.email') }} *</label>
|
||||
{!! Form::text('email', null, array('placeholder' => 'email@test.com','class' => 'form-control')) !!}
|
||||
<hr />
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.user.avatar') }}</label>
|
||||
<div class="icon-container">
|
||||
<div id="appimage">
|
||||
@if(isset($user->avatar) && !empty($user->avatar) || old('avatar'))
|
||||
<?php
|
||||
if(isset($user->avatar)) $avatar = $user->avatar;
|
||||
else $avatar = old('avatar');
|
||||
?>
|
||||
<img style="max-width: 115px" src="{{ asset('storage/'.$avatar) }}" />
|
||||
{!! Form::hidden('avatar', $avatar, ['class' => 'form-control']) !!}
|
||||
@else
|
||||
<img style="max-width: 115px" src="/img/heimdall-icon-small.png" />
|
||||
@endif
|
||||
</div>
|
||||
<div class="upload-btn-wrapper">
|
||||
<button class="btn">{{ __('app.buttons.upload')}} </button>
|
||||
<input type="file" id="upload" name="file" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: -40px; width: 100%; padding: 0" class="create">
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.password') }} *</label>
|
||||
{!! Form::password('password', null, array('class' => 'form-control')) !!}
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.user.password_confirm') }} *</label>
|
||||
{!! Form::password('password_confirmation', null, array('class' => 'form-control')) !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<label>{{ __('app.user.secure_front') }}</label>
|
||||
{!! Form::hidden('public_front', '0') !!}
|
||||
<label class="switch">
|
||||
<?php
|
||||
$checked = true;
|
||||
if(isset($user->public_front) && (bool)$user->public_front === false) $checked = false;
|
||||
$set_checked = ($checked) ? ' checked="checked"' : '';
|
||||
?>
|
||||
<input type="checkbox" name="public_front" value="1"<?php echo $set_checked;?> />
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.user.autologin') }}</label>
|
||||
{!! Form::hidden('autologin_allow', '0') !!}
|
||||
<label class="switch">
|
||||
<?php
|
||||
$checked = false;
|
||||
if(isset($user->autologin) && !empty($user->autologin)) $checked = true;
|
||||
$set_checked = ($checked) ? ' checked="checked"' : '';
|
||||
?>
|
||||
<input type="checkbox" name="autologin_allow" value="1"<?php echo $set_checked;?> />
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<footer>
|
||||
<div class="section-title"> </div>
|
||||
<div class="module-actions">
|
||||
<button type="submit"class="button"><i class="fa fa-save"></i><span>{{ __('app.buttons.save') }}</span></button>
|
||||
<a href="{{ route('users.index', [], false) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
66
resources/views/users/index.blade.php
Normal file
66
resources/views/users/index.blade.php
Normal file
@@ -0,0 +1,66 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<section class="module-container">
|
||||
<header>
|
||||
<div class="section-title">
|
||||
{{ __('app.user.user_list') }}
|
||||
@if( isset($trash) && $trash->count() > 0 )
|
||||
<a class="trashed" href="{{ route('users.index', ['trash' => true], false) }}">{{ __('app.apps.view_trash') }} ({{ $trash->count() }})</a>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
<div class="module-actions">
|
||||
<a href="{{ route('users.create', [], false) }}" title="" class="button"><i class="fa fa-plus"></i><span>{{ __('app.buttons.add') }}</span></a>
|
||||
<a href="{{ route('dash', [], false) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('app.user.username') }}</th>
|
||||
<th>{{ __('app.apps.password') }}</th>
|
||||
<th>{{ __('app.apps.autologin_url') }}</th>
|
||||
<th class="text-center" width="100">{{ __('app.settings.edit') }}</th>
|
||||
<th class="text-center" width="100">{{ __('app.delete') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if($users->first())
|
||||
@foreach($users as $user)
|
||||
<tr>
|
||||
<td>{{ $user->username }}</td>
|
||||
<td><i class="fa {{ (!is_null($user->password) ? 'fa-check' : 'fa-times') }}" /></td>
|
||||
<td>
|
||||
@if(is_null($user->autologin))
|
||||
<i class="fa fa-times" />
|
||||
@else
|
||||
<a href="{{ route('user.autologin', $user->autologin) }}">{{ route('user.autologin', $user->autologin) }}</a>
|
||||
@endif
|
||||
</td>
|
||||
<td class="text-center"><a{{ $user->target }} href="{!! route('users.edit', [$user->id], false) !!}" title="{{ __('user.settings.edit') }} {!! $user->title !!}"><i class="fas fa-edit"></i></a></td>
|
||||
<td class="text-center">
|
||||
@if($user->id !== 1)
|
||||
{!! Form::open(['method' => 'DELETE','route' => ['users.destroy', $user->id],'style'=>'display:inline']) !!}
|
||||
<button class="link" type="submit"><i class="fa fa-trash-alt"></i></button>
|
||||
{!! Form::close() !!}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@else
|
||||
<tr>
|
||||
<td colspan="4" class="form-error text-center">
|
||||
<strong>{{ __('app.user.settings.no_items') }}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
|
||||
@endsection
|
||||
32
resources/views/users/scripts.blade.php
Normal file
32
resources/views/users/scripts.blade.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<script src="/js/select2.min.js"></script>
|
||||
<script>
|
||||
$( function() {
|
||||
|
||||
var elem = $('.color-picker')[0];
|
||||
var hueb = new Huebee( elem, {
|
||||
// options
|
||||
});
|
||||
|
||||
var availableTags = @json(App\Item::supportedOptions());
|
||||
|
||||
$( "#appname" ).autocomplete({
|
||||
source: availableTags,
|
||||
select: function( event, ui ) {
|
||||
$.post('/appload', { app: ui.item.value }, function(data) {
|
||||
$('#appimage').html("<img src='/storage/"+data.icon+"' /><input type='hidden' name='icon' value='"+data.icon+"' />");
|
||||
$('input[name=colour]').val(data.colour);
|
||||
hueb.setColor( data.colour );
|
||||
$('input[name=pinned]').prop('checked', true);
|
||||
if(data.config != null) {
|
||||
$.get('/view/'+data.config, function(getdata) {
|
||||
$('#sapconfig').html(getdata).show();
|
||||
});
|
||||
}
|
||||
}, "json");
|
||||
}
|
||||
});
|
||||
|
||||
$('.tags').select2();
|
||||
|
||||
});
|
||||
</script>
|
||||
52
resources/views/users/trash.blade.php
Normal file
52
resources/views/users/trash.blade.php
Normal file
@@ -0,0 +1,52 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<section class="module-container">
|
||||
<header>
|
||||
<div class="section-title">
|
||||
Showing Deleted Applications
|
||||
</div>
|
||||
<div class="module-actions">
|
||||
<a href="{{ route('items.index', [], false) }}" title="" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('app.title') }}</th>
|
||||
<th>Url</th>
|
||||
<th class="text-center" width="100">{{ __('app.restore') }}</th>
|
||||
<th class="text-center" width="100">{{ __('app.delete') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if($trash->first())
|
||||
@foreach($trash as $app)
|
||||
<tr>
|
||||
<td>{{ $app->title }}</td>
|
||||
<td>{{ __('app.url') }}</td>
|
||||
<td class="text-center"><a href="{!! route('items.restore', [$app->id], false) !!}" title="{{ __('app.restore') }} {!! $app->title !!}"><i class="fas fa-undo"></i></a></td>
|
||||
<td class="text-center">
|
||||
{!! Form::open(['method' => 'DELETE','route' => ['items.destroy', $app->id],'style'=>'display:inline']) !!}
|
||||
<input type="hidden" name="force" value="1" />
|
||||
<button type="submit"><i class="fa fa-trash-alt"></i></button>
|
||||
{!! Form::close() !!}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@else
|
||||
<tr>
|
||||
<td colspan="5" class="form-error text-center">
|
||||
<strong>{{ __('app.settings.no_items') }}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
|
||||
@endsection
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user