Implemented remainder of activity types

Also fixed audit log to work for non-entity items.
This commit is contained in:
Dan Brown 2020-11-20 19:33:11 +00:00
parent da37700ac2
commit bd6a1a66d1
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
11 changed files with 55 additions and 10 deletions

View File

@ -6,6 +6,7 @@ use BookStack\Auth\User;
use BookStack\Entities\Entity; use BookStack\Entities\Entity;
use BookStack\Model; use BookStack\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;
/** /**
* @property string $type * @property string $type
@ -46,6 +47,16 @@ class Activity extends Model
return trans('activities.' . $this->type); return trans('activities.' . $this->type);
} }
/**
* Check if this activity is intended to be for an entity.
*/
public function isForEntity(): bool
{
return Str::startsWith($this->type, [
'page_', 'chapter_', 'book_', 'bookshelf_'
]);
}
/** /**
* Checks if another Activity matches the general information of another. * Checks if another Activity matches the general information of another.
*/ */

View File

@ -44,9 +44,8 @@ class ActivityType
const ROLE_UPDATE = 'role_update'; const ROLE_UPDATE = 'role_update';
const ROLE_DELETE = 'role_delete'; const ROLE_DELETE = 'role_delete';
// TODO - Implement all below const AUTH_PASSWORD_RESET = 'auth_password_reset_request';
const ACCESS_PASSWORD_RESET = 'access_password_reset_request'; const AUTH_PASSWORD_RESET_UPDATE = 'auth_password_reset_update';
const ACCESS_PASSWORD_RESET_UPDATE = 'access_password_reset_update'; const AUTH_LOGIN = 'auth_login';
const ACCESS_LOGIN = 'access_login'; const AUTH_REGISTER = 'auth_register';
const ACCESS_FAILED_LOGIN = 'access_failed_login';
} }

View File

@ -1,9 +1,11 @@
<?php namespace BookStack\Auth\Access; <?php namespace BookStack\Auth\Access;
use BookStack\Actions\ActivityType;
use BookStack\Auth\SocialAccount; use BookStack\Auth\SocialAccount;
use BookStack\Auth\User; use BookStack\Auth\User;
use BookStack\Auth\UserRepo; use BookStack\Auth\UserRepo;
use BookStack\Exceptions\UserRegistrationException; use BookStack\Exceptions\UserRegistrationException;
use BookStack\Facades\Activity;
use Exception; use Exception;
class RegistrationService class RegistrationService
@ -68,6 +70,8 @@ class RegistrationService
$newUser->socialAccounts()->save($socialAccount); $newUser->socialAccounts()->save($socialAccount);
} }
Activity::add(ActivityType::AUTH_REGISTER, $socialAccount ?? $newUser);
// Start email confirmation flow if required // Start email confirmation flow if required
if ($this->emailConfirmationService->confirmationRequired() && !$emailConfirmed) { if ($this->emailConfirmationService->confirmationRequired() && !$emailConfirmed) {
$newUser->save(); $newUser->save();

View File

@ -1,9 +1,11 @@
<?php namespace BookStack\Auth\Access; <?php namespace BookStack\Auth\Access;
use BookStack\Actions\ActivityType;
use BookStack\Auth\User; use BookStack\Auth\User;
use BookStack\Exceptions\JsonDebugException; use BookStack\Exceptions\JsonDebugException;
use BookStack\Exceptions\SamlException; use BookStack\Exceptions\SamlException;
use BookStack\Exceptions\UserRegistrationException; use BookStack\Exceptions\UserRegistrationException;
use BookStack\Facades\Activity;
use Exception; use Exception;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use OneLogin\Saml2\Auth; use OneLogin\Saml2\Auth;
@ -372,6 +374,7 @@ class Saml2Service extends ExternalAuthService
} }
auth()->login($user); auth()->login($user);
Activity::add(ActivityType::AUTH_LOGIN, "saml2; {$user->logDescriptor()}");
return $user; return $user;
} }
} }

View File

@ -1,10 +1,12 @@
<?php namespace BookStack\Auth\Access; <?php namespace BookStack\Auth\Access;
use BookStack\Actions\ActivityType;
use BookStack\Auth\SocialAccount; use BookStack\Auth\SocialAccount;
use BookStack\Auth\UserRepo; use BookStack\Auth\UserRepo;
use BookStack\Exceptions\SocialDriverNotConfigured; use BookStack\Exceptions\SocialDriverNotConfigured;
use BookStack\Exceptions\SocialSignInAccountNotUsed; use BookStack\Exceptions\SocialSignInAccountNotUsed;
use BookStack\Exceptions\UserRegistrationException; use BookStack\Exceptions\UserRegistrationException;
use BookStack\Facades\Activity;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Laravel\Socialite\Contracts\Factory as Socialite; use Laravel\Socialite\Contracts\Factory as Socialite;
use Laravel\Socialite\Contracts\Provider; use Laravel\Socialite\Contracts\Provider;
@ -98,6 +100,7 @@ class SocialAuthService
// Simply log the user into the application. // Simply log the user into the application.
if (!$isLoggedIn && $socialAccount !== null) { if (!$isLoggedIn && $socialAccount !== null) {
auth()->login($socialAccount->user); auth()->login($socialAccount->user);
Activity::add(ActivityType::AUTH_LOGIN, $socialAccount);
return redirect()->intended('/'); return redirect()->intended('/');
} }

View File

@ -1,8 +1,15 @@
<?php namespace BookStack\Auth; <?php namespace BookStack\Auth;
use BookStack\Interfaces\Loggable;
use BookStack\Model; use BookStack\Model;
class SocialAccount extends Model /**
* Class SocialAccount
* @property string $driver
* @property User $user
* @package BookStack\Auth
*/
class SocialAccount extends Model implements Loggable
{ {
protected $fillable = ['user_id', 'driver', 'driver_id', 'timestamps']; protected $fillable = ['user_id', 'driver', 'driver_id', 'timestamps'];
@ -11,4 +18,12 @@ class SocialAccount extends Model
{ {
return $this->belongsTo(User::class); return $this->belongsTo(User::class);
} }
/**
* @inheritDoc
*/
public function logDescriptor(): string
{
return "{$this->driver}; {$this->user->logDescriptor()}";
}
} }

View File

@ -2,6 +2,7 @@
namespace BookStack\Http\Controllers\Auth; namespace BookStack\Http\Controllers\Auth;
use BookStack\Actions\ActivityType;
use BookStack\Http\Controllers\Controller; use BookStack\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails; use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -52,6 +53,10 @@ class ForgotPasswordController extends Controller
$request->only('email') $request->only('email')
); );
if ($response === Password::RESET_LINK_SENT) {
$this->logActivity(ActivityType::AUTH_PASSWORD_RESET, $request->get('email'));
}
if ($response === Password::RESET_LINK_SENT || $response === Password::INVALID_USER) { if ($response === Password::RESET_LINK_SENT || $response === Password::INVALID_USER) {
$message = trans('auth.reset_password_sent', ['email' => $request->get('email')]); $message = trans('auth.reset_password_sent', ['email' => $request->get('email')]);
$this->showSuccessNotification($message); $this->showSuccessNotification($message);

View File

@ -3,10 +3,10 @@
namespace BookStack\Http\Controllers\Auth; namespace BookStack\Http\Controllers\Auth;
use Activity; use Activity;
use BookStack\Actions\ActivityType;
use BookStack\Auth\Access\SocialAuthService; use BookStack\Auth\Access\SocialAuthService;
use BookStack\Exceptions\LoginAttemptEmailNeededException; use BookStack\Exceptions\LoginAttemptEmailNeededException;
use BookStack\Exceptions\LoginAttemptException; use BookStack\Exceptions\LoginAttemptException;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Http\Controllers\Controller; use BookStack\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -151,6 +151,7 @@ class LoginController extends Controller
} }
} }
$this->logActivity(ActivityType::AUTH_LOGIN, $user);
return redirect()->intended($this->redirectPath()); return redirect()->intended($this->redirectPath());
} }

View File

@ -2,6 +2,7 @@
namespace BookStack\Http\Controllers\Auth; namespace BookStack\Http\Controllers\Auth;
use BookStack\Actions\ActivityType;
use BookStack\Http\Controllers\Controller; use BookStack\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -47,6 +48,7 @@ class ResetPasswordController extends Controller
{ {
$message = trans('auth.reset_password_success'); $message = trans('auth.reset_password_success');
$this->showSuccessNotification($message); $this->showSuccessNotification($message);
$this->logActivity(ActivityType::AUTH_PASSWORD_RESET_UPDATE, user());
return redirect($this->redirectPath()) return redirect($this->redirectPath())
->with('status', trans($response)); ->with('status', trans($response));
} }

View File

@ -111,7 +111,7 @@ return [
'audit_deleted_item_name' => 'Name: :name', 'audit_deleted_item_name' => 'Name: :name',
'audit_table_user' => 'User', 'audit_table_user' => 'User',
'audit_table_event' => 'Event', 'audit_table_event' => 'Event',
'audit_table_item' => 'Related Item', 'audit_table_related' => 'Related Item or Detail',
'audit_table_date' => 'Activity Date', 'audit_table_date' => 'Activity Date',
'audit_date_from' => 'Date Range From', 'audit_date_from' => 'Date Range From',
'audit_date_to' => 'Date Range To', 'audit_date_to' => 'Date Range To',

View File

@ -53,7 +53,7 @@
<th> <th>
<a href="{{ sortUrl('/settings/audit', $listDetails, ['sort' => 'key']) }}">{{ trans('settings.audit_table_event') }}</a> <a href="{{ sortUrl('/settings/audit', $listDetails, ['sort' => 'key']) }}">{{ trans('settings.audit_table_event') }}</a>
</th> </th>
<th>{{ trans('settings.audit_table_item') }}</th> <th>{{ trans('settings.audit_table_related') }}</th>
<th> <th>
<a href="{{ sortUrl('/settings/audit', $listDetails, ['sort' => 'created_at']) }}">{{ trans('settings.audit_table_date') }}</a></th> <a href="{{ sortUrl('/settings/audit', $listDetails, ['sort' => 'created_at']) }}">{{ trans('settings.audit_table_date') }}</a></th>
</tr> </tr>
@ -71,11 +71,13 @@
{{ $activity->entity->name }} {{ $activity->entity->name }}
</div> </div>
</a> </a>
@elseif($activity->detail) @elseif($activity->detail && $activity->isForEntity())
<div class="px-m"> <div class="px-m">
{{ trans('settings.audit_deleted_item') }} <br> {{ trans('settings.audit_deleted_item') }} <br>
{{ trans('settings.audit_deleted_item_name', ['name' => $activity->detail]) }} {{ trans('settings.audit_deleted_item_name', ['name' => $activity->detail]) }}
</div> </div>
@elseif($activity->detail)
<div class="px-m">{{ $activity->detail }}</div>
@endif @endif
</td> </td>
<td>{{ $activity->created_at }}</td> <td>{{ $activity->created_at }}</td>