Compare commits
54 Commits
v7.0.7
...
refactor_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1abd669de5 | ||
|
|
ac9df2fc08 | ||
|
|
eba24b9242 | ||
|
|
edd61705dc | ||
|
|
3f20e29901 | ||
|
|
36ae162626 | ||
|
|
00f7cb9dbb | ||
|
|
1ca3dc26eb | ||
|
|
2f3be267b3 | ||
|
|
5b8f6910fb | ||
|
|
9fe26ba814 | ||
|
|
5e97ed1c7e | ||
|
|
947fb7af7a | ||
|
|
44bcc157e5 | ||
|
|
278bf3da13 | ||
|
|
446bc81d3a | ||
|
|
9527aac242 | ||
|
|
c57f1f9d7d | ||
|
|
e372527d13 | ||
|
|
96be1e1275 | ||
|
|
8ce17d0585 | ||
|
|
6af1eaa4e4 | ||
|
|
da01487301 | ||
|
|
708d7b5fc5 | ||
|
|
62b5a159a9 | ||
|
|
a6d04509a5 | ||
|
|
0071596274 | ||
|
|
59f66051f8 | ||
|
|
9f1e59cf78 | ||
|
|
f1f68b8ef6 | ||
|
|
f22c3cdda9 | ||
|
|
5e15cc3bbe | ||
|
|
a6690493b0 | ||
|
|
17a6335d13 | ||
|
|
ca57f6de85 | ||
|
|
aefaabdb1a | ||
|
|
9211c8d3b1 | ||
|
|
eff1980df5 | ||
|
|
1553ba5630 | ||
|
|
ec24120d2a | ||
|
|
50df750202 | ||
|
|
dab4aced48 | ||
|
|
1774952312 | ||
|
|
d66d6e70a6 | ||
|
|
4635e9269d | ||
|
|
574867536d | ||
|
|
5488a4d118 | ||
|
|
e34f3c7c2c | ||
|
|
ceaff7b645 | ||
|
|
d27a025347 | ||
|
|
2b2853a183 | ||
|
|
a25263f868 | ||
|
|
4b9727067b | ||
|
|
00fc392a12 |
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Events\UserMerged;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -51,7 +52,7 @@ class MergeUsersByUsername extends Command
|
||||
|
||||
$bad_users = User::where('username', '=', trim($parts[0]))
|
||||
->whereNull('deleted_at')
|
||||
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')
|
||||
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations','uploads', 'acceptances')
|
||||
->get();
|
||||
|
||||
|
||||
@@ -105,10 +106,26 @@ class MergeUsersByUsername extends Command
|
||||
$managedLocation->save();
|
||||
}
|
||||
|
||||
foreach ($bad_user->uploads as $upload) {
|
||||
$this->info('Updating upload log record '.$upload->id.' to user '.$user->id);
|
||||
$upload->item_id = $user->id;
|
||||
$upload->save();
|
||||
}
|
||||
|
||||
foreach ($bad_user->acceptances as $acceptance) {
|
||||
$this->info('Updating acceptance log record '.$acceptance->id.' to user '.$user->id);
|
||||
$acceptance->item_id = $user->id;
|
||||
$acceptance->save();
|
||||
}
|
||||
|
||||
// Mark the user as deleted
|
||||
$this->info('Marking the user as deleted');
|
||||
$bad_user->deleted_at = Carbon::now()->timestamp;
|
||||
$bad_user->save();
|
||||
|
||||
event(new UserMerged($bad_user, $user, null));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class UserMerged
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(User $from_user, User $to_user, User $admin)
|
||||
public function __construct(User $from_user, User $to_user, ?User $admin)
|
||||
{
|
||||
$this->merged_from = $from_user;
|
||||
$this->merged_to = $to_user;
|
||||
|
||||
@@ -585,49 +585,8 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
$asset = $request->handleImages($asset);
|
||||
$asset = $asset->handleCustomFieldsForStoring($request);
|
||||
|
||||
// Update custom fields in the database.
|
||||
$model = AssetModel::find($request->input('model_id'));
|
||||
|
||||
// Check that it's an object and not a collection
|
||||
// (Sometimes people send arrays here and they shouldn't
|
||||
if (($model) && ($model instanceof AssetModel) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
|
||||
// Set the field value based on what was sent in the request
|
||||
$field_val = $request->input($field->db_column, null);
|
||||
|
||||
// If input value is null, use custom field's default value
|
||||
if ($field_val == null) {
|
||||
Log::debug('Field value for '.$field->db_column.' is null');
|
||||
$field_val = $field->defaultValue($request->get('model_id'));
|
||||
Log::debug('Use the default fieldset value of '.$field->defaultValue($request->get('model_id')));
|
||||
}
|
||||
|
||||
// if the field is set to encrypted, make sure we encrypt the value
|
||||
if ($field->field_encrypted == '1') {
|
||||
Log::debug('This model field is encrypted in this fieldset.');
|
||||
|
||||
if (Gate::allows('admin')) {
|
||||
|
||||
// If input value is null, use custom field's default value
|
||||
if (($field_val == null) && ($request->has('model_id') != '')) {
|
||||
$field_val = Crypt::encrypt($field->defaultValue($request->get('model_id')));
|
||||
} else {
|
||||
$field_val = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($field->element == 'checkbox') {
|
||||
if(is_array($field_val)) {
|
||||
$field_val = implode(',', $field_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
}
|
||||
}
|
||||
|
||||
if ($asset->save()) {
|
||||
if ($request->get('assigned_user')) {
|
||||
@@ -688,32 +647,7 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
$asset = $request->handleImages($asset);
|
||||
$model = AssetModel::find($asset->model_id);
|
||||
|
||||
// Update custom fields
|
||||
$problems_updating_encrypted_custom_fields = false;
|
||||
if (($model) && (isset($model->fieldset))) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
$field_val = $request->input($field->db_column, null);
|
||||
|
||||
if ($request->has($field->db_column)) {
|
||||
if ($field->element == 'checkbox') {
|
||||
if(is_array($field_val)) {
|
||||
$field_val = implode(',', $field_val);
|
||||
}
|
||||
}
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
$field_val = Crypt::encrypt($field_val);
|
||||
} else {
|
||||
$problems_updating_encrypted_custom_fields = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
$asset = $asset->handleCustomFieldsForStoring($request);
|
||||
|
||||
|
||||
if ($asset->save()) {
|
||||
|
||||
@@ -247,10 +247,6 @@ class UsersController extends Controller
|
||||
'jobtitle',
|
||||
'username',
|
||||
'employee_num',
|
||||
'assets',
|
||||
'accessories',
|
||||
'consumables',
|
||||
'licenses',
|
||||
'groups',
|
||||
'activated',
|
||||
'created_at',
|
||||
|
||||
@@ -160,29 +160,7 @@ class AssetsController extends Controller
|
||||
$asset = $request->handleImages($asset);
|
||||
}
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handled through the AssetRequest form request
|
||||
$model = AssetModel::find($request->get('model_id'));
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$asset = $asset->handleCustomFieldsForStoring($request);
|
||||
|
||||
// Validate the asset before saving
|
||||
if ($asset->isValid() && $asset->save()) {
|
||||
@@ -370,32 +348,7 @@ class AssetsController extends Controller
|
||||
$asset->notes = $request->input('notes');
|
||||
|
||||
$asset = $request->handleImages($asset);
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handlded through the AssetRequest form request
|
||||
// FIXME: No idea why this is returning a Builder error on db_column_name.
|
||||
// Need to investigate and fix. Using static method for now.
|
||||
$model = AssetModel::find($request->get('model_id'));
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$asset = $asset->handleCustomFieldsForStoring($request);
|
||||
|
||||
if ($asset->save()) {
|
||||
return redirect()->route('hardware.show', $assetId)
|
||||
@@ -905,7 +858,7 @@ class AssetsController extends Controller
|
||||
if ($request->input('update_location') == '1') {
|
||||
$asset->location_id = $request->input('location_id');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.
|
||||
|
||||
@@ -348,7 +348,6 @@ class SettingsController extends Controller
|
||||
}
|
||||
|
||||
$setting->default_eula_text = $request->input('default_eula_text');
|
||||
$setting->load_remote = $request->input('load_remote', 0);
|
||||
$setting->thumbnail_max_h = $request->input('thumbnail_max_h');
|
||||
$setting->privacy_policy_link = $request->input('privacy_policy_link');
|
||||
$setting->depreciation_method = $request->input('depreciation_method');
|
||||
@@ -393,10 +392,11 @@ class SettingsController extends Controller
|
||||
*
|
||||
* @since [v1.0]
|
||||
*
|
||||
* @return View
|
||||
* @return \Illuminate\Contracts\View\View | \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postBranding(ImageUploadRequest $request)
|
||||
{
|
||||
// Something has gone horribly wrong - no settings record exists!
|
||||
if (is_null($setting = Setting::getSettings())) {
|
||||
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
|
||||
}
|
||||
@@ -407,51 +407,75 @@ class SettingsController extends Controller
|
||||
$setting->version_footer = $request->input('version_footer');
|
||||
$setting->footer_text = $request->input('footer_text');
|
||||
$setting->skin = $request->input('skin');
|
||||
$setting->allow_user_skin = $request->input('allow_user_skin');
|
||||
$setting->allow_user_skin = $request->input('allow_user_skin', '0');
|
||||
$setting->show_url_in_emails = $request->input('show_url_in_emails', '0');
|
||||
$setting->logo_print_assets = $request->input('logo_print_assets', '0');
|
||||
$setting->load_remote = $request->input('load_remote', 0);
|
||||
|
||||
// Only allow the site name and CSS to be changed if lock_passwords is false
|
||||
// Only allow the site name, images, and CSS to be changed if lock_passwords is false
|
||||
// Because public demos make people act like dicks
|
||||
|
||||
if (! config('app.lock_passwords')) {
|
||||
$request->validate(['site_name' => 'required']);
|
||||
$setting->site_name = $request->input('site_name');
|
||||
if (!config('app.lock_passwords')) {
|
||||
|
||||
if ($request->has('site_name')) {
|
||||
$request->validate(['site_name' => 'required']);
|
||||
}
|
||||
|
||||
$setting->site_name = $request->input('site_name', 'Snipe-IT');
|
||||
$setting->custom_css = $request->input('custom_css');
|
||||
|
||||
// Logo upload
|
||||
$setting = $request->handleImages($setting, 600, 'logo', '', 'logo');
|
||||
|
||||
if ('1' == $request->input('clear_logo')) {
|
||||
Storage::disk('public')->delete($setting->logo);
|
||||
if ($request->input('clear_logo') == '1') {
|
||||
|
||||
if (($setting->logo) && (Storage::exists($setting->logo))) {
|
||||
Storage::disk('public')->delete($setting->logo);
|
||||
}
|
||||
$setting->logo = null;
|
||||
$setting->brand = 1;
|
||||
}
|
||||
|
||||
|
||||
// Email logo upload
|
||||
$setting = $request->handleImages($setting, 600, 'email_logo', '', 'email_logo');
|
||||
if ($request->input('clear_email_logo') == '1') {
|
||||
|
||||
|
||||
if ('1' == $request->input('clear_email_logo')) {
|
||||
Storage::disk('public')->delete($setting->email_logo);
|
||||
if (($setting->email_logo) && (Storage::exists($setting->email_logo))) {
|
||||
Storage::disk('public')->delete($setting->email_logo);
|
||||
}
|
||||
$setting->email_logo = null;
|
||||
// If they are uploading an image, validate it and upload it
|
||||
}
|
||||
|
||||
|
||||
// Label logo upload
|
||||
$setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo');
|
||||
if ($request->input('clear_label_logo') == '1') {
|
||||
|
||||
if ('1' == $request->input('clear_label_logo')) {
|
||||
Storage::disk('public')->delete($setting->label_logo);
|
||||
if (($setting->label_logo) && (Storage::exists($setting->label_logo))) {
|
||||
Storage::disk('public')->delete($setting->label_logo);
|
||||
}
|
||||
$setting->label_logo = null;
|
||||
}
|
||||
|
||||
|
||||
$setting = $request->handleImages($setting, 600, 'favicon', '', 'favicon');
|
||||
|
||||
// If the user wants to clear the favicon...
|
||||
// Favicon upload
|
||||
$setting = $request->handleImages($setting, 100, 'favicon', '', 'favicon');
|
||||
if ('1' == $request->input('clear_favicon')) {
|
||||
Storage::disk('public')->delete($setting->favicon);
|
||||
|
||||
if (($setting->favicon) && (Storage::exists($setting->favicon))) {
|
||||
Storage::disk('public')->delete($setting->favicon);
|
||||
}
|
||||
$setting->favicon = null;
|
||||
}
|
||||
|
||||
// Default avatar upload
|
||||
$setting = $request->handleImages($setting, 500, 'default_avatar', 'avatars', 'default_avatar');
|
||||
if ($request->input('clear_default_avatar') == '1') {
|
||||
|
||||
if (($setting->default_avatar) && (Storage::exists('avatars/'.$setting->default_avatar))) {
|
||||
Storage::disk('public')->delete('avatars/'.$setting->default_avatar);
|
||||
}
|
||||
$setting->default_avatar = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($setting->save()) {
|
||||
|
||||
@@ -42,7 +42,7 @@ class BulkUsersController extends Controller
|
||||
// Get the list of affected users
|
||||
$user_raw_array = request('ids');
|
||||
$users = User::whereIn('id', $user_raw_array)
|
||||
->with('groups', 'assets', 'licenses', 'accessories')->get();
|
||||
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations','uploads', 'acceptances')->get();
|
||||
|
||||
// bulk edit, display the bulk edit form
|
||||
if ($request->input('bulk_actions') == 'edit') {
|
||||
@@ -317,7 +317,7 @@ class BulkUsersController extends Controller
|
||||
|
||||
// Get the users
|
||||
$merge_into_user = User::find($request->input('merge_into_id'));
|
||||
$users_to_merge = User::whereIn('id', $user_ids_to_merge)->with('assets', 'licenses', 'consumables','accessories')->get();
|
||||
$users_to_merge = User::whereIn('id', $user_ids_to_merge)->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations','uploads', 'acceptances')->get();
|
||||
$admin = User::find(Auth::user()->id);
|
||||
|
||||
// Walk users
|
||||
@@ -344,10 +344,20 @@ class BulkUsersController extends Controller
|
||||
}
|
||||
|
||||
foreach ($user_to_merge->userlog as $log) {
|
||||
$log->target_id = $user_to_merge->id;
|
||||
$log->target_id = $merge_into_user->id;
|
||||
$log->save();
|
||||
}
|
||||
|
||||
foreach ($user_to_merge->uploads as $upload) {
|
||||
$upload->item_id = $merge_into_user->id;
|
||||
$upload->save();
|
||||
}
|
||||
|
||||
foreach ($user_to_merge->acceptances as $acceptance) {
|
||||
$acceptance->item_id = $merge_into_user->id;
|
||||
$acceptance->save();
|
||||
}
|
||||
|
||||
User::where('manager_id', '=', $user_to_merge->id)->update(['manager_id' => $merge_into_user->id]);
|
||||
|
||||
foreach ($user_to_merge->managedLocations as $managedLocation) {
|
||||
@@ -356,7 +366,6 @@ class BulkUsersController extends Controller
|
||||
}
|
||||
|
||||
$user_to_merge->delete();
|
||||
//$user_to_merge->save();
|
||||
|
||||
event(new UserMerged($user_to_merge, $merge_into_user, $admin));
|
||||
|
||||
|
||||
@@ -96,10 +96,7 @@ class ImageUploadRequest extends Request
|
||||
|
||||
$ext = $image->guessExtension();
|
||||
$file_name = $type.'-'.$form_fieldname.'-'.$item->id.'-'.str_random(10).'.'.$ext;
|
||||
|
||||
Log::info('File name will be: '.$file_name);
|
||||
Log::debug('File extension is: '.$ext);
|
||||
|
||||
|
||||
if (($image->getMimeType() == 'image/vnd.microsoft.icon') || ($image->getMimeType() == 'image/x-icon') || ($image->getMimeType() == 'image/avif') || ($image->getMimeType() == 'image/webp')) {
|
||||
// If the file is an icon, webp or avif, we need to just move it since gd doesn't support resizing
|
||||
// icons or avif, and webp support and needs to be compiled into gd for resizing to be available
|
||||
|
||||
@@ -24,7 +24,7 @@ class UsersTransformer
|
||||
|
||||
$array = [
|
||||
'id' => (int) $user->id,
|
||||
'avatar' => e($user->present()->gravatar),
|
||||
'avatar' => e($user->present()->gravatar) ?? null,
|
||||
'name' => e($user->getFullNameAttribute()),
|
||||
'first_name' => e($user->first_name),
|
||||
'last_name' => e($user->last_name),
|
||||
|
||||
@@ -111,7 +111,7 @@ class LogListener
|
||||
$logaction->target_type = User::class;
|
||||
$logaction->action_type = 'merged';
|
||||
$logaction->note = trans('general.merged_log_this_user_from', $to_from_array);
|
||||
$logaction->user_id = $event->admin->id;
|
||||
$logaction->user_id = $event->admin->id ?? null;
|
||||
$logaction->save();
|
||||
|
||||
// Add a record to the users being merged TO
|
||||
@@ -122,7 +122,7 @@ class LogListener
|
||||
$logaction->item_type = User::class;
|
||||
$logaction->action_type = 'merged';
|
||||
$logaction->note = trans('general.merged_log_this_user_into', $to_from_array);
|
||||
$logaction->user_id = $event->admin->id;
|
||||
$logaction->user_id = $event->admin->id ?? null;
|
||||
$logaction->save();
|
||||
|
||||
|
||||
|
||||
@@ -49,6 +49,6 @@ class PersonalAccessTokens extends Component
|
||||
{
|
||||
//this needs safety (though the scope of auth::user might kind of do it...)
|
||||
//seems like it does, test more
|
||||
Auth::user()->tokens()->find($tokenId)->delete();
|
||||
Auth::user()->tokens()->find($tokenId)?->delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,12 @@ use App\Presenters\Presentable;
|
||||
use App\Presenters\AssetPresenter;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
@@ -966,6 +968,46 @@ class Asset extends Depreciable
|
||||
return $cost;
|
||||
}
|
||||
|
||||
public function handleCustomFieldsForStoring($request) : Asset
|
||||
{
|
||||
$model = AssetModel::find($this->model_id);
|
||||
|
||||
if (($model) && ($model instanceof AssetModel) && ($model->fieldset)) {
|
||||
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
|
||||
/*
|
||||
* Check if the decrypted existing value is different from one we just submitted
|
||||
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
||||
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
||||
* different times will have different values, so it will *look* like it was updated
|
||||
* but it wasn't.
|
||||
*/
|
||||
if ($request->input($field->db_column)!='') {
|
||||
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$this->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$this->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$this->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$this->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------
|
||||
* BEGIN MUTATORS
|
||||
|
||||
@@ -481,8 +481,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
/**
|
||||
* Establishes the user -> uploads relationship
|
||||
*
|
||||
* @todo I don't think we use this?
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v3.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
@@ -496,6 +494,21 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the user -> acceptances relationship
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v7.0.7]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function acceptances()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Actionlog::class, 'target_id')
|
||||
->where('target_type', self::class)
|
||||
->where('action_type', '=', 'accepted')
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the user -> requested assets relationship
|
||||
*
|
||||
|
||||
@@ -432,6 +432,8 @@ class UserPresenter extends Presenter
|
||||
*/
|
||||
public function gravatar()
|
||||
{
|
||||
|
||||
// User's specific avatar
|
||||
if ($this->avatar) {
|
||||
|
||||
// Check if it's a google avatar or some external avatar
|
||||
@@ -443,6 +445,12 @@ class UserPresenter extends Presenter
|
||||
return Storage::disk('public')->url('avatars/'.e($this->avatar));
|
||||
}
|
||||
|
||||
// If there is a default avatar
|
||||
if (Setting::getSettings()->default_avatar!= '') {
|
||||
return Storage::disk('public')->url('avatars/'.e(Setting::getSettings()->default_avatar));
|
||||
}
|
||||
|
||||
// Fall back to Gravatar if the settings allow loading remote scripts
|
||||
if (Setting::getSettings()->load_remote == '1') {
|
||||
if ($this->model->gravatar != '') {
|
||||
|
||||
@@ -456,8 +464,8 @@ class UserPresenter extends Presenter
|
||||
}
|
||||
}
|
||||
|
||||
// Set a fun, gender-neutral default icon
|
||||
return config('app.url').'/img/default-sm.png';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -105,4 +105,64 @@ class ActionlogFactory extends Factory
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function filesUploaded()
|
||||
{
|
||||
return $this->state(function () {
|
||||
|
||||
return [
|
||||
'created_at' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
|
||||
'action_type' => 'uploaded',
|
||||
'item_type' => User::class,
|
||||
'filename' => $this->faker->unixTime('now'),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function acceptedSignature()
|
||||
{
|
||||
return $this->state(function () {
|
||||
|
||||
$asset = Asset::factory()->create();
|
||||
|
||||
return [
|
||||
'created_at' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
|
||||
'action_type' => 'accepted',
|
||||
'item_id' => $asset->id,
|
||||
'item_type' => Asset::class,
|
||||
'target_type' => User::class,
|
||||
'accept_signature' => $this->faker->unixTime('now'),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function acceptedEula()
|
||||
{
|
||||
return $this->state(function () {
|
||||
|
||||
$asset = Asset::factory()->create();
|
||||
|
||||
return [
|
||||
'created_at' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
|
||||
'action_type' => 'accepted',
|
||||
'item_id' => $asset->id,
|
||||
'item_type' => Asset::class,
|
||||
'target_type' => User::class,
|
||||
'filename' => $this->faker->unixTime('now'),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function userUpdated()
|
||||
{
|
||||
return $this->state(function () {
|
||||
|
||||
return [
|
||||
'created_at' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
|
||||
'action_type' => 'update',
|
||||
'target_type' => User::class,
|
||||
'item_type' => User::class,
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Models\Company;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\Manufacturer;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use App\Models\Supplier;
|
||||
|
||||
@@ -116,4 +117,16 @@ class ConsumableFactory extends Factory
|
||||
$consumable->category->update(['require_acceptance' => 1]);
|
||||
});
|
||||
}
|
||||
|
||||
public function checkedOutToUser(User $user = null)
|
||||
{
|
||||
return $this->afterCreating(function (Consumable $consumable) use ($user) {
|
||||
$consumable->users()->attach($consumable->id, [
|
||||
'consumable_id' => $consumable->id,
|
||||
'created_at' => Carbon::now(),
|
||||
'user_id' => User::factory()->create()->id,
|
||||
'assigned_to' => $user->id ?? User::factory()->create()->id,
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->string('default_avatar')->after('favicon')->default('default.png')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->dropColumn('default_avatar');
|
||||
});
|
||||
}
|
||||
};
|
||||
27
package-lock.json
generated
27
package-lock.json
generated
@@ -36,7 +36,7 @@
|
||||
"signature_pad": "^4.2.0",
|
||||
"tableexport.jquery.plugin": "1.30.0",
|
||||
"tether": "^1.4.0",
|
||||
"webpack": "^5.90.2"
|
||||
"webpack": "^5.92.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"all-contributors-cli": "^6.26.1",
|
||||
@@ -2497,6 +2497,14 @@
|
||||
"acorn": "^8"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-import-attributes": {
|
||||
"version": "1.9.5",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
|
||||
"integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
|
||||
"peerDependencies": {
|
||||
"acorn": "^8"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-node": {
|
||||
"version": "1.8.2",
|
||||
"license": "Apache-2.0",
|
||||
@@ -5291,8 +5299,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.16.0",
|
||||
"license": "MIT",
|
||||
"version": "5.17.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz",
|
||||
"integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
@@ -10394,7 +10403,8 @@
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"license": "MIT",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -10857,8 +10867,9 @@
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.91.0",
|
||||
"license": "MIT",
|
||||
"version": "5.92.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz",
|
||||
"integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.5",
|
||||
@@ -10866,10 +10877,10 @@
|
||||
"@webassemblyjs/wasm-edit": "^1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "^1.12.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.9.0",
|
||||
"acorn-import-attributes": "^1.9.5",
|
||||
"browserslist": "^4.21.10",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.16.0",
|
||||
"enhanced-resolve": "^5.17.0",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
|
||||
@@ -56,6 +56,6 @@
|
||||
"signature_pad": "^4.2.0",
|
||||
"tableexport.jquery.plugin": "1.30.0",
|
||||
"tether": "^1.4.0",
|
||||
"webpack": "^5.90.2"
|
||||
"webpack": "^5.92.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,8 +122,8 @@ return [
|
||||
'ldap_test' => 'Test LDAP',
|
||||
'ldap_test_sync' => 'Test LDAP Synchronization',
|
||||
'license' => 'Software License',
|
||||
'load_remote' => 'Use Gravatar',
|
||||
'load_remote_help_text' => 'Uncheck this box if your install cannot load scripts from the outside internet. This will prevent Snipe-IT from trying load images from Gravatar.',
|
||||
'load_remote' => 'Load Remote Avatars',
|
||||
'load_remote_help_text' => 'Uncheck this box if your install cannot load scripts from the outside internet. This will prevent Snipe-IT from trying load avatars from Gravatar or other outside sources.',
|
||||
'login' => 'Login Attempts',
|
||||
'login_attempt' => 'Login Attempt',
|
||||
'login_ip' => 'IP Address',
|
||||
@@ -375,5 +375,6 @@ return [
|
||||
'timezone' => 'Timezone',
|
||||
'profile_edit' => 'Edit Profile',
|
||||
'profile_edit_help' => 'Allow users to edit their own profiles.',
|
||||
'default_avatar' => 'Upload default avatar',
|
||||
|
||||
];
|
||||
|
||||
@@ -549,6 +549,8 @@ return [
|
||||
'license_seats' => ':count License Seat|:count License Seats',
|
||||
'consumables' => ':count Consumable|:count Consumables',
|
||||
'components' => ':count Component|:count Components',
|
||||
]
|
||||
],
|
||||
'more_info' => 'More Info',
|
||||
'quickscan_bulk_help' => 'Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log. Note that if this asset is checked out, it will not change the location of the person, asset or location it is checked out to.',
|
||||
|
||||
];
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<input type="checkbox" value="1" name="update_location" {{ old('update_location') == '1' ? ' checked="checked"' : '' }}> {{ trans('admin/hardware/form.asset_location') }}
|
||||
</label>
|
||||
|
||||
<a href="#" class="text-dark-gray" tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="<i class='far fa-life-ring'></i> More Info" data-html="true" data-content="Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log.<br><br>Note that if this asset is checked out, it will not change the location of the person, asset or location it is checked out to."><i class="far fa-life-ring"></i></a>
|
||||
<a href="#" class="text-dark-gray" tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="<i class='far fa-life-ring'></i>"{{ trans('general.more_info') }} data-html="true" data-content="{{ trans('general.quickscan_bulk_help') }}"><i class="far fa-life-ring"></i></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -324,7 +324,7 @@ dir="{{ in_array(app()->getLocale(),['ar-SA','fa-IR', 'he-IL']) ? 'rtl' : 'ltr'
|
||||
<img src="{{ Auth::user()->present()->gravatar() }}" class="user-image"
|
||||
alt="">
|
||||
@else
|
||||
<i class="fas fa-users" aria-hidden="true"></i>
|
||||
<i class="fas fa-user" aria-hidden="true"></i>
|
||||
@endif
|
||||
|
||||
<span class="hidden-xs">{{ Auth::user()->getFullNameAttribute() }} <strong
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
</td>
|
||||
<!-- Delete Button -->
|
||||
<td style="vertical-align: middle;" class="text-right">
|
||||
<a class="action-link btn btn-danger btn-sm" wire:click="deleteToken('{{ $token->id }}')">
|
||||
<a class="action-link btn btn-danger btn-sm" wire:click="deleteToken('{{ $token->id }}')"
|
||||
wire:loading.attr="disabled">
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<script nonce="{{ csrf_token() }}">
|
||||
$(function () {
|
||||
|
||||
var locale = '{{ config('app.locale') }}';
|
||||
var locale = '{{ app()->getLocale() }}';
|
||||
var blockedFields = "searchable,sortable,switchable,title,visible,formatter,class".split(",");
|
||||
|
||||
var keyBlocked = function(key) {
|
||||
@@ -46,7 +46,6 @@
|
||||
stickyHeader: true,
|
||||
stickyHeaderOffsetLeft: parseInt($('body').css('padding-left'), 10),
|
||||
stickyHeaderOffsetRight: parseInt($('body').css('padding-right'), 10),
|
||||
locale: '{{ app()->getLocale() }}',
|
||||
undefinedText: '',
|
||||
iconsPrefix: 'fa',
|
||||
cookieStorage: '{{ config('session.bs_table_storage') }}',
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="col-md-9">
|
||||
<label class="btn btn-default{{ (config('app.lock_passwords')) ? ' disabled' : '' }}">
|
||||
{{ trans('button.select_file') }}
|
||||
<input type="file" name="{{ $logoVariable }}" class="js-uploadFile" id="{{ $logoId }}" accept="{{ (isset($allowedTypes) ? $allowedTypes : "image/gif,image/jpeg,image/webp,image/png,image/svg,image/svg+xml") }}" data-maxsize="{{ $maxSize ?? Helper::file_upload_max_size() }}"
|
||||
<input type="file" name="{{ $logoVariable }}" class="js-uploadFile" id="{{ $logoId }}" accept="{{ $allowedTypes ?? "image/gif,image/jpeg,image/webp,image/png,image/svg,image/svg+xml" }}" data-maxsize="{{ $maxSize ?? Helper::file_upload_max_size() }}"
|
||||
style="display:none; max-width: 90%"{{ (config('app.lock_passwords')) ? ' disabled' : '' }}>
|
||||
</label>
|
||||
|
||||
@@ -28,13 +28,12 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-9 col-md-offset-3">
|
||||
|
||||
@if (($setting->$logoVariable!='') && (Storage::disk('public')->exists(e($snipeSettings->$logoVariable))))
|
||||
<div class="pull-left" style="padding-right: 20px;">
|
||||
<a href="{{ Storage::disk('public')->url(e($snipeSettings->$logoVariable)) }}"{!! ($logoVariable!='favicon') ? ' data-toggle="lightbox"' : '' !!}>
|
||||
<img id="{{ $logoId }}-imagePreview" style="height: 80px; padding-bottom: 5px;" alt="" src="{{ Storage::disk('public')->url(e($snipeSettings->$logoVariable)) }}">
|
||||
</a>
|
||||
</div>
|
||||
@if (($setting->$logoVariable!='') && (Storage::disk('public')->exists(($logoPath ?? ''). $snipeSettings->$logoVariable)))
|
||||
<div class="pull-left" style="padding-right: 20px;">
|
||||
<a href="{{ Storage::disk('public')->url(e(($logoPath ?? '').$snipeSettings->$logoVariable)) }}"{!! ($logoVariable!='favicon') ? ' data-toggle="lightbox"' : '' !!}>
|
||||
<img id="{{ $logoId }}-imagePreview" style="height: 80px; padding-bottom: 5px;" alt="" src="{{ Storage::disk('public')->url(e(($logoPath ?? ''). $snipeSettings->$logoVariable)) }}">
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div id="{{ $logoId }}-previewContainer" style="display: none;">
|
||||
@@ -44,7 +43,7 @@
|
||||
|
||||
|
||||
</div>
|
||||
@if (($setting->$logoVariable!='') && (Storage::disk('public')->exists(e($snipeSettings->$logoVariable))))
|
||||
@if (($setting->$logoVariable!='') && (Storage::disk('public')->exists(($logoPath ?? '').$snipeSettings->$logoVariable)))
|
||||
|
||||
<div class="col-md-9 col-md-offset-3">
|
||||
<label id="{{ $logoId }}-deleteCheckbox" for="{{ $logoClearVariable }}" style="font-weight: normal" class="form-control">
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<a style="padding-left: 10px; font-size: 18px;" class="text-dark-gray" data-trigger="focus" tabindex="0" role="button" data-toggle="popover" title="More Info" data-placement="right" data-html="true" data-content="{{ (isset($helpText)) ? $helpText : 'Help Info Missing' }}">
|
||||
<a style="padding-left: 10px; font-size: 18px;" class="text-dark-gray" data-trigger="focus" tabindex="0" role="button" data-toggle="popover" title="{{ trans('general.more_info') }}" data-placement="right" data-html="true" data-content="{{ (isset($helpText)) ? $helpText : 'Help Info Missing' }}">
|
||||
<i class="far fa-life-ring" aria-hidden="true"><span class="sr-only">{{ trans('general.moreinfo') }}</span></i>
|
||||
</a>
|
||||
|
||||
@@ -109,7 +109,37 @@
|
||||
"maxSize" => 20000
|
||||
])
|
||||
|
||||
<!-- Include logo in print assets -->
|
||||
<!-- Default Avatar -->
|
||||
@include('partials/forms/edit/uploadLogo', [
|
||||
"logoVariable" => "default_avatar",
|
||||
"logoId" => "defaultAvatar",
|
||||
"logoLabel" => trans('admin/settings/general.default_avatar'),
|
||||
"logoClearVariable" => "clear_default_avatar",
|
||||
"logoPath" => "avatars/",
|
||||
"helpBlock" => trans('general.image_filetypes_help', ['size' => Helper::file_upload_max_size_readable()]),
|
||||
])
|
||||
|
||||
<!-- Load gravatar -->
|
||||
<div class="form-group {{ $errors->has('load_remote') ? 'error' : '' }}">
|
||||
<div class="col-md-3">
|
||||
<strong>{{ trans('admin/settings/general.load_remote') }}</strong>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<label class="form-control">
|
||||
{{ Form::checkbox('load_remote', '1', old('load_remote', $setting->load_remote)) }}
|
||||
{{ trans('general.yes') }}
|
||||
{!! $errors->first('load_remote', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
</label>
|
||||
|
||||
<p class="help-block">
|
||||
{{ trans('admin/settings/general.load_remote_help_text') }}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Include logo in print assets -->
|
||||
<div class="form-group">
|
||||
<div class="col-md-3">
|
||||
<strong>{{ trans('admin/settings/general.logo_print_assets') }}</strong>
|
||||
|
||||
@@ -144,24 +144,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Load gravatar -->
|
||||
<div class="form-group {{ $errors->has('load_remote') ? 'error' : '' }}">
|
||||
<div class="col-md-3">
|
||||
<strong>{{ trans('admin/settings/general.load_remote') }}</strong>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<label class="form-control">
|
||||
{{ Form::checkbox('load_remote', '1', old('load_remote', $setting->load_remote)) }}
|
||||
{{ trans('general.yes') }}
|
||||
{!! $errors->first('load_remote', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
</label>
|
||||
|
||||
<p class="help-block">
|
||||
{{ trans('admin/settings/general.load_remote_help_text') }}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- unique serial -->
|
||||
<div class="form-group">
|
||||
|
||||
@@ -39,12 +39,28 @@
|
||||
<th class="col-md-1">
|
||||
<!-- <input type="checkbox" id="checkAll"> -->
|
||||
</th>
|
||||
<th class="col-md-6">{{ trans('general.name') }}</th>
|
||||
<th class="col-md-5">{{ trans('general.groups') }}</th>
|
||||
<th class="col-md-5">{{ trans('general.assets') }}</th>
|
||||
<th class="col-md-5">{{ trans('general.accessories') }}</th>
|
||||
<th class="col-md-5">{{ trans('general.licenses') }}</th>
|
||||
<th class="col-md-5">{{ trans('general.consumables') }}</th>
|
||||
<th class="col-md-3">{{ trans('general.name') }}</th>
|
||||
<th class="col-md-3">{{ trans('general.groups') }}</th>
|
||||
<th class="text-right">
|
||||
<i class="fas fa-barcode fa-fw" aria-hidden="true" style="font-size: 17px;"></i>
|
||||
<span class="sr-only">{{ trans('general.assets') }}</span>
|
||||
</th>
|
||||
<th class="text-right">
|
||||
<i class="far fa-keyboard fa-fw" aria-hidden="true" style="font-size: 17px;"></i>
|
||||
<span class="sr-only">{{ trans('general.accessories') }}</span>
|
||||
</th>
|
||||
<th class="text-right">
|
||||
<i class="far fa-save fa-fw" aria-hidden="true" style="font-size: 17px;"></i>
|
||||
<span class="sr-only">{{ trans('general.licenses') }}</span>
|
||||
</th>
|
||||
<th class="text-right">
|
||||
<i class="fas fa-tint fa-fw" aria-hidden="true" style="font-size: 17px;"></i>
|
||||
<span class="sr-only">{{ trans('general.consumables') }}</span>
|
||||
</th>
|
||||
<th class="text-right">
|
||||
<i class="fas fa-paperclip fa-fw" aria-hidden="true" style="font-size: 17px;"></i>
|
||||
<span class="sr-only">{{ trans('general.files') }}</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -71,17 +87,20 @@
|
||||
</a>
|
||||
@endforeach
|
||||
</td>
|
||||
<td>
|
||||
{{ number_format($user->assets()->count()) }}
|
||||
<td class="text-right">
|
||||
{{ number_format($user->assets->count()) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ number_format($user->accessories()->count()) }}
|
||||
<td class="text-right">
|
||||
{{ number_format($user->accessories->count()) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ number_format($user->licenses()->count()) }}
|
||||
<td class="text-right">
|
||||
{{ number_format($user->licenses->count()) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ number_format($user->consumables()->count()) }}
|
||||
<td class="text-right">
|
||||
{{ number_format($user->consumables->count()) }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ number_format($user->uploads->count()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@@ -89,13 +108,13 @@
|
||||
<tfoot>
|
||||
|
||||
<tr>
|
||||
<td colspan="7">
|
||||
<td colspan="8">
|
||||
{{ Form::select('status_id', $statuslabel_list , old('status_id'), array('class'=>'select2', 'style'=>'width:250px')) }}
|
||||
<label>{{ trans('admin/users/general.update_user_assets_status') }}</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="7" class="col-md-12 alert-danger">
|
||||
<td colspan="8" class="col-md-12 alert-danger">
|
||||
<label class="form-control">
|
||||
<input type="checkbox" name="delete_user" value="1">
|
||||
<span><i class="fa fa-warning fa-2x"></i> {{ trans('general.bulk_soft_delete') }}</span>
|
||||
|
||||
@@ -66,6 +66,10 @@
|
||||
<i class="fas fa-tint fa-fw" aria-hidden="true" style="font-size: 17px;"></i>
|
||||
<span class="sr-only">{{ trans('general.consumables') }}</span>
|
||||
</th>
|
||||
<th class="col-md-1 text-right">
|
||||
<i class="fas fa-paperclip fa-fw" aria-hidden="true" style="font-size: 17px;"></i>
|
||||
<span class="sr-only">{{ trans('general.files') }}</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -93,16 +97,19 @@
|
||||
@endforeach
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ number_format($user->assets()->count()) }}
|
||||
{{ number_format($user->assets->count()) }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ number_format($user->accessories()->count()) }}
|
||||
{{ number_format($user->accessories->count()) }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ number_format($user->licenses()->count()) }}
|
||||
{{ number_format($user->licenses->count()) }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ number_format($user->consumables()->count()) }}
|
||||
{{ number_format($user->consumables->count()) }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ number_format($user->uploads->count()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
135
tests/Feature/Console/MergeUsersTest.php
Normal file
135
tests/Feature/Console/MergeUsersTest.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Console;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\User;
|
||||
use App\Models\Actionlog;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
||||
class MergeUsersTest extends TestCase
|
||||
{
|
||||
public function testAssetsAreTransferredOnUserMerge()
|
||||
{
|
||||
$user1 = User::factory()->create(['username' => 'user1']);
|
||||
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
|
||||
|
||||
Asset::factory()->count(3)->assignedToUser($user1)->create();
|
||||
Asset::factory()->count(3)->assignedToUser($user_to_merge_into)->create();
|
||||
|
||||
$this->artisan('snipeit:merge-users')->assertExitCode(0);
|
||||
|
||||
$this->assertEquals(6, $user_to_merge_into->refresh()->assets->count());
|
||||
$this->assertEquals(0, $user1->refresh()->assets->count());
|
||||
|
||||
}
|
||||
|
||||
public function testLicensesAreTransferredOnUserMerge(): void
|
||||
{
|
||||
$user1 = User::factory()->create(['username' => 'user1']);
|
||||
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
|
||||
|
||||
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user1->id]);
|
||||
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user_to_merge_into->id]);
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->licenses->count());
|
||||
|
||||
$this->artisan('snipeit:merge-users')->assertExitCode(0);
|
||||
|
||||
$this->assertEquals(6, $user_to_merge_into->refresh()->licenses->count());
|
||||
$this->assertEquals(0, $user1->refresh()->licenses->count());
|
||||
|
||||
}
|
||||
|
||||
public function testAccessoriesTransferredOnUserMerge(): void
|
||||
{
|
||||
$user1 = User::factory()->create(['username' => 'user1']);
|
||||
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
|
||||
|
||||
Accessory::factory()->count(3)->checkedOutToUser($user1)->create();
|
||||
Accessory::factory()->count(3)->checkedOutToUser($user_to_merge_into)->create();
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->accessories->count());
|
||||
|
||||
$this->artisan('snipeit:merge-users')->assertExitCode(0);
|
||||
|
||||
$this->assertEquals(6, $user_to_merge_into->refresh()->accessories->count());
|
||||
$this->assertEquals(0, $user1->refresh()->accessories->count());
|
||||
|
||||
}
|
||||
|
||||
public function testConsumablesTransferredOnUserMerge(): void
|
||||
{
|
||||
$user1 = User::factory()->create(['username' => 'user1']);
|
||||
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
|
||||
|
||||
Consumable::factory()->count(3)->checkedOutToUser($user1)->create();
|
||||
Consumable::factory()->count(3)->checkedOutToUser($user_to_merge_into)->create();
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->consumables->count());
|
||||
|
||||
$this->artisan('snipeit:merge-users')->assertExitCode(0);
|
||||
|
||||
$this->assertEquals(6, $user_to_merge_into->refresh()->consumables->count());
|
||||
$this->assertEquals(0, $user1->refresh()->consumables->count());
|
||||
|
||||
}
|
||||
|
||||
public function testFilesAreTransferredOnUserMerge(): void
|
||||
{
|
||||
$user1 = User::factory()->create(['username' => 'user1']);
|
||||
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
|
||||
|
||||
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user1->id]);
|
||||
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user_to_merge_into->id]);
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->uploads->count());
|
||||
|
||||
$this->artisan('snipeit:merge-users')->assertExitCode(0);
|
||||
|
||||
$this->assertEquals(6, $user_to_merge_into->refresh()->uploads->count());
|
||||
$this->assertEquals(0, $user1->refresh()->uploads->count());
|
||||
|
||||
}
|
||||
|
||||
public function testAcceptancesAreTransferredOnUserMerge(): void
|
||||
{
|
||||
$user1 = User::factory()->create(['username' => 'user1']);
|
||||
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
|
||||
|
||||
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user1->id]);
|
||||
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user_to_merge_into->id]);
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->acceptances->count());
|
||||
|
||||
$this->artisan('snipeit:merge-users')->assertExitCode(0);
|
||||
|
||||
$this->assertEquals(6, $user_to_merge_into->refresh()->acceptances->count());
|
||||
$this->assertEquals(0, $user1->refresh()->acceptances->count());
|
||||
|
||||
}
|
||||
|
||||
public function testUserUpdateHistoryIsTransferredOnUserMerge(): void
|
||||
{
|
||||
$user1 = User::factory()->create(['username' => 'user1']);
|
||||
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
|
||||
|
||||
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user1->id, 'item_id' => $user1->id]);
|
||||
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user_to_merge_into->id, 'item_id' => $user_to_merge_into->id]);
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->userlog->count());
|
||||
|
||||
$this->artisan('snipeit:merge-users')->assertExitCode(0);
|
||||
|
||||
// This needs to be more than the otherwise expected because the merge action itself is logged for the two merging users
|
||||
$this->assertEquals(7, $user_to_merge_into->refresh()->userlog->count());
|
||||
$this->assertEquals(1, $user1->refresh()->userlog->count());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -2,15 +2,242 @@
|
||||
|
||||
namespace Tests\Feature\Settings;
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Models\User;
|
||||
use App\Models\Setting;
|
||||
|
||||
|
||||
class BrandingSettingsTest extends TestCase
|
||||
{
|
||||
public function testSiteNameIsRequired()
|
||||
{
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
$response = $this->actingAs(User::factory()->superuser()->create())
|
||||
->from(route('settings.branding.index'))
|
||||
->post(route('settings.branding.save', ['site_name' => '']))
|
||||
->assertInvalid('site_name');
|
||||
->assertSessionHasErrors(['site_name'])
|
||||
->assertInvalid(['site_name'])
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('settings.branding.index'));
|
||||
|
||||
$this->followRedirects($response)->assertSee(trans('general.error'));
|
||||
}
|
||||
|
||||
public function testSiteNameCanBeSaved()
|
||||
{
|
||||
$response = $this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save', ['site_name' => 'My Awesome Site']))
|
||||
->assertStatus(302)
|
||||
->assertValid('site_name')
|
||||
->assertRedirect(route('settings.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$this->followRedirects($response)->assertSee('Success');
|
||||
}
|
||||
|
||||
|
||||
public function testLogoCanBeUploaded()
|
||||
{
|
||||
$this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.');
|
||||
|
||||
Storage::fake('public');
|
||||
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(
|
||||
route('settings.branding.save',
|
||||
['logo' => UploadedFile::fake()->image('logo.jpg')])
|
||||
)->assertValid('logo')
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('settings.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
|
||||
$setting = Setting::first();
|
||||
|
||||
$this->assertNotNull($setting->logo);
|
||||
$this->assertDatabaseHas('settings', ['logo' => $setting->logo]);
|
||||
Storage::disk('public')->assertExists($setting->logo);
|
||||
}
|
||||
|
||||
public function testLogoCanBeDeleted()
|
||||
{
|
||||
$this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.');
|
||||
Storage::fake('testdisk');
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',
|
||||
['logo' => UploadedFile::fake()->image('logo.jpg')]
|
||||
));
|
||||
|
||||
$setting = Setting::getSettings()->first();
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',['clear_logo' => '1']));
|
||||
|
||||
Storage::disk('testdisk')->assertMissing('logo.jpg');
|
||||
$setting->refresh();
|
||||
$this->assertNull($setting->logo);
|
||||
}
|
||||
|
||||
public function testEmailLogoCanBeUploaded()
|
||||
{
|
||||
$this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.');
|
||||
Storage::fake('testdisk');
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',
|
||||
['email_logo' => UploadedFile::fake()->image('email-logo.jpg')]
|
||||
))
|
||||
->assertValid('email_logo')
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('settings.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$setting = Setting::getSettings()->first();
|
||||
\Log::error($setting->toArray());
|
||||
Storage::disk('testdisk')->assertExists($setting->email_logo);
|
||||
}
|
||||
|
||||
public function testEmailLogoCanBeDeleted()
|
||||
{
|
||||
$this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.');
|
||||
Storage::fake('testdisk');
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',
|
||||
['email_logo' => UploadedFile::fake()->image('email-logo.jpg')]
|
||||
));
|
||||
|
||||
$setting = Setting::getSettings()->first();
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',['clear_email_logo' => '1']));
|
||||
|
||||
Storage::disk('testdisk')->assertMissing('email-logo.jpg');
|
||||
$setting->refresh();
|
||||
$this->assertNull($setting->email_logo);
|
||||
}
|
||||
|
||||
|
||||
public function testLabelLogoCanBeUploaded()
|
||||
{
|
||||
$this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.');
|
||||
|
||||
Storage::fake('testdisk');
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',
|
||||
['label_logo' => UploadedFile::fake()->image('label-logo.jpg')]
|
||||
))
|
||||
->assertValid('label_logo')
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('settings.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$setting = Setting::getSettings()->first();
|
||||
Storage::disk('testdisk')->assertExists($setting->label_logo);
|
||||
}
|
||||
|
||||
public function testLabelLogoCanBeDeleted()
|
||||
{
|
||||
$this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.');
|
||||
Storage::fake('testdisk');
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',
|
||||
['label_logo' => UploadedFile::fake()->image('label-logo.jpg')]
|
||||
));
|
||||
|
||||
$setting = Setting::getSettings()->first();
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',['clear_label_logo' => '1']));
|
||||
|
||||
Storage::disk('testdisk')->assertMissing('label-logo.jpg');
|
||||
$setting->refresh();
|
||||
$this->assertNull($setting->label_logo);
|
||||
}
|
||||
|
||||
public function testDefaultAvatarCanBeUploaded()
|
||||
{
|
||||
$this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.');
|
||||
$setting = Setting::getSettings()->first();
|
||||
|
||||
Storage::fake('testdisk');
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',
|
||||
['default_avatar' => UploadedFile::fake()->image('default-avatar.jpg')]
|
||||
))
|
||||
->assertValid('default_avatar')
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('settings.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$setting->refresh();
|
||||
Storage::disk('testdisk')->assertExists($setting->default_avatar);
|
||||
}
|
||||
|
||||
public function testDefaultAvatarCanBeDeleted()
|
||||
{
|
||||
$this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.');
|
||||
Storage::fake('testdisk');
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',
|
||||
['default_avatar' => UploadedFile::fake()->image('default-avatar.jpg')]
|
||||
));
|
||||
|
||||
$setting = Setting::getSettings()->first();
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',['clear_default_avatar' => '1']));
|
||||
|
||||
Storage::disk('testdisk')->assertMissing('default-avatar.jpg');
|
||||
$setting->refresh();
|
||||
$this->assertNull($setting->default_avatar);
|
||||
}
|
||||
|
||||
public function testFaviconCanBeUploaded()
|
||||
{
|
||||
$this->markTestIncomplete('This fails mimetype validation on the mock');
|
||||
Storage::fake('testdisk');
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',
|
||||
['favicon' => UploadedFile::fake()->image('favicon.svg')]
|
||||
))
|
||||
->assertValid('favicon')
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('settings.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$setting = Setting::getSettings()->first();
|
||||
Storage::disk('testdisk')->assertExists($setting->favicon);
|
||||
}
|
||||
|
||||
public function testFaviconCanBeDeleted()
|
||||
{
|
||||
$this->markTestIncomplete('This fails mimetype validation on the mock');
|
||||
Storage::fake('testdisk');
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',
|
||||
['favicon' => UploadedFile::fake()->image('favicon.ico')->mimeType('image/x-icon')]
|
||||
));
|
||||
|
||||
$setting = Setting::getSettings()->first();
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('settings.branding.save',['clear_favicon' => '1']));
|
||||
|
||||
Storage::disk('testdisk')->assertMissing('favicon.ico');
|
||||
$setting->refresh();
|
||||
$this->assertNull($setting->favicon);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -144,4 +144,17 @@ class UserSearchTest extends TestCase
|
||||
'User index contains unexpected user from another company'
|
||||
);
|
||||
}
|
||||
|
||||
public function testUsersIndexWhenInvalidSortFieldIsPassed()
|
||||
{
|
||||
$this->markIncompleteIfSqlite('This test is not compatible with SQLite');
|
||||
|
||||
$this->actingAsForApi(User::factory()->viewUsers()->create())
|
||||
->getJson(route('api.users.index', [
|
||||
'sort' => 'assets',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertStatus(200)
|
||||
->json();
|
||||
}
|
||||
}
|
||||
|
||||
213
tests/Feature/Users/Ui/MergeUsersTest.php
Normal file
213
tests/Feature/Users/Ui/MergeUsersTest.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Users\Ui;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\User;
|
||||
use App\Models\Actionlog;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
||||
class MergeUsersTest extends TestCase
|
||||
{
|
||||
public function testAssetsAreTransferredOnUserMerge()
|
||||
{
|
||||
$user1 = User::factory()->create();
|
||||
$user2 = User::factory()->create();
|
||||
$user_to_merge_into = User::factory()->create();
|
||||
|
||||
Asset::factory()->count(3)->assignedToUser($user1)->create();
|
||||
Asset::factory()->count(3)->assignedToUser($user2)->create();
|
||||
Asset::factory()->count(3)->assignedToUser($user_to_merge_into)->create();
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
'merge_into_id' => $user_to_merge_into->id
|
||||
])
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->followRedirects($response)->assertSee('Success');
|
||||
$this->assertEquals(9, $user_to_merge_into->refresh()->assets->count());
|
||||
$this->assertEquals(0, $user1->refresh()->assets->count());
|
||||
$this->assertEquals(0, $user2->refresh()->assets->count());
|
||||
|
||||
}
|
||||
|
||||
public function testLicensesAreTransferredOnUserMerge()
|
||||
{
|
||||
$user1 = User::factory()->create();
|
||||
$user2 = User::factory()->create();
|
||||
$user_to_merge_into = User::factory()->create();
|
||||
|
||||
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user1->id]);
|
||||
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user2->id]);
|
||||
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user_to_merge_into->id]);
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->licenses->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
'merge_into_id' => $user_to_merge_into->id
|
||||
])
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->followRedirects($response)->assertSee('Success');
|
||||
$this->assertEquals(9, $user_to_merge_into->refresh()->licenses->count());
|
||||
$this->assertEquals(0, $user1->refresh()->licenses->count());
|
||||
$this->assertEquals(0, $user2->refresh()->licenses->count());
|
||||
|
||||
}
|
||||
|
||||
public function testAccessoriesTransferredOnUserMerge()
|
||||
{
|
||||
$user1 = User::factory()->create();
|
||||
$user2 = User::factory()->create();
|
||||
$user_to_merge_into = User::factory()->create();
|
||||
|
||||
Accessory::factory()->count(3)->checkedOutToUser($user1)->create();
|
||||
Accessory::factory()->count(3)->checkedOutToUser($user2)->create();
|
||||
Accessory::factory()->count(3)->checkedOutToUser($user_to_merge_into)->create();
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->accessories->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
'merge_into_id' => $user_to_merge_into->id
|
||||
])
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->followRedirects($response)->assertSee('Success');
|
||||
$this->assertEquals(9, $user_to_merge_into->refresh()->accessories->count());
|
||||
$this->assertEquals(0, $user1->refresh()->accessories->count());
|
||||
$this->assertEquals(0, $user2->refresh()->accessories->count());
|
||||
|
||||
}
|
||||
|
||||
public function testConsumablesTransferredOnUserMerge()
|
||||
{
|
||||
$user1 = User::factory()->create();
|
||||
$user2 = User::factory()->create();
|
||||
$user_to_merge_into = User::factory()->create();
|
||||
|
||||
Consumable::factory()->count(3)->checkedOutToUser($user1)->create();
|
||||
Consumable::factory()->count(3)->checkedOutToUser($user2)->create();
|
||||
Consumable::factory()->count(3)->checkedOutToUser($user_to_merge_into)->create();
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->consumables->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
'merge_into_id' => $user_to_merge_into->id
|
||||
])
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->followRedirects($response)->assertSee('Success');
|
||||
$this->assertEquals(9, $user_to_merge_into->refresh()->consumables->count());
|
||||
$this->assertEquals(0, $user1->refresh()->consumables->count());
|
||||
$this->assertEquals(0, $user2->refresh()->consumables->count());
|
||||
|
||||
}
|
||||
|
||||
public function testFilesAreTransferredOnUserMerge()
|
||||
{
|
||||
$user1 = User::factory()->create();
|
||||
$user2 = User::factory()->create();
|
||||
$user_to_merge_into = User::factory()->create();
|
||||
|
||||
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user1->id]);
|
||||
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user2->id]);
|
||||
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user_to_merge_into->id]);
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->uploads->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
'merge_into_id' => $user_to_merge_into->id
|
||||
])
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->followRedirects($response)->assertSee('Success');
|
||||
$this->assertEquals(9, $user_to_merge_into->refresh()->uploads->count());
|
||||
$this->assertEquals(0, $user1->refresh()->uploads->count());
|
||||
$this->assertEquals(0, $user2->refresh()->uploads->count());
|
||||
|
||||
}
|
||||
|
||||
public function testAcceptancesAreTransferredOnUserMerge()
|
||||
{
|
||||
$user1 = User::factory()->create();
|
||||
$user2 = User::factory()->create();
|
||||
$user_to_merge_into = User::factory()->create();
|
||||
|
||||
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user1->id]);
|
||||
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user2->id]);
|
||||
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user_to_merge_into->id]);
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->acceptances->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
'merge_into_id' => $user_to_merge_into->id
|
||||
])
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->followRedirects($response)->assertSee('Success');
|
||||
$this->assertEquals(9, $user_to_merge_into->refresh()->acceptances->count());
|
||||
$this->assertEquals(0, $user1->refresh()->acceptances->count());
|
||||
$this->assertEquals(0, $user2->refresh()->acceptances->count());
|
||||
|
||||
}
|
||||
|
||||
public function testUserUpdateHistoryIsTransferredOnUserMerge()
|
||||
{
|
||||
$user1 = User::factory()->create();
|
||||
$user2 = User::factory()->create();
|
||||
$user_to_merge_into = User::factory()->create();
|
||||
|
||||
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user1->id, 'item_id' => $user1->id]);
|
||||
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user2->id, 'item_id' => $user2->id]);
|
||||
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user_to_merge_into->id, 'item_id' => $user_to_merge_into->id]);
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->userlog->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
'merge_into_id' => $user_to_merge_into->id
|
||||
])
|
||||
->assertStatus(302)
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->followRedirects($response)->assertSee('Success');
|
||||
|
||||
// This needs to be 2 more than the otherwise expected because the merge action itself is logged for the two merging users
|
||||
$this->assertEquals(11, $user_to_merge_into->refresh()->userlog->count());
|
||||
$this->assertEquals(2, $user1->refresh()->userlog->count());
|
||||
$this->assertEquals(2, $user2->refresh()->userlog->count());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -10,4 +10,11 @@ trait CanSkipTests
|
||||
$this->markTestIncomplete($message);
|
||||
}
|
||||
}
|
||||
|
||||
public function markIncompleteIfSqlite($message = 'Test skipped due to database driver being sqlite.')
|
||||
{
|
||||
if (config('database.default') === 'sqlite') {
|
||||
$this->markTestIncomplete($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user