mirror of
https://gitlab.com/signalytic/client-external/streamline/streamline-emr.git
synced 2026-09-12 19:21:33 +00:00
update dockerfiles based on latest streamline image
The latest images incorporate all changes previously added by the dockerfiles. The arm image however is still missing/unreliable from the registry and must be built independently.
This commit is contained in:
@@ -0,0 +1,300 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Illuminate\Support\Str;
|
||||
use InvalidArgumentException;
|
||||
use OwenIt\Auditing\Contracts\AttributeEncoder;
|
||||
|
||||
trait Audit
|
||||
{
|
||||
/**
|
||||
* Audit data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* The Audit attributes that belong to the metadata.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $metadata = [];
|
||||
|
||||
/**
|
||||
* The Auditable attributes that were modified.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $modified = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function auditable()
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
$morphPrefix = Config::get('audit.user.morph_prefix', 'user');
|
||||
|
||||
return $this->morphTo(__FUNCTION__, $morphPrefix . '_type', $morphPrefix . '_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConnectionName()
|
||||
{
|
||||
return Config::get('audit.drivers.database.connection');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTable(): string
|
||||
{
|
||||
return Config::get('audit.drivers.database.table', parent::getTable());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolveData(): array
|
||||
{
|
||||
$morphPrefix = Config::get('audit.user.morph_prefix', 'user');
|
||||
|
||||
// Metadata
|
||||
$this->data = [
|
||||
'audit_id' => $this->id,
|
||||
'audit_event' => $this->event,
|
||||
'audit_tags' => $this->tags,
|
||||
'audit_created_at' => $this->serializeDate($this->{$this->getCreatedAtColumn()}),
|
||||
'audit_updated_at' => $this->serializeDate($this->{$this->getUpdatedAtColumn()}),
|
||||
'user_id' => $this->getAttribute($morphPrefix . '_id'),
|
||||
'user_type' => $this->getAttribute($morphPrefix . '_type'),
|
||||
];
|
||||
|
||||
// add resolvers data to metadata
|
||||
$resolverData = [];
|
||||
foreach (array_keys(Config::get('audit.resolvers', [])) as $name) {
|
||||
$resolverData['audit_' . $name] = $this->$name;
|
||||
}
|
||||
$this->data = array_merge($this->data, $resolverData);
|
||||
|
||||
if ($this->user) {
|
||||
foreach ($this->user->getArrayableAttributes() as $attribute => $value) {
|
||||
$this->data['user_' . $attribute] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->metadata = array_keys($this->data);
|
||||
|
||||
// Modified Auditable attributes
|
||||
foreach ($this->new_values as $key => $value) {
|
||||
$this->data['new_' . $key] = $value;
|
||||
}
|
||||
|
||||
foreach ($this->old_values as $key => $value) {
|
||||
$this->data['old_' . $key] = $value;
|
||||
}
|
||||
|
||||
$this->modified = array_diff_key(array_keys($this->data), $this->metadata);
|
||||
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted value of an Eloquent model.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getFormattedValue(Model $model, string $key, $value)
|
||||
{
|
||||
// Apply defined get mutator
|
||||
if ($model->hasGetMutator($key)) {
|
||||
return $model->mutateAttribute($key, $value);
|
||||
}
|
||||
|
||||
if (method_exists($model, 'hasAttributeMutator') && $model->hasAttributeMutator($key)) {
|
||||
return $model->mutateAttributeMarkedAttribute($key, $value);
|
||||
}
|
||||
|
||||
if (array_key_exists(
|
||||
$key,
|
||||
$model->getCasts()
|
||||
) && $model->getCasts()[$key] == 'Illuminate\Database\Eloquent\Casts\AsArrayObject') {
|
||||
$arrayObject = new \Illuminate\Database\Eloquent\Casts\ArrayObject(json_decode($value, true) ?: []);
|
||||
return $arrayObject;
|
||||
}
|
||||
|
||||
// Cast to native PHP type
|
||||
if ($model->hasCast($key)) {
|
||||
if ($model->getCastType($key) == 'datetime' ) {
|
||||
$value = $this->castDatetimeUTC($model, $value);
|
||||
}
|
||||
|
||||
unset($model->classCastCache[$key]);
|
||||
|
||||
return $model->castAttribute($key, $value);
|
||||
}
|
||||
|
||||
// Honour DateTime attribute
|
||||
if ($value !== null && in_array($key, $model->getDates(), true)) {
|
||||
return $model->asDateTime($this->castDatetimeUTC($model, $value));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function castDatetimeUTC($model, $value)
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $value)) {
|
||||
return Date::instance(Carbon::createFromFormat('Y-m-d', $value, Date::now('UTC')->getTimezone())->startOfDay());
|
||||
}
|
||||
|
||||
if (preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/', $value)) {
|
||||
return Date::instance(Carbon::createFromFormat('Y-m-d H:i:s', $value, Date::now('UTC')->getTimezone()));
|
||||
}
|
||||
|
||||
try {
|
||||
return Date::createFromFormat($model->getDateFormat(), $value, Date::now('UTC')->getTimezone());
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDataValue(string $key)
|
||||
{
|
||||
if (!array_key_exists($key, $this->data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$value = $this->data[$key];
|
||||
|
||||
// User value
|
||||
if ($this->user && Str::startsWith($key, 'user_')) {
|
||||
return $this->getFormattedValue($this->user, substr($key, 5), $value);
|
||||
}
|
||||
|
||||
// Auditable value
|
||||
if ($this->auditable && Str::startsWith($key, ['new_', 'old_'])) {
|
||||
$attribute = substr($key, 4);
|
||||
|
||||
return $this->getFormattedValue(
|
||||
$this->auditable,
|
||||
$attribute,
|
||||
$this->decodeAttributeValue($this->auditable, $attribute, $value)
|
||||
);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode attribute value.
|
||||
*
|
||||
* @param Contracts\Auditable $auditable
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function decodeAttributeValue(Contracts\Auditable $auditable, string $attribute, $value)
|
||||
{
|
||||
$attributeModifiers = $auditable->getAttributeModifiers();
|
||||
|
||||
if (!array_key_exists($attribute, $attributeModifiers)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$attributeDecoder = $attributeModifiers[$attribute];
|
||||
|
||||
if (is_subclass_of($attributeDecoder, AttributeEncoder::class)) {
|
||||
return call_user_func([$attributeDecoder, 'decode'], $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata(bool $json = false, int $options = 0, int $depth = 512)
|
||||
{
|
||||
if (empty($this->data)) {
|
||||
$this->resolveData();
|
||||
}
|
||||
|
||||
$metadata = [];
|
||||
|
||||
foreach ($this->metadata as $key) {
|
||||
$value = $this->getDataValue($key);
|
||||
$metadata[$key] = $value;
|
||||
|
||||
if ($value instanceof DateTimeInterface) {
|
||||
$metadata[$key] = !is_null($this->auditable) ? $this->auditable->serializeDate($value) : $this->serializeDate($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $json ? json_encode($metadata, $options, $depth) : $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getModified(bool $json = false, int $options = 0, int $depth = 512)
|
||||
{
|
||||
if (empty($this->data)) {
|
||||
$this->resolveData();
|
||||
}
|
||||
|
||||
$modified = [];
|
||||
|
||||
foreach ($this->modified as $key) {
|
||||
$attribute = substr($key, 4);
|
||||
$state = substr($key, 0, 3);
|
||||
|
||||
$value = $this->getDataValue($key);
|
||||
$modified[$attribute][$state] = $value;
|
||||
|
||||
if ($value instanceof DateTimeInterface) {
|
||||
$modified[$attribute][$state] = !is_null($this->auditable) ? $this->auditable->serializeDate($value) : $this->serializeDate($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $json ? json_encode($modified, $options, $depth) : $modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Audit tags as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTags(): array
|
||||
{
|
||||
return preg_split('/,/', $this->tags, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,774 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use OwenIt\Auditing\Contracts\AttributeEncoder;
|
||||
use OwenIt\Auditing\Contracts\AttributeRedactor;
|
||||
use OwenIt\Auditing\Contracts\Resolver;
|
||||
use OwenIt\Auditing\Events\AuditCustom;
|
||||
use OwenIt\Auditing\Exceptions\AuditableTransitionException;
|
||||
use OwenIt\Auditing\Exceptions\AuditingException;
|
||||
|
||||
trait Auditable
|
||||
{
|
||||
/**
|
||||
* Auditable attributes excluded from the Audit.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $excludedAttributes = [];
|
||||
|
||||
/**
|
||||
* Audit event name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $auditEvent;
|
||||
|
||||
/**
|
||||
* Is auditing disabled?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $auditingDisabled = false;
|
||||
|
||||
/**
|
||||
* Property may set custom event data to register
|
||||
* @var null|array
|
||||
*/
|
||||
public $auditCustomOld = null;
|
||||
|
||||
/**
|
||||
* Property may set custom event data to register
|
||||
* @var null|array
|
||||
*/
|
||||
public $auditCustomNew = null;
|
||||
|
||||
/**
|
||||
* If this is a custom event (as opposed to an eloquent event
|
||||
* @var bool
|
||||
*/
|
||||
public $isCustomEvent = false;
|
||||
|
||||
/**
|
||||
* @var array Preloaded data to be used by resolvers
|
||||
*/
|
||||
public $preloadedResolverData = [];
|
||||
|
||||
/**
|
||||
* Auditable boot logic.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function bootAuditable()
|
||||
{
|
||||
if (static::isAuditingEnabled()) {
|
||||
static::observe(new AuditableObserver());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function audits(): MorphMany
|
||||
{
|
||||
return $this->morphMany(
|
||||
Config::get('audit.implementation', Models\Audit::class),
|
||||
'auditable'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the Auditable attributes to exclude from the Audit.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function resolveAuditExclusions()
|
||||
{
|
||||
$this->excludedAttributes = $this->getAuditExclude();
|
||||
|
||||
// When in strict mode, hidden and non visible attributes are excluded
|
||||
if ($this->getAuditStrict()) {
|
||||
// Hidden attributes
|
||||
$this->excludedAttributes = array_merge($this->excludedAttributes, $this->hidden);
|
||||
|
||||
// Non visible attributes
|
||||
if ($this->visible) {
|
||||
$invisible = array_diff(array_keys($this->attributes), $this->visible);
|
||||
|
||||
$this->excludedAttributes = array_merge($this->excludedAttributes, $invisible);
|
||||
}
|
||||
}
|
||||
|
||||
// Exclude Timestamps
|
||||
if (!$this->getAuditTimestamps()) {
|
||||
if ($this->getCreatedAtColumn()) {
|
||||
$this->excludedAttributes[] = $this->getCreatedAtColumn();
|
||||
}
|
||||
if ($this->getUpdatedAtColumn()) {
|
||||
$this->excludedAttributes[] = $this->getUpdatedAtColumn();
|
||||
}
|
||||
if (in_array(SoftDeletes::class, class_uses_recursive(get_class($this)))) {
|
||||
$this->excludedAttributes[] = $this->getDeletedAtColumn();
|
||||
}
|
||||
}
|
||||
|
||||
// Valid attributes are all those that made it out of the exclusion array
|
||||
$attributes = Arr::except($this->attributes, $this->excludedAttributes);
|
||||
|
||||
foreach ($attributes as $attribute => $value) {
|
||||
// Apart from null, non scalar values will be excluded
|
||||
if (
|
||||
is_array($value) ||
|
||||
(is_object($value) &&
|
||||
!method_exists($value, '__toString') &&
|
||||
!($value instanceof \UnitEnum))
|
||||
) {
|
||||
$this->excludedAttributes[] = $attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAuditExclude(): array
|
||||
{
|
||||
return $this->auditExclude ?? Config::get('audit.exclude', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAuditInclude(): array
|
||||
{
|
||||
return $this->auditInclude ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the old/new attributes of a retrieved event.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRetrievedEventAttributes(): array
|
||||
{
|
||||
// This is a read event with no attribute changes,
|
||||
// only metadata will be stored in the Audit
|
||||
|
||||
return [
|
||||
[],
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the old/new attributes of a created event.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getCreatedEventAttributes(): array
|
||||
{
|
||||
$new = [];
|
||||
|
||||
foreach ($this->attributes as $attribute => $value) {
|
||||
if ($this->isAttributeAuditable($attribute)) {
|
||||
$new[$attribute] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
[],
|
||||
$new,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getCustomEventAttributes(): array
|
||||
{
|
||||
return [
|
||||
$this->auditCustomOld,
|
||||
$this->auditCustomNew
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the old/new attributes of an updated event.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUpdatedEventAttributes(): array
|
||||
{
|
||||
$old = [];
|
||||
$new = [];
|
||||
|
||||
foreach ($this->getDirty() as $attribute => $value) {
|
||||
if ($this->isAttributeAuditable($attribute)) {
|
||||
$old[$attribute] = Arr::get($this->original, $attribute);
|
||||
$new[$attribute] = Arr::get($this->attributes, $attribute);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
$old,
|
||||
$new,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the old/new attributes of a deleted event.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDeletedEventAttributes(): array
|
||||
{
|
||||
$old = [];
|
||||
|
||||
foreach ($this->attributes as $attribute => $value) {
|
||||
if ($this->isAttributeAuditable($attribute)) {
|
||||
$old[$attribute] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
$old,
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the old/new attributes of a restored event.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRestoredEventAttributes(): array
|
||||
{
|
||||
// A restored event is just a deleted event in reverse
|
||||
return array_reverse($this->getDeletedEventAttributes());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readyForAuditing(): bool
|
||||
{
|
||||
if (static::$auditingDisabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isCustomEvent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->isEventAuditable($this->auditEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify attribute value.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
* @throws AuditingException
|
||||
*
|
||||
*/
|
||||
protected function modifyAttributeValue(string $attribute, $value)
|
||||
{
|
||||
$attributeModifiers = $this->getAttributeModifiers();
|
||||
|
||||
if (!array_key_exists($attribute, $attributeModifiers)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$attributeModifier = $attributeModifiers[$attribute];
|
||||
|
||||
if (is_subclass_of($attributeModifier, AttributeRedactor::class)) {
|
||||
return call_user_func([$attributeModifier, 'redact'], $value);
|
||||
}
|
||||
|
||||
if (is_subclass_of($attributeModifier, AttributeEncoder::class)) {
|
||||
return call_user_func([$attributeModifier, 'encode'], $value);
|
||||
}
|
||||
|
||||
throw new AuditingException(sprintf('Invalid AttributeModifier implementation: %s', $attributeModifier));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function toAudit(): array
|
||||
{
|
||||
if (!$this->readyForAuditing()) {
|
||||
throw new AuditingException('A valid audit event has not been set');
|
||||
}
|
||||
|
||||
$attributeGetter = $this->resolveAttributeGetter($this->auditEvent);
|
||||
|
||||
if (!method_exists($this, $attributeGetter)) {
|
||||
throw new AuditingException(sprintf(
|
||||
'Unable to handle "%s" event, %s() method missing',
|
||||
$this->auditEvent,
|
||||
$attributeGetter
|
||||
));
|
||||
}
|
||||
|
||||
$this->resolveAuditExclusions();
|
||||
|
||||
list($old, $new) = $this->$attributeGetter();
|
||||
|
||||
if ($this->getAttributeModifiers() && !$this->isCustomEvent) {
|
||||
foreach ($old as $attribute => $value) {
|
||||
$old[$attribute] = $this->modifyAttributeValue($attribute, $value);
|
||||
}
|
||||
|
||||
foreach ($new as $attribute => $value) {
|
||||
$new[$attribute] = $this->modifyAttributeValue($attribute, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$morphPrefix = Config::get('audit.user.morph_prefix', 'user');
|
||||
|
||||
$tags = implode(',', $this->generateTags());
|
||||
|
||||
$user = $this->resolveUser();
|
||||
|
||||
return $this->transformAudit(array_merge([
|
||||
'old_values' => $old,
|
||||
'new_values' => $new,
|
||||
'event' => $this->auditEvent,
|
||||
'auditable_id' => $this->getKey(),
|
||||
'auditable_type' => $this->getMorphClass(),
|
||||
$morphPrefix . '_id' => $user ? $user->getAuthIdentifier() : null,
|
||||
$morphPrefix . '_type' => $user ? $user->getMorphClass() : null,
|
||||
'tags' => empty($tags) ? null : $tags,
|
||||
], $this->runResolvers()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transformAudit(array $data): array
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the User.
|
||||
*
|
||||
* @return mixed|null
|
||||
* @throws AuditingException
|
||||
*
|
||||
*/
|
||||
protected function resolveUser()
|
||||
{
|
||||
if (! empty($this->preloadedResolverData['user'] ?? null)) {
|
||||
return $this->preloadedResolverData['user'];
|
||||
}
|
||||
|
||||
$userResolver = Config::get('audit.user.resolver');
|
||||
|
||||
if (is_null($userResolver) && Config::has('audit.resolver') && !Config::has('audit.user.resolver')) {
|
||||
trigger_error(
|
||||
'The config file audit.php is not updated to the new version 13.0. Please see https://laravel-auditing.com/guide/upgrading.html',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$userResolver = Config::get('audit.resolver.user');
|
||||
}
|
||||
|
||||
if (is_subclass_of($userResolver, \OwenIt\Auditing\Contracts\UserResolver::class)) {
|
||||
return call_user_func([$userResolver, 'resolve'], $this);
|
||||
}
|
||||
|
||||
throw new AuditingException('Invalid UserResolver implementation');
|
||||
}
|
||||
|
||||
protected function runResolvers(): array
|
||||
{
|
||||
$resolved = [];
|
||||
$resolvers = Config::get('audit.resolvers', []);
|
||||
if (empty($resolvers) && Config::has('audit.resolver')) {
|
||||
trigger_error(
|
||||
'The config file audit.php is not updated to the new version 13.0. Please see https://laravel-auditing.com/guide/upgrading.html',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$resolvers = Config::get('audit.resolver', []);
|
||||
}
|
||||
|
||||
foreach ($resolvers as $name => $implementation) {
|
||||
if (empty($implementation)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_subclass_of($implementation, Resolver::class)) {
|
||||
throw new AuditingException('Invalid Resolver implementation for: ' . $name);
|
||||
}
|
||||
$resolved[$name] = call_user_func([$implementation, 'resolve'], $this);
|
||||
}
|
||||
return $resolved;
|
||||
}
|
||||
|
||||
public function preloadResolverData()
|
||||
{
|
||||
$this->preloadedResolverData = $this->runResolvers();
|
||||
|
||||
if (!empty ($this->resolveUser())) {
|
||||
$this->preloadedResolverData['user'] = $this->resolveUser();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an attribute is eligible for auditing.
|
||||
*
|
||||
* @param string $attribute
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAttributeAuditable(string $attribute): bool
|
||||
{
|
||||
// The attribute should not be audited
|
||||
if (in_array($attribute, $this->excludedAttributes, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The attribute is auditable when explicitly
|
||||
// listed or when the include array is empty
|
||||
$include = $this->getAuditInclude();
|
||||
|
||||
return empty($include) || in_array($attribute, $include, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether an event is auditable.
|
||||
*
|
||||
* @param string $event
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isEventAuditable($event): bool
|
||||
{
|
||||
return is_string($this->resolveAttributeGetter($event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute getter method resolver.
|
||||
*
|
||||
* @param string $event
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function resolveAttributeGetter($event)
|
||||
{
|
||||
if (empty($event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->isCustomEvent) {
|
||||
return 'getCustomEventAttributes';
|
||||
}
|
||||
|
||||
foreach ($this->getAuditEvents() as $key => $value) {
|
||||
$auditableEvent = is_int($key) ? $value : $key;
|
||||
|
||||
$auditableEventRegex = sprintf('/%s/', preg_replace('/\*+/', '.*', $auditableEvent));
|
||||
|
||||
if (preg_match($auditableEventRegex, $event)) {
|
||||
return is_int($key) ? sprintf('get%sEventAttributes', ucfirst($event)) : $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setAuditEvent(string $event): Contracts\Auditable
|
||||
{
|
||||
$this->auditEvent = $this->isEventAuditable($event) ? $event : null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAuditEvent()
|
||||
{
|
||||
return $this->auditEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAuditEvents(): array
|
||||
{
|
||||
return $this->auditEvents ?? Config::get('audit.events', [
|
||||
'created',
|
||||
'updated',
|
||||
'deleted',
|
||||
'restored',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Auditing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function disableAuditing()
|
||||
{
|
||||
static::$auditingDisabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Auditing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function enableAuditing()
|
||||
{
|
||||
static::$auditingDisabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether auditing is enabled.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isAuditingEnabled(): bool
|
||||
{
|
||||
if (App::runningInConsole()) {
|
||||
return Config::get('audit.enabled', true) && Config::get('audit.console', false);
|
||||
}
|
||||
|
||||
return Config::get('audit.enabled', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAuditStrict(): bool
|
||||
{
|
||||
return $this->auditStrict ?? Config::get('audit.strict', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAuditTimestamps(): bool
|
||||
{
|
||||
return $this->auditTimestamps ?? Config::get('audit.timestamps', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAuditDriver()
|
||||
{
|
||||
return $this->auditDriver ?? Config::get('audit.driver', 'database');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAuditThreshold(): int
|
||||
{
|
||||
return $this->auditThreshold ?? Config::get('audit.threshold', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAttributeModifiers(): array
|
||||
{
|
||||
return $this->attributeModifiers ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function generateTags(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transitionTo(Contracts\Audit $audit, bool $old = false): Contracts\Auditable
|
||||
{
|
||||
// The Audit must be for an Auditable model of this type
|
||||
if ($this->getMorphClass() !== $audit->auditable_type) {
|
||||
throw new AuditableTransitionException(sprintf(
|
||||
'Expected Auditable type %s, got %s instead',
|
||||
$this->getMorphClass(),
|
||||
$audit->auditable_type
|
||||
));
|
||||
}
|
||||
|
||||
// The Audit must be for this specific Auditable model
|
||||
if ($this->getKey() !== $audit->auditable_id) {
|
||||
throw new AuditableTransitionException(sprintf(
|
||||
'Expected Auditable id (%s)%s, got (%s)%s instead',
|
||||
gettype($this->getKey()),
|
||||
$this->getKey(),
|
||||
gettype($audit->auditable_id),
|
||||
$audit->auditable_id
|
||||
));
|
||||
}
|
||||
|
||||
// Redacted data should not be used when transitioning states
|
||||
foreach ($this->getAttributeModifiers() as $attribute => $modifier) {
|
||||
if (is_subclass_of($modifier, AttributeRedactor::class)) {
|
||||
throw new AuditableTransitionException('Cannot transition states when an AttributeRedactor is set');
|
||||
}
|
||||
}
|
||||
|
||||
// The attribute compatibility between the Audit and the Auditable model must be met
|
||||
$modified = $audit->getModified();
|
||||
|
||||
if ($incompatibilities = array_diff_key($modified, $this->getAttributes())) {
|
||||
throw new AuditableTransitionException(sprintf(
|
||||
'Incompatibility between [%s:%s] and [%s:%s]',
|
||||
$this->getMorphClass(),
|
||||
$this->getKey(),
|
||||
get_class($audit),
|
||||
$audit->getKey()
|
||||
), array_keys($incompatibilities));
|
||||
}
|
||||
|
||||
$key = $old ? 'old' : 'new';
|
||||
|
||||
foreach ($modified as $attribute => $value) {
|
||||
if (array_key_exists($key, $value)) {
|
||||
$this->setAttribute($attribute, $value[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pivot help methods
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Methods for auditing pivot actions
|
||||
|
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param string $relationName
|
||||
* @param mixed $id
|
||||
* @param array $attributes
|
||||
* @param bool $touch
|
||||
* @param array $columns
|
||||
* @return void
|
||||
* @throws AuditingException
|
||||
*/
|
||||
public function auditAttach(string $relationName, $id, array $attributes = [], $touch = true, $columns = ['*'])
|
||||
{
|
||||
if (!method_exists($this, $relationName) || !method_exists($this->{$relationName}(), 'attach')) {
|
||||
throw new AuditingException('Relationship ' . $relationName . ' was not found or does not support method attach');
|
||||
}
|
||||
|
||||
$old = $this->{$relationName}()->get($columns);
|
||||
$this->{$relationName}()->attach($id, $attributes, $touch);
|
||||
$new = $this->{$relationName}()->get($columns);
|
||||
$this->dispatchRelationAuditEvent($relationName, 'attach', $old, $new);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relationName
|
||||
* @param mixed $ids
|
||||
* @param bool $touch
|
||||
* @param array $columns
|
||||
* @return int
|
||||
* @throws AuditingException
|
||||
*/
|
||||
public function auditDetach(string $relationName, $ids = null, $touch = true, $columns = ['*'])
|
||||
{
|
||||
if (!method_exists($this, $relationName) || !method_exists($this->{$relationName}(), 'detach')) {
|
||||
throw new AuditingException('Relationship ' . $relationName . ' was not found or does not support method detach');
|
||||
}
|
||||
|
||||
$old = $this->{$relationName}()->get($columns);
|
||||
$results = $this->{$relationName}()->detach($ids, $touch);
|
||||
$new = $this->{$relationName}()->get($columns);
|
||||
$this->dispatchRelationAuditEvent($relationName, 'detach', $old, $new);
|
||||
|
||||
return empty($results) ? 0 : $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $relationName
|
||||
* @param \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $ids
|
||||
* @param bool $detaching
|
||||
* @param array $columns
|
||||
* @return array
|
||||
* @throws AuditingException
|
||||
*/
|
||||
public function auditSync($relationName, $ids, $detaching = true, $columns = ['*'])
|
||||
{
|
||||
if (!method_exists($this, $relationName) || !method_exists($this->{$relationName}(), 'sync')) {
|
||||
throw new AuditingException('Relationship ' . $relationName . ' was not found or does not support method sync');
|
||||
}
|
||||
|
||||
$old = $this->{$relationName}()->get($columns);
|
||||
$changes = $this->{$relationName}()->sync($ids, $detaching);
|
||||
if (collect($changes)->flatten()->isEmpty()) {
|
||||
$old = $new = collect([]);
|
||||
} else {
|
||||
$new = $this->{$relationName}()->get($columns);
|
||||
}
|
||||
$this->dispatchRelationAuditEvent($relationName, 'sync', $old, $new);
|
||||
|
||||
return $changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relationName
|
||||
* @param \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $ids
|
||||
* @param array $columns
|
||||
* @return array
|
||||
* @throws AuditingException
|
||||
*/
|
||||
public function auditSyncWithoutDetaching(string $relationName, $ids, $columns = ['*'])
|
||||
{
|
||||
if (!method_exists($this, $relationName) || !method_exists($this->{$relationName}(), 'syncWithoutDetaching')) {
|
||||
throw new AuditingException('Relationship ' . $relationName . ' was not found or does not support method syncWithoutDetaching');
|
||||
}
|
||||
|
||||
return $this->auditSync($relationName, $ids, false, $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relationName
|
||||
* @param string $event
|
||||
* @param \Illuminate\Support\Collection $old
|
||||
* @param \Illuminate\Support\Collection $new
|
||||
* @return void
|
||||
*/
|
||||
private function dispatchRelationAuditEvent($relationName, $event, $old, $new)
|
||||
{
|
||||
$this->auditCustomOld[$relationName] = $old->diff($new)->toArray();
|
||||
$this->auditCustomNew[$relationName] = $new->diff($old)->toArray();
|
||||
|
||||
if (
|
||||
empty($this->auditCustomOld[$relationName]) &&
|
||||
empty($this->auditCustomNew[$relationName])
|
||||
) {
|
||||
$this->auditCustomOld = $this->auditCustomNew = [];
|
||||
}
|
||||
|
||||
$this->auditEvent = $event;
|
||||
$this->isCustomEvent = true;
|
||||
Event::dispatch(AuditCustom::class, [$this]);
|
||||
$this->isCustomEvent = false;
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing;
|
||||
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
use OwenIt\Auditing\Events\DispatchAudit;
|
||||
use OwenIt\Auditing\Events\DispatchingAudit;
|
||||
use OwenIt\Auditing\Facades\Auditor;
|
||||
|
||||
class AuditableObserver
|
||||
{
|
||||
/**
|
||||
* Is the model being restored?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $restoring = false;
|
||||
|
||||
/**
|
||||
* Handle the retrieved event.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function retrieved(Auditable $model)
|
||||
{
|
||||
$this->dispatchAudit($model->setAuditEvent('retrieved'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the created event.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function created(Auditable $model)
|
||||
{
|
||||
$this->dispatchAudit($model->setAuditEvent('created'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the updated event.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updated(Auditable $model)
|
||||
{
|
||||
// Ignore the updated event when restoring
|
||||
if (!static::$restoring) {
|
||||
$this->dispatchAudit($model->setAuditEvent('updated'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the deleted event.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleted(Auditable $model)
|
||||
{
|
||||
$this->dispatchAudit($model->setAuditEvent('deleted'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the restoring event.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function restoring(Auditable $model)
|
||||
{
|
||||
// When restoring a model, an updated event is also fired.
|
||||
// By keeping track of the main event that took place,
|
||||
// we avoid creating a second audit with wrong values
|
||||
static::$restoring = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the restored event.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function restored(Auditable $model)
|
||||
{
|
||||
$this->dispatchAudit($model->setAuditEvent('restored'));
|
||||
|
||||
// Once the model is restored, we need to put everything back
|
||||
// as before, in case a legitimate update event is fired
|
||||
static::$restoring = false;
|
||||
}
|
||||
|
||||
protected function dispatchAudit(Auditable $model)
|
||||
{
|
||||
if (!$model->readyForAuditing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$model->preloadResolverData();
|
||||
if (!Config::get('audit.queue.enable', false)) {
|
||||
return Auditor::execute($model);
|
||||
}
|
||||
|
||||
if (!$this->fireDispatchingAuditEvent($model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unload the relations to prevent large amounts of unnecessary data from being serialized.
|
||||
app()->make('events')->dispatch(new DispatchAudit($model->withoutRelations()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire the Auditing event.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function fireDispatchingAuditEvent(Auditable $model): bool
|
||||
{
|
||||
return app()->make('events')
|
||||
->until(new DispatchingAudit($model)) !== false;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing;
|
||||
|
||||
if (app() instanceof \Illuminate\Foundation\Application) {
|
||||
class_alias(\Illuminate\Foundation\Support\Providers\EventServiceProvider::class, '\OwenIt\Auditing\ServiceProvider');
|
||||
} else {
|
||||
class_alias(\Laravel\Lumen\Providers\EventServiceProvider::class, '\OwenIt\Auditing\ServiceProvider');
|
||||
}
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use OwenIt\Auditing\Events\AuditCustom;
|
||||
use OwenIt\Auditing\Events\DispatchAudit;
|
||||
use OwenIt\Auditing\Listeners\RecordCustomAudit;
|
||||
use OwenIt\Auditing\Listeners\ProcessDispatchAudit;
|
||||
|
||||
class AuditingEventServiceProvider extends ServiceProvider
|
||||
{
|
||||
protected $listen = [
|
||||
AuditCustom::class => [
|
||||
RecordCustomAudit::class,
|
||||
],
|
||||
DispatchAudit::class => [
|
||||
ProcessDispatchAudit::class,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Register any events for your application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
parent::boot();
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing;
|
||||
|
||||
use Illuminate\Contracts\Support\DeferrableProvider;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use OwenIt\Auditing\Console\AuditDriverCommand;
|
||||
use OwenIt\Auditing\Console\AuditResolverCommand;
|
||||
use OwenIt\Auditing\Console\InstallCommand;
|
||||
use OwenIt\Auditing\Contracts\Auditor;
|
||||
|
||||
class AuditingServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->registerPublishing();
|
||||
$this->mergeConfigFrom(__DIR__ . '/../config/audit.php', 'audit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->commands([
|
||||
AuditDriverCommand::class,
|
||||
AuditResolverCommand::class,
|
||||
InstallCommand::class,
|
||||
]);
|
||||
|
||||
$this->app->singleton(Auditor::class, function ($app) {
|
||||
return new \OwenIt\Auditing\Auditor($app);
|
||||
});
|
||||
|
||||
$this->app->register(AuditingEventServiceProvider::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the package's publishable resources.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function registerPublishing()
|
||||
{
|
||||
if ($this->app->runningInConsole()) {
|
||||
// Lumen lacks a config_path() helper, so we use base_path()
|
||||
$this->publishes([
|
||||
__DIR__ . '/../config/audit.php' => base_path('config/audit.php'),
|
||||
], 'config');
|
||||
|
||||
if (!class_exists('CreateAuditsTable')) {
|
||||
$this->publishes([
|
||||
__DIR__ . '/../database/migrations/audits.stub' => database_path(
|
||||
sprintf('migrations/%s_create_audits_table.php', date('Y_m_d_His'))
|
||||
),
|
||||
], 'migrations');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing;
|
||||
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Manager;
|
||||
use InvalidArgumentException;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
use OwenIt\Auditing\Contracts\AuditDriver;
|
||||
use OwenIt\Auditing\Drivers\Database;
|
||||
use OwenIt\Auditing\Events\Audited;
|
||||
use OwenIt\Auditing\Events\Auditing;
|
||||
use OwenIt\Auditing\Exceptions\AuditingException;
|
||||
|
||||
class Auditor extends Manager implements Contracts\Auditor
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultDriver()
|
||||
{
|
||||
return 'database';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createDriver($driver)
|
||||
{
|
||||
try {
|
||||
return parent::createDriver($driver);
|
||||
} catch (InvalidArgumentException $exception) {
|
||||
if (class_exists($driver)) {
|
||||
return $this->container->make($driver);
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function auditDriver(Auditable $model): AuditDriver
|
||||
{
|
||||
$driver = $this->driver($model->getAuditDriver());
|
||||
|
||||
if (!$driver instanceof AuditDriver) {
|
||||
throw new AuditingException('The driver must implement the AuditDriver contract');
|
||||
}
|
||||
|
||||
return $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute(Auditable $model): void
|
||||
{
|
||||
if (!$model->readyForAuditing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$driver = $this->auditDriver($model);
|
||||
|
||||
if (!$this->fireAuditingEvent($model, $driver)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we want to avoid storing empty values
|
||||
$allowEmpty = Config::get('audit.empty_values');
|
||||
$explicitAllowEmpty = in_array($model->getAuditEvent(), Config::get('audit.allowed_empty_values', []));
|
||||
|
||||
if (!$allowEmpty && !$explicitAllowEmpty) {
|
||||
if (
|
||||
empty($model->toAudit()['new_values']) &&
|
||||
empty($model->toAudit()['old_values'])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$audit = $driver->audit($model);
|
||||
if (!$audit) {
|
||||
return;
|
||||
}
|
||||
|
||||
$driver->prune($model);
|
||||
|
||||
$this->container->make('events')->dispatch(
|
||||
new Audited($model, $driver, $audit)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the Database audit driver.
|
||||
*
|
||||
* @return \OwenIt\Auditing\Drivers\Database
|
||||
*/
|
||||
protected function createDatabaseDriver(): Database
|
||||
{
|
||||
return $this->container->make(Database::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire the Auditing event.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
* @param \OwenIt\Auditing\Contracts\AuditDriver $driver
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function fireAuditingEvent(Auditable $model, AuditDriver $driver): bool
|
||||
{
|
||||
return $this
|
||||
->container
|
||||
->make('events')
|
||||
->until(new Auditing($model, $driver)) !== false;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Console;
|
||||
|
||||
use Illuminate\Console\GeneratorCommand;
|
||||
|
||||
class AuditDriverCommand extends GeneratorCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $name = 'auditing:audit-driver';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $description = 'Create a new audit driver';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $type = 'AuditDriver';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getStub()
|
||||
{
|
||||
return __DIR__ . '/../../stubs/driver.stub';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return $rootNamespace . '\AuditDrivers';
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Console;
|
||||
|
||||
use Illuminate\Console\GeneratorCommand;
|
||||
|
||||
class AuditResolverCommand extends GeneratorCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $name = 'auditing:audit-resolver';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $description = 'Create a new audit resolver';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $type = 'AuditResolver';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getStub()
|
||||
{
|
||||
return __DIR__ . '/../../stubs/resolver.stub';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return $rootNamespace . '\AuditResolvers';
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Add your new resolver to the resolvers array in audit.php config file.');
|
||||
return parent::handle();
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class InstallCommand extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $signature = 'auditing:install';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $description = 'Install all of the Auditing resources';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->comment('Publishing Auditing Configuration...');
|
||||
$this->callSilent('vendor:publish', ['--tag' => 'config']);
|
||||
|
||||
$this->comment('Publishing Auditing Migrations...');
|
||||
$this->callSilent('vendor:publish', ['--tag' => 'migrations']);
|
||||
|
||||
$this->registerAuditingServiceProvider();
|
||||
|
||||
$this->info('Auditing installed successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Auditing service provider in the application configuration file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerAuditingServiceProvider()
|
||||
{
|
||||
$namespace = Str::replaceLast('\\', '', app()->getNamespace());
|
||||
|
||||
$appConfig = file_get_contents(config_path('app.php'));
|
||||
|
||||
if (Str::contains($appConfig, 'OwenIt\\Auditing\\AuditingServiceProvider::class')) {
|
||||
return;
|
||||
}
|
||||
|
||||
file_put_contents(config_path('app.php'), str_replace(
|
||||
"{$namespace}\\Providers\EventServiceProvider::class," . PHP_EOL,
|
||||
"{$namespace}\\Providers\EventServiceProvider::class," . PHP_EOL . " OwenIt\Auditing\AuditingServiceProvider::class," . PHP_EOL,
|
||||
$appConfig
|
||||
));
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
interface AttributeEncoder extends AttributeModifier
|
||||
{
|
||||
/**
|
||||
* Encode an attribute value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function encode($value);
|
||||
|
||||
/**
|
||||
* Decode an attribute value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode($value);
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
interface AttributeModifier
|
||||
{
|
||||
//
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
interface AttributeRedactor extends AttributeModifier
|
||||
{
|
||||
/**
|
||||
* Redact an attribute value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function redact($value): string;
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
/**
|
||||
* @mixin \OwenIt\Auditing\Models\Audit
|
||||
*/
|
||||
interface Audit
|
||||
{
|
||||
/**
|
||||
* Get the current connection name for the model.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getConnectionName();
|
||||
|
||||
/**
|
||||
* Get the table associated with the model.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTable();
|
||||
|
||||
/**
|
||||
* Get the auditable model to which this Audit belongs.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function auditable();
|
||||
|
||||
/**
|
||||
* User responsible for the changes.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function user();
|
||||
|
||||
/**
|
||||
* Audit data resolver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function resolveData(): array;
|
||||
|
||||
/**
|
||||
* Get an Audit data value.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDataValue(string $key);
|
||||
|
||||
/**
|
||||
* Get the Audit metadata.
|
||||
*
|
||||
* @param bool $json
|
||||
* @param int $options
|
||||
* @param int $depth
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public function getMetadata(bool $json = false, int $options = 0, int $depth = 512);
|
||||
|
||||
/**
|
||||
* Get the Auditable modified attributes.
|
||||
*
|
||||
* @param bool $json
|
||||
* @param int $options
|
||||
* @param int $depth
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public function getModified(bool $json = false, int $options = 0, int $depth = 512);
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
interface AuditDriver
|
||||
{
|
||||
/**
|
||||
* Perform an audit.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return \OwenIt\Auditing\Contracts\Audit
|
||||
*/
|
||||
public function audit(Auditable $model): ?Audit;
|
||||
|
||||
/**
|
||||
* Remove older audits that go over the threshold.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function prune(Auditable $model): bool;
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
|
||||
interface Auditable
|
||||
{
|
||||
/**
|
||||
* Auditable Model audits.
|
||||
*
|
||||
* @return MorphMany<\OwenIt\Auditing\Models\Audit>
|
||||
*/
|
||||
public function audits(): MorphMany;
|
||||
|
||||
/**
|
||||
* Set the Audit event.
|
||||
*
|
||||
* @param string $event
|
||||
*
|
||||
* @return Auditable
|
||||
*/
|
||||
public function setAuditEvent(string $event): Auditable;
|
||||
|
||||
/**
|
||||
* Get the Audit event that is set.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getAuditEvent();
|
||||
|
||||
/**
|
||||
* Get the events that trigger an Audit.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAuditEvents(): array;
|
||||
|
||||
/**
|
||||
* Is the model ready for auditing?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function readyForAuditing(): bool;
|
||||
|
||||
/**
|
||||
* Return data for an Audit.
|
||||
*
|
||||
* @throws \OwenIt\Auditing\Exceptions\AuditingException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toAudit(): array;
|
||||
|
||||
/**
|
||||
* Get the (Auditable) attributes included in audit.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAuditInclude(): array;
|
||||
|
||||
/**
|
||||
* Get the (Auditable) attributes excluded from audit.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAuditExclude(): array;
|
||||
|
||||
/**
|
||||
* Get the strict audit status.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getAuditStrict(): bool;
|
||||
|
||||
/**
|
||||
* Get the audit (Auditable) timestamps status.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getAuditTimestamps(): bool;
|
||||
|
||||
/**
|
||||
* Get the Audit Driver.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getAuditDriver();
|
||||
|
||||
/**
|
||||
* Get the Audit threshold.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getAuditThreshold(): int;
|
||||
|
||||
/**
|
||||
* Get the Attribute modifiers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributeModifiers(): array;
|
||||
|
||||
/**
|
||||
* Transform the data before performing an audit.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function transformAudit(array $data): array;
|
||||
|
||||
/**
|
||||
* Generate an array with the model tags.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function generateTags(): array;
|
||||
|
||||
/**
|
||||
* Transition to another model state from an Audit.
|
||||
*
|
||||
* @param Audit $audit
|
||||
* @param bool $old
|
||||
*
|
||||
* @throws \OwenIt\Auditing\Exceptions\AuditableTransitionException
|
||||
*
|
||||
* @return Auditable
|
||||
*/
|
||||
public function transitionTo(Audit $audit, bool $old = false): Auditable;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
interface Auditor
|
||||
{
|
||||
/**
|
||||
* Get an audit driver instance.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return AuditDriver
|
||||
*/
|
||||
public function auditDriver(Auditable $model): AuditDriver;
|
||||
|
||||
/**
|
||||
* Perform an audit.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute(Auditable $model);
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see Resolver
|
||||
*/
|
||||
interface IpAddressResolver
|
||||
{
|
||||
/**
|
||||
* Resolve the IP Address.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function resolve(): string;
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
interface Resolver
|
||||
{
|
||||
public static function resolve(Auditable $auditable);
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see Resolver
|
||||
*/
|
||||
interface UrlResolver
|
||||
{
|
||||
/**
|
||||
* Resolve the URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function resolve(): string;
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see Resolver
|
||||
*/
|
||||
interface UserAgentResolver
|
||||
{
|
||||
/**
|
||||
* Resolve the User Agent.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function resolve();
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Contracts;
|
||||
|
||||
interface UserResolver
|
||||
{
|
||||
/**
|
||||
* Resolve the User.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public static function resolve();
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Drivers;
|
||||
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use OwenIt\Auditing\Contracts\Audit;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
use OwenIt\Auditing\Contracts\AuditDriver;
|
||||
|
||||
class Database implements AuditDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function audit(Auditable $model): ?Audit
|
||||
{
|
||||
$implementation = Config::get('audit.implementation', \OwenIt\Auditing\Models\Audit::class);
|
||||
|
||||
return call_user_func([$implementation, 'create'], $model->toAudit());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prune(Auditable $model): bool
|
||||
{
|
||||
if (($threshold = $model->getAuditThreshold()) > 0) {
|
||||
$forRemoval = $model->audits()
|
||||
->latest()
|
||||
->get()
|
||||
->slice($threshold)
|
||||
->pluck('id');
|
||||
|
||||
if (!$forRemoval->isEmpty()) {
|
||||
return $model->audits()
|
||||
->whereIn('id', $forRemoval)
|
||||
->delete() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Encoders;
|
||||
|
||||
class Base64Encoder implements \OwenIt\Auditing\Contracts\AttributeEncoder
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function encode($value)
|
||||
{
|
||||
return base64_encode($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function decode($value)
|
||||
{
|
||||
return base64_decode($value);
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Events;
|
||||
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
|
||||
class AuditCustom
|
||||
{
|
||||
/**
|
||||
* The Auditable model.
|
||||
*
|
||||
* @var \OwenIt\Auditing\Contracts\Auditable
|
||||
*/
|
||||
public $model;
|
||||
|
||||
/**
|
||||
* Create a new Auditing event instance.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
*/
|
||||
public function __construct(Auditable $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Events;
|
||||
|
||||
use OwenIt\Auditing\Contracts\Audit;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
use OwenIt\Auditing\Contracts\AuditDriver;
|
||||
|
||||
class Audited
|
||||
{
|
||||
/**
|
||||
* The Auditable model.
|
||||
*
|
||||
* @var \OwenIt\Auditing\Contracts\Auditable
|
||||
*/
|
||||
public $model;
|
||||
|
||||
/**
|
||||
* Audit driver.
|
||||
*
|
||||
* @var \OwenIt\Auditing\Contracts\AuditDriver
|
||||
*/
|
||||
public $driver;
|
||||
|
||||
/**
|
||||
* The Audit model.
|
||||
*
|
||||
* @var \OwenIt\Auditing\Contracts\Audit|null
|
||||
*/
|
||||
public $audit;
|
||||
|
||||
/**
|
||||
* Create a new Audited event instance.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
* @param \OwenIt\Auditing\Contracts\AuditDriver $driver
|
||||
* @param \OwenIt\Auditing\Contracts\Audit $audit
|
||||
*/
|
||||
public function __construct(Auditable $model, AuditDriver $driver, Audit $audit = null)
|
||||
{
|
||||
$this->model = $model;
|
||||
$this->driver = $driver;
|
||||
$this->audit = $audit;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Events;
|
||||
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
use OwenIt\Auditing\Contracts\AuditDriver;
|
||||
|
||||
class Auditing
|
||||
{
|
||||
/**
|
||||
* The Auditable model.
|
||||
*
|
||||
* @var \OwenIt\Auditing\Contracts\Auditable
|
||||
*/
|
||||
public $model;
|
||||
|
||||
/**
|
||||
* Audit driver.
|
||||
*
|
||||
* @var \OwenIt\Auditing\Contracts\AuditDriver
|
||||
*/
|
||||
public $driver;
|
||||
|
||||
/**
|
||||
* Create a new Auditing event instance.
|
||||
*
|
||||
* @param \OwenIt\Auditing\Contracts\Auditable $model
|
||||
* @param \OwenIt\Auditing\Contracts\AuditDriver $driver
|
||||
*/
|
||||
public function __construct(Auditable $model, AuditDriver $driver)
|
||||
{
|
||||
$this->model = $model;
|
||||
$this->driver = $driver;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Events;
|
||||
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
|
||||
class DispatchAudit
|
||||
{
|
||||
/**
|
||||
* The Auditable model.
|
||||
*
|
||||
* @var Auditable
|
||||
*/
|
||||
public $model;
|
||||
|
||||
/**
|
||||
* Create a new DispatchAudit event instance.
|
||||
*
|
||||
* @param Auditable $model
|
||||
*/
|
||||
public function __construct(Auditable $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Events;
|
||||
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
|
||||
class DispatchingAudit
|
||||
{
|
||||
/**
|
||||
* The Auditable model.
|
||||
*
|
||||
* @var Auditable
|
||||
*/
|
||||
public $model;
|
||||
|
||||
/**
|
||||
* Create a new DispatchingAudit event instance.
|
||||
*
|
||||
* @param Auditable $model
|
||||
*/
|
||||
public function __construct(Auditable $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Exceptions;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class AuditableTransitionException extends AuditingException
|
||||
{
|
||||
/**
|
||||
* Attribute incompatibilities.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $incompatibilities = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($message = '', array $incompatibilities = [], $code = 0, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
$this->incompatibilities = $incompatibilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attribute incompatibilities.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getIncompatibilities(): array
|
||||
{
|
||||
return $this->incompatibilities;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class AuditingException extends Exception
|
||||
{
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
/**
|
||||
* @method static \OwenIt\Auditing\Contracts\AuditDriver auditDriver(\OwenIt\Auditing\Contracts\Auditable $model);
|
||||
* @method static void execute(\OwenIt\Auditing\Contracts\Auditable $model);
|
||||
*/
|
||||
class Auditor extends Facade
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return \OwenIt\Auditing\Contracts\Auditor::class;
|
||||
}
|
||||
}
|
||||
Vendored
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Listeners;
|
||||
|
||||
use OwenIt\Auditing\Facades\Auditor;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use OwenIt\Auditing\Events\DispatchAudit;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
class ProcessDispatchAudit implements ShouldQueue
|
||||
{
|
||||
public function viaConnection(): string
|
||||
{
|
||||
return Config::get('audit.queue.connection', 'sync');
|
||||
}
|
||||
|
||||
public function viaQueue(): string
|
||||
{
|
||||
return Config::get('audit.queue.queue', 'default');
|
||||
}
|
||||
|
||||
public function withDelay(DispatchAudit $event): int
|
||||
{
|
||||
return Config::get('audit.queue.delay', 0);
|
||||
}
|
||||
|
||||
public function handle(DispatchAudit $event)
|
||||
{
|
||||
Auditor::execute($event->model);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Listeners;
|
||||
|
||||
use OwenIt\Auditing\Facades\Auditor;
|
||||
|
||||
class RecordCustomAudit
|
||||
{
|
||||
public function handle(\OwenIt\Auditing\Contracts\Auditable $model)
|
||||
{
|
||||
Auditor::execute($model);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property string $tags
|
||||
* @property string $event
|
||||
* @property array $new_values
|
||||
* @property array $old_values
|
||||
* @property mixed $user
|
||||
* @property mixed $auditable.
|
||||
*/
|
||||
class Audit extends Model implements \OwenIt\Auditing\Contracts\Audit
|
||||
{
|
||||
use \OwenIt\Auditing\Audit;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $casts = [
|
||||
'old_values' => 'json',
|
||||
'new_values' => 'json',
|
||||
// Note: Please do not add 'auditable_id' in here, as it will break non-integer PK models
|
||||
];
|
||||
|
||||
public function getSerializedDate($date)
|
||||
{
|
||||
return $this->serializeDate($date);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Redactors;
|
||||
|
||||
class LeftRedactor implements \OwenIt\Auditing\Contracts\AttributeRedactor
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function redact($value): string
|
||||
{
|
||||
$total = strlen($value);
|
||||
$tenth = ceil($total / 10);
|
||||
|
||||
// Make sure single character strings get redacted
|
||||
$length = ($total > $tenth) ? ($total - $tenth) : 1;
|
||||
|
||||
return str_pad(substr($value, $length), $total, '#', STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Redactors;
|
||||
|
||||
class RightRedactor implements \OwenIt\Auditing\Contracts\AttributeRedactor
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function redact($value): string
|
||||
{
|
||||
$total = strlen($value);
|
||||
$tenth = ceil($total / 10);
|
||||
|
||||
// Make sure single character strings get redacted
|
||||
$length = ($total > $tenth) ? ($total - $tenth) : 1;
|
||||
|
||||
return str_pad(substr($value, 0, -$length), $total, '#', STR_PAD_RIGHT);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Resolvers;
|
||||
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
use OwenIt\Auditing\Contracts\Resolver;
|
||||
|
||||
class DumpResolver implements Resolver
|
||||
{
|
||||
public static function resolve(Auditable $auditable): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Resolvers;
|
||||
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
use OwenIt\Auditing\Contracts\Resolver;
|
||||
|
||||
class IpAddressResolver implements Resolver
|
||||
{
|
||||
public static function resolve(Auditable $auditable): string
|
||||
{
|
||||
return $auditable->preloadedResolverData['ip_address'] ?? Request::ip();
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Resolvers;
|
||||
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
|
||||
class UrlResolver implements \OwenIt\Auditing\Contracts\Resolver
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function resolve(Auditable $auditable): string
|
||||
{
|
||||
if (! empty($auditable->preloadedResolverData['url'] ?? null)) {
|
||||
return $auditable->preloadedResolverData['url'];
|
||||
}
|
||||
|
||||
if (App::runningInConsole()) {
|
||||
return self::resolveCommandLine();
|
||||
}
|
||||
|
||||
return Request::fullUrl();
|
||||
}
|
||||
|
||||
public static function resolveCommandLine(): string
|
||||
{
|
||||
$command = Request::server('argv', null);
|
||||
if (is_array($command)) {
|
||||
return implode(' ', $command);
|
||||
}
|
||||
|
||||
return 'console';
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Resolvers;
|
||||
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
use OwenIt\Auditing\Contracts\Resolver;
|
||||
|
||||
class UserAgentResolver implements Resolver
|
||||
{
|
||||
public static function resolve(Auditable $auditable)
|
||||
{
|
||||
return $auditable->preloadedResolverData['user_agent'] ?? Request::header('User-Agent');
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace OwenIt\Auditing\Resolvers;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
|
||||
class UserResolver implements \OwenIt\Auditing\Contracts\UserResolver
|
||||
{
|
||||
/**
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public static function resolve()
|
||||
{
|
||||
$guards = Config::get('audit.user.guards', [
|
||||
\config('auth.defaults.guard')
|
||||
]);
|
||||
|
||||
foreach ($guards as $guard) {
|
||||
try {
|
||||
$authenticated = Auth::guard($guard)->check();
|
||||
} catch (\Exception $exception) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (true === $authenticated) {
|
||||
return Auth::guard($guard)->user();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user