Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
30 KB
Referenced Files
None
Subscribers
None
diff --git a/bin/quickstart.sh b/bin/quickstart.sh
index 67885bf2..d2621dbf 100755
--- a/bin/quickstart.sh
+++ b/bin/quickstart.sh
@@ -1,82 +1,82 @@
#!/bin/bash
set -e
function die() {
echo "$1"
exit 1
}
rpm -qv composer >/dev/null 2>&1 || \
test ! -z "$(which composer 2>/dev/null)" || \
die "Is composer installed?"
rpm -qv docker-compose >/dev/null 2>&1 || \
test ! -z "$(which docker-compose 2>/dev/null)" || \
die "Is docker-compose installed?"
rpm -qv npm >/dev/null 2>&1 || \
test ! -z "$(which npm 2>/dev/null)" || \
die "Is npm installed?"
rpm -qv php >/dev/null 2>&1 || \
test ! -z "$(which php 2>/dev/null)" || \
die "Is php installed?"
rpm -qv php-ldap >/dev/null 2>&1 || \
test ! -z "$(php --ini | grep ldap)" || \
die "Is php-ldap installed?"
rpm -qv php-mysqlnd >/dev/null 2>&1 || \
test ! -z "$(php --ini | grep mysql)" || \
die "Is php-mysqlnd installed?"
base_dir=$(dirname $(dirname $0))
bin/regen-certs
docker pull kolab/centos7:latest
docker-compose down
docker-compose build
docker-compose up -d kolab mariadb redis
pushd ${base_dir}/src/
cp .env.example .env
if [ -f ".env.local" ]; then
# Ensure there's a line ending
echo "" >> .env
cat .env.local >> .env
fi
rm -rf vendor/ composer.lock
composer install
npm install
find bootstrap/cache/ -type f ! -name ".gitignore" -delete
./artisan key:generate
./artisan jwt:secret -f
./artisan clear-compiled
./artisan cache:clear
if [ ! -z "$(rpm -qv chromium 2>/dev/null)" ]; then
chver=$(rpmquery --queryformat="%{VERSION}" chromium | awk -F'.' '{print $1}')
./artisan dusk:chrome-driver ${chver}
fi
if [ ! -f 'resources/countries.php' ]; then
./artisan data:countries
fi
npm run dev
popd
-docker-compose up -d worker
+docker-compose up -d worker nginx
pushd ${base_dir}/src/
rm -rf database/database.sqlite
php -dmemory_limit=512M ./artisan migrate:refresh --seed
./artisan serve
popd
diff --git a/bin/regen-certs b/bin/regen-certs
index 30e76274..c02869a9 100755
--- a/bin/regen-certs
+++ b/bin/regen-certs
@@ -1,65 +1,65 @@
#!/bin/bash
base_dir=$(dirname $(dirname $0))
base_dir="${base_dir}/docker/certs/"
if [ ! -d "${base_dir}" ]; then
mkdir -p ${base_dir}
fi
if [ ! -f "${base_dir}/ca.key" ]; then
openssl genrsa -out ${base_dir}/ca.key 4096
openssl req \
-new \
-x509 \
-nodes \
-days 3650 \
-key ${base_dir}/ca.key \
-out ${base_dir}/ca.cert \
-subj '/O=Example CA/'
fi
if [ -f /etc/pki/tls/openssl.cnf ]; then
openssl_cnf="/etc/pki/tls/openssl.cnf"
elif [ -f /etc/ssl/openssl.cnf ]; then
openssl_cnf="/etc/ssl/openssl.cnf"
else
echo "No openssl.cnf"
exit 1
fi
-for name in kolab.mgmt.com kolab.hosted.com; do
+for name in kolab.mgmt.com kolab.hosted.com imap.hosted.com; do
openssl genrsa -out ${base_dir}/${name}.key 4096
openssl req \
-new \
-key ${base_dir}/${name}.key \
-out ${base_dir}/${name}.csr \
-subj "/O=Example CA/CN=${name}/" \
-reqexts SAN \
-config <(cat ${openssl_cnf} \
<(printf "[SAN]\nsubjectAltName=DNS:${name}"))
openssl x509 \
-req \
-in ${base_dir}/${name}.csr \
-CA ${base_dir}/ca.cert \
-CAkey ${base_dir}/ca.key \
-CAcreateserial \
-out ${base_dir}/${name}.cert \
-days 28 \
-extfile <(cat ${openssl_cnf} \
<(printf "[SAN]\nsubjectAltName=DNS:${name}")) \
-extensions SAN
# 'cause java ...
openssl pkcs8 \
-topk8 \
-inform pem \
-in ${base_dir}/${name}.key \
-outform pem \
-nocrypt \
-out ${base_dir}/${name}_p8.key
done
diff --git a/docker-compose.yml b/docker-compose.yml
index 76e13a90..310ece71 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,73 +1,90 @@
version: '2.1'
services:
kolab:
build:
context: ./docker/kolab/
container_name: kolab
depends_on:
mariadb:
condition: service_healthy
extra_hosts:
- "kolab.mgmt.com:127.0.0.1"
healthcheck:
interval: 10s
test: test -f /tmp/kolab-init.done
timeout: 5s
retries: 30
hostname: kolab.mgmt.com
image: kolab
network_mode: host
tmpfs:
- /run
- /tmp
- /var/run
- /var/tmp
tty: true
volumes:
- ./docker/certs/ca.cert:/etc/pki/tls/certs/ca.cert:ro
- ./docker/certs/ca.cert:/etc/pki/ca-trust/source/anchors/ca.cert:ro
- ./docker/certs/kolab.hosted.com.cert:/etc/pki/tls/certs/kolab.hosted.com.cert
- ./docker/certs/kolab.hosted.com.key:/etc/pki/tls/certs/kolab.hosted.com.key
- ./docker/certs/kolab.mgmt.com.cert:/etc/pki/tls/certs/kolab.mgmt.com.cert
- ./docker/certs/kolab.mgmt.com.key:/etc/pki/tls/certs/kolab.mgmt.com.key
- ./docker/kolab/utils:/root/utils:ro
- /sys/fs/cgroup:/sys/fs/cgroup:ro
mariadb:
container_name: kolab-mariadb
environment:
MYSQL_ROOT_PASSWORD: Welcome2KolabSystems
healthcheck:
interval: 10s
test: test -e /var/run/mysqld/mysqld.sock
timeout: 5s
retries: 30
image: mariadb
network_mode: host
+ nginx:
+ build:
+ context: ./docker/nginx/
+ container_name: kolab-nginx
+ hostname: nginx.hosted.com
+ image: kolab-nginx
+ network_mode: host
+ tmpfs:
+ - /run
+ - /tmp
+ - /var/run
+ - /var/tmp
+ tty: true
+ volumes:
+ - ./docker/certs/imap.hosted.com.cert:/etc/pki/tls/certs/imap.hosted.com.cert
+ - ./docker/certs/imap.hosted.com.key:/etc/pki/tls/private/imap.hosted.com.key
+ - /sys/fs/cgroup:/sys/fs/cgroup:ro
redis:
build:
context: ./docker/redis/
container_name: kolab-redis
hostname: redis
image: redis
network_mode: host
volumes:
- ./docker/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
worker:
build:
context: ./docker/worker/
container_name: kolab-worker
depends_on:
kolab:
condition: service_healthy
hostname: worker
image: kolab-worker
network_mode: host
tmpfs:
- /run
- /tmp
- /var/run
- /var/tmp
tty: true
volumes:
- ./src:/home/worker/src.orig:ro
- /sys/fs/cgroup:/sys/fs/cgroup:ro
diff --git a/docker/kolab/Dockerfile b/docker/kolab/Dockerfile
index 9b0a6aa7..7dc12fe9 100644
--- a/docker/kolab/Dockerfile
+++ b/docker/kolab/Dockerfile
@@ -1,25 +1,25 @@
FROM kolab/centos7:latest
RUN yum -y install rsyslog && \
yum --enablerepo=kolab-16-updates-testing -y update pykolab && \
yum clean all
COPY kolab-init.service /etc/systemd/system/kolab-init.service
COPY kolab-vlv.service /etc/systemd/system/kolab-vlv.service
RUN rm -rf /etc/systemd/system/multi-user.target.wants/{avahi-daemon,sshd}.* && \
ln -s /etc/systemd/system/kolab-init.service \
/etc/systemd/system/multi-user.target.wants/kolab-init.service && \
ln -s /etc/systemd/system/kolab-vlv.service \
/etc/systemd/system/multi-user.target.wants/kolab-vlv.service
RUN sed -i -r -e 's/^SELINUX=.*$/SELINUX=permissive/g' /etc/selinux/config 2>/dev/null || :
COPY kolab-init.sh /usr/local/sbin/
RUN chmod 750 /usr/local/sbin/kolab-init.sh
COPY kolab-vlv.sh /usr/local/sbin/
RUN chmod 750 /usr/local/sbin/kolab-vlv.sh
CMD ["/lib/systemd/systemd"]
-EXPOSE 21/tcp 22/tcp 25/tcp 53/tcp 53/udp 80/tcp 110/tcp 143/tcp 389/tcp 443/tcp 465/tcp 587/tcp 993/tcp 995/tcp 5353/udp 8880/tcp 8443/tcp 8447/tcp
+EXPOSE 21/tcp 22/tcp 25/tcp 53/tcp 53/udp 80/tcp 110/tcp 143/tcp 389/tcp 443/tcp 465/tcp 587/tcp 993/tcp 995/tcp 5353/udp 8880/tcp 8443/tcp 8447/tcp 9143/tcp 9993/tcp 10143/tcp
diff --git a/docker/kolab/utils/09-enable-debugging.sh b/docker/kolab/utils/09-enable-debugging.sh
index 81b612e1..7cfcd9aa 100755
--- a/docker/kolab/utils/09-enable-debugging.sh
+++ b/docker/kolab/utils/09-enable-debugging.sh
@@ -1,8 +1,22 @@
#!/bin/bash
echo "chatty: 1" >> /etc/imapd.conf
echo "debug: 1" >> /etc/imapd.conf
+sed -i -r \
+ -e '/allowplaintext/ a\
+imaplain_allowplaintext: yes' \
+ /etc/imapd.conf
+
+cp /etc/cyrus.conf /etc/cyrus.conf.orig
+
+sed -i \
+ -e '/SERVICES/ a\
+ imaplain cmd="imapd" listen=127.0.0.1:10143 prefork=1' \
+ -e '/SERVICES/ a\
+ imap cmd="imapd" listen=127.0.0.1:9143 prefork=1' \
+ /etc/cyrus.conf
+
systemctl restart cyrus-imapd
sed -i -r -e "s/_debug'] = (.*);/_debug'] = true;/g" /etc/roundcubemail/config.inc.php
diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile
new file mode 100644
index 00000000..6449a7df
--- /dev/null
+++ b/docker/nginx/Dockerfile
@@ -0,0 +1,20 @@
+FROM fedora:31
+
+RUN dnf -y install \
+ nginx \
+ nginx-mod-mail \
+ rsyslog && \
+ dnf clean all
+
+RUN sed -i -r -e 's/^SELINUX=.*$/SELINUX=permissive/g' /etc/selinux/config 2>/dev/null || :
+
+COPY nginx.conf /etc/nginx/nginx.conf
+
+#RUN /usr/sbin/nginx -t
+
+RUN ln -s /usr/lib/systemd/system/nginx.service \
+ /etc/systemd/system/multi-user.target.wants/nginx.service
+
+CMD ["/lib/systemd/systemd"]
+
+EXPOSE 110/tcp 143/tcp 993/tcp 995/tcp
diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf
new file mode 100644
index 00000000..8ad776f2
--- /dev/null
+++ b/docker/nginx/nginx.conf
@@ -0,0 +1,45 @@
+user nginx;
+worker_processes auto;
+error_log /var/log/nginx/error.log debug;
+pid /run/nginx.pid;
+
+# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
+include /usr/share/nginx/modules/*.conf;
+
+events {
+ worker_connections 1024;
+}
+
+mail {
+ server_name imap.hosted.com;
+ auth_http 127.0.0.1:8000/api/webhooks/nginx;
+
+ proxy_pass_error_message on;
+
+ server {
+ listen 1143;
+ protocol imap;
+
+ proxy on;
+ starttls on;
+
+ ssl_certificate /etc/pki/tls/certs/imap.hosted.com.cert;
+ ssl_certificate_key /etc/pki/tls/private/imap.hosted.com.key;
+
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+ }
+
+ server {
+ listen 1993 ssl;
+ protocol imap;
+
+ proxy on;
+
+ ssl_certificate /etc/pki/tls/certs/imap.hosted.com.cert;
+ ssl_certificate_key /etc/pki/tls/private/imap.hosted.com.key;
+
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+ }
+}
diff --git a/src/.gitignore b/src/.gitignore
index 266ea4c4..18fe9c80 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,20 +1,21 @@
database/database.sqlite
node_modules/
package-lock.json
public/css/app.css
public/hot
public/js/app.js
public/storage/
storage/*.key
storage/export/
vendor
.env
.env.backup
+.env.local
.env.testing
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
composer.lock
resources/countries.php
diff --git a/src/app/Console/Commands/UserStatus.php b/src/app/Console/Commands/UserStatus.php
new file mode 100644
index 00000000..10eff915
--- /dev/null
+++ b/src/app/Console/Commands/UserStatus.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\User;
+use Illuminate\Console\Command;
+
+class UserStatus extends Command
+{
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'user:status {user}';
+
+ /**
+ * The console command description.
+ *
+ * @var string
+ */
+ protected $description = 'Display the status of a user';
+
+ /**
+ * Create a new command instance.
+ *
+ * @return void
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+ /**
+ * Execute the console command.
+ *
+ * @return mixed
+ */
+ public function handle()
+ {
+ $user = User::where('email', $this->argument('user'))->first();
+
+ if (!$user) {
+ return 1;
+ }
+
+ $this->info("Found user: {$user->id}");
+
+ $this->info($user->status);
+ }
+}
diff --git a/src/app/Console/Commands/UserSuspend.php b/src/app/Console/Commands/UserSuspend.php
new file mode 100644
index 00000000..d0f90ede
--- /dev/null
+++ b/src/app/Console/Commands/UserSuspend.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\User;
+use Illuminate\Console\Command;
+
+class UserSuspend extends Command
+{
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'user:suspend {user}';
+
+ /**
+ * The console command description.
+ *
+ * @var string
+ */
+ protected $description = 'Suspend a user';
+
+ /**
+ * Create a new command instance.
+ *
+ * @return void
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+ /**
+ * Execute the console command.
+ *
+ * @return mixed
+ */
+ public function handle()
+ {
+ $user = User::where('email', $this->argument('user'))->first();
+
+ if (!$user) {
+ return 1;
+ }
+
+ $this->info("Found user: {$user->id}");
+
+ $user->suspend();
+ }
+}
diff --git a/src/app/Console/Commands/UserUnsuspend.php b/src/app/Console/Commands/UserUnsuspend.php
new file mode 100644
index 00000000..8497de6a
--- /dev/null
+++ b/src/app/Console/Commands/UserUnsuspend.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\User;
+use Illuminate\Console\Command;
+
+class UserUnsuspend extends Command
+{
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'user:unsuspend {user}';
+
+ /**
+ * The console command description.
+ *
+ * @var string
+ */
+ protected $description = 'Remove a user suspension';
+
+ /**
+ * Create a new command instance.
+ *
+ * @return void
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+ /**
+ * Execute the console command.
+ *
+ * @return mixed
+ */
+ public function handle()
+ {
+ $user = User::where('email', $this->argument('user'))->first();
+
+ if (!$user) {
+ return 1;
+ }
+
+ $this->info("Found user {$user->id}");
+
+ $user->unsuspend();
+ }
+}
diff --git a/src/app/Http/Controllers/API/NGINXController.php b/src/app/Http/Controllers/API/NGINXController.php
new file mode 100644
index 00000000..73caf4f0
--- /dev/null
+++ b/src/app/Http/Controllers/API/NGINXController.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace App\Http\Controllers\API;
+
+use App\Http\Controllers\Controller;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Validator;
+
+class NGINXController extends Controller
+{
+ /**
+ * Authentication request.
+ *
+ * @param \Illuminate\Http\Request $request The API request.
+ *
+ * @return \Illuminate\Http\Response The response
+ */
+ public function authenticate(Request $request)
+ {
+ /**
+ * Auth-Login-Attempt: 1
+ * Auth-Method: plain
+ * Auth-Pass: simple123
+ * Auth-Protocol: imap
+ * Auth-Ssl: on
+ * Auth-User: john@kolab.org
+ * Client-Ip: 127.0.0.1
+ * Host: 127.0.0.1
+ *
+ * Auth-SSL: on
+ * Auth-SSL-Verify: SUCCESS
+ * Auth-SSL-Subject: /CN=example.com
+ * Auth-SSL-Issuer: /CN=example.com
+ * Auth-SSL-Serial: C07AD56B846B5BFF
+ * Auth-SSL-Fingerprint: 29d6a80a123d13355ed16b4b04605e29cb55a5ad
+ */
+ \Log::debug($request->headers);
+
+ $response = response("")->withHeaders(
+ [
+ "Auth-Status" => 'OK',
+ "Auth-Server" => '127.0.0.1',
+ "Auth-Port" => '10143',
+ "Auth-Pass" => $request->headers->get('Auth-Pass')
+ ]
+ );
+
+ \Log::debug($response->headers);
+
+ return $response;
+ }
+}
diff --git a/src/routes/api.php b/src/routes/api.php
index ab75bd80..9571281a 100644
--- a/src/routes/api.php
+++ b/src/routes/api.php
@@ -1,57 +1,58 @@
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::group(
[
'middleware' => 'api',
'prefix' => 'auth'
],
function ($router) {
Route::get('info', 'API\UsersController@info');
Route::post('login', 'API\UsersController@login');
Route::post('logout', 'API\UsersController@logout');
Route::post('refresh', 'API\UsersController@refresh');
Route::post('password-reset/init', 'API\PasswordResetController@init');
Route::post('password-reset/verify', 'API\PasswordResetController@verify');
Route::post('password-reset', 'API\PasswordResetController@reset');
Route::get('signup/plans', 'API\SignupController@plans');
Route::post('signup/init', 'API\SignupController@init');
Route::post('signup/verify', 'API\SignupController@verify');
Route::post('signup', 'API\SignupController@signup');
}
);
Route::group(
[
'middleware' => 'auth:api',
'prefix' => 'v4'
],
function () {
Route::apiResource('domains', API\DomainsController::class);
Route::get('domains/{id}/confirm', 'API\DomainsController@confirm');
Route::apiResource('entitlements', API\EntitlementsController::class);
Route::apiResource('packages', API\PackagesController::class);
Route::apiResource('skus', API\SkusController::class);
Route::apiResource('users', API\UsersController::class);
Route::apiResource('wallets', API\WalletsController::class);
Route::post('payments', 'API\PaymentsController@store');
}
);
+Route::get('webhooks/nginx', 'API\NGINXController@authenticate');
Route::post('webhooks/payment/mollie', 'API\PaymentsController@webhook');
diff --git a/src/tests/Feature/UserTest.php b/src/tests/Feature/UserTest.php
index a80c8961..984f1cb9 100644
--- a/src/tests/Feature/UserTest.php
+++ b/src/tests/Feature/UserTest.php
@@ -1,371 +1,377 @@
<?php
namespace Tests\Feature;
use App\Domain;
use App\User;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
class UserTest extends TestCase
{
public function setUp(): void
{
parent::setUp();
- $this->deleteTestUser('user-create-test@' . \config('app.domain'));
- $this->deleteTestUser('userdeletejob@kolabnow.com');
+ $this->deleteTestUser('test@' . \config('app.domain'));
+ $this->deleteTestUser('userdeletejob@' . \config('app.domain'));
$this->deleteTestUser('UserAccountA@UserAccount.com');
$this->deleteTestUser('UserAccountB@UserAccount.com');
$this->deleteTestUser('UserAccountC@UserAccount.com');
$this->deleteTestDomain('UserAccount.com');
}
public function tearDown(): void
{
- $this->deleteTestUser('user-create-test@' . \config('app.domain'));
- $this->deleteTestUser('userdeletejob@kolabnow.com');
+ $this->deleteTestUser('test@' . \config('app.domain'));
+ $this->deleteTestUser('userdeletejob@' . \config('app.domain'));
$this->deleteTestUser('UserAccountA@UserAccount.com');
$this->deleteTestUser('UserAccountB@UserAccount.com');
$this->deleteTestUser('UserAccountC@UserAccount.com');
$this->deleteTestDomain('UserAccount.com');
parent::tearDown();
}
/**
* Tests for User::assignPackage()
*/
public function testAssignPackage(): void
{
$this->markTestIncomplete();
+
+ $package = \App\Package::where('title', 'kolab')->first();
+
+ $user = $this->getTestUser('test@' . \config('app.domain'));
+
+ $user->assignPackage($package);
}
/**
* Tests for User::assignPlan()
*/
public function testAssignPlan(): void
{
$this->markTestIncomplete();
}
/**
* Tests for User::assignSku()
*/
public function testAssignSku(): void
{
$this->markTestIncomplete();
}
/**
* Verify user creation process
*/
public function testUserCreateJob(): void
{
// Fake the queue, assert that no jobs were pushed...
Queue::fake();
Queue::assertNothingPushed();
$user = User::create([
- 'email' => 'user-create-test@' . \config('app.domain')
+ 'email' => 'test@' . \config('app.domain')
]);
Queue::assertPushed(\App\Jobs\UserCreate::class, 1);
Queue::assertPushed(\App\Jobs\UserCreate::class, function ($job) use ($user) {
$job_user = TestCase::getObjectProperty($job, 'user');
return $job_user->id === $user->id
&& $job_user->email === $user->email;
});
Queue::assertPushedWithChain(\App\Jobs\UserCreate::class, [
\App\Jobs\UserVerify::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\UserVerify::class, 1);
Queue::assertPushed(\App\Jobs\UserVerify::class, function ($job) use ($user) {
$job_user = TestCase::getObjectProperty($job, 'user');
return $job_user->id === $user->id
&& $job_user->email === $user->email;
});
*/
}
/**
* Verify a wallet assigned a controller is among the accounts of the assignee.
*/
public function testListUserAccounts(): void
{
$userA = $this->getTestUser('UserAccountA@UserAccount.com');
$userB = $this->getTestUser('UserAccountB@UserAccount.com');
$this->assertTrue($userA->wallets()->count() == 1);
$userA->wallets()->each(
function ($wallet) use ($userB) {
$wallet->addController($userB);
}
);
$this->assertTrue($userB->accounts()->get()[0]->id === $userA->wallets()->get()[0]->id);
}
public function testAccounts(): void
{
$this->markTestIncomplete();
}
public function testCanDelete(): void
{
$this->markTestIncomplete();
}
public function testCanRead(): void
{
$this->markTestIncomplete();
}
public function testCanUpdate(): void
{
$this->markTestIncomplete();
}
/**
* Tests for User::domains()
*/
public function testDomains(): void
{
$user = $this->getTestUser('john@kolab.org');
$domains = [];
foreach ($user->domains() as $domain) {
$domains[] = $domain->namespace;
}
$this->assertContains(\config('app.domain'), $domains);
$this->assertContains('kolab.org', $domains);
// Jack is not the wallet controller, so for him the list should not
// include John's domains, kolab.org specifically
$user = $this->getTestUser('jack@kolab.org');
$domains = [];
foreach ($user->domains() as $domain) {
$domains[] = $domain->namespace;
}
$this->assertContains(\config('app.domain'), $domains);
$this->assertNotContains('kolab.org', $domains);
}
public function testUserQuota(): void
{
// TODO: This test does not test much, probably could be removed
// or moved to somewhere else, or extended with
// other entitlements() related cases.
$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 testDelete(): void
{
Queue::fake();
- $user = $this->getTestUser('userdeletejob@kolabnow.com');
+ $user = $this->getTestUser('userdeletejob@' . \config('app.domain'));
$package = \App\Package::where('title', 'kolab')->first();
$user->assignPackage($package);
$id = $user->id;
$this->assertCount(4, $user->entitlements()->get());
$user->delete();
$this->assertCount(0, $user->entitlements()->get());
$this->assertTrue($user->fresh()->trashed());
$this->assertFalse($user->fresh()->isDeleted());
// Delete the user for real
$job = new \App\Jobs\UserDelete($id);
$job->handle();
$this->assertTrue(User::withTrashed()->where('id', $id)->first()->isDeleted());
$user->forceDelete();
$this->assertCount(0, User::withTrashed()->where('id', $id)->get());
// Test an account with users
$userA = $this->getTestUser('UserAccountA@UserAccount.com');
$userB = $this->getTestUser('UserAccountB@UserAccount.com');
$userC = $this->getTestUser('UserAccountC@UserAccount.com');
$package_kolab = \App\Package::where('title', 'kolab')->first();
$package_domain = \App\Package::where('title', 'domain-hosting')->first();
$domain = $this->getTestDomain('UserAccount.com', [
'status' => Domain::STATUS_NEW,
'type' => Domain::TYPE_HOSTED,
]);
$userA->assignPackage($package_kolab);
$domain->assignPackage($package_domain, $userA);
$userA->assignPackage($package_kolab, $userB);
$userA->assignPackage($package_kolab, $userC);
$entitlementsA = \App\Entitlement::where('entitleable_id', $userA->id);
$entitlementsB = \App\Entitlement::where('entitleable_id', $userB->id);
$entitlementsC = \App\Entitlement::where('entitleable_id', $userC->id);
$entitlementsDomain = \App\Entitlement::where('entitleable_id', $domain->id);
$this->assertSame(4, $entitlementsA->count());
$this->assertSame(4, $entitlementsB->count());
$this->assertSame(4, $entitlementsC->count());
$this->assertSame(1, $entitlementsDomain->count());
// Delete non-controller user
$userC->delete();
$this->assertTrue($userC->fresh()->trashed());
$this->assertFalse($userC->fresh()->isDeleted());
$this->assertSame(0, $entitlementsC->count());
// Delete the controller (and expect "sub"-users to be deleted too)
$userA->delete();
$this->assertSame(0, $entitlementsA->count());
$this->assertSame(0, $entitlementsB->count());
$this->assertSame(0, $entitlementsDomain->count());
$this->assertTrue($userA->fresh()->trashed());
$this->assertTrue($userB->fresh()->trashed());
$this->assertTrue($domain->fresh()->trashed());
$this->assertFalse($userA->isDeleted());
$this->assertFalse($userB->isDeleted());
$this->assertFalse($domain->isDeleted());
}
/**
* Tests for User::findByEmail()
*/
public function testFindByEmail(): void
{
$user = $this->getTestUser('john@kolab.org');
$result = User::findByEmail('john');
$this->assertNull($result);
$result = User::findByEmail('non-existing@email.com');
$this->assertNull($result);
$result = User::findByEmail('john@kolab.org');
$this->assertInstanceOf(User::class, $result);
$this->assertSame($user->id, $result->id);
// Use an alias
$result = User::findByEmail('john.doe@kolab.org');
$this->assertInstanceOf(User::class, $result);
$this->assertSame($user->id, $result->id);
// TODO: searching by external email (setting)
$this->markTestIncomplete();
}
/**
* Tests for UserAliasesTrait::setAliases()
*/
public function testSetAliases(): void
{
Queue::fake();
$user = $this->getTestUser('UserAccountA@UserAccount.com');
$this->assertCount(0, $user->aliases->all());
// Add an alias
$user->setAliases(['UserAlias1@UserAccount.com']);
$aliases = $user->aliases()->get();
$this->assertCount(1, $aliases);
$this->assertSame('useralias1@useraccount.com', $aliases[0]['alias']);
// Add another alias
$user->setAliases(['UserAlias1@UserAccount.com', 'UserAlias2@UserAccount.com']);
$aliases = $user->aliases()->orderBy('alias')->get();
$this->assertCount(2, $aliases);
$this->assertSame('useralias1@useraccount.com', $aliases[0]->alias);
$this->assertSame('useralias2@useraccount.com', $aliases[1]->alias);
// Remove an alias
$user->setAliases(['UserAlias1@UserAccount.com']);
$aliases = $user->aliases()->get();
$this->assertCount(1, $aliases);
$this->assertSame('useralias1@useraccount.com', $aliases[0]['alias']);
// Remove all aliases
$user->setAliases([]);
$this->assertCount(0, $user->aliases()->get());
// TODO: Test that the changes are propagated to ldap
}
/**
* Tests for UserSettingsTrait::setSettings()
*/
public function testSetSettings(): void
{
$this->markTestIncomplete();
}
/**
* Tests for User::users()
*/
public function testUsers(): void
{
$john = $this->getTestUser('john@kolab.org');
$jack = $this->getTestUser('jack@kolab.org');
$ned = $this->getTestUser('ned@kolab.org');
$wallet = $john->wallets()->first();
$users = $john->users()->orderBy('email')->get();
$this->assertCount(3, $users);
$this->assertEquals($jack->id, $users[0]->id);
$this->assertEquals($john->id, $users[1]->id);
$this->assertEquals($ned->id, $users[2]->id);
$this->assertSame($wallet->id, $users[0]->wallet_id);
$this->assertSame($wallet->id, $users[1]->wallet_id);
$this->assertSame($wallet->id, $users[2]->wallet_id);
$users = $jack->users()->orderBy('email')->get();
$this->assertCount(0, $users);
$users = $ned->users()->orderBy('email')->get();
$this->assertCount(3, $users);
}
public function testWallets(): void
{
$this->markTestIncomplete();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Apr 4 2026, 10:09 AM (4 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18773364
Default Alt Text
(30 KB)

Event Timeline