Compare commits

...

41 Commits

Author SHA1 Message Date
snipe 2844800caf Merge remote-tracking branch 'origin/develop'
# Conflicts:
#	config/version.php
2020-10-26 14:26:05 -07:00
snipe b7e8b9bad7 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2020-10-26 14:24:43 -07:00
snipe a7ecaa6ebc Merge pull request #8619 from uberbrady/fix_ldap_paging
Fixed #8563 - Clean up AdLdap2 integration to better handle paged result-sets
2020-10-26 14:24:34 -07:00
snipe 7937258f6e Bumped version 2020-10-26 14:24:19 -07:00
Brady Wetherington cce0739bb7 Clean up AdLdap2 integration to better handle paged result-sets 2020-10-26 12:53:45 -07:00
snipe c93f4ef0d5 Merge remote-tracking branch 'origin/develop' 2020-10-23 19:50:56 -07:00
snipe 89e36dbc42 Merge pull request #8606 from uberbrady/fix_cant_manage_self
Add a new custom validator for Users
2020-10-23 19:16:11 -07:00
snipe d317052ede Updated CSS assets with green skin edits 2020-10-23 18:55:00 -07:00
snipe 8ee9e5e059 Fixed #8537 - wrong sorting on dashboard 2020-10-23 18:33:10 -07:00
snipe 2602e4d602 Exclude the config directory from backups
Everything there is handled via .env anyway
2020-10-23 18:21:32 -07:00
snipe f357d9fc90 Include audit settings text in settings overview so they get picked up by the filter box 2020-10-23 18:13:28 -07:00
Brady Wetherington 0eda53c484 Add a new custom validator for Users to prevent someone from managing themselves 2020-10-23 16:55:10 -07:00
snipe 79a4acae1a Merge remote-tracking branch 'origin/develop'
# Conflicts:
#	config/version.php
2020-10-23 14:29:40 -07:00
snipe 91e0b26bbb Bumped version 2020-10-23 14:28:55 -07:00
snipe 5f82214703 Merge remote-tracking branch 'origin/develop' 2020-10-23 14:24:24 -07:00
Brady Wetherington d517e2fd61 Merge pull request #8594 from uberbrady/try_to_fix_ldap_oom
Possible fix to #8563 - unset $ldapUsers to avoid OOM'ing
2020-10-23 14:23:53 -07:00
snipe 28612d8b61 Merge remote-tracking branch 'origin/develop' 2020-10-23 14:23:46 -07:00
snipe 6ee3d0eb97 Merge pull request #8605 from snipe/fixes/legacy_location_id_equals_zero
Fix for legacy location_id=0 issue that can cause failure to checkout/checkin
2020-10-23 14:22:53 -07:00
snipe 7987a4eca4 Used consistent phrasing in query 2020-10-23 14:22:15 -07:00
snipe 2aa8e1e76b Merge pull request #8596 from snipe/fixes/8462_move_accessory_notes
Fixes #8462 - move accessory notes into pivot table
2020-10-23 14:19:51 -07:00
snipe be0e327221 Simplified the migration 2020-10-23 14:14:34 -07:00
snipe 9a1acced58 Fix for legacy location_id=0 issue 2020-10-23 14:00:04 -07:00
snipe d74df93c48 Merge remote-tracking branch 'origin/develop' 2020-10-23 12:10:13 -07:00
snipe b9a9949570 Use the form partial for avatars 2020-10-23 12:09:20 -07:00
snipe 4ccba5337a Added https://gravatar address to CSP 2020-10-23 12:09:03 -07:00
snipe 8aae2b46cd Merge remote-tracking branch 'origin/develop' 2020-10-23 11:56:10 -07:00
snipe d03d4deef9 Temp fix for #8561 - manager_id validation error 2020-10-23 11:55:53 -07:00
snipe 21ceea0aed Removed extra debugging 2020-10-23 08:19:04 -07:00
snipe 2219c9ccb5 Merge remote-tracking branch 'origin/develop' 2020-10-23 06:55:39 -07:00
snipe bf9e53fbe7 Updated markdown templates 2020-10-23 06:55:23 -07:00
snipe f68580b482 Make the email table wider 2020-10-23 06:55:04 -07:00
snipe aec2f2a249 Fixed #8576 - switch to HTML from markdown
This is really stupid. A markdown table with over 3 columns doesn’t render correctly. :(
2020-10-23 06:54:45 -07:00
snipe 831da2d6d1 New mail vendor files 2020-10-23 06:17:07 -07:00
snipe f2aebe5f9a Fixed #8558 - error on asset acceptance when no sig is required 2020-10-23 05:09:03 -07:00
snipe 40c0ba9a95 Merge remote-tracking branch 'origin/develop' 2020-10-23 04:46:44 -07:00
snipe f5a0726f98 Fixed #8597 - Added leading slash to notifications console commands 2020-10-23 04:46:26 -07:00
snipe 2263dae8f4 Fixed HTML 2020-10-23 04:07:55 -07:00
snipe 88f03e6b55 Added last_checkout and notes from pivot for accessories 2020-10-23 00:44:26 -07:00
snipe 8827d33a43 Fixed query to copy notes 2020-10-23 00:25:20 -07:00
snipe 66ac5d05ad Started migration to normalize note 2020-10-22 23:18:14 -07:00
Brady Wetherington 18012279f9 Possible fix to #8563 - unset $ldapUsers to avoid OOM'ing 2020-10-22 21:51:23 -07:00
51 changed files with 492 additions and 290 deletions
+5 -10
View File
@@ -117,7 +117,7 @@ class LdapSync extends Command
$this->dryrun = true;
}
$this->checkIfLdapIsEnabled();
$this->checkLdapConnetion();
$this->checkLdapConnection();
$this->setBaseDn();
$this->getUserDefaultLocation();
/*
@@ -221,12 +221,11 @@ class LdapSync extends Command
*
* @since 5.0.0
*
* @param int $page The page to get the result set
*/
private function processLdapUsers(int $page=0): void
private function processLdapUsers(): void
{
try {
$ldapUsers = $this->ldap->getLdapUsers($page);
$ldapUsers = $this->ldap->getLdapUsers();
} catch (Exception $e) {
$this->outputError($e);
exit($e->getMessage());
@@ -242,13 +241,9 @@ class LdapSync extends Command
}
// Process each individual users
foreach ($ldapUsers as $user) {
foreach ($ldapUsers->getResults() as $user) { // AdLdap2's paginate() method is weird, it gets *everything* and ->getResults() returns *everything*
$this->updateCreateUser($user);
}
if ($ldapUsers->getCurrentPage() < $ldapUsers->getPages()-1) {
$this->processLdapUsers($ldapUsers->getCurrentPage() + 1);
}
}
/**
@@ -355,7 +350,7 @@ class LdapSync extends Command
*
* @since 5.0.0
*/
private function checkLdapConnetion(): void
private function checkLdapConnection(): void
{
try {
$this->ldap->testLdapAdUserConnection();
@@ -58,7 +58,7 @@ class SendExpectedCheckinAlerts extends Command
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
return new AlertRecipient($item);
});
Notification::send($recipients, new ExpectedCheckinAdminNotification($assets));
\Notification::send($recipients, new ExpectedCheckinAdminNotification($assets));
}
}
}
@@ -55,14 +55,14 @@ class SendExpirationAlerts extends Command
$assets = Asset::getExpiringWarrantee($threshold);
if ($assets->count() > 0) {
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $threshold]));
Notification::send($recipients, new ExpiringAssetsNotification($assets, $threshold));
\Notification::send($recipients, new ExpiringAssetsNotification($assets, $threshold));
}
// Expiring licenses
$licenses = License::getExpiringLicenses($threshold);
if ($licenses->count() > 0) {
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $threshold]));
Notification::send($recipients, new ExpiringLicenseNotification($licenses, $threshold));
\Notification::send($recipients, new ExpiringLicenseNotification($licenses, $threshold));
}
} else {
if ($settings->alert_email == '') {
+1 -1
View File
@@ -52,7 +52,7 @@ class SendInventoryAlerts extends Command
return new AlertRecipient($item);
});
Notification::send($recipients, new InventoryAlert($items, $settings->alert_threshold));
\Notification::send($recipients, new InventoryAlert($items, $settings->alert_threshold));
}
} else {
if ($settings->alert_email == '') {
@@ -75,7 +75,8 @@ class AccessoryCheckoutController extends Controller
'accessory_id' => $accessory->id,
'created_at' => Carbon::now(),
'user_id' => Auth::id(),
'assigned_to' => $request->get('assigned_to')
'assigned_to' => $request->get('assigned_to'),
'note' => $request->input('note')
]);
DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first();
@@ -94,7 +94,7 @@ class AcceptanceController extends Controller {
if (!Storage::exists('private_uploads/signatures')) Storage::makeDirectory('private_uploads/signatures', 775);
$sig_filename = '';
if ($request->filled('signature_output')) {
$sig_filename = "siglog-" .Str::uuid() . '-'.date('Y-m-d-his').".png";
$data_uri = e($request->input('signature_output'));
@@ -154,7 +154,6 @@ class AccessoriesController extends Controller
$offset = request('offset', 0);
$limit = request('limit', 50);
$accessory->lastCheckoutArray = $accessory->lastCheckout->toArray();
$accessory_users = $accessory->users;
$total = $accessory_users->count();
@@ -76,9 +76,32 @@ class AssetCheckinController extends Controller
$asset->status_id = e($request->get('status_id'));
}
// This is just meant to correct legacy issues where some user data would have 0
// as a location ID, which isn't valid. Later versions of Snipe-IT have stricter validation
// rules, so it's necessary to fix this for long-time users. It's kinda gross, but will help
// people (and their data) in the long run
if ($asset->rtd_location_id=='0') {
\Log::debug('Manually override the RTD location IDs');
\Log::debug('Original RTD Location ID: '.$asset->rtd_location_id);
$asset->rtd_location_id = '';
\Log::debug('New RTD Location ID: '.$asset->rtd_location_id);
}
if ($asset->location_id=='0') {
\Log::debug('Manually override the location IDs');
\Log::debug('Original Location ID: '.$asset->location_id);
$asset->location_id = '';
\Log::debug('New RTD Location ID: '.$asset->location_id);
}
$asset->location_id = $asset->rtd_location_id;
\Log::debug('After Location ID: '.$asset->location_id);
\Log::debug('After RTD Location ID: '.$asset->rtd_location_id);
if ($request->filled('location_id')) {
\Log::debug('NEW Location ID: '.$request->get('location_id'));
$asset->location_id = e($request->get('location_id'));
}
@@ -97,6 +120,6 @@ class AssetCheckinController extends Controller
return redirect()->route("hardware.index")->with('success', trans('admin/hardware/message.checkin.success'));
}
// Redirect to the asset management page with error
return redirect()->route("hardware.index")->with('error', trans('admin/hardware/message.checkin.error'));
return redirect()->route("hardware.index")->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
}
}
@@ -80,7 +80,7 @@ class AssetCheckoutController extends Controller
}
// Redirect to the asset management page with error
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($asset->getErrors());
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
} catch (ModelNotFoundException $e) {
return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($asset->getErrors());
} catch (CheckoutNotAllowed $e) {
+1 -1
View File
@@ -106,7 +106,7 @@ class SecurityHeaders
$csp_policy[] = "connect-src 'self'";
$csp_policy[] = "object-src 'none'";
$csp_policy[] = "font-src 'self' data:";
$csp_policy[] = "img-src 'self' data: gravatar.com maps.google.com maps.gstatic.com *.googleapis.com";
$csp_policy[] = "img-src 'self' data: ".config('app.url')." https://secure.gravatar.com http://gravatar.com maps.google.com maps.gstatic.com *.googleapis.com";
$csp_policy = join(';', $csp_policy);
$response->headers->set('Content-Security-Policy', $csp_policy);
}
+1 -1
View File
@@ -34,7 +34,7 @@ class SaveUserRequest extends FormRequest
{
$rules = [
'manager_id' => "nullable|exists:users,id|different:users.id"
'manager_id' => "nullable|exists:users,id"
];
switch($this->method())
@@ -68,8 +68,13 @@ class AccessoriesTransformer
$array = array();
foreach ($accessory_users as $user) {
\Log::debug(print_r($user->pivot, true));
\Log::debug(print_r($user->pivot, true));
$array[] = [
'assigned_pivot_id' => $user->pivot->id,
'id' => (int) $user->id,
'username' => e($user->username),
@@ -77,7 +82,8 @@ class AccessoriesTransformer
'first_name'=> e($user->first_name),
'last_name'=> e($user->last_name),
'employee_number' => e($user->employee_num),
'checkout_notes' => $accessory->lastCheckoutArray[0]['note'],
'checkout_notes' => $user->pivot->note,
'last_checkout' => Helper::getFormattedDateObject($user->pivot->created_at, 'datetime'),
'type' => 'user',
'available_actions' => ['checkin' => true]
];
+1 -1
View File
@@ -234,7 +234,7 @@ class Accessory extends SnipeModel
public function users()
{
return $this->belongsToMany('\App\Models\User', 'accessories_users', 'accessory_id', 'assigned_to')->withPivot('id')->withTrashed();
return $this->belongsToMany('\App\Models\User', 'accessories_users', 'accessory_id', 'assigned_to')->withPivot('id', 'created_at', 'note')->withTrashed();
}
/**
-3
View File
@@ -120,9 +120,6 @@ class Setting extends Model
try {
$usercount = User::withTrashed()->count();
$settingsCount = self::count();
\Log::debug('User table and settings table exist and have records.');
\Log::debug('Settings: '.$settingsCount );
\Log::debug('Users: '.$usercount );
return $usercount > 0 && $settingsCount > 0;
} catch (\Throwable $th) {
\Log::debug('User table and settings table DO NOT exist or DO NOT have records');
+3 -2
View File
@@ -74,7 +74,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'password' => 'required|min:8',
'locale' => 'max:10|nullable',
'website' => 'url|nullable',
'manager_id' => 'nullable|exists:users,id|different:users.id',
'manager_id' => 'nullable|exists:users,id|cant_manage_self',
'location_id' => 'exists:locations,id|nullable',
];
@@ -295,7 +295,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
*/
public function accessories()
{
return $this->belongsToMany('\App\Models\Accessory', 'accessories_users', 'assigned_to', 'accessory_id')->withPivot('id')->withTrashed();
return $this->belongsToMany('\App\Models\Accessory', 'accessories_users', 'assigned_to', 'accessory_id')
->withPivot('id', 'created_at', 'note')->withTrashed();
}
/**
@@ -107,6 +107,27 @@ class ValidationServiceProvider extends ServiceProvider
return preg_match('/\p{Z}|\p{S}|\p{P}/', $value);
});
Validator::extend('cant_manage_self', function ($attribute, $value, $parameters, $validator) {
// $value is the actual *value* of the thing that's being validated
// $attribute is the name of the field that the validation is running on - probably manager_id in our case
// $parameters are the optional parameters - an array for everything, split on commas. But we don't take any params here.
// $validator gives us proper access to the rest of the actual data
$data = $validator->getData();
if(array_key_exists("id", $data)) {
if ($value && $value == $data['id']) {
// if you definitely have an ID - you're saving an existing user - and your ID matches your manager's ID - fail.
return false;
} else {
return true;
}
} else {
// no 'id' key to compare against (probably because this is a new user)
// so it automatically passes this validation
return true;
}
});
}
+1
View File
@@ -48,6 +48,7 @@ return [
*/
'exclude' => [
base_path('vendor'),
base_path('config'),
base_path('node_modules'),
],
+5 -5
View File
@@ -1,10 +1,10 @@
<?php
return array (
'app_version' => 'v5.0.2',
'full_app_version' => 'v5.0.2 - build 5414-gc3e8f6406',
'build_version' => '5414',
'app_version' => 'v5.0.4',
'full_app_version' => 'v5.0.4 - build 5452-gc93f4ef0d',
'build_version' => '5452',
'prerelease_version' => '',
'hash_version' => 'gc3e8f6406',
'full_hash' => 'v5.0.1-19-gc3e8f6406',
'hash_version' => 'gc93f4ef0d',
'full_hash' => 'v5.0.4-7-gc93f4ef0d',
'branch' => 'master',
);
@@ -0,0 +1,89 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\Accessory;
use App\Models\Actionlog;
class MoveAccessoryCheckoutNoteToJoinTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('accessories_users', function (Blueprint $table) {
$table->string('note')->nullable(true)->default(null);
});
// Loop through the checked out accessories, find their related action_log entry, and copy over the note
// to the newly created note field
$accessories = Accessory::get();
$count = 0;
\Log::debug('Accessory Count: '. $accessories->count());
// Loop through all of the accessories
foreach ($accessories as $accessory) {
$count++;
\Log::debug('Querying join logs');
$join_logs = DB::table('accessories_users')->get();
// Loop through the accessories_users records
foreach ($join_logs as $join_log) {
\Log::debug($join_logs->count().' join log records');
\Log::debug('Looking for accessories_users that match '. $join_log->created_at);
// Get the records from action_logs so we can copy the notes over to the new notes field
// on the accessories_users table
$action_log_entries = Actionlog::where('created_at', '=',$join_log->created_at)
->where('target_id', '=',$join_log->assigned_to)
->where('item_id', '=',$accessory->id)
->where('target_type', '=','App\\Models\\User')
->where('action_type', '=', 'checkout')
->orderBy('created_at', 'DESC')->get();
\Log::debug($action_log_entries->count().' matching entries in the action_logs table');
\Log::debug('Looking for action_logs that match '. $join_log->created_at);
foreach ($action_log_entries as $action_log_entry) {
\Log::debug('Checkout date in asset log: '.$action_log_entry->created_at.' against accessories_users: '.$join_log->created_at);
\Log::debug('Action log: '.$action_log_entry->created_at);
\Log::debug('Join log: '.$join_log->created_at);
if ($action_log_entry->created_at == $join_log->created_at) {
DB::table('accessories_users')
->where('id', $join_log->id)
->update(['note' => $action_log_entry->note]);
} else {
\Log::debug('No match');
}
}
}
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('accessories_users', function (Blueprint $table) {
$table->dropColumn('note');
});
}
}
@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\User;
use App\Models\Asset;
class FixZeroValuesForLocations extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
App\Models\Asset::where('location_id', '=', '0')
->update(['location_id' => null]);
App\Models\Asset::where('rtd_location_id', '=', '0')
->update(['rtd_location_id' => null]);
App\Models\User::where('location_id', '=', '0')
->update(['location_id' => null]);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}
+35 -15
View File
@@ -4170,7 +4170,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@@ -4191,12 +4192,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -4211,17 +4214,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -4338,7 +4344,8 @@
"inherits": {
"version": "2.0.4",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@@ -4350,6 +4357,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -4364,6 +4372,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -4371,12 +4380,14 @@
"minimist": {
"version": "1.2.5",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -4395,6 +4406,7 @@
"version": "0.5.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "^1.2.5"
}
@@ -4456,7 +4468,8 @@
"npm-normalize-package-bin": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.4.8",
@@ -4484,7 +4497,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -4496,6 +4510,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -4573,7 +4588,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -4609,6 +4625,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -4628,6 +4645,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -4671,12 +4689,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},
@@ -5826,7 +5846,8 @@
},
"js-yaml": {
"version": "3.7.0",
"resolved": "",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
"integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
"dev": true,
"requires": {
"argparse": "^1.0.7",
@@ -6035,7 +6056,6 @@
"integrity": "sha512-J9X76xnncMw+wIqb15HeWfPMqPwYxSpPY8yWPJ7rAZN/ZDzFkjCSZObryCyUe8zbrVRNiuCnIeQteCzMn7GnWw==",
"requires": {
"canvg": "1.5.3",
"file-saver": "github:eligrey/FileSaver.js#e865e37af9f9947ddcced76b549e27dc45c1cb2e",
"html2canvas": "1.0.0-alpha.12",
"omggif": "1.0.7",
"promise-polyfill": "8.1.0",
@@ -6044,7 +6064,7 @@
"dependencies": {
"file-saver": {
"version": "github:eligrey/FileSaver.js#e865e37af9f9947ddcced76b549e27dc45c1cb2e",
"from": "github:eligrey/FileSaver.js#1.3.8"
"from": "github:eligrey/FileSaver.js#e865e37af9f9947ddcced76b549e27dc45c1cb2e"
}
}
},
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+4 -4
View File
@@ -7,7 +7,7 @@
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=747948e5f269f64047f7",
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=d7996d850e8bcdc4e167",
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=eb25d2ec49f730d09431",
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=0cfa39cacd9c83b4f53b",
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=8dfcf59850a3f5775b8c",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=35602987835e5d50d162",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=6bd9c2420a41eaf96f0b",
"/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=60de5bc2660c35544c4d",
@@ -19,9 +19,9 @@
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=71c178700d68294e3413",
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=b4fc4a74e1f6367dc3e2",
"/css/dist/all.css": "/css/dist/all.css?id=6e3b75006f2b19d69f37",
"/css/blue.png": "/css/blue.png?id=e83a6c29e04fe851f212",
"/css/blue@2x.png": "/css/blue@2x.png?id=51135dd4d24f88f5de0b",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=0cfa39cacd9c83b4f53b",
"/css/blue.png": "/css/blue.png?id=4c85d6a97173123bd14a",
"/css/blue@2x.png": "/css/blue@2x.png?id=62c67c6a822439e8a4ac",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=8dfcf59850a3f5775b8c",
"/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=6bd9c2420a41eaf96f0b",
"/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=2f665cf40d7348b3f94c",
"/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=4a19f5ae861f98f40bab",
+1
View File
@@ -117,6 +117,7 @@ return array(
"hashed_pass" => "Your current password is incorrect",
"statuslabel_type" => "You must select a valid status label type",
],
'cant_manage_self' => "A user cannot be their own manager",
/*
|--------------------------------------------------------------------------
@@ -76,6 +76,7 @@
<tr>
<th data-searchable="false" data-formatter="usersLinkFormatter" data-sortable="false" data-field="name">{{ trans('general.user') }}</th>
<th data-searchable="false" data-sortable="false" data-field="checkout_notes">{{ trans('general.notes') }}</th>
<th data-searchable="false" data-formatter="dateDisplayFormatter" data-sortable="false" data-field="last_checkout">{{ trans('admin/hardware/table.checkout_date') }}</th>
<th data-searchable="false" data-sortable="false" data-field="actions" data-formatter="accessoriesInOutFormatter">{{ trans('table.actions') }}</th>
</tr>
</thead>
+14 -17
View File
@@ -94,28 +94,25 @@
</div>
<!-- Avatar -->
@if ($user->avatar)
<div class="form-group {{ $errors->has('avatar_delete') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="avatar_delete">{{ trans('general.avatar_delete') }}</label>
<div class="col-md-8">
{{ Form::checkbox('avatar_delete') }}
<img src="{{ url('/') }}/uploads/avatars/{{ $user->avatar }}" class="avatar img-circle" alt="{{ $user->present()->fullName() }} avatar image">
{!! $errors->first('avatar_delete', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<div class="form-group {{ $errors->has('image_delete') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="avatar_delete">{{ trans('general.image_delete') }}</label>
<div class="col-md-9">
<label for="avatar_delete">
{{ Form::checkbox('avatar_delete', '1', old('avatar_delete'), array('class' => 'minimal')) }}
</label>
<br>
<img src="{{ url('/') }}/uploads/avatars/{{ $user->avatar }}" alt="{{ $user->present()->fullName() }} avatar image">
{!! $errors->first('avatar_delete', '<span class="alert-msg" aria-hidden="true"><br>:message</span>') !!}
</div>
</div>
@endif
<div class="form-group {{ $errors->has('avatar') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="avatar">{{ trans('general.image_upload') }}</label>
<div class="col-md-5">
<label class="btn btn-default">
{{ trans('button.select_file') }}
<input type="file" name="avatar" accept="image/gif,image/jpeg,image/png,image/svg" hidden>
</label>
<p class="help-block">{{ trans('general.image_filetypes_help') }}</p>
{!! $errors->first('avatar', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
@include ('partials.forms.edit.image-upload', ['fieldname' => 'avatar'])
+3
View File
@@ -178,6 +178,9 @@
<table
data-cookie-id-table="dashActivityReport"
data-height="400"
data-pagination="false"
data-id-table="dashActivityReport"
data-side-pagination="server"
data-sort-order="desc"
data-sort-name="created_at"
id="dashActivityReport"
+2 -2
View File
@@ -71,7 +71,7 @@
@if (!$asset->model)
<div class="col-md-12">
<div class="callout callout-danger">
<h2>NO MODEL ASSOCIATED</h4>
<h2>NO MODEL ASSOCIATED</h2>
<p>This will break things in weird and horrible ways. Edit this asset now to assign it a model. </p>
</div>
</div>
@@ -735,7 +735,7 @@
@endif
@if (($asset->assignedTo) && ($asset->deleted_at==''))
<h2>{{ trans('admin/hardware/form.checkedout_to') }}</h4>
<h2>{{ trans('admin/hardware/form.checkedout_to') }}</h2>
<p>
@if($asset->checkedOutToUser()) <!-- Only users have avatars currently-->
<img src="{{ $asset->assignedTo->present()->gravatar() }}" class="user-image-inline" alt="{{ $asset->assignedTo->present()->fullName() }}">
@@ -1,20 +1,17 @@
@component('mail::message')
{{ trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count'=>$assets->count(), 'threshold' => $threshold]) }}
@component('mail::table')
| |{{ trans('mail.name') }} |{{ trans('mail.expires') }} |{{ trans('mail.Days') }}|{{ trans('mail.supplier') }} | {{ trans('mail.assigned_to') }}
| |:------------- |:-------------|:---------|:---------|:---------|:---------|
<table width="100%">
<tr><td>&nbsp;</td><td>{{ trans('mail.name') }}</td><td>{{ trans('mail.Days') }}</td><td>{{ trans('mail.expires') }}</td><td>{{ trans('mail.supplier') }}</td><td>{{ trans('mail.assigned_to') }}</td></tr>
@foreach ($assets as $asset)
@php
$expires = \App\Helpers\Helper::getFormattedDateObject($asset->present()->warrantee_expires, 'date');
$diff = round(abs(strtotime($asset->present()->warrantee_expires) - strtotime(date('Y-m-d')))/86400);
$icon = ($diff <= ($threshold / 2)) ? '🚨' : (($diff <= $threshold) ? '⚠️' : ' ');
@endphp
|{{ $icon }}| [{{ $asset->present()->name }}]({{ route('hardware.show', $asset->id) }}) | {{ $expires['formatted'] }} | {{ $diff }} {{ trans('mail.Days') }} | {{ ($asset->supplier ? e($asset->supplier->name) : '') }}|{{ ($asset->assignedTo ? e($asset->assignedTo->present()->name()) : '') }}
<tr><td>{{ $icon }} </td><td> <a href="{{ route('hardware.show', $asset->id) }}">{{ $asset->present()->name }}</a> </td><td> {{ $diff }} {{ trans('mail.Days') }} </td><td> {{ $expires['formatted'] }} </td><td> {{ ($asset->supplier ? e($asset->supplier->name) : '') }} </td><td> {{ ($asset->assignedTo ? e($asset->assignedTo->present()->name()) : '') }} </td></tr>
@endforeach
</table>
@endcomponent
@endcomponent
+2 -1
View File
@@ -139,9 +139,10 @@
<i class="fa fa-bell fa-4x" aria-hidden="true"></i>
<br><br>
<span class="name">Notifications</span>
</a>
</h5>
<p class="help-block">Email alerts</p>
<p class="help-block">Email alerts, audit settings</p>
</div>
</div>
</div>
+18 -18
View File
@@ -1,19 +1,19 @@
<table class="action" align="center" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center">
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td align="center">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<a href="{{ $url }}" class="button button-{{ $color ?? 'blue' }}" target="_blank">{{ $slot }}</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<table class="action" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table border="0" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td>
<a href="{{ $url }}" class="button button-{{ $color ?? 'primary' }}" target="_blank">{{ $slot }}</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
+9 -9
View File
@@ -1,11 +1,11 @@
<tr>
<td>
<table class="footer" align="center" width="570" cellpadding="0" cellspacing="0">
<tr>
<td class="content-cell" align="center">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
</table>
</td>
<td>
<table class="footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="content-cell" align="center">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
</table>
</td>
</tr>
+5 -33
View File
@@ -1,35 +1,7 @@
<tr>
<td class="header"{!! ($snipeSettings->header_color!='') ? ' style="background-color: '.e($snipeSettings->header_color).'"' : '' !!}>
@if (($snipeSettings->show_images_in_email=='1' ) && ($snipeSettings::setupCompleted()))
<!-- show text and logo -->
@if ($snipeSettings->brand == '3')
@if ($snipeSettings->email_logo!='')
<img class="logo-text" src="{{ Storage::disk('public')->url('').e($snipeSettings->email_logo) }}"alt="{{ $snipeSettings->site_name }}">
@elseif ($snipeSettings->logo!='')
<img class="logo-text" src="{{ Storage::disk('public')->url('').e($snipeSettings->logo) }}"alt="{{ $snipeSettings->site_name }}">
@endif
{{ $snipeSettings->site_name }}
<!-- show only logo -->
@elseif ($snipeSettings->brand == '2')
@if ($snipeSettings->email_logo!='')
<img class="logo-only" style="float:left" src="{{ Storage::disk('public')->url('').e($snipeSettings->email_logo) }}" alt="{{ $snipeSettings->site_name }}">
@elseif ($snipeSettings->logo!='')
<img class="logo-only" src="{{ Storage::disk('public')->url('').e($snipeSettings->logo) }}" alt="{{ $snipeSettings->site_name }}">
@endif
<!-- show only text -->
@else
{{ $snipeSettings->site_name }}
@endif
@else
{{ $snipeSettings->site_name }}
@endif
</td>
<td class="header">
<a href="{{ $url }}">
{{ $slot }}
</a>
</td>
</tr>
+41 -47
View File
@@ -1,60 +1,54 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<style>
@media only screen and (max-width: 600px) {
.inner-body {
width: 100% !important;
}
<style>
@media only screen and (max-width: 600px) {
.inner-body {
width: 100% !important;
}
.footer {
width: 100% !important;
}
}
.footer {
width: 100% !important;
}
}
@media only screen and (max-width: 500px) {
.button {
width: 100% !important;
}
}
.logo {
width:50px;
height:50px;
}
</style>
@media only screen and (max-width: 500px) {
.button {
width: 100% !important;
}
}
</style>
<table class="wrapper" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center">
<table class="content" width="100%" cellpadding="0" cellspacing="0">
{{ $header ?? '' }}
<table class="wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table class="content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
{{ $header ?? '' }}
<!-- Email Body -->
<tr>
<td class="body" width="100%" cellpadding="0" cellspacing="0">
<table class="inner-body" align="center" width="90%" cellpadding="0" cellspacing="0">
<!-- Body content -->
<tr>
<td class="content-cell">
{{ Illuminate\Mail\Markdown::parse($slot) }}
<!-- Email Body -->
<tr>
<td class="body" width="100%" cellpadding="0" cellspacing="0">
<table class="inner-body" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<!-- Body content -->
<tr>
<td class="content-cell">
{{ Illuminate\Mail\Markdown::parse($slot) }}
{{ $subcopy ?? '' }}
</td>
</tr>
</table>
</td>
</tr>
{{ $subcopy ?? '' }}
</td>
</tr>
</table>
</td>
</tr>
{{ $footer ?? '' }}
</table>
</td>
</tr>
</table>
{{ $footer ?? '' }}
</table>
</td>
</tr>
</table>
</body>
</html>
+3 -2
View File
@@ -1,7 +1,7 @@
<table class="panel" width="100%" cellpadding="0" cellspacing="0">
<table class="panel" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="panel-content">
<table width="100%" cellpadding="0" cellspacing="0">
<table width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="panel-item">
{{ Illuminate\Mail\Markdown::parse($slot) }}
@@ -11,3 +11,4 @@
</td>
</tr>
</table>
+6 -6
View File
@@ -1,7 +1,7 @@
<table class="promotion" align="center" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
<table class="promotion" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
</table>
@@ -1,7 +1,7 @@
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table border="0" cellpadding="0" cellspacing="0">
<table border="0" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td>
<a href="{{ $url }}" class="button button-green" target="_blank">{{ $slot }}</a>
+6 -6
View File
@@ -1,7 +1,7 @@
<table class="subcopy" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td>
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
<table class="subcopy" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td>
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
</table>
+54 -54
View File
@@ -1,13 +1,15 @@
/* Base */
body, body *:not(html):not(style):not(br):not(tr):not(code) {
font-family: Avenir, Helvetica, sans-serif;
body,
body *:not(html):not(style):not(br):not(tr):not(code) {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
box-sizing: border-box;
}
body {
background-color: #f5f8fa;
color: #74787E;
background-color: #f8fafc;
color: #74787e;
height: 100%;
hyphens: auto;
line-height: 1.4;
@@ -30,7 +32,7 @@ blockquote {
}
a {
color: #3869D4;
color: #3869d4;
}
a img {
@@ -40,7 +42,7 @@ a img {
/* Typography */
h1 {
color: #2F3133;
color: #3d4852;
font-size: 19px;
font-weight: bold;
margin-top: 0;
@@ -48,7 +50,7 @@ h1 {
}
h2 {
color: #2F3133;
color: #3d4852;
font-size: 16px;
font-weight: bold;
margin-top: 0;
@@ -56,7 +58,7 @@ h2 {
}
h3 {
color: #2F3133;
color: #3d4852;
font-size: 14px;
font-weight: bold;
margin-top: 0;
@@ -64,7 +66,7 @@ h3 {
}
p {
color: #74787E;
color: #3d4852;
font-size: 16px;
line-height: 1.5em;
margin-top: 0;
@@ -82,7 +84,7 @@ img {
/* Layout */
.wrapper {
background-color: #f5f8fa;
background-color: #f8fafc;
margin: 0;
padding: 0;
width: 100%;
@@ -105,7 +107,6 @@ img {
.header {
padding: 25px 0;
text-align: center;
font-size: 20px;
}
.header a {
@@ -119,9 +120,9 @@ img {
/* Body */
.body {
background-color: #FFFFFF;
border-bottom: 1px solid #EDEFF2;
border-top: 1px solid #EDEFF2;
background-color: #ffffff;
border-bottom: 1px solid #edeff2;
border-top: 1px solid #edeff2;
margin: 0;
padding: 0;
width: 100%;
@@ -131,9 +132,10 @@ img {
}
.inner-body {
background-color: #FFFFFF;
background-color: #ffffff;
margin: 0 auto;
padding: 0;
width: 90%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 570px;
@@ -142,7 +144,7 @@ img {
/* Subcopy */
.subcopy {
border-top: 1px solid #EDEFF2;
border-top: 1px solid #edeff2;
margin-top: 25px;
padding-top: 25px;
}
@@ -164,7 +166,7 @@ img {
}
.footer p {
color: #AEAEAE;
color: #aeaeae;
font-size: 12px;
text-align: center;
}
@@ -180,19 +182,21 @@ img {
}
.table th {
border-bottom: 1px solid #EDEFF2;
border-bottom: 1px solid #edeff2;
padding-bottom: 8px;
margin: 0;
}
.table td {
color: #74787E;
color: #74787e;
font-size: 15px;
line-height: 15px;
padding: 8px 0;
line-height: 18px;
padding: 10px 0;
margin: 0;
}
.content-cell {
padding: 20px;
padding: 35px;
}
/* Buttons */
@@ -210,34 +214,37 @@ img {
.button {
border-radius: 3px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16);
color: #FFF;
color: #fff;
display: inline-block;
text-decoration: none;
-webkit-text-size-adjust: none;
}
.button-blue {
background-color: #3097D1;
border-top: 10px solid #3097D1;
border-right: 18px solid #3097D1;
border-bottom: 10px solid #3097D1;
border-left: 18px solid #3097D1;
.button-blue,
.button-primary {
background-color: #3490dc;
border-top: 10px solid #3490dc;
border-right: 18px solid #3490dc;
border-bottom: 10px solid #3490dc;
border-left: 18px solid #3490dc;
}
.button-green {
background-color: #2ab27b;
border-top: 10px solid #2ab27b;
border-right: 18px solid #2ab27b;
border-bottom: 10px solid #2ab27b;
border-left: 18px solid #2ab27b;
.button-green,
.button-success {
background-color: #38c172;
border-top: 10px solid #38c172;
border-right: 18px solid #38c172;
border-bottom: 10px solid #38c172;
border-left: 18px solid #38c172;
}
.button-red {
background-color: #bf5329;
border-top: 10px solid #bf5329;
border-right: 18px solid #bf5329;
border-bottom: 10px solid #bf5329;
border-left: 18px solid #bf5329;
.button-red,
.button-error {
background-color: #e3342f;
border-top: 10px solid #e3342f;
border-right: 18px solid #e3342f;
border-bottom: 10px solid #e3342f;
border-left: 18px solid #e3342f;
}
/* Panels */
@@ -247,7 +254,7 @@ img {
}
.panel-content {
background-color: #EDEFF2;
background-color: #f1f5f8;
padding: 16px;
}
@@ -263,8 +270,8 @@ img {
/* Promotions */
.promotion {
background-color: #FFFFFF;
border: 2px dashed #9BA2AB;
background-color: #ffffff;
border: 2px dashed #9ba2ab;
margin: 0;
margin-bottom: 25px;
margin-top: 25px;
@@ -284,15 +291,8 @@ img {
text-align: center;
}
.logo-text {
max-width: 150px;
max-height: 150px;
vertical-align:middle;
}
/* Utilities */
.logo-only {
max-width: 640px;
max-height: 150px;
vertical-align:middle;
.break-all {
word-break: break-all;
}
+31 -31
View File
@@ -1,39 +1,39 @@
@component('mail::layout')
{{-- Header --}}
@slot('header')
@component('mail::header', ['url' => config('app.url')])
@if (($snipeSettings->show_images_in_email=='1' ) && ($snipeSettings::setupCompleted()))
{{-- Header --}}
@slot('header')
@component('mail::header', ['url' => config('app.url')])
@if (($snipeSettings->show_images_in_email=='1' ) && ($snipeSettings::setupCompleted()))
@if ($snipeSettings->brand == '3')
@if ($snipeSettings->logo!='')
<img class="navbar-brand-img logo" src="{{ url('/') }}/uploads/{{ $snipeSettings->logo }}">
@endif
{{ $snipeSettings->site_name }}
@if ($snipeSettings->brand == '3')
@if ($snipeSettings->logo!='')
<img class="navbar-brand-img logo" src="{{ url('/') }}/uploads/{{ $snipeSettings->logo }}">
@endif
{{ $snipeSettings->site_name }}
@elseif ($snipeSettings->brand == '2')
@if ($snipeSettings->logo!='')
<img class="navbar-brand-img logo" src="{{ url('/') }}/uploads/{{ $snipeSettings->logo }}">
@endif
@else
{{ $snipeSettings->site_name }}
@endif
@else
Snipe-IT
@endif
@endcomponent
@endslot
@elseif ($snipeSettings->brand == '2')
@if ($snipeSettings->logo!='')
<img class="navbar-brand-img logo" src="{{ url('/') }}/uploads/{{ $snipeSettings->logo }}">
@endif
@else
{{ $snipeSettings->site_name }}
@endif
@else
Snipe-IT
@endif
@endcomponent
@endslot
{{-- Body --}}
{{ $slot }}
{{-- Body --}}
{{ $slot }}
{{-- Subcopy --}}
@isset($subcopy)
@slot('subcopy')
@component('mail::subcopy')
{{ $subcopy }}
@endcomponent
@endslot
@endisset
{{-- Subcopy --}}
@isset($subcopy)
@slot('subcopy')
@component('mail::subcopy')
{{ $subcopy }}
@endcomponent
@endslot
@endisset
{{-- Footer --}}
@slot('footer')
+1
View File
@@ -0,0 +1 @@
{{ $slot }}: {{ $url }}
+1
View File
@@ -0,0 +1 @@
{{ $slot }}
+1
View File
@@ -0,0 +1 @@
[{{ $slot }}]({{ $url }})
+9
View File
@@ -0,0 +1,9 @@
{!! strip_tags($header) !!}
{!! strip_tags($slot) !!}
@isset($subcopy)
{!! strip_tags($subcopy) !!}
@endisset
{!! strip_tags($footer) !!}
+27
View File
@@ -0,0 +1,27 @@
@component('mail::layout')
{{-- Header --}}
@slot('header')
@component('mail::header', ['url' => config('app.url')])
{{ config('app.name') }}
@endcomponent
@endslot
{{-- Body --}}
{{ $slot }}
{{-- Subcopy --}}
@isset($subcopy)
@slot('subcopy')
@component('mail::subcopy')
{{ $subcopy }}
@endcomponent
@endslot
@endisset
{{-- Footer --}}
@slot('footer')
@component('mail::footer')
© {{ date('Y') }} {{ config('app.name') }}. @lang('All rights reserved.')
@endcomponent
@endslot
@endcomponent
+1
View File
@@ -0,0 +1 @@
{{ $slot }}
+1
View File
@@ -0,0 +1 @@
{{ $slot }}
@@ -0,0 +1 @@
[{{ $slot }}]({{ $url }})
+1
View File
@@ -0,0 +1 @@
{{ $slot }}
+1
View File
@@ -0,0 +1 @@
{{ $slot }}