diff --git a/bin/phpdoc b/bin/phpdoc
new file mode 100755
--- /dev/null
+++ b/bin/phpdoc
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+cwd=$(dirname $0)
+
+pushd ${cwd}/..
+phpdoc
+popd
diff --git a/bin/phpstan b/bin/phpstan
new file mode 100755
--- /dev/null
+++ b/bin/phpstan
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+cwd=$(dirname $0)
+
+pushd ${cwd}/../src/
+
+php -dmemory_limit=256M \
+ vendor/bin/phpstan \
+ analyse
+
+popd
diff --git a/bin/phpunit b/bin/phpunit
new file mode 100755
--- /dev/null
+++ b/bin/phpunit
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+cwd=$(dirname $0)
+
+pushd ${cwd}/../src/
+
+php -dzend_extension=xdebug.so \
+ vendor/bin/phpunit \
+ --exclude-group imap \
+ --stop-on-defect \
+ --stop-on-error \
+ --stop-on-failure \
+ --testsuite Browser,Unit,Feature
+
+popd
diff --git a/bin/quickstart.sh b/bin/quickstart.sh
--- a/bin/quickstart.sh
+++ b/bin/quickstart.sh
@@ -43,10 +43,10 @@
docker-compose up -d kolab mariadb redis
pushd ${base_dir}/src/
+cp .env.example .env
composer install
npm install
find bootstrap/cache/ -type f ! -name ".gitignore" -delete
-cp .env.example .env
./artisan key:generate
./artisan jwt:secret -f
./artisan clear-compiled
diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml
--- a/phpdoc.dist.xml
+++ b/phpdoc.dist.xml
@@ -11,8 +11,10 @@
src/app/
src/database/
+ src/database/factories/
src/database/migrations/
src/database/seeds/
+ src/resources/
src/resources/
diff --git a/src/.env.example b/src/.env.example
--- a/src/.env.example
+++ b/src/.env.example
@@ -25,9 +25,8 @@
IMAP_URI=ssl://127.0.0.1:993
IMAP_ADMIN_LOGIN=cyrus-admin
IMAP_ADMIN_PASSWORD=Welcome2KolabSystems
-IMAP_VERIFY_PEER=true
-IMAP_VERIFY_NAME=true
-IMAP_CAFILE=null
+IMAP_VERIFY_HOST=false
+IMAP_VERIFY_PEER=false
LDAP_BASE_DN="dc=mgmt,dc=com"
LDAP_DOMAIN_BASE_DN="ou=Domains,dc=mgmt,dc=com"
diff --git a/src/.gitignore b/src/.gitignore
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,5 +1,6 @@
database/database.sqlite
node_modules/
+package-lock.json
public/css/app.css
public/hot
public/js/app.js
diff --git a/src/app/Auth/LDAPUserProvider.php b/src/app/Auth/LDAPUserProvider.php
--- a/src/app/Auth/LDAPUserProvider.php
+++ b/src/app/Auth/LDAPUserProvider.php
@@ -3,32 +3,68 @@
namespace App\Auth;
use App\User;
-use Carbon\Carbon;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Support\Facades\Hash;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
+/**
+ * A user provider that integrates an LDAP deployment.
+ */
class LDAPUserProvider extends EloquentUserProvider implements UserProvider
{
+ /**
+ * Retrieve the user by its ID.
+ *
+ * @param string $identifier The unique ID for the user to attempt to retrieve.
+ *
+ * @return \Illuminate\Contracts\Auth\Authenticatable|null
+ */
public function retrieveById($identifier)
{
return parent::retrieveById($identifier);
}
+ /**
+ * Retrieve the user by its credentials.
+ *
+ * Please note that this function also validates the password.
+ *
+ * @param array $credentials An array containing the email and password.
+ *
+ * @return User|null
+ */
public function retrieveByCredentials(array $credentials)
{
$entries = User::where('email', '=', $credentials['email']);
if ($entries->count() == 1) {
- $user = $entries->select('id', 'email', 'password', 'password_ldap')->first();
+ $user = $entries->select(['id', 'email', 'password', 'password_ldap'])->first();
+
+ if (!$this->validateCredentials($user, $credentials)) {
+ return null;
+ }
return $user;
+ } else {
+ if ($entries->count() > 1) {
+ \Log::warning("Multiple entries for {$credentials['email']}");
+ } else {
+ \Log::warning("No entries for {$credentials['email']}");
+ }
}
return null;
}
+ /**
+ * Validate the credentials for a user.
+ *
+ * @param Authenticatable $user The user.
+ * @param array $credentials The credentials.
+ *
+ * @return bool
+ */
public function validateCredentials(Authenticatable $user, array $credentials)
{
$authenticated = false;
@@ -46,6 +82,8 @@
if ($hash == $user->password_ldap) {
$authenticated = true;
}
+ } else {
+ \Log::error("Incomplete credentials for {$user->email}");
}
}
@@ -53,8 +91,18 @@
// TODO: Update password if necessary, examine whether writing to
// user->password is sufficient?
if ($authenticated) {
- $user->password = $credentials['password'];
- $user->save();
+ \Log::info("Successful authentication for {$user->email}");
+
+ if (empty($user->password)) {
+ $user->password = $credentials['password'];
+ $user->save();
+ }
+
+ if (empty($user->password_ldap)) {
+ $user->password_ldap = '{SSHA512}' . base64_encode(
+ pack('H*', hash('sha512', $credentials['password']))
+ );
+ }
} else {
// TODO: Try actual LDAP?
\Log::info("Authentication failed for {$user->email}");
diff --git a/src/app/Backends/IMAP.php b/src/app/Backends/IMAP.php
--- a/src/app/Backends/IMAP.php
+++ b/src/app/Backends/IMAP.php
@@ -89,8 +89,8 @@
'socket_options' => [
'ssl' => [
'verify_peer' => \config('imap.verify_peer'),
- 'verify_peer_name' => \config('imap.verify_name'),
- 'cafile' => \config('imap.cafile'),
+ 'verify_peer_name' => \config('imap.verify_peer'),
+ 'verify_host' => \config('imap.verify_host')
],
],
],
diff --git a/src/app/Backends/LDAP.php b/src/app/Backends/LDAP.php
--- a/src/app/Backends/LDAP.php
+++ b/src/app/Backends/LDAP.php
@@ -162,7 +162,7 @@
*
* @param \App\User $user The user account to create.
*
- * @return void
+ * @return bool|void
*/
public static function createUser(User $user)
{
@@ -213,12 +213,56 @@
//
}
+ public static function deleteDomain($domain)
+ {
+ $config = self::getConfig('admin');
+ $ldap = self::initLDAP($config);
+
+ $hosted_root_dn = \config('ldap.hosted.root_dn');
+ $mgmt_root_dn = \config('ldap.admin.root_dn');
+
+ $domain_base_dn = "ou={$domain->namespace},{$hosted_root_dn}";
+
+ if ($ldap->get_entry($domain_base_dn)) {
+ $ldap->delete_entry_recursive($domain_base_dn);
+ }
+
+ if ($ldap_domain = $ldap->find_domain($domain->namespace)) {
+ if ($ldap->get_entry($ldap_domain['dn'])) {
+ $ldap->delete_entry($ldap_domain['dn']);
+ }
+ }
+ }
+
+ public static function deleteUser($user)
+ {
+ $config = self::getConfig('admin');
+ $ldap = self::initLDAP($config);
+
+ list($_local, $_domain) = explode('@', $user->email, 2);
+
+ $domain = $ldap->find_domain($_domain);
+
+ if (!$domain) {
+ return false;
+ }
+
+ $base_dn = $ldap->domain_root_dn($_domain);
+ $dn = "uid={$user->email},ou=People,{$base_dn}";
+
+ if (!$ldap->get_entry($dn)) {
+ return false;
+ }
+
+ $ldap->delete_entry($dn);
+ }
+
/**
* Update a user in LDAP.
*
* @param \App\User $user The user account to update.
*
- * @return void
+ * @return bool|void
*/
public static function updateUser(User $user)
{
diff --git a/src/app/Console/Commands/PackageSkusCommand.php b/src/app/Console/Commands/PackageSkusCommand.php
--- a/src/app/Console/Commands/PackageSkusCommand.php
+++ b/src/app/Console/Commands/PackageSkusCommand.php
@@ -39,12 +39,12 @@
*/
public function handle()
{
- $packages = Package::get();
+ $packages = Package::all();
foreach ($packages as $package) {
$this->info(sprintf("Package: %s", $package->title));
- foreach ($package->skus()->get() as $sku) {
+ foreach ($package->skus as $sku) {
$this->info(sprintf(" SKU: %s (%d)", $sku->title, $sku->pivot->qty));
}
}
diff --git a/src/app/Console/Commands/PlanPackagesCommand.php b/src/app/Console/Commands/PlanPackagesCommand.php
--- a/src/app/Console/Commands/PlanPackagesCommand.php
+++ b/src/app/Console/Commands/PlanPackagesCommand.php
@@ -39,14 +39,14 @@
*/
public function handle()
{
- $plans = Plan::get();
+ $plans = Plan::all();
foreach ($plans as $plan) {
$this->info(sprintf("Plan: %s", $plan->title));
$plan_costs = 0;
- foreach ($plan->packages()->get() as $package) {
+ foreach ($plan->packages as $package) {
$qtyMin = $package->pivot->qty_min;
$qtyMax = $package->pivot->qty_max;
@@ -65,7 +65,7 @@
)
);
- foreach ($package->skus()->get() as $sku) {
+ foreach ($package->skus as $sku) {
$this->info(sprintf(" SKU: %s (%d)", $sku->title, $sku->pivot->qty));
}
diff --git a/src/app/Console/Commands/UserDomains.php b/src/app/Console/Commands/UserDomains.php
--- a/src/app/Console/Commands/UserDomains.php
+++ b/src/app/Console/Commands/UserDomains.php
@@ -40,8 +40,6 @@
*/
public function handle()
{
- DB::enableQueryLog();
-
$user = User::where('email', $this->argument('userid'))->first();
$this->info("Found user: {$user->id}");
@@ -49,7 +47,5 @@
foreach ($user->domains() as $domain) {
$this->info("Domain: {$domain->namespace}");
}
-
- dd(DB::getQueryLog());
}
}
diff --git a/src/app/Console/Commands/UserEntitlementsCommand.php b/src/app/Console/Commands/UserEntitlementsCommand.php
--- a/src/app/Console/Commands/UserEntitlementsCommand.php
+++ b/src/app/Console/Commands/UserEntitlementsCommand.php
@@ -2,7 +2,7 @@
namespace App\Console\Commands;
-use App\Domain;
+use App\Sku;
use App\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
@@ -44,19 +44,19 @@
$this->info("Found user: {$user->id}");
- $entitlements = $user->entitlements()->get();
+ $skus_counted = [];
- foreach ($entitlements as $entitlement) {
- //yes: dd($entitlement);
- $_entitleable = $entitlement->entitleable;
-
- if ($_entitleable instanceof Domain) {
- $this->info(sprintf("Domain: %s", $_entitleable->namespace));
+ foreach ($user->entitlements as $entitlement) {
+ if (!array_key_exists($entitlement->sku_id, $skus_counted)) {
+ $skus_counted[$entitlement->sku_id] = 1;
+ } else {
+ $skus_counted[$entitlement->sku_id] += 1;
}
+ }
- if ($_entitleable instanceof User) {
- $this->info(sprintf("User: %s", $_entitleable->email));
- }
+ foreach ($skus_counted as $id => $qty) {
+ $sku = Sku::find($id);
+ $this->info("SKU: {$sku->title} ({$qty})");
}
}
}
diff --git a/src/app/Domain.php b/src/app/Domain.php
--- a/src/app/Domain.php
+++ b/src/app/Domain.php
@@ -3,9 +3,17 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\SoftDeletes;
+/**
+ * The eloquent definition of a Domain.
+ *
+ * @property string $namespace
+ */
class Domain extends Model
{
+ use SoftDeletes;
+
// we've simply never heard of this domain
public const STATUS_NEW = 1 << 0;
// it's been activated
@@ -17,7 +25,7 @@
// ownership of the domain has been confirmed
public const STATUS_CONFIRMED = 1 << 4;
// domain has been verified that it exists in DNS
-// public const STATUS_VERIFIED = 1 << 5;
+ public const STATUS_VERIFIED = 1 << 5;
// domain has been created in LDAP
public const STATUS_LDAP_READY = 1 << 6;
@@ -33,6 +41,7 @@
public const HASH_CNAME = 3;
public $incrementing = false;
+
protected $keyType = 'bigint';
protected $fillable = [
@@ -41,6 +50,35 @@
'type'
];
+ /**
+ * Assign a package to a domain. The domain should not belong to any existing entitlements.
+ *
+ * @param \App\Package $package The package to assign.
+ *
+ * @return \App\Domain
+ */
+ public function assignPackage($package, $user)
+ {
+ $wallet_id = $user->wallets()->get()[0]->id;
+
+ foreach ($package->skus as $sku) {
+ for ($i = $sku->pivot->qty; $i > 0; $i--) {
+ \App\Entitlement::create(
+ [
+ 'owner_id' => $user->id,
+ 'wallet_id' => $wallet_id,
+ 'sku_id' => $sku->id,
+ 'entitleable_id' => $this->id,
+ 'entitleable_type' => Domain::class
+ ]
+ );
+ }
+ }
+
+ return $this;
+ }
+
+
public function entitlement()
{
return $this->morphOne('App\Entitlement', 'entitleable');
@@ -65,7 +103,7 @@
*/
public function isActive(): bool
{
- return $this->status & self::STATUS_ACTIVE;
+ return ($this->status & self::STATUS_ACTIVE) == true;
}
/**
@@ -75,7 +113,7 @@
*/
public function isConfirmed(): bool
{
- return $this->status & self::STATUS_CONFIRMED;
+ return ($this->status & self::STATUS_CONFIRMED) == true;
}
/**
@@ -85,7 +123,7 @@
*/
public function isDeleted(): bool
{
- return $this->status & self::STATUS_DELETED;
+ return ($this->status & self::STATUS_DELETED) == true;
}
/**
@@ -95,7 +133,7 @@
*/
public function isExternal(): bool
{
- return $this->type & self::TYPE_EXTERNAL;
+ return ($this->type & self::TYPE_EXTERNAL) == true;
}
/**
@@ -105,7 +143,7 @@
*/
public function isHosted(): bool
{
- return $this->type & self::TYPE_HOSTED;
+ return ($this->type & self::TYPE_HOSTED) == true;
}
/**
@@ -115,7 +153,7 @@
*/
public function isNew(): bool
{
- return $this->status & self::STATUS_NEW;
+ return ($this->status & self::STATUS_NEW) == true;
}
/**
@@ -125,7 +163,7 @@
*/
public function isPublic(): bool
{
- return $this->type & self::TYPE_PUBLIC;
+ return ($this->type & self::TYPE_PUBLIC) == true;
}
/**
@@ -135,7 +173,7 @@
*/
public function isLdapReady(): bool
{
- return $this->status & self::STATUS_LDAP_READY;
+ return ($this->status & self::STATUS_LDAP_READY) == true;
}
/**
@@ -145,7 +183,7 @@
*/
public function isSuspended(): bool
{
- return $this->status & self::STATUS_SUSPENDED;
+ return ($this->status & self::STATUS_SUSPENDED) == true;
}
/**
@@ -154,12 +192,11 @@
*
* @return bool
*/
-/*
public function isVerified(): bool
{
- return $this->status & self::STATUS_VERIFIED;
+ return ($this->status & self::STATUS_VERIFIED) == true;
}
-*/
+
/**
* Domain status mutator
*
@@ -176,7 +213,7 @@
self::STATUS_SUSPENDED,
self::STATUS_DELETED,
self::STATUS_LDAP_READY,
-// self::STATUS_VERIFIED,
+ self::STATUS_VERIFIED,
];
foreach ($allowed_values as $value) {
@@ -232,7 +269,7 @@
$records = \dns_get_record('kolab-verify.' . $this->namespace, DNS_CNAME);
if ($records === false) {
- throw new \Exception("Failed to get DNS record for $domain");
+ throw new \Exception("Failed to get DNS record for {$this->namespace}");
}
foreach ($records as $records) {
@@ -277,14 +314,13 @@
* @return bool True if registered, False otherwise
* @throws \Exception Throws exception on DNS or DB errors
*/
-/*
public function verify(): bool
{
if ($this->isVerified()) {
return true;
}
- $record = \dns_get_record($this->namespace, DNS_SOA);
+ $record = \dns_get_record($this->namespace, DNS_ANY);
if ($record === false) {
throw new \Exception("Failed to get DNS record for {$this->namespace}");
@@ -299,5 +335,4 @@
return false;
}
-*/
}
diff --git a/src/app/Entitlement.php b/src/app/Entitlement.php
--- a/src/app/Entitlement.php
+++ b/src/app/Entitlement.php
@@ -8,6 +8,11 @@
* The eloquent definition of an Entitlement.
*
* Owned by a {@link \App\User}, billed to a {@link \App\Wallet}.
+ *
+ * @property \App\User $owner The owner of this entitlement (subject).
+ * @property \App\Sku $sku The SKU to which this entitlement applies.
+ * @property \App\Wallet $wallet The wallet to which this entitlement is charged.
+ * @property \App\Domain|\App\User $entitleable The entitled object (receiver of the entitlement).
*/
class Entitlement extends Model
{
@@ -40,7 +45,7 @@
];
/**
- * Principally entitleable objects such as 'Domain' or 'Mailbox'.
+ * Principally entitleable objects such as 'Domain' or 'User'.
*
* @return mixed
*/
@@ -52,7 +57,7 @@
/**
* The SKU concerned.
*
- * @return Sku
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function sku()
{
@@ -62,7 +67,7 @@
/**
* The owner of this entitlement.
*
- * @return User
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function owner()
{
@@ -72,7 +77,7 @@
/**
* The wallet this entitlement is being billed to
*
- * @return Wallet
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function wallet()
{
diff --git a/src/app/Handlers/Base.php b/src/app/Handlers/Base.php
new file mode 100644
--- /dev/null
+++ b/src/app/Handlers/Base.php
@@ -0,0 +1,29 @@
+sku_id)->active) {
+ if (!$entitlement->sku->active) {
\Log::error("Sku not active");
return false;
}
diff --git a/src/app/Handlers/DomainHosting.php b/src/app/Handlers/DomainHosting.php
--- a/src/app/Handlers/DomainHosting.php
+++ b/src/app/Handlers/DomainHosting.php
@@ -4,7 +4,7 @@
use App\Sku;
-class DomainHosting
+class DomainHosting extends \App\Handlers\Base
{
public static function entitleableClass()
{
@@ -13,7 +13,7 @@
public static function preReq($entitlement, $domain)
{
- if (!Sku::find($entitlement->sku_id)->active) {
+ if (!$entitlement->sku->active) {
\Log::error("Sku not active");
return false;
}
diff --git a/src/app/Handlers/DomainRegistration.php b/src/app/Handlers/DomainRegistration.php
--- a/src/app/Handlers/DomainRegistration.php
+++ b/src/app/Handlers/DomainRegistration.php
@@ -4,7 +4,7 @@
use App\Sku;
-class DomainRegistration
+class DomainRegistration extends \App\Handlers\Base
{
public static function entitleableClass()
{
@@ -13,7 +13,7 @@
public static function preReq($entitlement, $domain)
{
- if (!Sku::find($entitlement->sku_id)->active) {
+ if (!$entitlement->sku->active) {
\Log::error("Sku not active");
return false;
}
diff --git a/src/app/Handlers/Groupware.php b/src/app/Handlers/Groupware.php
--- a/src/app/Handlers/Groupware.php
+++ b/src/app/Handlers/Groupware.php
@@ -4,7 +4,7 @@
use App\Sku;
-class Groupware
+class Groupware extends \App\Handlers\Base
{
public static function entitleableClass()
{
@@ -13,7 +13,7 @@
public static function preReq($entitlement, $user)
{
- if (!Sku::find($entitlement->sku_id)->active) {
+ if (!$entitlement->sku->active) {
\Log::error("Sku not active");
return false;
}
diff --git a/src/app/Handlers/Mailbox.php b/src/app/Handlers/Mailbox.php
--- a/src/app/Handlers/Mailbox.php
+++ b/src/app/Handlers/Mailbox.php
@@ -6,16 +6,16 @@
use App\Sku;
use App\User;
-class Mailbox
+class Mailbox extends \App\Handlers\Base
{
public static function entitleableClass()
{
return \App\User::class;
}
- public static function preReq(Entitlement $entitlement, User $user)
+ public static function preReq($entitlement, $user)
{
- if (!Sku::find($entitlement->sku_id)->active) {
+ if (!$entitlement->sku->active) {
\Log::error("Sku not active");
return false;
}
diff --git a/src/app/Handlers/Resource.php b/src/app/Handlers/Resource.php
--- a/src/app/Handlers/Resource.php
+++ b/src/app/Handlers/Resource.php
@@ -4,7 +4,7 @@
use App\Sku;
-class Resource
+class Resource extends \App\Handlers\Base
{
public static function entitleableClass()
{
@@ -13,7 +13,7 @@
public static function preReq($entitlement, $owner)
{
- if (!Sku::find($entitlement->sku_id)->active) {
+ if (!$entitlement->sku->active) {
\Log::error("Sku not active");
return false;
}
diff --git a/src/app/Handlers/SharedFolder.php b/src/app/Handlers/SharedFolder.php
--- a/src/app/Handlers/SharedFolder.php
+++ b/src/app/Handlers/SharedFolder.php
@@ -4,7 +4,7 @@
use App\Sku;
-class SharedFolder
+class SharedFolder extends \App\Handlers\Base
{
public static function entitleableClass()
{
@@ -13,7 +13,7 @@
public static function preReq($entitlement, $owner)
{
- if (!Sku::find($entitlement->sku_id)->active) {
+ if (!$entitlement->sku->active) {
\Log::error("Sku not active");
return false;
}
diff --git a/src/app/Handlers/Storage.php b/src/app/Handlers/Storage.php
--- a/src/app/Handlers/Storage.php
+++ b/src/app/Handlers/Storage.php
@@ -2,32 +2,16 @@
namespace App\Handlers;
-use App\Quota;
-use App\Sku;
-use App\User;
-
-class Storage
+class Storage extends \App\Handlers\Base
{
- public static function createDefaultEntitleable(User $user)
- {
- $quota = new Quota();
- $quota->user_id = $user->id;
- $quota->save();
-
- return $quota->id;
- }
-
public static function entitleableClass()
{
- return Quota::class;
+ return null;
}
- public static function preReq($entitlement, $user)
+ public static function preReq($entitlement, $object)
{
- if (!Sku::find($entitlement->sku_id)->active) {
- \Log::error("Sku not active");
- return false;
- }
+ // TODO: The storage can not be modified to below what is already consumed.
return true;
}
diff --git a/src/app/Http/Controllers/API/DomainsController.php b/src/app/Http/Controllers/API/DomainsController.php
--- a/src/app/Http/Controllers/API/DomainsController.php
+++ b/src/app/Http/Controllers/API/DomainsController.php
@@ -12,7 +12,7 @@
/**
* Return a list of domains owned by the current user
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse
*/
public function index()
{
@@ -31,7 +31,7 @@
/**
* Show the form for creating a new resource.
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse
*/
public function create()
{
@@ -43,7 +43,7 @@
*
* @param int $id Domain identifier
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse|void
*/
public function confirm($id)
{
@@ -69,7 +69,7 @@
*
* @param int $id
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse
*/
public function destroy($id)
{
@@ -105,7 +105,7 @@
*
* @param int $id Domain identifier
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse|void
*/
public function show($id)
{
@@ -209,7 +209,7 @@
/**
* Check if the current user has access to the domain
*
- * @param \App\Domain Domain
+ * @param \App\Domain $domain The domain
*
* @return bool True if current user has access, False otherwise
*/
diff --git a/src/app/Http/Controllers/API/PasswordResetController.php b/src/app/Http/Controllers/API/PasswordResetController.php
--- a/src/app/Http/Controllers/API/PasswordResetController.php
+++ b/src/app/Http/Controllers/API/PasswordResetController.php
@@ -24,7 +24,7 @@
*
* Verifies user email, sends verification email message.
*
- * @param Illuminate\Http\Request HTTP request
+ * @param \Illuminate\Http\Request $request HTTP request
*
* @return \Illuminate\Http\JsonResponse JSON response
*/
@@ -63,7 +63,7 @@
/**
* Validation of the verification code.
*
- * @param Illuminate\Http\Request HTTP request
+ * @param \Illuminate\Http\Request $request HTTP request
*
* @return \Illuminate\Http\JsonResponse JSON response
*/
@@ -106,7 +106,7 @@
/**
* Password change
*
- * @param Illuminate\Http\Request HTTP request
+ * @param \Illuminate\Http\Request $request HTTP request
*
* @return \Illuminate\Http\JsonResponse JSON response
*/
diff --git a/src/app/Http/Controllers/API/SignupController.php b/src/app/Http/Controllers/API/SignupController.php
--- a/src/app/Http/Controllers/API/SignupController.php
+++ b/src/app/Http/Controllers/API/SignupController.php
@@ -29,7 +29,7 @@
/**
* Returns plans definitions for signup.
*
- * @param Illuminate\Http\Request HTTP request
+ * @param \Illuminate\Http\Request $request HTTP request
*
* @return \Illuminate\Http\JsonResponse JSON response
*/
@@ -55,7 +55,7 @@
* Verifies user name and email/phone, sends verification email/sms message.
* Returns the verification code.
*
- * @param Illuminate\Http\Request HTTP request
+ * @param \Illuminate\Http\Request $request HTTP request
*
* @return \Illuminate\Http\JsonResponse JSON response
*/
@@ -102,7 +102,7 @@
/**
* Validation of the verification code.
*
- * @param Illuminate\Http\Request HTTP request
+ * @param \Illuminate\Http\Request $request HTTP request
*
* @return \Illuminate\Http\JsonResponse JSON response
*/
@@ -153,7 +153,7 @@
/**
* Finishes the signup process by creating the user account.
*
- * @param Illuminate\Http\Request HTTP request
+ * @param \Illuminate\Http\Request $request HTTP request
*
* @return \Illuminate\Http\JsonResponse JSON response
*/
@@ -220,18 +220,10 @@
]);
}
- // Create SKUs (after domain)
- foreach ($plan->packages as $package) {
- foreach ($package->skus as $sku) {
- $sku->registerEntitlement($user, is_object($domain) ? [$domain] : []);
- }
- }
+ $user->assignPlan($plan, $domain);
// Save the external email and plan in user settings
- $user->setSettings([
- 'external_email' => $user_email,
- 'plan' => $plan->id,
- ]);
+ $user->setSetting('external_email', $user_email);
// Remove the verification code
$this->code->delete();
@@ -244,8 +236,8 @@
/**
* Checks if the input string is a valid email address or a phone number
*
- * @param string $email Email address or phone number
- * @param bool &$is_phone Will be set to True if the string is valid phone number
+ * @param string $input Email address or phone number
+ * @param bool $is_phone Will have been set to True if the string is valid phone number
*
* @return string Error message label on validation error
*/
@@ -297,7 +289,7 @@
/**
* Login (kolab identity) validation
*
- * @param string $email Login (local part of an email address)
+ * @param string $login Login (local part of an email address)
* @param string $domain Domain name
* @param bool $external Enables additional checks for domain part
*
diff --git a/src/app/Http/Controllers/API/UsersController.php b/src/app/Http/Controllers/API/UsersController.php
--- a/src/app/Http/Controllers/API/UsersController.php
+++ b/src/app/Http/Controllers/API/UsersController.php
@@ -46,7 +46,7 @@
*
* The user themself, and other user entitlements.
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse
*/
public function index()
{
@@ -157,11 +157,11 @@
}
/**
- * Display the specified resource.
+ * Display information on the user account specified by $id.
*
* @param int $id The account to show information for.
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse|void
*/
public function show($id)
{
@@ -171,25 +171,13 @@
return abort(403);
}
- $result = false;
-
- $user->entitlements()->each(
- function ($entitlement) {
- if ($entitlement->user_id == $id) {
- $result = true;
- }
- }
- );
-
- if ($user->id == $id) {
- $result = true;
- }
-
- if (!$result) {
+ // TODO: check whether or not the user is allowed
+ // for now, only allow self.
+ if ($user->id != $id) {
return abort(404);
}
- return \App\User::find($id);
+ return response()->json($user);
}
/**
diff --git a/src/app/Jobs/UserDelete.php b/src/app/Jobs/DomainDelete.php
copy from src/app/Jobs/UserDelete.php
copy to src/app/Jobs/DomainDelete.php
--- a/src/app/Jobs/UserDelete.php
+++ b/src/app/Jobs/DomainDelete.php
@@ -2,20 +2,22 @@
namespace App\Jobs;
+use App\Backends\LDAP;
+use App\Domain;
use Illuminate\Bus\Queueable;
-use Illuminate\Queue\SerializesModels;
-use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+use Illuminate\Queue\InteractsWithQueue;
-class UserDelete implements ShouldQueue
+class DomainDelete implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
- protected $user;
+ protected $domain;
public $tries = 5;
@@ -25,13 +27,13 @@
/**
* Create a new job instance.
*
- * @param \App\User $user The user to delete.
+ * @param Domain $domain The domain to delete.
*
* @return void
*/
- public function __construct(\App\User $user)
+ public function __construct(Domain $domain)
{
- $this->user = $user;
+ $this->domain = $domain;
}
/**
@@ -41,6 +43,6 @@
*/
public function handle()
{
- //
+ LDAP::deleteDomain($this->domain);
}
}
diff --git a/src/app/Jobs/UserDelete.php b/src/app/Jobs/UserDelete.php
--- a/src/app/Jobs/UserDelete.php
+++ b/src/app/Jobs/UserDelete.php
@@ -2,6 +2,8 @@
namespace App\Jobs;
+use App\Backends\LDAP;
+use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
@@ -25,13 +27,13 @@
/**
* Create a new job instance.
*
- * @param \App\User $user The user to delete.
+ * @param int $user_id The ID of the user to delete.
*
* @return void
*/
- public function __construct(\App\User $user)
+ public function __construct(int $user_id)
{
- $this->user = $user;
+ $this->user = User::withTrashed()->find($user_id);
}
/**
@@ -41,6 +43,6 @@
*/
public function handle()
{
- //
+ LDAP::deleteUser($this->user);
}
}
diff --git a/src/app/Mail/PasswordReset.php b/src/app/Mail/PasswordReset.php
--- a/src/app/Mail/PasswordReset.php
+++ b/src/app/Mail/PasswordReset.php
@@ -19,7 +19,7 @@
/**
* Create a new message instance.
*
- * @param \App\VerificationCode A verification code object
+ * @param \App\VerificationCode $code A verification code object
*
* @return void
*/
diff --git a/src/app/Observers/DomainObserver.php b/src/app/Observers/DomainObserver.php
--- a/src/app/Observers/DomainObserver.php
+++ b/src/app/Observers/DomainObserver.php
@@ -36,16 +36,14 @@
public function created(Domain $domain)
{
// Create domain record in LDAP, then check if it exists in DNS
-/*
- $chain = [
- new \App\Jobs\DomainVerify($domain),
- ];
-
- \App\Jobs\DomainCreate::withChain($chain)->dispatch($domain);
-*/
\App\Jobs\DomainCreate::dispatch($domain);
}
+ public function deleting(Domain $domain)
+ {
+ //
+ }
+
/**
* Handle the domain "updated" event.
*
@@ -67,7 +65,7 @@
*/
public function deleted(Domain $domain)
{
- //
+ \App\Jobs\DomainDelete::dispatch($domain);
}
/**
diff --git a/src/app/Observers/EntitlementObserver.php b/src/app/Observers/EntitlementObserver.php
--- a/src/app/Observers/EntitlementObserver.php
+++ b/src/app/Observers/EntitlementObserver.php
@@ -19,7 +19,7 @@
*
* @param Entitlement $entitlement The entitlement being created.
*
- * @return void
+ * @return bool|null
*/
public function creating(Entitlement $entitlement)
{
diff --git a/src/app/Observers/UserObserver.php b/src/app/Observers/UserObserver.php
--- a/src/app/Observers/UserObserver.php
+++ b/src/app/Observers/UserObserver.php
@@ -65,6 +65,11 @@
\App\Jobs\UserCreate::withChain($chain)->dispatch($user);
}
+ public function deleted(User $user)
+ {
+ //
+ }
+
/**
* Handle the "deleting" event.
*
@@ -74,7 +79,16 @@
*/
public function deleting(User $user)
{
- // TODO \App\Jobs\UserDelete::dispatch($user);
+ // Entitlements do not have referential integrity on the entitled object, so this is our
+ // way of doing an onDelete('cascade') without the foreign key.
+ $entitlements = \App\Entitlement::where('entitleable_id', $user->id)
+ ->where('entitleable_type', \App\User::class)->get();
+
+ foreach ($entitlements as $entitlement) {
+ $entitlement->delete();
+ }
+
+ \App\Jobs\UserDelete::dispatch($user->id);
}
/**
@@ -88,7 +102,7 @@
*/
public function retrieving(User $user)
{
- // TODO \App\Jobs\UserRead::dispatch($user);
+ // TODO \App\Jobs\UserRead::dispatch($user);
}
/**
diff --git a/src/app/Package.php b/src/app/Package.php
--- a/src/app/Package.php
+++ b/src/app/Package.php
@@ -45,6 +45,17 @@
return $costs;
}
+ public function isDomain()
+ {
+ foreach ($this->skus as $sku) {
+ if ($sku->hander_class::entitleableClass() == \App\Domain::class) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public function skus()
{
return $this->belongsToMany(
diff --git a/src/app/PackageSku.php b/src/app/PackageSku.php
--- a/src/app/PackageSku.php
+++ b/src/app/PackageSku.php
@@ -4,6 +4,9 @@
use Illuminate\Database\Eloquent\Relations\Pivot;
+/**
+ * Link SKUs to Packages.
+ */
class PackageSku extends Pivot
{
protected $fillable = [
diff --git a/src/app/Plan.php b/src/app/Plan.php
--- a/src/app/Plan.php
+++ b/src/app/Plan.php
@@ -3,6 +3,7 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
+use Spatie\Translatable\HasTranslations;
/**
* The eloquent definition of a Plan.
@@ -11,10 +12,12 @@
*
* A "Family Plan" as such may exist of "2 or more Kolab packages",
* and apply a discount for the third and further Kolab packages.
+ *
+ * @property \App\Package[] $packages
*/
class Plan extends Model
{
- use \Spatie\Translatable\HasTranslations;
+ use HasTranslations;
public $incrementing = false;
protected $keyType = 'string';
@@ -58,6 +61,15 @@
return $costs;
}
+ /**
+ * The relationship to packages.
+ *
+ * The plan contains one or more packages. Each package may have its minimum number (for
+ * billing) or its maximum (to allow topping out "enterprise" customers on a "small business"
+ * plan).
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
+ */
public function packages()
{
return $this->belongsToMany(
@@ -65,6 +77,7 @@
'plan_packages'
)->using('App\PlanPackage')->withPivot(
[
+ 'qty',
'qty_min',
'qty_max',
'discount_qty',
@@ -74,15 +87,15 @@
}
/**
- * Checks if the plan has domain SKU assigned
+ * Checks if the plan has any type of domain SKU assigned.
+ *
+ * @return bool
*/
public function hasDomain(): bool
{
foreach ($this->packages as $package) {
- foreach ($package->skus as $sku) {
- if ($sku->handler_class::entitleableClass() == \App\Domain::class) {
- return true;
- }
+ if ($package->isDomain()) {
+ return true;
}
}
diff --git a/src/app/PlanPackage.php b/src/app/PlanPackage.php
--- a/src/app/PlanPackage.php
+++ b/src/app/PlanPackage.php
@@ -4,6 +4,12 @@
use Illuminate\Database\Eloquent\Relations\Pivot;
+/**
+ * Link Packages to Plans.
+ *
+ * @property integer $qty_min
+ * @property \App\Package $package
+ */
class PlanPackage extends Pivot
{
protected $fillable = [
@@ -24,16 +30,26 @@
'discount_rate' => 'integer'
];
+ /**
+ * Calculate the costs for this plan.
+ *
+ * @return integer
+ */
public function cost()
{
$costs = 0;
if ($this->qty_min > 0) {
- foreach ($this->package->skus() as $sku) {
- $costs += $sku->cost;
- }
+ $costs += $this->package->cost() * $this->qty_min;
+ } elseif ($this->qty > 0) {
+ $costs += $this->package->cost() * $this->qty;
}
return $costs;
}
+
+ public function package()
+ {
+ return $this->belongsTo('App\Package');
+ }
}
diff --git a/src/app/Quota.php b/src/app/Quota.php
deleted file mode 100644
--- a/src/app/Quota.php
+++ /dev/null
@@ -1,29 +0,0 @@
- 'int',
- ];
-
- public function entitlement()
- {
- return $this->morphOne('App\Entitlement', 'entitleable');
- }
-
- /**
- * The owner of this quota entry
- *
- * @return \App\User
- */
- public function user()
- {
- return $this->belongsTo('App\User', 'user_id', 'id');
- }
-}
diff --git a/src/app/SignupCode.php b/src/app/SignupCode.php
--- a/src/app/SignupCode.php
+++ b/src/app/SignupCode.php
@@ -7,6 +7,8 @@
/**
* The eloquent definition of a SignupCode.
+ *
+ * @property datetime $expires_at
*/
class SignupCode extends Model
{
diff --git a/src/app/Sku.php b/src/app/Sku.php
--- a/src/app/Sku.php
+++ b/src/app/Sku.php
@@ -29,7 +29,7 @@
/**
* List the entitlements that consume this SKU.
*
- * @return Entitlement[]
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function entitlements()
{
@@ -43,48 +43,4 @@
'package_skus'
)->using('App\PackageSku')->withPivot(['qty']);
}
-
- /**
- * Register (default) SKU entitlement for specified user.
- * This method should be used e.g. on user creation when we have
- * a set of SKUs and want to create entitlements for them (using
- * default values).
- */
- public function registerEntitlement(\App\User $user, array $params = [])
- {
- if (!$this->active) {
- \Log::debug("Skipped registration of an entitlement for non-active SKU ($this->title)");
- return;
- }
-
- $wallet = $user->wallets()->get()[0];
-
- $entitlement = new \App\Entitlement();
- $entitlement->owner_id = $user->id;
- $entitlement->wallet_id = $wallet->id;
- $entitlement->sku_id = $this->id;
-
- $entitlement->entitleable_type = $this->handler_class::entitleableClass();
-
- if ($user instanceof $entitlement->entitleable_type) {
- $entitlement->entitleable_id = $user->id;
- } else {
- foreach ($params as $param) {
- if ($param instanceof $entitlement->entitleable_type) {
- $entitlement->entitleable_id = $param->id;
- break;
- }
- }
- }
-
- if (empty($entitlement->entitleable_id)) {
- if (method_exists($this->handler_class, 'createDefaultEntitleable')) {
- $entitlement->entitleable_id = $this->handler_class::createDefaultEntitleable($user);
- } else {
- throw new Exception("Failed to create an entitlement for SKU ($this->title). Missing entitleable_id.");
- }
- }
-
- $entitlement->save();
- }
}
diff --git a/src/app/User.php b/src/app/User.php
--- a/src/app/User.php
+++ b/src/app/User.php
@@ -4,6 +4,7 @@
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
+use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Iatstuti\Database\Support\NullableFields;
use Tymon\JWTAuth\Contracts\JWTSubject;
@@ -11,12 +12,16 @@
/**
* The eloquent definition of a User.
+ *
+ * @property integer $id
+ * @property integer $status
*/
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
use NullableFields;
use UserSettingsTrait;
+ use SoftDeletes;
// a new user, default on creation
public const STATUS_NEW = 1 << 0;
@@ -78,26 +83,72 @@
/**
* Any wallets on which this user is a controller.
*
- * @return Wallet[]
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function accounts()
{
return $this->belongsToMany(
'App\Wallet', // The foreign object definition
'user_accounts', // The table name
- 'user_id', // The local foreign key
- 'wallet_id' // The remote foreign key
+ 'user_id', // The local foreign key
+ 'wallet_id' // The remote foreign key
);
}
/**
+ * Assign a package to a user. The user should not have any existing entitlements.
+ *
+ * @param \App\Package $package The package to assign.
+ * @param \App\User|null $user Assign the package to another user.
+ *
+ * @return \App\User
+ */
+ public function assignPackage($package, $user = null)
+ {
+ if (!$user) {
+ $user = $this;
+ }
+
+ $wallet_id = $this->wallets()->get()[0]->id;
+
+ foreach ($package->skus as $sku) {
+ for ($i = $sku->pivot->qty; $i > 0; $i--) {
+ \App\Entitlement::create(
+ [
+ 'owner_id' => $this->id,
+ 'wallet_id' => $wallet_id,
+ 'sku_id' => $sku->id,
+ 'entitleable_id' => $user->id,
+ 'entitleable_type' => User::class
+ ]
+ );
+ }
+ }
+
+ return $user;
+ }
+
+ public function assignPlan($plan, $domain = null)
+ {
+ $this->setSetting('plan_id', $plan->id);
+
+ foreach ($plan->packages as $package) {
+ if ($package->isDomain()) {
+ $domain->assignPackage($package, $this);
+ } else {
+ $this->assignPackage($package);
+ }
+ }
+ }
+
+ /**
* List the domains to which this user is entitled.
*
* @return Domain[]
*/
public function domains()
{
- $domains = Domain::whereRaw(
+ $dbdomains = Domain::whereRaw(
sprintf(
'(type & %s) AND (status & %s)',
Domain::TYPE_PUBLIC,
@@ -105,19 +156,27 @@
)
)->get();
- foreach ($this->entitlements()->get() as $entitlement) {
+ $domains = [];
+
+ foreach ($dbdomains as $dbdomain) {
+ $domains[] = $dbdomain;
+ }
+
+ $entitlements = Entitlement::where('owner_id', $this->id)->get();
+
+ foreach ($entitlements as $entitlement) {
if ($entitlement->entitleable instanceof Domain) {
- $domain = Domain::find($entitlement->entitleable_id);
- \Log::info("Found domain {$domain->namespace}");
+ $domain = $entitlement->entitleable;
+ \Log::info("Found domain for {$this->email}: {$domain->namespace} (owned)");
$domains[] = $domain;
}
}
- foreach ($this->accounts()->get() as $wallet) {
- foreach ($wallet->entitlements()->get() as $entitlement) {
+ foreach ($this->accounts as $wallet) {
+ foreach ($wallet->entitlements as $entitlement) {
if ($entitlement->entitleable instanceof Domain) {
- $domain = Domain::find($entitlement->entitleable_id);
- \Log::info("Found domain {$domain->namespace}");
+ $domain = $entitlement->entitleable;
+ \Log::info("Found domain {$this->email}: {$domain->namespace} (charged)");
$domains[] = $domain;
}
}
@@ -134,17 +193,19 @@
/**
* Entitlements for this user.
*
- * @return Entitlement[]
+ * Note that these are entitlements that apply to the user account, and not entitlements that
+ * this user owns.
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function entitlements()
{
- return $this->hasMany('App\Entitlement', 'owner_id', 'id');
+ return $this->hasMany('App\Entitlement', 'entitleable_id', 'id');
}
public function addEntitlement($entitlement)
{
- // FIXME: This contains() check looks fishy
- if (!$this->entitlements()->get()->contains($entitlement)) {
+ if (!$this->entitlements->contains($entitlement)) {
return $this->entitlements()->save($entitlement);
}
}
@@ -187,7 +248,7 @@
*/
public function isActive(): bool
{
- return $this->status & self::STATUS_ACTIVE;
+ return ($this->status & self::STATUS_ACTIVE) == true;
}
/**
@@ -197,7 +258,7 @@
*/
public function isDeleted(): bool
{
- return $this->status & self::STATUS_DELETED;
+ return ($this->status & self::STATUS_DELETED) == true;
}
/**
@@ -208,7 +269,7 @@
*/
public function isImapReady(): bool
{
- return $this->status & self::STATUS_IMAP_READY;
+ return ($this->status & self::STATUS_IMAP_READY) == true;
}
/**
@@ -218,7 +279,7 @@
*/
public function isLdapReady(): bool
{
- return $this->status & self::STATUS_LDAP_READY;
+ return ($this->status & self::STATUS_LDAP_READY) == true;
}
/**
@@ -228,7 +289,7 @@
*/
public function isNew(): bool
{
- return $this->status & self::STATUS_NEW;
+ return ($this->status & self::STATUS_NEW) == true;
}
/**
@@ -238,13 +299,13 @@
*/
public function isSuspended(): bool
{
- return $this->status & self::STATUS_SUSPENDED;
+ return ($this->status & self::STATUS_SUSPENDED) == true;
}
/**
* Any (additional) properties of this user.
*
- * @return \App\UserSetting[]
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function settings()
{
@@ -254,7 +315,7 @@
/**
* Verification codes for this user.
*
- * @return VerificationCode[]
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function verificationcodes()
{
@@ -264,13 +325,20 @@
/**
* Wallets this user owns.
*
- * @return Wallet[]
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function wallets()
{
return $this->hasMany('App\Wallet');
}
+ /**
+ * User password mutator
+ *
+ * @param string $password The password in plain text.
+ *
+ * @return void
+ */
public function setPasswordAttribute($password)
{
if (!empty($password)) {
@@ -281,6 +349,13 @@
}
}
+ /**
+ * User LDAP password mutator
+ *
+ * @param string $password The password in plain text.
+ *
+ * @return void
+ */
public function setPasswordLdapAttribute($password)
{
if (!empty($password)) {
diff --git a/src/app/UserSetting.php b/src/app/UserSetting.php
--- a/src/app/UserSetting.php
+++ b/src/app/UserSetting.php
@@ -21,10 +21,14 @@
/**
* The user to which this setting belongs.
*
- * @return \App\User
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
- return $this->belongsTo('\App\User', 'user_id' /* local */, 'id' /* remote */);
+ return $this->belongsTo(
+ '\App\User',
+ 'user_id', /* local */
+ 'id' /* remote */
+ );
}
}
diff --git a/src/app/Utils.php b/src/app/Utils.php
--- a/src/app/Utils.php
+++ b/src/app/Utils.php
@@ -49,7 +49,7 @@
*/
public static function uuidStr(): string
{
- return (string) Uuid::uuid4();
+ return Uuid::uuid4()->toString();
}
private static function combine($input, $r, $index, $data, $i, &$output): void
diff --git a/src/app/VerificationCode.php b/src/app/VerificationCode.php
--- a/src/app/VerificationCode.php
+++ b/src/app/VerificationCode.php
@@ -33,7 +33,7 @@
/**
* The user to which this setting belongs.
*
- * @return \App\User
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
diff --git a/src/app/Wallet.php b/src/app/Wallet.php
--- a/src/app/Wallet.php
+++ b/src/app/Wallet.php
@@ -10,16 +10,13 @@
* The eloquent definition of a wallet -- a container with a chunk of change.
*
* A wallet is owned by an {@link \App\User}.
+ *
+ * @property integer $balance
*/
class Wallet extends Model
{
use NullableFields;
- /**
- Our table name for the shall be 'wallet'.
-
- @var string
- */
public $incrementing = false;
protected $keyType = 'string';
@@ -53,7 +50,7 @@
*/
public function addController(User $user)
{
- if (!$this->controllers()->get()->contains($user)) {
+ if (!$this->controllers->contains($user)) {
$this->controllers()->save($user);
}
}
@@ -67,7 +64,7 @@
*/
public function removeController(User $user)
{
- if ($this->controllers()->get()->contains($user)) {
+ if ($this->controllers->contains($user)) {
$this->controllers()->detach($user);
}
}
@@ -107,7 +104,7 @@
/**
* Controllers of this wallet.
*
- * @return \App\User[]
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function controllers()
{
@@ -122,7 +119,7 @@
/**
* Entitlements billed to this wallet.
*
- * @return Entitlement[]
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function entitlements()
{
@@ -132,7 +129,7 @@
/**
* The owner of the wallet -- the wallet is in his/her back pocket.
*
- * @return User
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function owner()
{
diff --git a/src/composer.json b/src/composer.json
--- a/src/composer.json
+++ b/src/composer.json
@@ -37,6 +37,8 @@
"laravel/dusk": "~5.9.1",
"mockery/mockery": "^1.0",
"nunomaduro/collision": "^3.0",
+ "nunomaduro/larastan": "^0.4",
+ "phpstan/phpstan": "0.11.19",
"phpunit/phpunit": "^7.5"
},
"config": {
diff --git a/src/config/imap.php b/src/config/imap.php
--- a/src/config/imap.php
+++ b/src/config/imap.php
@@ -5,6 +5,5 @@
'admin_login' => env('IMAP_ADMIN_LOGIN', 'cyrus-admin'),
'admin_password' => env('IMAP_ADMIN_PASSWORD', null),
'verify_peer' => env('IMAP_VERIFY_PEER', true),
- 'verify_name' => env('IMAP_VERIFY_NAME', true),
- 'cafile' => env('IMAP_CAFILE', null),
+ 'verify_host' => env('IMAP_VERIFY_HOST', true)
];
diff --git a/src/database/migrations/2019_10_10_095050_create_quota_table.php b/src/database/migrations/2019_10_10_095050_create_quota_table.php
--- a/src/database/migrations/2019_10_10_095050_create_quota_table.php
+++ b/src/database/migrations/2019_10_10_095050_create_quota_table.php
@@ -13,6 +13,7 @@
*/
public function up()
{
+ /*
Schema::create('quotas', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id');
@@ -21,6 +22,7 @@
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
+ */
}
/**
diff --git a/src/database/migrations/2019_12_10_105942_create_plan_packages_table.php b/src/database/migrations/2019_12_10_105942_create_plan_packages_table.php
--- a/src/database/migrations/2019_12_10_105942_create_plan_packages_table.php
+++ b/src/database/migrations/2019_12_10_105942_create_plan_packages_table.php
@@ -20,6 +20,7 @@
$table->string('plan_id', 36);
$table->string('package_id', 36);
+ $table->integer('qty')->default(1);
$table->integer('qty_min')->default(0);
$table->integer('qty_max')->default(0);
diff --git a/src/database/migrations/2020_02_11_110959_add_deleted_at.php b/src/database/migrations/2020_02_11_110959_add_deleted_at.php
new file mode 100644
--- /dev/null
+++ b/src/database/migrations/2020_02_11_110959_add_deleted_at.php
@@ -0,0 +1,51 @@
+softDeletes();
+ }
+ );
+
+ Schema::table(
+ 'users',
+ function (Blueprint $table) {
+ $table->softDeletes();
+ }
+ );
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table(
+ 'domains',
+ function (Blueprint $table) {
+ $table->dropColumn(['deleted_at']);
+ }
+ );
+ Schema::table(
+ 'users',
+ function (Blueprint $table) {
+ $table->dropColumn(['deleted_at']);
+ }
+ );
+ }
+}
diff --git a/src/database/seeds/DatabaseSeeder.php b/src/database/seeds/DatabaseSeeder.php
--- a/src/database/seeds/DatabaseSeeder.php
+++ b/src/database/seeds/DatabaseSeeder.php
@@ -15,9 +15,9 @@
[
DomainSeeder::class,
SkuSeeder::class,
- UserSeeder::class,
PackageSeeder::class,
- PlanSeeder::class
+ PlanSeeder::class,
+ UserSeeder::class
]
);
}
diff --git a/src/database/seeds/DomainSeeder.php b/src/database/seeds/DomainSeeder.php
--- a/src/database/seeds/DomainSeeder.php
+++ b/src/database/seeds/DomainSeeder.php
@@ -35,5 +35,21 @@
]
);
}
+
+ $domains = [
+ 'example.com',
+ 'example.net',
+ 'example.org'
+ ];
+
+ foreach ($domains as $domain) {
+ Domain::create(
+ [
+ 'namespace' => $domain,
+ 'status' => Domain::STATUS_CONFIRMED + Domain::STATUS_ACTIVE,
+ 'type' => Domain::TYPE_EXTERNAL
+ ]
+ );
+ }
}
}
diff --git a/src/database/seeds/PlanSeeder.php b/src/database/seeds/PlanSeeder.php
--- a/src/database/seeds/PlanSeeder.php
+++ b/src/database/seeds/PlanSeeder.php
@@ -159,8 +159,8 @@
);
$packages = [
- Package::firstOrCreate(['title' => 'kolab']),
Package::firstOrCreate(['title' => 'domain-hosting']),
+ Package::firstOrCreate(['title' => 'kolab']),
];
$plan->packages()->saveMany($packages);
diff --git a/src/database/seeds/UserSeeder.php b/src/database/seeds/UserSeeder.php
--- a/src/database/seeds/UserSeeder.php
+++ b/src/database/seeds/UserSeeder.php
@@ -19,12 +19,12 @@
$domain = Domain::create(
[
'namespace' => 'kolab.org',
- 'status' => Domain::STATUS_NEW + Domain::STATUS_ACTIVE + Domain::STATUS_CONFIRMED,
+ 'status' => Domain::STATUS_NEW + Domain::STATUS_ACTIVE + Domain::STATUS_CONFIRMED + Domain::STATUS_VERIFIED,
'type' => Domain::TYPE_EXTERNAL
]
);
- $user = User::create(
+ $john = User::create(
[
'name' => "John Doe",
'email' => 'john@kolab.org',
@@ -33,38 +33,43 @@
]
);
- $user_wallets = $user->wallets()->get();
-
- $sku_domain = Sku::where('title', 'domain')->first();
- $sku_mailbox = Sku::where('title', 'mailbox')->first();
-
- $entitlement_domain = Entitlement::create(
+ $john->setSettings(
[
- 'owner_id' => $user->id,
- 'wallet_id' => $user_wallets[0]->id,
- 'sku_id' => $sku_domain->id,
- 'entitleable_id' => $domain->id,
- 'entitleable_type' => Domain::class
+ "first_name" => "John",
+ "last_name" => "Doe",
+ "currency" => "USD",
+ "country" => "US"
]
);
- $entitlement_mailbox = Entitlement::create(
+ $user_wallets = $john->wallets()->get();
+
+ $package_domain = \App\Package::where('title', 'domain-hosting')->first();
+ $package_kolab = \App\Package::where('title', 'kolab')->first();
+
+ $domain->assignPackage($package_domain, $john);
+ $john->assignPackage($package_kolab);
+
+ $jack = User::create(
[
- 'owner_id' => $user->id,
- 'wallet_id' => $user_wallets[0]->id,
- 'sku_id' => $sku_mailbox->id,
- 'entitleable_id' => $user->id,
- 'entitleable_type' => User::class
+ 'name' => "Jack Daniels",
+ 'email' => 'jack@kolab.org',
+ 'password' => 'simple123',
+ 'email_verified_at' => now()
]
);
- $user->setSettings(
+ $jack->setSettings(
[
- "first_name" => "John",
- "last_name" => "Doe",
+ "first_name" => "Jack",
+ "last_name" => "Daniels",
"currency" => "USD",
"country" => "US"
]
);
+
+ $john->assignPackage($package_kolab, $jack);
+
+ factory(User::class, 10)->create();
}
}
diff --git a/src/package-lock.json b/src/package-lock.json
--- a/src/package-lock.json
+++ b/src/package-lock.json
@@ -855,6 +855,12 @@
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
"dev": true
},
+ "@types/color-name": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
+ "dev": true
+ },
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
@@ -884,12 +890,44 @@
"integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==",
"dev": true
},
+ "@types/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+ "dev": true
+ },
"@types/q": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==",
"dev": true
},
+ "@types/unist": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
+ "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==",
+ "dev": true
+ },
+ "@types/vfile": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/vfile/-/vfile-3.0.2.tgz",
+ "integrity": "sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "@types/unist": "*",
+ "@types/vfile-message": "*"
+ }
+ },
+ "@types/vfile-message": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-2.0.0.tgz",
+ "integrity": "sha512-GpTIuDpb9u4zIO165fUy9+fXcULdD8HFRNli04GehoMVbeNq7D6OBnqSmg3lxZnC+UvgUhEWKxdKiwYUkGltIw==",
+ "dev": true,
+ "requires": {
+ "vfile-message": "*"
+ }
+ },
"@vue/component-compiler-utils": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.0.0.tgz",
@@ -1135,6 +1173,12 @@
"integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
"dev": true
},
+ "acorn-jsx": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz",
+ "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==",
+ "dev": true
+ },
"adjust-sourcemap-loader": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-1.2.0.tgz",
@@ -1217,6 +1261,15 @@
"integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
"dev": true
},
+ "ansi-escapes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz",
+ "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.8.1"
+ }
+ },
"ansi-html": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
@@ -1292,6 +1345,12 @@
"integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
"dev": true
},
+ "array-find-index": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+ "dev": true
+ },
"array-flatten": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
@@ -1375,6 +1434,12 @@
"integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=",
"dev": true
},
+ "astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+ "dev": true
+ },
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
@@ -1503,6 +1568,12 @@
"object.assign": "^4.1.0"
}
},
+ "bail": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+ "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+ "dev": true
+ },
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -1656,9 +1727,9 @@
"dev": true
},
"bootstrap": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz",
- "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.4.1.tgz",
+ "integrity": "sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==",
"dev": true
},
"brace-expansion": {
@@ -1921,6 +1992,25 @@
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
+ "camelcase-keys": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz",
+ "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=",
+ "dev": true,
+ "requires": {
+ "camelcase": "^4.1.0",
+ "map-obj": "^2.0.0",
+ "quick-lru": "^1.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+ "dev": true
+ }
+ }
+ },
"caniuse-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@@ -1939,6 +2029,12 @@
"integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==",
"dev": true
},
+ "ccount": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz",
+ "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==",
+ "dev": true
+ },
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -1950,6 +2046,36 @@
"supports-color": "^5.3.0"
}
},
+ "character-entities": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+ "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+ "dev": true
+ },
+ "character-entities-html4": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+ "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
+ "dev": true
+ },
+ "character-entities-legacy": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+ "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+ "dev": true
+ },
+ "character-reference-invalid": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+ "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+ "dev": true
+ },
+ "chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
+ },
"charenc": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
@@ -2041,6 +2167,21 @@
}
}
},
+ "cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^3.1.0"
+ }
+ },
+ "cli-width": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+ "dev": true
+ },
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@@ -2091,6 +2232,15 @@
"shallow-clone": "^3.0.0"
}
},
+ "clone-regexp": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz",
+ "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==",
+ "dev": true,
+ "requires": {
+ "is-regexp": "^2.0.0"
+ }
+ },
"coa": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
@@ -2108,6 +2258,12 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true
},
+ "collapse-white-space": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+ "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
+ "dev": true
+ },
"collect.js": {
"version": "4.16.6",
"resolved": "https://registry.npmjs.org/collect.js/-/collect.js-4.16.6.tgz",
@@ -2721,6 +2877,15 @@
}
}
},
+ "currently-unhandled": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+ "dev": true,
+ "requires": {
+ "array-find-index": "^1.0.1"
+ }
+ },
"cyclist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
@@ -2754,6 +2919,24 @@
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
+ "decamelize-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+ "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=",
+ "dev": true,
+ "requires": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ },
+ "dependencies": {
+ "map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+ "dev": true
+ }
+ }
+ },
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
@@ -2774,6 +2957,12 @@
"regexp.prototype.flags": "^1.2.0"
}
},
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
+ },
"deepmerge": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz",
@@ -2958,6 +3147,15 @@
"buffer-indexof": "^1.0.0"
}
},
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
"dom-serializer": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.1.tgz",
@@ -2988,6 +3186,15 @@
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
"dev": true
},
+ "domhandler": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+ "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "1"
+ }
+ },
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
@@ -3180,6 +3387,149 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
+ "eslint": {
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz",
+ "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "ajv": "^6.10.0",
+ "chalk": "^2.1.0",
+ "cross-spawn": "^6.0.5",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^1.4.3",
+ "eslint-visitor-keys": "^1.1.0",
+ "espree": "^6.1.2",
+ "esquery": "^1.0.1",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^5.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.0.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^7.0.0",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.14",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.3",
+ "progress": "^2.0.0",
+ "regexpp": "^2.0.1",
+ "semver": "^6.1.2",
+ "strip-ansi": "^5.2.0",
+ "strip-json-comments": "^3.0.1",
+ "table": "^5.2.3",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "eslint-scope": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
+ "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
+ "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "globals": {
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz",
+ "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.8.1"
+ }
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
+ "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "eslint-plugin-vue": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-6.1.2.tgz",
+ "integrity": "sha512-M75oAB+2a/LNkLKRbeEaS07EjzjIUaV7/hYoHAfRFeeF8ZMmCbahUn8nQLsLP85mkar24+zDU3QW2iT1JRsACw==",
+ "dev": true,
+ "requires": {
+ "semver": "^5.6.0",
+ "vue-eslint-parser": "^7.0.0"
+ }
+ },
"eslint-scope": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
@@ -3190,12 +3540,55 @@
"estraverse": "^4.1.1"
}
},
+ "eslint-utils": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
+ "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
+ "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+ "dev": true
+ },
+ "espree": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz",
+ "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==",
+ "dev": true,
+ "requires": {
+ "acorn": "^7.1.0",
+ "acorn-jsx": "^5.1.0",
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
+ "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==",
+ "dev": true
+ }
+ }
+ },
"esprima": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
"integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
"dev": true
},
+ "esquery": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.1.0.tgz",
+ "integrity": "sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^4.0.0"
+ }
+ },
"esrecurse": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
@@ -3269,6 +3662,15 @@
"strip-eof": "^1.0.0"
}
},
+ "execall": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz",
+ "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==",
+ "dev": true,
+ "requires": {
+ "clone-regexp": "^2.1.0"
+ }
+ },
"expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@@ -3383,6 +3785,12 @@
}
}
},
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
"extend-shallow": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
@@ -3393,6 +3801,17 @@
"is-extendable": "^1.0.1"
}
},
+ "external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dev": true,
+ "requires": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ }
+ },
"extglob": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
@@ -3502,6 +3921,12 @@
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
"dev": true
},
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
"fastparse": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
@@ -3523,6 +3948,24 @@
"integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==",
"dev": true
},
+ "figures": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz",
+ "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-entry-cache": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+ "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^2.0.1"
+ }
+ },
"file-loader": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-2.0.0.tgz",
@@ -3639,6 +4082,34 @@
"resolve-dir": "^1.0.1"
}
},
+ "flat-cache": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+ "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+ "dev": true,
+ "requires": {
+ "flatted": "^2.0.0",
+ "rimraf": "2.6.3",
+ "write": "1.0.3"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "flatted": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
+ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
+ "dev": true
+ },
"flush-write-stream": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
@@ -4316,14 +4787,26 @@
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "dev": true
+ },
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
- "get-stream": {
- "version": "4.1.0",
+ "get-stdin": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz",
+ "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==",
+ "dev": true
+ },
+ "get-stream": {
+ "version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"dev": true,
@@ -4442,6 +4925,12 @@
}
}
},
+ "globjoin": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
+ "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=",
+ "dev": true
+ },
"globs": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/globs/-/globs-0.1.4.tgz",
@@ -4451,6 +4940,23 @@
"glob": "^7.1.1"
}
},
+ "gonzales-pe": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.2.4.tgz",
+ "integrity": "sha512-v0Ts/8IsSbh9n1OJRnSfa7Nlxi4AkXIsWB6vPept8FDbL4bXn3FNuxjYtO/nmBGu7GDkL9MFeGebeSu6l55EPQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "1.1.x"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz",
+ "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=",
+ "dev": true
+ }
+ }
+ },
"graceful-fs": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
@@ -4595,6 +5101,12 @@
"parse-passwd": "^1.0.0"
}
},
+ "hosted-git-info": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
+ "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
+ "dev": true
+ },
"hpack.js": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
@@ -4659,6 +5171,45 @@
"uglify-js": "3.4.x"
}
},
+ "html-tags": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
+ "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
+ "dev": true
+ },
+ "htmlparser2": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+ "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^1.3.1",
+ "domhandler": "^2.3.0",
+ "domutils": "^1.5.1",
+ "entities": "^1.1.1",
+ "inherits": "^2.0.1",
+ "readable-stream": "^3.1.1"
+ },
+ "dependencies": {
+ "entities": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz",
+ "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
"http-deceiver": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
@@ -4852,6 +5403,12 @@
"resolve-from": "^3.0.0"
}
},
+ "import-lazy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+ "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
+ "dev": true
+ },
"import-local": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
@@ -4868,6 +5425,12 @@
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
+ "indent-string": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
+ "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
+ "dev": true
+ },
"indexes-of": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
@@ -4902,6 +5465,86 @@
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true
},
+ "inquirer": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz",
+ "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^2.4.2",
+ "cli-cursor": "^3.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^3.0.0",
+ "lodash": "^4.17.15",
+ "mute-stream": "0.0.8",
+ "run-async": "^2.2.0",
+ "rxjs": "^6.5.3",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^5.1.0",
+ "through": "^2.3.6"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "dependencies": {
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ }
+ }
+ }
+ }
+ },
"internal-ip": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
@@ -4983,6 +5626,28 @@
}
}
},
+ "is-alphabetical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+ "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+ "dev": true
+ },
+ "is-alphanumeric": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz",
+ "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=",
+ "dev": true
+ },
+ "is-alphanumerical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+ "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+ "dev": true,
+ "requires": {
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0"
+ }
+ },
"is-arguments": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
@@ -5062,6 +5727,12 @@
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
"dev": true
},
+ "is-decimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+ "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+ "dev": true
+ },
"is-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
@@ -5117,6 +5788,12 @@
"is-extglob": "^2.1.1"
}
},
+ "is-hexadecimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+ "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+ "dev": true
+ },
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
@@ -5173,6 +5850,12 @@
"path-is-inside": "^1.0.2"
}
},
+ "is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+ "dev": true
+ },
"is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@@ -5182,6 +5865,12 @@
"isobject": "^3.0.1"
}
},
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+ "dev": true
+ },
"is-regex": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
@@ -5191,6 +5880,12 @@
"has": "^1.0.1"
}
},
+ "is-regexp": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz",
+ "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==",
+ "dev": true
+ },
"is-resolvable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
@@ -5221,12 +5916,30 @@
"has-symbols": "^1.0.0"
}
},
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "is-whitespace-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
+ "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
+ "dev": true
+ },
"is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
"dev": true
},
+ "is-word-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
+ "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
+ "dev": true
+ },
"is-wsl": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
@@ -5305,6 +6018,12 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
"json3": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
@@ -5341,6 +6060,12 @@
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"dev": true
},
+ "known-css-properties": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.17.0.tgz",
+ "integrity": "sha512-Vi3nxDGMm/z+lAaCjvAR1u+7fiv+sG6gU/iYDj5QOF8h76ytK9EW/EKfF0NeTyiGBi8Jy6Hklty/vxISrLox3w==",
+ "dev": true
+ },
"laravel-mix": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-4.1.4.tgz",
@@ -5406,6 +6131,48 @@
"invert-kv": "^2.0.0"
}
},
+ "leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+ "dev": true
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "lines-and-columns": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
+ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
+ "dev": true
+ },
+ "load-json-file": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
+ "strip-bom": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
"loader-runner": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
@@ -5548,12 +6315,27 @@
"integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
"dev": true
},
+ "log-symbols": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
+ "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2"
+ }
+ },
"loglevel": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz",
"integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==",
"dev": true
},
+ "longest-streak": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
+ "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+ "dev": true
+ },
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -5563,6 +6345,16 @@
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
+ "loud-rejection": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+ "dev": true,
+ "requires": {
+ "currently-unhandled": "^0.4.1",
+ "signal-exit": "^3.0.0"
+ }
+ },
"lower-case": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
@@ -5609,6 +6401,12 @@
"integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
"dev": true
},
+ "map-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
+ "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=",
+ "dev": true
+ },
"map-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
@@ -5618,6 +6416,24 @@
"object-visit": "^1.0.0"
}
},
+ "markdown-escapes": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
+ "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
+ "dev": true
+ },
+ "markdown-table": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz",
+ "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==",
+ "dev": true
+ },
+ "mathml-tag-names": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
+ "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==",
+ "dev": true
+ },
"md5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
@@ -5648,6 +6464,15 @@
"safe-buffer": "^5.1.2"
}
},
+ "mdast-util-compact": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz",
+ "integrity": "sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^1.1.0"
+ }
+ },
"mdn-data": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
@@ -5681,6 +6506,40 @@
"readable-stream": "^2.0.1"
}
},
+ "meow": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz",
+ "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==",
+ "dev": true,
+ "requires": {
+ "camelcase-keys": "^4.0.0",
+ "decamelize-keys": "^1.0.0",
+ "loud-rejection": "^1.0.0",
+ "minimist-options": "^3.0.1",
+ "normalize-package-data": "^2.3.4",
+ "read-pkg-up": "^3.0.0",
+ "redent": "^2.0.0",
+ "trim-newlines": "^2.0.0",
+ "yargs-parser": "^10.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+ "dev": true
+ },
+ "yargs-parser": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
+ "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^4.1.0"
+ }
+ }
+ }
+ },
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -5801,6 +6660,16 @@
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
+ "minimist-options": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz",
+ "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==",
+ "dev": true,
+ "requires": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0"
+ }
+ },
"mississippi": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
@@ -5882,6 +6751,12 @@
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
"dev": true
},
+ "mute-stream": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+ "dev": true
+ },
"nan": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
@@ -5908,6 +6783,12 @@
"to-regex": "^3.0.1"
}
},
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
@@ -6002,6 +6883,18 @@
"semver": "^5.3.0"
}
},
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -6014,6 +6907,12 @@
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
"dev": true
},
+ "normalize-selector": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
+ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=",
+ "dev": true
+ },
"normalize-url": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz",
@@ -6208,6 +7107,15 @@
"wrappy": "1"
}
},
+ "onetime": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
+ "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^2.1.0"
+ }
+ },
"opn": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
@@ -6227,6 +7135,20 @@
"last-call-webpack-plugin": "^3.0.0"
}
},
+ "optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ }
+ },
"original": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
@@ -6253,6 +7175,12 @@
"mem": "^4.0.0"
}
},
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true
+ },
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
@@ -6342,6 +7270,23 @@
"no-case": "^2.2.0"
}
},
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0"
+ },
+ "dependencies": {
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ }
+ }
+ },
"parse-asn1": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz",
@@ -6356,6 +7301,20 @@
"safe-buffer": "^5.1.1"
}
},
+ "parse-entities": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz",
+ "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==",
+ "dev": true,
+ "requires": {
+ "character-entities": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "character-reference-invalid": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-hexadecimal": "^1.0.0"
+ }
+ },
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
@@ -6462,6 +7421,12 @@
"sha.js": "^2.4.8"
}
},
+ "picomatch": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz",
+ "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==",
+ "dev": true
+ },
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
@@ -6655,17 +7620,44 @@
"postcss": "^7.0.0"
}
},
- "postcss-load-config": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz",
- "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==",
+ "postcss-html": {
+ "version": "0.36.0",
+ "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz",
+ "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==",
"dev": true,
"requires": {
- "cosmiconfig": "^5.0.0",
- "import-cwd": "^2.0.0"
+ "htmlparser2": "^3.10.0"
}
},
- "postcss-loader": {
+ "postcss-jsx": {
+ "version": "0.36.4",
+ "resolved": "https://registry.npmjs.org/postcss-jsx/-/postcss-jsx-0.36.4.tgz",
+ "integrity": "sha512-jwO/7qWUvYuWYnpOb0+4bIIgJt7003pgU3P6nETBLaOyBXuTD55ho21xnals5nBrlpTIFodyd3/jBi6UO3dHvA==",
+ "dev": true,
+ "requires": {
+ "@babel/core": ">=7.2.2"
+ }
+ },
+ "postcss-less": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz",
+ "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.14"
+ }
+ },
+ "postcss-load-config": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz",
+ "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==",
+ "dev": true,
+ "requires": {
+ "cosmiconfig": "^5.0.0",
+ "import-cwd": "^2.0.0"
+ }
+ },
+ "postcss-loader": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz",
"integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==",
@@ -6690,6 +7682,22 @@
}
}
},
+ "postcss-markdown": {
+ "version": "0.36.0",
+ "resolved": "https://registry.npmjs.org/postcss-markdown/-/postcss-markdown-0.36.0.tgz",
+ "integrity": "sha512-rl7fs1r/LNSB2bWRhyZ+lM/0bwKv9fhl38/06gF6mKMo/NPnp55+K1dSTosSVjFZc0e1ppBlu+WT91ba0PMBfQ==",
+ "dev": true,
+ "requires": {
+ "remark": "^10.0.1",
+ "unist-util-find-all-after": "^1.0.2"
+ }
+ },
+ "postcss-media-query-parser": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
+ "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=",
+ "dev": true
+ },
"postcss-merge-longhand": {
"version": "4.0.11",
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz",
@@ -7151,6 +8159,119 @@
}
}
},
+ "postcss-reporter": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz",
+ "integrity": "sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "lodash": "^4.17.11",
+ "log-symbols": "^2.2.0",
+ "postcss": "^7.0.7"
+ },
+ "dependencies": {
+ "log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.1"
+ }
+ }
+ }
+ },
+ "postcss-resolve-nested-selector": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
+ "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=",
+ "dev": true
+ },
+ "postcss-safe-parser": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz",
+ "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.26"
+ },
+ "dependencies": {
+ "postcss": {
+ "version": "7.0.26",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.26.tgz",
+ "integrity": "sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "postcss-sass": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.4.2.tgz",
+ "integrity": "sha512-hcRgnd91OQ6Ot9R90PE/khUDCJHG8Uxxd3F7Y0+9VHjBiJgNv7sK5FxyHMCBtoLmmkzVbSj3M3OlqUfLJpq0CQ==",
+ "dev": true,
+ "requires": {
+ "gonzales-pe": "^4.2.4",
+ "postcss": "^7.0.21"
+ },
+ "dependencies": {
+ "postcss": {
+ "version": "7.0.26",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.26.tgz",
+ "integrity": "sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "postcss-scss": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.0.0.tgz",
+ "integrity": "sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0"
+ }
+ },
"postcss-selector-parser": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz",
@@ -7190,6 +8311,12 @@
}
}
},
+ "postcss-syntax": {
+ "version": "0.36.2",
+ "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz",
+ "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==",
+ "dev": true
+ },
"postcss-unique-selectors": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz",
@@ -7207,6 +8334,12 @@
"integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==",
"dev": true
},
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true
+ },
"prettier": {
"version": "1.16.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz",
@@ -7231,6 +8364,12 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true
},
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true
+ },
"promise-inflight": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@@ -7342,6 +8481,12 @@
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
"dev": true
},
+ "quick-lru": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz",
+ "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=",
+ "dev": true
+ },
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -7387,6 +8532,72 @@
}
}
},
+ "read-pkg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^4.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^3.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+ "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
+ "dev": true,
+ "requires": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^3.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "dev": true,
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "dev": true,
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+ "dev": true
+ }
+ }
+ },
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
@@ -7425,6 +8636,16 @@
"source-map": "~0.5.0"
}
},
+ "redent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz",
+ "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=",
+ "dev": true,
+ "requires": {
+ "indent-string": "^3.0.0",
+ "strip-indent": "^2.0.0"
+ }
+ },
"regenerate": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
@@ -7486,6 +8707,12 @@
"define-properties": "^1.1.2"
}
},
+ "regexpp": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
+ "dev": true
+ },
"regexpu-core": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz",
@@ -7529,6 +8756,62 @@
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
"dev": true
},
+ "remark": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/remark/-/remark-10.0.1.tgz",
+ "integrity": "sha512-E6lMuoLIy2TyiokHprMjcWNJ5UxfGQjaMSMhV+f4idM625UjjK4j798+gPs5mfjzDE6vL0oFKVeZM6gZVSVrzQ==",
+ "dev": true,
+ "requires": {
+ "remark-parse": "^6.0.0",
+ "remark-stringify": "^6.0.0",
+ "unified": "^7.0.0"
+ }
+ },
+ "remark-parse": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-6.0.3.tgz",
+ "integrity": "sha512-QbDXWN4HfKTUC0hHa4teU463KclLAnwpn/FBn87j9cKYJWWawbiLgMfP2Q4XwhxxuuuOxHlw+pSN0OKuJwyVvg==",
+ "dev": true,
+ "requires": {
+ "collapse-white-space": "^1.0.2",
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "is-word-character": "^1.0.0",
+ "markdown-escapes": "^1.0.0",
+ "parse-entities": "^1.1.0",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "trim": "0.0.1",
+ "trim-trailing-lines": "^1.0.0",
+ "unherit": "^1.0.4",
+ "unist-util-remove-position": "^1.0.0",
+ "vfile-location": "^2.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "remark-stringify": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-6.0.4.tgz",
+ "integrity": "sha512-eRWGdEPMVudijE/psbIDNcnJLRVx3xhfuEsTDGgH4GsFF91dVhw5nhmnBppafJ7+NWINW6C7ZwWbi30ImJzqWg==",
+ "dev": true,
+ "requires": {
+ "ccount": "^1.0.0",
+ "is-alphanumeric": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "longest-streak": "^2.0.1",
+ "markdown-escapes": "^1.0.0",
+ "markdown-table": "^1.1.0",
+ "mdast-util-compact": "^1.0.0",
+ "parse-entities": "^1.0.2",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "stringify-entities": "^1.0.1",
+ "unherit": "^1.0.4",
+ "xtend": "^4.0.1"
+ }
+ },
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -7649,6 +8932,16 @@
}
}
},
+ "restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "requires": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
"ret": {
"version": "0.1.15",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
@@ -7716,6 +9009,15 @@
"inherits": "^2.0.1"
}
},
+ "run-async": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+ "dev": true,
+ "requires": {
+ "is-promise": "^2.1.0"
+ }
+ },
"run-queue": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
@@ -7725,6 +9027,15 @@
"aproba": "^1.1.1"
}
},
+ "rxjs": {
+ "version": "6.5.4",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz",
+ "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -8043,6 +9354,17 @@
"integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
"dev": true
},
+ "slice-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+ "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ }
+ },
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -8270,6 +9592,38 @@
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
"dev": true
},
+ "spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+ "dev": true
+ },
"spdy": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz",
@@ -8342,6 +9696,12 @@
}
}
},
+ "specificity": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz",
+ "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==",
+ "dev": true
+ },
"split-string": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
@@ -8378,6 +9738,12 @@
"integrity": "sha512-to7oADIniaYwS3MhtCa/sQhrxidCCQiF/qp4/m5iN3ipf0Y7Xlri0f6eG29r08aL7JYl8n32AF3Q5GYBZ7K8vw==",
"dev": true
},
+ "state-toggle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
+ "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
+ "dev": true
+ },
"static-extend": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
@@ -8500,6 +9866,18 @@
"safe-buffer": "~5.1.0"
}
},
+ "stringify-entities": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz",
+ "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==",
+ "dev": true,
+ "requires": {
+ "character-entities-html4": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-hexadecimal": "^1.0.0"
+ }
+ },
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
@@ -8509,12 +9887,30 @@
"ansi-regex": "^2.0.0"
}
},
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true
+ },
"strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
"dev": true
},
+ "strip-indent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz",
+ "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=",
+ "dev": true
+ },
+ "strip-json-comments": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
+ "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
+ "dev": true
+ },
"style-loader": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz",
@@ -8538,6 +9934,12 @@
}
}
},
+ "style-search": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
+ "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=",
+ "dev": true
+ },
"stylehacks": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
@@ -8562,35 +9964,567 @@
}
}
},
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "svgo": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz",
- "integrity": "sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ==",
+ "stylelint": {
+ "version": "12.0.1",
+ "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-12.0.1.tgz",
+ "integrity": "sha512-1mn39pqZiC/e8KUPoRMc1WMM83Upb2ILaSGxkCvKxALHutEOs2txcPQocJiXdO4Zx4FY4prGqjlkwrbthAxqig==",
"dev": true,
"requires": {
- "chalk": "^2.4.1",
- "coa": "^2.0.2",
- "css-select": "^2.0.0",
- "css-select-base-adapter": "^0.1.1",
- "css-tree": "1.0.0-alpha.33",
- "csso": "^3.5.1",
- "js-yaml": "^3.13.1",
- "mkdirp": "~0.5.1",
- "object.values": "^1.1.0",
- "sax": "~1.2.4",
- "stable": "^0.1.8",
- "unquote": "~1.1.1",
- "util.promisify": "~1.0.0"
- }
+ "autoprefixer": "^9.7.1",
+ "balanced-match": "^1.0.0",
+ "chalk": "^3.0.0",
+ "cosmiconfig": "^6.0.0",
+ "debug": "^4.1.1",
+ "execall": "^2.0.0",
+ "file-entry-cache": "^5.0.1",
+ "get-stdin": "^7.0.0",
+ "global-modules": "^2.0.0",
+ "globby": "^9.2.0",
+ "globjoin": "^0.1.4",
+ "html-tags": "^3.1.0",
+ "ignore": "^5.1.4",
+ "import-lazy": "^4.0.0",
+ "imurmurhash": "^0.1.4",
+ "known-css-properties": "^0.17.0",
+ "leven": "^3.1.0",
+ "lodash": "^4.17.15",
+ "log-symbols": "^3.0.0",
+ "mathml-tag-names": "^2.1.1",
+ "meow": "^5.0.0",
+ "micromatch": "^4.0.2",
+ "normalize-selector": "^0.2.0",
+ "postcss": "^7.0.21",
+ "postcss-html": "^0.36.0",
+ "postcss-jsx": "^0.36.3",
+ "postcss-less": "^3.1.4",
+ "postcss-markdown": "^0.36.0",
+ "postcss-media-query-parser": "^0.2.3",
+ "postcss-reporter": "^6.0.1",
+ "postcss-resolve-nested-selector": "^0.1.1",
+ "postcss-safe-parser": "^4.0.1",
+ "postcss-sass": "^0.4.2",
+ "postcss-scss": "^2.0.0",
+ "postcss-selector-parser": "^3.1.0",
+ "postcss-syntax": "^0.36.2",
+ "postcss-value-parser": "^4.0.2",
+ "resolve-from": "^5.0.0",
+ "slash": "^3.0.0",
+ "specificity": "^0.4.1",
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "style-search": "^0.1.0",
+ "sugarss": "^2.0.0",
+ "svg-tags": "^1.0.0",
+ "table": "^5.4.6",
+ "v8-compile-cache": "^2.1.0",
+ "write-file-atomic": "^3.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "autoprefixer": {
+ "version": "9.7.4",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.4.tgz",
+ "integrity": "sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.8.3",
+ "caniuse-lite": "^1.0.30001020",
+ "chalk": "^2.4.2",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^7.0.26",
+ "postcss-value-parser": "^4.0.2"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "browserslist": {
+ "version": "4.8.6",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.6.tgz",
+ "integrity": "sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30001023",
+ "electron-to-chromium": "^1.3.341",
+ "node-releases": "^1.1.47"
+ }
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001027",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001027.tgz",
+ "integrity": "sha512-7xvKeErvXZFtUItTHgNtLgS9RJpVnwBlWX8jSo/BO8VsF6deszemZSkJJJA1KOKrXuzZH4WALpAJdq5EyfgMLg==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+ "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
+ "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
+ "dev": true,
+ "requires": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.1.0",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.7.2"
+ }
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "dir-glob": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
+ "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
+ "dev": true,
+ "requires": {
+ "path-type": "^3.0.0"
+ },
+ "dependencies": {
+ "path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ }
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "electron-to-chromium": {
+ "version": "1.3.349",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.349.tgz",
+ "integrity": "sha512-uEb2zs6EJ6OZIqaMsCSliYVgzE/f7/s1fLWqtvRtHg/v5KBF2xds974fUnyatfxIDgkqzQVwFtam5KExqywx0Q==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "globby": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz",
+ "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==",
+ "dev": true,
+ "requires": {
+ "@types/glob": "^7.1.1",
+ "array-union": "^1.0.2",
+ "dir-glob": "^2.2.2",
+ "fast-glob": "^2.2.6",
+ "glob": "^7.1.3",
+ "ignore": "^4.0.3",
+ "pify": "^4.0.1",
+ "slash": "^2.0.0"
+ },
+ "dependencies": {
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
+ "slash": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+ "dev": true
+ }
+ }
+ },
+ "ignore": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
+ "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
+ "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "dependencies": {
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ }
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node-releases": {
+ "version": "1.1.49",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.49.tgz",
+ "integrity": "sha512-xH8t0LS0disN0mtRCh+eByxFPie+msJUBL/lJDBuap53QGiYPa9joh83K4pCZgWJ+2L4b9h88vCVdXQ60NO2bg==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.3.0"
+ }
+ },
+ "parse-json": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
+ "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ },
+ "postcss": {
+ "version": "7.0.26",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.26.tgz",
+ "integrity": "sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz",
+ "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=",
+ "dev": true,
+ "requires": {
+ "dot-prop": "^4.1.1",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ },
+ "resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "v8-compile-cache": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
+ "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==",
+ "dev": true
+ }
+ }
+ },
+ "stylelint-config-recommended": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-3.0.0.tgz",
+ "integrity": "sha512-F6yTRuc06xr1h5Qw/ykb2LuFynJ2IxkKfCMf+1xqPffkxh0S09Zc902XCffcsw/XMFq/OzQ1w54fLIDtmRNHnQ==",
+ "dev": true
+ },
+ "stylelint-config-standard": {
+ "version": "19.0.0",
+ "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-19.0.0.tgz",
+ "integrity": "sha512-VvcODsL1PryzpYteWZo2YaA5vU/pWfjqBpOvmeA8iB2MteZ/ZhI1O4hnrWMidsS4vmEJpKtjdhLdfGJmmZm6Cg==",
+ "dev": true,
+ "requires": {
+ "stylelint-config-recommended": "^3.0.0"
+ }
+ },
+ "sugarss": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz",
+ "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.2"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "svg-tags": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
+ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
+ "dev": true
+ },
+ "svgo": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz",
+ "integrity": "sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "coa": "^2.0.2",
+ "css-select": "^2.0.0",
+ "css-select-base-adapter": "^0.1.1",
+ "css-tree": "1.0.0-alpha.33",
+ "csso": "^3.5.1",
+ "js-yaml": "^3.13.1",
+ "mkdirp": "~0.5.1",
+ "object.values": "^1.1.0",
+ "sax": "~1.2.4",
+ "stable": "^0.1.8",
+ "unquote": "~1.1.1",
+ "util.promisify": "~1.0.0"
+ }
+ },
+ "table": {
+ "version": "5.4.6",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+ "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.10.2",
+ "lodash": "^4.17.14",
+ "slice-ansi": "^2.1.0",
+ "string-width": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
},
"tapable": {
"version": "1.1.3",
@@ -8676,6 +10610,12 @@
}
}
},
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
@@ -8713,6 +10653,15 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
"to-arraybuffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@@ -8779,12 +10728,36 @@
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
"dev": true
},
+ "trim": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+ "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=",
+ "dev": true
+ },
+ "trim-newlines": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz",
+ "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=",
+ "dev": true
+ },
"trim-right": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
"dev": true
},
+ "trim-trailing-lines": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz",
+ "integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==",
+ "dev": true
+ },
+ "trough": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+ "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+ "dev": true
+ },
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
@@ -8797,6 +10770,21 @@
"integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
"dev": true
},
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ },
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@@ -8813,6 +10801,15 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
+ "typedarray-to-buffer": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "dev": true,
+ "requires": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
"uglify-js": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
@@ -8837,6 +10834,16 @@
}
}
},
+ "unherit": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
+ "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
"unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
@@ -8865,6 +10872,22 @@
"integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==",
"dev": true
},
+ "unified": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-7.1.0.tgz",
+ "integrity": "sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "@types/vfile": "^3.0.0",
+ "bail": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-plain-obj": "^1.1.0",
+ "trough": "^1.0.0",
+ "vfile": "^3.0.0",
+ "x-is-string": "^0.1.0"
+ }
+ },
"union-value": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@@ -8915,6 +10938,57 @@
"imurmurhash": "^0.1.4"
}
},
+ "unist-util-find-all-after": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-1.0.5.tgz",
+ "integrity": "sha512-lWgIc3rrTMTlK1Y0hEuL+k+ApzFk78h+lsaa2gHf63Gp5Ww+mt11huDniuaoq1H+XMK2lIIjjPkncxXcDp3QDw==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^3.0.0"
+ }
+ },
+ "unist-util-is": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+ "dev": true
+ },
+ "unist-util-remove-position": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz",
+ "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^1.1.0"
+ }
+ },
+ "unist-util-stringify-position": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.2.tgz",
+ "integrity": "sha512-nK5n8OGhZ7ZgUwoUbL8uiVRwAbZyzBsB/Ddrlbu6jwwubFza4oe15KlyEaLNMXQW1svOQq4xesUeqA85YrIUQA==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.2"
+ }
+ },
+ "unist-util-visit": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
+ "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit-parents": "^2.0.0"
+ }
+ },
+ "unist-util-visit-parents": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
+ "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^3.0.0"
+ }
+ },
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
@@ -9085,6 +11159,16 @@
"integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==",
"dev": true
},
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -9097,6 +11181,51 @@
"integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==",
"dev": true
},
+ "vfile": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-3.0.1.tgz",
+ "integrity": "sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^2.0.0",
+ "replace-ext": "1.0.0",
+ "unist-util-stringify-position": "^1.0.0",
+ "vfile-message": "^1.0.0"
+ },
+ "dependencies": {
+ "unist-util-stringify-position": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz",
+ "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==",
+ "dev": true
+ },
+ "vfile-message": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz",
+ "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==",
+ "dev": true,
+ "requires": {
+ "unist-util-stringify-position": "^1.1.1"
+ }
+ }
+ }
+ },
+ "vfile-location": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz",
+ "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==",
+ "dev": true
+ },
+ "vfile-message": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.2.tgz",
+ "integrity": "sha512-gNV2Y2fDvDOOqq8bEe7cF3DXU6QgV4uA9zMR2P8tix11l1r7zju3zry3wZ8sx+BEfuO6WQ7z2QzfWTvqHQiwsA==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-stringify-position": "^2.0.0"
+ }
+ },
"vm-browserify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz",
@@ -9109,6 +11238,47 @@
"integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==",
"dev": true
},
+ "vue-eslint-parser": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.0.0.tgz",
+ "integrity": "sha512-yR0dLxsTT7JfD2YQo9BhnQ6bUTLsZouuzt9SKRP7XNaZJV459gvlsJo4vT2nhZ/2dH9j3c53bIx9dnqU2prM9g==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1",
+ "eslint-scope": "^5.0.0",
+ "eslint-visitor-keys": "^1.1.0",
+ "espree": "^6.1.2",
+ "esquery": "^1.0.1",
+ "lodash": "^4.17.15"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "eslint-scope": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
+ "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
"vue-hot-reload-api": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
@@ -9496,6 +11666,12 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true
+ },
"worker-farm": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
@@ -9550,6 +11726,27 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
+ "write": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+ "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+ "dev": true,
+ "requires": {
+ "mkdirp": "^0.5.1"
+ }
+ },
+ "write-file-atomic": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.1.tgz",
+ "integrity": "sha512-JPStrIyyVJ6oCSz/691fAjFtefZ6q+fP6tm+OS4Qw6o+TGQxNp1ziY2PgS+X/m0V8OWhZiO/m4xSj+Pr4RrZvw==",
+ "dev": true,
+ "requires": {
+ "imurmurhash": "^0.1.4",
+ "is-typedarray": "^1.0.0",
+ "signal-exit": "^3.0.2",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ },
"ws": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
@@ -9559,6 +11756,12 @@
"async-limiter": "~1.0.0"
}
},
+ "x-is-string": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
+ "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=",
+ "dev": true
+ },
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@@ -9577,6 +11780,26 @@
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"dev": true
},
+ "yaml": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.7.2.tgz",
+ "integrity": "sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.6.3"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.4.tgz",
+ "integrity": "sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ==",
+ "dev": true,
+ "requires": {
+ "regenerator-runtime": "^0.13.2"
+ }
+ }
+ }
+ },
"yargs": {
"version": "12.0.5",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
diff --git a/src/phpdoc b/src/phpdoc
new file mode 120000
--- /dev/null
+++ b/src/phpdoc
@@ -0,0 +1 @@
+../bin/phpdoc
\ No newline at end of file
diff --git a/src/phpstan b/src/phpstan
new file mode 120000
--- /dev/null
+++ b/src/phpstan
@@ -0,0 +1 @@
+../bin/phpstan
\ No newline at end of file
diff --git a/src/phpstan.neon b/src/phpstan.neon
new file mode 100644
--- /dev/null
+++ b/src/phpstan.neon
@@ -0,0 +1,6 @@
+includes:
+ - ./vendor/nunomaduro/larastan/extension.neon
+parameters:
+ level: 3
+ paths:
+ - app/
diff --git a/src/phpunit b/src/phpunit
new file mode 120000
--- /dev/null
+++ b/src/phpunit
@@ -0,0 +1 @@
+../bin/phpunit
\ No newline at end of file
diff --git a/src/phpunit.xml b/src/phpunit.xml
--- a/src/phpunit.xml
+++ b/src/phpunit.xml
@@ -9,6 +9,10 @@
processIsolation="false"
stopOnFailure="false">
+
+ tests/Browser
+
+
tests/Unit
@@ -23,6 +27,9 @@
./app
+
+
+
diff --git a/src/tests/Browser/PasswordResetTest.php b/src/tests/Browser/PasswordResetTest.php
--- a/src/tests/Browser/PasswordResetTest.php
+++ b/src/tests/Browser/PasswordResetTest.php
@@ -22,8 +22,7 @@
{
parent::setUp();
- $user = User::firstOrCreate(['email' => 'passwordresettestdusk@' . \config('app.domain')]);
- $user->setSetting('external_email', 'external@domain.tld');
+ $this->deleteTestUser('passwordresettestdusk@' . \config('app.domain'));
}
/**
@@ -33,7 +32,9 @@
*/
public function tearDown(): void
{
- User::where('email', 'passwordresettestdusk@' . \config('app.domain'))->delete();
+ $this->deleteTestUser('passwordresettestdusk@' . \config('app.domain'));
+
+ parent::tearDown();
}
/**
@@ -61,6 +62,9 @@
*/
public function testPasswordResetStep1()
{
+ $user = $this->getTestUser('passwordresettestdusk@' . \config('app.domain'));
+ $user->setSetting('external_email', 'external@domain.tld');
+
$this->browse(function (Browser $browser) {
$browser->visit(new PasswordReset());
diff --git a/src/tests/Browser/SignupTest.php b/src/tests/Browser/SignupTest.php
--- a/src/tests/Browser/SignupTest.php
+++ b/src/tests/Browser/SignupTest.php
@@ -22,10 +22,18 @@
{
parent::setUp();
- Domain::where('namespace', 'user-domain-signup.com')->delete();
- User::where('email', 'signuptestdusk@' . \config('app.domain'))
- ->orWhere('email', 'admin@user-domain-signup.com')
- ->delete();
+ $this->deleteTestUser('signuptestdusk@' . \config('app.domain'));
+ $this->deleteTestUser('admin@user-domain-signup.com');
+ $this->deleteTestDomain('user-domain-signup.com');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('signuptestdusk@' . \config('app.domain'));
+ $this->deleteTestUser('admin@user-domain-signup.com');
+ $this->deleteTestDomain('user-domain-signup.com');
+
+ parent::tearDown();
}
/**
diff --git a/src/tests/DuskTestCase.php b/src/tests/DuskTestCase.php
--- a/src/tests/DuskTestCase.php
+++ b/src/tests/DuskTestCase.php
@@ -2,15 +2,69 @@
namespace Tests;
-use Laravel\Dusk\TestCase as BaseTestCase;
+use App\Domain;
+use App\User;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
+use Illuminate\Support\Facades\Queue;
+use Laravel\Dusk\TestCase as BaseTestCase;
abstract class DuskTestCase extends BaseTestCase
{
use CreatesApplication;
+ protected function deleteTestDomain($name)
+ {
+ Queue::fake();
+ $domain = Domain::withTrashed()->where('namespace', $name)->first();
+ if (!$domain) {
+ return;
+ }
+
+ $job = new \App\Jobs\DomainDelete($domain);
+ $job->handle();
+
+ $domain->forceDelete();
+ }
+
+ protected function deleteTestUser($email)
+ {
+ Queue::fake();
+ $user = User::withTrashed()->where('email', $email)->first();
+
+ if (!$user) {
+ return;
+ }
+
+ $job = new \App\Jobs\UserDelete($user->id);
+ $job->handle();
+
+ $user->forceDelete();
+ }
+
+ /**
+ * Get Domain object by namespace, create it if needed.
+ * Skip LDAP jobs.
+ */
+ protected function getTestDomain($name, $attrib = [])
+ {
+ // Disable jobs (i.e. skip LDAP oprations)
+ Queue::fake();
+ return Domain::firstOrCreate(['namespace' => $name], $attrib);
+ }
+
+ /**
+ * Get User object by email, create it if needed.
+ * Skip LDAP jobs.
+ */
+ protected function getTestUser($email, $attrib = [])
+ {
+ // Disable jobs (i.e. skip LDAP oprations)
+ Queue::fake();
+ return User::firstOrCreate(['email' => $email], $attrib);
+ }
+
/**
* Prepare for Dusk test execution.
*
diff --git a/src/tests/Feature/Controller/DomainsTest.php b/src/tests/Feature/Controller/DomainsTest.php
--- a/src/tests/Feature/Controller/DomainsTest.php
+++ b/src/tests/Feature/Controller/DomainsTest.php
@@ -20,8 +20,16 @@
{
parent::setUp();
- User::where('email', 'test1@domainscontroller.com')->delete();
- Domain::where('namespace', 'domainscontroller.com')->delete();
+ $this->deleteTestUser('test1@domainscontroller.com');
+ $this->deleteTestDomain('domainscontroller.com');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('test1@domainscontroller.com');
+ $this->deleteTestDomain('domainscontroller.com');
+
+ parent::tearDown();
}
/**
diff --git a/src/tests/Feature/Controller/PasswordResetTest.php b/src/tests/Feature/Controller/PasswordResetTest.php
--- a/src/tests/Feature/Controller/PasswordResetTest.php
+++ b/src/tests/Feature/Controller/PasswordResetTest.php
@@ -16,7 +16,7 @@
{
parent::setUp();
- $user = $this->getTestUser('passwordresettest@' . \config('app.domain'));
+ $this->deleteTestUser('passwordresettest@' . \config('app.domain'));
}
/**
@@ -24,8 +24,9 @@
*/
public function tearDown(): void
{
- User::where('email', 'passwordresettest@' . \config('app.domain'))
- ->delete();
+ $this->deleteTestUser('passwordresettest@' . \config('app.domain'));
+
+ parent::tearDown();
}
/**
@@ -101,7 +102,7 @@
Queue::assertNothingPushed();
// Add required external email address to user settings
- $user = User::where('email', 'passwordresettest@' . \config('app.domain'))->first();
+ $user = $this->getTestUser('passwordresettest@' . \config('app.domain'));
$user->setSetting('external_email', 'ext@email.com');
$data = [
@@ -150,7 +151,7 @@
$this->assertArrayHasKey('short_code', $json['errors']);
// Add verification code and required external email address to user settings
- $user = User::where('email', 'passwordresettest@' . \config('app.domain'))->first();
+ $user = $this->getTestUser('passwordresettest@' . \config('app.domain'));
$code = new VerificationCode(['mode' => 'password-reset']);
$user->verificationcodes()->save($code);
@@ -192,7 +193,7 @@
public function testPasswordResetVerifyValidInput()
{
// Add verification code and required external email address to user settings
- $user = User::where('email', 'passwordresettest@' . \config('app.domain'))->first();
+ $user = $this->getTestUser('passwordresettest@' . \config('app.domain'));
$code = new VerificationCode(['mode' => 'password-reset']);
$user->verificationcodes()->save($code);
@@ -228,7 +229,7 @@
$this->assertCount(1, $json['errors']);
$this->assertArrayHasKey('password', $json['errors']);
- $user = User::where('email', 'passwordresettest@' . \config('app.domain'))->first();
+ $user = $this->getTestUser('passwordresettest@' . \config('app.domain'));
$code = new VerificationCode(['mode' => 'password-reset']);
$user->verificationcodes()->save($code);
@@ -285,7 +286,7 @@
*/
public function testPasswordResetValidInput()
{
- $user = User::where('email', 'passwordresettest@' . \config('app.domain'))->first();
+ $user = $this->getTestUser('passwordresettest@' . \config('app.domain'));
$code = new VerificationCode(['mode' => 'password-reset']);
$user->verificationcodes()->save($code);
diff --git a/src/tests/Feature/Controller/SignupTest.php b/src/tests/Feature/Controller/SignupTest.php
--- a/src/tests/Feature/Controller/SignupTest.php
+++ b/src/tests/Feature/Controller/SignupTest.php
@@ -11,7 +11,7 @@
class SignupTest extends TestCase
{
- private static $domain;
+ private $domain;
/**
* {@inheritDoc}
@@ -22,8 +22,14 @@
// TODO: Some tests depend on existence of individual and group plans,
// we should probably create plans here to not depend on that
- $domain = self::getPublicDomain();
- $user = $this->getTestUser("SignupControllerTest1@$domain");
+ $this->domain = $this->getPublicDomain();
+
+ $this->deleteTestUser("SignupControllerTest1@$this->domain");
+ $this->deleteTestUser("signuplogin@$this->domain");
+ $this->deleteTestUser("admin@external.com");
+
+ $this->deleteTestDomain('external.com');
+ $this->deleteTestDomain('signup-domain.com');
}
/**
@@ -31,39 +37,37 @@
*/
public function tearDown(): void
{
- $domain = self::getPublicDomain();
+ $this->deleteTestUser("SignupControllerTest1@$this->domain");
+ $this->deleteTestUser("signuplogin@$this->domain");
+ $this->deleteTestUser("admin@external.com");
- User::where('email', "signuplogin@$domain")
- ->orWhere('email', "SignupControllerTest1@$domain")
- ->orWhere('email', 'admin@external.com')
- ->delete();
+ $this->deleteTestDomain('external.com');
+ $this->deleteTestDomain('signup-domain.com');
- Domain::where('namespace', 'signup-domain.com')
- ->orWhere('namespace', 'external.com')
- ->delete();
+ parent::tearDown();
}
/**
* Return a public domain for signup tests
*/
- public function getPublicDomain(): string
+ private function getPublicDomain(): string
{
- if (!self::$domain) {
+ if (!$this->domain) {
$this->refreshApplication();
$public_domains = Domain::getPublicDomains();
- self::$domain = reset($public_domains);
+ $this->domain = reset($public_domains);
- if (empty(self::$domain)) {
- self::$domain = 'signup-domain.com';
+ if (empty($this->domain)) {
+ $this->domain = 'signup-domain.com';
Domain::create([
- 'namespace' => self::$domain,
+ 'namespace' => $this->domain,
'status' => Domain::STATUS_ACTIVE,
'type' => Domain::TYPE_PUBLIC,
]);
}
}
- return self::$domain;
+ return $this->domain;
}
/**
@@ -418,7 +422,7 @@
});
// Check if the code has been removed
- $this->assertNull(SignupCode::where($result['code'])->first());
+ $this->assertNull(SignupCode::where('code', $result['code'])->first());
// Check if the user has been created
$user = User::where('email', $identity)->first();
@@ -451,7 +455,7 @@
'plan' => 'group',
];
- $response = $this->post('/api/auth/signup/init', $data);
+ $response = $this->withoutMiddleware()->post('/api/auth/signup/init', $data);
$json = $response->json();
$response->assertStatus(200);
@@ -603,15 +607,17 @@
['administrator', $domain, false, ['login' => 'validation.loginexists']],
['sales', $domain, false, ['login' => 'validation.loginexists']],
['root', $domain, false, ['login' => 'validation.loginexists']],
+
// existing user
- ['SignupControllerTest1', $domain, false, ['login' => 'validation.loginexists']],
+ ['jack', 'kolab.org', true, ['domain' => 'validation.domainexists']],
// Domain account
['admin', 'kolabsys.com', true, null],
['testnonsystemdomain', 'invalid', true, ['domain' => 'validation.domaininvalid']],
['testnonsystemdomain', '.com', true, ['domain' => 'validation.domaininvalid']],
+
// existing user
- ['SignupControllerTest1', $domain, true, ['domain' => 'validation.domainexists']],
+ ['john', 'kolab.org', true, ['domain' => 'validation.domainexists']],
];
}
@@ -630,6 +636,6 @@
$result = $method->invoke(new SignupController(), $login, $domain, $external);
- $this->assertSame($expected_result, $result);
+ $this->assertSame($expected_result, $result, var_export(func_get_args(), true));
}
}
diff --git a/src/tests/Feature/Controller/UsersTest.php b/src/tests/Feature/Controller/UsersTest.php
--- a/src/tests/Feature/Controller/UsersTest.php
+++ b/src/tests/Feature/Controller/UsersTest.php
@@ -17,8 +17,18 @@
{
parent::setUp();
- User::where('email', 'UsersControllerTest1@userscontroller.com')->delete();
- Domain::where('namespace', 'userscontroller.com')->delete();
+ $this->deleteTestUser('UsersControllerTest1@userscontroller.com');
+ $this->deleteTestUser('UserEntitlement2A@UserEntitlement.com');
+ $this->deleteTestDomain('userscontroller.com');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('UsersControllerTest1@userscontroller.com');
+ $this->deleteTestUser('UserEntitlement2A@UserEntitlement.com');
+ $this->deleteTestDomain('userscontroller.com');
+
+ parent::tearDown();
}
/**
diff --git a/src/tests/Feature/DomainOwnerTest.php b/src/tests/Feature/DomainOwnerTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Feature/DomainOwnerTest.php
@@ -0,0 +1,46 @@
+deleteTestUser('jane@kolab.org');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('jane@kolab.org');
+
+ parent::tearDown();
+ }
+
+ public function testJohnCreateJane(): void
+ {
+ $john = User::where('email', 'john@kolab.org')->first();
+
+ $jane = User::create(
+ [
+ 'name' => 'Jane Doe',
+ 'email' => 'jane@kolab.org',
+ 'password' => 'simple123',
+ 'email_verified_at' => now()
+ ]
+ );
+
+ $package = Package::where('title', 'kolab')->first();
+
+ $john->assignPackage($package, $jane);
+
+ // assert jane has a mailbox entitlement
+ $this->assertTrue($jane->entitlements->count() == 4);
+ }
+}
diff --git a/src/tests/Feature/DomainTest.php b/src/tests/Feature/DomainTest.php
--- a/src/tests/Feature/DomainTest.php
+++ b/src/tests/Feature/DomainTest.php
@@ -13,21 +13,32 @@
class DomainTest extends TestCase
{
+ private $domains = [
+ 'public-active.com',
+ 'gmail.com',
+ 'ci-success-cname.kolab.org',
+ 'ci-success-txt.kolab.org',
+ 'ci-failure-cname.kolab.org',
+ 'ci-failure-txt.kolab.org',
+ 'ci-failure-none.kolab.org',
+ ];
+
public function setUp(): void
{
parent::setUp();
- $domains = [
- 'public-active.com',
- 'gmail.com',
- 'ci-success-cname.kolab.org',
- 'ci-success-txt.kolab.org',
- 'ci-failure-cname.kolab.org',
- 'ci-failure-txt.kolab.org',
- 'ci-failure-none.kolab.org',
- ];
-
- Domain::whereIn('namespace', $domains)->delete();
+ foreach ($this->domains as $domain) {
+ $this->deleteTestDomain($domain);
+ }
+ }
+
+ public function tearDown(): void
+ {
+ foreach ($this->domains as $domain) {
+ $this->deleteTestDomain($domain);
+ }
+
+ parent::tearDown();
}
/**
@@ -46,31 +57,19 @@
]);
Queue::assertPushed(\App\Jobs\DomainCreate::class, 1);
- Queue::assertPushed(\App\Jobs\DomainCreate::class, function ($job) use ($domain) {
- $job_domain = TestCase::getObjectProperty($job, 'domain');
-
- return $job_domain->id === $domain->id
- && $job_domain->namespace === $domain->namespace;
- });
-/*
- Queue::assertPushedWithChain(\App\Jobs\DomainCreate::class, [
- \App\Jobs\DomainVerify::class,
- ]);
-*/
-/*
- FIXME: Looks like we can't really do detailed assertions on chained jobs
- Another thing to consider is if we maybe should run these jobs
- independently (not chained) and make sure there's no race-condition
- in status update
-
- Queue::assertPushed(\App\Jobs\DomainVerify::class, 1);
- Queue::assertPushed(\App\Jobs\DomainVerify::class, function ($job) use ($domain) {
- $job_domain = TestCase::getObjectProperty($job, 'domain');
-
- return $job_domain->id === $domain->id
- && $job_domain->namespace === $domain->namespace;
- });
-*/
+
+ Queue::assertPushed(
+ \App\Jobs\DomainCreate::class,
+ function ($job) use ($domain) {
+ $job_domain = TestCase::getObjectProperty($job, 'domain');
+
+ return $job_domain->id === $domain->id &&
+ $job_domain->namespace === $domain->namespace;
+ }
+ );
+
+ $job = new \App\Jobs\DomainCreate($domain);
+ $job->handle();
}
/**
@@ -142,17 +141,17 @@
$domain = $this->getTestDomain('ci-failure-none.kolab.org', $domain_props);
$this->assertTrue($domain->confirm() === false);
- $this->assertTrue(!$domain->isConfirmed());
+ $this->assertFalse($domain->isConfirmed());
$domain = $this->getTestDomain('ci-failure-txt.kolab.org', $domain_props);
$this->assertTrue($domain->confirm() === false);
- $this->assertTrue(!$domain->isConfirmed());
+ $this->assertFalse($domain->isConfirmed());
$domain = $this->getTestDomain('ci-failure-cname.kolab.org', $domain_props);
$this->assertTrue($domain->confirm() === false);
- $this->assertTrue(!$domain->isConfirmed());
+ $this->assertFalse($domain->isConfirmed());
$domain = $this->getTestDomain('ci-success-txt.kolab.org', $domain_props);
diff --git a/src/tests/Feature/EntitlementTest.php b/src/tests/Feature/EntitlementTest.php
--- a/src/tests/Feature/EntitlementTest.php
+++ b/src/tests/Feature/EntitlementTest.php
@@ -15,9 +15,16 @@
{
parent::setUp();
- User::where('email', 'entitlement-test@kolabnow.com')
- ->orWhere('email', 'entitled-user@custom-domain.com')
- ->delete();
+ $this->deleteTestUser('entitlement-test@kolabnow.com');
+ $this->deleteTestUser('entitled-user@custom-domain.com');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('entitlement-test@kolabnow.com');
+ $this->deleteTestUser('entitled-user@custom-domain.com');
+
+ parent::tearDown();
}
/**
@@ -37,16 +44,14 @@
]
);
- $this->assertTrue($owner->id != $user->id);
-
- $wallets = $owner->wallets()->get();
+ $wallet = $owner->wallets()->first();
$entitlement_own_mailbox = new Entitlement(
[
'owner_id' => $owner->id,
'entitleable_id' => $owner->id,
'entitleable_type' => User::class,
- 'wallet_id' => $wallets[0]->id,
+ 'wallet_id' => $wallet->id,
'sku_id' => $sku_mailbox->id,
'description' => "Owner Mailbox Entitlement Test"
]
@@ -57,7 +62,7 @@
'owner_id' => $owner->id,
'entitleable_id' => $domain->id,
'entitleable_type' => Domain::class,
- 'wallet_id' => $wallets[0]->id,
+ 'wallet_id' => $wallet->id,
'sku_id' => $sku_domain->id,
'description' => "User Domain Entitlement Test"
]
@@ -68,7 +73,7 @@
'owner_id' => $owner->id,
'entitleable_id' => $user->id,
'entitleable_type' => User::class,
- 'wallet_id' => $wallets[0]->id,
+ 'wallet_id' => $wallet->id,
'sku_id' => $sku_mailbox->id,
'description' => "User Mailbox Entitlement Test"
]
@@ -81,9 +86,43 @@
$this->assertTrue($owner->entitlements()->count() == 3);
$this->assertTrue($sku_domain->entitlements()->where('owner_id', $owner->id)->count() == 1);
$this->assertTrue($sku_mailbox->entitlements()->where('owner_id', $owner->id)->count() == 2);
- $this->assertTrue($wallets[0]->entitlements()->count() == 3);
- $this->assertTrue($wallets[0]->fresh()->balance < 0.00);
+ $this->assertTrue($wallet->entitlements()->count() == 3);
+ $this->assertTrue($wallet->fresh()->balance < 0.00);
+ }
+
+ public function testAddExistingEntitlement(): void
+ {
+ $this->markTestIncomplete();
+ }
+
+ public function testEntitlementFunctions(): void
+ {
+ $user = $this->getTestUser('entitlement-test@kolabnow.com');
+
+ $package = \App\Package::where('title', 'kolab')->first();
+
+ $user->assignPackage($package);
+
+ $wallet = $user->wallets()->first();
+ $this->assertNotNull($wallet);
+
+ $sku = \App\Sku::where('title', 'mailbox')->first();
+ $this->assertNotNull($sku);
+
+ $entitlement = Entitlement::where('owner_id', $user->id)->where('sku_id', $sku->id)->first();
+ $this->assertNotNull($entitlement);
+
+ $e_sku = $entitlement->sku;
+ $this->assertSame($sku->id, $e_sku->id);
+
+ $e_wallet = $entitlement->wallet;
+ $this->assertSame($wallet->id, $e_wallet->id);
+
+ $e_owner = $entitlement->owner;
+ $this->assertSame($user->id, $e_owner->id);
- // TODO: Test case of adding entitlement that already exists
+ $e_entitleable = $entitlement->entitleable;
+ $this->assertSame($user->id, $e_entitleable->id);
+ $this->assertTrue($e_entitleable instanceof \App\User);
}
}
diff --git a/src/tests/Feature/Jobs/DomainCreateTest.php b/src/tests/Feature/Jobs/DomainCreateTest.php
--- a/src/tests/Feature/Jobs/DomainCreateTest.php
+++ b/src/tests/Feature/Jobs/DomainCreateTest.php
@@ -5,6 +5,7 @@
use App\Jobs\DomainCreate;
use App\Domain;
use Illuminate\Support\Facades\Mail;
+use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
class DomainCreateTest extends TestCase
@@ -16,7 +17,14 @@
{
parent::setUp();
- Domain::where('namespace', 'domain-create-test.com')->delete();
+ $this->deleteTestDomain('domain-create-test.com');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestDomain('domain-create-test.com');
+
+ parent::tearDown();
}
/**
@@ -24,6 +32,8 @@
*/
public function testHandle(): void
{
+ Queue::fake();
+
$domain = $this->getTestDomain(
'domain-create-test.com',
[
@@ -34,12 +44,6 @@
$this->assertFalse($domain->isLdapReady());
- $mock = \Mockery::mock('alias:App\Backends\LDAP');
- $mock->shouldReceive('createDomain')
- ->once()
- ->with($domain)
- ->andReturn(null);
-
$job = new DomainCreate($domain);
$job->handle();
diff --git a/src/tests/Feature/Jobs/DomainVerifyTest.php b/src/tests/Feature/Jobs/DomainVerifyTest.php
--- a/src/tests/Feature/Jobs/DomainVerifyTest.php
+++ b/src/tests/Feature/Jobs/DomainVerifyTest.php
@@ -16,9 +16,16 @@
{
parent::setUp();
- Domain::where('namespace', 'gmail.com')
- ->orWhere('namespace', 'some-non-existing-domain.fff')
- ->delete();
+ $this->deleteTestDomain('gmail.com');
+ $this->deleteTestDomain('some-non-existing-domain.fff');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestDomain('gmail.com');
+ $this->deleteTestDomain('some-non-existing-domain.fff');
+
+ parent::tearDown();
}
/**
diff --git a/src/tests/Feature/Jobs/PasswordResetEmailTest.php b/src/tests/Feature/Jobs/PasswordResetEmailTest.php
--- a/src/tests/Feature/Jobs/PasswordResetEmailTest.php
+++ b/src/tests/Feature/Jobs/PasswordResetEmailTest.php
@@ -22,13 +22,7 @@
{
parent::setUp();
- $this->code = new VerificationCode([
- 'mode' => 'password-reset',
- ]);
-
- $user = $this->getTestUser('PasswordReset@UserAccount.com');
- $user->verificationcodes()->save($this->code);
- $user->setSettings(['external_email' => 'etx@email.com']);
+ $this->deleteTestUser('PasswordReset@UserAccount.com');
}
/**
@@ -38,7 +32,9 @@
*/
public function tearDown(): void
{
- $this->code->user->delete();
+ $this->deleteTestUser('PasswordReset@UserAccount.com');
+
+ parent::tearDown();
}
/**
@@ -48,20 +44,28 @@
*/
public function testPasswordResetEmailHandle()
{
+ $code = new VerificationCode([
+ 'mode' => 'password-reset',
+ ]);
+
+ $user = $this->getTestUser('PasswordReset@UserAccount.com');
+ $user->verificationcodes()->save($code);
+ $user->setSettings(['external_email' => 'etx@email.com']);
+
Mail::fake();
// Assert that no jobs were pushed...
Mail::assertNothingSent();
- $job = new PasswordResetEmail($this->code);
+ $job = new PasswordResetEmail($code);
$job->handle();
// Assert the email sending job was pushed once
Mail::assertSent(PasswordReset::class, 1);
// Assert the mail was sent to the code's email
- Mail::assertSent(PasswordReset::class, function ($mail) {
- return $mail->hasTo($this->code->user->getSetting('external_email'));
+ Mail::assertSent(PasswordReset::class, function ($mail) use ($code) {
+ return $mail->hasTo($code->user->getSetting('external_email'));
});
}
}
diff --git a/src/tests/Feature/Jobs/UserCreateTest.php b/src/tests/Feature/Jobs/UserCreateTest.php
--- a/src/tests/Feature/Jobs/UserCreateTest.php
+++ b/src/tests/Feature/Jobs/UserCreateTest.php
@@ -16,7 +16,14 @@
{
parent::setUp();
- User::where('email', 'new-job-user@' . \config('app.domain'))->delete();
+ $this->deleteTestUser('new-job-user@' . \config('app.domain'));
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('new-job-user@' . \config('app.domain'));
+
+ parent::tearDown();
}
/**
@@ -28,11 +35,13 @@
$this->assertFalse($user->isLdapReady());
+ /*
$mock = \Mockery::mock('alias:App\Backends\LDAP');
$mock->shouldReceive('createUser')
->once()
->with($user)
->andReturn(null);
+ */
$job = new UserCreate($user);
$job->handle();
diff --git a/src/tests/Feature/Jobs/UserVerifyTest.php b/src/tests/Feature/Jobs/UserVerifyTest.php
--- a/src/tests/Feature/Jobs/UserVerifyTest.php
+++ b/src/tests/Feature/Jobs/UserVerifyTest.php
@@ -16,7 +16,14 @@
{
parent::setUp();
- User::where('email', 'new-job-user@' . \config('app.domain'))->delete();
+ $this->deleteTestUser('new-job-user@' . \config('app.domain'));
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('new-job-user@' . \config('app.domain'));
+
+ parent::tearDown();
}
/**
@@ -28,24 +35,9 @@
$this->assertFalse($user->isImapReady());
- $mock = \Mockery::mock('alias:App\Backends\IMAP');
- $mock->shouldReceive('verifyAccount')
- ->once()
- ->with($user->email)
- ->andReturn(false);
-
$job = new UserVerify($user);
$job->handle();
$this->assertTrue($user->fresh()->isImapReady() === false);
-
- $mock->shouldReceive('verifyAccount')
- ->once()
- ->with($user->email)
- ->andReturn(true);
-
- $job->handle();
-
- $this->assertTrue($user->fresh()->isImapReady());
}
}
diff --git a/src/tests/Feature/PlanTest.php b/src/tests/Feature/PlanTest.php
--- a/src/tests/Feature/PlanTest.php
+++ b/src/tests/Feature/PlanTest.php
@@ -25,6 +25,8 @@
public function tearDown(): void
{
Plan::where('title', 'test-plan')->delete();
+
+ parent::tearDown();
}
/**
@@ -78,4 +80,30 @@
$this->assertTrue($plan->hasDomain() === true);
}
+
+ /**
+ * Test for a plan's cost.
+ */
+ public function testCost(): void
+ {
+ $plan = Plan::where('title', 'individual')->first();
+
+ $package_costs = 0;
+
+ foreach ($plan->packages as $package) {
+ $package_costs += $package->cost();
+ }
+
+ $this->assertTrue(
+ $package_costs == 999,
+ "The total costs of all packages for this plan is not 9.99"
+ );
+
+ $this->assertTrue(
+ $plan->cost() == 999,
+ "The total costs for this plan is not 9.99"
+ );
+
+ $this->assertTrue($plan->cost() == $package_costs);
+ }
}
diff --git a/src/tests/Feature/SignupCodeTest.php b/src/tests/Feature/SignupCodeTest.php
--- a/src/tests/Feature/SignupCodeTest.php
+++ b/src/tests/Feature/SignupCodeTest.php
@@ -29,10 +29,21 @@
$this->assertFalse($code->isExpired());
$this->assertTrue(strlen($code->code) === SignupCode::CODE_LENGTH);
- $this->assertTrue(strlen($code->short_code) === env('VERIFICATION_CODE_LENGTH', SignupCode::SHORTCODE_LENGTH));
+
+ $this->assertTrue(
+ strlen($code->short_code) === env(
+ 'VERIFICATION_CODE_LENGTH',
+ SignupCode::SHORTCODE_LENGTH
+ )
+ );
+
$this->assertSame($data['data'], $code->data);
$this->assertInstanceOf(\DateTime::class, $code->expires_at);
- $this->assertSame(env('SIGNUP_CODE_EXPIRY', SignupCode::CODE_EXP_HOURS), $code->expires_at->diff($now)->h + 1);
+
+ $this->assertSame(
+ env('SIGNUP_CODE_EXPIRY', SignupCode::CODE_EXP_HOURS),
+ $code->expires_at->diff($now)->h + 1
+ );
$inst = SignupCode::find($code->code);
diff --git a/src/tests/Feature/SkuTest.php b/src/tests/Feature/SkuTest.php
--- a/src/tests/Feature/SkuTest.php
+++ b/src/tests/Feature/SkuTest.php
@@ -5,7 +5,6 @@
use App\Domain;
use App\Entitlement;
use App\Handlers;
-use App\Quota;
use App\Sku;
use App\User;
use Tests\TestCase;
@@ -17,8 +16,16 @@
{
parent::setUp();
- User::where('email', 'sku-test-user@custom-domain.com')->delete();
- Domain::where('namespace', 'custom-domain.com')->delete();
+ $this->deleteTestUser('sku-test-user@custom-domain.com');
+ $this->deleteTestDomain('custom-domain.com');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('sku-test-user@custom-domain.com');
+ $this->deleteTestDomain('custom-domain.com');
+
+ parent::tearDown();
}
/**
@@ -35,13 +42,24 @@
]
);
+ \Log::debug(var_export($domain->toArray(), true));
+
$user = $this->getTestUser('sku-test-user@custom-domain.com');
$wallet = $user->wallets()->first();
// \App\Handlers\Mailbox SKU
- // Note, we're testing mailbox SKU before domain SKU as it may potentially fail in that order
+ // Note, we're testing mailbox SKU before domain SKU as it may potentially fail in that
+ // order
$sku = Sku::where('title', 'mailbox')->first();
- $sku->registerEntitlement($user);
+ Entitlement::create(
+ [
+ 'owner_id' => $user->id,
+ 'wallet_id' => $wallet->id,
+ 'sku_id' => $sku->id,
+ 'entitleable_id' => $user->id,
+ 'entitleable_type' => User::class
+ ]
+ );
$entitlements = $sku->entitlements()->where('owner_id', $user->id)->get();
$wallet->refresh();
@@ -50,7 +68,10 @@
$balance = -$sku->cost;
$this->assertCount(1, $entitlements);
$this->assertEquals($user->id, $entitlements[0]->entitleable_id);
- $this->assertSame(Handlers\Mailbox::entitleableClass(), $entitlements[0]->entitleable_type);
+ $this->assertSame(
+ Handlers\Mailbox::entitleableClass(),
+ $entitlements[0]->entitleable_type
+ );
} else {
$this->assertCount(0, $entitlements);
}
@@ -59,16 +80,40 @@
// \App\Handlers\Domain SKU
$sku = Sku::where('title', 'domain')->first();
- $sku->registerEntitlement($user, [$domain]);
+ Entitlement::create(
+ [
+ 'owner_id' => $user->id,
+ 'wallet_id' => $wallet->id,
+ 'sku_id' => $sku->id,
+ 'entitleable_id' => $domain->id,
+ 'entitleable_type' => Domain::class
+ ]
+ );
+
+ $entitlements = $sku->entitlements->where('owner_id', $user->id);
+
+ foreach ($entitlements as $entitlement) {
+ \Log::debug(var_export($entitlement->toArray(), true));
+ }
- $entitlements = $sku->entitlements()->where('owner_id', $user->id)->get();
$wallet->refresh();
if ($sku->active) {
$balance -= $sku->cost;
$this->assertCount(1, $entitlements);
- $this->assertEquals($domain->id, $entitlements[0]->entitleable_id);
- $this->assertSame(Handlers\Domain::entitleableClass(), $entitlements[0]->entitleable_type);
+
+ $_domain = Domain::find($entitlements->first()->entitleable_id);
+
+ $this->assertEquals(
+ $domain->id,
+ $entitlements->first()->entitleable_id,
+ var_export($_domain->toArray(), true)
+ );
+
+ $this->assertSame(
+ Handlers\Domain::entitleableClass(),
+ $entitlements->first()->entitleable_type
+ );
} else {
$this->assertCount(0, $entitlements);
}
@@ -77,16 +122,27 @@
// \App\Handlers\DomainRegistration SKU
$sku = Sku::where('title', 'domain-registration')->first();
- $sku->registerEntitlement($user, [$domain]);
+ Entitlement::create(
+ [
+ 'owner_id' => $user->id,
+ 'wallet_id' => $user->wallets()->get()[0]->id,
+ 'sku_id' => $sku->id,
+ 'entitleable_id' => $domain->id,
+ 'entitleable_type' => Domain::class
+ ]
+ );
- $entitlements = $sku->entitlements()->where('owner_id', $user->id)->get();
+ $entitlements = $sku->entitlements->where('owner_id', $user->id);
$wallet->refresh();
if ($sku->active) {
$balance -= $sku->cost;
$this->assertCount(1, $entitlements);
- $this->assertEquals($domain->id, $entitlements[0]->entitleable_id);
- $this->assertSame(Handlers\DomainRegistration::entitleableClass(), $entitlements[0]->entitleable_type);
+ $this->assertEquals($domain->id, $entitlements->first()->entitleable_id);
+ $this->assertSame(
+ Handlers\DomainRegistration::entitleableClass(),
+ $entitlements->first()->entitleable_type
+ );
} else {
$this->assertCount(0, $entitlements);
}
@@ -95,16 +151,27 @@
// \App\Handlers\DomainHosting SKU
$sku = Sku::where('title', 'domain-hosting')->first();
- $sku->registerEntitlement($user, [$domain]);
+ Entitlement::create(
+ [
+ 'owner_id' => $user->id,
+ 'wallet_id' => $wallet->id,
+ 'sku_id' => $sku->id,
+ 'entitleable_id' => $domain->id,
+ 'entitleable_type' => Domain::class
+ ]
+ );
- $entitlements = $sku->entitlements()->where('owner_id', $user->id)->get();
+ $entitlements = $sku->entitlements->where('owner_id', $user->id);
$wallet->refresh();
if ($sku->active) {
$balance -= $sku->cost;
$this->assertCount(1, $entitlements);
- $this->assertEquals($domain->id, $entitlements[0]->entitleable_id);
- $this->assertSame(Handlers\DomainHosting::entitleableClass(), $entitlements[0]->entitleable_type);
+ $this->assertEquals($domain->id, $entitlements->first()->entitleable_id);
+ $this->assertSame(
+ Handlers\DomainHosting::entitleableClass(),
+ $entitlements->first()->entitleable_type
+ );
} else {
$this->assertCount(0, $entitlements);
}
@@ -113,16 +180,27 @@
// \App\Handlers\Groupware SKU
$sku = Sku::where('title', 'groupware')->first();
- $sku->registerEntitlement($user, [$domain]);
+ Entitlement::create(
+ [
+ 'owner_id' => $user->id,
+ 'wallet_id' => $user->wallets()->get()[0]->id,
+ 'sku_id' => $sku->id,
+ 'entitleable_id' => $user->id,
+ 'entitleable_type' => User::class
+ ]
+ );
- $entitlements = $sku->entitlements()->where('owner_id', $user->id)->get();
+ $entitlements = $sku->entitlements->where('owner_id', $user->id);
$wallet->refresh();
if ($sku->active) {
$balance -= $sku->cost;
$this->assertCount(1, $entitlements);
- $this->assertEquals($user->id, $entitlements[0]->entitleable_id);
- $this->assertSame(Handlers\Mailbox::entitleableClass(), $entitlements[0]->entitleable_type);
+ $this->assertEquals($user->id, $entitlements->first()->entitleable_id);
+ $this->assertSame(
+ Handlers\Mailbox::entitleableClass(),
+ $entitlements->first()->entitleable_type
+ );
} else {
$this->assertCount(0, $entitlements);
}
@@ -131,26 +209,35 @@
// \App\Handlers\Storage SKU
$sku = Sku::where('title', 'storage')->first();
- $sku->registerEntitlement($user, [$domain]);
+ Entitlement::create(
+ [
+ 'owner_id' => $user->id,
+ 'wallet_id' => $wallet->id,
+ 'sku_id' => $sku->id,
+ 'entitleable_id' => $user->id,
+ 'entitleable_type' => User::class
+ ]
+ );
- $entitlements = $sku->entitlements()->where('owner_id', $user->id)->get();
+ $entitlements = $sku->entitlements->where('owner_id', $user->id);
$wallet->refresh();
if ($sku->active) {
$balance -= $sku->cost;
- // For Storage entitlement we expect additional Quota record
- $quota = Quota::where('user_id', $user->id)->first();
- $this->assertTrue(!empty($quota));
- // TODO: This should be a constant and/or config option, and probably
- // quota should not be in bytes
- $this->assertSame(2147483648, $quota->value);
$this->assertCount(1, $entitlements);
- $this->assertEquals($quota->id, $entitlements[0]->entitleable_id);
- $this->assertSame(Handlers\Storage::entitleableClass(), $entitlements[0]->entitleable_type);
} else {
$this->assertCount(0, $entitlements);
}
$this->assertEquals($balance, $wallet->balance);
}
+
+ public function testSkuPackages(): void
+ {
+ $sku = Sku::where('title', 'mailbox')->first();
+
+ $packages = $sku->packages;
+
+ $this->assertCount(2, $packages);
+ }
}
diff --git a/src/tests/Feature/UserTest.php b/src/tests/Feature/UserTest.php
--- a/src/tests/Feature/UserTest.php
+++ b/src/tests/Feature/UserTest.php
@@ -12,7 +12,20 @@
{
parent::setUp();
- User::where('email', 'user-create-test@' . \config('app.domain'))->delete();
+ $this->deleteTestUser('user-create-test@' . \config('app.domain'));
+ $this->deleteTestUser('UserAccountA@UserAccount.com');
+ $this->deleteTestUser('UserAccountB@UserAccount.com');
+ $this->deleteTestUser('userdeletejob@kolabnow.com');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('user-create-test@' . \config('app.domain'));
+ $this->deleteTestUser('UserAccountA@UserAccount.com');
+ $this->deleteTestUser('UserAccountB@UserAccount.com');
+ $this->deleteTestUser('userdeletejob@kolabnow.com');
+
+ parent::tearDown();
}
/**
@@ -87,6 +100,47 @@
$this->assertContains('kolab.org', $domains);
}
+ public function testUserQuota(): void
+ {
+ $user = $this->getTestUser('john@kolab.org');
+ $storage_sku = \App\Sku::where('title', 'storage')->first();
+
+ $count = 0;
+
+ foreach ($user->entitlements()->get() as $entitlement) {
+ if ($entitlement->sku_id == $storage_sku->id) {
+ $count += 1;
+ }
+ }
+
+ $this->assertTrue($count == 2);
+ }
+
+ /**
+ * Test user deletion
+ */
+ public function testUserDelete(): void
+ {
+ $user = $this->getTestUser('userdeletejob@kolabnow.com');
+
+ $package = \App\Package::where('title', 'kolab')->first();
+
+ $user->assignPackage($package);
+
+ $id = $user->id;
+
+ $user->delete();
+
+ $job = new \App\Jobs\UserDelete($id);
+ $job->handle();
+
+ $user->forceDelete();
+
+ $entitlements = \App\Entitlement::where('owner_id', 'id')->get();
+
+ $this->assertCount(0, $entitlements);
+ }
+
/**
* Tests for User::findByEmail()
*/
diff --git a/src/tests/Feature/VerificationCodeTest.php b/src/tests/Feature/VerificationCodeTest.php
--- a/src/tests/Feature/VerificationCodeTest.php
+++ b/src/tests/Feature/VerificationCodeTest.php
@@ -10,6 +10,20 @@
class VerificationCodeTest extends TestCase
{
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $this->deleteTestUser('UserAccountA@UserAccount.com');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('UserAccountA@UserAccount.com');
+
+ parent::tearDown();
+ }
+
/**
* Test VerificationCode creation
*/
diff --git a/src/tests/Feature/WalletTest.php b/src/tests/Feature/WalletTest.php
--- a/src/tests/Feature/WalletTest.php
+++ b/src/tests/Feature/WalletTest.php
@@ -27,15 +27,17 @@
parent::setUp();
foreach ($this->users as $user) {
- User::where('email', $user)->delete();
+ $this->deleteTestUser($user);
}
}
public function tearDown(): void
{
foreach ($this->users as $user) {
- User::where('email', $user)->delete();
+ $this->deleteTestUser($user);
}
+
+ parent::tearDown();
}
/**
@@ -138,7 +140,10 @@
}
);
- $this->assertTrue($userB->accounts()->count() == 1);
+ $this->assertTrue(
+ $userB->accounts()->count() == 1,
+ "number of accounts (1 expected): {$userB->accounts()->count()}"
+ );
$aWallet = $userA->wallets()->get();
$bAccount = $userB->accounts()->get();
diff --git a/src/tests/TestCase.php b/src/tests/TestCase.php
--- a/src/tests/TestCase.php
+++ b/src/tests/TestCase.php
@@ -11,6 +11,35 @@
{
use CreatesApplication;
+ protected function deleteTestDomain($name)
+ {
+ Queue::fake();
+ $domain = Domain::withTrashed()->where('namespace', $name)->first();
+ if (!$domain) {
+ return;
+ }
+
+ $job = new \App\Jobs\DomainDelete($domain);
+ $job->handle();
+
+ $domain->forceDelete();
+ }
+
+ protected function deleteTestUser($email)
+ {
+ Queue::fake();
+ $user = User::withTrashed()->where('email', $email)->first();
+
+ if (!$user) {
+ return;
+ }
+
+ $job = new \App\Jobs\UserDelete($user->id);
+ $job->handle();
+
+ $user->forceDelete();
+ }
+
/**
* Get Domain object by namespace, create it if needed.
* Skip LDAP jobs.