1491 lines
67 KiB
Plaintext
1491 lines
67 KiB
Plaintext
<?php
|
|
|
|
use Illuminate\Validation\Rule;
|
|
|
|
return [
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Initial passwords for 1st login after installation,
|
|
| should be changed after login!
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'init_passwords' => [
|
|
'super-user' => 'SecurePassword', // Initial password, should be changed after 1st login
|
|
'super-admin' => 'SecurePassword',
|
|
'bank' => 'SecurePassword',
|
|
'admin' => 'SecurePassword',
|
|
'test-profile' => 'password',
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Central Bank (Level 0 Source Bank)
|
|
|--------------------------------------------------------------------------
|
|
| Configuration for the central bank that is created during database seeding.
|
|
| The central bank is the source of currency creation/removal in the system.
|
|
|
|
|
*/
|
|
'central_bank' => [
|
|
'name' => 'Central Bank',
|
|
'full_name' => 'Central Bank',
|
|
'email' => 'bank@example.org',
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Mail addresses
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'mail' => [
|
|
'system_admin' => [
|
|
'email' => 'admin@timebank.cc',
|
|
'name' => 'admin@timebank.cc',
|
|
],
|
|
'user_admin' => [
|
|
'email' => 'info@timebank.cc',
|
|
'name' => 'info@timebank.cc',
|
|
],
|
|
'content_admin' => [
|
|
'email' => 'info@timebank.cc',
|
|
'name' => config('app.name'),
|
|
],
|
|
'payments' => [
|
|
'email' => 'payments@timebank.cc',
|
|
'name' => config('app.name'),
|
|
],
|
|
'chat_messenger' => [
|
|
'email' => 'chats@timebank.cc',
|
|
'name' => config('app.name'),
|
|
],
|
|
'support' => [
|
|
'email' => env('MAIL_SUPPORT_ADDRESS', 'support@timebank.cc'),
|
|
'name' => env('MAIL_SUPPORT_NAME', 'Timebank.cc Support Team'),
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Platform specific translations
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'platform_translations' => [
|
|
'en' => [
|
|
'platform_name' => 'Timebank.cc',
|
|
'platform_name_legal' => 'association Timebank.cc',
|
|
'platform_name_short' => 'Timebank',
|
|
'platform_slogan' => 'Your time is currency',
|
|
'platform_currency_name' => 'Hour',
|
|
'platform_currency_name_plural' => 'Hours',
|
|
'platform_currency_symbol' => 'H',
|
|
'platform_currency_position_end' => false, // true will place currency symbol behind currency amount
|
|
'platform_user' => 'timebanker',
|
|
'platform_users' => 'timebankers',
|
|
'platform_principles' => 'Timebank principles',
|
|
],
|
|
'nl' => [
|
|
'platform_name' => 'Timebank.cc',
|
|
'platform_name_legal' => 'vereniging Timebank.cc',
|
|
'platform_name_short' => 'Timebank',
|
|
'platform_slogan' => 'Jouw tijd is deelbaar',
|
|
'platform_currency_name' => 'Uur',
|
|
'platform_currency_name_plural' => 'Uren',
|
|
'platform_currency_symbol' => 'H',
|
|
'platform_currency_position_end' => false, // true will place currency symbol behind currency amount
|
|
'platform_user' => 'timebanker',
|
|
'platform_users' => 'timebankers',
|
|
'platform_principles' => 'Timebank principes',
|
|
],
|
|
'fr' => [
|
|
'platform_name' => 'Timebank.cc',
|
|
'platform_name_legal' => 'association Timebank.cc',
|
|
'platform_name_short' => 'Timebank',
|
|
'platform_slogan' => 'Ton temps est une monnaie',
|
|
'platform_currency_name' => 'Heure',
|
|
'platform_currency_name_plural' => 'Heures',
|
|
'platform_currency_symbol' => 'H',
|
|
'platform_currency_position_end' => false, // true will place currency symbol behind currency amount
|
|
'platform_user' => 'tempobanquier',
|
|
'platform_users' => 'tempobanquiers',
|
|
'platform_principles' => 'Principes de Timebank',
|
|
],
|
|
'es' => [
|
|
'platform_name' => 'Timebank.cc',
|
|
'platform_name_legal' => 'asociación Timebank.cc',
|
|
'platform_name_short' => 'Timebank',
|
|
'platform_slogan' => 'Tu tiempo es compartible',
|
|
'platform_currency_name' => 'Hora',
|
|
'platform_currency_name_plural' => 'Horas',
|
|
'platform_currency_symbol' => 'H',
|
|
'platform_currency_position_end' => false, // true will place currency symbol behind currency amount
|
|
'platform_user' => 'tiempobanker',
|
|
'platform_users' => 'tiempobankers',
|
|
'platform_principles' => 'Principios de Timebank',
|
|
],
|
|
'de' => [
|
|
'platform_name' => 'Timebank.cc',
|
|
'platform_name_legal' => 'Verein Timebank.cc',
|
|
'platform_name_short' => 'Timebank',
|
|
'platform_slogan' => 'Deine Zeit ist Währung',
|
|
'platform_currency_name' => 'Stunde',
|
|
'platform_currency_name_plural' => 'Stunden',
|
|
'platform_currency_symbol' => 'Std',
|
|
'platform_currency_position_end' => false, // true will place currency symbol behind currency amount
|
|
'platform_user' => 'Zeitbanker',
|
|
'platform_users' => 'Zeitbankers',
|
|
'platform_principles' => 'Timebank Prinzipien',
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Admin settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'admin_settings' => [
|
|
'log_lines' => 100, // Show last nr of lines of the log on admin dashboard
|
|
'activity_log_delete_records_older_than_days' => 365 // 1 year
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| IP Address Retention
|
|
|--------------------------------------------------------------------------
|
|
| Configure retention period for IP addresses stored in profile tables
|
|
| (last_login_ip) and activity logs. IP addresses older than this period
|
|
| should be anonymized or deleted for GDPR compliance.
|
|
|
|
|
*/
|
|
'ip_retention' => [
|
|
'retention_days' => 180, // Retain IP addresses for 6 months (180 days)
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Logging settings
|
|
|--------------------------------------------------------------------------
|
|
| Configure Laravel's default log rotation and retention.
|
|
| These settings apply to the standard laravel.log files.
|
|
|
|
|
*/
|
|
'logging' => [
|
|
'daily_retention_days' => 14, // Number of days to keep daily log files (default: 14)
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Presence System settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'presence_settings' => [
|
|
'keep_last_presence_updates' => 10, // nr of most recent activity log records to keep
|
|
'update_interval' => 60, // Update presence time in seconds
|
|
|
|
],
|
|
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Default Profile Properties
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'profiles' => [
|
|
'user' => [
|
|
'limit_min' => 0,
|
|
'limit_max' => 6000, // 100 H
|
|
'profile_photo_path_new' => 'app-images/profile-user-new.svg',
|
|
'profile_photo_path_default' => 'app-images/profile-user-default.svg',
|
|
'messenger_can_create_groups' => true, // true: profile can start a group chat
|
|
|
|
],
|
|
'organization' => [
|
|
'limit_min' => 0,
|
|
'limit_max' => 6000, // 100 H4
|
|
'profile_photo_path_new' => 'app-images/profile-organization-default.svg',
|
|
'profile_photo_path_default' => 'app-images/profile-organization-default.svg',
|
|
'messenger_can_create_groups' => true, // true: profile can start a group chat
|
|
|
|
],
|
|
'bank' => [
|
|
'level' => 1, // by default a non-public system bank is created as this can be privately installed and later changed to a public level 2 bank
|
|
'limit_min' => 0,
|
|
'limit_max' => null, // unlimited H
|
|
'profile_photo_path_new' => 'app-images/profile-bank-default.svg',
|
|
'profile_photo_path_default' => 'app-images/profile-bank-default.svg',
|
|
'messenger_can_create_groups' => true, // true: profile can start a group chat
|
|
],
|
|
'admin' => [
|
|
'limit_min' => 0,
|
|
'limit_max' => 0,
|
|
'profile_photo_path_new' => 'app-images/profile-admin-default.svg',
|
|
'profile_photo_path_default' => 'app-images/profile-admin-default.svg',
|
|
'messenger_can_create_groups' => true, // true: profile can start a group chat
|
|
],
|
|
],
|
|
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Default Account Properties
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| The default account properties that will be set into the database when new accounts are created.
|
|
| The balance limits are in minutes. A negative balance limit should be set as 'limit_min' = -300
|
|
|
|
|
| Receiving types - defines which transaction types the account can receive:
|
|
| 1 => worked time
|
|
| 2 => gift
|
|
| 3 => donation
|
|
| 4 => currency creation
|
|
| 5 => currency removal
|
|
| 6 => migration
|
|
|
|
|
| Note: When renaming the account names, make sure also translation keys exists for the new names!
|
|
|
|
|
|
|
*/
|
|
// TODO JOERI: Check transaction types
|
|
'accounts' => [
|
|
'user' => [
|
|
'name' => 'personal',
|
|
'limit_min' => 0,
|
|
'limit_max' => 6000, // 100 H
|
|
'receiving_types' => [1,2,6],
|
|
],
|
|
'user_project' => [
|
|
'name' => 'personal project',
|
|
'limit_min' => 0,
|
|
'receiving_types' => [1,3,6],
|
|
],
|
|
'organization' => [
|
|
'name' => 'organization',
|
|
'limit_min' => 0,
|
|
'limit_max' => 12000, // 200 H, default value, manually set organizations with a big turn-over to a higher limit
|
|
'receiving_types' => [1,3,6],
|
|
],
|
|
'bank' => [
|
|
'name' => 'banking system',
|
|
'limit_min' => 0, // The 'source' bank and the debit account should have limit_min = NULL, other banks can use this config
|
|
'limit_max' => 600000, // 10.000 H
|
|
'receiving_types' => [1,4,6],
|
|
],
|
|
'community' => [
|
|
'name' => 'community',
|
|
'limit_min' => 0, // The 'source' bank and the debit account should have limit_min = NULL, other banks can use this config
|
|
'limit_max' => null,
|
|
'receiving_types' => [3,4],
|
|
],
|
|
'debit' => [
|
|
'name' => 'debit',
|
|
'limit_min' => null, // The 'source' bank and the debit account should have limit_min = NULL, other banks can use this config
|
|
'limit_max' => 0,
|
|
'receiving_types' => [5],
|
|
],
|
|
],
|
|
'maxLengthHoursInput' => [ // Sets the default max length the amount component can have for the hours input box
|
|
'user' => 3,
|
|
'organization' => 3,
|
|
'bank' => 5,
|
|
'admin' => 10,
|
|
'transaction_types' => [],
|
|
],
|
|
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Bank Properties
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
'banks' => [
|
|
'level' => [
|
|
0 => 'Source', // Single source bank that has the debit account and can create / remove currency
|
|
1 => 'System', // System banks that are private and bridge between level 0 and 2
|
|
2 => 'Public', // Public banks that bring currency into circulation, or remove currency from circulation
|
|
],
|
|
],
|
|
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Profile type permission settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Payment types - defines which transaction types the user type can pay:
|
|
| 1 => worked time
|
|
| 2 => gift
|
|
| 3 => donation
|
|
| 4 => currency creation
|
|
| 5 => currency removal
|
|
| 6 => migration
|
|
|
|
|
| Note: Internal migration payments between accounts of the same owner are always allowed.
|
|
| External migration payments are defined below.
|
|
*/
|
|
// TODO JOERI: Check transaction types
|
|
'permissions' => [
|
|
'user' => [
|
|
'payment_types' => [1,2,3],
|
|
],
|
|
'user_project' => [
|
|
'payment_types' => [1,2,3],
|
|
],
|
|
'organization' => [
|
|
'payment_types' => [1,2,3],
|
|
],
|
|
'bank' => [
|
|
'payment_types' => [1,2,3,5,6],
|
|
],
|
|
'admin' => [
|
|
'payment_types' => [], // Admins do not have an account and can not make payments
|
|
],
|
|
],
|
|
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Public / Private settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
'account_info' => [
|
|
'user' => [
|
|
'balance_public' => true, //Privacy during transactions (payment flow)
|
|
'sumBalances_public' => true, //Privacy on profile pages (viewing profiles)
|
|
'countTransfersSince' => 365 * 2, // days ago
|
|
'countTransfersSince_humanReadable' => 'past 2 years', // Short description of countTransfersSince in base language: must have translation key!
|
|
'countTransfers_public' => true,
|
|
'countTransfersReceived_public' => true,
|
|
'countTransfersGiven_public' => true,
|
|
'countTransfersReceivedOrGiven_public' => true,
|
|
'lastTransferDate_public' => true,
|
|
],
|
|
'organization' => [
|
|
'balance_public' => true, //Privacy during transactions (payment flow)
|
|
'sumBalances_public' => true, //Privacy on profile pages (viewing profiles)
|
|
'countTransfersSince' => 365, // days ago
|
|
'countTransfersSince_humanReadable' => 'past year', // Short description of countTransfersSince in base language: must have translation key!
|
|
'countTransfers_public' => true,
|
|
'countTransfersReceived_public' => true,
|
|
'countTransfersGiven_public' => true,
|
|
'countTransfersReceivedOrGiven_public' => true,
|
|
'lastTransferDate_public' => true,
|
|
],
|
|
'bank' => [
|
|
'balance_public' => false, //Privacy during transactions (payment flow)
|
|
'sumBalances_public' => true, //Privacy on profile pages (viewing profiles)
|
|
'countTransfersSince' => 365, // days ago
|
|
'countTransfersSince_humanReadable' => 'past year', // Short description of countTransfersSince in base language: must have translation key!
|
|
'countTransfers_public' => true,
|
|
'countTransfersReceived_public' => true,
|
|
'countTransfersGiven_public' => true,
|
|
'countTransfersReceivedOrGiven_public' => true,
|
|
'lastTransferDate_public' => true,
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Verification rules and file size limits
|
|
|--------------------------------------------------------------------------
|
|
| Here you can set the verification rules that will be used to verify data
|
|
| that will be submitted in forms.
|
|
|
|
|
| Also you can set here the uploaded file properties and limits as well as
|
|
| the default files that will be used when no file is uploaded by the user.
|
|
*/
|
|
|
|
|
|
|
|
'rules' => [
|
|
'phone' => 'nullable|phone:mobile,strict', //mobile phone for future sms verification, strict mode, no spaces, no dashes, no brackets
|
|
'phone_public' => 'boolean|nullable',
|
|
'comment' => 'nullable|string|max:1000',
|
|
'profile_user' => [
|
|
'name' => [
|
|
'required',
|
|
'string',
|
|
'unique:users,name',
|
|
'unique:organizations,name',
|
|
'unique:banks,name',
|
|
'unique:banks,full_name',
|
|
'unique:admins,name',
|
|
'unique:admins,full_name',
|
|
'min:3',
|
|
'max:40',
|
|
function ($attribute, $value, $fail) {
|
|
// Disallow the following words to be used inside the name:
|
|
$disallowedWords = [
|
|
'admin',
|
|
'administrator',
|
|
'superuser',
|
|
'super-user',
|
|
'super-admin',
|
|
'supervisor',
|
|
'webmaster',
|
|
'web-master',
|
|
'tijd-bank',
|
|
'tijdbank',
|
|
'bank',
|
|
'timebank',
|
|
'time-bank',
|
|
'moderator',
|
|
'regulator',
|
|
'belasting',
|
|
'tax',
|
|
'test',
|
|
];
|
|
|
|
// Disallowed names as they might conflict with (future) url paths
|
|
$completelyDisallowedNames = [
|
|
'test',
|
|
'debug',
|
|
'user',
|
|
'users',
|
|
'member',
|
|
'members',
|
|
'profile',
|
|
'organization',
|
|
'organizations',
|
|
'organisation',
|
|
'organisations',
|
|
'bank',
|
|
'banks',
|
|
'admin',
|
|
'transaction',
|
|
'transactions',
|
|
'transfer',
|
|
'transfers',
|
|
'statement',
|
|
'statements',
|
|
'payment',
|
|
'payments',
|
|
'pay',
|
|
'paid',
|
|
'invoice',
|
|
'request',
|
|
'requests',
|
|
'edit',
|
|
'show',
|
|
'update',
|
|
'message',
|
|
'messages',
|
|
'messenger',
|
|
'messengers',
|
|
'berichten',
|
|
'chat',
|
|
'talk',
|
|
'meet',
|
|
'drive',
|
|
'cloud',
|
|
'config',
|
|
'settings',
|
|
'agenda',
|
|
'calendar',
|
|
'news',
|
|
'nieuws',
|
|
'vote',
|
|
'poll',
|
|
'auth',
|
|
'authenticate',
|
|
'verify',
|
|
'verification',
|
|
'date',
|
|
'datum',
|
|
'confirm',
|
|
'mail',
|
|
'post',
|
|
'posts',
|
|
'blog',
|
|
];
|
|
|
|
// Check for disallowed substrings
|
|
foreach ($disallowedWords as $word) {
|
|
if (str_contains(strtolower($value), $word)) {
|
|
$fail(trans('validation.custom.profile_user.name.disallowed', ['word' => $word]));
|
|
}
|
|
}
|
|
|
|
// Check for completely disallowed names
|
|
if (in_array(strtolower($value), array_map('strtolower', $completelyDisallowedNames))) {
|
|
$fail(trans('validation.custom.profile_user.name.completely_disallowed', ['name' => $value]));
|
|
}
|
|
},
|
|
'regex:/^[\p{L}0-9-_ ]+$/u', // letters (including accented), numbers, spaces, dashes and underscores
|
|
],
|
|
'full_name' => [
|
|
'nullable',
|
|
'string',
|
|
'unique:organizations,name',
|
|
'unique:banks,name',
|
|
'unique:banks,full_name',
|
|
'unique:admins,name',
|
|
'unique:admins,full_name',
|
|
'min:3',
|
|
'max:40',
|
|
'regex:/^[\p{L}0-9-_ ]+$/u', // letters (including accented), numbers, spaces, dashes and underscores
|
|
function ($attribute, $value, $fail) {
|
|
// Disallow the following words to be used inside the name:
|
|
$disallowedWords = [
|
|
'admin',
|
|
'administrator',
|
|
'superuser',
|
|
'super-user',
|
|
'super-admin',
|
|
'supervisor',
|
|
'webmaster',
|
|
'web-master',
|
|
'tijd-bank',
|
|
'tijdbank',
|
|
'bank',
|
|
'timebank',
|
|
'time-bank',
|
|
'moderator',
|
|
'regulator',
|
|
'belasting',
|
|
'tax',
|
|
'test',
|
|
];
|
|
|
|
// Check for disallowed substrings
|
|
foreach ($disallowedWords as $word) {
|
|
if (str_contains(strtolower($value), $word)) {
|
|
$fail(trans('validation.custom.profile_user.name.disallowed', ['word' => $word]));
|
|
}
|
|
}
|
|
},
|
|
],
|
|
'email' => 'required|email|unique:users,email|unique:organizations,email|unique:banks,email|unique:admins,email|max:40',
|
|
// 'password' => 'required|min:6|same:passwordConfirmation',
|
|
'password' => 'required|min:6|confirmed',
|
|
'profile_photo' => 'nullable|mimes:gif,jpg,jpeg,png,svg|max:6144', // max 6 MB
|
|
'about' => 'nullable|string|max:1000', //Cyclos: no max characters
|
|
'about_max_input' => 1000, // should match validation rule!
|
|
'about_short' => 'nullable|string|max:150', //Cyclos: no max characters
|
|
'about_short_max_input' => 150, // should match validation rule!
|
|
'motivation' => 'nullable|string|max:300', //Cyclos: no max characters
|
|
'motivation_max_input' => 300, // should match validation rule!
|
|
'date_of_birth' => 'nullable|date',
|
|
'languages' => 'required',
|
|
'languages_id' => 'int',
|
|
'website' => 'nullable|regex:/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/',
|
|
],
|
|
'profile_organization' => [
|
|
'name' => [
|
|
'required',
|
|
'string',
|
|
'unique:users,name',
|
|
'unique:organizations,name',
|
|
'unique:banks,name',
|
|
'unique:banks,full_name',
|
|
'unique:admins,name',
|
|
'unique:admins,full_name',
|
|
'min:3',
|
|
'max:40',
|
|
function ($attribute, $value, $fail) {
|
|
// Disallow the following words to be used inside the name:
|
|
$disallowedWords = [
|
|
'admin',
|
|
'administrator',
|
|
'superuser',
|
|
'super-user',
|
|
'supervisor',
|
|
'webmaster',
|
|
'web-master',
|
|
'tijd-bank',
|
|
'tijdbank',
|
|
'bank',
|
|
'timebank',
|
|
'time-bank',
|
|
'moderator',
|
|
'regulator',
|
|
'belasting',
|
|
'tax',
|
|
'test',
|
|
];
|
|
|
|
// Disallowed names as they might conflict with (future) url paths
|
|
$completelyDisallowedNames = [
|
|
'test',
|
|
'debug',
|
|
'user',
|
|
'users',
|
|
'member',
|
|
'members',
|
|
'profile',
|
|
'organization',
|
|
'organizations',
|
|
'organisation',
|
|
'organisations',
|
|
'bank',
|
|
'banks',
|
|
'admin',
|
|
'transaction',
|
|
'transactions',
|
|
'transfer',
|
|
'transfers',
|
|
'statement',
|
|
'statements',
|
|
'payment',
|
|
'payments',
|
|
'pay',
|
|
'paid',
|
|
'invoice',
|
|
'request',
|
|
'requests',
|
|
'edit',
|
|
'show',
|
|
'update',
|
|
'message',
|
|
'messages',
|
|
'messenger',
|
|
'messengers',
|
|
'berichten',
|
|
'chat',
|
|
'talk',
|
|
'meet',
|
|
'drive',
|
|
'cloud',
|
|
'config',
|
|
'settings',
|
|
'agenda',
|
|
'calendar',
|
|
'news',
|
|
'nieuws',
|
|
'vote',
|
|
'poll',
|
|
'auth',
|
|
'authenticate',
|
|
'verify',
|
|
'verification',
|
|
'date',
|
|
'datum',
|
|
'confirm',
|
|
'mail',
|
|
'post',
|
|
'posts',
|
|
'blog',
|
|
];
|
|
|
|
// Check for disallowed substrings
|
|
foreach ($disallowedWords as $word) {
|
|
if (str_contains(strtolower($value), $word)) {
|
|
$fail(trans('validation.custom.profile_user.name.disallowed', ['word' => $word]));
|
|
}
|
|
}
|
|
|
|
// Check for completely disallowed names
|
|
if (in_array(strtolower($value), array_map('strtolower', $completelyDisallowedNames))) {
|
|
$fail(trans('validation.custom.profile_user.name.completely_disallowed', ['name' => $value]));
|
|
}
|
|
},
|
|
'regex:/^[\p{L}0-9-_ ]+$/u', // letters (including accented), numbers, spaces, dashes and underscores
|
|
],
|
|
'full_name' => [
|
|
'nullable',
|
|
'string',
|
|
'unique:users,name',
|
|
'unique:organizations,name',
|
|
'unique:banks,name',
|
|
'unique:banks,full_name',
|
|
'unique:admins,name',
|
|
'unique:admins,full_name',
|
|
'min:3',
|
|
'max:40',
|
|
'regex:/^[\p{L}0-9-_ ]+$/u', // letters (including accented), numbers, spaces, dashes and underscores
|
|
],
|
|
'email' => 'required|email|unique:users,email|unique:organizations,email|unique:banks,email|unique:admins,email|max:40',
|
|
'password' => 'required|string|min:8|confirmed',
|
|
'profile_photo' => 'nullable|mimes:gif,jpg,jpeg,png,svg|max:6144', // max 6 MB
|
|
'about' => 'nullable|string|max:1000',
|
|
'about_max_input' => 1000, // should match validation rule!
|
|
'about_short' => 'nullable|string|max:150',
|
|
'about_short_max_input' => 150, // should match validation rule!
|
|
'motivation' => 'nullable|string|max:200',
|
|
'motivation_max_input' => 200, // should match validation rule!
|
|
'languages' => 'required',
|
|
'languages_id' => 'int',
|
|
'website' => 'nullable|regex:/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/',
|
|
],
|
|
'profile_bank' => [
|
|
'name' => [
|
|
'required',
|
|
'string',
|
|
'unique:users,name',
|
|
'unique:organizations,name',
|
|
'unique:banks,name',
|
|
'unique:banks,full_name',
|
|
'unique:admins,name',
|
|
'unique:admins,full_name',
|
|
'min:3',
|
|
'max:40',
|
|
'regex:/^[\p{L}0-9-_ ]+$/u', // letters (including accented), numbers, spaces, dashes and underscores
|
|
],
|
|
'full_name' => [
|
|
'nullable',
|
|
'string',
|
|
'unique:users,name',
|
|
'unique:organizations,name',
|
|
'unique:banks,name',
|
|
'unique:banks,full_name',
|
|
'unique:admins,name',
|
|
'unique:admins,full_name',
|
|
'min:3',
|
|
'max:40',
|
|
'regex:/^[\p{L}0-9-_ ]+$/u', // letters (including accented), numbers, spaces, dashes and underscores
|
|
],
|
|
'email' => 'required|email|unique:users,email|unique:organizations,email|unique:banks,email|unique:admins,email|max:40',
|
|
'password' => 'required|string|min:12|confirmed',
|
|
'profile_photo' => 'nullable|mimes:gif,jpg,jpeg,png,svg|max:6144', // max 6 MB
|
|
'about' => 'nullable|string|max:1000',
|
|
'about_max_input' => 1000, // should match validation rule!
|
|
'about_short' => 'nullable|string|max:150',
|
|
'about_short_max_input' => 150, // should match validation rule!
|
|
'motivation' => 'nullable|string|max:200',
|
|
'motivation_max_input' => 200, // should match validation rule!
|
|
'languages' => 'required',
|
|
'languages_id' => 'int',
|
|
'website' => 'nullable|regex:/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/',
|
|
],
|
|
'profile_admin' => [
|
|
'name' => [
|
|
'required',
|
|
'string',
|
|
'unique:users,name',
|
|
'unique:organizations,name',
|
|
'unique:banks,name',
|
|
'unique:banks,full_name',
|
|
'unique:admins,name',
|
|
'unique:admins,full_name',
|
|
'min:3',
|
|
'max:40',
|
|
'regex:/^[\p{L}0-9-_ ]+$/u', // letters (including accented), numbers, spaces, dashes and underscores
|
|
],
|
|
'full_name' => [
|
|
'nullable',
|
|
'string',
|
|
'unique:users,name',
|
|
'unique:organizations,name',
|
|
'unique:banks,name',
|
|
'unique:banks,full_name',
|
|
'unique:admins,name',
|
|
'unique:admins,full_name',
|
|
'min:3',
|
|
'max:40',
|
|
'regex:/^[\p{L}0-9-_ ]+$/u', // letters (including accented), numbers, spaces, dashes and underscores
|
|
],
|
|
'email' => 'required|email|unique:users,email|unique:organizations,email|unique:banks,email|unique:admins,email|max:40',
|
|
'password' => 'required|string|min:12|confirmed',
|
|
'profile_photo' => 'nullable|mimes:gif,jpg,jpeg,png,svg|max:6144', // max 6 MB
|
|
'about' => 'nullable|string|max:1000',
|
|
'about_max_input' => 1000, // should match validation rule!
|
|
'about_short' => 'nullable|string|max:150',
|
|
'about_short_max_input' => 150, // should match validation rule!
|
|
'motivation' => 'nullable|string|max:200',
|
|
'motivation_max_input' => 200, // should match validation rule!
|
|
'languages' => 'required',
|
|
'languages_id' => 'int',
|
|
'website' => 'nullable|regex:/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/',
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Authentication Settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'auth' => [
|
|
'minimum_registration_age' => 18, // Minimum age for registration (GDPR Article 8 compliance)
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Base Language
|
|
|--------------------------------------------------------------------------
|
|
| Translations are linked by their context to one base language.
|
|
|
|
|
| IMPORTANT: This language is also used as fallback locale, therefore all names, titles, terms, etc. must be at least in this language!
|
|
| IMPORTANT: The base language can not be changed in an existing project, unless the new base language pre-exists for all translations!
|
|
*/
|
|
'base_language' => 'en', // Do not change in existing project, see note above
|
|
'base_language_name' => 'English', // Do not change in existing project, see note above
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Search settings
|
|
|--------------------------------------------------------------------------
|
|
| Configuration of Elasticsearch matching and highlighting.
|
|
| More info: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
|
|
|
|
|
*/
|
|
'main_search_bar' => [
|
|
'boosted_fields' => [ // fields with a boost factor, 1,0 neutral, 1,5 boosted, 0,5 penalized
|
|
'profile' => [
|
|
'name' => 1,
|
|
'full_name' => 1,
|
|
'cyclos_skills' => 1.5, // lower than tags, to promote use of tags
|
|
'tags' => 2,
|
|
'tag_categories' => 1.4,
|
|
'motivation' => 1,
|
|
'about_short' => 1,
|
|
'about' => 1,
|
|
'district' => 1,
|
|
'city' => 1,
|
|
'division' => 1,
|
|
'country' => 1,
|
|
],
|
|
'post' => [
|
|
'title' => 2, // title is the most important field
|
|
'content' => 1,
|
|
'excerpt' => 1.5,
|
|
'post_category_name' => 2, // category name is important for posts
|
|
],
|
|
],
|
|
'boosted_models' => [ // search score multiplier
|
|
'user' => 1,
|
|
'organization' => 3,
|
|
'bank' => 3,
|
|
'post' => 4,
|
|
],
|
|
'search' => [
|
|
'type' => 'best_fields', // 'best_fields', 'most_fields', 'cross_fields', 'phrase', 'phrase_prefix'
|
|
'prefix_length' => 4, //characters at the beginning of the word that must match
|
|
'fragment_size' => 80, //The size of the highlighted fragment in characters.
|
|
'fragmenter' => 'span', // 'simple' or 'span'
|
|
'number_of_fragments' => 2, // The maximum number of fragments to return. If the number of fragments is set to 0, no fragments are returned. Instead, the entire field contents are highlighted and returned.
|
|
'pre-tags' => '<span class="font-semibold text-white leading-tight">', // HTML tags to wrap around highlighted text
|
|
'post-tags' => '</span>', // HTML tags to wrap around highlighted text
|
|
'order' => 'score', // 'score' or 'none', the order of the fragments
|
|
'max_results' => 50, // defines setSize property for maximum amount of search results. Setting a high number will consume a lot of cache memory!
|
|
],
|
|
'model_indices' => [ // Elasticsearch indices that will be searched (defined in Models and imported by Scout)
|
|
'posts_index',
|
|
'users_index',
|
|
'organizations_index',
|
|
'banks_index',
|
|
],
|
|
'suggestions' => 4, // max number of suggestions to show in search bar. Showing suggestions slows down the reactivity of the search bar!
|
|
'category_ids_posts' => [4,5,6,7,8,113], //Include these posts category_id's
|
|
'cache_results' => 5 // minutes (TTL) to store search results in cache memory. TTL is extended whenever a search result is opened.
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Search Optimization settings (Optional)
|
|
|--------------------------------------------------------------------------
|
|
| These settings work with the SearchOptimizationHelper class.
|
|
| Add this section to timebank-cc.php config if you want
|
|
| to use the advanced search optimization features.
|
|
*/
|
|
'search_optimization' => [
|
|
'enabled' => true,
|
|
'cache_ttl' => 3600, // 1 hour for category hierarchies
|
|
'analytics' => [
|
|
'enabled' => true,
|
|
'track_searches' => true,
|
|
'max_recent_searches' => 10,
|
|
'retention_hours' => 24,
|
|
'track_location_data' => true, // Track location-based search patterns
|
|
],
|
|
'boost_factors' => [
|
|
'verified_profiles' => 1.2,
|
|
'complete_profiles' => 1.1,
|
|
'recent_activity' => 1.05,
|
|
'exact_category_match' => 2.0, // Multiplier for exact category name matches
|
|
'fuzzy_category_match' => 1.0, // Multiplier for fuzzy category matches
|
|
],
|
|
'location_boosts' => [
|
|
'same_district' => 5.0, // Highest boost for same district
|
|
'same_city' => 3.0, // High boost for same city
|
|
'same_division' => 2.0, // Medium boost for same division/state
|
|
'same_country' => 1.5, // Base boost for same country
|
|
'different_country' => 1.0, // Neutral for different countries
|
|
'no_location' => 0.9, // Slight penalty for profiles without location
|
|
],
|
|
'performance' => [
|
|
'enable_query_caching' => true,
|
|
'cache_search_results' => true,
|
|
'optimize_highlights' => true,
|
|
'batch_process_results' => true,
|
|
'enable_location_caching' => true, // Cache location hierarchy lookups
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Payment settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'payment' => [
|
|
'amount_rule' => 'required|integer|min:1',
|
|
'description_rule' => 'required|string|min:3|max:500',
|
|
],
|
|
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Post settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'posts' => [
|
|
'postable_is_auth_user' => true, // Post editor profile that is stored. Set to true: Users, set to false: active profile models stored in session (users, organizations, banks, admins)
|
|
'site-content-writer' => 'Timebank.cc', // Writer name for general site content such as static pages. This name can be a non-exsisting user / organization
|
|
'title_rule' => 'required|string|min:3|max:150',
|
|
'title_max_input' => 150, // should match tile_rule
|
|
'slug_rule' => ['required', 'string', 'min:3', 'max:150', 'regex:/^[\pL\pM\pN-]+$/u'],
|
|
'excerpt_rule' => 'nullable|string|string|max:500',
|
|
'excerpt_max_input' => 500, // should match excerpt_rule
|
|
'content_rule' => 'nullable|string|max:1048576', // max 1 MB in bytes
|
|
'content_max_input' => 10000, // 10000 characters is equivalent of a main newspaper article / 10 min of reading time
|
|
'image_rule' => 'nullable|image|mimes:jpg,jpeg,png,gif,webp|max:12288', // max 12 MB - check also the max file size in the .htaccess file and php.ini!
|
|
'media_owner_rule' => 'nullable|string|max:150',
|
|
'media_caption_rule' => 'nullable|string|max:300',
|
|
'media_caption_max_input' => 300, // should match media_caption_rule
|
|
'meeting_venue_rule' => 'nullable|string|max:50',
|
|
'meeting_address_rule' => 'nullable|string|max:100',
|
|
'meeting_transaction_types' => [1,2,3,], // Possible transaction types: 1 = Work, 2 = Gift, 3 = Donation
|
|
|
|
'static' => [
|
|
'getting-started' => [
|
|
'limit' => 1, // Maximum number of posts to show in the static getting-started page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the getting-started page
|
|
],
|
|
'faq' => [
|
|
'limit' => null, // Maximum number of posts to show in the static FAQ page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the FAQ page
|
|
],
|
|
'organizations' => [
|
|
'limit' => null, // Maximum number of posts to show in the static organizations page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the organizations page
|
|
],
|
|
'principles' => [
|
|
'limit' => 1, // Maximum number of posts to show in the static principles page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the principles page
|
|
],
|
|
'events' => [
|
|
'limit' => 5, // Maximum number of posts to show in the static events page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the events page
|
|
],
|
|
'the-hague' => [
|
|
'limit' => 1, // Maximum number of posts to show in the static the-hague page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the the-hague page
|
|
],
|
|
'lekkernassuh' => [
|
|
'limit' => 1, // Maximum number of posts to show in the static lekkernassuh page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the lekkernassuh page
|
|
],
|
|
'amst-brus-lisb' => [
|
|
'limit' => 1, // Maximum number of posts to show in the static ams-bru-lis page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the ams-bru-lis page
|
|
],
|
|
'work-with-us' => [
|
|
'limit' => 1, // Maximum number of posts to show in the static work-with-us page
|
|
'hideAuthor' => false, // Hide the author of the static posts in the work-with-us page
|
|
],
|
|
'philosophy' => [
|
|
'limit' => 1, // Maximum number of posts to show in the static philosophy page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the philosophy page
|
|
],
|
|
'timebank-organization' => [
|
|
'limit' => null, // Maximum number of posts to show in the static timebank-organization page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the timebank-organization page
|
|
],
|
|
'history' => [
|
|
'limit' => null, // Maximum number of posts to show in the static history page
|
|
'hideAuthor' => false, // Hide the author of the static posts in the history page
|
|
],
|
|
'press-media' => [
|
|
'limit' => 10, // Maximum number of posts to show in the static press-media page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the press-media page
|
|
],
|
|
'research' => [
|
|
'limit' => null, // Maximum number of posts to show in the static research page
|
|
'hideAuthor' => false, // Hide the author of the static posts in the research page
|
|
],
|
|
'meet-the-team' => [
|
|
'limit' => 1, // Maximum number of posts to show in the static meet-the-team page
|
|
'hideAuthor' => false, // Hide the author of the static posts in the meet-the-team page
|
|
],
|
|
'messenger' => [
|
|
'limit' => 1, // Maximum number of posts to show in the static messenger page
|
|
'hideAuthor' => true, // Hide the author of the static posts in the messenger page
|
|
],
|
|
]
|
|
],
|
|
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Tags settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'tags' => [
|
|
'allow_tag_transations_for_non_admins' => false, // Set to true if all profile types can also add a translation when creating a new skill tag
|
|
'name_rule' => [
|
|
'required',
|
|
'string',
|
|
'min:3',
|
|
'max:80',
|
|
function ($attribute, $value, $fail) {
|
|
if (preg_match('/[!?@#\$*\_\+{}\[\]<>\/|=.,\\\\]/', $value)) {
|
|
$fail(__('The :attribute cannot contain special characters like !?@#$*_+{}[]<>/\|=,.'));
|
|
}
|
|
},
|
|
function ($attribute, $value, $fail) {
|
|
if (!preg_match('/\S+\s+\S+/', $value)) {
|
|
// If the input doesn't have at least 2 words, fail the validation for this field
|
|
$fail(__('The :attribute must be at least 2 words.'));
|
|
}
|
|
},
|
|
],
|
|
'exists_in_current_locale_rule' => [
|
|
function ($attribute, $value, $fail) {
|
|
$existsInCurrentLocale = Illuminate\Support\Facades\DB::table('taggable_tags')
|
|
->join('taggable_locales', 'taggable_tags.tag_id', '=', 'taggable_locales.taggable_tag_id')
|
|
->where('taggable_locales.locale', app()->getLocale())
|
|
->where(function ($query) use ($value) {
|
|
$query->where('taggable_tags.name', $value)
|
|
->orWhere('taggable_tags.normalized', $value);
|
|
})
|
|
->exists();
|
|
|
|
if ($existsInCurrentLocale) {
|
|
$fail(__('This :attribute name already exists.'));
|
|
}
|
|
},
|
|
],
|
|
'comment_rule' => 'string|max:500|nullable',
|
|
],
|
|
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Media Library settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'media_library' => [
|
|
'max_file_size' => 1024 * 1024 * 12, // 12 MB
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Custom Messenger settings
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
'messenger' => [
|
|
'default_unread_mail_delay' => 8, // In hours. After this default delay an email will be send to notify an unread chat message. Users / profiles can change this in their settings
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| WireChat Configuration
|
|
|--------------------------------------------------------------------------
|
|
| Configuration for the WireChat messaging system including disappearing
|
|
| messages, cleanup schedules, user permissions, and attachments.
|
|
*/
|
|
'wirechat' => [
|
|
'disappearing_messages' => [
|
|
// Allow users to mark messages as "kept" to prevent immediate deletion
|
|
'allow_users_to_keep' => true,
|
|
|
|
// Duration in DAYS before regular messages are deleted
|
|
'duration' => 120, // 120 days (4 months) - timebank_cc custom value
|
|
|
|
// Duration in DAYS before kept messages are also deleted
|
|
// Even "kept" messages are eventually cleaned up (prevents orphaned data)
|
|
'kept_messages_duration' => 720, // 720 days (24 months / 2 years)
|
|
|
|
// Laravel schedule frequency for cleanup job
|
|
// Options: 'everyMinute', 'everyFiveMinutes', 'everyTenMinutes', 'hourly'
|
|
'cleanup_schedule' => 'hourly',
|
|
],
|
|
|
|
'profile_deletion' => [
|
|
// When a profile is permanently deleted, release their kept messages
|
|
// This sets kept_at = null, allowing normal cleanup to process them
|
|
'release_kept_messages' => true,
|
|
],
|
|
|
|
'attachments' => [
|
|
'storage_folder' => 'attachments',
|
|
'storage_disk' => 'public',
|
|
'disk_visibility' => 'public', // Use 'private' to enforce temporary URLs
|
|
'max_uploads' => 5, // Maximum number of files that can be uploaded at once
|
|
// Media Upload Settings (images/videos)
|
|
'media_mimes' => ['png', 'jpg', 'jpeg', 'gif'], // Allowed media file types
|
|
'media_max_upload_size' => 12288, // Size in KB (12 MB)
|
|
// File Upload Settings (documents)
|
|
'file_mimes' => ['zip', 'rar', 'txt', 'pdf'], // Allowed document file types
|
|
'file_max_upload_size' => 12288, // Size in KB (12 MB)
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Reaction settings
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
'reactions' => [
|
|
'star' => [
|
|
'enabled' => true,
|
|
'only_with_interaction' => true, // Require interaction between profiles
|
|
'interaction' => 'hasTransactionsWith', // Method to check for interaction
|
|
'icon_file' => 'star.svg',
|
|
'display_name' => 'Star',
|
|
'description' => 'Give a star to recommend and show appreciation.', // Tooltip text
|
|
'disabled_reasons' => [
|
|
'cannot_react_own_profile' => 'You cannot give yourself a star.',
|
|
'no_interaction' => 'You first need to have an exchange with each other.',
|
|
],
|
|
],
|
|
'bookmark' => [
|
|
'enabled' => true,
|
|
'only_with_interaction' => false, // Anyone can bookmark
|
|
'interaction' => 'hasTransactionsWith', // Not used since only_with_interaction is false
|
|
'icon_file' => 'bookmark.svg',
|
|
'display_name' => 'Bookmark',
|
|
'description' => 'Save in your contact list.', // Tooltip text
|
|
'disabled_reasons' => [
|
|
'cannot_react_own_profile' => 'You cannot bookmark your own profile.',
|
|
'no_interaction' => 'You need an interaction to bookmark.',
|
|
],
|
|
],
|
|
'reserve' => [
|
|
'enabled' => true,
|
|
'only_with_interaction' => false, // Anyone can reserve
|
|
'interaction' => 'hasTransactionsWith', // Not used since only_with_interaction is false
|
|
'icon_file' => 'reserved.svg',
|
|
'display_name' => 'Reserve',
|
|
'description' => 'Puts you on the reservations lists.', // Tooltip text
|
|
'disabled_reasons' => [
|
|
'cannot_react_own_profile' => 'You cannot reserve right now.',
|
|
'no_interaction' => 'You need an interaction to reserve this.',
|
|
],
|
|
'count_public_threshold' => 3 // Threshold before nr of reservations is shown publicly
|
|
],
|
|
'like' => [
|
|
'enabled' => true,
|
|
'only_with_interaction' => false,
|
|
'interaction' => 'hasTransactionsWith', // WARNING: new interaction methods should always be tested on development server!
|
|
'icon_file' => 'heart-icon.svg',
|
|
'display_name' => 'Like',
|
|
'description' => 'Show appreciation.',
|
|
'disabled_reasons' => [
|
|
'cannot_react_own_profile' => 'You cannot like your own content.',
|
|
'no_interaction' => 'You need an interaction to like this.',
|
|
],
|
|
],
|
|
'vote' => [
|
|
'enabled' => false, // Disabled reaction type
|
|
'only_with_interaction' => false,
|
|
'interaction' => 'hasParticipatedWithExample', // WARNING: new interaction methods should always be tested on development server!
|
|
'icon_file' => 'hand-raised.svg',
|
|
'display_name' => 'Vote',
|
|
'description' => 'Cast a vote.',
|
|
'disabled_reasons' => [
|
|
'cannot_react_own_profile' => 'You cannot vote for yourself.',
|
|
'no_interaction' => 'You need to have participated to vote.',
|
|
],
|
|
],
|
|
'dislike' => [
|
|
'enabled' => false,
|
|
'only_with_interaction' => false,
|
|
'interaction' => 'hasCollaboratedWithExample', // WARNING: new interaction methods should always be tested on development server!
|
|
'icon_file' => 'thumbs-down.svg',
|
|
'display_name' => 'Dislike',
|
|
'description' => 'Show disapproval.',
|
|
'disabled_reasons' => [
|
|
'cannot_react_own_profile' => 'You cannot dislike your own content.',
|
|
'no_interaction' => 'You need an interaction to dislike this.',
|
|
],
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Online settings
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
'online' => [
|
|
'contact_list' => [
|
|
'dashboard' => [
|
|
'enabled' => true, // enable / disable online contact list on dashboard
|
|
'reaction_types_for_user' => ['Star', 'Bookmark'], // show in contact list if exists in array of reaction types
|
|
'reaction_types_for_organization' => ['Bookmark'], // show in contact list if exists in array of reaction types
|
|
'reaction_types_for_bank' => ['Star, Bookmark'], // show in contact list if exists in array of reaction types
|
|
],
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Mailing (Bulk Mail Newsletter) Configuration
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
'mailing' => [
|
|
'send_delay_seconds' => 5, // Delay between individual emails
|
|
'batch_size' => 10, // Process emails in batches
|
|
'max_retries' => 3, // Maximum retry attempts for failed emails
|
|
'retry_delay_minutes' => 15, // Base delay before first retry (exponential backoff applies)
|
|
'retry_multiplier' => 2, // Multiplier for exponential backoff (delay * multiplier^attempt)
|
|
'max_retry_delay_hours' => 24, // Maximum delay between retries (caps exponential backoff)
|
|
'abandon_after_hours' => 72, // Completely abandon email retries after this time
|
|
'use_fallback_locale' => false, // Whether to use fallback locale when recipient's preferred locale is unavailable
|
|
'fallback_locale' => 'en', // Fallback locale to use when recipient's preferred locale has no translations
|
|
'from_address' => [
|
|
'local_newsletter' => 'news@timebank.cc',
|
|
'general_newsletter' => 'news@timebank.cc',
|
|
'system_message' => 'system@timebank.cc'
|
|
],
|
|
'bounce_address' => env('MAIL_BOUNCE_ADDRESS', 'bounces@timebank.cc'),
|
|
'templates' => [
|
|
'wrapper' => 'emails.newsletter.wrapper',
|
|
'news_block' => 'emails.newsletter.blocks.news',
|
|
'article_block' => 'emails.newsletter.blocks.article',
|
|
'event_block' => 'emails.newsletter.blocks.event',
|
|
'image_block' => 'emails.newsletter.blocks.image'
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Bounce Handling Thresholds
|
|
|--------------------------------------------------------------------------
|
|
| Configure how many hard bounces are required before taking action.
|
|
| This provides a conservative approach to prevent false positives.
|
|
*/
|
|
'bounce_thresholds' => [
|
|
// Number of hard bounces before email is suppressed from future mailings
|
|
'suppression_threshold' => 1,
|
|
|
|
// Number of hard bounces before email_verified_at is set to null
|
|
'verification_reset_threshold' => 1,
|
|
|
|
// Time window in days to count bounces (prevents old bounces from accumulating)
|
|
'counting_window_days' => 365,
|
|
|
|
// Only count these bounce types toward thresholds
|
|
'counted_bounce_types' => ['hard'],
|
|
|
|
// Specific bounce reasons that count as definitive hard bounces
|
|
'definitive_hard_bounce_patterns' => [
|
|
'user unknown',
|
|
'no such user',
|
|
'mailbox unavailable',
|
|
'does not exist',
|
|
'invalid recipient',
|
|
'address rejected',
|
|
'5.1.1', // User unknown
|
|
'5.1.2', // Domain not found
|
|
'5.1.3', // Invalid address
|
|
'550', // Mailbox unavailable
|
|
'551', // User not local
|
|
],
|
|
|
|
// Automatic cleanup settings
|
|
'automatic_cleanup' => [
|
|
// Day of week for cleanup (0 = Sunday, 1 = Monday, etc.)
|
|
'day_of_week' => 1, // Monday
|
|
|
|
// Time to run cleanup (24-hour format)
|
|
'time' => '03:00',
|
|
|
|
// Number of days after which to delete soft bounces
|
|
'cleanup_days' => 90,
|
|
|
|
// Only cleanup these bounce types (hard bounces are kept for suppression)
|
|
'cleanup_bounce_types' => ['soft', 'unknown'],
|
|
],
|
|
]
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Footer Navigation Configuration
|
|
|--------------------------------------------------------------------------
|
|
| Configure footer sections and links for white-labeling.
|
|
| Each section can be reordered, hidden, or customized per platform.
|
|
| All titles should have translation keys.
|
|
*/
|
|
'footer' => [
|
|
'sections' => [
|
|
[
|
|
'title' => 'Who we are',
|
|
'order' => 1,
|
|
'visible' => true,
|
|
'links' => [
|
|
['route' => 'static-philosophy', 'title' => 'Our philosophy', 'order' => 1, 'visible' => true],
|
|
['route' => 'static-timebank-organization', 'title' => 'Timebank organization', 'order' => 2, 'visible' => true],
|
|
['route' => 'static-history', 'title' => 'History', 'order' => 3, 'visible' => true],
|
|
['route' => 'static-press-media', 'title' => 'Press and media', 'order' => 4, 'visible' => true],
|
|
['route' => 'static-research', 'title' => 'Economic and research', 'order' => 5, 'visible' => true],
|
|
],
|
|
],
|
|
[
|
|
'title' => 'Community',
|
|
'order' => 2,
|
|
'visible' => true,
|
|
'links' => [
|
|
['route' => 'static-events', 'title' => 'Events', 'order' => 1, 'visible' => true],
|
|
['route' => 'static-the-hague', 'title' => 'The Hague', 'order' => 2, 'visible' => true],
|
|
['route' => 'static-lekkernassuh', 'title' => 'Lekkernassûh', 'order' => 3, 'visible' => true],
|
|
['route' => 'static-amst-brus-lisb', 'title' => 'Amsterdam, Brussels, Lisbon', 'order' => 4, 'visible' => true],
|
|
['route' => 'static-work-w-us', 'title' => 'Work with us', 'order' => 5, 'visible' => true],
|
|
],
|
|
],
|
|
[
|
|
'title' => 'Help',
|
|
'order' => 3,
|
|
'visible' => true,
|
|
'links' => [
|
|
['route' => 'static-getting-started', 'title' => 'Getting started', 'order' => 1, 'visible' => true],
|
|
['route' => 'static-faq', 'title' => 'FAQ', 'order' => 2, 'visible' => true],
|
|
['route' => 'static-organizations', 'title' => 'Organizations', 'order' => 3, 'visible' => true],
|
|
['route' => 'static-principles', 'title' => 'messages.platform_principles', 'order' => 4, 'visible' => true],
|
|
['route' => 'static-privacy', 'title' => 'Privacy policy', 'order' => 5, 'visible' => true],
|
|
],
|
|
],
|
|
[
|
|
'title' => 'Contact us',
|
|
'order' => 4,
|
|
'visible' => true,
|
|
'links' => [
|
|
['route' => 'static-team', 'title' => 'Meet the team', 'order' => 1, 'visible' => true],
|
|
['route' => 'static-report-issue', 'title' => 'Report an issue', 'order' => 2, 'visible' => true],
|
|
// ['route' => 'static-report-error', 'title' => 'Report an issue', 'order' => 2, 'visible' => false],
|
|
['route' => 'static-messenger', 'title' => 'Chat messenger', 'order' => 3, 'visible' => true, 'auth_required' => true],
|
|
['url' => 'mailto:info@timebank.cc', 'title' => 'info@timebank.cc', 'order' => 4, 'visible' => true],
|
|
],
|
|
],
|
|
],
|
|
'tagline' => 'Your time is currency',
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Search Engine Indexing
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
'seo' => [
|
|
'allow_indexing_guest' => false, // Allow search engines to index guest pages
|
|
'allow_indexing_auth' => false, // Allow search engines to index authenticated pages
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Profile Session Timeouts
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Define the inactivity timeout in minutes for each profile type.
|
|
| After the specified timeout, the user's session will expire and they
|
|
| will be logged out automatically. This provides security by ensuring
|
|
| inactive sessions are terminated.
|
|
|
|
|
| The key should be the fully qualified class name of the model.
|
|
| A default value is used if the active profile type isn't found here.
|
|
|
|
|
| IMPORTANT: These timeouts OVERRIDE the SESSION_LIFETIME setting from .env
|
|
| They are enforced by ProfileSessionTimeout middleware.
|
|
|
|
|
| Security Best Practices:
|
|
| - User profiles: Short timeout (30-120 min) for regular accounts
|
|
| - Organizations: Medium timeout (30-60 min) for community profiles
|
|
| - Banks: Short timeout (15-30 min) for financial operations
|
|
| - Admins: Very short timeout (15-30 min) for privileged access
|
|
|
|
|
*/
|
|
'profile_timeouts' => [
|
|
App\Models\User::class => 120, // minutes
|
|
App\Models\Organization::class => 60,
|
|
App\Models\Bank::class => 30,
|
|
App\Models\Admin::class => 360, // TODO: change to 30 for production
|
|
],
|
|
'profile_timeout_default' => 120, // minutes. Fallback default if type not listed or no profile active
|
|
|
|
'profile_inactive' => [
|
|
'days_not_logged_in' => 365 * 2, // Profile marked as inactive after this many days without login
|
|
're-activate_at_login' => true, // Remove inactive_at record at login
|
|
'messenger_hidden' => true, // Not searchable in chat messenger
|
|
'profile_search_hidden' => true, // Profile page is hidden from main search bar for non-Admin and non-Banks
|
|
'profile_hidden' => true, // Profile page is hidden for non-Admin and non-Banks
|
|
'profile_labeled' => true, // Profile has inactive label
|
|
],
|
|
|
|
'profile_email_unverified' => [
|
|
'messenger_hidden' => true, // True means not searchable in chat messenger
|
|
'profile_search_hidden' => true, // Profile page is hidden from main search bar for non-Admin and non-Banks
|
|
'profile_hidden' => false, // Profile page is hidden for non-Admin and non-Banks
|
|
'profile_labeled' => true, // Profile has email unverified label
|
|
],
|
|
|
|
'profile_incomplete' => [
|
|
'messenger_hidden' => true, // True means not searchable in chat messenger
|
|
'profile_search_hidden' => true, // Profile page is hidden from main search bar for non-Admin and non-Banks
|
|
'profile_hidden' => false, // Profile page is hidden for non-Admin and non-Banks
|
|
'profile_labeled' => false, // Profile has incomplete label
|
|
'check_fields' => ['about', 'about_short', 'motivation', 'cyclos_skills'], // One these fields that must have data to be considered as a complete profile
|
|
'check_fields_min_total_length' => 100, // Minimum total length of all check_fields that must be filled in to be considered as a complete profile
|
|
'check_relations' => ['tags', 'languages', 'locations'], // One these relations that must be filled in to be considered as a complete profile
|
|
'show_warning_modal' => true, // Show profile incomplete warning modal on edit profile page
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Delete Profile Settings
|
|
|--------------------------------------------------------------------------
|
|
| Configure what happens to account balances when a profile is deleted.
|
|
|
|
|
| The logic follows this elseif structure:
|
|
| 1. If 'donate_balances_to_organization_account_specified' is true:
|
|
| User can select an organization to donate balance to
|
|
| 2. Else if 'transfer_balances_to_bank_client' is true:
|
|
| Transfer balances to a bank the profile was a client of
|
|
| 3. Else if 'transfer_balances_to_account_id' is set (not null):
|
|
| Transfer balances to this specific account id
|
|
| 4. Else if 'transfer_balances_to_debit_account' is true:
|
|
| Transfer balances to debit account (removes currency from circulation)
|
|
*/
|
|
'delete_profile' => [
|
|
// Grace period: Days to wait before permanent deletion (allows restoration)
|
|
'grace_period_days' => 1, // Profiles can be restored within this many days after deletion
|
|
|
|
// NOTE: These are days AFTER the profile is marked inactive (not days since last login)
|
|
// Total time = days_not_logged_in (350) + days_after_inactive
|
|
'days_after_inactive' => [
|
|
'warning_1' => 0, // First warning
|
|
'warning_2' => 30, // Second warning
|
|
'warning_final' => 60, // Final warning
|
|
'run_delete' => 90, // Delete profile
|
|
],
|
|
'account_balances' => [
|
|
// If accounts of deleted profile are not 0?
|
|
'donate_balances_to_organization_account_specified' => true, // Allow profile to donate all balances to an organization they specify
|
|
// elseif
|
|
'transfer_balances_to_bank_client' => false, // BANKCLIENTS ARE NOT USED YET - Transfer all balances to a (local) bank the profile was a bankClient of
|
|
// elseif
|
|
'transfer_balances_to_account_id' => null, // Or transfer balances to this specific account id. Set to null to disable setting
|
|
// else
|
|
'transfer_balances_to_debit_account' => true, // Set this to true to transfer balance to debit account (removes dead currency)
|
|
],
|
|
'log_trimming' => [
|
|
// Automatic log file trimming for inactive profile processing logs
|
|
'retention_days' => 30, // Keep log entries for this many days (default: 30)
|
|
'schedule_frequency' => 'monthly', // Laravel schedule frequency: daily, weekly, monthly (default: monthly)
|
|
'schedule_time' => '03:30', // Time to run log trimming (24-hour format, default: 03:30)
|
|
],
|
|
],
|
|
];
|