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 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/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,69 @@
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 User|null
+ */
public function retrieveById($identifier)
{
- return parent::retrieveById($identifier);
+ $authenticatable = parent::retrieveById($identifier);
+ return $authenticatable->user;
}
+ /**
+ * 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']);
+ $entries = User::where('email', '=', $credentials['email'])->get();
if ($entries->count() == 1) {
$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 +83,8 @@
if ($hash == $user->password_ldap) {
$authenticated = true;
}
+ } else {
+ \Log::error("Incomplete credentials for {$user->email}");
}
}
@@ -53,6 +92,8 @@
// TODO: Update password if necessary, examine whether writing to
// user->password is sufficient?
if ($authenticated) {
+ \Log::info("Successful authentication for {$user->email}");
+
$user->password = $credentials['password'];
$user->save();
} else {
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 = [
@@ -65,7 +74,7 @@
*/
public function isActive(): bool
{
- return $this->status & self::STATUS_ACTIVE;
+ return ($this->status & self::STATUS_ACTIVE) == true;
}
/**
@@ -75,7 +84,7 @@
*/
public function isConfirmed(): bool
{
- return $this->status & self::STATUS_CONFIRMED;
+ return ($this->status & self::STATUS_CONFIRMED) == true;
}
/**
@@ -85,7 +94,7 @@
*/
public function isDeleted(): bool
{
- return $this->status & self::STATUS_DELETED;
+ return ($this->status & self::STATUS_DELETED) == true;
}
/**
@@ -95,7 +104,7 @@
*/
public function isExternal(): bool
{
- return $this->type & self::TYPE_EXTERNAL;
+ return ($this->type & self::TYPE_EXTERNAL) == true;
}
/**
@@ -105,7 +114,7 @@
*/
public function isHosted(): bool
{
- return $this->type & self::TYPE_HOSTED;
+ return ($this->type & self::TYPE_HOSTED) == true;
}
/**
@@ -115,7 +124,7 @@
*/
public function isNew(): bool
{
- return $this->status & self::STATUS_NEW;
+ return ($this->status & self::STATUS_NEW) == true;
}
/**
@@ -125,7 +134,7 @@
*/
public function isPublic(): bool
{
- return $this->type & self::TYPE_PUBLIC;
+ return ($this->type & self::TYPE_PUBLIC) == true;
}
/**
@@ -135,7 +144,7 @@
*/
public function isLdapReady(): bool
{
- return $this->status & self::STATUS_LDAP_READY;
+ return ($this->status & self::STATUS_LDAP_READY) == true;
}
/**
@@ -145,7 +154,7 @@
*/
public function isSuspended(): bool
{
- return $this->status & self::STATUS_SUSPENDED;
+ return ($this->status & self::STATUS_SUSPENDED) == true;
}
/**
@@ -154,12 +163,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 +184,7 @@
self::STATUS_SUSPENDED,
self::STATUS_DELETED,
self::STATUS_LDAP_READY,
-// self::STATUS_VERIFIED,
+ self::STATUS_VERIFIED,
];
foreach ($allowed_values as $value) {
@@ -232,7 +240,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 +285,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 +306,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
@@ -40,7 +40,7 @@
];
/**
- * Principally entitleable objects such as 'Domain' or 'Mailbox'.
+ * Principally entitleable objects such as 'Domain' or 'User'.
*
* @return mixed
*/
@@ -52,7 +52,7 @@
/**
* The SKU concerned.
*
- * @return Sku
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function sku()
{
@@ -62,7 +62,7 @@
/**
* The owner of this entitlement.
*
- * @return User
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function owner()
{
@@ -72,7 +72,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,14 @@
+sku_id)->active) {
\Log::error("Sku not active");
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()
{
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()
{
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 @@
/**
* Display a listing of the resource.
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse
*/
public function index()
{
@@ -22,7 +22,7 @@
/**
* Show the form for creating a new resource.
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse
*/
public function create()
{
@@ -34,7 +34,7 @@
*
* @param int $id Domain identifier
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse|void
*/
public function confirm($id)
{
@@ -57,7 +57,7 @@
*
* @param int $id
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse
*/
public function destroy($id)
{
@@ -93,7 +93,7 @@
*
* @param int $id Domain identifier
*
- * @return \Illuminate\Http\Response
+ * @return \Illuminate\Http\JsonResponse|void
*/
public function show($id)
{
@@ -197,7 +197,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
*/
@@ -218,15 +218,14 @@
'status' => Domain::STATUS_NEW,
'type' => Domain::TYPE_EXTERNAL,
]);
- }
- // Create SKUs (after domain)
- foreach ($plan->packages as $package) {
- foreach ($package->skus as $sku) {
- $sku->registerEntitlement($user, is_object($domain) ? [$domain] : []);
- }
+ $domain_package = \App\Package::where('title', 'domain-hosting')->first();
+ $domain_package->assign($domain, $user);
}
+ $user_package = \App\Package::where('title', 'kolab')->first();
+ $user_package->assign($user);
+
// Save the external email and plan in user settings
$user->setSettings([
'external_email' => $user_email,
@@ -244,8 +243,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 +296,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()
{
@@ -141,11 +141,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)
{
@@ -155,25 +155,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
@@ -34,6 +34,40 @@
'discount_rate'
];
+ public function assign($object, $user = null)
+ {
+ // if user == null, $object is a user ;-)
+ if ($user === null) {
+ $user = $object;
+ }
+
+ $entitleable_type = null;
+
+ if ($object instanceof \App\Domain) {
+ $entitleable_type = \App\Domain::class;
+ }
+
+ if ($object instanceof \App\User) {
+ $entitleable_type = \App\User::class;
+ }
+
+ $wallet_id = $user->wallets()->get()[0]->id;
+
+ foreach ($this->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' => $entitleable_type ? $object->id : null,
+ 'entitleable_type' => $entitleable_type
+ ]
+ );
+ }
+ }
+ }
+
public function cost()
{
$costs = 0;
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
@@ -11,6 +11,8 @@
*
* 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
{
@@ -58,6 +60,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(
@@ -74,7 +85,9 @@
}
/**
- * 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
{
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,6 +30,11 @@
'discount_rate' => 'integer'
];
+ /**
+ * Calculate the costs for this plan.
+ *
+ * @return integer
+ */
public function cost()
{
$costs = 0;
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,18 +83,51 @@
/**
* 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
+ * @param \App\User|null $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;
+ }
+
/**
* List the domains to which this user is entitled.
*
@@ -97,7 +135,7 @@
*/
public function domains()
{
- $domains = Domain::whereRaw(
+ $dbdomains = Domain::whereRaw(
sprintf(
'(type & %s) AND (status & %s)',
Domain::TYPE_PUBLIC,
@@ -105,19 +143,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 +180,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 +235,7 @@
*/
public function isActive(): bool
{
- return $this->status & self::STATUS_ACTIVE;
+ return ($this->status & self::STATUS_ACTIVE) == true;
}
/**
@@ -197,7 +245,7 @@
*/
public function isDeleted(): bool
{
- return $this->status & self::STATUS_DELETED;
+ return ($this->status & self::STATUS_DELETED) == true;
}
/**
@@ -208,7 +256,7 @@
*/
public function isImapReady(): bool
{
- return $this->status & self::STATUS_IMAP_READY;
+ return ($this->status & self::STATUS_IMAP_READY) == true;
}
/**
@@ -218,7 +266,7 @@
*/
public function isLdapReady(): bool
{
- return $this->status & self::STATUS_LDAP_READY;
+ return ($this->status & self::STATUS_LDAP_READY) == true;
}
/**
@@ -228,7 +276,7 @@
*/
public function isNew(): bool
{
- return $this->status & self::STATUS_NEW;
+ return ($this->status & self::STATUS_NEW) == true;
}
/**
@@ -238,13 +286,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 +302,7 @@
/**
* Verification codes for this user.
*
- * @return VerificationCode[]
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function verificationcodes()
{
@@ -264,13 +312,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 +336,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.5",
"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,14 +13,16 @@
*/
public function up()
{
+ /*
Schema::create('quotas', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id');
- $table->integer('value')->default(2147483648);
+ $table->unsignedInteger('value')->default(2147483648);
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
+ */
}
/**
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/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();
+
+ $package_domain->assign($domain, $john);
+ $package_kolab->assign($john);
+
+ $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, 50)->create();
}
}
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
@@ -23,6 +23,9 @@
./app
+
+
+
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
@@ -25,7 +25,7 @@
public function tearDown(): void
{
User::where('email', 'passwordresettest@' . \config('app.domain'))
- ->delete();
+ ->forceDelete();
}
/**
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,16 @@
{
parent::setUp();
- User::where('email', 'UsersControllerTest1@userscontroller.com')->delete();
- Domain::where('namespace', 'userscontroller.com')->delete();
+ $this->deleteTestUser('UsersControllerTest1@userscontroller.com');
+ $this->deleteTestDomain('userscontroller.com');
+ }
+
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('UsersControllerTest1@userscontroller.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,44 @@
+forceDelete();
+ }
+
+ 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);
+ }
+
+ public function tearDown(): void
+ {
+ User::where('email', 'jane@kolab.org')->forceDelete();
+ parent::tearDown();
+ }
+}
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,28 @@
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();
+ Domain::withTrashed()->whereIn('namespace', $this->domains)->forceDelete();
+ }
+
+ public function tearDown(): void
+ {
+ Domain::whereIn('namespace', $this->domains)->delete();
+
+ parent::tearDown();
}
/**
@@ -52,25 +59,9 @@
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;
- });
-*/
+ $job = new \App\Jobs\DomainCreate($domain);
+ $job->handle();
}
/**
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
@@ -18,7 +18,7 @@
Domain::where('namespace', 'gmail.com')
->orWhere('namespace', 'some-non-existing-domain.fff')
- ->delete();
+ ->forceDelete();
}
/**
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
@@ -38,7 +38,9 @@
*/
public function tearDown(): void
{
- $this->code->user->delete();
+ $this->code->user->forceDelete();
+
+ parent::tearDown();
}
/**
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,7 @@
{
parent::setUp();
- User::where('email', 'new-job-user@' . \config('app.domain'))->delete();
+ $this->deleteTestUser('new-job-user@' . \config('app.domain'));
}
/**
@@ -28,11 +28,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,7 @@
{
parent::setUp();
- User::where('email', 'new-job-user@' . \config('app.domain'))->delete();
+ User::where('email', 'new-job-user@' . \config('app.domain'))->forceDelete();
}
/**
@@ -28,24 +28,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/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,22 +209,22 @@
// \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);
}
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,43 @@
$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();
+ }
+
/**
* Tests for User::findByEmail()
*/
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,14 +27,14 @@
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);
}
}
@@ -138,7 +138,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.