mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-18 10:28:07 +00:00
Compare commits
76 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a1f3471d6 | ||
|
|
85c939b4da | ||
|
|
f883c3cee7 | ||
|
|
06dc357524 | ||
|
|
4d601c4a9c | ||
|
|
09d386a303 | ||
|
|
0740bd0425 | ||
|
|
d179d0f6df | ||
|
|
25ddd330c1 | ||
|
|
e0f33da4ac | ||
|
|
ae4a651f2a | ||
|
|
593d7ce5c0 | ||
|
|
6fcde1b467 | ||
|
|
789c27f654 | ||
|
|
a53910d364 | ||
|
|
abcc9c1c7b | ||
|
|
26aaab2f07 | ||
|
|
fe265a972d | ||
|
|
98d9d76225 | ||
|
|
9aeeb0fa73 | ||
|
|
57e09cc4de | ||
|
|
ed28e8fe55 | ||
|
|
689140a553 | ||
|
|
7221d55ff8 | ||
|
|
0e3b0d36d8 | ||
|
|
10cdbb4b6a | ||
|
|
b0de4841f6 | ||
|
|
a98c8764d5 | ||
|
|
fbf47fc9c9 | ||
|
|
6240f81f14 | ||
|
|
edbe49d404 | ||
|
|
d8f0c47d8f | ||
|
|
6770e198d9 | ||
|
|
5f22c8c862 | ||
|
|
a56de2e93a | ||
|
|
38f0120ecc | ||
|
|
abe67c9734 | ||
|
|
ee2c9fed8f | ||
|
|
e0a9b75923 | ||
|
|
2a3634d461 | ||
|
|
2ec4f488b6 | ||
|
|
60df61d508 | ||
|
|
9a9b8ab34e | ||
|
|
a876a8cf82 | ||
|
|
a5eeb06055 | ||
|
|
4d0c713174 | ||
|
|
507e913241 | ||
|
|
1a79ae7b16 | ||
|
|
dcb071b5bc | ||
|
|
005072e301 | ||
|
|
da7b401a67 | ||
|
|
9d98e466eb | ||
|
|
33373be186 | ||
|
|
41e754b424 | ||
|
|
327c017b8f | ||
|
|
c6170f5f07 | ||
|
|
a8a90e197b | ||
|
|
dd1345d1ba | ||
|
|
a1f73095fd | ||
|
|
e50aeefbfa | ||
|
|
cb5afe3343 | ||
|
|
5be36f5bbd | ||
|
|
1bc0ae9233 | ||
|
|
22797eb493 | ||
|
|
e4392951c7 | ||
|
|
532bb3e096 | ||
|
|
ab0755b2e9 | ||
|
|
8f4da0dc7b | ||
|
|
724e4c4e5b | ||
|
|
b590995b4e | ||
|
|
9b58c3b0b1 | ||
|
|
e6d2b8ee9a | ||
|
|
f130380809 | ||
|
|
ad8e520047 | ||
|
|
d8635a619c | ||
|
|
c3dcbab9cc |
208 changed files with 5368 additions and 2951 deletions
|
|
@ -14,6 +14,14 @@ rocky9-deploy:
|
|||
- rocky9-package
|
||||
- rocky9-test
|
||||
|
||||
rocky10-deploy:
|
||||
extends: .deploy
|
||||
script:
|
||||
- ./deploy_packages.sh rockylinux 10
|
||||
needs:
|
||||
- rocky10-package
|
||||
- rocky10-test
|
||||
|
||||
debian12-deploy:
|
||||
extends: .deploy
|
||||
script:
|
||||
|
|
@ -22,26 +30,24 @@ debian12-deploy:
|
|||
- debian12-package
|
||||
- debian12-test
|
||||
|
||||
debian13-deploy:
|
||||
extends: .deploy
|
||||
script:
|
||||
- ./deploy_packages.sh debian trixie
|
||||
needs:
|
||||
- debian13-package
|
||||
- debian13-test
|
||||
|
||||
remi-rocky8-deploy:
|
||||
extends: .deploy
|
||||
rules:
|
||||
- changes:
|
||||
- .gitlab-ci.yml
|
||||
#rules:
|
||||
#- changes:
|
||||
# - .gitlab-ci.yml
|
||||
script:
|
||||
- ./deploy_packages.sh rockylinux 8
|
||||
needs:
|
||||
- remi-rocky8-package
|
||||
|
||||
remi-rocky9-deploy:
|
||||
extends: .deploy
|
||||
rules:
|
||||
- changes:
|
||||
- .gitlab-ci.yml
|
||||
script:
|
||||
- ./deploy_packages.sh rockylinux 9
|
||||
needs:
|
||||
- remi-rocky9-package
|
||||
|
||||
.deploy:
|
||||
stage: deploy
|
||||
tags: ["docker"]
|
||||
|
|
|
|||
|
|
@ -4,12 +4,6 @@ rocky8-package:
|
|||
extends: .package
|
||||
image: gitlab.linphone.org:4567/bc/public/docker/rocky8-php:$ROCKY_8_IMAGE_VERSION
|
||||
script:
|
||||
# We install this dependency only for the pipeline
|
||||
- dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
|
||||
- dnf -y module reset php
|
||||
- dnf -y module enable php:remi-8.2
|
||||
- dnf -y update php\*
|
||||
- dnf -y install php-sodium
|
||||
- make package-el8
|
||||
|
||||
rocky9-package:
|
||||
|
|
@ -18,20 +12,28 @@ rocky9-package:
|
|||
extends: .package
|
||||
image: gitlab.linphone.org:4567/bc/public/docker/rocky9-php:$ROCKY_9_IMAGE_VERSION
|
||||
script:
|
||||
# We install this dependency only for the pipeline
|
||||
- dnf -y install https://rpms.remirepo.net/enterprise/remi-release-9.rpm
|
||||
- dnf -y module reset php
|
||||
- dnf -y module enable php:remi-8.2
|
||||
- dnf -y update php\*
|
||||
- dnf -y install php-sodium
|
||||
- make package-el9
|
||||
|
||||
rocky10-package:
|
||||
needs:
|
||||
- prepare-package
|
||||
extends: .package
|
||||
image: gitlab.linphone.org:4567/bc/public/docker/rocky10-php:$ROCKY_10_IMAGE_VERSION
|
||||
script:
|
||||
- make package-el10
|
||||
|
||||
debian12-package:
|
||||
needs:
|
||||
- prepare-package
|
||||
extends: .debian_package
|
||||
image: gitlab.linphone.org:4567/bc/public/docker/debian12-php:$DEBIAN_12_IMAGE_VERSION
|
||||
|
||||
debian13-package:
|
||||
needs:
|
||||
- prepare-package
|
||||
extends: .debian_package
|
||||
image: gitlab.linphone.org:4567/bc/public/docker/debian13-php:$DEBIAN_13_IMAGE_VERSION
|
||||
|
||||
.debian_package:
|
||||
extends: .package
|
||||
script:
|
||||
|
|
@ -46,21 +48,12 @@ remi-rocky8-package:
|
|||
- dnf -y module reset redis
|
||||
- dnf -y install @redis:6
|
||||
|
||||
remi-rocky9-package:
|
||||
image: gitlab.linphone.org:4567/bc/public/docker/rocky9-php:$ROCKY_9_IMAGE_VERSION
|
||||
extends: .remi-rocky-package
|
||||
variables:
|
||||
ROCKY_RELEASE: 9
|
||||
before_script:
|
||||
- dnf -y module reset redis
|
||||
- dnf -y install @redis:7
|
||||
|
||||
.remi-rocky-package:
|
||||
extends: .package
|
||||
rules:
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^release/ || $CI_COMMIT_REF_NAME == "master"
|
||||
- changes:
|
||||
- .gitlab-ci.yml
|
||||
#- changes:
|
||||
# - .gitlab-ci.yml
|
||||
script:
|
||||
# Remi
|
||||
- mkdir -p $CI_PROJECT_DIR/build
|
||||
|
|
|
|||
|
|
@ -10,12 +10,18 @@ rocky9-test:
|
|||
needs:
|
||||
- rocky9-package
|
||||
|
||||
rocky10-test:
|
||||
extends: .rocky-test
|
||||
image: gitlab.linphone.org:4567/bc/public/docker/rocky10-php:$ROCKY_10_IMAGE_VERSION
|
||||
needs:
|
||||
- rocky10-package
|
||||
|
||||
.rocky-test:
|
||||
extends: .test
|
||||
script:
|
||||
- yum -y localinstall build/*.rpm
|
||||
- cd /opt/belledonne-communications/share/flexisip-account-manager/flexiapi
|
||||
- composer install --ignore-platform-req=ext-sodium # Rocky 8 use the external library
|
||||
- composer install --ignore-platform-req=ext-sodium # Rocky 8 and 9 use the external library
|
||||
- vendor/bin/phpcs
|
||||
- vendor/bin/phpmd . ansi phpmd.xml
|
||||
- php artisan key:generate
|
||||
|
|
@ -27,10 +33,16 @@ debian12-test:
|
|||
needs:
|
||||
- debian12-package
|
||||
|
||||
debian13-test:
|
||||
extends: .debian-test
|
||||
image: gitlab.linphone.org:4567/bc/public/docker/debian13-php:$DEBIAN_13_IMAGE_VERSION
|
||||
needs:
|
||||
- debian13-package
|
||||
|
||||
.debian-test:
|
||||
extends: .test
|
||||
script:
|
||||
- apt update
|
||||
#- apt update
|
||||
- apt install -y ./build/*.deb
|
||||
- cd /opt/belledonne-communications/share/flexisip-account-manager/flexiapi
|
||||
- composer install
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
variables:
|
||||
ROCKY_8_IMAGE_VERSION: 20250702_171834_update_rocky8_dockerhub
|
||||
ROCKY_9_IMAGE_VERSION: 20250702_171314_update_rocky9_dockerhub
|
||||
DEBIAN_12_IMAGE_VERSION: 20241204_162237_update_download_linphone_org
|
||||
ROCKY_10_IMAGE_VERSION: 20250908_164454_rocky10_first
|
||||
DEBIAN_12_IMAGE_VERSION: 20250908_154742_refresh_dependencies
|
||||
DEBIAN_13_IMAGE_VERSION: 20251204_115628_update_packages
|
||||
PHP_REDIS_REMI_VERSION: php-pecl-redis6-6.1.0-1
|
||||
PHP_IGBINARY_REMI_VERSION: php-pecl-igbinary-3.2.16-2
|
||||
PHP_MSGPACK_REMI_VERSION: php-pecl-msgpack-2.2.0-3
|
||||
|
|
|
|||
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
||||
|
||||
## [2.1]
|
||||
|
||||
### Added
|
||||
|
||||
- **Add CardDav servers** They can be configured in the administration panels and the API.
|
||||
- **Rockylinux 10 support** Packages are now available in the official repository
|
||||
- **Artisan cleanup script for statistics** Add an artisan console script to clear statistics after n days `app:clear-statistics {days} {--apply}`
|
||||
- **Add Voicemail features and related API endpoints** to integrate with `flexisip-voicemail`
|
||||
|
||||
### Changed
|
||||
|
||||
- **Contacts Lists** The Contacts Lists are now handled per Space. During the migration, if there is only one Space present, existing Contacts Lists are automatically attached to it, otherwise the first Super Space available is used. If they are then attached to the wrong Space you'll have to change directly their `space_id` value in the `contacts_lists` database table.
|
||||
- **PHP 8.2 minimum** Laravel and its dependencies were upgraded to version 11 as well.
|
||||
- **Logout the user when the password is correctly changed**
|
||||
|
||||
## [2.0]
|
||||
|
||||
### Added
|
||||
|
|
|
|||
10
INSTALL.md
10
INSTALL.md
|
|
@ -24,6 +24,14 @@ FlexiAPI is packaged for Debian and RedHat, you can setup those repositories usi
|
|||
|
||||
The `artisan` script is in the root directory of where the application is setup, with packages its often `/opt/belledonne-communications/share/flexisip-account-manager/flexiapi/`.
|
||||
|
||||
⚠️ If you want to enable JWT authentication the php-sodium dependency is required, on Rockylinux it is only available in the Remi repository in some cases. You can install it with the following steps:
|
||||
|
||||
dnf -y install https://rpms.remirepo.net/enterprise/remi-release-{rockylinux-release}.rpm
|
||||
dnf -y module reset php
|
||||
dnf -y module enable php:remi-{php-version}
|
||||
dnf -y update php\*
|
||||
dnf -y install php-sodium
|
||||
|
||||
# 2. Web server configuration
|
||||
|
||||
The package will deploy a `flexisip-account-manager.conf` file in the apache2 configuration directory.
|
||||
|
|
@ -31,6 +39,8 @@ This file can be loaded and configured in your specific VirtualHost configuratio
|
|||
|
||||
To know more about the web server configuration part, you can directly [visit the official Laravel installation documentation](https://laravel.com/docs/).
|
||||
|
||||
⚠️ The Account Manager is handling files upload, please ensure that you raised `upload_max_filesize` and `post_max_size` to a reasonable number in your `php.ini` file to prevent file upload errors.
|
||||
|
||||
# 3. .env file configuration
|
||||
|
||||
Complete all the variables in the `.env` file (from the `.env.example` one if you setup the instance manually) or by overwriting them in your Docker or web-server configuration.
|
||||
|
|
|
|||
21
Makefile
21
Makefile
|
|
@ -50,7 +50,7 @@ package-common:
|
|||
cp -R cron/ $(OUTPUT_DIR)/flexisip-account-manager/
|
||||
cp flexisip-account-manager.spec.run $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
|
||||
tar cvf flexisip-account-manager.tar.gz -C $(OUTPUT_DIR) flexisip-account-manager
|
||||
tar cf flexisip-account-manager.tar.gz -C $(OUTPUT_DIR) flexisip-account-manager
|
||||
mv flexisip-account-manager.tar.gz $(OUTPUT_DIR)/rpmbuild/SOURCES/flexisip-account-manager.tar.gz
|
||||
|
||||
package-end-common:
|
||||
|
|
@ -59,15 +59,20 @@ package-end-common:
|
|||
|
||||
rpm-el8-only:
|
||||
mkdir -p build
|
||||
sed -i 's/Requires:.*/Requires: php >= 8.1, php-gd, php-pdo, php-redis, php-mysqlnd, php-mbstring/g' $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
rpmbuild -v -bb --define 'dist .el8' --define '_topdir $(OUTPUT_DIR)/rpmbuild' --define "_rpmdir $(OUTPUT_DIR)/rpmbuild" $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
sed -i 's/Requires:.*/Requires: php >= 8.2, php-gd, php-pdo, php-redis, php-mysqlnd, php-mbstring/g' $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
rpmbuild --quiet -bb --define 'dist .el8' --define '_topdir $(OUTPUT_DIR)/rpmbuild' --define "_rpmdir $(OUTPUT_DIR)/rpmbuild" $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
@echo "📦✅ RPM el8 Package Created"
|
||||
|
||||
rpm-el9-only:
|
||||
mkdir -p build
|
||||
rpmbuild -v -bb --define 'dist .el9' --define '_topdir $(OUTPUT_DIR)/rpmbuild' --define "_rpmdir $(OUTPUT_DIR)/rpmbuild" $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
rpmbuild --quiet -bb --define 'dist .el9' --define '_topdir $(OUTPUT_DIR)/rpmbuild' --define "_rpmdir $(OUTPUT_DIR)/rpmbuild" $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
@echo "📦✅ RPM el9 Package Created"
|
||||
|
||||
rpm-el10-only:
|
||||
mkdir -p build
|
||||
rpmbuild --quiet -bb --define 'dist .el10' --define '_topdir $(OUTPUT_DIR)/rpmbuild' --define "_rpmdir $(OUTPUT_DIR)/rpmbuild" $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
@echo "📦✅ RPM el10 Package Created"
|
||||
|
||||
rpm-cleanup:
|
||||
@echo "🧹 Cleanup"
|
||||
mv rpmbuild/*/*.rpm build/.
|
||||
|
|
@ -76,11 +81,11 @@ rpm-cleanup:
|
|||
deb-only:
|
||||
mkdir -p build
|
||||
sed -i 's/posttrans/post/g' $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
rpmbuild -v -bb --with deb --define '_topdir $(OUTPUT_DIR)/rpmbuild' --define "_rpmfilename tmp.rpm" --define "_rpmdir $(OUTPUT_DIR)/rpmbuild" $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
rpmbuild --quiet -bb --with deb --define '_topdir $(OUTPUT_DIR)/rpmbuild' --define "_rpmfilename tmp.rpm" --define "_rpmdir $(OUTPUT_DIR)/rpmbuild" $(OUTPUT_DIR)/rpmbuild/SPECS/flexisip-account-manager.spec
|
||||
fakeroot alien -g -k --scripts $(OUTPUT_DIR)/rpmbuild/tmp.rpm
|
||||
rm -r $(OUTPUT_DIR)/rpmbuild
|
||||
rm -rf $(OUTPUT_DIR)/*.orig
|
||||
sed -i 's/Depends:.*/Depends: $${shlibs:Depends}, php (>= 8.1), php-xml, php-pdo, php-gd, php-redis, php-mysql, php-mbstring, php-sqlite3/g' $(OUTPUT_DIR)/bc-flexisip-account-manager*/debian/control
|
||||
sed -i 's/Depends:.*/Depends: $${shlibs:Depends}, php (>= 8.2), php-xml, php-pdo, php-gd, php-redis, php-mysql, php-mbstring, php-sqlite3/g' $(OUTPUT_DIR)/bc-flexisip-account-manager*/debian/control
|
||||
|
||||
cd `ls -rt $(OUTPUT_DIR) | tail -1` && dpkg-buildpackage --no-sign
|
||||
@echo "📦✅ DEB Package Created"
|
||||
|
|
@ -101,6 +106,10 @@ package-el9: rpm-el9-only rpm-cleanup cleanup-package-semvers package-end-common
|
|||
rpm-el9: prepare-common package-el9
|
||||
rpm-el9-dev: prepare-dev package-semvers package-common package-el9
|
||||
|
||||
package-el10: rpm-el10-only rpm-cleanup cleanup-package-semvers package-end-common
|
||||
rpm-el10: prepare-common package-el10
|
||||
rpm-el10-dev: prepare-dev package-semvers package-common package-el10
|
||||
|
||||
package-deb: deb-only cleanup-package-semvers package-end-common
|
||||
deb: prepare-common package-deb
|
||||
deb-dev: prepare-dev package-semvers package-common package-deb
|
||||
|
|
|
|||
1
cron/flexiapi.cron
Normal file
1
cron/flexiapi.cron
Normal file
|
|
@ -0,0 +1 @@
|
|||
* * * * * apache /opt/belledonne-communications/share/flexisip-account-manager/flexiapi/artisan schedule:run >> /dev/null 2>&1
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
cd /opt/belledonne-communications/share/flexisip-account-manager/flexiapi/
|
||||
sudo -su www-data && php artisan digest:clear-nonces 60
|
||||
sudo -su www-data && php artisan accounts:clear-api-keys 60
|
||||
sudo -su www-data && php artisan accounts:clear-accounts-tombstones 7 --apply
|
||||
sudo -su www-data && php artisan accounts:clear-api-keys 60
|
||||
sudo -su www-data && php artisan accounts:clear-files 30 --apply
|
||||
sudo -su www-data && php artisan accounts:clear-unconfirmed 30 --apply
|
||||
sudo -su www-data && php artisan spaces:expiration-emails
|
||||
sudo -su www-data && php artisan app:clear-statistics 30 --apply
|
||||
sudo -su www-data && php artisan digest:clear-nonces 60
|
||||
sudo -su www-data && php artisan spaces:expiration-emails
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
cd /opt/belledonne-communications/share/flexisip-account-manager/flexiapi/
|
||||
php artisan digest:clear-nonces 60
|
||||
php artisan accounts:clear-api-keys 60
|
||||
php artisan accounts:clear-accounts-tombstones 7 --apply
|
||||
php artisan accounts:clear-api-keys 60
|
||||
php artisan accounts:clear-files 30 --apply
|
||||
php artisan accounts:clear-unconfirmed 30 --apply
|
||||
php artisan app:clear-statistics 30 --apply
|
||||
php artisan digest:clear-nonces 60
|
||||
php artisan spaces:expiration-emails
|
||||
php artisan app:clear-statistics 30 --apply
|
||||
|
|
@ -97,3 +97,5 @@ HCAPTCHA_SITEKEY=site-key
|
|||
JWT_RSA_PUBLIC_KEY_PEM=
|
||||
JWT_SIP_IDENTIFIER=
|
||||
|
||||
# Temporary toggles
|
||||
APP_SHOW_LOGIN_COUNTER_TEMP= # default true
|
||||
|
|
@ -23,8 +23,8 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Carbon\Carbon;
|
||||
|
||||
use Awobaz\Compoships\Compoships;
|
||||
|
|
@ -36,7 +36,7 @@ class Account extends Authenticatable
|
|||
use HasFactory;
|
||||
use Compoships;
|
||||
|
||||
protected $with = ['passwords', 'emailChangeCode', 'types', 'actions', 'dictionaryEntries'];
|
||||
protected $with = ['passwords', 'emailChangeCode', 'types', 'actions', 'dictionaryEntries', 'carddavServers'];
|
||||
protected $hidden = ['expire_time', 'pivot', 'currentProvisioningToken', 'currentRecoveryCode', 'dictionaryEntries'];
|
||||
protected $appends = ['realm', 'provisioning_token', 'provisioning_token_expire_at', 'dictionary'];
|
||||
protected $casts = [
|
||||
|
|
@ -73,6 +73,9 @@ class Account extends Authenticatable
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* config('app.sip_domain') is required for the Tests suit
|
||||
*/
|
||||
$builder->where('domain', config('app.sip_domain') ?? space()->domain);
|
||||
});
|
||||
}
|
||||
|
|
@ -131,6 +134,23 @@ class Account extends Authenticatable
|
|||
return $this->belongsToMany(Account::class, 'contacts', 'account_id', 'contact_id');
|
||||
}
|
||||
|
||||
public function files()
|
||||
{
|
||||
return $this->hasMany(AccountFile::class)->latest();
|
||||
}
|
||||
|
||||
public function voicemails()
|
||||
{
|
||||
return $this->hasMany(AccountFile::class)
|
||||
->whereIn('content_type', AccountFile::VOICEMAIL_CONTENTTYPES)
|
||||
->latest();
|
||||
}
|
||||
|
||||
public function uploadedVoicemails()
|
||||
{
|
||||
return $this->voicemails()->whereNotNull('name');
|
||||
}
|
||||
|
||||
public function vcardsStorage()
|
||||
{
|
||||
return $this->hasMany(VcardStorage::class);
|
||||
|
|
@ -146,6 +166,12 @@ class Account extends Authenticatable
|
|||
return $this->hasMany(AccountDictionaryEntry::class);
|
||||
}
|
||||
|
||||
public function carddavServers()
|
||||
{
|
||||
return $this->belongsToMany(SpaceCardDavServer::class, 'account_carddav_credentials', 'account_id', 'space_carddav_server_id')
|
||||
->withPivot('username', 'realm', 'algorithm', 'password');
|
||||
}
|
||||
|
||||
public function getDictionaryAttribute()
|
||||
{
|
||||
if ($this->dictionaryEntries->isEmpty()) return new stdClass;
|
||||
|
|
@ -318,6 +344,15 @@ class Account extends Authenticatable
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getRemainingCardDavCredentialsCreatableAttribute(): Collection
|
||||
{
|
||||
return $this->space->carddavServers()->whereNotIn('id', function ($query) {
|
||||
$query->select('space_carddav_server_id')
|
||||
->from('account_carddav_credentials')
|
||||
->where('account_id', $this->id);
|
||||
})->get();
|
||||
}
|
||||
|
||||
public function getIdentifierAttribute(): string
|
||||
{
|
||||
return $this->attributes['username'] . '@' . $this->attributes['domain'];
|
||||
|
|
|
|||
20
flexiapi/app/AccountCardDavCredentials.php
Normal file
20
flexiapi/app/AccountCardDavCredentials.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AccountCardDavCredentials extends Model
|
||||
{
|
||||
protected $table = 'account_carddav_credentials';
|
||||
|
||||
public function cardDavServer()
|
||||
{
|
||||
return $this->hasOne(SpaceCardDavServer::class, 'id', 'space_carddav_server_id');
|
||||
}
|
||||
|
||||
public function getIdentifierAttribute()
|
||||
{
|
||||
return $this->username . '@' . $this->domain;
|
||||
}
|
||||
}
|
||||
74
flexiapi/app/AccountFile.php
Normal file
74
flexiapi/app/AccountFile.php
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AccountFile extends Model
|
||||
{
|
||||
use HasUuids;
|
||||
|
||||
public const VOICEMAIL_CONTENTTYPES = ['audio/opus', 'audio/wav'];
|
||||
public const FILES_PATH = 'files';
|
||||
protected $hidden = ['account_id', 'updated_at', 'sending_by_mail_at', 'sent_by_mail_at', 'sending_by_mail_tryouts'];
|
||||
protected $appends = ['download_url'];
|
||||
protected $casts = [
|
||||
'uploaded_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::deleting(function (AccountFile $accountFile) {
|
||||
Storage::delete($accountFile->getPathAttribute());
|
||||
});
|
||||
}
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo(Account::class)->withoutGlobalScopes();
|
||||
}
|
||||
|
||||
public function getMaxUploadSizeAttribute(): ?int
|
||||
{
|
||||
return maxUploadSize();
|
||||
}
|
||||
|
||||
public function getUploadUrlAttribute(): ?string
|
||||
{
|
||||
return route('file.upload', $this->attributes['id']);
|
||||
}
|
||||
|
||||
public function getPathAttribute(): string
|
||||
{
|
||||
return self::FILES_PATH . '/' . $this->attributes['name'];
|
||||
}
|
||||
|
||||
public function getUrlAttribute(): ?string
|
||||
{
|
||||
return !empty($this->attributes['name'])
|
||||
&& !empty($this->attributes['id'])
|
||||
? replaceHost(
|
||||
route('file.show', ['uuid' => $this->attributes['id'], 'name' => $this->attributes['name']]),
|
||||
$this->account->space->host
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
public function getDownloadUrlAttribute(): ?string
|
||||
{
|
||||
return !empty($this->attributes['name'])
|
||||
&& !empty($this->attributes['id'])
|
||||
? replaceHost(route(
|
||||
'file.download',
|
||||
['uuid' => $this->attributes['id'], 'name' => $this->attributes['name']]
|
||||
), $this->account->space->host)
|
||||
: null;
|
||||
}
|
||||
|
||||
public function isVoicemailAudio(): bool
|
||||
{
|
||||
return in_array($this->attributes['content_type'], self::VOICEMAIL_CONTENTTYPES);
|
||||
}
|
||||
}
|
||||
|
|
@ -29,11 +29,6 @@ class ClearAccountsTombstones extends Command
|
|||
protected $signature = 'accounts:clear-accounts-tombstones {days} {--apply}';
|
||||
protected $description = 'Clear deleted accounts tombstones after n days';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$tombstones = AccountTombstone::where(
|
||||
|
|
|
|||
35
flexiapi/app/Console/Commands/Accounts/ClearFiles.php
Normal file
35
flexiapi/app/Console/Commands/Accounts/ClearFiles.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\Accounts;
|
||||
|
||||
use App\AccountFile;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class ClearFiles extends Command
|
||||
{
|
||||
protected $signature = 'accounts:clear-files {days} {--apply}';
|
||||
protected $description = 'Remove the uploaded files after n days';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$files = AccountFile::where(
|
||||
'created_at',
|
||||
'<',
|
||||
Carbon::now()->subDays($this->argument('days'))->toDateTimeString()
|
||||
);
|
||||
|
||||
$count = $files->count();
|
||||
|
||||
if ($this->option('apply')) {
|
||||
$this->info($count . ' files in deletion…');
|
||||
$files->delete();
|
||||
$this->info($count . ' files deleted');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$this->info($count . ' files to delete');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -29,11 +29,6 @@ class ClearUnconfirmed extends Command
|
|||
protected $signature = 'accounts:clear-unconfirmed {days} {--apply} {--and-confirmed}';
|
||||
protected $description = 'Clear unconfirmed accounts after n days';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$accounts = Account::where(
|
||||
|
|
|
|||
|
|
@ -30,18 +30,15 @@ class CreateAdminTest extends Command
|
|||
protected $signature = 'accounts:create-admin-test';
|
||||
protected $description = 'Create a test admin account, only for tests purpose';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$username = 'admin_test';
|
||||
$domain = 'sip.example.org';
|
||||
|
||||
$this->call('spaces:create-update', [
|
||||
'domain' => $domain,
|
||||
'sip_domain' => $domain,
|
||||
'host' => $domain,
|
||||
'name' => $domain,
|
||||
'--super' => 'true'
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,11 +28,6 @@ class Seed extends Command
|
|||
protected $signature = 'accounts:seed {json-file-path}';
|
||||
protected $description = 'Seed some accounts from a JSON file';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$file = $this->argument('json-file-path');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\Accounts;
|
||||
|
||||
use App\AccountFile;
|
||||
use App\Mail\Voicemail;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class SendVoicemailsEmails extends Command
|
||||
{
|
||||
protected $signature = 'accounts:send-voicemails-emails {--tryout}';
|
||||
protected $description = 'Send the voicemail emails';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$voicemails = AccountFile::whereNotNull('uploaded_at')
|
||||
->whereNull('sent_by_mail_at')
|
||||
->where('sending_by_mail_tryouts', '<', is_int($this->option('tryout'))
|
||||
? $this->option('tryout')
|
||||
: 3)
|
||||
->get();
|
||||
|
||||
foreach ($voicemails as $voicemail) {
|
||||
$voicemail->sending_by_mail_at = Carbon::now();
|
||||
$voicemail->save();
|
||||
|
||||
if (Mail::to(users: $voicemail->account)->send(new Voicemail($voicemail))) {
|
||||
$voicemail->sent_by_mail_at = Carbon::now();
|
||||
$this->info('Voicemail sent to ' . $voicemail->account->identifier);
|
||||
} else {
|
||||
$voicemail->sending_by_mail_tryouts++;
|
||||
$this->info('Error sending voicemail to ' . $voicemail->account->identifier);
|
||||
}
|
||||
|
||||
$voicemail->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,11 +28,6 @@ class SetAdmin extends Command
|
|||
protected $signature = 'accounts:set-admin {id}';
|
||||
protected $description = 'Give the admin role to an account';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$account = Account::withoutGlobalScopes()->where('id', $this->argument('id'))->first();
|
||||
|
|
|
|||
33
flexiapi/app/Console/Commands/UpdatePhoneCountries.php
Normal file
33
flexiapi/app/Console/Commands/UpdatePhoneCountries.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\PhoneCountry;
|
||||
use Illuminate\Console\Command;
|
||||
use libphonenumber\PhoneNumberUtil;
|
||||
|
||||
class UpdatePhoneCountries extends Command
|
||||
{
|
||||
protected $signature = 'app:update-phone-countries';
|
||||
protected $description = 'Update the phone_countries table from the getCountryCodes() function';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$phoneNumberUtils = PhoneNumberUtil::getInstance();
|
||||
$countryCodes = getCountryCodes();
|
||||
|
||||
foreach (array_diff(
|
||||
array_keys($countryCodes),
|
||||
PhoneCountry::pluck('code')->toArray()
|
||||
) as $code) {
|
||||
if ($resolvedMetadata = $phoneNumberUtils->getMetadataForRegion($code)) {
|
||||
$phoneCountry = new PhoneCountry();
|
||||
$phoneCountry->code = $code;
|
||||
$phoneCountry->country_code = $resolvedMetadata->getCountryCode();
|
||||
$phoneCountry->save();
|
||||
|
||||
$this->info($code . ' - ' . $countryCodes[$code] . ' inserted');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,4 +15,9 @@ class ContactsList extends Model
|
|||
{
|
||||
return $this->belongsToMany(Account::class, 'contacts_list_contact', 'contacts_list_id', 'contact_id');
|
||||
}
|
||||
|
||||
public function space()
|
||||
{
|
||||
return $this->belongsTo(Space::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
use App\Account;
|
||||
|
|
@ -28,24 +29,15 @@ use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
|
|||
use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
$hostSpace = null;
|
||||
|
||||
function space($reload = false): ?Space
|
||||
function space(): ?Space
|
||||
{
|
||||
global $hostSpace;
|
||||
|
||||
if ($hostSpace != null && $reload == false) {
|
||||
return $hostSpace;
|
||||
}
|
||||
|
||||
$hostSpace = Space::where('host', request()->host())->first();
|
||||
return $hostSpace;
|
||||
return is_object(request()->space) ? request()->space : null;
|
||||
}
|
||||
|
||||
function passwordAlgorithms(): array
|
||||
{
|
||||
return [
|
||||
'MD5' => 'md5',
|
||||
'MD5' => 'md5',
|
||||
'SHA-256' => 'sha256',
|
||||
];
|
||||
}
|
||||
|
|
@ -109,7 +101,7 @@ function markdownDocumentationView(string $view): string
|
|||
$converter->getEnvironment()->addExtension(new TableOfContentsExtension());
|
||||
|
||||
return (string) $converter->convert(
|
||||
(string)view($view, [
|
||||
(string) view($view, [
|
||||
'app_name' => space()->name
|
||||
])->render()
|
||||
);
|
||||
|
|
@ -167,7 +159,15 @@ function resolveDomain(Request $request): string
|
|||
&& $request->user()
|
||||
&& $request->user()->superAdmin
|
||||
? $request->get('domain')
|
||||
: config('app.sip_domain');
|
||||
: $request->space->domain;
|
||||
}
|
||||
|
||||
function maxUploadSize(): int
|
||||
{
|
||||
return min(
|
||||
ini_parse_quantity(ini_get('upload_max_filesize')),
|
||||
ini_parse_quantity(ini_get('post_max_size'))
|
||||
);
|
||||
}
|
||||
|
||||
function captchaConfigured(): bool
|
||||
|
|
@ -214,7 +214,7 @@ function validateIsoDate($attribute, $value, $parameters, $validator): bool
|
|||
// Regex from https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/
|
||||
: '/^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/';
|
||||
|
||||
return (bool)preg_match($regex, $value);
|
||||
return (bool) preg_match($regex, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -226,236 +226,253 @@ function validateIsoDate($attribute, $value, $parameters, $validator): bool
|
|||
function getCountryCodes()
|
||||
{
|
||||
return [
|
||||
'AF' => 'Afghanistan',
|
||||
'AX' => 'Åland Islands',
|
||||
'AL' => 'Albania',
|
||||
'DZ' => 'Algeria',
|
||||
'AS' => 'American Samoa',
|
||||
'AD' => 'Andorra',
|
||||
'AO' => 'Angola',
|
||||
'AI' => 'Anguilla',
|
||||
'AE' => 'United Arab Emirates',
|
||||
'AF' => 'Afghanistan',
|
||||
'AG' => 'Antigua & Barbuda',
|
||||
'AI' => 'Anguilla',
|
||||
'AL' => 'Albania',
|
||||
'AM' => 'Armenia',
|
||||
'AO' => 'Angola',
|
||||
'AQ' => 'Antarctica',
|
||||
'AR' => 'Argentina',
|
||||
'AU' => 'Australia',
|
||||
'AS' => 'American Samoa',
|
||||
'AT' => 'Austria',
|
||||
'AU' => 'Australia',
|
||||
'AW' => 'Aruba',
|
||||
'AX' => 'Åland Islands',
|
||||
'AZ' => 'Azerbaijan',
|
||||
'BS' => 'Bahamas',
|
||||
'BH' => 'Bahrain',
|
||||
'BD' => 'Bangladesh',
|
||||
'BB' => 'Barbados',
|
||||
'BY' => 'Belarus',
|
||||
'BE' => 'Belgium',
|
||||
'BZ' => 'Belize',
|
||||
'BJ' => 'Benin',
|
||||
'BM' => 'Bermuda',
|
||||
'BT' => 'Bhutan',
|
||||
'BO' => 'Bolivia',
|
||||
'BA' => 'Bosnia & Herzegovina',
|
||||
'BW' => 'Botswana',
|
||||
'BR' => 'Brazil',
|
||||
'IO' => 'British Indian Ocean Territory',
|
||||
'BN' => 'Brunei',
|
||||
'BG' => 'Bulgaria',
|
||||
'BB' => 'Barbados',
|
||||
'BD' => 'Bangladesh',
|
||||
'BE' => 'Belgium',
|
||||
'BF' => 'Burkina Faso',
|
||||
'BG' => 'Bulgaria',
|
||||
'BH' => 'Bahrain',
|
||||
'BI' => 'Burundi',
|
||||
'KH' => 'Cambodia',
|
||||
'CM' => 'Cameroon',
|
||||
'BJ' => 'Benin',
|
||||
'BL' => 'St. Barthélemy',
|
||||
'BM' => 'Bermuda',
|
||||
'BN' => 'Brunei',
|
||||
'BO' => 'Bolivia',
|
||||
'BQ' => 'Bonaire, Sint Eustatius & Saba',
|
||||
'BR' => 'Brazil',
|
||||
'BS' => 'Bahamas',
|
||||
'BT' => 'Bhutan',
|
||||
'BV' => 'Bouvet Island',
|
||||
'BW' => 'Botswana',
|
||||
'BY' => 'Belarus',
|
||||
'BZ' => 'Belize',
|
||||
'CA' => 'Canada',
|
||||
'CV' => 'Cape Verde',
|
||||
'KY' => 'Cayman Islands',
|
||||
'CF' => 'Central African Republic',
|
||||
'TD' => 'Chad',
|
||||
'CL' => 'Chile',
|
||||
'CN' => 'China',
|
||||
'CX' => 'Christmas Island',
|
||||
'CC' => 'Cocos (Keeling) Islands',
|
||||
'CO' => 'Colombia',
|
||||
'KM' => 'Comoros',
|
||||
'CG' => 'Congo - Brazzaville',
|
||||
'CD' => 'Congo - Kinshasa',
|
||||
'CF' => 'Central African Republic',
|
||||
'CG' => 'Congo - Brazzaville',
|
||||
'CH' => 'Switzerland',
|
||||
'CI' => "Côte d'Ivoire",
|
||||
'CK' => 'Cook Islands',
|
||||
'CL' => 'Chile',
|
||||
'CM' => 'Cameroon',
|
||||
'CN' => 'China',
|
||||
'CO' => 'Colombia',
|
||||
'CR' => 'Costa Rica',
|
||||
'CI' => 'Côte d’Ivoire',
|
||||
'HR' => 'Croatia',
|
||||
'CU' => 'Cuba',
|
||||
'CV' => 'Cabo Verde',
|
||||
'CW' => 'Curaçao',
|
||||
'CX' => 'Christmas Island',
|
||||
'CY' => 'Cyprus',
|
||||
'CZ' => 'Czechia',
|
||||
'DK' => 'Denmark',
|
||||
'DE' => 'Germany',
|
||||
'DJ' => 'Djibouti',
|
||||
'DK' => 'Denmark',
|
||||
'DM' => 'Dominica',
|
||||
'DO' => 'Dominican Republic',
|
||||
'DZ' => 'Algeria',
|
||||
'EC' => 'Ecuador',
|
||||
'EG' => 'Egypt',
|
||||
'SV' => 'El Salvador',
|
||||
'GQ' => 'Equatorial Guinea',
|
||||
'ER' => 'Eritrea',
|
||||
'EE' => 'Estonia',
|
||||
'EG' => 'Egypt',
|
||||
'EH' => 'Western Sahara',
|
||||
'ER' => 'Eritrea',
|
||||
'ES' => 'Spain',
|
||||
'ET' => 'Ethiopia',
|
||||
'FK' => 'Falkland Islands',
|
||||
'FO' => 'Faroe Islands',
|
||||
'FJ' => 'Fiji',
|
||||
'FI' => 'Finland',
|
||||
'FJ' => 'Fiji',
|
||||
'FK' => 'Falkland Islands',
|
||||
'FM' => 'Micronesia',
|
||||
'FO' => 'Faroe Islands',
|
||||
'FR' => 'France',
|
||||
'GF' => 'French Guiana',
|
||||
'PF' => 'French Polynesia',
|
||||
'GA' => 'Gabon',
|
||||
'GM' => 'Gambia',
|
||||
'GB' => 'United Kingdom',
|
||||
'GD' => 'Grenada',
|
||||
'GE' => 'Georgia',
|
||||
'DE' => 'Germany',
|
||||
'GF' => 'French Guiana',
|
||||
'GG' => 'Guernsey',
|
||||
'GH' => 'Ghana',
|
||||
'GI' => 'Gibraltar',
|
||||
'GR' => 'Greece',
|
||||
'GL' => 'Greenland',
|
||||
'GD' => 'Grenada',
|
||||
'GP' => 'Guadeloupe',
|
||||
'GU' => 'Guam',
|
||||
'GT' => 'Guatemala',
|
||||
'GG' => 'Guernsey',
|
||||
'GM' => 'Gambia',
|
||||
'GN' => 'Guinea',
|
||||
'GP' => 'Guadeloupe',
|
||||
'GQ' => 'Equatorial Guinea',
|
||||
'GR' => 'Greece',
|
||||
'GS' => 'South Georgia & South Sandwich Islands',
|
||||
'GT' => 'Guatemala',
|
||||
'GU' => 'Guam',
|
||||
'GW' => 'Guinea-Bissau',
|
||||
'GY' => 'Guyana',
|
||||
'HT' => 'Haiti',
|
||||
'HK' => 'Hong Kong',
|
||||
'HM' => 'Heard & McDonald Islands',
|
||||
'HN' => 'Honduras',
|
||||
'HK' => 'Hong Kong SAR China',
|
||||
'HR' => 'Croatia',
|
||||
'HT' => 'Haiti',
|
||||
'HU' => 'Hungary',
|
||||
'IS' => 'Iceland',
|
||||
'IN' => 'India',
|
||||
'ID' => 'Indonesia',
|
||||
'IR' => 'Iran',
|
||||
'IQ' => 'Iraq',
|
||||
'IE' => 'Ireland',
|
||||
'IM' => 'Isle of Man',
|
||||
'IL' => 'Israel',
|
||||
'IM' => 'Isle of Man',
|
||||
'IN' => 'India',
|
||||
'IO' => 'British Indian Ocean Territory',
|
||||
'IQ' => 'Iraq',
|
||||
'IR' => 'Iran',
|
||||
'IS' => 'Iceland',
|
||||
'IT' => 'Italy',
|
||||
'JM' => 'Jamaica',
|
||||
'JP' => 'Japan',
|
||||
'JE' => 'Jersey',
|
||||
'JM' => 'Jamaica',
|
||||
'JO' => 'Jordan',
|
||||
'KZ' => 'Kazakhstan',
|
||||
'JP' => 'Japan',
|
||||
'KE' => 'Kenya',
|
||||
'KG' => 'Kyrgyzstan',
|
||||
'KH' => 'Cambodia',
|
||||
'KI' => 'Kiribati',
|
||||
'KM' => 'Comoros',
|
||||
'KN' => 'St. Kitts & Nevis',
|
||||
'KP' => 'North Korea',
|
||||
'KR' => 'South Korea',
|
||||
'KW' => 'Kuwait',
|
||||
'KG' => 'Kyrgyzstan',
|
||||
'KY' => 'Cayman Islands',
|
||||
'KZ' => 'Kazakhstan',
|
||||
'LA' => 'Laos',
|
||||
'LV' => 'Latvia',
|
||||
'LB' => 'Lebanon',
|
||||
'LS' => 'Lesotho',
|
||||
'LR' => 'Liberia',
|
||||
'LY' => 'Libya',
|
||||
'LC' => 'St. Lucia',
|
||||
'LI' => 'Liechtenstein',
|
||||
'LK' => 'Sri Lanka',
|
||||
'LR' => 'Liberia',
|
||||
'LS' => 'Lesotho',
|
||||
'LT' => 'Lithuania',
|
||||
'LU' => 'Luxembourg',
|
||||
'MO' => 'Macao SAR China',
|
||||
'MK' => 'North Macedonia',
|
||||
'LV' => 'Latvia',
|
||||
'LY' => 'Libya',
|
||||
'MA' => 'Morocco',
|
||||
'MC' => 'Monaco',
|
||||
'MD' => 'Moldova',
|
||||
'ME' => 'Montenegro',
|
||||
'MF' => 'St. Martin',
|
||||
'MG' => 'Madagascar',
|
||||
'MW' => 'Malawi',
|
||||
'MY' => 'Malaysia',
|
||||
'MV' => 'Maldives',
|
||||
'ML' => 'Mali',
|
||||
'MT' => 'Malta',
|
||||
'MH' => 'Marshall Islands',
|
||||
'MK' => 'North Macedonia',
|
||||
'ML' => 'Mali',
|
||||
'MM' => 'Myanmar',
|
||||
'MN' => 'Mongolia',
|
||||
'MO' => 'Macao',
|
||||
'MP' => 'Northern Mariana Islands',
|
||||
'MQ' => 'Martinique',
|
||||
'MR' => 'Mauritania',
|
||||
'MU' => 'Mauritius',
|
||||
'YT' => 'Mayotte',
|
||||
'MX' => 'Mexico',
|
||||
'FM' => 'Micronesia',
|
||||
'MD' => 'Moldova',
|
||||
'MC' => 'Monaco',
|
||||
'MN' => 'Mongolia',
|
||||
'ME' => 'Montenegro',
|
||||
'MS' => 'Montserrat',
|
||||
'MA' => 'Morocco',
|
||||
'MT' => 'Malta',
|
||||
'MU' => 'Mauritius',
|
||||
'MV' => 'Maldives',
|
||||
'MW' => 'Malawi',
|
||||
'MX' => 'Mexico',
|
||||
'MY' => 'Malaysia',
|
||||
'MZ' => 'Mozambique',
|
||||
'MM' => 'Myanmar (Burma)',
|
||||
'NA' => 'Namibia',
|
||||
'NR' => 'Nauru',
|
||||
'NP' => 'Nepal',
|
||||
'NL' => 'Netherlands',
|
||||
'NC' => 'New Caledonia',
|
||||
'NZ' => 'New Zealand',
|
||||
'NI' => 'Nicaragua',
|
||||
'NE' => 'Niger',
|
||||
'NG' => 'Nigeria',
|
||||
'NU' => 'Niue',
|
||||
'NF' => 'Norfolk Island',
|
||||
'MP' => 'Northern Mariana Islands',
|
||||
'NG' => 'Nigeria',
|
||||
'NI' => 'Nicaragua',
|
||||
'NL' => 'Netherlands',
|
||||
'NO' => 'Norway',
|
||||
'NP' => 'Nepal',
|
||||
'NR' => 'Nauru',
|
||||
'NU' => 'Niue',
|
||||
'NZ' => 'New Zealand',
|
||||
'OM' => 'Oman',
|
||||
'PK' => 'Pakistan',
|
||||
'PW' => 'Palau',
|
||||
'PS' => 'Palestinian Territories',
|
||||
'PA' => 'Panama',
|
||||
'PG' => 'Papua New Guinea',
|
||||
'PY' => 'Paraguay',
|
||||
'PE' => 'Peru',
|
||||
'PF' => 'French Polynesia',
|
||||
'PG' => 'Papua New Guinea',
|
||||
'PH' => 'Philippines',
|
||||
'PK' => 'Pakistan',
|
||||
'PL' => 'Poland',
|
||||
'PT' => 'Portugal',
|
||||
'PM' => 'St. Pierre & Miquelon',
|
||||
'PN' => 'Pitcairn Islands',
|
||||
'PR' => 'Puerto Rico',
|
||||
'PS' => 'Palestine',
|
||||
'PT' => 'Portugal',
|
||||
'PW' => 'Palau',
|
||||
'PY' => 'Paraguay',
|
||||
'QA' => 'Qatar',
|
||||
'RE' => 'Réunion',
|
||||
'RO' => 'Romania',
|
||||
'RS' => 'Serbia',
|
||||
'RU' => 'Russia',
|
||||
'RW' => 'Rwanda',
|
||||
'SH' => 'St. Helena',
|
||||
'KN' => 'St. Kitts & Nevis',
|
||||
'LC' => 'St. Lucia',
|
||||
'PM' => 'St. Pierre & Miquelon',
|
||||
'VC' => 'St. Vincent & Grenadines',
|
||||
'WS' => 'Samoa',
|
||||
'SM' => 'San Marino',
|
||||
'ST' => 'São Tomé & Príncipe',
|
||||
'SA' => 'Saudi Arabia',
|
||||
'SN' => 'Senegal',
|
||||
'RS' => 'Serbia',
|
||||
'SC' => 'Seychelles',
|
||||
'SL' => 'Sierra Leone',
|
||||
'SG' => 'Singapore',
|
||||
'SK' => 'Slovakia',
|
||||
'SI' => 'Slovenia',
|
||||
'SB' => 'Solomon Islands',
|
||||
'SO' => 'Somalia',
|
||||
'ZA' => 'South Africa',
|
||||
'ES' => 'Spain',
|
||||
'LK' => 'Sri Lanka',
|
||||
'SC' => 'Seychelles',
|
||||
'SD' => 'Sudan',
|
||||
'SR' => 'Suriname',
|
||||
'SJ' => 'Svalbard & Jan Mayen',
|
||||
'SZ' => 'Eswatini',
|
||||
'SE' => 'Sweden',
|
||||
'CH' => 'Switzerland',
|
||||
'SG' => 'Singapore',
|
||||
'SH' => 'St. Helena',
|
||||
'SI' => 'Slovenia',
|
||||
'SJ' => 'Svalbard & Jan Mayen',
|
||||
'SK' => 'Slovakia',
|
||||
'SL' => 'Sierra Leone',
|
||||
'SM' => 'San Marino',
|
||||
'SN' => 'Senegal',
|
||||
'SO' => 'Somalia',
|
||||
'SR' => 'Suriname',
|
||||
'SS' => 'South Sudan',
|
||||
'ST' => 'São Tomé & Príncipe',
|
||||
'SV' => 'El Salvador',
|
||||
'SX' => 'Sint Maarten',
|
||||
'SY' => 'Syria',
|
||||
'TW' => 'Taiwan',
|
||||
'TJ' => 'Tajikistan',
|
||||
'TZ' => 'Tanzania',
|
||||
'TH' => 'Thailand',
|
||||
'TL' => 'Timor-Leste',
|
||||
'TG' => 'Togo',
|
||||
'TK' => 'Tokelau',
|
||||
'TO' => 'Tonga',
|
||||
'TT' => 'Trinidad & Tobago',
|
||||
'TN' => 'Tunisia',
|
||||
'TM' => 'Turkmenistan',
|
||||
'SZ' => 'Eswatini',
|
||||
'TC' => 'Turks & Caicos Islands',
|
||||
'TD' => 'Chad',
|
||||
'TF' => 'French Southern Territories',
|
||||
'TG' => 'Togo',
|
||||
'TH' => 'Thailand',
|
||||
'TJ' => 'Tajikistan',
|
||||
'TK' => 'Tokelau',
|
||||
'TL' => 'Timor-Leste',
|
||||
'TM' => 'Turkmenistan',
|
||||
'TN' => 'Tunisia',
|
||||
'TO' => 'Tonga',
|
||||
'TR' => 'Türkiye',
|
||||
'TT' => 'Trinidad & Tobago',
|
||||
'TV' => 'Tuvalu',
|
||||
'UG' => 'Uganda',
|
||||
'TW' => 'Taiwan',
|
||||
'TZ' => 'Tanzania',
|
||||
'UA' => 'Ukraine',
|
||||
'AE' => 'United Arab Emirates',
|
||||
'GB' => 'United Kingdom',
|
||||
'UG' => 'Uganda',
|
||||
'UM' => 'U.S. Minor Outlying Islands',
|
||||
'US' => 'United States',
|
||||
'UY' => 'Uruguay',
|
||||
'UZ' => 'Uzbekistan',
|
||||
'VU' => 'Vanuatu',
|
||||
'VA' => 'Holy See (Vatican City)',
|
||||
'VC' => 'St. Vincent & Grenadines',
|
||||
'VE' => 'Venezuela',
|
||||
'VN' => 'Vietnam',
|
||||
'VG' => 'British Virgin Islands',
|
||||
'VI' => 'U.S. Virgin Islands',
|
||||
'VN' => 'Vietnam',
|
||||
'VU' => 'Vanuatu',
|
||||
'WF' => 'Wallis & Futuna',
|
||||
'EH' => 'Western Sahara',
|
||||
'WS' => 'Samoa',
|
||||
'YE' => 'Yemen',
|
||||
'YT' => 'Mayotte',
|
||||
'ZA' => 'South Africa',
|
||||
'ZM' => 'Zambia',
|
||||
'ZW' => 'Zimbabwe',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ class AuthenticateController extends Controller
|
|||
return redirect()->route('account.dashboard');
|
||||
}
|
||||
|
||||
return view('account.login', [
|
||||
return view('account.login', config('app.show_login_counter_temp') ? [
|
||||
'count' => Account::where('activated', true)->count()
|
||||
]);
|
||||
]: []);
|
||||
}
|
||||
|
||||
public function authenticate(Request $request)
|
||||
|
|
|
|||
32
flexiapi/app/Http/Controllers/Account/FileController.php
Normal file
32
flexiapi/app/Http/Controllers/Account/FileController.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Account;
|
||||
|
||||
use App\AccountFile;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class FileController extends Controller
|
||||
{
|
||||
public function show(string $uuid, string $name)
|
||||
{
|
||||
$file = AccountFile::findOrFail($uuid);
|
||||
|
||||
if ($file->name != $name) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
return Storage::get($file->path);
|
||||
}
|
||||
|
||||
public function download(string $uuid, string $name)
|
||||
{
|
||||
$file = AccountFile::findOrFail($uuid);
|
||||
|
||||
if ($file->name != $name) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
return Storage::download($file->path);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ namespace App\Http\Controllers\Account;
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PasswordController extends Controller
|
||||
|
|
@ -46,12 +47,10 @@ class PasswordController extends Controller
|
|||
|
||||
if ($account->passwords()->count() > 0) {
|
||||
Log::channel('events')->info('Web: Password changed', ['id' => $account->identifier]);
|
||||
|
||||
return redirect()->route('account.dashboard');
|
||||
return redirect()->route('account.logout');
|
||||
}
|
||||
|
||||
Log::channel('events')->info('Web: Password set for the first time', ['id' => $account->identifier]);
|
||||
|
||||
return redirect()->route('account.dashboard');
|
||||
return redirect()->route('account.logout');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ class ProvisioningController extends Controller
|
|||
private function checkProvisioningHeader(Request $request)
|
||||
{
|
||||
if (!$request->hasHeader('x-linphone-provisioning')
|
||||
&& space()?->provisioning_use_linphone_provisioning_header) {
|
||||
&& $request->space->provisioning_use_linphone_provisioning_header) {
|
||||
abort(400, 'x-linphone-provisioning header is missing');
|
||||
}
|
||||
}
|
||||
|
|
@ -172,8 +172,8 @@ class ProvisioningController extends Controller
|
|||
|
||||
$dom->appendChild($config);
|
||||
|
||||
if (space()?->custom_provisioning_entries) {
|
||||
$rc = parse_ini_string(space()->custom_provisioning_entries, true);
|
||||
if ($request->space?->custom_provisioning_entries) {
|
||||
$rc = parse_ini_string($request->space->custom_provisioning_entries, true);
|
||||
|
||||
foreach ($rc as $sectionName => $values) {
|
||||
$section = $dom->createElement('section');
|
||||
|
|
@ -189,6 +189,44 @@ class ProvisioningController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
$remoteContactDirectoryCounter = 0;
|
||||
$authInfoIndex = 0;
|
||||
|
||||
// CardDav servers
|
||||
|
||||
if ($request->space?->carddavServers) {
|
||||
foreach ($request->space->carddavServers as $carddavServer) {
|
||||
$carddavServer->getProvisioningSection($config, $remoteContactDirectoryCounter);
|
||||
$remoteContactDirectoryCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($account) {
|
||||
foreach ($account->carddavServers as $carddavServer) {
|
||||
$section = $dom->createElement('section');
|
||||
$section->setAttribute('name', 'auth_info_' . $authInfoIndex);
|
||||
$config->appendChild($section);
|
||||
|
||||
$entry = $dom->createElement('entry', $carddavServer->pivot->username);
|
||||
$entry->setAttribute('name', 'username');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $carddavServer->pivot->realm);
|
||||
$entry->setAttribute('name', 'realm');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $carddavServer->pivot->password);
|
||||
$entry->setAttribute('name', 'ha1');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $carddavServer->pivot->algorithm);
|
||||
$entry->setAttribute('name', 'algorithm');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$authInfoIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Password reset
|
||||
if ($account && $request->has('reset_password')) {
|
||||
$account->updatePassword(Str::random(10));
|
||||
|
|
@ -251,7 +289,6 @@ class ProvisioningController extends Controller
|
|||
}
|
||||
|
||||
$passwords = $account->passwords()->get();
|
||||
$authInfoIndex = 0;
|
||||
|
||||
foreach ($passwords as $password) {
|
||||
$section = $xpath->query("//section[@name='auth_info_" . $authInfoIndex . "']")->item(0);
|
||||
|
|
@ -297,7 +334,7 @@ class ProvisioningController extends Controller
|
|||
}
|
||||
|
||||
// Overwrite all the entries
|
||||
if (space()?->custom_provisioning_overwrite_all) {
|
||||
if ($request->space?->custom_provisioning_overwrite_all) {
|
||||
$xpath = new \DOMXpath($dom);
|
||||
$entries = $xpath->query("//section/entry");
|
||||
if (!is_null($entries)) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ namespace App\Http\Controllers\Account;
|
|||
use App\ResetPasswordEmailToken;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ResetPasswordEmailController extends Controller
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -26,7 +26,7 @@ use Illuminate\Support\Facades\Log;
|
|||
use App\Account;
|
||||
use App\AccountType;
|
||||
|
||||
class AccountAccountTypeController extends Controller
|
||||
class AccountTypeController extends Controller
|
||||
{
|
||||
public function create(int $id)
|
||||
{
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -27,7 +27,7 @@ use App\Account;
|
|||
use App\AccountAction;
|
||||
use App\Rules\NoUppercase;
|
||||
|
||||
class AccountActionController extends Controller
|
||||
class ActionController extends Controller
|
||||
{
|
||||
public function create(int $accountId)
|
||||
{
|
||||
|
|
@ -17,13 +17,13 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
use App\Account;
|
||||
|
||||
class AccountActivityController extends Controller
|
||||
class ActivityController extends Controller
|
||||
{
|
||||
public function index(int $accountId)
|
||||
{
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Account;
|
||||
use App\AccountCardDavCredentials;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use App\Http\Requests\Account\CardDavCredentials;
|
||||
|
||||
class CardDavCredentialsController extends Controller
|
||||
{
|
||||
public function create(int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$this->checkFeatureEnabled($account);
|
||||
|
||||
return view('admin.account.carddav.create', [
|
||||
'account' => $account,
|
||||
'carddavServers' => $account->remainingCardDavCredentialsCreatable
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(CardDavCredentials $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$this->checkFeatureEnabled($account);
|
||||
|
||||
$request->validate([
|
||||
'carddav_id' => ['required', Rule::exists('space_carddav_servers', 'id')->where(function (Builder $query) use ($account) {
|
||||
return $query->where('space_id', $account->space->id);
|
||||
})]
|
||||
]);
|
||||
|
||||
$accountCarddavCredentials = new AccountCardDavCredentials;
|
||||
$accountCarddavCredentials->space_carddav_server_id = $request->get('carddav_id');
|
||||
$accountCarddavCredentials->account_id = $account->id;
|
||||
$accountCarddavCredentials->username = $request->get('username');
|
||||
$accountCarddavCredentials->realm = $request->get('realm');
|
||||
$accountCarddavCredentials->password = bchash(
|
||||
$request->get('username'),
|
||||
$request->get('realm'),
|
||||
$request->get('password'),
|
||||
$request->get('algorithm')
|
||||
);
|
||||
$accountCarddavCredentials->algorithm = $request->get('algorithm');
|
||||
$accountCarddavCredentials->save();
|
||||
|
||||
return redirect()->route('admin.account.show', $account);
|
||||
}
|
||||
|
||||
public function delete(int $accountId, int $cardDavId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$this->checkFeatureEnabled($account);
|
||||
|
||||
$accountCarddavCredentials = AccountCardDavCredentials::where('space_carddav_server_id', $cardDavId)
|
||||
->where('account_id', $account->id)
|
||||
->firstOrFail();
|
||||
|
||||
return view('admin.account.carddav.delete', [
|
||||
'account' => $account,
|
||||
'carddavCredentials' => $accountCarddavCredentials,
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$this->checkFeatureEnabled($account);
|
||||
|
||||
$accountCarddavCredentials = AccountCardDavCredentials::where('space_carddav_server_id', $request->carddav_id)
|
||||
->where('account_id', $account->id)
|
||||
->delete();
|
||||
|
||||
return redirect()->route('admin.account.show', $account);
|
||||
}
|
||||
|
||||
private function checkFeatureEnabled(Account $account)
|
||||
{
|
||||
if (!$account->space->carddav_user_credentials) {
|
||||
abort(403, 'CardDav Credentials features disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -26,7 +26,7 @@ use Illuminate\Support\Facades\Log;
|
|||
use App\Account;
|
||||
use App\ContactsList;
|
||||
|
||||
class AccountContactController extends Controller
|
||||
class ContactController extends Controller
|
||||
{
|
||||
public function index(int $accountId)
|
||||
{
|
||||
|
|
@ -17,14 +17,14 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Account;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Libraries\FlexisipRedisConnector;
|
||||
|
||||
class AccountDeviceController extends Controller
|
||||
class DeviceController extends Controller
|
||||
{
|
||||
public function index(int $accountId)
|
||||
{
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -25,7 +25,7 @@ use Illuminate\Http\Request;
|
|||
use App\Account;
|
||||
use App\AccountDictionaryEntry;
|
||||
|
||||
class AccountDictionaryController extends Controller
|
||||
class DictionaryController extends Controller
|
||||
{
|
||||
public function create(int $accountId)
|
||||
{
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Account;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class FileController extends Controller
|
||||
{
|
||||
public function delete(int $accountId, string $fileId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$file = $account->files()->where('id', $fileId)->firstOrFail();
|
||||
|
||||
return view('admin.account.file.delete', [
|
||||
'account' => $account,
|
||||
'file' => $file
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $accountId, string $fileId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$accountFile = $account->files()
|
||||
->where('id', $fileId)
|
||||
->firstOrFail();
|
||||
$accountFile->delete();
|
||||
|
||||
return redirect()->route('admin.account.show', $account)->withFragment('#files');
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Account;
|
||||
use App\ExternalAccount;
|
||||
|
|
@ -32,7 +32,7 @@ use Illuminate\Support\Facades\Storage;
|
|||
use Illuminate\Validation\Rules\File;
|
||||
use Propaganistas\LaravelPhone\PhoneNumber;
|
||||
|
||||
class AccountImportController extends Controller
|
||||
class ImportController extends Controller
|
||||
{
|
||||
private Collection $errors;
|
||||
private string $importDirectory = 'imported_csv';
|
||||
|
|
@ -307,7 +307,7 @@ class AccountImportController extends Controller
|
|||
'account_id' => $passwordAccount->id,
|
||||
'password' => bchash(
|
||||
$passwordAccount->username,
|
||||
space()?->account_realm ?? $domain,
|
||||
$request->space?->account_realm ?? $domain,
|
||||
$passwords[$passwordAccount->username],
|
||||
$algorithm
|
||||
),
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Account;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
|
@ -26,7 +26,7 @@ use App\StatisticsCall;
|
|||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AccountStatisticsController extends Controller
|
||||
class StatisticsController extends Controller
|
||||
{
|
||||
public function edit(Request $request, int $accountId)
|
||||
{
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -27,7 +27,7 @@ use Illuminate\Validation\Rule;
|
|||
use App\AccountType;
|
||||
use App\Rules\NoUppercase;
|
||||
|
||||
class AccountTypeController extends Controller
|
||||
class TypeController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin\Space;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Space\CardDavServer;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Space;
|
||||
use App\SpaceCardDavServer;
|
||||
|
||||
class CardDavServerController extends Controller
|
||||
{
|
||||
public function create(Space $space)
|
||||
{
|
||||
return view('admin.space.carddav_server.create_edit', [
|
||||
'space' => $space,
|
||||
'carddavServer' => new SpaceCardDavServer
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(CardDavServer $request, Space $space)
|
||||
{
|
||||
$carddavServer = new SpaceCardDavServer;
|
||||
$carddavServer->space_id = $space->id;
|
||||
$carddavServer->fill($request->validated());
|
||||
$carddavServer->enabled = getRequestBoolean($request, 'enabled');
|
||||
$carddavServer->use_exact_match_policy = getRequestBoolean($request, 'use_exact_match_policy');
|
||||
$carddavServer->save();
|
||||
|
||||
return redirect()->route('admin.spaces.integration', $space);
|
||||
}
|
||||
|
||||
public function edit(Space $space, int $carddavServerId)
|
||||
{
|
||||
return view('admin.space.carddav_server.create_edit', [
|
||||
'space' => $space,
|
||||
'carddavServer' => $space->carddavServers()->findOrFail($carddavServerId)
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(CardDavServer $request, Space $space, int $carddavServerId)
|
||||
{
|
||||
$carddavServer = $space->carddavServers()->findOrFail($carddavServerId);
|
||||
$carddavServer->fill($request->validated());
|
||||
$carddavServer->enabled = getRequestBoolean($request, 'enabled');
|
||||
$carddavServer->use_exact_match_policy = getRequestBoolean($request, 'use_exact_match_policy');
|
||||
$carddavServer->save();
|
||||
|
||||
return redirect()->route('admin.spaces.integration', $space);
|
||||
}
|
||||
|
||||
public function delete(Space $space, int $carddavServerId)
|
||||
{
|
||||
return view('admin.space.carddav_server.delete', [
|
||||
'space' => $space,
|
||||
'carddavServer' => $space->carddavServers()->findOrFail($carddavServerId)
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Space $space, int $carddavServerId)
|
||||
{
|
||||
$carddavServer = $space->carddavServers()->findOrFail($carddavServerId);
|
||||
$carddavServer->delete();
|
||||
|
||||
return redirect()->route('admin.spaces.integration', $space->id);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,18 +17,19 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Space;
|
||||
|
||||
use App\Account;
|
||||
use App\ContactsList;
|
||||
use App\Space;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ContactsListContactController extends Controller
|
||||
{
|
||||
public function add(Request $request, int $contactsListId)
|
||||
public function add(Request $request, Space $space, int $contactsListId)
|
||||
{
|
||||
$accounts = Account::orderBy('updated_at', $request->get('updated_at_order', 'desc'));
|
||||
$accounts = $space->accounts()->orderBy('updated_at', $request->get('updated_at_order', 'desc'));
|
||||
|
||||
if ($request->has('search')) {
|
||||
$accounts = $accounts->where('username', 'like', '%' . $request->get('search') . '%');
|
||||
|
|
@ -38,9 +39,9 @@ class ContactsListContactController extends Controller
|
|||
$accounts = $accounts->where('domain', $request->get('domain'));
|
||||
}
|
||||
|
||||
return view('admin.contacts_list.contacts.add', [
|
||||
'domains' => Account::groupBy('domain')->pluck('domain'),
|
||||
'contacts_list' => ContactsList::findOrFail($contactsListId),
|
||||
return view('admin.space.contacts_list.contacts.add', [
|
||||
'space' => $space,
|
||||
'contacts_list' => $space->contactsLists()->findOrFail($contactsListId),
|
||||
'params' => [
|
||||
'contacts_list_id' => $contactsListId
|
||||
],
|
||||
|
|
@ -52,33 +53,33 @@ class ContactsListContactController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
public function search(Request $request, int $contactsListId)
|
||||
public function search(Request $request, Space $space, int $contactsListId)
|
||||
{
|
||||
return redirect()->route('admin.contacts_lists.contacts.add', ['contacts_list_id' => $contactsListId] + $request->except('_token'));
|
||||
return redirect()->route('admin.spaces.contacts_lists.contacts.add', ['contacts_list_id' => $contactsListId] + $request->except('_token'));
|
||||
}
|
||||
|
||||
public function store(Request $request, int $contactsListId)
|
||||
public function store(Request $request, Space $space, int $contactsListId)
|
||||
{
|
||||
$request->validate([
|
||||
'contacts_ids' => 'required|exists:accounts,id'
|
||||
]);
|
||||
|
||||
$contactsList = ContactsList::findOrFail($contactsListId);
|
||||
$contactsList = $space->contactsLists()->findOrFail($contactsListId);
|
||||
$contactsList->contacts()->detach($request->get('contacts_ids')); // Just in case
|
||||
$contactsList->contacts()->attach($request->get('contacts_ids'));
|
||||
|
||||
return redirect()->route('admin.contacts_lists.edit', $contactsList->id);
|
||||
return redirect()->route('admin.spaces.contacts_lists.edit', [$space, $contactsList->id]);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $contactsListId)
|
||||
public function destroy(Request $request, Space $space, int $contactsListId)
|
||||
{
|
||||
$request->validate([
|
||||
'contacts_ids' => 'required|exists:accounts,id'
|
||||
]);
|
||||
|
||||
$contactsList = ContactsList::findOrFail($contactsListId);
|
||||
$contactsList = $space->contactsLists()->findOrFail($contactsListId);
|
||||
$contactsList->contacts()->detach($request->get('contacts_ids'));
|
||||
|
||||
return redirect()->route('admin.contacts_lists.edit', $contactsList->id);
|
||||
return redirect()->route('admin.spaces.contacts_lists.edit', [$space, $contactsList->id]);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,61 +17,67 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
namespace App\Http\Controllers\Admin\Space;
|
||||
|
||||
use App\Account;
|
||||
use App\ContactsList;
|
||||
use App\Space;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ContactsListController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
public function index(Request $request, Space $space)
|
||||
{
|
||||
$request->validate([
|
||||
'order_by' => 'in:title,updated_at,contacts_count',
|
||||
'order_sort' => 'in:asc,desc',
|
||||
]);
|
||||
|
||||
$contactsLists = ContactsList::orderBy($request->get('order_by', 'updated_at'), $request->get('order_sort', 'desc'));
|
||||
$contactsLists = $space->contactsLists()->orderBy($request->get('order_by', 'updated_at'), $request->get('order_sort', 'desc'));
|
||||
|
||||
return view('admin.contacts_list.index', [
|
||||
return view('admin.space.contacts_list.index', [
|
||||
'space' => $space,
|
||||
'contacts_lists' => $contactsLists
|
||||
->paginate(20)
|
||||
->appends($request->query()),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(Request $request)
|
||||
public function create(Request $request, Space $space)
|
||||
{
|
||||
return view('admin.contacts_list.create_edit', [
|
||||
return view('admin.space.contacts_list.create_edit', [
|
||||
'space' => $space,
|
||||
'contacts_list' => new ContactsList,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
public function store(Request $request, Space $space)
|
||||
{
|
||||
$request->validate([
|
||||
'title' => 'required|unique:contacts_lists'
|
||||
]);
|
||||
|
||||
$contactsList = new ContactsList;
|
||||
$contactsList->space_id = $space->id;
|
||||
$contactsList->title = $request->get('title');
|
||||
$contactsList->description = $request->get('description');
|
||||
$contactsList->save();
|
||||
|
||||
return redirect()->route('admin.contacts_lists.edit', $contactsList->id);
|
||||
return redirect()->route('admin.spaces.contacts_lists.edit', [$space, $contactsList->id]);
|
||||
}
|
||||
|
||||
public function search(Request $request, int $contactsListId)
|
||||
public function search(Request $request, Space $space, int $contactsListId)
|
||||
{
|
||||
return redirect()->route('admin.contacts_lists.edit', ['contacts_list_id' => $contactsListId] + $request->except('_token'));
|
||||
return redirect()->route('admin.spaces.contacts_lists.edit', [
|
||||
'space' => $space,
|
||||
'contacts_list_id' => $contactsListId] + $request->except('_token'));
|
||||
}
|
||||
|
||||
public function edit(Request $request, int $id)
|
||||
public function edit(Request $request, Space $space, int $id)
|
||||
{
|
||||
$contacts = ContactsList::findOrFail($id)->contacts();
|
||||
$contacts = $space->contactsLists()->findOrFail($id)->contacts();
|
||||
|
||||
if ($request->has('search')) {
|
||||
$contacts = $contacts->where('username', 'like', '%' . $request->get('search') . '%');
|
||||
|
|
@ -83,14 +89,15 @@ class ContactsListController extends Controller
|
|||
|
||||
$contacts = $contacts->get();
|
||||
|
||||
return view('admin.contacts_list.create_edit', [
|
||||
return view('admin.space.contacts_list.create_edit', [
|
||||
'space' => $space,
|
||||
'domains' => Account::groupBy('domain')->pluck('domain'),
|
||||
'contacts_list' => ContactsList::findOrFail($id),
|
||||
'contacts_list' => $space->contactsLists()->findOrFail($id),
|
||||
'contacts' => $contacts
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, int $id)
|
||||
public function update(Request $request, Space $space, int $id)
|
||||
{
|
||||
$request->validate([
|
||||
'title' => [
|
||||
|
|
@ -99,26 +106,27 @@ class ContactsListController extends Controller
|
|||
],
|
||||
]);
|
||||
|
||||
$contactsList = ContactsList::findOrFail($id);
|
||||
$contactsList = $space->contactsLists()->findOrFail($id);
|
||||
$contactsList->title = $request->get('title');
|
||||
$contactsList->description = $request->get('description');
|
||||
$contactsList->save();
|
||||
|
||||
return redirect()->route('admin.contacts_lists.index');
|
||||
return redirect()->route('admin.spaces.contacts_lists.index', $space);
|
||||
}
|
||||
|
||||
public function delete(int $id)
|
||||
public function delete(Space $space, int $id)
|
||||
{
|
||||
return view('admin.contacts_list.delete', [
|
||||
'contacts_list' => ContactsList::findOrFail($id),
|
||||
return view('admin.space.contacts_list.delete', [
|
||||
'space' => $space,
|
||||
'contacts_list' => $space->contactsLists()->findOrFail($id),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Request $request)
|
||||
public function destroy(Request $request, Space $space)
|
||||
{
|
||||
$contactsList = ContactsList::findOrFail($request->get('contacts_lists_id'));
|
||||
$contactsList = $space->contactsLists()->findOrFail($request->get('contacts_lists_id'));
|
||||
$contactsList->delete();
|
||||
|
||||
return redirect()->route('admin.contacts_lists.index');
|
||||
return redirect()->route('admin.spaces.contacts_lists.index', $space);
|
||||
}
|
||||
}
|
||||
|
|
@ -146,6 +146,7 @@ class SpaceController extends Controller
|
|||
$space->expire_at = $request->get('expire_at');
|
||||
$space->custom_theme = getRequestBoolean($request, 'custom_theme');
|
||||
$space->web_panel = getRequestBoolean($request, 'web_panel');
|
||||
$space->carddav_user_credentials = getRequestBoolean($request, 'carddav_user_credentials');
|
||||
$space->save();
|
||||
|
||||
return redirect()->route('admin.spaces.show', $space);
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class StatisticsController extends Controller
|
|||
|
||||
$domain = $request->user()->superAdmin
|
||||
? $request->get('domain')
|
||||
: $request->user()->domain;
|
||||
: $request->space->domain;
|
||||
|
||||
if ($domain) {
|
||||
$fromQuery->where('to_domain', $domain);
|
||||
|
|
|
|||
42
flexiapi/app/Http/Controllers/Api/Account/FileController.php
Normal file
42
flexiapi/app/Http/Controllers/Api/Account/FileController.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Account;
|
||||
|
||||
use App\AccountFile;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Rules\AudioMime;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class FileController extends Controller
|
||||
{
|
||||
public function upload(Request $request, string $uuid)
|
||||
{
|
||||
$file = AccountFile::findOrFail($uuid);
|
||||
|
||||
if (!empty($file->name)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$request->validate(['file' => 'required|file']);
|
||||
|
||||
if ($file->isVoicemailAudio()) {
|
||||
$request->validate(['file' => [new AudioMime($file)]]);
|
||||
}
|
||||
|
||||
$uploadedFile = $request->file('file');
|
||||
$name = Str::random(8) . '_' . $uploadedFile->getClientOriginalName();
|
||||
|
||||
if ($uploadedFile->storeAs(AccountFile::FILES_PATH, $name)) {
|
||||
$file->name = $name;
|
||||
$file->size = $uploadedFile->getSize();
|
||||
$file->uploaded_at = Carbon::now();
|
||||
$file->save();
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
abort(503);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,12 +10,12 @@ class VcardsStorageController extends Controller
|
|||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
return (new AdminVcardsStorageController)->index($request->user()->id);
|
||||
return (new AdminVcardsStorageController)->index($request, $request->user()->id);
|
||||
}
|
||||
|
||||
public function show(Request $request, string $uuid)
|
||||
{
|
||||
return (new AdminVcardsStorageController)->show($request->user()->id, $uuid);
|
||||
return (new AdminVcardsStorageController)->show($request, $request->user()->id, $uuid);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Controllers\Api\Admin\Account\VoicemailController as AdminVoicemailController;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class VoicemailController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
return (new AdminVoicemailController)->index($request, $request->user()->id);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
return (new AdminVoicemailController)->store($request, $request->user()->id);
|
||||
}
|
||||
|
||||
public function show(Request $request, string $uuid)
|
||||
{
|
||||
return (new AdminVoicemailController)->show($request, $request->user()->id, $uuid);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, string $uuid)
|
||||
{
|
||||
return (new AdminVoicemailController)->destroy($request, $request->user()->id, $uuid);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,33 +17,32 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
namespace App\Http\Controllers\Api\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Account;
|
||||
use App\AccountAction;
|
||||
use App\Rules\NoUppercase;
|
||||
|
||||
class AccountActionController extends Controller
|
||||
class ActionController extends Controller
|
||||
{
|
||||
public function index(int $id)
|
||||
public function index(Request $request, int $accountId)
|
||||
{
|
||||
return $this->resolveAccount($id)->actions;
|
||||
return $this->resolveAccount($request, $accountId)->actions;
|
||||
}
|
||||
|
||||
public function get(int $id, int $actionId)
|
||||
public function get(Request $request, int $accountId, int $actionId)
|
||||
{
|
||||
return $this->resolveAccount($id)
|
||||
return $this->resolveAccount($request, $accountId)
|
||||
->actions()
|
||||
->where('id', $actionId)
|
||||
->firstOrFail();
|
||||
}
|
||||
|
||||
public function store(Request $request, int $id)
|
||||
public function store(Request $request, int $accountId)
|
||||
{
|
||||
$account = $this->resolveAccount($id);
|
||||
$account = $this->resolveAccount($request, $accountId);
|
||||
|
||||
$request->validate([
|
||||
'key' => ['required', 'alpha_dash', new NoUppercase],
|
||||
|
|
@ -59,9 +58,9 @@ class AccountActionController extends Controller
|
|||
return $accountAction;
|
||||
}
|
||||
|
||||
public function update(Request $request, int $id, int $actionId)
|
||||
public function update(Request $request, int $accountId, int $actionId)
|
||||
{
|
||||
$account = $this->resolveAccount($id);
|
||||
$account = $this->resolveAccount($request, $accountId);
|
||||
|
||||
$request->validate([
|
||||
'key' => ['alpha_dash', new NoUppercase],
|
||||
|
|
@ -79,17 +78,17 @@ class AccountActionController extends Controller
|
|||
return $accountAction;
|
||||
}
|
||||
|
||||
public function destroy(int $id, int $actionId)
|
||||
public function destroy(Request $request, int $accountId, int $actionId)
|
||||
{
|
||||
return $this->resolveAccount($id)
|
||||
return $this->resolveAccount($request, $accountId)
|
||||
->actions()
|
||||
->where('id', $actionId)
|
||||
->delete();
|
||||
}
|
||||
|
||||
private function resolveAccount(int $id)
|
||||
private function resolveAccount(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
if ($account->dtmf_protocol == null) abort(403, 'DTMF Protocol must be configured');
|
||||
|
||||
return $account;
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Account;
|
||||
use App\Space;
|
||||
use App\AccountCardDavCredentials;
|
||||
use App\SpaceCardDavServer;
|
||||
use App\Http\Requests\Account\CardDavCredentials;
|
||||
|
||||
class CardDavCredentialsController extends Controller
|
||||
{
|
||||
public function index(Request $request, int $accountId)
|
||||
{
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$cardDavServers = $account->carddavServers;
|
||||
|
||||
if ($cardDavServers->isEmpty()) return new \stdClass;
|
||||
|
||||
return $cardDavServers->map(function ($cardDavServer) {
|
||||
return $this->extractCardDavServer($cardDavServer);
|
||||
})->keyBy('carddav_id');
|
||||
}
|
||||
|
||||
public function show(Request $request, int $accountId, int $cardDavServerId)
|
||||
{
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$cardDavServer = $account->cardDavServers()->findOrFail($cardDavServerId);
|
||||
|
||||
return $this->extractCardDavServer($cardDavServer);
|
||||
}
|
||||
|
||||
public function update(CardDavCredentials $request, int $accountId, int $cardDavServerId)
|
||||
{
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$cardDavServer = $request->space->cardDavServers()->findOrFail($cardDavServerId);
|
||||
|
||||
$accountCarddavCredentials = AccountCardDavCredentials::where('account_id', $account->id)
|
||||
->where('space_carddav_server_id', $cardDavServer->id)
|
||||
->delete();
|
||||
|
||||
$accountCarddavCredentials = new AccountCardDavCredentials;
|
||||
$accountCarddavCredentials->space_carddav_server_id = $cardDavServer->id;
|
||||
$accountCarddavCredentials->account_id = $account->id;
|
||||
$accountCarddavCredentials->username = $request->get('username');
|
||||
$accountCarddavCredentials->realm = $request->get('realm');
|
||||
$accountCarddavCredentials->password = bchash(
|
||||
$request->get('username'),
|
||||
$request->get('realm'),
|
||||
$request->get('password'),
|
||||
$request->get('algorithm')
|
||||
);
|
||||
$accountCarddavCredentials->algorithm = $request->get('algorithm');
|
||||
return $accountCarddavCredentials->save();
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $accountId, int $cardDavServerId)
|
||||
{
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$cardDavServer = $account->cardDavServers()->findOrFail($cardDavServerId);
|
||||
|
||||
return $cardDavServer->delete();
|
||||
}
|
||||
|
||||
private function extractCardDavServer(SpaceCardDavServer $cardDavServer)
|
||||
{
|
||||
return [
|
||||
'carddav_id' => $cardDavServer->id,
|
||||
'username' => $cardDavServer->pivot->username,
|
||||
'realm' => $cardDavServer->pivot->realm,
|
||||
'algorithm' => $cardDavServer->pivot->algorithm,
|
||||
'password' => $cardDavServer->pivot->password,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -17,40 +17,39 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
namespace App\Http\Controllers\Api\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Account;
|
||||
|
||||
class AccountContactController extends Controller
|
||||
class ContactController extends Controller
|
||||
{
|
||||
public function index(int $id)
|
||||
public function index(Request $request, int $accountId)
|
||||
{
|
||||
return Account::findOrFail($id)->contacts;
|
||||
return $request->space->accounts()->findOrFail($accountId)->contacts;
|
||||
}
|
||||
|
||||
public function show(int $id, int $contactId)
|
||||
public function show(Request $request, int $accountId, int $contactId)
|
||||
{
|
||||
return Account::findOrFail($id)
|
||||
return $request->space->accounts()->findOrFail($accountId)
|
||||
->contacts()
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
}
|
||||
|
||||
public function add(int $id, int $contactId)
|
||||
public function add(Request $request, int $accountId, int $contactId)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$account->contacts()->detach($contactId);
|
||||
|
||||
if (Account::findOrFail($contactId)) {
|
||||
if ($request->space->accounts()->findOrFail($contactId)) {
|
||||
return $account->contacts()->attach($contactId);
|
||||
}
|
||||
}
|
||||
|
||||
public function remove(int $id, int $contactId)
|
||||
public function remove(Request $request, int $accountId, int $contactId)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
|
||||
if (!$account->contacts()->pluck('id')->contains($contactId)) {
|
||||
abort(404);
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
namespace App\Http\Controllers\Api\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -26,7 +26,7 @@ use Illuminate\Support\Str;
|
|||
use App\AccountCreationToken;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
|
||||
class AccountCreationTokenController extends Controller
|
||||
class CreationTokenController extends Controller
|
||||
{
|
||||
public function create(Request $request)
|
||||
{
|
||||
|
|
@ -17,23 +17,23 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
namespace App\Http\Controllers\Api\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Account;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AccountDictionaryController extends Controller
|
||||
class DictionaryController extends Controller
|
||||
{
|
||||
public function index(int $accountId)
|
||||
public function index(Request $request, int $accountId)
|
||||
{
|
||||
return Account::findOrFail($accountId)->dictionary;
|
||||
return $request->space->accounts()->findOrFail($accountId)->dictionary;
|
||||
}
|
||||
|
||||
public function show(int $accountId, string $key)
|
||||
public function show(Request $request, int $accountId, string $key)
|
||||
{
|
||||
return Account::findOrFail($accountId)->dictionaryEntries()->where('key', $key)->first();
|
||||
return $request->space->accounts()
|
||||
->findOrFail($accountId)->dictionaryEntries()->where('key', $key)->first();
|
||||
}
|
||||
|
||||
public function set(Request $request, int $accountId, string $key)
|
||||
|
|
@ -42,7 +42,7 @@ class AccountDictionaryController extends Controller
|
|||
'value' => 'required'
|
||||
]);
|
||||
|
||||
$account = Account::findOrFail($accountId);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$result = $account->setDictionaryEntry($key, $request->get('value'));
|
||||
|
||||
if (function_exists('accountServiceAccountEditedHook')) {
|
||||
|
|
@ -53,8 +53,15 @@ class AccountDictionaryController extends Controller
|
|||
return $result;
|
||||
}
|
||||
|
||||
public function destroy(int $accountId, string $key)
|
||||
public function destroy(Request $request, int $accountId, string $key)
|
||||
{
|
||||
return Account::findOrFail($accountId)->dictionaryEntries()->where('key', $key)->delete();
|
||||
return $request->space->accounts()
|
||||
->findOrFail($accountId)->dictionaryEntries()->where('key', $key)->delete();
|
||||
}
|
||||
|
||||
public function clear(Request $request, int $accountId)
|
||||
{
|
||||
return $request->space->accounts()
|
||||
->findOrFail($accountId)->dictionaryEntries()->delete();
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
namespace App\Http\Controllers\Api\Admin\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Rules\NoUppercase;
|
||||
|
|
@ -25,7 +25,7 @@ use Illuminate\Http\Request;
|
|||
|
||||
use App\AccountType;
|
||||
|
||||
class AccountTypeController extends Controller
|
||||
class TypeController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\Account;
|
||||
|
||||
use App\Account;
|
||||
use App\AccountFile;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class VoicemailController extends Controller
|
||||
{
|
||||
public function index(Request $request, int $accountId)
|
||||
{
|
||||
return Account::findOrFail($accountId)->voicemails;
|
||||
}
|
||||
|
||||
public function store(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$request->validate([
|
||||
'sip_from' => 'nullable|starts_with:sip',
|
||||
'content_type' => [
|
||||
'required',
|
||||
Rule::in(AccountFile::VOICEMAIL_CONTENTTYPES),
|
||||
]
|
||||
]);
|
||||
|
||||
$voicemail = new AccountFile;
|
||||
$voicemail->account_id = $account->id;
|
||||
$voicemail->sip_from = $request->get('sip_from');
|
||||
$voicemail->content_type = $request->get('content_type');
|
||||
$voicemail->save();
|
||||
|
||||
$voicemail->append(['upload_url', 'max_upload_size']);
|
||||
|
||||
return $voicemail;
|
||||
}
|
||||
|
||||
public function show(Request $request, int $accountId, string $uuid)
|
||||
{
|
||||
return Account::findOrFail($accountId)->voicemails()->where('id', $uuid)->firstOrFail();
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $accountId, string $uuid)
|
||||
{
|
||||
return Account::findOrFail($accountId)->voicemails()->where('id', $uuid)->delete();
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,6 @@ use Illuminate\Support\Str;
|
|||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
use App\Account;
|
||||
use App\AccountTombstone;
|
||||
use App\AccountType;
|
||||
use App\ContactsList;
|
||||
|
|
@ -35,18 +34,23 @@ use App\Http\Requests\Account\Update\Api\AsAdminRequest as ApiAsAdminRequest;
|
|||
use App\Mail\Provisioning;
|
||||
use App\Mail\ResetPassword;
|
||||
use App\Services\AccountService;
|
||||
use App\Space;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
return Account::without(['passwords', 'admin'])->with(['phoneChangeCode', 'emailChangeCode'])->paginate(20);
|
||||
return $request->space->accounts()
|
||||
->without(['passwords', 'admin'])
|
||||
->with(['phoneChangeCode', 'emailChangeCode'])
|
||||
->paginate(20);
|
||||
}
|
||||
|
||||
public function show(Request $request, $accountId)
|
||||
{
|
||||
$account = Account::without(['passwords', 'admin'])->with(['phoneChangeCode', 'emailChangeCode'])->findOrFail($accountId);
|
||||
$account = $request->space->accounts()
|
||||
->without(['passwords', 'admin'])
|
||||
->with(['phoneChangeCode', 'emailChangeCode'])
|
||||
->findOrFail($accountId);
|
||||
|
||||
if ($request->user()->admin) {
|
||||
if ($account->phoneChangeCode) {
|
||||
|
|
@ -61,27 +65,29 @@ class AccountController extends Controller
|
|||
return $account;
|
||||
}
|
||||
|
||||
public function search(string $sip)
|
||||
public function search(Request $request, string $sip)
|
||||
{
|
||||
$account = Account::sip($sip)->first();
|
||||
$account = $request->space->accounts()->sip($sip)->first();
|
||||
|
||||
if (!$account) abort(404, 'SIP address not found');
|
||||
if (!$account)
|
||||
abort(404, 'SIP address not found');
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
public function searchByEmail(string $email)
|
||||
public function searchByEmail(Request $request, string $email)
|
||||
{
|
||||
$account = Account::where('email', $email)->first();
|
||||
$account = $request->space->accounts()->where('email', $email)->first();
|
||||
|
||||
if (!$account) abort(404, 'Email address not found');
|
||||
if (!$account)
|
||||
abort(404, 'Email address not found');
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
|
||||
if (!$account->hasTombstone()) {
|
||||
$tombstone = new AccountTombstone();
|
||||
|
|
@ -95,9 +101,9 @@ class AccountController extends Controller
|
|||
Log::channel('events')->info('API Admin: Account destroyed', ['id' => $account->identifier]);
|
||||
}
|
||||
|
||||
public function activate(int $accountId)
|
||||
public function activate(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$account->activated = true;
|
||||
$account->save();
|
||||
|
||||
|
|
@ -106,9 +112,9 @@ class AccountController extends Controller
|
|||
return $account;
|
||||
}
|
||||
|
||||
public function deactivate(int $accountId)
|
||||
public function deactivate(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$account->activated = false;
|
||||
$account->save();
|
||||
|
||||
|
|
@ -117,9 +123,9 @@ class AccountController extends Controller
|
|||
return $account;
|
||||
}
|
||||
|
||||
public function block(int $accountId)
|
||||
public function block(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$account->blocked = true;
|
||||
$account->save();
|
||||
|
||||
|
|
@ -128,9 +134,9 @@ class AccountController extends Controller
|
|||
return $account;
|
||||
}
|
||||
|
||||
public function unblock(int $accountId)
|
||||
public function unblock(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$account->blocked = false;
|
||||
$account->save();
|
||||
|
||||
|
|
@ -139,9 +145,9 @@ class AccountController extends Controller
|
|||
return $account;
|
||||
}
|
||||
|
||||
public function provision(int $accountId)
|
||||
public function provision(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
$account->provision();
|
||||
$account->save();
|
||||
|
||||
|
|
@ -164,55 +170,56 @@ class AccountController extends Controller
|
|||
return $account->makeVisible(['provisioning_token']);
|
||||
}
|
||||
|
||||
public function typeAdd(int $accountId, int $typeId)
|
||||
public function typeAdd(Request $request, int $accountId, int $typeId)
|
||||
{
|
||||
if (Account::findOrFail($accountId)->types()->pluck('id')->contains($typeId)) {
|
||||
if ($request->space->accounts()->findOrFail($accountId)->types()->pluck('id')->contains($typeId)) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
if (AccountType::findOrFail($typeId)) {
|
||||
return Account::findOrFail($accountId)->types()->attach($typeId);
|
||||
return $request->space->accounts()->findOrFail($accountId)->types()->attach($typeId);
|
||||
}
|
||||
}
|
||||
|
||||
public function typeRemove(int $accountId, int $typeId)
|
||||
public function typeRemove(Request $request, int $accountId, int $typeId)
|
||||
{
|
||||
if (!Account::findOrFail($accountId)->types()->pluck('id')->contains($typeId)) {
|
||||
if (!$request->space->accounts()->findOrFail($accountId)->types()->pluck('id')->contains($typeId)) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
return Account::findOrFail($accountId)->types()->detach($typeId);
|
||||
return $request->space->accounts()->findOrFail($accountId)->types()->detach($typeId);
|
||||
}
|
||||
|
||||
public function contactsListAdd(int $accountId, int $contactsListId)
|
||||
public function contactsListAdd(Request $request, int $accountId, int $contactsListId)
|
||||
{
|
||||
if (Account::findOrFail($accountId)->contactsLists()->pluck('id')->contains($contactsListId)) {
|
||||
if ($request->space->accounts()->findOrFail($accountId)->contactsLists()->pluck('id')->contains($contactsListId)) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
if (ContactsList::findOrFail($contactsListId)) {
|
||||
return Account::findOrFail($accountId)->contactsLists()->attach($contactsListId);
|
||||
return $request->space->accounts()->findOrFail($accountId)->contactsLists()->attach($contactsListId);
|
||||
}
|
||||
}
|
||||
|
||||
public function contactsListRemove(int $accountId, int $contactsListId)
|
||||
public function contactsListRemove(Request $request, int $accountId, int $contactsListId)
|
||||
{
|
||||
if (!Account::findOrFail($accountId)->contactsLists()->pluck('id')->contains($contactsListId)) {
|
||||
if (!$request->space->accounts()->findOrFail($accountId)->contactsLists()->pluck('id')->contains($contactsListId)) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
return Account::findOrFail($accountId)->contactsLists()->detach($contactsListId);
|
||||
return $request->space->accounts()->findOrFail($accountId)->contactsLists()->detach($contactsListId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emails
|
||||
*/
|
||||
|
||||
public function sendProvisioningEmail(int $accountId)
|
||||
public function sendProvisioningEmail(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
|
||||
if (!$account->email) abort(403, 'No email configured');
|
||||
if (!$account->email)
|
||||
abort(403, 'No email configured');
|
||||
|
||||
$account->provision();
|
||||
|
||||
|
|
@ -221,11 +228,12 @@ class AccountController extends Controller
|
|||
Log::channel('events')->info('API: Sending provisioning email', ['id' => $account->identifier]);
|
||||
}
|
||||
|
||||
public function sendResetPasswordEmail(int $accountId)
|
||||
public function sendResetPasswordEmail(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
$account = $request->space->accounts()->findOrFail($accountId);
|
||||
|
||||
if (!$account->email) abort(403, 'No email configured');
|
||||
if (!$account->email)
|
||||
abort(403, 'No email configured');
|
||||
|
||||
$resetPasswordEmail = new ResetPasswordEmailToken;
|
||||
$resetPasswordEmail->account_id = $account->id;
|
||||
|
|
|
|||
|
|
@ -22,21 +22,27 @@ namespace App\Http\Controllers\Api\Admin;
|
|||
use App\Http\Controllers\Controller;
|
||||
use App\Libraries\FlexisipRedisConnector;
|
||||
use App\Account;
|
||||
use Illuminate\Http\Request;
|
||||
use stdClass;
|
||||
|
||||
class DeviceController extends Controller
|
||||
{
|
||||
public function index(int $accountId)
|
||||
public function index(Request $request, int $accountId)
|
||||
{
|
||||
$devices = (new FlexisipRedisConnector)->getDevices(Account::findOrFail($accountId)->identifier);
|
||||
$devices = (new FlexisipRedisConnector)->getDevices(
|
||||
$request->space->accounts()->findOrFail($accountId)->identifier
|
||||
);
|
||||
|
||||
return ($devices->isEmpty()) ? new stdClass : $devices;
|
||||
}
|
||||
|
||||
public function destroy(int $accountId, string $uuid)
|
||||
public function destroy(Request $request, int $accountId, string $uuid)
|
||||
{
|
||||
$connector = new FlexisipRedisConnector;
|
||||
|
||||
return $connector->deleteDevice(Account::findOrFail($accountId)->identifier, $uuid);
|
||||
return $connector->deleteDevice(
|
||||
$request->space->accounts()->findOrFail($accountId)->identifier,
|
||||
$uuid
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,16 +23,12 @@ use App\Http\Controllers\Controller;
|
|||
use App\Http\Requests\ExternalAccount\CreateUpdate;
|
||||
use App\Services\AccountService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
use App\ExternalAccount;
|
||||
use App\Account;
|
||||
|
||||
class ExternalAccountController extends Controller
|
||||
{
|
||||
public function show(int $accountId)
|
||||
public function show(Request $request, int $accountId)
|
||||
{
|
||||
return Account::findOrFail($accountId)->external()->firstOrFail();
|
||||
return $request->space->accounts()->findOrFail($accountId)->external()->firstOrFail();
|
||||
}
|
||||
|
||||
public function store(CreateUpdate $request, int $accountId)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\PhoneCountry;
|
||||
|
||||
class PhoneCountryController extends Controller
|
||||
{
|
||||
public function activate(string $code)
|
||||
{
|
||||
$phoneCountry = PhoneCountry::where('code', $code)->firstOrFail();
|
||||
return PhoneCountry::where('country_code', $phoneCountry->country_code)->update(['activated' => true]);
|
||||
}
|
||||
|
||||
public function deactivate(string $code)
|
||||
{
|
||||
$phoneCountry = PhoneCountry::where('code', $code)->firstOrFail();
|
||||
return PhoneCountry::where('country_code', $phoneCountry->country_code)->update(['activated' => false]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\Space;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Space\CardDavServer;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Space;
|
||||
use App\SpaceCardDavServer;
|
||||
|
||||
class CardDavServerController extends Controller
|
||||
{
|
||||
public function index(string $domain)
|
||||
{
|
||||
return Space::where('domain', $domain)->firstOrFail()->carddavServers;
|
||||
}
|
||||
|
||||
public function show(string $domain, int $carddavServerId)
|
||||
{
|
||||
return Space::where('domain', $domain)->firstOrFail()->carddavServers()->findOrFail($carddavServerId);
|
||||
}
|
||||
|
||||
public function store(CardDavServer $request, string $domain)
|
||||
{
|
||||
$space = Space::where('domain', $domain)->firstOrFail();
|
||||
|
||||
$carddavServer = new SpaceCardDavServer;
|
||||
$carddavServer->space_id = $space->id;
|
||||
$carddavServer->fill($request->validated());
|
||||
$carddavServer->enabled = $request->has('enabled') && (bool)$request->get('enabled');
|
||||
$carddavServer->use_exact_match_policy = $request->has('use_exact_match_policy') && (bool)$request->get('use_exact_match_policy');
|
||||
|
||||
return $carddavServer->save();
|
||||
}
|
||||
|
||||
public function update(CardDavServer $request, string $domain, int $carddavServerId)
|
||||
{
|
||||
$space = Space::where('domain', $domain)->firstOrFail();
|
||||
|
||||
$carddavServer = $space->carddavServers()->findOrFail($carddavServerId);
|
||||
$carddavServer->fill($request->validated());
|
||||
$carddavServer->enabled = $request->has('enabled') && (bool)$request->get('enabled');
|
||||
$carddavServer->use_exact_match_policy = $request->has('use_exact_match_policy') && (bool)$request->get('use_exact_match_policy');
|
||||
|
||||
return $carddavServer->save();
|
||||
}
|
||||
|
||||
public function destroy(string $domain, int $carddavServerId)
|
||||
{
|
||||
$space = Space::where('domain', $domain)->firstOrFail();
|
||||
|
||||
$carddavServer = $space->carddavServers()->findOrFail($carddavServerId);
|
||||
return $carddavServer->delete();
|
||||
}
|
||||
}
|
||||
|
|
@ -17,9 +17,8 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
namespace App\Http\Controllers\Api\Admin\Space;
|
||||
|
||||
use App\Account;
|
||||
use App\ContactsList;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -28,12 +27,12 @@ class ContactsListController extends Controller
|
|||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
return ContactsList::all();
|
||||
return $request->space->contactsLists;
|
||||
}
|
||||
|
||||
public function get(int $contactsListId)
|
||||
public function get(Request $request, int $contactsListId)
|
||||
{
|
||||
return ContactsList::findOrFail($contactsListId);
|
||||
return $request->space->contactsLists()->findOrFail($contactsListId);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
|
|
@ -44,6 +43,7 @@ class ContactsListController extends Controller
|
|||
]);
|
||||
|
||||
$contactsList = new ContactsList;
|
||||
$contactsList->space_id = $request->space->id;
|
||||
$contactsList->title = $request->get('title');
|
||||
$contactsList->description = $request->get('description');
|
||||
$contactsList->save();
|
||||
|
|
@ -59,6 +59,7 @@ class ContactsListController extends Controller
|
|||
]);
|
||||
|
||||
$contactsList = ContactsList::findOrFail($contactsListId);
|
||||
$contactsList->space_id = $request->space->id;
|
||||
$contactsList->title = $request->get('title');
|
||||
$contactsList->description = $request->get('description');
|
||||
$contactsList->save();
|
||||
|
|
@ -66,25 +67,25 @@ class ContactsListController extends Controller
|
|||
return $contactsList;
|
||||
}
|
||||
|
||||
public function destroy(int $contactsListId)
|
||||
public function destroy(Request $request, int $contactsListId)
|
||||
{
|
||||
return ContactsList::where('id', $contactsListId)
|
||||
return $request->space->contactsLists()->where('id', $contactsListId)
|
||||
->delete();
|
||||
}
|
||||
|
||||
public function contactAdd(int $id, int $contactId)
|
||||
public function contactAdd(Request $request, int $id, int $contactId)
|
||||
{
|
||||
$contactsList = ContactsList::findOrFail($id);
|
||||
$contactsList = $request->space->contactsLists()->findOrFail($id);
|
||||
$contactsList->contacts()->detach($contactId);
|
||||
|
||||
if (Account::findOrFail($contactId)) {
|
||||
if ($request->space->accounts()->findOrFail($contactId)) {
|
||||
return $contactsList->contacts()->attach($contactId);
|
||||
}
|
||||
}
|
||||
|
||||
public function contactRemove(int $id, int $contactId)
|
||||
public function contactRemove(Request $request, int $id, int $contactId)
|
||||
{
|
||||
$contactsList = ContactsList::findOrFail($id);
|
||||
$contactsList = $request->space->contactsLists()->findOrFail($id);
|
||||
|
||||
if (!$contactsList->contacts()->pluck('id')->contains($contactId)) {
|
||||
abort(404);
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
namespace App\Http\Controllers\Api\Admin\Space;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\EmailServer\CreateUpdate;
|
||||
|
|
@ -45,38 +45,37 @@ class SpaceController extends Controller
|
|||
]);
|
||||
|
||||
$space = new Space;
|
||||
$space->name = $request->get('name');
|
||||
$space->domain = $request->get('domain');
|
||||
$space->host = $request->get('host');
|
||||
$this->setRequestBoolean($request, $space, 'super');
|
||||
$this->setRequestBoolean($request, $space, 'disable_chat_feature');
|
||||
$this->setRequestBoolean($request, $space, 'disable_meetings_feature');
|
||||
$this->setRequestBoolean($request, $space, 'disable_broadcast_feature');
|
||||
$this->setRequestBoolean($request, $space, 'hide_settings');
|
||||
$this->setRequestBoolean($request, $space, 'hide_account_settings');
|
||||
$this->setRequestBoolean($request, $space, 'disable_call_recordings_feature');
|
||||
$this->setRequestBoolean($request, $space, 'only_display_sip_uri_username');
|
||||
$this->setRequestBoolean($request, $space, 'assistant_hide_create_account');
|
||||
$this->setRequestBoolean($request, $space, 'assistant_disable_qr_code');
|
||||
$this->setRequestBoolean($request, $space, 'assistant_hide_third_party_account');
|
||||
$space->max_account = $request->get('max_account', 0);
|
||||
$space->max_accounts = $request->get('max_accounts', 0);
|
||||
$space->expire_at = $request->get('expire_at');
|
||||
|
||||
$space->copyright_text = $request->get('copyright_text');
|
||||
$space->intro_registration_text = $request->get('intro_registration_text');
|
||||
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
||||
$space->account_proxy_registrar_address = $request->get('account_proxy_registrar_address');
|
||||
$space->account_realm = $request->get('account_realm');
|
||||
$space->copyright_text = $request->get('copyright_text');
|
||||
$space->custom_provisioning_entries = $request->get('custom_provisioning_entries');
|
||||
$space->domain = $request->get('domain');
|
||||
$space->expire_at = $request->get('expire_at');
|
||||
$space->host = $request->get('host');
|
||||
$space->intro_registration_text = $request->get('intro_registration_text');
|
||||
$space->max_account = $request->get('max_account', 0);
|
||||
$space->max_accounts = $request->get('max_accounts', 0);
|
||||
$space->name = $request->get('name');
|
||||
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
||||
$this->setRequestBoolean($request, $space, 'assistant_disable_qr_code');
|
||||
$this->setRequestBoolean($request, $space, 'assistant_hide_create_account');
|
||||
$this->setRequestBoolean($request, $space, 'assistant_hide_third_party_account');
|
||||
$this->setRequestBoolean($request, $space, 'carddav_user_credentials');
|
||||
$this->setRequestBoolean($request, $space, 'custom_provisioning_overwrite_all');
|
||||
$this->setRequestBoolean($request, $space, 'provisioning_use_linphone_provisioning_header');
|
||||
$this->setRequestBoolean($request, $space, 'custom_theme');
|
||||
$this->setRequestBoolean($request, $space, 'web_panel');
|
||||
$this->setRequestBoolean($request, $space, 'public_registration');
|
||||
$this->setRequestBoolean($request, $space, 'phone_registration');
|
||||
$this->setRequestBoolean($request, $space, 'disable_broadcast_feature');
|
||||
$this->setRequestBoolean($request, $space, 'disable_call_recordings_feature');
|
||||
$this->setRequestBoolean($request, $space, 'disable_chat_feature');
|
||||
$this->setRequestBoolean($request, $space, 'disable_meetings_feature');
|
||||
$this->setRequestBoolean($request, $space, 'hide_account_settings');
|
||||
$this->setRequestBoolean($request, $space, 'hide_settings');
|
||||
$this->setRequestBoolean($request, $space, 'intercom_features');
|
||||
|
||||
$this->setRequestBoolean($request, $space, 'only_display_sip_uri_username');
|
||||
$this->setRequestBoolean($request, $space, 'phone_registration');
|
||||
$this->setRequestBoolean($request, $space, 'provisioning_use_linphone_provisioning_header');
|
||||
$this->setRequestBoolean($request, $space, 'public_registration');
|
||||
$this->setRequestBoolean($request, $space, 'super');
|
||||
$this->setRequestBoolean($request, $space, 'web_panel');
|
||||
$space->save();
|
||||
|
||||
return $space->refresh();
|
||||
|
|
@ -90,30 +89,30 @@ class SpaceController extends Controller
|
|||
public function update(Request $request, string $domain)
|
||||
{
|
||||
$request->validate([
|
||||
'super' => 'required|boolean',
|
||||
'disable_chat_feature' => 'required|boolean',
|
||||
'disable_meetings_feature' => 'required|boolean',
|
||||
'disable_broadcast_feature' => 'required|boolean',
|
||||
'hide_settings' => 'required|boolean',
|
||||
'hide_account_settings' => 'required|boolean',
|
||||
'disable_call_recordings_feature' => 'required|boolean',
|
||||
'only_display_sip_uri_username' => 'required|boolean',
|
||||
'assistant_hide_create_account' => 'required|boolean',
|
||||
'assistant_disable_qr_code' => 'required|boolean',
|
||||
'assistant_hide_third_party_account' => 'required|boolean',
|
||||
'max_account' => 'required|integer',
|
||||
'max_accounts' => 'required|integer',
|
||||
'expire_at' => 'nullable|date|after_or_equal:today',
|
||||
'account_realm' => ['nullable', new Domain()],
|
||||
|
||||
'assistant_disable_qr_code' => 'required|boolean',
|
||||
'assistant_hide_create_account' => 'required|boolean',
|
||||
'assistant_hide_third_party_account' => 'required|boolean',
|
||||
'carddav_user_credentials' => 'required|boolean',
|
||||
'custom_provisioning_entries' => ['nullable', new Ini(Space::FORBIDDEN_KEYS)],
|
||||
'custom_provisioning_overwrite_all' => 'required|boolean',
|
||||
'provisioning_use_linphone_provisioning_header' => 'required|boolean',
|
||||
'custom_theme' => 'required|boolean',
|
||||
'web_panel' => 'required|boolean',
|
||||
'public_registration' => 'required|boolean',
|
||||
'phone_registration' => 'required|boolean',
|
||||
'disable_broadcast_feature' => 'required|boolean',
|
||||
'disable_call_recordings_feature' => 'required|boolean',
|
||||
'disable_chat_feature' => 'required|boolean',
|
||||
'disable_meetings_feature' => 'required|boolean',
|
||||
'expire_at' => 'nullable|date|after_or_equal:today',
|
||||
'hide_account_settings' => 'required|boolean',
|
||||
'hide_settings' => 'required|boolean',
|
||||
'intercom_features' => 'required|boolean',
|
||||
'max_account' => 'required|integer',
|
||||
'max_accounts' => 'required|integer',
|
||||
'only_display_sip_uri_username' => 'required|boolean',
|
||||
'phone_registration' => 'required|boolean',
|
||||
'provisioning_use_linphone_provisioning_header' => 'required|boolean',
|
||||
'public_registration' => 'required|boolean',
|
||||
'super' => 'required|boolean',
|
||||
'web_panel' => 'required|boolean',
|
||||
]);
|
||||
|
||||
$space = Space::where('domain', $domain)->firstOrFail();
|
||||
|
|
@ -132,33 +131,33 @@ class SpaceController extends Controller
|
|||
$space->name = $request->get('name');
|
||||
$space->host = $request->get('host');
|
||||
$space->super = $request->get('super');
|
||||
$space->disable_chat_feature = $request->get('disable_chat_feature');
|
||||
$space->disable_meetings_feature = $request->get('disable_meetings_feature');
|
||||
$space->disable_broadcast_feature = $request->get('disable_broadcast_feature');
|
||||
$space->hide_settings = $request->get('hide_settings');
|
||||
$space->hide_account_settings = $request->get('hide_account_settings');
|
||||
$space->disable_call_recordings_feature = $request->get('disable_call_recordings_feature');
|
||||
$space->only_display_sip_uri_username = $request->get('only_display_sip_uri_username');
|
||||
$space->assistant_hide_create_account = $request->get('assistant_hide_create_account');
|
||||
$space->assistant_disable_qr_code = $request->get('assistant_disable_qr_code');
|
||||
$space->assistant_hide_third_party_account = $request->get('assistant_hide_third_party_account');
|
||||
$space->max_account = $request->get('max_account', 0);
|
||||
$space->max_accounts = $request->get('max_accounts', 0);
|
||||
$space->expire_at = $request->get('expire_at');
|
||||
|
||||
$space->copyright_text = $request->get('copyright_text');
|
||||
$space->intro_registration_text = $request->get('intro_registration_text');
|
||||
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
||||
$space->account_proxy_registrar_address = $request->get('account_proxy_registrar_address');
|
||||
$space->account_realm = $request->get('account_realm');
|
||||
$space->assistant_disable_qr_code = $request->get('assistant_disable_qr_code');
|
||||
$space->assistant_hide_create_account = $request->get('assistant_hide_create_account');
|
||||
$space->assistant_hide_third_party_account = $request->get('assistant_hide_third_party_account');
|
||||
$space->copyright_text = $request->get('copyright_text');
|
||||
$space->carddav_user_credentials = $request->get('carddav_user_credentials');
|
||||
$space->custom_provisioning_entries = $request->get('custom_provisioning_entries');
|
||||
$space->custom_provisioning_overwrite_all = $request->get('custom_provisioning_overwrite_all');
|
||||
$space->provisioning_use_linphone_provisioning_header = $request->get('provisioning_use_linphone_provisioning_header');
|
||||
$space->custom_theme = $request->get('custom_theme');
|
||||
$space->web_panel = $request->get('web_panel');
|
||||
$space->public_registration = $request->get('public_registration');
|
||||
$space->phone_registration = $request->get('phone_registration');
|
||||
$space->disable_broadcast_feature = $request->get('disable_broadcast_feature');
|
||||
$space->disable_call_recordings_feature = $request->get('disable_call_recordings_feature');
|
||||
$space->disable_chat_feature = $request->get('disable_chat_feature');
|
||||
$space->disable_meetings_feature = $request->get('disable_meetings_feature');
|
||||
$space->expire_at = $request->get('expire_at');
|
||||
$space->hide_account_settings = $request->get('hide_account_settings');
|
||||
$space->hide_settings = $request->get('hide_settings');
|
||||
$space->intercom_features = $request->get('intercom_features');
|
||||
$space->intro_registration_text = $request->get('intro_registration_text');
|
||||
$space->max_account = $request->get('max_account', 0);
|
||||
$space->max_accounts = $request->get('max_accounts', 0);
|
||||
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
||||
$space->only_display_sip_uri_username = $request->get('only_display_sip_uri_username');
|
||||
$space->phone_registration = $request->get('phone_registration');
|
||||
$space->provisioning_use_linphone_provisioning_header = $request->get('provisioning_use_linphone_provisioning_header');
|
||||
$space->public_registration = $request->get('public_registration');
|
||||
$space->web_panel = $request->get('web_panel');
|
||||
|
||||
$space->save();
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Account;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Rules\Vcard;
|
||||
use App\VcardStorage;
|
||||
|
|
@ -30,15 +29,15 @@ use stdClass;
|
|||
|
||||
class VcardsStorageController extends Controller
|
||||
{
|
||||
public function index(int $accountId)
|
||||
public function index(Request $request, int $accountId)
|
||||
{
|
||||
$list = Account::findOrFail($accountId)->vcardsStorage()->get()->keyBy('uuid');
|
||||
$list = $request->space->accounts()->findOrFail($accountId)->vcardsStorage()->get()->keyBy('uuid');
|
||||
return $list->isEmpty() ? new stdClass : $list;
|
||||
}
|
||||
|
||||
public function show(int $accountId, string $uuid)
|
||||
public function show(Request $request, int $accountId, string $uuid)
|
||||
{
|
||||
return Account::findOrFail($accountId)->vcardsStorage()->where('uuid', $uuid)->firstOrFail();
|
||||
return $request->space->accounts()->findOrFail($accountId)->vcardsStorage()->where('uuid', $uuid)->firstOrFail();
|
||||
}
|
||||
|
||||
public function store(Request $request, int $accountId)
|
||||
|
|
@ -48,18 +47,14 @@ class VcardsStorageController extends Controller
|
|||
]);
|
||||
|
||||
$vcardo = VObject\Reader::read($request->get('vcard'));
|
||||
$vcardoUID = substr($vcardo->UID, 9);
|
||||
|
||||
$request->merge(['uuid' => $vcardoUID]);
|
||||
$request->validate(['uuid' => 'uuid']);
|
||||
|
||||
if (Account::findOrFail($accountId)->vcardsStorage()->where('uuid', $vcardoUID)->first()) {
|
||||
if ($request->space->accounts()->findOrFail($accountId)->vcardsStorage()->where('uuid', $vcardo->UID)->first()) {
|
||||
abort(409, 'Vcard already exists');
|
||||
}
|
||||
|
||||
$vcard = new VcardStorage();
|
||||
$vcard->account_id = $accountId;
|
||||
$vcard->uuid = $vcardoUID;
|
||||
$vcard->uuid = $vcardo->UID;
|
||||
$vcard->vcard = preg_replace('/\r\n?/', "\n", $vcardo->serialize());
|
||||
$vcard->save();
|
||||
|
||||
|
|
@ -68,24 +63,17 @@ class VcardsStorageController extends Controller
|
|||
|
||||
public function update(Request $request, int $accountId, string $uuid)
|
||||
{
|
||||
$request->merge(['uuid' => $uuid]);
|
||||
|
||||
$request->validate([
|
||||
'uuid' => 'uuid',
|
||||
'vcard' => ['required', new Vcard()]
|
||||
]);
|
||||
|
||||
$vcardo = VObject\Reader::read($request->get('vcard'));
|
||||
$vcardoUID = substr($vcardo->UID, 9);
|
||||
|
||||
$request->merge(['vuuid' => $vcardoUID]);
|
||||
$request->validate(['vuuid' => 'uuid']);
|
||||
|
||||
if ($vcardoUID != $uuid) {
|
||||
if ($vcardo->UID != $uuid) {
|
||||
abort(422, 'UUID should be the same');
|
||||
}
|
||||
|
||||
$vcard = Account::findOrFail($accountId)->vcardsStorage()->where('uuid', $uuid)->firstOrFail();
|
||||
$vcard = $request->space->accounts()->findOrFail($accountId)->vcardsStorage()->where('uuid', $uuid)->firstOrFail();
|
||||
$vcard->vcard = preg_replace('/\r\n?/', "\n", $vcardo->serialize());
|
||||
$vcard->save();
|
||||
|
||||
|
|
@ -94,10 +82,7 @@ class VcardsStorageController extends Controller
|
|||
|
||||
public function destroy(Request $request, int $accountId, string $uuid)
|
||||
{
|
||||
$request->merge(['uuid' => $uuid]);
|
||||
$request->validate(['uuid' => 'uuid']);
|
||||
|
||||
$vcard = Account::findOrFail($accountId)->vcardsStorage()->where('uuid', $uuid)->firstOrFail();
|
||||
$vcard = $request->space->accounts()->findOrFail($accountId)->vcardsStorage()->where('uuid', $uuid)->firstOrFail();
|
||||
|
||||
return $vcard->delete();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
/**
|
||||
* The application's global HTTP middleware stack.
|
||||
*
|
||||
* These middleware are run during every request to your application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\App\Http\Middleware\CheckForMaintenanceMode::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware groups.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\Localization::class,
|
||||
'space.check',
|
||||
],
|
||||
|
||||
'api' => [
|
||||
'throttle:600,1', // move to 600 instead of 60
|
||||
'bindings',
|
||||
'validate_json',
|
||||
'localization',
|
||||
'space.check',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware.
|
||||
*
|
||||
* These middleware may be assigned to groups or used individually.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewareAliases = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.admin' => \App\Http\Middleware\AuthenticateAdmin::class,
|
||||
'auth.super_admin' => \App\Http\Middleware\AuthenticateSuperAdmin::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'auth.digest_or_key' => \App\Http\Middleware\AuthenticateDigestOrKey::class,
|
||||
'auth.jwt' => \App\Http\Middleware\AuthenticateJWT::class,
|
||||
'auth.check_blocked' => \App\Http\Middleware\CheckBlocked::class,
|
||||
'validate_json' => \App\Http\Middleware\ValidateJSON::class,
|
||||
'web_panel_enabled' => \App\Http\Middleware\IsWebPanelEnabled::class,
|
||||
'public_registration' => \App\Http\Middleware\IsPublicRegistration::class,
|
||||
'phone_registration' => \App\Http\Middleware\IsPhoneRegistration::class,
|
||||
'intercom_features' => \App\Http\Middleware\IsIntercomFeatures::class,
|
||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'cookie' => \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
'cookie.encrypt' => \App\Http\Middleware\EncryptCookies::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'space.check' => \App\Http\Middleware\SpaceCheck::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'localization' => \App\Http\Middleware\Localization::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The priority-sorted list of middleware.
|
||||
*
|
||||
* This forces non-global middleware to always be in the given order.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewarePriority = [
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\Illuminate\Auth\Middleware\Authorize::class,
|
||||
];
|
||||
}
|
||||
|
|
@ -29,7 +29,9 @@ class AuthenticateAdmin
|
|||
return redirect()->route('account.login');
|
||||
}
|
||||
|
||||
if (!$request->user()->admin) {
|
||||
if (!$request->user()->admin
|
||||
|| (!$request->user()->superAdmin && $request->user()->domain != $request->space->domain)
|
||||
) {
|
||||
return abort(403, 'Unauthorized area');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,18 +76,20 @@ class AuthenticateJWT
|
|||
}
|
||||
|
||||
$account = null;
|
||||
$identifierKey = config('services.jwt.sip_identifier');
|
||||
if ($identifierKey == '') $identifierKey = 'sip_identity';
|
||||
|
||||
if ($token->claims()->has(config('services.jwt.sip_identifier'))) {
|
||||
list($username, $domain) = parseSIP($token->claims()->get(config('services.jwt.sip_identifier')));
|
||||
if ($token->claims()->has($identifierKey)) {
|
||||
list($username, $domain) = parseSIP($token->claims()->get($identifierKey));
|
||||
|
||||
$account = Account::withoutGlobalScopes()
|
||||
->where('username', $username)
|
||||
->where('domain', $domain)
|
||||
->first();
|
||||
->where('username', $username)
|
||||
->where('domain', $domain)
|
||||
->first();
|
||||
} elseif ($token->claims()->has('email')) {
|
||||
$account = Account::withoutGlobalScopes()
|
||||
->where('email', $token->claims()->get('email'))
|
||||
->first();
|
||||
->where('email', $token->claims()->get('email'))
|
||||
->first();
|
||||
}
|
||||
|
||||
if (!$account) {
|
||||
|
|
@ -99,8 +101,7 @@ class AuthenticateJWT
|
|||
return $next($request);
|
||||
}
|
||||
|
||||
if (
|
||||
!empty(config('app.account_authentication_bearer'))
|
||||
if (!empty(config('app.account_authentication_bearer'))
|
||||
// Bypass the JWT auth if we have an API Key
|
||||
&& !$request->header('x-api-key')
|
||||
&& !$request->cookie('x-api-key')
|
||||
|
|
@ -130,7 +131,7 @@ class AuthenticateJWT
|
|||
$response = new Response();
|
||||
$response->header(
|
||||
'WWW-Authenticate',
|
||||
$bearer . 'error="' . $error . '", error_description="'. $description . '"'
|
||||
$bearer . 'error="' . $error . '", error_description="' . $description . '"'
|
||||
);
|
||||
$response->setStatusCode(401);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
|
||||
|
||||
class CheckForMaintenanceMode extends Middleware
|
||||
{
|
||||
/**
|
||||
* The URIs that should be reachable while maintenance mode is enabled.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
|
||||
|
||||
class EncryptCookies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The names of the cookies that should not be encrypted.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
19
flexiapi/app/Http/Middleware/IsCardDavCredentialsEnabled.php
Normal file
19
flexiapi/app/Http/Middleware/IsCardDavCredentialsEnabled.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class IsCardDavCredentialsEnabled
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if ($request->space->carddav_user_credentials) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
abort(403, 'CardDav Credentials features disabled');
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ class IsIntercomFeatures
|
|||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (space()?->intercom_features) {
|
||||
if ($request->space->intercom_features) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class IsPhoneRegistration
|
|||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (space()?->phone_registration) {
|
||||
if ($request->space->phone_registration) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ class IsPublicRegistration
|
|||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (space()?->public_registration) {
|
||||
if ($request->space?->public_registration) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return abort(404, 'Public registration disabled');
|
||||
abort(404, 'Public registration disabled');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class IsWebPanelEnabled
|
|||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!$request->expectsJson() && space()?->web_panel) {
|
||||
if (!$request->expectsJson() && $request->space->web_panel) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use App\Space;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
|
@ -15,15 +16,16 @@ class SpaceCheck
|
|||
abort(503, 'APP_ROOT_HOST is not configured');
|
||||
}
|
||||
|
||||
$space = space(reload: true);
|
||||
$space = Space::where('host', config('app.sip_domain') ?? request()->host())->first();
|
||||
|
||||
if ($space != null) {
|
||||
if (!str_ends_with($space->host, config('app.root_host'))) {
|
||||
abort(503, 'The APP_ROOT_HOST configured does not match with the current root domain');
|
||||
}
|
||||
|
||||
$request->merge(['space' => $space]);
|
||||
|
||||
Config::set('app.url', '://' . $space->host);
|
||||
Config::set('app.sip_domain', $space->domain);
|
||||
|
||||
if ($space->isExpired()) {
|
||||
abort($request->expectsJson() ? 403 : 490, 'The related Space has expired');
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
|
||||
|
||||
class TrimStrings extends Middleware
|
||||
{
|
||||
/**
|
||||
* The names of the attributes that should not be trimmed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The trusted proxies for this application.
|
||||
*
|
||||
* @var array|string
|
||||
*/
|
||||
protected $proxies;
|
||||
|
||||
/**
|
||||
* The headers that should be used to detect proxies.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
||||
|
||||
class VerifyCsrfToken extends Middleware
|
||||
{
|
||||
/**
|
||||
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $addHttpCookie = true;
|
||||
|
||||
/**
|
||||
* The URIs that should be excluded from CSRF verification.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
|
|
@ -17,21 +17,23 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
namespace App\Http\Requests\Account;
|
||||
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
abstract class TestCaseWithSpaceMiddleware extends BaseTestCase
|
||||
use App\Rules\Domain;
|
||||
use App\Rules\PasswordAlgorithm;
|
||||
|
||||
class CardDavCredentials extends FormRequest
|
||||
{
|
||||
use CreatesApplication;
|
||||
use RefreshDatabase;
|
||||
use TestUtilsTrait;
|
||||
|
||||
public function setUp(): void
|
||||
public function rules()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config()->set('app.sip_domain', 'sip.example.com');
|
||||
return [
|
||||
'username' => 'required',
|
||||
'password' => 'required',
|
||||
'algorithm' => ['required', new PasswordAlgorithm],
|
||||
'realm' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
42
flexiapi/app/Http/Requests/Space/CardDavServer.php
Normal file
42
flexiapi/app/Http/Requests/Space/CardDavServer.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\Space;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
use App\EmailServer;
|
||||
use App\Rules\CommaList;
|
||||
|
||||
class CardDavServer extends FormRequest
|
||||
{
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'uri' => 'required|url',
|
||||
'min_characters' => 'integer|min:1',
|
||||
'results_limit' => 'integer|min:0',
|
||||
'timeout' => 'integer|min:1',
|
||||
'delay' => 'integer|min:100',
|
||||
'fields_for_user_input' => [new CommaList],
|
||||
'fields_for_domain' => [new CommaList],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ class StatisticsGraphFactory
|
|||
$toQuery = StatisticsMessage::query();
|
||||
|
||||
if (!Auth::user()?->superAdmin) {
|
||||
$fromQuery->where('from_domain', space()->domain);
|
||||
$fromQuery->where('from_domain', $this->request->space->domain);
|
||||
$toQuery->toDomain(space()->domain);
|
||||
} elseif ($this->domain) {
|
||||
$fromQuery->where('from_domain', $this->domain);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ namespace App\Mail;
|
|||
use App\Space;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ namespace App\Mail;
|
|||
use App\Account;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ namespace App\Mail;
|
|||
use App\Account;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ namespace App\Mail;
|
|||
use App\Account;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
|
|
|
|||
|
|
@ -20,10 +20,8 @@
|
|||
namespace App\Mail;
|
||||
|
||||
use App\Account;
|
||||
use App\ResetPasswordEmailToken;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
|
|
|
|||
44
flexiapi/app/Mail/Voicemail.php
Normal file
44
flexiapi/app/Mail/Voicemail.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\AccountFile;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Mail\Mailables\Attachment;
|
||||
|
||||
class Voicemail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public function __construct(public AccountFile $accountFile)
|
||||
{
|
||||
}
|
||||
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: $this->accountFile->account->space->name .
|
||||
': ' .
|
||||
__('New voice message from :sipfrom', ['sipfrom' => $this->accountFile->sip_from]),
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
markdown: 'mails.voicemail',
|
||||
);
|
||||
}
|
||||
|
||||
public function attachments(): array
|
||||
{
|
||||
return [
|
||||
Attachment::fromStorage($this->accountFile->path)
|
||||
->withMime($this->accountFile->content_type)
|
||||
];
|
||||
}
|
||||
}
|
||||
38
flexiapi/app/Rules/AudioMime.php
Normal file
38
flexiapi/app/Rules/AudioMime.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use App\AccountFile;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
class AudioMime implements Rule
|
||||
{
|
||||
public function __construct(private AccountFile $accountFile)
|
||||
{
|
||||
}
|
||||
|
||||
public function passes($attribute, $file): bool
|
||||
{
|
||||
$mimeType = null;
|
||||
switch ($file->getMimeType()) {
|
||||
case 'audio/opus':
|
||||
$mimeType = 'audio/opus';
|
||||
break;
|
||||
|
||||
case 'audio/vnd.wave':
|
||||
case 'audio/wav':
|
||||
case 'audio/wave':
|
||||
case 'audio/x-wav':
|
||||
case 'audio/x-pn-wav':
|
||||
$mimeType = 'audio/wav';
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->accountFile->content_type == $mimeType;
|
||||
}
|
||||
|
||||
public function message()
|
||||
{
|
||||
return __('The file should have the declared mime-type');
|
||||
}
|
||||
}
|
||||
21
flexiapi/app/Rules/CommaList.php
Normal file
21
flexiapi/app/Rules/CommaList.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use Respect\Validation\Validator;
|
||||
|
||||
class CommaList implements Rule
|
||||
{
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
preg_match_all('/[^, ]+/', $value, $matches);
|
||||
|
||||
return $value == null || (!empty($matches) && (implode(',', $matches[0]) == $value));
|
||||
}
|
||||
|
||||
public function message()
|
||||
{
|
||||
return 'The :attribute should be null or contain a list of words separated by commas without spaces';
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use Respect\Validation\Validator;
|
||||
use Propaganistas\LaravelPhone\PhoneNumber;
|
||||
|
||||
class IsNotPhoneNumber implements Rule
|
||||
|
|
|
|||
|
|
@ -23,11 +23,6 @@ use Illuminate\Contracts\Validation\Rule;
|
|||
|
||||
class WithoutSpaces implements Rule
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
return preg_match('/^\S*$/u', $value);
|
||||
|
|
|
|||
|
|
@ -62,10 +62,10 @@ class AccountService
|
|||
$account = new Account();
|
||||
$account->username = $request->get('username');
|
||||
$account->activated = false;
|
||||
$account->domain = space()->domain;
|
||||
$account->domain = $request->space->domain;
|
||||
$account->ip_address = $request->ip();
|
||||
$account->created_at = Carbon::now();
|
||||
$account->user_agent = space()->name;
|
||||
$account->user_agent = $request->space->name;
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
|
||||
if ($request->asAdmin) {
|
||||
|
|
@ -73,7 +73,7 @@ class AccountService
|
|||
$account->display_name = $request->get('display_name');
|
||||
$account->activated = $request->has('activated') ? (bool)$request->get('activated') : false;
|
||||
$account->domain = resolveDomain($request);
|
||||
$account->user_agent = $request->header('User-Agent') ?? space()->name;
|
||||
$account->user_agent = $request->header('User-Agent') ?? $request->space->name;
|
||||
$account->admin = $request->has('admin') && (bool)$request->get('admin');
|
||||
|
||||
if (!$request->api && $request->has('role')) {
|
||||
|
|
@ -113,8 +113,8 @@ class AccountService
|
|||
);
|
||||
|
||||
if (!$request->api) {
|
||||
if (!empty(space()?->newsletter_registration_address) && $request->has('newsletter')) {
|
||||
Mail::to(space()->newsletter_registration_address)->send(new NewsletterRegistration($account));
|
||||
if (!empty($request->space?->newsletter_registration_address) && $request->has('newsletter')) {
|
||||
Mail::to($request->space->newsletter_registration_address)->send(new NewsletterRegistration($account));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,52 +21,67 @@ namespace App;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class Space extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $with = ['emailServer'];
|
||||
protected $with = ['emailServer', 'carddavServers'];
|
||||
|
||||
public const FORBIDDEN_KEYS = [
|
||||
'disable_chat_feature',
|
||||
'disable_meetings_feature',
|
||||
'disable_broadcast_feature',
|
||||
'max_account',
|
||||
'hide_settings',
|
||||
'hide_account_settings',
|
||||
'disable_call_recordings_feature',
|
||||
'only_display_sip_uri_username',
|
||||
'assistant_hide_create_account',
|
||||
'account_proxy_registrar_address',
|
||||
'account_realm',
|
||||
'assistant_disable_qr_code',
|
||||
'assistant_hide_create_account',
|
||||
'assistant_hide_third_party_account',
|
||||
'copyright_text',
|
||||
'disable_broadcast_feature',
|
||||
'disable_call_recordings_feature',
|
||||
'disable_chat_feature',
|
||||
'disable_meetings_feature',
|
||||
'hide_account_settings',
|
||||
'hide_settings',
|
||||
'intro_registration_text',
|
||||
'max_account',
|
||||
'newsletter_registration_address',
|
||||
'account_proxy_registrar_address',
|
||||
'account_realm'
|
||||
'only_display_sip_uri_username',
|
||||
];
|
||||
|
||||
protected $hidden = ['id'];
|
||||
protected $casts = [
|
||||
'super' => 'boolean',
|
||||
'assistant_disable_qr_code' => 'boolean',
|
||||
'assistant_hide_create_account' => 'boolean',
|
||||
'assistant_hide_third_party_account' => 'boolean',
|
||||
'carddav_user_credentials' => 'boolean',
|
||||
'disable_broadcast_feature' => 'boolean',
|
||||
'disable_call_recordings_feature' => 'boolean',
|
||||
'disable_chat_feature' => 'boolean',
|
||||
'disable_meetings_feature' => 'boolean',
|
||||
'disable_broadcast_feature' => 'boolean',
|
||||
'hide_settings' => 'boolean',
|
||||
'hide_account_settings' => 'boolean',
|
||||
'disable_call_recordings_feature' => 'boolean',
|
||||
'only_display_sip_uri_username' => 'boolean',
|
||||
'assistant_hide_create_account' => 'boolean',
|
||||
'assistant_disable_qr_code' => 'boolean',
|
||||
'assistant_hide_third_party_account' => 'boolean',
|
||||
'expire_at' => 'date',
|
||||
'hide_account_settings' => 'boolean',
|
||||
'hide_settings' => 'boolean',
|
||||
'only_display_sip_uri_username' => 'boolean',
|
||||
'super' => 'boolean',
|
||||
];
|
||||
|
||||
public const HOST_REGEX = '[\w\-]+';
|
||||
public const DOMAIN_REGEX = '(?=^.{4,253}$)(^((?!-)[a-z0-9-]{1,63}(?<!-)\.)+[a-z]{2,63}$)';
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::addGlobalScope('domain', function (Builder $builder) {
|
||||
if (!Auth::hasUser()) return;
|
||||
|
||||
if (Auth::hasUser() || Auth::user()->superAdmin) {
|
||||
return;
|
||||
}
|
||||
|
||||
$builder->where('domain', Auth::user()->domain);
|
||||
});
|
||||
}
|
||||
|
||||
public function accounts()
|
||||
{
|
||||
return $this->hasMany(Account::class, 'domain', 'domain');
|
||||
|
|
@ -82,6 +97,16 @@ class Space extends Model
|
|||
return $this->hasOne(SpaceEmailServer::class);
|
||||
}
|
||||
|
||||
public function carddavServers()
|
||||
{
|
||||
return $this->hasMany(SpaceCardDavServer::class);
|
||||
}
|
||||
|
||||
public function contactsLists()
|
||||
{
|
||||
return $this->hasMany(ContactsList::class);
|
||||
}
|
||||
|
||||
public function scopeNotFull(Builder $query)
|
||||
{
|
||||
return $query->where('max_accounts', 0)
|
||||
|
|
|
|||
82
flexiapi/app/SpaceCardDavServer.php
Normal file
82
flexiapi/app/SpaceCardDavServer.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class SpaceCardDavServer extends Model
|
||||
{
|
||||
protected $hidden = ['space_id'];
|
||||
protected $table = 'space_carddav_servers';
|
||||
protected $fillable = ['uri', 'enabled', 'min_characters', 'results_limist', 'use_exact_match_policy', 'timeout', 'delay', 'fields_for_user_input', 'fields_for_domain'];
|
||||
|
||||
protected $casts = [
|
||||
'enabled' => 'boolean',
|
||||
'use_exact_match_policy' => 'boolean',
|
||||
];
|
||||
|
||||
public function space()
|
||||
{
|
||||
return $this->belongsTo(Space::class);
|
||||
}
|
||||
|
||||
public function accounts()
|
||||
{
|
||||
return $this->belongsToMany(Account::class, 'account_carddav_credentials', 'space_carddav_server_id', 'account_id');
|
||||
}
|
||||
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return __('CardDav Server') . ' ' . $this->id;
|
||||
}
|
||||
|
||||
public function getProvisioningSection($config, int $remoteContactDirectoryCounter)
|
||||
{
|
||||
$dom = $config->ownerDocument;
|
||||
|
||||
$section = $dom->createElement('section');
|
||||
$section->setAttribute('name', 'remote_contact_directory_' . $remoteContactDirectoryCounter);
|
||||
|
||||
$entry = $dom->createElement('entry', $this->enabled ? '1': '0');
|
||||
$entry->setAttribute('name', 'enabled');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', 'carddav');
|
||||
$entry->setAttribute('name', 'type');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $this->uri);
|
||||
$entry->setAttribute('name', 'uri');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $this->min_characters);
|
||||
$entry->setAttribute('name', 'min_characters');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $this->results_limit);
|
||||
$entry->setAttribute('name', 'results_limit');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $this->timeout);
|
||||
$entry->setAttribute('name', 'timeout');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $this->delay);
|
||||
$entry->setAttribute('name', 'delay');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $this->fields_for_user_input);
|
||||
$entry->setAttribute('name', 'carddav_fields_for_user_input');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $this->fields_for_domain);
|
||||
$entry->setAttribute('name', 'carddav_fields_for_domain');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $this->use_exact_match_policy ? '1': '0');
|
||||
$entry->setAttribute('name', 'carddav_use_exact_match_policy');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$config->appendChild($section);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +1,18 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register The Auto Loader
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Composer provides a convenient, automatically generated class loader
|
||||
| for our application. We just need to utilize it! We'll require it
|
||||
| into the script here so that we do not have to worry about the
|
||||
| loading of any our classes "manually". Feels great to relax.
|
||||
|
|
||||
*/
|
||||
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Bootstrap Laravel and handle the command...
|
||||
/** @var Application $app */
|
||||
$app = require_once __DIR__.'/bootstrap/app.php';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Run The Artisan Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When we run the console application, the current CLI command will be
|
||||
| executed in this console and the response sent back to a terminal
|
||||
| or another output device for the developers. Here goes nothing!
|
||||
|
|
||||
*/
|
||||
$status = $app->handleCommand(new ArgvInput);
|
||||
|
||||
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
|
||||
|
||||
$status = $kernel->handle(
|
||||
$input = new Symfony\Component\Console\Input\ArgvInput,
|
||||
new Symfony\Component\Console\Output\ConsoleOutput
|
||||
);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Shutdown The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Once Artisan has finished running, we will fire off the shutdown events
|
||||
| so that any final work may be done by the application before we shut
|
||||
| down the process. This is the last thing to happen to the request.
|
||||
|
|
||||
*/
|
||||
|
||||
$kernel->terminate($input, $status);
|
||||
|
||||
exit($status);
|
||||
exit($status);
|
||||
|
|
@ -1,55 +1,50 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Create The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The first thing we will do is create a new Laravel application instance
|
||||
| which serves as the "glue" for all the components of Laravel, and is
|
||||
| the IoC container for the system binding all of the various parts.
|
||||
|
|
||||
*/
|
||||
use App\Http\Middleware\Authenticate;
|
||||
use App\Http\Middleware\AuthenticateAdmin;
|
||||
use App\Http\Middleware\AuthenticateDigestOrKey;
|
||||
use App\Http\Middleware\AuthenticateJWT;
|
||||
use App\Http\Middleware\AuthenticateSuperAdmin;
|
||||
use App\Http\Middleware\CheckBlocked;
|
||||
use App\Http\Middleware\IsCardDavCredentialsEnabled;
|
||||
use App\Http\Middleware\IsIntercomFeatures;
|
||||
use App\Http\Middleware\IsPhoneRegistration;
|
||||
use App\Http\Middleware\IsPublicRegistration;
|
||||
use App\Http\Middleware\IsWebPanelEnabled;
|
||||
use App\Http\Middleware\Localization;
|
||||
use App\Http\Middleware\SpaceCheck;
|
||||
use App\Http\Middleware\ValidateJSON;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
|
||||
$app = new Illuminate\Foundation\Application(
|
||||
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
|
||||
);
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__ . '/../routes/web.php',
|
||||
commands: __DIR__ . '/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
$middleware->append(SpaceCheck::class);
|
||||
$middleware->append(Localization::class);
|
||||
$middleware->api(append: [ValidateJSON::class]);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Bind Important Interfaces
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next, we need to bind some important interfaces into the container so
|
||||
| we will be able to resolve them when needed. The kernels serve the
|
||||
| incoming requests to this application from both the web and CLI.
|
||||
|
|
||||
*/
|
||||
$middleware->alias([
|
||||
'auth.admin' => AuthenticateAdmin::class,
|
||||
'auth.check_blocked' => CheckBlocked::class,
|
||||
'auth.digest_or_key' => AuthenticateDigestOrKey::class,
|
||||
'auth.jwt' => AuthenticateJWT::class,
|
||||
'auth.super_admin' => AuthenticateSuperAdmin::class,
|
||||
'auth' => Authenticate::class,
|
||||
'feature.carddav_user_credentials' => IsCardDavCredentialsEnabled::class,
|
||||
'feature.intercom' => IsIntercomFeatures::class,
|
||||
'feature.phone_registration' => IsPhoneRegistration::class,
|
||||
'feature.public_registration' => IsPublicRegistration::class,
|
||||
'feature.web_panel_enabled' => IsWebPanelEnabled::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
//
|
||||
})->create();
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Http\Kernel::class,
|
||||
App\Http\Kernel::class
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Console\Kernel::class,
|
||||
App\Console\Kernel::class
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Debug\ExceptionHandler::class,
|
||||
App\Exceptions\Handler::class
|
||||
);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Return The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This script returns the application instance. The instance is given to
|
||||
| the calling script so we can separate the building of the instances
|
||||
| from the actual running of the application and sending responses.
|
||||
|
|
||||
*/
|
||||
|
||||
return $app;
|
||||
|
|
|
|||
|
|
@ -8,33 +8,33 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"awobaz/compoships": "^2.3",
|
||||
"doctrine/dbal": "^3.0",
|
||||
"endroid/qr-code": "^5.0",
|
||||
"fakerphp/faker": "^1.23",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/tinker": "^2.9",
|
||||
"php": ">=8.2",
|
||||
"laravel/framework": "^11.45.1",
|
||||
"awobaz/compoships": "^2.4.1",
|
||||
"doctrine/dbal": "^3.10.1",
|
||||
"endroid/qr-code": "^5.1",
|
||||
"fakerphp/faker": "^1.24.1",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"lcobucci/jwt": "^4.3",
|
||||
"namoshek/laravel-redis-sentinel": "^0.5",
|
||||
"ovh/ovh": "^3.3",
|
||||
"parsedown/laravel": "^1.2",
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"propaganistas/laravel-phone": "^5.3",
|
||||
"ovh/ovh": "^3.5",
|
||||
"parsedown/laravel": "^1.2.1",
|
||||
"phpunit/phpunit": "^10.5.50",
|
||||
"propaganistas/laravel-phone": "^5.3.6",
|
||||
"react/socket": "^1.16",
|
||||
"respect/validation": "^2.3",
|
||||
"respect/validation": "^2.4.4",
|
||||
"rvxlab/hcaptcha": "^5.2",
|
||||
"sabre/vobject": "^4.5"
|
||||
"sabre/vobject": "^4.5.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^7.0",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"nunomaduro/collision": "^8.5",
|
||||
"phpmd/phpmd": "^2.15",
|
||||
"squizlabs/php_codesniffer": "^3.7"
|
||||
"squizlabs/php_codesniffer": "^3.13.2"
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "8.1"
|
||||
"php": "8.2"
|
||||
},
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
|
|
|
|||
1449
flexiapi/composer.lock
generated
1449
flexiapi/composer.lock
generated
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -37,6 +37,12 @@ return [
|
|||
'recovery_code_expiration_minutes' => env('APP_RECOVERY_CODE_EXPIRATION_MINUTES', 10),
|
||||
'provisioning_token_expiration_minutes' => env('APP_PROVISIONING_TOKEN_EXPIRATION_MINUTES', 0),
|
||||
'reset_password_email_token_expiration_minutes' => env('APP_RESET_PASSWORD_EMAIL_TOKEN_EXPIRATION_MINUTES', 1440),
|
||||
|
||||
/**
|
||||
* Temporary toggles
|
||||
*/
|
||||
'show_login_counter_temp' => env('APP_SHOW_LOGIN_COUNTER_TEMP', true),
|
||||
|
||||
/**
|
||||
* Amount of minutes before re-authorizing the generation of a new account creation token
|
||||
*/
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue