mirror of
https://github.com/snipe/snipe-it.git
synced 2024-11-10 15:44:11 -08:00
Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net> # Conflicts: # public/css/dist/all.css # public/css/dist/bootstrap-table.css # public/js/dist/bootstrap-table.js # public/mix-manifest.json
This commit is contained in:
commit
60f9a8be9a
|
@ -1,4 +1,4 @@
|
|||
FROM alpine:3.18.5
|
||||
FROM alpine:3.18.6
|
||||
# Apache + PHP
|
||||
RUN apk add --no-cache \
|
||||
apache2 \
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Events\CheckoutableCheckedOut;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Transformers\ConsumablesTransformer;
|
||||
|
@ -11,6 +12,7 @@ use App\Models\Consumable;
|
|||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ConsumablesController extends Controller
|
||||
{
|
||||
|
@ -290,17 +292,9 @@ class ConsumablesController extends Controller
|
|||
]
|
||||
);
|
||||
|
||||
// Log checkout event
|
||||
$logaction = $consumable->logCheckout($request->input('note'), $user);
|
||||
$data['log_id'] = $logaction->id;
|
||||
$data['eula'] = $consumable->getEula();
|
||||
$data['first_name'] = $user->first_name;
|
||||
$data['item_name'] = $consumable->name;
|
||||
$data['checkout_date'] = $logaction->created_at;
|
||||
$data['note'] = $logaction->note;
|
||||
$data['require_acceptance'] = $consumable->requireAcceptance();
|
||||
event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note')));
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,6 @@ class ConsumableCheckoutController extends Controller
|
|||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
||||
}
|
||||
|
||||
|
||||
$admin_user = Auth::user();
|
||||
$assigned_to = e($request->input('assigned_to'));
|
||||
|
||||
|
|
|
@ -37,23 +37,33 @@ class SlackSettingsForm extends Component
|
|||
|
||||
public function mount() {
|
||||
$this->webhook_text= [
|
||||
"slack" => array(
|
||||
"slack" => array(
|
||||
"name" => trans('admin/settings/general.slack') ,
|
||||
"icon" => 'fab fa-slack',
|
||||
"placeholder" => "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXX",
|
||||
"link" => 'https://api.slack.com/messaging/webhooks',
|
||||
"icon" => 'fab fa-slack',
|
||||
"placeholder" => "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXX",
|
||||
"link" => 'https://api.slack.com/messaging/webhooks',
|
||||
"test" => "testWebhook"
|
||||
),
|
||||
"general"=> array(
|
||||
"name" => trans('admin/settings/general.general_webhook'),
|
||||
"icon" => "fab fa-hashtag",
|
||||
"placeholder" => trans('general.url'),
|
||||
"link" => "",
|
||||
"test" => "testWebhook"
|
||||
),
|
||||
"google" => array(
|
||||
"name" => trans('admin/settings/general.google_workspaces'),
|
||||
"icon" => "fa-brands fa-google",
|
||||
"placeholder" => "https://chat.googleapis.com/v1/spaces/xxxxxxxx/messages?key=xxxxxx",
|
||||
"link" => "https://developers.google.com/chat/how-tos/webhooks#register_the_incoming_webhook",
|
||||
"test" => "googleWebhookTest"
|
||||
),
|
||||
"microsoft" => array(
|
||||
"name" => trans('admin/settings/general.ms_teams'),
|
||||
"icon" => "fa-brands fa-microsoft",
|
||||
"placeholder" => "https://abcd.webhook.office.com/webhookb2/XXXXXXX",
|
||||
"link" => "https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=dotnet#create-incoming-webhooks-1",
|
||||
"test" => "msTeamTestWebhook"
|
||||
),
|
||||
];
|
||||
|
||||
|
@ -64,10 +74,14 @@ class SlackSettingsForm extends Component
|
|||
$this->webhook_icon = $this->webhook_text[$this->setting->webhook_selected]["icon"];
|
||||
$this->webhook_placeholder = $this->webhook_text[$this->setting->webhook_selected]["placeholder"];
|
||||
$this->webhook_link = $this->webhook_text[$this->setting->webhook_selected]["link"];
|
||||
$this->webhook_test = $this->webhook_text[$this->setting->webhook_selected]["test"];
|
||||
$this->webhook_endpoint = $this->setting->webhook_endpoint;
|
||||
$this->webhook_channel = $this->setting->webhook_channel;
|
||||
$this->webhook_botname = $this->setting->webhook_botname;
|
||||
$this->webhook_options = $this->setting->webhook_selected;
|
||||
if($this->webhook_selected == 'microsoft' || $this->webhook_selected == 'google'){
|
||||
$this->webhook_channel = '#NA';
|
||||
}
|
||||
|
||||
|
||||
if($this->setting->webhook_endpoint != null && $this->setting->webhook_channel != null){
|
||||
|
@ -87,10 +101,14 @@ class SlackSettingsForm extends Component
|
|||
$this->webhook_placeholder = $this->webhook_text[$this->webhook_selected]["placeholder"];
|
||||
$this->webhook_endpoint = null;
|
||||
$this->webhook_link = $this->webhook_text[$this->webhook_selected]["link"];
|
||||
$this->webhook_test = $this->webhook_text[$this->webhook_selected]["test"];
|
||||
if($this->webhook_selected != 'slack'){
|
||||
$this->isDisabled= '';
|
||||
$this->save_button = trans('general.save');
|
||||
}
|
||||
if($this->webhook_selected == 'microsoft' || $this->webhook_selected == 'google'){
|
||||
$this->webhook_channel = '#NA';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -151,6 +169,7 @@ class SlackSettingsForm extends Component
|
|||
|
||||
}
|
||||
|
||||
|
||||
public function clearSettings(){
|
||||
|
||||
if (Helper::isDemoMode()) {
|
||||
|
@ -187,7 +206,35 @@ class SlackSettingsForm extends Component
|
|||
}
|
||||
|
||||
}
|
||||
public function msTeamTestWebhook(){
|
||||
public function googleWebhookTest(){
|
||||
|
||||
$payload = [
|
||||
"text" => trans('general.webhook_test_msg', ['app' => $this->webhook_name]),
|
||||
];
|
||||
|
||||
try {
|
||||
$response = Http::withHeaders([
|
||||
'content-type' => 'applications/json',
|
||||
])->post($this->webhook_endpoint,
|
||||
$payload)->throw();
|
||||
|
||||
|
||||
if (($response->getStatusCode() == 302) || ($response->getStatusCode() == 301)) {
|
||||
return session()->flash('error', trans('admin/settings/message.webhook.error_redirect', ['endpoint' => $this->webhook_endpoint]));
|
||||
}
|
||||
|
||||
$this->isDisabled='';
|
||||
$this->save_button = trans('general.save');
|
||||
return session()->flash('success' , trans('admin/settings/message.webhook.success', ['webhook_name' => $this->webhook_name]));
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->isDisabled='disabled';
|
||||
$this->save_button = trans('admin/settings/general.webhook_presave');
|
||||
return session()->flash('error' , trans('admin/settings/message.webhook.error', ['error_message' => $e->getMessage(), 'app' => $this->webhook_name]));
|
||||
}
|
||||
}
|
||||
public function msTeamTestWebhook(){
|
||||
|
||||
$payload =
|
||||
[
|
||||
|
|
|
@ -60,7 +60,7 @@ class CheckoutableListener
|
|||
if ($this->shouldSendWebhookNotification()) {
|
||||
|
||||
//slack doesn't include the url in its messaging format so this is needed to hit the endpoint
|
||||
if(Setting::getSettings()->webhook_selected =='slack') {
|
||||
if(Setting::getSettings()->webhook_selected =='slack' || Setting::getSettings()->webhook_selected =='general') {
|
||||
|
||||
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckoutNotification($event));
|
||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\GoogleChat\Card;
|
||||
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||
use NotificationChannels\GoogleChat\Section;
|
||||
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||
|
||||
|
@ -38,6 +43,10 @@ class CheckinAccessoryNotification extends Notification
|
|||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
|
||||
|
@ -132,6 +141,32 @@ class CheckinAccessoryNotification extends Notification
|
|||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||
->fact(trans('mail.notes'), $note ?: '');
|
||||
}
|
||||
public function toGoogleChat()
|
||||
{
|
||||
$item = $this->item;
|
||||
$note = $this->note;
|
||||
|
||||
return GoogleChatMessage::create()
|
||||
->to($this->settings->webhook_endpoint)
|
||||
->card(
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Accessory_Checkin_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
KeyValue::create(
|
||||
trans('mail.checked_into').': '.$item->location->name ? $item->location->name : '',
|
||||
trans('admin/consumables/general.remaining').': '.$item->numRemaining(),
|
||||
trans('admin/hardware/form.notes').": ".$note ?: '',
|
||||
)
|
||||
->onClick(route('accessories.show', $item->id))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
|
|
|
@ -10,6 +10,11 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\GoogleChat\Card;
|
||||
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||
use NotificationChannels\GoogleChat\Section;
|
||||
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||
|
||||
|
@ -46,6 +51,10 @@ class CheckinAssetNotification extends Notification
|
|||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
|
||||
|
@ -108,6 +117,33 @@ class CheckinAssetNotification extends Notification
|
|||
->fact(trans('admin/hardware/form.status'), $item->assetstatus->name)
|
||||
->fact(trans('mail.notes'), $note ?: '');
|
||||
}
|
||||
public function toGoogleChat()
|
||||
{
|
||||
$target = $this->target;
|
||||
$item = $this->item;
|
||||
$note = $this->note;
|
||||
|
||||
return GoogleChatMessage::create()
|
||||
->to($this->settings->webhook_endpoint)
|
||||
->card(
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Asset_Checkin_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
KeyValue::create(
|
||||
trans('mail.checked_into') ?: '',
|
||||
$item->location->name ? $item->location->name : '',
|
||||
trans('admin/hardware/form.status').": ".$item->assetstatus->name,
|
||||
)
|
||||
->onClick(route('hardware.show', $item->id))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\GoogleChat\Card;
|
||||
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||
use NotificationChannels\GoogleChat\Section;
|
||||
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||
|
||||
|
@ -43,6 +48,10 @@ class CheckinLicenseSeatNotification extends Notification
|
|||
{
|
||||
$notifyBy = [];
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
|
||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||
|
@ -113,6 +122,34 @@ class CheckinLicenseSeatNotification extends Notification
|
|||
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
||||
->fact(trans('mail.notes'), $note ?: '');
|
||||
}
|
||||
public function toGoogleChat()
|
||||
{
|
||||
$target = $this->target;
|
||||
$item = $this->item;
|
||||
$note = $this->note;
|
||||
|
||||
return GoogleChatMessage::create()
|
||||
->to($this->settings->webhook_endpoint)
|
||||
->card(
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.License_Checkin_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
KeyValue::create(
|
||||
trans('mail.checkedin_from') ?: '',
|
||||
$target->present()->fullName() ?: '',
|
||||
trans('admin/consumables/general.remaining').': '.$item->availCount()->count(),
|
||||
)
|
||||
->onClick(route('licenses.show', $item->id))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\GoogleChat\Card;
|
||||
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||
use NotificationChannels\GoogleChat\Section;
|
||||
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||
|
||||
|
@ -37,6 +42,10 @@ class CheckoutAccessoryNotification extends Notification
|
|||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
|
||||
|
@ -123,6 +132,34 @@ class CheckoutAccessoryNotification extends Notification
|
|||
->fact(trans('mail.notes'), $note ?: '');
|
||||
|
||||
}
|
||||
public function toGoogleChat()
|
||||
{
|
||||
$target = $this->target;
|
||||
$item = $this->item;
|
||||
$note = $this->note;
|
||||
|
||||
return GoogleChatMessage::create()
|
||||
->to($this->settings->webhook_endpoint)
|
||||
->card(
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Accessory_Checkout_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
KeyValue::create(
|
||||
trans('mail.assigned_to') ?: '',
|
||||
$target->present()->name ?: '',
|
||||
trans('admin/consumables/general.remaining').": ". $item->numRemaining(),
|
||||
)
|
||||
->onClick(route('users.show', $target->id))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
|
|
|
@ -11,6 +11,13 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\GoogleChat\Card;
|
||||
use NotificationChannels\GoogleChat\Enums\Icon;
|
||||
use NotificationChannels\GoogleChat\Enums\ImageStyle;
|
||||
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||
use NotificationChannels\GoogleChat\Section;
|
||||
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||
|
||||
|
@ -54,13 +61,18 @@ class CheckoutAssetNotification extends Notification
|
|||
*/
|
||||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
|
||||
return [MicrosoftTeamsChannel::class];
|
||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||
}
|
||||
$notifyBy = [];
|
||||
|
||||
if ((Setting::getSettings()) && (Setting::getSettings()->webhook_selected == 'slack')) {
|
||||
if ((Setting::getSettings()->webhook_selected == 'slack') || (Setting::getSettings()->webhook_selected == '')) {
|
||||
\Log::debug('use webhook');
|
||||
$notifyBy[] = 'slack';
|
||||
}
|
||||
|
@ -143,6 +155,33 @@ class CheckoutAssetNotification extends Notification
|
|||
|
||||
|
||||
}
|
||||
public function toGoogleChat()
|
||||
{
|
||||
$target = $this->target;
|
||||
$item = $this->item;
|
||||
$note = $this->note;
|
||||
|
||||
return GoogleChatMessage::create()
|
||||
->to($this->settings->webhook_endpoint)
|
||||
->card(
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Asset_Checkout_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
KeyValue::create(
|
||||
trans('mail.assigned_to') ?: '',
|
||||
$target->present()->name ?: '',
|
||||
$note ?: '',
|
||||
)
|
||||
->onClick(route('users.show', $target->id))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\GoogleChat\Card;
|
||||
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||
use NotificationChannels\GoogleChat\Section;
|
||||
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||
|
||||
|
@ -44,6 +49,10 @@ class CheckoutConsumableNotification extends Notification
|
|||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
|
||||
|
@ -128,6 +137,33 @@ class CheckoutConsumableNotification extends Notification
|
|||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||
->fact(trans('mail.notes'), $note ?: '');
|
||||
}
|
||||
public function toGoogleChat()
|
||||
{
|
||||
$target = $this->target;
|
||||
$item = $this->item;
|
||||
$note = $this->note;
|
||||
|
||||
return GoogleChatMessage::create()
|
||||
->to($this->settings->webhook_endpoint)
|
||||
->card(
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Consumable_checkout_notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
KeyValue::create(
|
||||
trans('mail.assigned_to') ?: '',
|
||||
$target->present()->fullName() ?: '',
|
||||
trans('admin/consumables/general.remaining').': '.$item->numRemaining(),
|
||||
)
|
||||
->onClick(route('users.show', $target->id))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\GoogleChat\Card;
|
||||
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||
use NotificationChannels\GoogleChat\Section;
|
||||
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||
|
||||
|
@ -43,9 +48,12 @@ class CheckoutLicenseSeatNotification extends Notification
|
|||
*/
|
||||
public function via()
|
||||
{
|
||||
|
||||
$notifyBy = [];
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
|
||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||
|
@ -129,6 +137,33 @@ class CheckoutLicenseSeatNotification extends Notification
|
|||
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
||||
->fact(trans('mail.notes'), $note ?: '');
|
||||
}
|
||||
public function toGoogleChat()
|
||||
{
|
||||
$target = $this->target;
|
||||
$item = $this->item;
|
||||
$note = $this->note;
|
||||
|
||||
return GoogleChatMessage::create()
|
||||
->to($this->settings->webhook_endpoint)
|
||||
->card(
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.License_Checkout_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
KeyValue::create(
|
||||
trans('mail.assigned_to') ?: '',
|
||||
$target->present()->name ?: '',
|
||||
trans('admin/consumables/general.remaining').': '.$item->availCount()->count(),
|
||||
)
|
||||
->onClick(route('users.show', $target->id))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"intervention/image": "^2.5",
|
||||
"javiereguiluz/easyslugger": "^1.0",
|
||||
"laravel-notification-channels/google-chat": "^1.0",
|
||||
"laravel-notification-channels/microsoft-teams": "^1.1",
|
||||
"laravel/framework": "^8.46",
|
||||
"laravel/helpers": "^1.4",
|
||||
|
|
59
composer.lock
generated
59
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "89580c52de91168aac8321460bd428e2",
|
||||
"content-hash": "9cca85cd0074df9154765b1ab52f83fa",
|
||||
"packages": [
|
||||
{
|
||||
"name": "alek13/slack",
|
||||
|
@ -3188,6 +3188,63 @@
|
|||
},
|
||||
"time": "2015-04-12T19:57:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel-notification-channels/google-chat",
|
||||
"version": "v1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel-notification-channels/google-chat.git",
|
||||
"reference": "843078439403a925b484cef99a26b447e30a9c32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel-notification-channels/google-chat/zipball/843078439403a925b484cef99a26b447e30a9c32",
|
||||
"reference": "843078439403a925b484cef99a26b447e30a9c32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^6.3 || ^7.0",
|
||||
"illuminate/notifications": "~8.0",
|
||||
"illuminate/support": "~8.0",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^6.0",
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"NotificationChannels\\GoogleChat\\GoogleChatServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"NotificationChannels\\GoogleChat\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank Dixon",
|
||||
"email": "frank@thetreehouse.family",
|
||||
"homepage": "https://thetreehouse.family",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Google Chat Notification Channel for Laravel (fka. Hangouts Chat)",
|
||||
"homepage": "https://github.com/laravel-notification-channels/google-chat",
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel-notification-channels/google-chat/issues",
|
||||
"source": "https://github.com/laravel-notification-channels/google-chat/tree/v1.0.1"
|
||||
},
|
||||
"time": "2021-07-15T22:40:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel-notification-channels/microsoft-teams",
|
||||
"version": "v1.1.4",
|
||||
|
|
|
@ -91,4 +91,29 @@ class ConsumableFactory extends Factory
|
|||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function withoutItemsRemaining()
|
||||
{
|
||||
return $this->state(function () {
|
||||
return [
|
||||
'qty' => 1,
|
||||
];
|
||||
})->afterCreating(function (Consumable $consumable) {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$consumable->users()->attach($consumable->id, [
|
||||
'consumable_id' => $consumable->id,
|
||||
'user_id' => $user->id,
|
||||
'assigned_to' => $user->id,
|
||||
'note' => '',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function requiringAcceptance()
|
||||
{
|
||||
return $this->afterCreating(function (Consumable $consumable) {
|
||||
$consumable->category->update(['require_acceptance' => 1]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -3348,9 +3348,9 @@
|
|||
"integrity": "sha1-EQPWvADPv6jPyaJZmrUYxVZD2j8="
|
||||
},
|
||||
"bootstrap-table": {
|
||||
"version": "1.22.1",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.22.1.tgz",
|
||||
"integrity": "sha512-Nw8p+BmaiMDSfoer/p49YeI3vJQAWhudxhyKMuqnJBb3NRvCRewMk7JDgiN9SQO3YeSejOirKtcdWpM0dtddWg=="
|
||||
"version": "1.22.2",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.22.2.tgz",
|
||||
"integrity": "sha512-ZjZGcEXm/N7N/wAykmANWKKV+U+7AxgoNuBwWLrKbvAGT8XXS2f0OCiFmuMwpkqg7pDbF+ff9bEf/lOAlxcF1w=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
"bootstrap-colorpicker": "^2.5.3",
|
||||
"bootstrap-datepicker": "^1.10.0",
|
||||
"bootstrap-less": "^3.3.8",
|
||||
"bootstrap-table": "1.22.1",
|
||||
"bootstrap-table": "1.22.2",
|
||||
"chart.js": "^2.9.4",
|
||||
"clipboard": "^2.0.11",
|
||||
"css-loader": "^5.0.0",
|
||||
|
|
|
@ -70,6 +70,7 @@ return [
|
|||
'general_settings_keywords' => 'company support, signature, acceptance, email format, username format, images, per page, thumbnail, eula, tos, dashboard, privacy',
|
||||
'general_settings_help' => 'Default EULA and more',
|
||||
'generate_backup' => 'Generate Backup',
|
||||
'google_workspaces' => 'Google Workspaces',
|
||||
'header_color' => 'Header Color',
|
||||
'info' => 'These settings let you customize certain aspects of your installation.',
|
||||
'label_logo' => 'Label Logo',
|
||||
|
|
|
@ -42,6 +42,7 @@ return [
|
|||
'checkin_date' => 'Checkin Date:',
|
||||
'checkout_date' => 'Checkout Date:',
|
||||
'checkedout_from' => 'Checked out from',
|
||||
'checkedin_from' => 'Checked in from',
|
||||
'checked_into' => 'Checked into',
|
||||
'click_on_the_link_accessory' => 'Please click on the link at the bottom to confirm that you have received the accessory.',
|
||||
'click_on_the_link_asset' => 'Please click on the link at the bottom to confirm that you have received the asset.',
|
||||
|
|
|
@ -61,9 +61,9 @@
|
|||
<div class="col-md-9 required" wire:ignore>
|
||||
|
||||
@if (Helper::isDemoMode())
|
||||
{{ Form::select('webhook_selected', array('slack' => trans('admin/settings/general.slack'), 'general' => trans('admin/settings/general.general_webhook'), 'microsoft' => trans('admin/settings/general.ms_teams')), old('webhook_selected', $webhook_selected), array('class'=>'select2 form-control', 'aria-label' => 'webhook_selected', 'id' => 'select2', 'style'=>'width:100%', 'disabled')) }}
|
||||
{{ Form::select('webhook_selected', array('slack' => trans('admin/settings/general.slack'), 'general' => trans('admin/settings/general.general_webhook'),'google' => trans('admin/settings/general.google_workspaces'), 'microsoft' => trans('admin/settings/general.ms_teams')), old('webhook_selected', $webhook_selected), array('class'=>'select2 form-control', 'aria-label' => 'webhook_selected', 'id' => 'select2', 'style'=>'width:100%', 'disabled')) }}
|
||||
@else
|
||||
{{ Form::select('webhook_selected', array('slack' => trans('admin/settings/general.slack'), 'general' => trans('admin/settings/general.general_webhook'), 'microsoft' => trans('admin/settings/general.ms_teams')), old('webhook_selected', $webhook_selected), array('class'=>'select2 form-control', 'aria-label' => 'webhook_selected', 'id' => 'select2', 'data-minimum-results-for-search' => '-1', 'style'=>'width:100%')) }}
|
||||
{{ Form::select('webhook_selected', array('slack' => trans('admin/settings/general.slack'), 'general' => trans('admin/settings/general.general_webhook'),'google' => trans('admin/settings/general.google_workspaces'), 'microsoft' => trans('admin/settings/general.ms_teams')), old('webhook_selected', $webhook_selected), array('class'=>'select2 form-control', 'aria-label' => 'webhook_selected', 'id' => 'select2', 'data-minimum-results-for-search' => '-1', 'style'=>'width:100%')) }}
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
@ -90,23 +90,25 @@
|
|||
|
||||
|
||||
<!-- Webhook channel -->
|
||||
<div class="form-group{{ $errors->has('webhook_channel') ? ' error' : '' }}">
|
||||
<div class="col-md-2">
|
||||
{{ Form::label('webhook_channel', trans('admin/settings/general.webhook_channel',['app' => $webhook_name ])) }}
|
||||
</div>
|
||||
<div class="col-md-9 required">
|
||||
<input type="text" wire:model.lazy="webhook_channel" class="form-control" placeholder="#IT-Ops" value="{{ old('webhook_channel', $webhook_channel) }}"{{ Helper::isDemoMode() ? ' disabled' : ''}}>
|
||||
@if($webhook_selected != 'microsoft' && $webhook_selected!= 'google')
|
||||
<div class="form-group{{ $errors->has('webhook_channel') ? ' error' : '' }}">
|
||||
<div class="col-md-2">
|
||||
{{ Form::label('webhook_channel', trans('admin/settings/general.webhook_channel',['app' => $webhook_name ])) }}
|
||||
</div>
|
||||
<div class="col-md-9 required">
|
||||
<input type="text" wire:model.lazy="webhook_channel" class="form-control" placeholder="#IT-Ops" value="{{ old('webhook_channel', $webhook_channel) }}"{{ Helper::isDemoMode() ? ' disabled' : ''}}>
|
||||
|
||||
{!! $errors->first('webhook_channel', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
{!! $errors->first('webhook_channel', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Helper::isDemoMode())
|
||||
@include('partials.forms.demo-mode')
|
||||
@endif
|
||||
|
||||
<!-- Webhook botname -->
|
||||
@if($webhook_selected != 'microsoft')
|
||||
@if($webhook_selected != 'microsoft' && $webhook_selected != 'google')
|
||||
<div class="form-group{{ $errors->has('webhook_botname') ? ' error' : '' }}">
|
||||
<div class="col-md-2">
|
||||
{{ Form::label('webhook_botname', trans('admin/settings/general.webhook_botname',['app' => $webhook_name ])) }}
|
||||
|
@ -122,14 +124,11 @@
|
|||
@endif
|
||||
|
||||
<!--Webhook Integration Test-->
|
||||
|
||||
@if($webhook_endpoint != null && $webhook_channel != null)
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-9">
|
||||
@if($webhook_selected == "microsoft")
|
||||
<a href="#" wire:click.prevent="msTeamTestWebhook"
|
||||
@else
|
||||
<a href="#" wire:click.prevent="testWebhook"
|
||||
@endif
|
||||
<a href="#" wire:click.prevent="{{$webhook_test}}"
|
||||
class="btn btn-default btn-sm pull-left">
|
||||
<i class="{{$webhook_icon}}" aria-hidden="true"></i>
|
||||
{!! trans('admin/settings/general.webhook_test',['app' => ucwords($webhook_selected) ]) !!}
|
||||
|
|
|
@ -21,7 +21,7 @@ class AccessoryCheckoutTest extends TestCase
|
|||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testValidation()
|
||||
public function testValidationWhenCheckingOutAccessory()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->checkoutAccessories()->create())
|
||||
->postJson(route('api.accessories.checkout', Accessory::factory()->create()), [
|
||||
|
|
96
tests/Feature/Api/Consumables/ConsumableCheckoutTest.php
Normal file
96
tests/Feature/Api/Consumables/ConsumableCheckoutTest.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Consumables;
|
||||
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckoutConsumableNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ConsumableCheckoutTest extends TestCase
|
||||
{
|
||||
use InteractsWithSettings;
|
||||
|
||||
public function testCheckingOutConsumableRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->postJson(route('api.consumables.checkout', Consumable::factory()->create()))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testValidationWhenCheckingOutConsumable()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->checkoutConsumables()->create())
|
||||
->postJson(route('api.consumables.checkout', Consumable::factory()->create()), [
|
||||
// missing assigned_to
|
||||
])
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testConsumableMustBeAvailableWhenCheckingOut()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->checkoutConsumables()->create())
|
||||
->postJson(route('api.consumables.checkout', Consumable::factory()->withoutItemsRemaining()->create()), [
|
||||
'assigned_to' => User::factory()->create()->id,
|
||||
])
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testConsumableCanBeCheckedOut()
|
||||
{
|
||||
$consumable = Consumable::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkoutConsumables()->create())
|
||||
->postJson(route('api.consumables.checkout', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
$this->assertTrue($user->consumables->contains($consumable));
|
||||
}
|
||||
|
||||
public function testUserSentNotificationUponCheckout()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$consumable = Consumable::factory()->requiringAcceptance()->create();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkoutConsumables()->create())
|
||||
->postJson(route('api.consumables.checkout', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
Notification::assertSentTo($user, CheckoutConsumableNotification::class);
|
||||
}
|
||||
|
||||
public function testActionLogCreatedUponCheckout()
|
||||
{$consumable = Consumable::factory()->create();
|
||||
$actor = User::factory()->checkoutConsumables()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAsForApi($actor)
|
||||
->postJson(route('api.consumables.checkout', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
'note' => 'oh hi there',
|
||||
]);
|
||||
|
||||
$this->assertEquals(
|
||||
1,
|
||||
Actionlog::where([
|
||||
'action_type' => 'checkout',
|
||||
'target_id' => $user->id,
|
||||
'target_type' => User::class,
|
||||
'item_id' => $consumable->id,
|
||||
'item_type' => Consumable::class,
|
||||
'user_id' => $actor->id,
|
||||
'note' => 'oh hi there',
|
||||
])->count(),
|
||||
'Log entry either does not exist or there are more than expected'
|
||||
);
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ class AccessoryCheckoutTest extends TestCase
|
|||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testValidation()
|
||||
public function testValidationWhenCheckingOutAccessory()
|
||||
{
|
||||
$this->actingAs(User::factory()->checkoutAccessories()->create())
|
||||
->post(route('accessories.checkout.store', Accessory::factory()->create()), [
|
||||
|
|
96
tests/Feature/Checkouts/ConsumableCheckoutTest.php
Normal file
96
tests/Feature/Checkouts/ConsumableCheckoutTest.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Checkouts;
|
||||
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckoutConsumableNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ConsumableCheckoutTest extends TestCase
|
||||
{
|
||||
use InteractsWithSettings;
|
||||
|
||||
public function testCheckingOutConsumableRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAs(User::factory()->create())
|
||||
->post(route('consumables.checkout.store', Consumable::factory()->create()))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testValidationWhenCheckingOutConsumable()
|
||||
{
|
||||
$this->actingAs(User::factory()->checkoutConsumables()->create())
|
||||
->post(route('consumables.checkout.store', Consumable::factory()->create()), [
|
||||
// missing assigned_to
|
||||
])
|
||||
->assertSessionHas('error');
|
||||
}
|
||||
|
||||
public function testConsumableMustBeAvailableWhenCheckingOut()
|
||||
{
|
||||
$this->actingAs(User::factory()->checkoutConsumables()->create())
|
||||
->post(route('consumables.checkout.store', Consumable::factory()->withoutItemsRemaining()->create()), [
|
||||
'assigned_to' => User::factory()->create()->id,
|
||||
])
|
||||
->assertSessionHas('error');
|
||||
}
|
||||
|
||||
public function testConsumableCanBeCheckedOut()
|
||||
{
|
||||
$consumable = Consumable::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkoutConsumables()->create())
|
||||
->post(route('consumables.checkout.store', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
$this->assertTrue($user->consumables->contains($consumable));
|
||||
}
|
||||
|
||||
public function testUserSentNotificationUponCheckout()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$consumable = Consumable::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkoutConsumables()->create())
|
||||
->post(route('consumables.checkout.store', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
Notification::assertSentTo($user, CheckoutConsumableNotification::class);
|
||||
}
|
||||
|
||||
public function testActionLogCreatedUponCheckout()
|
||||
{
|
||||
$consumable = Consumable::factory()->create();
|
||||
$actor = User::factory()->checkoutConsumables()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('consumables.checkout.store', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
'note' => 'oh hi there',
|
||||
]);
|
||||
|
||||
$this->assertEquals(
|
||||
1,
|
||||
Actionlog::where([
|
||||
'action_type' => 'checkout',
|
||||
'target_id' => $user->id,
|
||||
'target_type' => User::class,
|
||||
'item_id' => $consumable->id,
|
||||
'item_type' => Consumable::class,
|
||||
'user_id' => $actor->id,
|
||||
'note' => 'oh hi there',
|
||||
])->count(),
|
||||
'Log entry either does not exist or there are more than expected'
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue