diff --git a/Makefile b/Makefile index 50584e4..578fdcf 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ package-common: # General cp README.md $(OUTPUT_DIR)/flexisip-account-manager/ cp -R httpd/ $(OUTPUT_DIR)/flexisip-account-manager/ + cp -R cron/ $(OUTPUT_DIR)/flexisip-account-manager/ cp flexisip-account-manager.spec $(OUTPUT_DIR)/rpmbuild/SPECS/ tar cvf flexisip-account-manager.tar.gz -C $(OUTPUT_DIR) flexisip-account-manager diff --git a/cron/flexiapi.debian b/cron/flexiapi.debian new file mode 100644 index 0000000..b529a5c --- /dev/null +++ b/cron/flexiapi.debian @@ -0,0 +1,6 @@ +#!/bin/sh + +cd /opt/belledonne-communications/share/flexisip-account-manager/flexiapi/ +sudo -su www-data && php artisan digest:expired-nonces-clear 60 +sudo -su www-data && php artisan accounts:clear-accounts-tombstones 7 --apply +sudo -su www-data && php artisan accounts:clear-unconfirmed 30 --apply \ No newline at end of file diff --git a/cron/flexiapi.redhat b/cron/flexiapi.redhat new file mode 100644 index 0000000..6793c50 --- /dev/null +++ b/cron/flexiapi.redhat @@ -0,0 +1,6 @@ +#!/bin/sh + +cd /opt/belledonne-communications/share/flexisip-account-manager/flexiapi/ +scl enable rh-php73 "php artisan digest:expired-nonces-clear 60" +scl enable rh-php73 "php artisan accounts:clear-accounts-tombstones 7 --apply" +scl enable rh-php73 "php artisan accounts:clear-unconfirmed 30 --apply" \ No newline at end of file diff --git a/flexiapi/app/Helpers/Utils.php b/flexiapi/app/Helpers/Utils.php index be2a283..2f40026 100644 --- a/flexiapi/app/Helpers/Utils.php +++ b/flexiapi/app/Helpers/Utils.php @@ -58,6 +58,12 @@ class Utils return mt_rand(1000, 9999); } + public static function percent($value, $max) + { + if ($max == 0) $max = 1; + return round(($value*100)/$max, 2); + } + public static function markdownDocumentationView($view) { $environment = Environment::createCommonMarkEnvironment(); diff --git a/flexiapi/app/Http/Controllers/Account/RegisterController.php b/flexiapi/app/Http/Controllers/Account/RegisterController.php index fb23b82..2c7b820 100644 --- a/flexiapi/app/Http/Controllers/Account/RegisterController.php +++ b/flexiapi/app/Http/Controllers/Account/RegisterController.php @@ -91,7 +91,7 @@ class RegisterController extends Controller $account->domain = config('app.sip_domain'); $account->ip_address = $request->ip(); $account->creation_time = Carbon::now(); - $account->user_agent = config('app.name'); + $account->user_agent = $request->header('User-Agent') ?? config('app.name'); $account->save(); $account->confirmation_key = Str::random($this->emailCodeSize); @@ -143,7 +143,7 @@ class RegisterController extends Controller $account->domain = config('app.sip_domain'); $account->ip_address = $request->ip(); $account->creation_time = Carbon::now(); - $account->user_agent = config('app.name'); + $account->user_agent = $request->header('User-Agent') ?? config('app.name'); $account->save(); $alias = new Alias; diff --git a/flexiapi/app/Http/Controllers/Admin/StatisticsController.php b/flexiapi/app/Http/Controllers/Admin/StatisticsController.php new file mode 100644 index 0000000..d81d76d --- /dev/null +++ b/flexiapi/app/Http/Controllers/Admin/StatisticsController.php @@ -0,0 +1,53 @@ + $day, + 'max_day' => $maxDay, + ]); + } + + public function showWeek(Request $request) + { + $week = StatisticsCruncher::week(); + $maxWeek = 0; + foreach ($week as $day) { + if ($maxWeek < $day['all']) $maxWeek = $day['all']; + } + + return view('admin.statistics.show_week', [ + 'week' => $week, + 'max_week' => $maxWeek, + ]); + } + + public function showMonth(Request $request) + { + $month = StatisticsCruncher::month(); + $maxMonth = 0; + foreach ($month as $day) { + if ($maxMonth < $day['all']) $maxMonth = $day['all']; + } + + return view('admin.statistics.show_month', [ + 'month' => $month, + 'max_month' => $maxMonth, + ]); + } +} diff --git a/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php b/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php index a7cfec1..fe650e8 100644 --- a/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php @@ -124,7 +124,7 @@ class AccountController extends Controller $account->domain = $request->has('domain') && config('app.everyone_is_admin') ? $request->get('domain') : config('app.sip_domain'); - $account->user_agent = config('app.name'); + $account->user_agent = $request->header('User-Agent') ?? config('app.name'); if (!$request->has('activated') || !(bool)$request->get('activated')) { $account->confirmation_key = Str::random(WebAuthenticateController::$emailCodeSize); diff --git a/flexiapi/app/Http/Controllers/Api/StatisticController.php b/flexiapi/app/Http/Controllers/Api/StatisticController.php new file mode 100644 index 0000000..0398610 --- /dev/null +++ b/flexiapi/app/Http/Controllers/Api/StatisticController.php @@ -0,0 +1,43 @@ +. +*/ + +namespace App\Http\Controllers\Api; + +use App\Http\Controllers\Controller; +use Illuminate\Http\Request; + +use App\Libraries\StatisticsCruncher; + +class StatisticController extends Controller +{ + public function month(Request $request) + { + return StatisticsCruncher::month(); + } + + public function week(Request $request) + { + return StatisticsCruncher::week(); + } + + public function day(Request $request) + { + return StatisticsCruncher::day(); + } +} diff --git a/flexiapi/app/Libraries/StatisticsCruncher.php b/flexiapi/app/Libraries/StatisticsCruncher.php new file mode 100644 index 0000000..4fb2c31 --- /dev/null +++ b/flexiapi/app/Libraries/StatisticsCruncher.php @@ -0,0 +1,197 @@ +. +*/ + +namespace App\Libraries; + +use Illuminate\Support\Facades\DB; + +use Carbon\Carbon; +use Carbon\CarbonPeriod; +use Carbon\CarbonInterval; + +use App\Account; + + +class StatisticsCruncher +{ + public static function month() + { + $data = self::getAccountFrom(Carbon::now()->subMonth()) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + $dataAliases = self::getAccountFrom(Carbon::now()->subMonth()) + ->whereIn('id', function($query) { + $query->select('account_id') + ->from('aliases'); + }) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + $dataActivated = self::getAccountFrom(Carbon::now()->subMonth()) + ->where('activated', true) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + $dataAliasesActivated = self::getAccountFrom(Carbon::now()->subMonth()) + ->where('activated', true) + ->whereIn('id', function($query) { + $query->select('account_id') + ->from('aliases'); + }) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + return self::compileStatistics( + collect(CarbonPeriod::create(Carbon::now()->subMonth(), Carbon::now()))->map->format('Y-m-d'), + $data, + $dataAliases, + $dataActivated, + $dataAliasesActivated + ); + } + + public static function week() + { + $data = self::getAccountFrom(Carbon::now()->subWeek()) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + $dataAliases = self::getAccountFrom(Carbon::now()->subWeek()) + ->whereIn('id', function($query) { + $query->select('account_id') + ->from('aliases'); + }) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + $dataActivated = self::getAccountFrom(Carbon::now()->subWeek()) + ->where('activated', true) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + $dataAliasesActivated = self::getAccountFrom(Carbon::now()->subWeek()) + ->where('activated', true) + ->whereIn('id', function($query) { + $query->select('account_id') + ->from('aliases'); + }) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + return self::compileStatistics( + collect(CarbonPeriod::create(Carbon::now()->subWeek(), Carbon::now()))->map->format('Y-m-d'), + $data, + $dataAliases, + $dataActivated, + $dataAliasesActivated + ); + } + + public static function day() + { + $data = self::getAccountFrom(Carbon::now()->subDay()) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d %H') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + $dataAliases = self::getAccountFrom(Carbon::now()->subDay()) + ->whereIn('id', function($query) { + $query->select('account_id') + ->from('aliases'); + }) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d %H') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + $dataActivated = self::getAccountFrom(Carbon::now()->subDay()) + ->where('activated', true) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d %H') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + $dataAliasesActivated = self::getAccountFrom(Carbon::now()->subDay()) + ->where('activated', true) + ->whereIn('id', function($query) { + $query->select('account_id') + ->from('aliases'); + }) + ->get(array( + DB::raw("date_format(creation_time,'%Y-%m-%d %H') as moment"), + DB::raw('COUNT(*) as "count"') + ))->each->setAppends([])->pluck('count', 'moment'); + + return self::compileStatistics( + collect(CarbonInterval::hour()->toPeriod(Carbon::now()->subDay(), Carbon::now()))->map->format('Y-m-d H'), + $data, + $dataAliases, + $dataActivated, + $dataAliasesActivated + ); + } + + private static function getAccountFrom($date) + { + return Account::where('creation_time', '>=', $date) + ->groupBy('moment') + ->orderBy('moment', 'DESC') + ->setEagerLoads([]); + } + + private static function compileStatistics($period, $data, $dataAliases, $dataActivated, $dataAliasesActivated) + { + $stats = []; + + foreach ($period as $moment) { + $all = $data[$moment] ?? 0; + $aliases = $dataAliases[$moment] ?? 0; + $activated = $dataActivated[$moment] ?? 0; + $activatedAliases = $dataAliasesActivated[$moment] ?? 0; + + $stats[$moment] = [ + 'all' => $all, + 'phone' => $aliases, + 'email' => $all - $aliases, + 'activated_phone' => $activatedAliases, + 'activated_email' => $activated - $activatedAliases + ]; + } + + return $stats; + } +} \ No newline at end of file diff --git a/flexiapi/composer.phar b/flexiapi/composer.phar index 4891693..8138062 100755 Binary files a/flexiapi/composer.phar and b/flexiapi/composer.phar differ diff --git a/flexiapi/config/app.php b/flexiapi/config/app.php index b4f8227..79e667a 100644 --- a/flexiapi/config/app.php +++ b/flexiapi/config/app.php @@ -257,9 +257,9 @@ return [ 'Storage' => Illuminate\Support\Facades\Storage::class, 'Str' => Illuminate\Support\Str::class, 'URL' => Illuminate\Support\Facades\URL::class, + 'Utils' => App\Helpers\Utils::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, - ], ]; diff --git a/flexiapi/database/migrations/2021_09_06_132040_add_accounts_tombstones_table.php b/flexiapi/database/migrations/2021_09_06_132040_add_accounts_tombstones_table.php index 43fdcf1..7910f46 100644 --- a/flexiapi/database/migrations/2021_09_06_132040_add_accounts_tombstones_table.php +++ b/flexiapi/database/migrations/2021_09_06_132040_add_accounts_tombstones_table.php @@ -1,4 +1,21 @@ . +*/ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; diff --git a/flexiapi/database/migrations/2021_09_16_120958_add_unique_accounts_passwords_aliases_table.php b/flexiapi/database/migrations/2021_09_16_120958_add_unique_accounts_passwords_aliases_table.php index 07f9188..fa4bce9 100644 --- a/flexiapi/database/migrations/2021_09_16_120958_add_unique_accounts_passwords_aliases_table.php +++ b/flexiapi/database/migrations/2021_09_16_120958_add_unique_accounts_passwords_aliases_table.php @@ -1,4 +1,21 @@ . +*/ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; diff --git a/flexiapi/public/css/charts.css b/flexiapi/public/css/charts.css new file mode 100644 index 0000000..01fde53 --- /dev/null +++ b/flexiapi/public/css/charts.css @@ -0,0 +1,77 @@ +.legend { + margin-bottom: 1rem; +} + +.legend div:before { + content: ''; + display: inline-block; + width: 1rem; + height: 1rem; + vertical-align: middle; + background-color: gray; + margin: 0 0.5rem; + opacity: 0.5; +} + +.columns { + display: flex; + height: 600px; + align-items: stretch; + border: 1px solid #CCC; + margin-bottom: 10rem; +} + +.columns .column { + flex: 1; + display: flex; + flex-direction: column; + align-items: stretch; + justify-content: flex-end; + position: relative; +} + +.columns .column .bar { + border-right: 1px solid white; + font-size: 0.5rem; + text-align: center; + position: relative; + opacity: 0.5; +} + +.columns .column::after { + display: block; + content: attr(data-value); + position: absolute; + top: calc(100% + 1rem); + writing-mode: vertical-rl; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.columns .column .bar.activated, +.legend div.activated:before { + opacity: 1; +} + +.columns .column .bar.first, +.legend .first:before { + background-color: salmon; +} + +.columns .column .bar.second, +.legend .second:before { + background-color: seagreen; +} + +.columns .column .bar::after { + display: block; + content: attr(data-value); + color: white; + position: absolute; + font-size: 0.75rem; + line-height: 1rem; + left: 0rem; + top: calc(50% - 0.5rem); + width: 100%; +} \ No newline at end of file diff --git a/flexiapi/resources/views/account/documentation_markdown.blade.php b/flexiapi/resources/views/account/documentation_markdown.blade.php index b4cbe1e..1e84962 100644 --- a/flexiapi/resources/views/account/documentation_markdown.blade.php +++ b/flexiapi/resources/views/account/documentation_markdown.blade.php @@ -84,6 +84,14 @@ Finally the account page allows you to provision the account, using a QR Code or The provisioning link can be generated and refreshed from this page as well. +### Create and edit an account + +Administrators can create and edit accounts directly from the admin panel. + ### Delete an account -The deletion of an account is definitive, all the database related data (password, aliases…) will be destroyed after the deletion. \ No newline at end of file +The deletion of an account is definitive, all the database related data (password, aliases…) will be destroyed after the deletion. + +## Statistics + +The statistics panel show registrations statistics based on their type (mobile and email based registration) and their activations states. \ No newline at end of file diff --git a/flexiapi/resources/views/account/panel.blade.php b/flexiapi/resources/views/account/panel.blade.php index 2d6c05f..909853f 100644 --- a/flexiapi/resources/views/account/panel.blade.php +++ b/flexiapi/resources/views/account/panel.blade.php @@ -54,6 +54,12 @@

Manage the Flexisip accounts

+ +
+
Statistics
+
+

Show some registration statistics

+
API Key
diff --git a/flexiapi/resources/views/admin/statistics/parts/columns.blade.php b/flexiapi/resources/views/admin/statistics/parts/columns.blade.php new file mode 100644 index 0000000..b62f166 --- /dev/null +++ b/flexiapi/resources/views/admin/statistics/parts/columns.blade.php @@ -0,0 +1,12 @@ +
+
+
+
\ No newline at end of file diff --git a/flexiapi/resources/views/admin/statistics/parts/legend.blade.php b/flexiapi/resources/views/admin/statistics/parts/legend.blade.php new file mode 100644 index 0000000..b250ea4 --- /dev/null +++ b/flexiapi/resources/views/admin/statistics/parts/legend.blade.php @@ -0,0 +1,6 @@ +
+
Unactivated phones
+
Activated phones
+
Unactivated emails
+
Activated emails
+
\ No newline at end of file diff --git a/flexiapi/resources/views/admin/statistics/show_day.blade.php b/flexiapi/resources/views/admin/statistics/show_day.blade.php new file mode 100644 index 0000000..75f5806 --- /dev/null +++ b/flexiapi/resources/views/admin/statistics/show_day.blade.php @@ -0,0 +1,37 @@ +@extends('layouts.account') + +@section('breadcrumb') + +@endsection + +@section('content') + + + +

Statistics

+ +@include('admin.statistics.parts.legend') + +

Day

+ +
+ @foreach ($day as $key => $hour) +
+ @include('admin.statistics.parts.columns', ['slice' => $hour, 'max' => $max_day]) +
+ @endforeach +
+ +@endsection \ No newline at end of file diff --git a/flexiapi/resources/views/admin/statistics/show_month.blade.php b/flexiapi/resources/views/admin/statistics/show_month.blade.php new file mode 100644 index 0000000..2cd07a4 --- /dev/null +++ b/flexiapi/resources/views/admin/statistics/show_month.blade.php @@ -0,0 +1,37 @@ +@extends('layouts.account') + +@section('breadcrumb') + +@endsection + +@section('content') + + + +

Statistics

+ +@include('admin.statistics.parts.legend') + +

Month

+ +
+@foreach ($month as $key => $day) +
+ @include('admin.statistics.parts.columns', ['slice' => $day, 'max' => $max_month]) +
+@endforeach +
+ +@endsection \ No newline at end of file diff --git a/flexiapi/resources/views/admin/statistics/show_week.blade.php b/flexiapi/resources/views/admin/statistics/show_week.blade.php new file mode 100644 index 0000000..80797ed --- /dev/null +++ b/flexiapi/resources/views/admin/statistics/show_week.blade.php @@ -0,0 +1,37 @@ +@extends('layouts.account') + +@section('breadcrumb') + +@endsection + +@section('content') + + + +

Statistics

+ +@include('admin.statistics.parts.legend') + +

Week

+ +
+@foreach ($week as $key => $day) +
+ @include('admin.statistics.parts.columns', ['slice' => $day, 'max' => $max_week]) +
+@endforeach +
+ +@endsection \ No newline at end of file diff --git a/flexiapi/resources/views/api/documentation_markdown.blade.php b/flexiapi/resources/views/api/documentation_markdown.blade.php index 8ae1c70..dd176f0 100644 --- a/flexiapi/resources/views/api/documentation_markdown.blade.php +++ b/flexiapi/resources/views/api/documentation_markdown.blade.php @@ -186,6 +186,17 @@ Activate an account. #### `GET /accounts/{id}/deactivate` Deactivate an account. +### Statistics + +#### `GET /statistics/day` +Retrieve registrations statistics for 24 hours. + +#### `GET /statistics/week` +Retrieve registrations statistics for a week. + +#### `GET /statistics/month` +Retrieve registrations statistics for a month. + # Provisioning When an account is having an available `confirmation_key` it can be provisioned using the two following URL. diff --git a/flexiapi/resources/views/layouts/base.blade.php b/flexiapi/resources/views/layouts/base.blade.php index 55d0602..028de06 100644 --- a/flexiapi/resources/views/layouts/base.blade.php +++ b/flexiapi/resources/views/layouts/base.blade.php @@ -13,6 +13,7 @@ @else @endif + @endif diff --git a/flexiapi/routes/api.php b/flexiapi/routes/api.php index adbed91..0dc3c85 100644 --- a/flexiapi/routes/api.php +++ b/flexiapi/routes/api.php @@ -33,6 +33,10 @@ Route::post('accounts/{sip}/activate/email', 'Api\AccountController@activateEmai Route::post('accounts/{sip}/activate/phone', 'Api\AccountController@activatePhone'); Route::group(['middleware' => ['auth.digest_or_key']], function () { + Route::get('statistic/month', 'Api\StatisticController@month'); + Route::get('statistic/week', 'Api\StatisticController@week'); + Route::get('statistic/day', 'Api\StatisticController@day'); + Route::get('accounts/me', 'Api\AccountController@show'); Route::delete('accounts/me', 'Api\AccountController@delete'); diff --git a/flexiapi/routes/web.php b/flexiapi/routes/web.php index d6ada5b..b81daba 100644 --- a/flexiapi/routes/web.php +++ b/flexiapi/routes/web.php @@ -71,6 +71,10 @@ Route::group(['middleware' => 'auth'], function () { Route::group(['middleware' => 'auth.admin'], function () { Route::post('admin/api_key', 'Admin\AccountController@generateApiKey')->name('admin.api_key.generate'); + Route::get('admin/statistics/day', 'Admin\StatisticsController@showDay')->name('admin.statistics.show.day'); + Route::get('admin/statistics/week', 'Admin\StatisticsController@showWeek')->name('admin.statistics.show.week'); + Route::get('admin/statistics/month', 'Admin\StatisticsController@showMonth')->name('admin.statistics.show.month'); + Route::get('admin/accounts/{account}/show', 'Admin\AccountController@show')->name('admin.account.show'); Route::get('admin/accounts/{account}/activate', 'Admin\AccountController@activate')->name('admin.account.activate'); diff --git a/flexisip-account-manager.spec b/flexisip-account-manager.spec index 77647df..7bd4bec 100644 --- a/flexisip-account-manager.spec +++ b/flexisip-account-manager.spec @@ -8,7 +8,7 @@ #%define _datadir %{_datarootdir} #%define _docdir %{_datadir}/doc -%define build_number 105 +%define build_number 106 %define var_dir /var/opt/belledonne-communications %define opt_dir /opt/belledonne-communications/share/flexisip-account-manager @@ -64,12 +64,16 @@ cp README* "$RPM_BUILD_ROOT%{opt_dir}/" mkdir -p "$RPM_BUILD_ROOT/etc/flexisip-account-manager" cp -R conf/* "$RPM_BUILD_ROOT/etc/flexisip-account-manager/" +mkdir -p $RPM_BUILD_ROOT/etc/cron.daily + %if %{with deb} mkdir -p $RPM_BUILD_ROOT/etc/apache2/conf-available cp httpd/flexisip-account-manager.conf "$RPM_BUILD_ROOT/etc/apache2/conf-available/" + cp cron/flexiapi.debian "$RPM_BUILD_ROOT/etc/cron.daily/" %else mkdir -p $RPM_BUILD_ROOT/opt/rh/httpd24/root/etc/httpd/conf.d cp httpd/flexisip-account-manager.conf "$RPM_BUILD_ROOT/opt/rh/httpd24/root/etc/httpd/conf.d/" + cp cron/flexiapi.redhat "$RPM_BUILD_ROOT/etc/cron.daily/" %endif # POST INSTALLATION @@ -168,15 +172,19 @@ fi %if %{with deb} %config(noreplace) /etc/apache2/conf-available/flexisip-account-manager.conf + %config(noreplace) /etc/cron.daily/flexiapi.debian %else %config(noreplace) /opt/rh/httpd24/root/etc/httpd/conf.d/flexisip-account-manager.conf + %config(noreplace) /etc/cron.daily/flexiapi.redhat %endif %clean rm -rf $RPM_BUILD_ROOT %changelog -* Tue Jan 5 2020 Timothée Jaussoin +* Tue Sep 28 2021 Timothée Jaussoin +- Install cron scripts +* Sun Jan 5 2020 Timothée Jaussoin - Import and configure the new API package * Thu Jul 4 2019 Sylvain Berfini - New files layout