git subrepo commit (merge) mailcow/src/mailcow-dockerized

subrepo: subdir:   "mailcow/src/mailcow-dockerized"
  merged:   "02ae5285"
upstream: origin:   "https://github.com/mailcow/mailcow-dockerized.git"
  branch:   "master"
  commit:   "649a5c01"
git-subrepo: version:  "0.4.3"
  origin:   "???"
  commit:   "???"
Change-Id: I870ad468fba026cc5abf3c5699ed1e12ff28b32b
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Computer.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Computer.php
new file mode 100644
index 0000000..72db0a0
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Computer.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+use LdapRecord\Models\ActiveDirectory\Concerns\HasPrimaryGroup;
+
+class Computer extends Entry
+{
+    use HasPrimaryGroup;
+
+    /**
+     * The object classes of the LDAP model.
+     *
+     * @var array
+     */
+    public static $objectClasses = [
+        'top',
+        'person',
+        'organizationalperson',
+        'user',
+        'computer',
+    ];
+
+    /**
+     * The groups relationship.
+     *
+     * Retrieves groups that the current computer is apart of.
+     *
+     * @return \LdapRecord\Models\Relations\HasMany
+     */
+    public function groups()
+    {
+        return $this->hasMany(Group::class, 'member')->with($this->primaryGroup());
+    }
+
+    /**
+     * The primary group relationship.
+     *
+     * @return Relations\HasOnePrimaryGroup
+     */
+    public function primaryGroup()
+    {
+        return $this->hasOnePrimaryGroup(Group::class, 'primarygroupid');
+    }
+
+    /**
+     * The managed by relationship.
+     *
+     * @return \LdapRecord\Models\Relations\HasOne
+     */
+    public function managedBy()
+    {
+        return $this->hasOne([Contact::class, Group::class, User::class], 'managedby');
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Concerns/HasPrimaryGroup.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Concerns/HasPrimaryGroup.php
new file mode 100644
index 0000000..97fd3a1
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Concerns/HasPrimaryGroup.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory\Concerns;
+
+use LdapRecord\Models\ActiveDirectory\Relations\HasOnePrimaryGroup;
+
+trait HasPrimaryGroup
+{
+    /**
+     * Returns a new has one primary group relationship.
+     *
+     * @param mixed  $related
+     * @param string $relationKey
+     * @param string $foreignKey
+     *
+     * @return HasOnePrimaryGroup
+     */
+    public function hasOnePrimaryGroup($related, $relationKey, $foreignKey = 'primarygroupid')
+    {
+        return new HasOnePrimaryGroup($this->newQuery(), $this, $related, $relationKey, $foreignKey);
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Contact.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Contact.php
new file mode 100644
index 0000000..52c451f
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Contact.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+class Contact extends Entry
+{
+    /**
+     * The object classes of the LDAP model.
+     *
+     * @var array
+     */
+    public static $objectClasses = [
+        'top',
+        'person',
+        'organizationalperson',
+        'contact',
+    ];
+
+    /**
+     * The groups relationship.
+     *
+     * Retrieves groups that the current contact is apart of.
+     *
+     * @return \LdapRecord\Models\Relations\HasMany
+     */
+    public function groups()
+    {
+        return $this->hasMany(Group::class, 'member');
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Container.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Container.php
new file mode 100644
index 0000000..1636cf3
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Container.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+class Container extends Entry
+{
+    /**
+     * The object classes of the LDAP model.
+     *
+     * @var array
+     */
+    public static $objectClasses = [
+        'top',
+        'container',
+    ];
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Entry.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Entry.php
new file mode 100644
index 0000000..79a9d63
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Entry.php
@@ -0,0 +1,167 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+use InvalidArgumentException;
+use LdapRecord\Connection;
+use LdapRecord\Models\Attributes\Sid;
+use LdapRecord\Models\Entry as BaseEntry;
+use LdapRecord\Models\Events\Updated;
+use LdapRecord\Models\Types\ActiveDirectory;
+use LdapRecord\Query\Model\ActiveDirectoryBuilder;
+
+/** @mixin ActiveDirectoryBuilder */
+class Entry extends BaseEntry implements ActiveDirectory
+{
+    /**
+     * The default attributes that should be mutated to dates.
+     *
+     * @var array
+     */
+    protected $defaultDates = [
+        'whenchanged' => 'windows',
+        'whencreated' => 'windows',
+        'dscorepropagationdata' => 'windows',
+    ];
+
+    /**
+     * The attribute key that contains the Object SID.
+     *
+     * @var string
+     */
+    protected $sidKey = 'objectsid';
+
+    /**
+     * @inheritdoc
+     */
+    public function getObjectSidKey()
+    {
+        return $this->sidKey;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getObjectSid()
+    {
+        return $this->getFirstAttribute($this->sidKey);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getConvertedSid()
+    {
+        try {
+            return (string) new Sid($this->getObjectSid());
+        } catch (InvalidArgumentException $e) {
+            return;
+        }
+    }
+
+    /**
+     * Create a new query builder.
+     *
+     * @param Connection $connection
+     *
+     * @return ActiveDirectoryBuilder
+     */
+    public function newQueryBuilder(Connection $connection)
+    {
+        return new ActiveDirectoryBuilder($connection);
+    }
+
+    /**
+     * Determine if the object is deleted.
+     *
+     * @return bool
+     */
+    public function isDeleted()
+    {
+        return strtoupper($this->getFirstAttribute('isDeleted')) === 'TRUE';
+    }
+
+    /**
+     * Restore a deleted object.
+     *
+     * @param string|null $newParentDn
+     *
+     * @throws \LdapRecord\LdapRecordException
+     *
+     * @return bool
+     */
+    public function restore($newParentDn = null)
+    {
+        if (! $this->isDeleted()) {
+            return false;
+        }
+
+        $root = $newParentDn ?? $this->getDefaultRestoreLocation();
+        $rdn = explode('\0A', $this->getDn(), 2)[0];
+        $newDn = implode(',', [$rdn, $root]);
+
+        // We will initialize a model listener for the "updated" event to set
+        // the models distinguished name so all attributes are synchronized
+        // properly after the model has been successfully restored.
+        $this->listenForModelEvent(Updated::class, function (Updated $event) use ($newDn) {
+            if ($this->is($event->getModel())) {
+                $this->setDn($newDn);
+            }
+        });
+
+        $this->save([
+            'isDeleted' => null,
+            'distinguishedName' => $newDn,
+        ]);
+    }
+
+    /**
+     * Get the RootDSE (AD schema) record from the directory.
+     *
+     * @param string|null $connection
+     *
+     * @throws \LdapRecord\Models\ModelNotFoundException
+     *
+     * @return static
+     */
+    public static function getRootDse($connection = null)
+    {
+        return static::on($connection ?? (new static())->getConnectionName())
+            ->in(null)
+            ->read()
+            ->whereHas('objectclass')
+            ->firstOrFail();
+    }
+
+    /**
+     * Get the objects restore location.
+     *
+     * @return string
+     */
+    protected function getDefaultRestoreLocation()
+    {
+        return $this->getFirstAttribute('lastKnownParent') ?? $this->getParentDn($this->getParentDn($this->getDn()));
+    }
+
+    /**
+     * Converts attributes for JSON serialization.
+     *
+     * @param array $attributes
+     *
+     * @return array
+     */
+    protected function convertAttributesForJson(array $attributes = [])
+    {
+        $attributes = parent::convertAttributesForJson($attributes);
+
+        if ($this->hasAttribute($this->sidKey)) {
+            // If the model has a SID set, we need to convert it due to it being in
+            // binary. Otherwise we will receive a JSON serialization exception.
+            return array_replace($attributes, [
+                $this->sidKey => [$this->getConvertedSid()],
+            ]);
+        }
+
+        return $attributes;
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/ExchangeDatabase.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/ExchangeDatabase.php
new file mode 100644
index 0000000..77abbbc
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/ExchangeDatabase.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+class ExchangeDatabase extends Entry
+{
+    /**
+     * @inheritdoc
+     */
+    public static $objectClasses = ['msExchMDB'];
+
+    /**
+     * @inheritdoc
+     */
+    public static function boot()
+    {
+        parent::boot();
+
+        static::addGlobalScope(new Scopes\InConfigurationContext());
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/ExchangeServer.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/ExchangeServer.php
new file mode 100644
index 0000000..d304876
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/ExchangeServer.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+class ExchangeServer extends Entry
+{
+    /**
+     * @inheritdoc
+     */
+    public static $objectClasses = ['msExchExchangeServer'];
+
+    /**
+     * @inheritdoc
+     */
+    public static function boot()
+    {
+        parent::boot();
+
+        static::addGlobalScope(new Scopes\HasServerRoleAttribute());
+        static::addGlobalScope(new Scopes\InConfigurationContext());
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/ForeignSecurityPrincipal.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/ForeignSecurityPrincipal.php
new file mode 100644
index 0000000..25287ae
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/ForeignSecurityPrincipal.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+class ForeignSecurityPrincipal extends Entry
+{
+    /**
+     * The object classes of the LDAP model.
+     *
+     * @var array
+     */
+    public static $objectClasses = ['foreignsecurityprincipal'];
+
+    /**
+     * The groups relationship.
+     *
+     * Retrieves groups that the current security principal is apart of.
+     *
+     * @return \LdapRecord\Models\Relations\HasMany
+     */
+    public function groups()
+    {
+        return $this->hasMany(Group::class, 'member');
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Group.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Group.php
new file mode 100644
index 0000000..6076f2f
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Group.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+class Group extends Entry
+{
+    /**
+     * The object classes of the LDAP model.
+     *
+     * @var array
+     */
+    public static $objectClasses = [
+        'top',
+        'group',
+    ];
+
+    /**
+     * The groups relationship.
+     *
+     * Retrieves groups that the current group is apart of.
+     *
+     * @return \LdapRecord\Models\Relations\HasMany
+     */
+    public function groups()
+    {
+        return $this->hasMany(static::class, 'member');
+    }
+
+    /**
+     * The members relationship.
+     *
+     * Retrieves members that are apart of the group.
+     *
+     * @return \LdapRecord\Models\Relations\HasMany
+     */
+    public function members()
+    {
+        return $this->hasMany([
+            static::class, User::class, Contact::class, Computer::class,
+        ], 'memberof')
+            ->using($this, 'member')
+            ->with($this->primaryGroupMembers());
+    }
+
+    /**
+     * The primary group members relationship.
+     *
+     * Retrieves members that are apart the primary group.
+     *
+     * @return \LdapRecord\Models\Relations\HasMany
+     */
+    public function primaryGroupMembers()
+    {
+        return $this->hasMany([
+            static::class, User::class, Contact::class, Computer::class,
+        ], 'primarygroupid', 'rid');
+    }
+
+    /**
+     * Get the RID of the group.
+     *
+     * @return array
+     */
+    public function getRidAttribute()
+    {
+        $objectSidComponents = explode('-', $this->getConvertedSid());
+
+        return [end($objectSidComponents)];
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/OrganizationalUnit.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/OrganizationalUnit.php
new file mode 100644
index 0000000..80aae9f
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/OrganizationalUnit.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+class OrganizationalUnit extends Entry
+{
+    /**
+     * The object classes of the LDAP model.
+     *
+     * @var array
+     */
+    public static $objectClasses = [
+        'top',
+        'organizationalunit',
+    ];
+
+    /**
+     * Get the creatable RDN attribute name.
+     *
+     * @return string
+     */
+    public function getCreatableRdnAttribute()
+    {
+        return 'ou';
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Printer.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Printer.php
new file mode 100644
index 0000000..df74216
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Printer.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+class Printer extends Entry
+{
+    /**
+     * The object classes of the LDAP model.
+     *
+     * @var array
+     */
+    public static $objectClasses = ['printqueue'];
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Relations/HasOnePrimaryGroup.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Relations/HasOnePrimaryGroup.php
new file mode 100644
index 0000000..540ec77
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Relations/HasOnePrimaryGroup.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory\Relations;
+
+use LdapRecord\Models\Model;
+use LdapRecord\Models\Relations\HasOne;
+
+class HasOnePrimaryGroup extends HasOne
+{
+    /**
+     * Get the foreign model by the given value.
+     *
+     * @param string $value
+     *
+     * @return Model|null
+     */
+    protected function getForeignModelByValue($value)
+    {
+        return $this->query->findBySid(
+            $this->getParentModelObjectSid()
+        );
+    }
+
+    /**
+     * Get the foreign value from the given model.
+     *
+     * Retrieves the last RID from the models Object SID.
+     *
+     * @param Model $model
+     *
+     * @return string
+     */
+    protected function getForeignValueFromModel(Model $model)
+    {
+        $objectSidComponents = explode('-', $model->getConvertedSid());
+
+        return end($objectSidComponents);
+    }
+
+    /**
+     * Get the parent relationship models converted object sid.
+     *
+     * @return string
+     */
+    protected function getParentModelObjectSid()
+    {
+        return preg_replace(
+            '/\d+$/',
+            $this->parent->getFirstAttribute($this->relationKey),
+            $this->parent->getConvertedSid()
+        );
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Scopes/HasServerRoleAttribute.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Scopes/HasServerRoleAttribute.php
new file mode 100644
index 0000000..cd08648
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Scopes/HasServerRoleAttribute.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory\Scopes;
+
+use LdapRecord\Models\Model;
+use LdapRecord\Models\Scope;
+use LdapRecord\Query\Model\Builder;
+
+class HasServerRoleAttribute implements Scope
+{
+    /**
+     * Includes condition of having a serverRole attribute.
+     *
+     * @param Builder $query
+     * @param Model   $model
+     *
+     * @return void
+     */
+    public function apply(Builder $query, Model $model)
+    {
+        $query->whereHas('serverRole');
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Scopes/InConfigurationContext.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Scopes/InConfigurationContext.php
new file mode 100644
index 0000000..2b1a177
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Scopes/InConfigurationContext.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory\Scopes;
+
+use LdapRecord\Models\ActiveDirectory\Entry;
+use LdapRecord\Models\Model;
+use LdapRecord\Models\Scope;
+use LdapRecord\Query\Model\Builder;
+
+class InConfigurationContext implements Scope
+{
+    /**
+     * Refines the base dn to be inside the configuration context.
+     *
+     * @param Builder $query
+     * @param Model   $model
+     *
+     * @throws \LdapRecord\Models\ModelNotFoundException
+     *
+     * @return void
+     */
+    public function apply(Builder $query, Model $model)
+    {
+        $query->in($this->getConfigurationNamingContext($model));
+    }
+
+    /**
+     * Get the LDAP server configuration naming context distinguished name.
+     *
+     * @param Model $model
+     *
+     * @throws \LdapRecord\Models\ModelNotFoundException
+     *
+     * @return mixed
+     */
+    protected function getConfigurationNamingContext(Model $model)
+    {
+        return Entry::getRootDse($model->getConnectionName())
+            ->getFirstAttribute('configurationNamingContext');
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Scopes/RejectComputerObjectClass.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Scopes/RejectComputerObjectClass.php
new file mode 100644
index 0000000..a616db1
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/Scopes/RejectComputerObjectClass.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory\Scopes;
+
+use LdapRecord\Models\Model;
+use LdapRecord\Models\Scope;
+use LdapRecord\Query\Model\Builder;
+
+class RejectComputerObjectClass implements Scope
+{
+    /**
+     * Prevent computer objects from being included in results.
+     *
+     * @param Builder $query
+     * @param Model   $model
+     *
+     * @return void
+     */
+    public function apply(Builder $query, Model $model)
+    {
+        $query->where('objectclass', '!=', 'computer');
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/User.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/User.php
new file mode 100644
index 0000000..84dd74b
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Models/ActiveDirectory/User.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace LdapRecord\Models\ActiveDirectory;
+
+use Illuminate\Contracts\Auth\Authenticatable;
+use LdapRecord\Models\ActiveDirectory\Concerns\HasPrimaryGroup;
+use LdapRecord\Models\ActiveDirectory\Scopes\RejectComputerObjectClass;
+use LdapRecord\Models\Concerns\CanAuthenticate;
+use LdapRecord\Models\Concerns\HasPassword;
+use LdapRecord\Query\Model\Builder;
+
+class User extends Entry implements Authenticatable
+{
+    use HasPassword;
+    use HasPrimaryGroup;
+    use CanAuthenticate;
+
+    /**
+     * The password's attribute name.
+     *
+     * @var string
+     */
+    protected $passwordAttribute = 'unicodepwd';
+
+    /**
+     * The password's hash method.
+     *
+     * @var string
+     */
+    protected $passwordHashMethod = 'encode';
+
+    /**
+     * The object classes of the LDAP model.
+     *
+     * @var array
+     */
+    public static $objectClasses = [
+        'top',
+        'person',
+        'organizationalperson',
+        'user',
+    ];
+
+    /**
+     * The attributes that should be mutated to dates.
+     *
+     * @var array
+     */
+    protected $dates = [
+        'lastlogon' => 'windows-int',
+        'lastlogoff' => 'windows-int',
+        'pwdlastset' => 'windows-int',
+        'lockouttime' => 'windows-int',
+        'accountexpires' => 'windows-int',
+        'badpasswordtime' => 'windows-int',
+        'lastlogontimestamp' => 'windows-int',
+    ];
+
+    /**
+     * @inheritdoc
+     */
+    protected static function boot()
+    {
+        parent::boot();
+
+        // Here we will add a global scope to reject the 'computer' object
+        // class. This is needed due to computer objects containing all
+        // of the ActiveDirectory 'user' object classes. Without
+        // this scope, they would be included in results.
+        static::addGlobalScope(new RejectComputerObjectClass());
+    }
+
+    /**
+     * The groups relationship.
+     *
+     * Retrieves groups that the user is apart of.
+     *
+     * @return \LdapRecord\Models\Relations\HasMany
+     */
+    public function groups()
+    {
+        return $this->hasMany(Group::class, 'member')->with($this->primaryGroup());
+    }
+
+    /**
+     * The manager relationship.
+     *
+     * Retrieves the manager of the user.
+     *
+     * @return \LdapRecord\Models\Relations\HasOne
+     */
+    public function manager()
+    {
+        return $this->hasOne(static::class, 'manager');
+    }
+
+    /**
+     * The primary group relationship of the current user.
+     *
+     * Retrieves the primary group the user is apart of.
+     *
+     * @return \LdapRecord\Models\Relations\HasOne
+     */
+    public function primaryGroup()
+    {
+        return $this->hasOnePrimaryGroup(Group::class, 'primarygroupid');
+    }
+
+    /**
+     * Scopes the query to exchange mailbox users.
+     *
+     * @param Builder $query
+     *
+     * @return Builder
+     */
+    public function scopeWhereHasMailbox(Builder $query)
+    {
+        return $query->whereHas('msExchMailboxGuid');
+    }
+}