diff --git a/.env.example b/.env.example index 67c5a07e..945b10b7 100644 --- a/.env.example +++ b/.env.example @@ -51,4 +51,12 @@ MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" HELLOSIGN_API_KEY= +HELLOSIGN_API_KEY_HOOK= HELLOSIGN_CLIENT_ID= + +SHUFTI_CLIENT_ID= +SHUFTI_CLIENT_SECRET= +SITE_URL= +COINMARKETCAP_KEY= + +SEENA_API_KEY= diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..83d2aa52 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,16 @@ +## Contributing to Casper Association Member Portal + +### Please follow these guidelines if you want to contribute to this project + +1. Fork the project. +2. Create a new branch from master (e.g. features/my-new-feature or issue/123-my-bugfix) +3. Try to follow the same coding style with regards to spacing and line width, etc. Following PSR-4 will more than suffice. +4. Create a pull request. Please create PR to development branch so we can do proper testing and staging before merging with master branch. + +### Report bugs using Github issues + +You can report a bug by clicking on the issues tab and 'New Issue'. Describe the issue the best you can. This makes it easy to fork and create a branch named after the issue purposed for fixing it. + +Thank you for your interest in the project! + +For security related issues, please email thomas@ledgerleap.com \ No newline at end of file diff --git a/README.md b/README.md index ceb6ac0a..650b376a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,81 @@ -<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p> - <p align="center"> -<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a> -<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a> -<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a> -<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a> + <img src="https://caspermember.com/images/logo.png" width="400"> </p> +# Casper Association Member Portal + +The Casper Association's member portal. + +This is the backend repo of the portal. To see the frontend repo, visit https://github.com/ledgerleapllc/CasperAssociationPortal + +## Prerequisites + + - Apache/2.4.29+ (Ubuntu) + - PHP 7.4+ + - MySql Ver 14.14 Distrib 5.7.37 + - Laravel Framework 8.47.0 + +## Setup + +We generally would use the latest version of Ubuntu for testing installs. Example hosting server: AWS ec2 t2 medium with at least 10Gb SSD. + +```bash +sudo apt -y install apache2 +sudo a2enmod rewrite +sudo a2enmod headers +sudo a2enmod ssl +sudo apt -y install software-properties-common +sudo add-apt-repository ppa:ondrej/php +sudo apt-get update +sudo apt-get install -y php7.4 +sudo apt-get install -y php7.4-{bcmath,bz2,intl,gd,mbstring,mysql,zip,common,curl,xml} +php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" +sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer +php -r "unlink('composer-setup.php');" +``` + +Setup the repo according to our VHOST path. Note, the actual VHOST path in this case should be set to **/var/www/CasperAssociationPortalBackend/public** + +```bash +cd /var/www/ +git clone https://github.com/ledgerleapllc/CasperAssociationPortalBackend +cd CasperAssociationPortalBackend +``` + +Install packages and setup environment + +```bash +composer install +composer update +cp .env.example .env +``` + +After adjusting .env with your variables, run Artisan to finish setup + +```bash +php artisan key:generate +php artisan migrate +php artisan passport:install +php artisan config:clear +php artisan route:clear +php artisan cache:clear +(crontab -l 2>>/dev/null; echo "* * * * * cd /var/www/CasperAssociationPortalBackend && php artisan schedule:run >> /dev/null 2>&1") | crontab - +``` + +You may also have to authorize Laravel to write to the storage directory + +```bash +sudo chown -R www-data:www-data storage/ +``` + +Last, you need to setup roles and admins to start using the portal and see it work. Visit the URL of the backend with the path **/install**. This will install these things for you. You will find your admin credentials generated in the Laravel log file. You may want to disable this endpoint after the initial install to prevent this install endpoint from being used again if you are planning on deploying to a production environment in the future. This is easily done by switching ENV variable **INSTALL_PATH_ENABLED** to 0, or false. You may need to run the following command if Laravel caching is on. + +```bash +php artisan config:clear +``` + +<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p> + ## About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: diff --git a/app/Console/Commands/CheckBallot.php b/app/Console/Commands/CheckBallot.php new file mode 100644 index 00000000..639b1008 --- /dev/null +++ b/app/Console/Commands/CheckBallot.php @@ -0,0 +1,62 @@ +<?php + +namespace App\Console\Commands; + +use App\Models\Ballot; +use Carbon\Carbon; +use Illuminate\Console\Command; + +class CheckBallot extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'ballot:check'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'ballot check'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + $settings = getSettings(); + $quorumRate = $settings['quorum_rate_ballot'] ?? 50; + $now = Carbon::now('UTC'); + $ballots = Ballot::with(['vote'])->where('status', 'active')->where('time_end', '<=', $now)->get(); + foreach ($ballots as $ballot) { + $vote = $ballot->vote; + if ($vote->result_count == 0) { + $ballot->status = 'fail'; + $ballot->save(); + } else { + $quorum = $vote->for_value / $vote->result_count * 100; + if($quorum >= $quorumRate) { + $ballot->status = 'pass'; + } else { + $ballot->status = 'fail'; + } + $ballot->save(); + } + } + } +} diff --git a/app/Console/Commands/CheckNodeStatus.php b/app/Console/Commands/CheckNodeStatus.php new file mode 100644 index 00000000..5e5564b5 --- /dev/null +++ b/app/Console/Commands/CheckNodeStatus.php @@ -0,0 +1,198 @@ +<?php + +namespace App\Console\Commands; + +use App\Models\MonitoringCriteria; +use App\Models\User; + +use Carbon\Carbon; + +use Illuminate\Console\Command; +use Illuminate\Support\Facades\Log; + +class CheckNodeStatus extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'node-status:check'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Check node status'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + $uptime = MonitoringCriteria::where('type', 'uptime')->first(); + $uptimeProbationStart = $uptime->probation_start; + if ($uptime->given_to_correct_unit == 'Weeks') { + $uptimeTime = (float) $uptime->given_to_correct_value * 7 * 24; + } else if ($uptime->given_to_correct_unit == 'Days') { + $uptimeTime = (float) $uptime->given_to_correct_value * 24; + } else { + $uptimeTime = (float) $uptime->given_to_correct_value; + } + + $blockHeight = MonitoringCriteria::where('type', 'block-height')->first(); + $blockHeightProbationStart = (float) $blockHeight->probation_start; + if ($blockHeight->given_to_correct_unit == 'Weeks') { + $blockHeightTime = (float) $blockHeight->given_to_correct_value * 7 * 24; + } else if ($blockHeight->given_to_correct_unit == 'Days') { + $blockHeightTime = (float) $blockHeight->given_to_correct_value * 24; + } else { + $blockHeightTime = (float) $blockHeight->given_to_correct_value; + } + + $updateResponsiveness = MonitoringCriteria::where('type', 'update-responsiveness')->first(); + $updateResponsivenessProbationStart = (float) $updateResponsiveness->probation_start; + if ($updateResponsiveness->given_to_correct_unit == 'Weeks') { + $updateResponsivenessTime = (float)$updateResponsiveness->given_to_correct_value * 7 * 24; + } else if ($updateResponsiveness->given_to_correct_unit == 'Days') { + $updateResponsivenessTime = (float) $updateResponsiveness->given_to_correct_value * 24; + } else { + $updateResponsivenessTime = (float) $updateResponsiveness->given_to_correct_value; + } + + $now = Carbon::now('UTC'); + $users = User::where('role', 'member') + ->where('banned', 0) + ->with(['metric', 'nodeInfo', 'profile']) + ->get(); + + foreach ($users as $user) { + $user->node_status = 'Online'; + $user->save(); + + $nodeInfo = $user->nodeInfo ? $user->nodeInfo : $user->metric; + + if (!$nodeInfo || !$user->node_verified_at || !$user->letter_verified_at || !$user->signature_request_id) { + $user->node_status = null; + $user->save(); + } else if ($user->is_fail_node == 1) { + $user->node_status = 'Offline'; + $user->save(); + } else if ($nodeInfo) { + $nodeInfo->uptime = $nodeInfo->uptime ? $nodeInfo->uptime : 0; + $nodeInfo->block_height_average = $nodeInfo->block_height_average ? $nodeInfo->block_height_average : 0; + $nodeInfo->update_responsiveness = $nodeInfo->update_responsiveness ? $nodeInfo->update_responsiveness : 100; + if ( + $nodeInfo->uptime >= $uptimeProbationStart && + $nodeInfo->block_height_average >= $blockHeightProbationStart && + $nodeInfo->update_responsiveness >= $updateResponsivenessProbationStart + ) { + $user->node_status = 'Online'; + $user->save(); + + $nodeInfo->uptime_time_start = null; + $nodeInfo->uptime_time_end = null; + + $nodeInfo->block_height_average_time_start = null; + $nodeInfo->block_height_average_time_end = null; + + $nodeInfo->update_responsiveness_time_start = null; + $nodeInfo->update_responsiveness_time_end = null; + + $nodeInfo->save(); + } + } + + if ($user->profile && $user->profile->status == 'approved' && $nodeInfo) { + $user->profile->extra_status = null; + $user->profile->save(); + + if ($nodeInfo->uptime < $uptimeProbationStart) { + $user->profile->extra_status = 'On Probation'; + $nodeInfo->uptime_time_start = now(); + $nodeInfo->uptime_time_end = Carbon::now('UTC')->addHours($uptimeTime); + } + + if ($nodeInfo->block_height_average < $blockHeightProbationStart) { + $user->profile->extra_status = 'On Probation'; + $nodeInfo->block_height_average_time_start = now(); + $nodeInfo->block_height_average_time_end = Carbon::now('UTC')->addHours($blockHeightTime); + } + + if ($nodeInfo->update_responsiveness < $updateResponsivenessProbationStart) { + $user->profile->extra_status = 'On Probation'; + $nodeInfo->update_responsiveness_time_start = now(); + $nodeInfo->update_responsiveness_time_end = Carbon::now('UTC')->addHours($updateResponsivenessTime); + } + + $user->profile->save(); + $nodeInfo->save(); + + if ($user->profile->extra_status == 'On Probation') { + if ($nodeInfo->uptime_time_end <= $now && $nodeInfo->uptime < $uptimeProbationStart) { + $user->profile->extra_status = 'Suspended'; + } + if ($nodeInfo->block_height_average_time_end <= $now && $nodeInfo->block_height_average < $blockHeightProbationStart) { + $user->profile->extra_status = 'Suspended'; + } + if ($nodeInfo->update_responsiveness_time_end <= $now && $nodeInfo->update_responsiveness < $updateResponsivenessProbationStart) { + $user->profile->extra_status = 'Suspended'; + } + $user->profile->save(); + } + } + + /* + if ($user->node_status != 'Probation' && $user->node_status != 'Pulled') { + if ($nodeInfo->uptime < $uptimeProbationStart) { + $user->node_status = 'Probation'; + $nodeInfo->uptime_time_start = now(); + $nodeInfo->uptime_time_end = Carbon::now('UTC')->addHours($uptimeTime); + } + + if ($nodeInfo->block_height_average < $blockHeightProbationStart) { + $user->node_status = 'Probation'; + $nodeInfo->block_height_average_time_start = now(); + $nodeInfo->block_height_average_time_end = Carbon::now('UTC')->addHours($blockHeightTime); + } + + if ($nodeInfo->update_responsiveness < $updateResponsivenessProbationStart) { + $user->node_status = 'Probation'; + $nodeInfo->update_responsiveness_time_start = now(); + $nodeInfo->update_responsiveness_time_end = Carbon::now('UTC')->addHours($updateResponsivenessTime); + } + + $user->save(); + $nodeInfo->save(); + continue; + } + + if ($user->node_status == 'Probation') { + if ($nodeInfo->uptime_time_end <= $now && $nodeInfo->uptime < $uptimeProbationStart) { + $user->node_status = 'Pulled'; + } + if ($nodeInfo->block_height_average_time_end <= $now && $nodeInfo->block_height_average < $blockHeightProbationStart) { + $user->node_status = 'Pulled'; + } + if ($nodeInfo->update_responsiveness_time_end <= $now && $nodeInfo->update_responsiveness < $updateResponsivenessProbationStart) { + $user->node_status = 'Pulled'; + } + $user->save(); + } + */ + } + } +} diff --git a/app/Console/Commands/KycReport.php b/app/Console/Commands/KycReport.php new file mode 100644 index 00000000..fca59009 --- /dev/null +++ b/app/Console/Commands/KycReport.php @@ -0,0 +1,136 @@ +<?php + +namespace App\Console\Commands; + +use App\Models\Shuftipro; +use App\Models\ShuftiproTemp; +use App\Models\User; +use App\Mail\AdminAlert; +use App\Http\EmailerHelper; +use Carbon\Carbon; +use Illuminate\Console\Command; +use Illuminate\Support\Facades\Mail; + +class KycReport extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'kyc:report'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Send admins a report of members stuck on KYC'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + // first do shufti temp records + $now = Carbon::now(); + $yesterday = Carbon::now()->subHours(12); + $records_temp = ShuftiproTemp::where('status', 'pending') + ->where('created_at', '<=', $yesterday) + ->limit(10) + ->get(); + + $persons_stuck_in_pending = array(); + $known_reference_ids = array(); + + if($records_temp) { + foreach($records_temp as $record) { + $user_id = $record->user_id ?? 0; + $person = User::where('id', $user_id)->first(); + $persons_stuck_in_pending[] = array( + "name" => $person->first_name.' '.$person->last_name, + "email" => $person->email, + "shufti_reference_id" => $record->reference_id, + "shufti_timestamp" => $record->created_at + ); + + $known_reference_ids[] = $record->reference_id; + } + } + + // now do shuftipro denied + $records_pro = Shuftipro::where('status', 'denied') + ->where('reviewed', 0) + ->limit(10) + ->get(); + + $persons_stuck_denied = array(); + + if($records_pro) { + foreach($records_pro as $record) { + if(!in_array($record->reference_id, $known_reference_ids)) { + $user_id = $record->user_id ?? 0; + $person = User::where('id', $user_id)->first(); + $persons_stuck_denied[] = array( + "name" => $person->first_name.' '.$person->last_name, + "email" => $person->email, + "shufti_reference_id" => $record->reference_id, + "shufti_timestamp" => $record->created_at + ); + } + } + } + + // now make a text list from the matching records + $body = ""; + $index = 1; + + if($persons_stuck_in_pending) { + $body .= "Members pending for over 24 hours:<br>"; + + foreach($persons_stuck_in_pending as $p) { + $body .= '<b>'.(string)$index.'. </b>'; + $body .= $p['name'].', '.$p['email'].'<br>'; + $index += 1; + } + } + + $index = 1; + + if($persons_stuck_denied) { + if($persons_stuck_in_pending) { + $body .= "<br><br>"; + } + + $body .= "Members denied by Shufti. Not reviewed yet:<br>"; + + foreach($persons_stuck_denied as $p) { + $body .= '<b>'.(string)$index.'. </b>'; + $body .= $p['name'].', '.$p['email'].'<br>'; + $index += 1; + } + } + + // compose email to admins + if($persons_stuck_in_pending || $persons_stuck_denied) { + $emailerData = EmailerHelper::getEmailerData(); + $admins = $emailerData['admins'] ?? array(); + + if($admins) { + Mail::to($admins)->send(new AdminAlert('Casper Association portal KYC issues require attention', $body)); + } + } + } +} diff --git a/app/Console/Commands/NodeInfo.php b/app/Console/Commands/NodeInfo.php new file mode 100644 index 00000000..7f416aea --- /dev/null +++ b/app/Console/Commands/NodeInfo.php @@ -0,0 +1,210 @@ +<?php + +namespace App\Console\Commands; + +use App\Models\Metric; +use App\Models\Node; +use App\Models\NodeInfo as ModelsNodeInfo; +use App\Models\User; + +use App\Services\NodeHelper; + +use Illuminate\Console\Command; +use Illuminate\Support\Facades\DB; + +use Carbon\Carbon; + +class NodeInfo extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'node-info'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'get node info'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + $nodeHelper = new NodeHelper(); + $nodeHelper->updateStats(); + $this->updateNode(); + // $this->updateUptime(); + $this->updateRank(); + } + + public function updateNode() + { + $nodes = Node::whereNotNull('protocol_version')->get(); + $max_hight_block = $nodes->max('block_height'); + + $base_block = 10; + $versions = $nodes->pluck('protocol_version'); + $versions = $versions->toArray(); + usort($versions, 'version_compare'); + $highestVersion = (end($versions)); + $grouped = $nodes->groupBy('node_address'); + foreach ($grouped as $key => $values) { + $key = strtolower($key); + + $versionsNodes = $values->pluck('protocol_version'); + $versionsNodes = $versionsNodes->toArray(); + + usort($versionsNodes, 'version_compare'); + + $highestVersionNode = (end($versionsNodes)); + if (version_compare($highestVersion, $highestVersionNode, '<')) { + $user = User::where('public_address_node', $key)->first(); + if ($user) { + $user->is_fail_node = 1; + $user->node_status = 'Offline'; + $user->save(); + } + } + + $totalResponsiveness = 0; + $totalBlockHeight = 0; + + $nodeInfo = ModelsNodeInfo::where('node_address', $key)->first(); + if ($nodeInfo) { + $groupedVersion = $values->groupBy('protocol_version'); + $countVersion = count($groupedVersion); + $totalArray = []; + + foreach ($groupedVersion as $ver => $items) { + $countItem = count($items); + $totalVerResponsiveness = 0; + $totalVerBlockHeight = 0; + $totalVerPeer = 0; + + foreach ($items as $item) { + $totalVerResponsiveness += $item->update_responsiveness; + $totalVerBlockHeight += $item->block_height; + $totalVerPeer += $item->peers; + } + + $totalArray[$ver] = [ + 'totalVerResponsiveness' => round($totalVerResponsiveness / $countItem), + 'totalVerBlockHeight' => round($totalVerBlockHeight / $countItem), + 'totalVerPeer' => round($totalVerPeer / $countItem), + ]; + } + foreach ($totalArray as $total) { + $totalResponsiveness += $total['totalVerResponsiveness']; + $totalBlockHeight += $total['totalVerBlockHeight']; + } + $block_height = round($totalBlockHeight / $countVersion); + $block_height_average = ($base_block - ($max_hight_block - $block_height)) * 10; + if ($block_height_average <= 0) { + $block_height_average = 0; + } + $nodeInfo->block_height_average = $block_height_average; + $nodeInfo->save(); + } + } + } + + public function updateUptime() + { + $nodes = ModelsNodeInfo::get(); + $now = Carbon::now('UTC'); + $time = $now->subDays(14); + foreach ($nodes as $node) { + $avg_uptime = Node::where('node_address', strtolower($node->node_address)) + ->whereNotNull('uptime') + ->where('created_at', '>=', $time) + ->avg('uptime'); + $node->uptime = $avg_uptime * 100; + $node->save(); + } + } + + public function updateRank() + { + $slide_value_uptime = 20; + $slide_value_update_responsiveness = 20; + $slide_value_delegotors = 20; + $slide_value_stake_amount = 20; + $slide_delegation_rate = 20; + + $max_uptime = Node::max('uptime'); + $max_uptime = $max_uptime * 100; + $max_delegators = ModelsNodeInfo::max('delegators_count'); + $max_stake_amount = ModelsNodeInfo::max('total_staked_amount'); + + DB::table('users')->update(['rank' => null]); + + $users = User::with(['metric'])->where('role', 'member') + ->leftJoin('node_info', 'users.public_address_node', '=', 'node_info.node_address') + ->where('banned', 0) + ->whereNotNull('users.public_address_node') + ->select([ + 'users.*', + 'node_info.delegation_rate', + 'node_info.delegators_count', + 'node_info.total_staked_amount', + ]) + ->get(); + + foreach ($users as $user) { + $latest = Node::where('node_address', strtolower($user->public_address_node))->whereNotnull('protocol_version')->orderBy('created_at', 'desc')->first(); + if (!$latest) { + $latest = new Node(); + } + $delegation_rate = $user->delegation_rate ? $user->delegation_rate / 100 : 1; + if (!$user->metric && !$user->nodeInfo) { + $user->totalScore = null; + continue; + } + $latest_uptime_node = isset($latest->uptime) ? $latest->uptime * 100 : null; + $latest_update_responsiveness_node = $latest->update_responsiveness ?? null; + $metric = $user->metric; + if (!$metric) { + $metric = new Metric(); + } + $latest_uptime_metric = $metric->uptime ? $metric->uptime : null; + $latest_update_responsiveness_metric = $metric->update_responsiveness ? $metric->update_responsiveness : null; + + $latest_uptime = $latest_uptime_node ?? $latest_uptime_metric ?? 1; + $latest_update_responsiveness = $latest_update_responsiveness_node ?? $latest_update_responsiveness_metric ?? 1; + + $delegators_count = $user->delegators_count ? $user->nodeInfo->delegators_count : 0; + $total_staked_amount = $user->total_staked_amount ? $user->nodeInfo->total_staked_amount : 0; + + $uptime_score = ($slide_value_uptime * $latest_uptime) / 100; + $update_responsiveness_score = ($slide_value_update_responsiveness * $latest_update_responsiveness) / 100; + $dellegator_score = ($delegators_count / $max_delegators) * $slide_value_delegotors; + $satke_amount_score = ($total_staked_amount / $max_stake_amount) * $slide_value_stake_amount; + $delegation_rate_score = ($slide_delegation_rate * (1 - $delegation_rate)) / 100; + $totalScore = $uptime_score + $update_responsiveness_score + $dellegator_score + $satke_amount_score + $delegation_rate_score; + + $user->totalScore = $totalScore; + } + $users = $users->sortByDesc('totalScore')->values(); + foreach ($users as $key => $user) { + User::where('id', $user->id)->update(['rank' => $key + 1]); + } + } + +} diff --git a/app/Console/Commands/NotifCheck.php b/app/Console/Commands/NotifCheck.php new file mode 100644 index 00000000..4fe87980 --- /dev/null +++ b/app/Console/Commands/NotifCheck.php @@ -0,0 +1,59 @@ +<?php + +namespace App\Console\Commands; + +use App\Models\Notification; +use Carbon\Carbon; +use Illuminate\Console\Command; + +class NotifCheck extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'notif:check'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Command description'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + $now = Carbon::now()->format('Y-m-d'); + // check notification waiting + $waitingNotification = Notification::where('status', 'waiting')->where('setting', 1)->where('start_date', '<=', $now)->where('end_date', '>=', $now)->get(); + foreach ($waitingNotification as $data) { + $data->status = 'active'; + $data->visibility = 'visible'; + $data->save(); + } + + // check notification expired + $expiredNotification = Notification::where('end_date', '<', $now)->where('setting', 1)->get(); + foreach ($expiredNotification as $data) { + $data->status = 'expired'; + $data->visibility = 'hidden'; + $data->save(); + } + } +} diff --git a/app/Console/Commands/PerkCheck.php b/app/Console/Commands/PerkCheck.php new file mode 100644 index 00000000..6d4a47eb --- /dev/null +++ b/app/Console/Commands/PerkCheck.php @@ -0,0 +1,59 @@ +<?php + +namespace App\Console\Commands; + +use App\Models\Perk; +use Carbon\Carbon; +use Illuminate\Console\Command; + +class PerkCheck extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'perk:check'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Perk check command'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + $now = Carbon::now()->format('Y-m-d'); + // check perk waiting + $waitingPerks = Perk::where('status', 'waiting')->where('setting', 1)->where('start_date', '<=', $now)->where('end_date', '>=', $now)->get(); + foreach ($waitingPerks as $perk) { + $perk->status = 'active'; + $perk->visibility = 'visible'; + $perk->save(); + } + + // check perk expired + $expiredPerks = Perk::where('end_date', '<', $now)->where('setting', 1)->where('status', '!=', 'expired')->get(); + foreach ($expiredPerks as $perk) { + $perk->status = 'expired'; + $perk->visibility = 'hidden'; + $perk->save(); + } + } +} diff --git a/app/Console/Commands/RefreshAddress.php b/app/Console/Commands/RefreshAddress.php new file mode 100644 index 00000000..54b32cc5 --- /dev/null +++ b/app/Console/Commands/RefreshAddress.php @@ -0,0 +1,98 @@ +<?php + +namespace App\Console\Commands; + +use Illuminate\Console\Command; + +use App\Models\Node; +use App\Models\NodeInfo; +use App\Models\User; + +use App\Services\ChecksumValidator; + +class RefreshAddress extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'refresh:address'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Refresh Address'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + // Runs Every 5 Mins = 300 Seconds + $nodes = Node::whereNotNull('node_address') + ->where('refreshed', 0) + ->orderBy('created_at', 'asc') + ->offset(0) + ->limit(50) + ->get(); + if ($nodes) { + foreach ($nodes as $node) { + $address = strtolower($node->node_address); + // $newAddress = (new ChecksumValidator())->do($address); + $node->node_address = $address; + $node->refreshed = 1; + $node->save(); + } + } + + $nodeInfos = NodeInfo::whereNotNull('node_address') + ->where('refreshed', 0) + ->orderBy('created_at', 'asc') + ->offset(0) + ->limit(50) + ->get(); + + if ($nodeInfos) { + foreach ($nodeInfos as $nodeInfo) { + $address = strtolower($nodeInfo->node_address); + // $newAddress = (new ChecksumValidator())->do($address); + $nodeInfo->node_address = $address; + $nodeInfo->refreshed = 1; + $nodeInfo->save(); + } + } + + $users = User::whereNotNull('public_address_node') + ->where('refreshed', 0) + ->orderBy('created_at', 'asc') + ->offset(0) + ->limit(50) + ->get(); + if ($users) { + foreach ($users as $user) { + $address = strtolower($user->public_address_node); + // $newAddress = (new ChecksumValidator())->do($address); + $user->public_address_node = $address; + $user->refreshed = 1; + $user->save(); + } + } + + return 0; + } +} diff --git a/app/Console/Commands/ShuftiproCheck.php b/app/Console/Commands/ShuftiproCheck.php new file mode 100644 index 00000000..45f93e24 --- /dev/null +++ b/app/Console/Commands/ShuftiproCheck.php @@ -0,0 +1,58 @@ +<?php + +namespace App\Console\Commands; + +use Illuminate\Console\Command; +use App\Models\ShuftiproTemp; +use App\Services\ShuftiproCheck as ServicesShuftiproCheck; +use Illuminate\Support\Facades\Log; + +class ShuftiproCheck extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'shuftipro:check'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Check Shuftipro Response'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + // Runs Every 5 Mins ( 300 Seconds ) + // Process 20 per Run + $shuftiproCheck = new ServicesShuftiproCheck(); + $records = ShuftiproTemp::where('status', 'booked') + ->orderBy('id', 'asc') + ->get(); + + foreach ($records as $record) { + try { + $shuftiproCheck->handle($record); + } catch (\Exception $th) { + Log::error($th->getMessage()); + } + } + } +} diff --git a/app/Console/Commands/TokenPriceCheck.php b/app/Console/Commands/TokenPriceCheck.php new file mode 100644 index 00000000..d5232a8d --- /dev/null +++ b/app/Console/Commands/TokenPriceCheck.php @@ -0,0 +1,70 @@ +<?php + +namespace App\Console\Commands; + +use App\Console\Helper; +use Illuminate\Console\Command; +use App\Models\TokenPrice as TokenPriceModel; + +class TokenPriceCheck extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'token-price:check'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Check Token Price'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + $response = Helper::getTokenPrice(); + if ( + isset($response) && + isset($response['data']) && + isset($response['data']['quote']) && + isset($response['data']['quote']['USD']) && + isset($response['data']['quote']['USD']['price']) + ) { + $price = (float) $response['data']['quote']['USD']['price']; + $price = round($price, 4); + + if ($price > 0) { + $tokenPrice = new TokenPriceModel; + $tokenPrice->price = $price; + $tokenPrice->save(); + + $limit = 48 * 7; + $count = TokenPriceModel::where('id', '>', 0) + ->get() + ->count(); + if ($count > $limit) { + TokenPriceModel::orderBy('created_at', 'asc') + ->limit(1) + ->delete(); + } + } + } + } +} diff --git a/app/Console/Helper.php b/app/Console/Helper.php new file mode 100644 index 00000000..11f414c5 --- /dev/null +++ b/app/Console/Helper.php @@ -0,0 +1,213 @@ +<?php + +namespace App\Console; + +use App\Models\Metric; +use App\Models\MonitoringCriteria; +use App\Models\Node; +use App\Models\NodeInfo; +use App\Models\Profile; +use App\Models\Shuftipro; +use App\Models\User; + +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Http;use Illuminate\Pagination\Paginator; +use Illuminate\Support\Collection; +use Illuminate\Pagination\LengthAwarePaginator; + +class Helper +{ + /** + * Acquire casper account info standard on a single valdator view basis + * + * @param string $vid valid validator ID + * @return void automatically places retrieved account info standard data in DB by user's validator ID + */ + public static function getAccountInfoStandard($user) + { + $vid = $user->public_address_node ?? ''; + $uid = $user->id ?? 0; + $pseudonym = $user->pseudonym ?? null; + + $THIS_SEENA_API_KEY = getenv('SEENA_API_KEY'); + + $response = Http::withHeaders([ + 'Authorization' => "token $THIS_SEENA_API_KEY", + ])->withOptions([ + 'verify' => false, + ])->get('https://seena.ledgerleap.com/account-info-standard?validator_id='.$vid); + + try { + $json = json_decode($response); + } catch (Exception $e) { + $json = array(); + } + + $blockchain_name = $json->message->owner->name ?? null; + $blockchain_desc = $json->message->owner->description ?? null; + $blockchain_logo = $json->message->owner->branding->logo->png_256 ?? null; + + $profile = Profile::where('user_id', $uid)->first(); + + if($profile && $json) { + if($blockchain_name) { + $profile->blockchain_name = $blockchain_name; + } + + if($blockchain_desc) { + $profile->blockchain_desc = $blockchain_desc; + } + + if( + $blockchain_logo && + $user->avatar == null + ) { + $user->avatar = $blockchain_logo; + $user->save(); + } + + $profile->save(); + $shufti_profile = Shuftipro::where('user_id', $uid)->first(); + + if( + $shufti_profile && + $shufti_profile->status == 'approved' && + $pseudonym + ) { + $shuft_status = $shufti_profile->status; + $reference_id = $shufti_profile->reference_id; + $hash = md5($pseudonym.$reference_id.$shuft_status); + $profile->casper_association_kyc_hash = $hash; + $profile->save(); + } + } + } + + // Get Token Price + public static function getTokenPrice() + { + $url = 'https://pro-api.coinmarketcap.com/v1/tools/price-conversion'; + + $apiKey = config('services.token_price.api_key'); + $response = Http::withHeaders([ + 'X-CMC_PRO_API_KEY' => $apiKey + ])->get($url, [ + 'amount' => 1, + 'symbol' => 'CSPR', + 'convert' => 'USD' + ]); + + return $response->json(); + } + + public static function getNodeInfo($user) + { + $max_update_responsiveness = DB::select("SELECT max(update_responsiveness) as max_update_responsiveness FROM + ( + SELECT MAX(update_responsiveness) as update_responsiveness FROM metric + UNION + SELECT MAX(update_responsiveness) as update_responsiveness FROM node_info + ) AS results + ;"); + $max_update_responsiveness = $max_update_responsiveness[0]->max_update_responsiveness ?? 0; + + $max_peers = DB::select("SELECT max(peers) as max_peers FROM + ( + SELECT MAX(peers) as peers FROM metric + UNION + SELECT MAX(peers) as peers FROM node_info + ) AS results + ;"); + $max_peers = $max_peers[0]->max_peers ?? 0; + $max_block_height = Node::max('block_height'); + $max_uptime = DB::select("SELECT max(uptime) as max_uptime FROM + ( + SELECT MAX(uptime) as uptime FROM metric + UNION + SELECT MAX(uptime) as uptime FROM node_info + ) AS results + ;"); + $max_uptime = $max_uptime[0]->max_uptime ?? 0; + + $latest = Node::where('node_address', strtolower($user->public_address_node)) + ->whereNotnull('protocol_version') + ->orderBy('created_at', 'desc') + ->first(); + if (!$latest) { + $latest = new Node(); + } + $latest_block_height = $latest->block_height ?? null; + $latest_update_responsiveness = $latest->update_responsiveness ?? null; + $latest_peers = $latest->peers ?? null; + + $metric = Metric::where('user_id', $user->id)->first(); + if (!$metric) { + $metric = new Metric(); + } + $metric_uptime = $metric->uptime ?? null; + $metric_block_height = $metric->block_height_average ? ($max_block_height - $metric->block_height_average) : null; + $metric_update_responsiveness = $metric->update_responsiveness ?? null; + $metric_peers = $metric->peers ?? null; + + $nodeInfo = NodeInfo::where('node_address', strtolower($user->public_address_node))->first(); + if (!$nodeInfo) { + $nodeInfo = new NodeInfo(); + } + $latest_uptime = $nodeInfo->uptime ?? null; + $nodeInfo_uptime = $nodeInfo->uptime ?? null; + $nodeInfo_block_height = $nodeInfo->block_height ?? null; + $nodeInfo_peers = $nodeInfo->peers ?? null; + $nodeInfo_update_responsiveness = $nodeInfo->update_responsiveness ?? null; + + $metric->avg_uptime = $nodeInfo_uptime ?? $metric_uptime; + $metric->avg_block_height_average = $nodeInfo_block_height ?? $metric_block_height; + $metric->avg_update_responsiveness = $nodeInfo_update_responsiveness ?? $metric_update_responsiveness; + $metric->avg_peers = $nodeInfo_peers ?? $metric_peers; + + $metric->max_peers = $max_peers; + $metric->max_update_responsiveness = $max_update_responsiveness; + $metric->max_block_height_average = $max_block_height; + $metric->max_uptime = $max_uptime; + + $metric->peers = $latest_peers ?? $metric_peers; + $metric->update_responsiveness = $latest_update_responsiveness ?? $metric_update_responsiveness; + $metric->block_height_average = $latest_block_height ?? $metric_block_height; + $metric->uptime = $latest_uptime ? $latest_uptime : $metric_uptime; + + $monitoringCriteria = MonitoringCriteria::get(); + $nodeInfo = NodeInfo::where('node_address', strtolower($user->public_address_node))->first(); + $rank = $user->rank; + $delegators = 0; + $stake_amount = 0; + $self_staked_amount = 0; + $is_open_port = 0; + if ($nodeInfo) { + $delegators = $nodeInfo->delegators_count; + $stake_amount = $nodeInfo->total_staked_amount; + $self_staked_amount = $nodeInfo->self_staked_amount; + $is_open_port = $nodeInfo->is_open_port; + } + $mbs = NodeInfo::max('mbs'); + $metric->mbs = $mbs; + $metric->rank = $rank; + $metric->is_open_port = $is_open_port; + $metric->delegators = $delegators; + $metric->stake_amount = $stake_amount; + $metric->self_staked_amount = $self_staked_amount; + $metric['node_status'] = $user->node_status; + $metric['monitoring_criteria'] = $monitoringCriteria; + return $metric; + } + + /** + * The attributes that are mass assignable. + * + * @var array + */ + public static function paginate($items, $perPage = 5, $page = null, $options = []) + { + $page = $page ?: (Paginator::resolveCurrentPage() ?: 1); + $items = $items instanceof Collection ? $items : Collection::make($items); + return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options); + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 69914e99..d476379e 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -25,6 +25,40 @@ class Kernel extends ConsoleKernel protected function schedule(Schedule $schedule) { // $schedule->command('inspire')->hourly(); + $schedule->command('ballot:check') + ->everyMinute() + ->runInBackground(); + /* + $schedule->command('shuftipro:check') + ->everyFiveMinutes() + ->runInBackground(); + // ->withoutOverlapping(); + */ + $schedule->command('perk:check') + ->everyThirtyMinutes() + ->runInBackground(); + $schedule->command('notif:check') + ->dailyAt('00:01') + ->runInBackground(); + $schedule->command('node-status:check') + ->everyFiveMinutes() + ->runInBackground(); + $schedule->command('token-price:check') + ->everyThirtyMinutes() + ->runInBackground(); + $schedule->command('node-info') + ->everyThirtyMinutes() + ->runInBackground(); + $schedule->command('refresh:address') + ->everyFiveMinutes() + ->runInBackground(); + + /** + * Added by blockchainthomas. Cron for alerting admins of members stuck at KYC on a daily basis + */ + $schedule->command('kyc:report') + ->dailyAt('10:02') + ->runInBackground(); } /** @@ -34,7 +68,7 @@ protected function schedule(Schedule $schedule) */ protected function commands() { - $this->load(__DIR__.'/Commands'); + $this->load(__DIR__ . '/Commands'); require base_path('routes/console.php'); } diff --git a/app/Helpers/helper.php b/app/Helpers/helper.php index 9776153b..6929b212 100644 --- a/app/Helpers/helper.php +++ b/app/Helpers/helper.php @@ -1,5 +1,7 @@ <?php +use App\Models\Setting; + if (!function_exists('generateString')) { function generateString($strength = 16) @@ -50,3 +52,17 @@ function total_ram_cpu_usage() 'load' => $load, ]; } + +// Get Settings +function getSettings() +{ + // Get Settings + $settings = []; + $items = Setting::get(); + if ($items) { + foreach ($items as $item) { + $settings[$item->name] = $item->value; + } + } + return $settings; +} diff --git a/app/Http/Controllers/Api/V1/AdminController.php b/app/Http/Controllers/Api/V1/AdminController.php index 8cf9c1ec..6e688fed 100644 --- a/app/Http/Controllers/Api/V1/AdminController.php +++ b/app/Http/Controllers/Api/V1/AdminController.php @@ -2,23 +2,98 @@ namespace App\Http\Controllers\Api\V1; +use App\Console\Helper; + use App\Http\Controllers\Controller; +use App\Http\EmailerHelper; + +use App\Mail\AdminAlert; use App\Mail\ResetKYC; +use App\Mail\ResetPasswordMail; +use App\Mail\InvitationMail; + +use App\Models\NodeInfo; +use App\Models\Ballot; +use App\Models\BallotFile; +use App\Models\BallotFileView; +use App\Models\Discussion; +use App\Models\DiscussionComment; +use App\Models\DocumentFile; +use App\Models\EmailerAdmin; +use App\Models\EmailerTriggerAdmin; +use App\Models\EmailerTriggerUser; +use App\Models\IpHistory; +use App\Models\LockRules; +use App\Models\MembershipAgreementFile; +use App\Models\Metric; +use App\Models\MonitoringCriteria; +use App\Models\Node; use App\Models\OwnerNode; +use App\Models\Perk; +use App\Models\Permission; +use App\Models\Profile; +use App\Models\Setting; use App\Models\Shuftipro; use App\Models\ShuftiproTemp; +use App\Models\TokenPrice; use App\Models\User; +use App\Models\VerifyUser; +use App\Models\Vote; +use App\Models\VoteResult; + use Illuminate\Http\Request; use Illuminate\Http\Response; + +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Mail; +use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Facades\Http; +use Illuminate\Support\Str; + +use Carbon\Carbon; + +use Aws\S3\S3Client; class AdminController extends Controller { public function getUsers(Request $request) { - $limit = $request->limit ?? 15; - $users = User::where('role', 'member')->orderBy('created_at', 'ASC')->paginate($limit); + $limit = $request->limit ?? 50; + $sort_key = $request->sort_key ?? ''; + $sort_direction = $request->sort_direction ?? ''; + if (!$sort_key) $sort_key = 'created_at'; + if (!$sort_direction) $sort_direction = 'desc'; + $users = User::where('role', 'member') + ->with(['profile']) + ->leftJoin('node_info', 'users.public_address_node', '=', 'node_info.node_address') + ->select([ + 'users.*', + 'node_info.delegation_rate', + 'node_info.delegators_count', + 'node_info.self_staked_amount', + 'node_info.total_staked_amount', + ]) + ->get(); + foreach ($users as $user) { + $status = 'Not Verified'; + if ($user->profile && $user->profile->status == 'approved') { + $status = 'Verified'; + if ($user->profile->extra_status) { + $status = $user->profile->extra_status; + } + } + $user->membership_status = $status; + } + if ($sort_direction == 'desc') { + $users = $users->sortByDesc($sort_key)->values(); + } else { + $users = $users->sortBy($sort_key)->values(); + } + $users = Helper::paginate($users, $limit, $request->page); + $users = $users->toArray(); + $users['data'] = (collect($users['data'])->values()); return $this->successResponse($users); } @@ -28,18 +103,117 @@ public function getUserDetail($id) if (!$user || $user->role == 'admin') { return $this->errorResponse(__('api.error.not_found'), Response::HTTP_NOT_FOUND); } - $response = $user->load(['profile', 'shuftipro','shuftiproTemp']); - return $this->successResponse($response); + $user = $user->load(['profile', 'shuftipro', 'shuftiproTemp']); + + $status = 'Not Verified'; + if ($user->profile && $user->profile->status == 'approved') { + $status = 'Verified'; + if ($user->profile->extra_status) { + $status = $user->profile->extra_status; + } + } + $user->membership_status = $status; + $user->metric = Helper::getNodeInfo($user); + return $this->successResponse($user); } - public function infoDashboard() + public function infoDashboard(Request $request) { + $timeframe_perk = $request->timeframe_perk ?? 'last_7days'; + $timeframe_comments = $request->timeframe_comments ?? 'last_7days'; + $timeframe_discussions = $request->timeframe_discussions ?? 'last_7days'; + // last_24hs, last_7days, last_30days, last_year + if ($timeframe_perk == 'last_24hs') { + $timeframe_perk = Carbon::now('UTC')->subHours(24); + } else if ($timeframe_perk == 'last_30days') { + $timeframe_perk = Carbon::now('UTC')->subDays(30); + } else if ($timeframe_perk == 'last_year') { + $timeframe_perk = Carbon::now('UTC')->subYear(); + } else { + $timeframe_perk = Carbon::now('UTC')->subDays(7); + } + + if ($timeframe_comments == 'last_24hs') { + $timeframe_comments = Carbon::now('UTC')->subHours(24); + } else if ($timeframe_comments == 'last_30days') { + $timeframe_comments = Carbon::now('UTC')->subDays(30); + } else if ($timeframe_comments == 'last_year') { + $timeframe_comments = Carbon::now('UTC')->subYear(); + } else { + $timeframe_comments = Carbon::now('UTC')->subDays(7); + } + + if ($timeframe_discussions == 'last_24hs') { + $timeframe_discussions = Carbon::now('UTC')->subHours(24); + } else if ($timeframe_discussions == 'last_30days') { + $timeframe_discussions = Carbon::now('UTC')->subDays(30); + } else if ($timeframe_discussions == 'last_year') { + $timeframe_discussions = Carbon::now('UTC')->subYear(); + } else { + $timeframe_discussions = Carbon::now('UTC')->subDays(7); + } + $totalUser = User::where('role', 'member')->count(); - $toTalStake = 0; - $totalDelagateer = 0; + $toTalStake = NodeInfo::sum('total_staked_amount'); + $totalDelagateer = NodeInfo::sum('delegators_count'); + $totalNewUserReady = User::where('banned', 0) + ->where('role', 'member') + ->where(function ($q) { + $q->where('users.node_verified_at', null) + ->orWhere('users.letter_verified_at', null) + ->orWhere('users.signature_request_id', null); + })->count(); + + $totalUserVerification = User::where('users.role', 'member') + ->where('banned', 0) + ->join('profile', function ($query) { + $query->on('profile.user_id', '=', 'users.id') + ->where('profile.status', 'pending'); + }) + ->join('shuftipro', 'shuftipro.user_id', '=', 'users.id') + ->count(); + $totalFailNode = User::where('banned', 0)->whereNotNull('public_address_node')->where('is_fail_node', 1)->count(); + + $totalPerksActive = Perk::where('status', 'active')->where('created_at', '>=', $timeframe_perk)->count(); + $totalPerksViews = Perk::where('status', 'active')->where('created_at', '>=', $timeframe_perk)->sum('total_views'); + + $totalNewComments = DiscussionComment::where('created_at', '>=', $timeframe_comments)->count(); + $totalNewDiscussions = Discussion::where('created_at', '>=', $timeframe_discussions)->count(); + + $uptime_nodes = NodeInfo::whereNotNull('uptime')->pluck('uptime'); + $uptime_metrics = Metric::whereNotNull('uptime')->pluck('uptime'); + + $blocks_hight_nodes = NodeInfo::whereNotNull('block_height_average')->pluck('block_height_average'); + $blocks_hight_metrics = Metric::whereNotNull('block_height_average')->pluck('block_height_average'); + $total_blocks_hight_metrics = 0; + $base_block = 10; + foreach ($blocks_hight_metrics as $value) { + $avg = ($base_block - $value) * 10; + if ($avg > 0) { + $total_blocks_hight_metrics += $avg; + } + } + + $responsiveness_nodes = NodeInfo::whereNotNull('update_responsiveness')->pluck('update_responsiveness'); + $responsiveness_metrics = Metric::whereNotNull('update_responsiveness')->pluck('update_responsiveness'); + + $countUptime = count($uptime_nodes) + count($uptime_metrics) > 0 ? count($uptime_nodes) + count($uptime_metrics) : 1; + $count_responsiveness_nodes = count($responsiveness_nodes) + count($responsiveness_metrics); + $count_responsiveness_nodes = $count_responsiveness_nodes > 0 ? $count_responsiveness_nodes : 1; + $count_blocks_hight = (count($blocks_hight_nodes) + count($blocks_hight_metrics)) > 0 ? (count($blocks_hight_nodes) + count($blocks_hight_metrics)) : 1; $response['totalUser'] = $totalUser; - $response['toTalStake'] = $toTalStake; - $response['totalDelagateer'] = $totalDelagateer; + $response['totalStake'] = $toTalStake; + $response['totalDelegators'] = $totalDelagateer; + $response['totalNewUserReady'] = $totalNewUserReady; + $response['totalUserVerification'] = $totalUserVerification; + $response['totalFailNode'] = $totalFailNode; + $response['totalPerksActive'] = $totalPerksActive; + $response['totalPerksViews'] = $totalPerksViews; + $response['totalNewComments'] = $totalNewComments; + $response['totalNewDiscussions'] = $totalNewDiscussions; + $response['avgUptime'] = ($uptime_nodes->sum() + $uptime_metrics->sum()) / $countUptime; + $response['avgBlockHeightAverage'] = ($blocks_hight_nodes->sum() + $total_blocks_hight_metrics) / $count_blocks_hight; + $response['avgUpdateResponsiveness'] = ($responsiveness_nodes->sum() + $responsiveness_metrics->sum()) / $count_responsiveness_nodes; return $this->successResponse($response); } @@ -53,52 +227,672 @@ public function getKYC($id) return $this->successResponse($response); } - // Approve KYC - public function approveKYC($id, Request $request) + // get intake + public function getIntakes(Request $request) + { + $limit = $request->limit ?? 50; + $search = $request->search ?? ''; + $users = User::select([ + 'id', 'email', 'node_verified_at', 'letter_verified_at', 'signature_request_id', 'created_at', + 'first_name', 'last_name', 'letter_file', 'letter_rejected_at' + ]) + ->where('banned', 0) + ->where('role', 'member') + ->where(function ($q) { + $q->where('users.node_verified_at', null) + ->orWhere('users.letter_verified_at', null) + ->orWhere('users.signature_request_id', null); + }) + ->where(function ($query) use ($search) { + if ($search) { + $query->where('users.email', 'like', '%' . $search . '%'); + } + }) + ->orderBy('users.id', 'desc') + ->paginate($limit); + + return $this->successResponse($users); + } + + public function submitBallot(Request $request) + { + try { + DB::beginTransaction(); + $user = auth()->user(); + // Validator + $validator = Validator::make($request->all(), [ + 'title' => 'required', + 'description' => 'required', + // 'time' => 'required', + // 'time_unit' => 'required|in:minutes,hours,days', + 'files' => 'array', + 'files.*' => 'file|max:100000|mimes:pdf,docx,doc,txt,rtf', + 'start_date' => 'required', + 'start_time' => 'required', + 'end_date' => 'required', + 'end_time' => 'required', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $time = $request->time; + $timeUnit = $request->time_unit; + $mins = 0; + if ($timeUnit == 'minutes') { + $mins = $time; + } else if ($timeUnit == 'hours') { + $mins = $time * 60; + } else if ($timeUnit == 'days') { + $mins = $time * 60 * 24; + } + $start = Carbon::createFromFormat("Y-m-d H:i:s", Carbon::now('UTC'), "UTC"); + $now = Carbon::now('UTC'); + $timeEnd = $start->addMinutes($mins); + + $endTime = $request->end_date . ' ' . $request->end_time; + $endTimeCarbon = Carbon::createFromFormat('Y-m-d H:i:s', $endTime, 'EST'); + $endTimeCarbon->setTimezone('UTC'); + + $ballot = new Ballot(); + $ballot->user_id = $user->id; + $ballot->title = $request->title; + $ballot->description = $request->description; + // $ballot->time = $time; + // $ballot->time_unit = $timeUnit; + // $ballot->time_end = $timeEnd; + $ballot->time_end = $endTimeCarbon; + $ballot->start_date = $request->start_date; + $ballot->start_time = $request->start_time; + $ballot->end_date = $request->end_date; + $ballot->end_time = $request->end_time; + $ballot->status = 'active'; + $ballot->created_at = $now; + $ballot->save(); + $vote = new Vote(); + $vote->ballot_id = $ballot->id; + $vote->save(); + if ($request->hasFile('files')) { + $files = $request->file('files'); + foreach ($files as $file) { + $name = $file->getClientOriginalName(); + $extension = $file->getClientOriginalExtension(); + $filenamehash = md5(Str::random(10) . '_' . (string)time()); + $fileNameToStore = $filenamehash . '.' . $extension; + + // S3 file upload + $S3 = new S3Client([ + 'version' => 'latest', + 'region' => getenv('AWS_DEFAULT_REGION'), + 'credentials' => [ + 'key' => getenv('AWS_ACCESS_KEY_ID'), + 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), + ], + ]); + + $s3result = $S3->putObject([ + 'Bucket' => getenv('AWS_BUCKET'), + 'Key' => 'perks/' . $fileNameToStore, + 'SourceFile' => $file + ]); + + // $ObjectURL = 'https://'.getenv('AWS_BUCKET') . '.s3.amazonaws.com/perks/'.$fileNameToStore; + $ObjectURL = $s3result['ObjectURL'] ?? getenv('SITE_URL') . '/not-found'; + $ballotFile = new BallotFile(); + $ballotFile->ballot_id = $ballot->id; + $ballotFile->name = $name; + $ballotFile->path = $ObjectURL; + $ballotFile->url = $ObjectURL; + $ballotFile->save(); + } + } + + DB::commit(); + return $this->metaSuccess(); + } catch (\Exception $ex) { + DB::rollBack(); + return $this->errorResponse('Submit ballot fail', Response::HTTP_BAD_REQUEST, $ex->getMessage()); + } + } + + public function editBallot($id, Request $request) + { + try { + DB::beginTransaction(); + // Validator + $validator = Validator::make($request->all(), [ + 'title' => 'nullable', + 'description' => 'nullable', + // 'time' => 'nullable', + // 'time_unit' => 'nullable|in:minutes,hours,days', + 'files' => 'array', + 'files.*' => 'file|max:100000|mimes:pdf,docx,doc,txt,rtf', + 'file_ids_remove' => 'array', + 'start_date' => 'required', + 'start_time' => 'required', + 'end_date' => 'required', + 'end_time' => 'required', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + $time = $request->time; + $timeUnit = $request->time_unit; + $ballot = Ballot::where('id', $id)->first(); + if (!$ballot) { + return $this->errorResponse('Not found ballot', Response::HTTP_BAD_REQUEST); + } + if ($request->title) $ballot->title = $request->title; + if ($request->description) $ballot->description = $request->description; + + $now = Carbon::now('UTC'); + $ballot->created_at = $now; + $ballot->time_end = $request->end_date . ' ' . $request->end_time; + $ballot->start_date = $request->start_date; + $ballot->start_time = $request->start_time; + $ballot->end_date = $request->end_date; + $ballot->end_time = $request->end_time; + + /* + if($time && $timeUnit && ($time != $ballot->time || $timeUnit != $ballot->time_unit)) { + $mins = 0; + if ($timeUnit == 'minutes') { + $mins = $time; + } else if ($timeUnit == 'hours') { + $mins = $time * 60; + } else if ($timeUnit == 'days') { + $mins = $time * 60 * 24; + } + $start = Carbon::createFromFormat("Y-m-d H:i:s", Carbon::now('UTC'), "UTC"); + $now = Carbon::now('UTC'); + $timeEnd = $start->addMinutes($mins); + $ballot->time = $time; + $ballot->time_unit = $timeUnit; + $ballot->created_at = $now; + $ballot->time_end = $timeEnd; + } + */ + + $ballot->save(); + if ($request->hasFile('files')) { + $files = $request->file('files'); + foreach ($files as $file) { + $name = $file->getClientOriginalName(); + $extension = $file->getClientOriginalExtension(); + $filenamehash = md5(Str::random(10) . '_' . (string)time()); + $fileNameToStore = $filenamehash . '.' . $extension; + + // S3 file upload + $S3 = new S3Client([ + 'version' => 'latest', + 'region' => getenv('AWS_DEFAULT_REGION'), + 'credentials' => [ + 'key' => getenv('AWS_ACCESS_KEY_ID'), + 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), + ], + ]); + + $s3result = $S3->putObject([ + 'Bucket' => getenv('AWS_BUCKET'), + 'Key' => 'perks/'.$fileNameToStore, + 'SourceFile' => $file + ]); + + // $ObjectURL = 'https://'.getenv('AWS_BUCKET').'.s3.amazonaws.com/perks/'.$fileNameToStore; + $ObjectURL = $s3result['ObjectURL'] ?? getenv('SITE_URL').'/not-found'; + $ballotFile = new BallotFile(); + $ballotFile->ballot_id = $ballot->id; + $ballotFile->name = $name; + $ballotFile->path = $ObjectURL; + $ballotFile->url = $ObjectURL; + $ballotFile->save(); + } + } + if ($request->file_ids_remove) { + foreach($request->file_ids_remove as $file_id) { + BallotFile::where('id', $file_id)->where('ballot_id', $id)->delete(); + } + } + DB::commit(); + return $this->metaSuccess(); + } catch (\Exception $ex) { + DB::rollBack(); + return $this->errorResponse('Submit ballot fail', Response::HTTP_BAD_REQUEST, $ex->getMessage()); + } + } + + public function getBallots(Request $request) + { + $limit = $request->limit ?? 50; + $status = $request->status; + $sort_key = $request->sort_key ?? ''; + $sort_direction = $request->sort_direction ?? ''; + if (!$sort_key) $sort_key = 'ballot.id'; + if (!$sort_direction) $sort_direction = 'desc'; + + $now = Carbon::now('EST'); + $startDate = $now->format('Y-m-d'); + $startTime = $now->format('H:i:s'); + + if ($status == 'active') { + $ballots = Ballot::with(['user', 'vote']) + ->where('ballot.status', 'active') + ->where(function ($query) use ($startDate, $startTime) { + $query->where('start_date', '<', $startDate) + ->orWhere(function ($query) use ($startDate, $startTime) { + $query->where('start_date', $startDate) + ->where('start_time', '<=', $startTime); + }); + }) + ->orderBy($sort_key, $sort_direction) + ->paginate($limit); + } else if ($status && $status == 'scheduled') { + $ballots = Ballot::with(['user', 'vote']) + ->where('ballot.status', 'active') + ->where(function ($query) use ($startDate, $startTime) { + $query->where('start_date', '>', $startDate) + ->orWhere(function ($query) use ($startDate, $startTime) { + $query->where('start_date', $startDate) + ->where('start_time', '>', $startTime); + }); + }) + ->orderBy($sort_key, $sort_direction) + ->paginate($limit); + } else if ($status && $status != 'active' && $status != 'scheduled') { + $ballots = Ballot::with(['user', 'vote']) + ->where('ballot.status', '!=', 'active') + ->orderBy($sort_key, $sort_direction) + ->paginate($limit); + } else { + $ballots = Ballot::with(['user', 'vote'])->orderBy($sort_key, $sort_direction)->paginate($limit); + } + return $this->successResponse($ballots); + } + + public function getDetailBallot($id) + { + $ballot = Ballot::with(['user', 'vote', 'files'])->where('id', $id)->first(); + if (!$ballot) { + return $this->errorResponse('Not found ballot', Response::HTTP_BAD_REQUEST); + } + return $this->successResponse($ballot); + } + + public function cancelBallot($id) + { + $ballot = Ballot::where('id', $id)->first(); + if (!$ballot || $ballot->status != 'active') { + return $this->errorResponse('Cannot cancle ballot', Response::HTTP_BAD_REQUEST); + } + $ballot->time_end = now(); + $ballot->status = 'cancelled'; + $ballot->save(); + return $this->metaSuccess(); + } + + public function getBallotVotes($id, Request $request) + { + $limit = $request->limit ?? 50; + $data = VoteResult::where('ballot_id', '=', $id)->with(['user', 'user.profile'])->orderBy('created_at', 'ASC')->paginate($limit); + + return $this->successResponse($data); + } + + public function getViewFileBallot(Request $request, $fileId) + { + $limit = $request->limit ?? 50; + $data = BallotFileView::where('ballot_file_id', '=', $fileId)->with(['user', 'user.profile'])->orderBy('created_at', 'ASC')->paginate($limit); + return $this->successResponse($data); + } + + // Get Global Settings + public function getGlobalSettings() + { + $items = Setting::get(); + $settings = []; + if ($items) { + foreach ($items as $item) { + $settings[$item->name] = $item->value; + } + } + + return $this->successResponse($settings); + } + + // Update Global Settings + public function updateGlobalSettings(Request $request) + { + $validator = Validator::make($request->all(), [ + 'quorum_rate_ballot' => 'required', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + $items = [ + 'quorum_rate_ballot' => $request->quorum_rate_ballot, + ]; + foreach ($items as $name => $value) { + $setting = Setting::where('name', $name)->first(); + if ($setting) { + $setting->value = $value; + $setting->save(); + } else { + $setting = new Setting(); + $setting->value = $value; + $setting->save(); + } + } + + return $this->metaSuccess(); + } + + public function getSubAdmins(Request $request) + { + $limit = $request->limit ?? 50; + $admins = User::with(['permissions'])->where(['role' => 'sub-admin']) + ->orderBy('created_at', 'DESC') + ->paginate($limit); + + return $this->successResponse($admins); + } + + public function inviteSubAdmin(Request $request) + { + $validator = Validator::make($request->all(), [ + 'email' => 'required|email', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $isExist = User::where(['email' => $request->email])->count() > 0; + if ($isExist) { + return $this->errorResponse('This email has already been used to invite another admin.', Response::HTTP_BAD_REQUEST); + } + + $code = Str::random(6); + // $url = $request->header('origin') ?? $request->root(); + $url = getenv('SITE_URL'); + $inviteUrl = $url . '/register-sub-admin?code=' . $code . '&email=' . urlencode($request->email); + + VerifyUser::where('email', $request->email)->where('type', VerifyUser::TYPE_INVITE_ADMIN)->delete(); + + $verify = new VerifyUser(); + $verify->email = $request->email; + $verify->type = VerifyUser::TYPE_INVITE_ADMIN; + $verify->code = $code; + $verify->created_at = now(); + $verify->save(); + $admin = User::create([ + 'first_name' => 'faker', + 'last_name' => 'faker', + 'email' => $request->email, + 'password' => '', + 'type' => '', + 'member_status' => 'invited', + 'role' => 'sub-admin' + ]); + + $data = [ + ['name' => 'intake', 'is_permission' => 0, 'user_id' => $admin->id], + ['name' => 'users', 'is_permission' => 0, 'user_id' => $admin->id], + ['name' => 'ballots', 'is_permission' => 0, 'user_id' => $admin->id], + ['name' => 'perks', 'is_permission' => 0, 'user_id' => $admin->id], + ['name' => 'teams', 'is_permission' => 0, 'user_id' => $admin->id], + ]; + + Permission::insert($data); + Mail::to($request->email)->send(new InvitationMail($inviteUrl)); + + return $this->successResponse($admin); + } + + public function changeSubAdminPermissions(Request $request, $id) + { + $validator = Validator::make($request->all(), [ + 'intake' => 'nullable|in:0,1', + 'users' => 'nullable|in:0,1', + 'ballots' => 'nullable|in:0,1', + 'perks' => 'nullable|in:0,1', + 'teams' => 'nullable|in:0,1', + ]); + + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + $admin = User::find($id); + if ($admin == null || $admin->role != 'sub-admin') { + return $this->errorResponse('There is no admin user with this email', Response::HTTP_BAD_REQUEST); + } + if (isset($request->intake)) { + $permisstion = Permission::where('user_id', $id)->where('name', 'intake')->first(); + if ($permisstion) { + $permisstion->is_permission = $request->intake; + $permisstion->save(); + } + } + if (isset($request->users)) { + $permisstion = Permission::where('user_id', $id)->where('name', 'users')->first(); + if ($permisstion) { + $permisstion->is_permission = $request->users; + $permisstion->save(); + } + } + + if (isset($request->ballots)) { + $permisstion = Permission::where('user_id', $id)->where('name', 'ballots')->first(); + if ($permisstion) { + $permisstion->is_permission = $request->ballots; + $permisstion->save(); + } + } + + if (isset($request->perks)) { + $permisstion = Permission::where('user_id', $id)->where('name', 'perks')->first(); + if ($permisstion) { + $permisstion->is_permission = $request->perks; + $permisstion->save(); + } + } + + if (isset($request->teams)) { + $permisstion = Permission::where('user_id', $id)->where('name', 'teams')->first(); + if ($permisstion) { + $permisstion->is_permission = $request->teams; + $permisstion->save(); + } else { + $permisstion = new Permission(); + $permisstion->is_permission = $request->teams; + $permisstion->user_id = $id; + $permisstion->name = 'teams'; + $permisstion->save(); + } + } + + return $this->metaSuccess(); + } + + public function resendLink(Request $request, $id) + { + $admin = User::find($id); + if ($admin == null || $admin->role != 'sub-admin') + return $this->errorResponse('No admin to be send invite link', Response::HTTP_BAD_REQUEST); + + $code = Str::random(6); + // $url = $request->header('origin') ?? $request->root(); + $url = getenv('SITE_URL'); + $inviteUrl = $url . '/register-sub-admin?code=' . $code . '&email=' . urlencode($admin->email); + + VerifyUser::where('email', $admin->email)->where('type', VerifyUser::TYPE_INVITE_ADMIN)->delete(); + + $verify = new VerifyUser(); + $verify->email = $admin->email; + $verify->type = VerifyUser::TYPE_INVITE_ADMIN; + $verify->code = $code; + $verify->created_at = now(); + $verify->save(); + + Mail::to($admin->email)->send(new InvitationMail($inviteUrl)); + + return $this->metaSuccess(); + } + + public function resetSubAdminResetPassword(Request $request, $id) + { + $admin = User::find($id); + if ($admin == null || $admin->role != 'sub-admin') + return $this->errorResponse('No admin to be revoked', Response::HTTP_BAD_REQUEST); + + $code = Str::random(6); + // $url = $request->header('origin') ?? $request->root(); + $url = getenv('SITE_URL'); + $resetUrl = $url . '/update-password?code=' . $code . '&email=' . urlencode($admin->email); + + VerifyUser::where('email', $admin->email)->where('type', VerifyUser::TYPE_RESET_PASSWORD)->delete(); + + $verify = new VerifyUser(); + $verify->email = $admin->email; + $verify->type = VerifyUser::TYPE_RESET_PASSWORD; + $verify->code = $code; + $verify->created_at = now(); + $verify->save(); + + Mail::to($admin->email)->send(new ResetPasswordMail($resetUrl)); + + return $this->metaSuccess(); + } + + public function revokeSubAdmin(Request $request, $id) + { + $admin = User::find($id); + if ($admin == null || $admin->role != 'sub-admin') + return $this->errorResponse('No admin to be revoked', Response::HTTP_BAD_REQUEST); + + $admin->member_status = 'revoked'; + $admin->banned = 1; + $admin->save(); + + return $this->metaSuccess(); + } + + public function undoRevokeSubAdmin(Request $request, $id) + { + $admin = User::find($id); + if ($admin == null || $admin->role != 'sub-admin') + return $this->errorResponse('No admin to be revoked', Response::HTTP_BAD_REQUEST); + if ($admin->password) { + $admin->member_status = 'active'; + } else { + $admin->member_status = 'invited'; + } + $admin->banned = 0; + $admin->save(); + + return $this->successResponse($admin); + } + + public function getIpHistories(Request $request, $id) + { + $admin = User::find($id); + if ($admin == null || $admin->role != 'sub-admin') { + return $this->errorResponse('Not found admin', Response::HTTP_BAD_REQUEST); + } + $limit = $request->limit ?? 50; + $ipAddress = IpHistory::where(['user_id' => $admin->id]) + ->orderBy('created_at', 'DESC') + ->paginate($limit); + + return $this->successResponse($ipAddress); + } + + public function approveIntakeUser($id) { $admin = auth()->user(); - $user = User::with(['shuftipro', 'profile'])->where('id', $id)->first(); - if ($user && $user->profile && $user->shuftipro) { - $user->kyc_verified_at = now(); + $user = User::where('id', $id)->where('banned', 0)->where('role', 'member')->first(); + if ($user && $user->letter_file) { + $user->letter_verified_at = now(); $user->save(); - $user->shuftipro->status = 'approved'; - $user->shuftipro->reviewed = 1; - $user->shuftipro->save(); - - $user->shuftipro->manual_approved_at = now(); - $user->shuftipro->manual_reviewer = $admin->email; - $user->shuftipro->save(); + $emailerData = EmailerHelper::getEmailerData(); + EmailerHelper::triggerUserEmail($user->email, 'Your letter of motivation is APPROVED', $emailerData, $user); + if ($user->letter_verified_at && $user->node_verified_at) { + EmailerHelper::triggerUserEmail($user->email, 'Congratulations', $emailerData, $user); + } return $this->metaSuccess(); } - return $this->errorResponse('Fail approve KYC', Response::HTTP_BAD_REQUEST); + return $this->errorResponse('Fail approved User', Response::HTTP_BAD_REQUEST); } - // Deny KYC - public function denyKYC($id, Request $request) + public function resetIntakeUser($id, Request $request) { $admin = auth()->user(); - $user = User::with(['shuftipro', 'profile'])->where('id', $id)->first(); - if ($user && $user->profile && $user->shuftipro) { - $user->kyc_verified_at = null; + + $user = User::where('id', $id)->where('banned', 0)->where('role', 'member')->first(); + if ($user) { + $user->letter_verified_at = null; + $user->letter_file = null; + $user->letter_rejected_at = now(); $user->save(); + $message = trim($request->get('message')); + if (!$message) { + return $this->errorResponse('please input message', Response::HTTP_BAD_REQUEST); + } + Mail::to($user->email)->send(new AdminAlert('You need to submit letter again', $message)); + return $this->metaSuccess(); + } + return $this->errorResponse('Fail reset User', Response::HTTP_BAD_REQUEST); + } - $user->shuftipro->status = 'denied'; - $user->shuftipro->reviewed = 1; - $user->shuftipro->save(); + public function banUser($id) + { + $admin = auth()->user(); - $user->shuftipro->manual_approved_at = now(); - $user->shuftipro->manual_reviewer = $admin->email; - $user->shuftipro->save(); + $user = User::where('id', $id)->where('banned', 0)->first(); + if ($user) { + $user->banned = 1; + $user->save(); + return $this->metaSuccess(); + } + return $this->errorResponse('Fail Ban User', Response::HTTP_BAD_REQUEST); + } + public function removeUser($id, Request $request) + { + $user = User::where('id', $id)->where('role', 'member')->first(); + if ($user) { + Shuftipro::where('user_id', $user->id)->delete(); + ShuftiproTemp::where('user_id', $user->id)->delete(); + Profile::where('user_id', $user->id)->delete(); + $user->delete(); return $this->metaSuccess(); } - return $this->errorResponse('Fail deny KYC', Response::HTTP_BAD_REQUEST); + return $this->errorResponse('Fail remove User', Response::HTTP_BAD_REQUEST); + } + + public function getVerificationUsers(Request $request) + { + $limit = $request->limit ?? 50; + $users = User::where('users.role', 'member')->where('banned', 0) + ->join('profile', function ($query) { + $query->on('profile.user_id', '=', 'users.id') + ->where('profile.status', 'pending'); + }) + ->join('shuftipro', 'shuftipro.user_id', '=', 'users.id') + ->select([ + 'users.id as user_id', + 'users.created_at', + 'users.email', + 'profile.*', + 'shuftipro.status as kyc_status', + 'shuftipro.background_checks_result', + 'shuftipro.manual_approved_at' + ])->paginate($limit); + return $this->successResponse($users); } // Reset KYC - public function resetKYC($userId, Request $request) + public function resetKYC($id, Request $request) { $admin = auth()->user(); @@ -107,71 +901,479 @@ public function resetKYC($userId, Request $request) return $this->errorResponse('please input message', Response::HTTP_BAD_REQUEST); } - $user = User::with(['profile'])->where('id', $userId)->first(); + $user = User::with(['profile'])->where('id', $id)->first(); if ($user && $user->profile) { - $user->kyc_verified_at = null; - $user->save(); - + $user->profile->status = null; + $user->profile->save(); + + Profile::where('user_id', $user->id)->delete(); Shuftipro::where('user_id', $user->id)->delete(); ShuftiproTemp::where('user_id', $user->id)->delete(); + DocumentFile::where('user_id', $user->id)->delete(); - Mail::to($user->email)->send(new ResetKYC($message)); + $user->kyc_verified_at = null; + $user->approve_at = null; + $user->reset_kyc = 1; + $user->save(); + + Mail::to($user->email)->send(new AdminAlert('You need to submit KYC again', $message)); return $this->metaSuccess(); } return $this->errorResponse('Fail Reset KYC', Response::HTTP_BAD_REQUEST); } - // get intake - public function getIntakes(Request $request) + public function refreshLinks($id) { - $limit = $request->limit ?? 15; - $users = User::select(['users.created_at as registration_date','users.id', 'users.email', 'users.kyc_verified_at', 'users.node_verified_at']) - ->leftJoin('owner_node', function ($join) { - $join->on('owner_node.user_id', '=', 'users.id'); - }) - ->leftJoin('users as u2', function ($join) { - $join->on('owner_node.email', '=', 'u2.email'); - }) - ->where(function ($q) { - $q->where('users.node_verified_at', null) - ->orWhere('users.kyc_verified_at', null) - ->orWhere('u2.node_verified_at', null) - ->orWhere('u2.kyc_verified_at', null); - })->where('users.role', '<>', 'admin') - ->groupBy(['users.created_at','users.id', 'users.email', 'users.kyc_verified_at', 'users.node_verified_at']) - ->paginate($limit); + $url = 'https://api.shuftipro.com/status'; + $user = User::with('shuftipro')->find($id); - foreach ($users as $user) { - $total = 0; - $unopenedInvites = 0; - $ownerNodes = OwnerNode::where('user_id', $user->id)->get(); - foreach ($ownerNodes as $node) { - $total ++; - $user2 = User::select(['users.id', 'users.email', 'users.kyc_verified_at', 'users.node_verified_at']) - ->where('email', $node->email)->first(); - $node->user = $user2; - if ($user2 && $user2->kyc_verified_at && $user2->node_verified_at) { - - } else { - $unopenedInvites ++; + $shuftipro = $user->shuftipro; + if ($shuftipro) { + $client_id = config('services.shufti.client_id'); + $secret_key = config('services.shufti.client_secret'); + + $response = Http::withBasicAuth($client_id, $secret_key)->post($url, [ + 'reference' => $shuftipro->reference_id + ]); + + $data = $response->json(); + if (!$data || !is_array($data)) return; + + if (!isset($data['reference']) || !isset($data['event'])) { + return $this->successResponse([ + 'success' => false, + ]); + } + + $events = [ + 'verification.accepted', + 'verification.declined', + 'request.timeout' + ]; + + if (!in_array($data['event'], $events)) { + return $this->successResponse([ + 'success' => false, + ]); + } + + $proofs = isset($data['proofs']) ? $data['proofs'] : null; + + if ($proofs && isset($proofs['document']) && isset($proofs['document']['proof'])) { + $shuftipro->document_proof = $proofs['document']['proof']; + } + + // Address Proof + if ($proofs && isset($proofs['address']) && isset($proofs['address']['proof'])) { + $shuftipro->address_proof = $proofs['address']['proof']; + } + + $shuftipro->save(); + + return $this->successResponse([ + 'success' => true, + ]); + } + + return $this->successResponse([ + 'success' => false, + ]); + } + + public function banAndDenyUser($id) + { + $user = User::with(['shuftipro', 'profile']) + ->where('id', $id) + ->where('users.role', 'member') + ->where('banned', 0) + ->first(); + + if ($user && $user->profileT) { + $user->profile->status = 'denied'; + $user->profile->save(); + $user->banned = 1; + $user->save(); + return $this->metaSuccess(); + } + + return $this->errorResponse('Fail deny and ban user', Response::HTTP_BAD_REQUEST); + } + + public function getVerificationDetail($id) + { + $user = User::with(['shuftipro', 'profile', 'documentFiles']) + ->leftJoin('shuftipro', 'shuftipro.user_id', '=', 'users.id') + ->where('users.id', $id) + ->select([ + 'users.*', + 'shuftipro.status as kyc_status', + 'shuftipro.background_checks_result', + ]) + ->where('users.role', 'member') + ->where('banned', 0) + ->first(); + + if ($user) { + if (isset($user->shuftipro) && isset($user->shuftipro->address_proof) && $user->shuftipro->address_proof) { + $url = Storage::disk('local')->url($user->shuftipro->address_proof); + $user->shuftipro->address_proof_link = asset($url); + } + return $this->successResponse($user); + } + + return $this->errorResponse('Fail get verification user', Response::HTTP_BAD_REQUEST); + } + + public function approveDocument($id) + { + $user = User::with(['profile']) + ->where('id', $id) + ->where('users.role', 'member') + ->where('banned', 0) + ->first(); + + if ($user && $user->profile) { + $user->profile->document_verified_at = now(); + $user->profile->save(); + return $this->metaSuccess(); + } + + return $this->errorResponse('Fail approve document', Response::HTTP_BAD_REQUEST); + } + + public function activeUser($id) + { + $user = User::with(['profile']) + ->where('id', $id) + ->where('users.role', 'member') + ->where('banned', 0) + ->first(); + + if ($user && $user->profile) { + $user->profile->status = 'approved'; + $user->profile->save(); + $user->approve_at = now(); + $user->save(); + return $this->metaSuccess(); + } + + return $this->errorResponse('Fail active document', Response::HTTP_BAD_REQUEST); + } + + // Add Emailer Admin + public function addEmailerAdmin(Request $request) + { + $user = Auth::user(); + + $email = $request->get('email'); + if (!$email) { + return [ + 'success' => false, + 'message' => 'Invalid email address' + ]; + } + + $record = EmailerAdmin::where('email', $email)->first(); + if ($record) { + return [ + 'success' => false, + 'message' => 'This emailer admin email address is already in use' + ]; + } + + $record = new EmailerAdmin; + $record->email = $email; + $record->save(); + + return ['success' => true]; + } + + // Delete Emailer Admin + public function deleteEmailerAdmin($adminId, Request $request) + { + $user = Auth::user(); + EmailerAdmin::where('id', $adminId)->delete(); + return ['success' => true]; + } + + // Get Emailer Data + public function getEmailerData(Request $request) + { + $user = Auth::user(); + $data = []; + + $admins = EmailerAdmin::where('id', '>', 0)->orderBy('email', 'asc')->get(); + $triggerAdmin = EmailerTriggerAdmin::where('id', '>', 0)->orderBy('id', 'asc')->get(); + $triggerUser = EmailerTriggerUser::where('id', '>', 0)->orderBy('id', 'asc')->get(); + + $data = [ + 'admins' => $admins, + 'triggerAdmin' => $triggerAdmin, + 'triggerUser' => $triggerUser, + ]; + + return [ + 'success' => true, + 'data' => $data + ]; + } + + // Update Emailer Trigger Admin + public function updateEmailerTriggerAdmin($recordId, Request $request) + { + $user = Auth::user(); + $record = EmailerTriggerAdmin::find($recordId); + + if ($record) { + $enabled = (int) $request->get('enabled'); + $record->enabled = $enabled; + $record->save(); + return ['success' => true]; + } + + return ['success' => false]; + } + + // Update Emailer Trigger User + public function updateEmailerTriggerUser($recordId, Request $request) + { + $user = Auth::user(); + $record = EmailerTriggerUser::find($recordId); + + if ($record) { + $enabled = (int) $request->get('enabled'); + $content = $request->get('content'); + + $record->enabled = $enabled; + if ($content) $record->content = $content; + + $record->save(); + + return ['success' => true]; + } + + return ['success' => false]; + } + + public function getMonitoringCriteria(Request $request) + { + $data = MonitoringCriteria::get(); + return $this->successResponse($data); + } + + public function updateMonitoringCriteria($type, Request $request) + { + $record = MonitoringCriteria::where('type', $type)->first(); + + if ($record) { + $validator = Validator::make($request->all(), [ + 'warning_level' => 'required|integer', + 'probation_start' => 'required', + // 'frame_calculate_unit' => 'required|in:Weeks,Days,Hours', + // 'frame_calculate_value' => 'required|integer', + 'given_to_correct_unit' => 'required|in:Weeks,Days,Hours', + 'given_to_correct_value' => 'required|integer', + // 'system_check_unit' => 'required|in:Weeks,Days,Hours', + // 'system_check_value' => 'required|integer', + ]); + + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $record->warning_level = $request->warning_level; + $record->probation_start = $request->probation_start; + // $record->frame_calculate_unit = $request->frame_calculate_unit; + // $record->frame_calculate_value = $request->frame_calculate_value; + $record->given_to_correct_unit = $request->given_to_correct_unit; + $record->given_to_correct_value = $request->given_to_correct_value; + // $record->system_check_unit = $request->system_check_unit; + // $record->system_check_value = $request->system_check_value; + $record->save(); + + return ['success' => true]; + } + + return ['success' => false]; + } + + public function updateLockRules(Request $request, $id) + { + $validator = Validator::make($request->all(), [ + 'is_lock' => 'required|boolean' + ]); + + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $rule = LockRules::where('id', $id)->first(); + + $rule->is_lock = $request->is_lock; + $rule->save(); + + return ['success' => true]; + } + + public function getLockRules() + { + $ruleKycNotVerify = LockRules::where('type', 'kyc_not_verify') + ->orderBy('id', 'ASC')->select(['id', 'screen', 'is_lock'])->get(); + $ruleStatusIsPoor = LockRules::where('type', 'status_is_poor') + ->orderBy('id', 'ASC')->select(['id', 'screen', 'is_lock'])->get(); + + $data = [ + 'kyc_not_verify' => $ruleKycNotVerify, + 'status_is_poor' => $ruleStatusIsPoor, + ]; + return $this->successResponse($data); + } + + public function getListNodes(Request $request) + { + $limit = $request->limit ?? 50; + $node_failing = $request->node_failing ?? ''; + $nodes = User::select([ + 'id as user_id', + 'public_address_node', + 'is_fail_node', + 'rank', + ]) + ->where('banned', 0) + ->whereNotNull('public_address_node') + ->where(function ($query) use ($node_failing) { + if ($node_failing == 1) { + $query->where('is_fail_node', 1); } + }) + ->orderBy('rank', 'asc') + ->paginate($limit); + + return $this->successResponse($nodes); + } + + // Get GraphInfo + public function getGraphInfo(Request $request) + { + $user = Auth::user(); + $graphDataDay = $graphDataWeek = $graphDataMonth = $graphDataYear = []; + + /* + $graphData = []; + $items = TokenPrice::orderBy('created_at', 'desc')->limit(100)->get(); + if ($items && count($items)) { + foreach ($items as $item) { + $name = strtotime($item->created_at); + $graphData[$name] = number_format($item->price, 4); } + } + */ - $user->beneficial_owners = $total; - $user->unopened_invites = $unopenedInvites; - if ($unopenedInvites == 0) { - $user->owner_kyc_status = 'Approved'; - } else { - $user->owner_kyc_status = 'Not Approve'; + $timeDay = Carbon::now('UTC')->subHours(24); + $timeWeek = Carbon::now('UTC')->subDays(7); + $timeMonth = Carbon::now('UTC')->subDays(30); + $timeYear = Carbon::now('UTC')->subYear(); + + $items = TokenPrice::orderBy('created_at', 'desc')->where('created_at', '>=', $timeDay)->get(); + if ($items && count($items)) { + foreach ($items as $item) { + $name = strtotime($item->created_at); + $graphDataDay[$name] = number_format($item->price, 4); } - if($user->kyc_verified_at && $user->node_verified_at) { - $user->kyc_status = 'Approved'; - } else { - $user->kyc_status = 'Not Approved'; + } + + $items = TokenPrice::orderBy('created_at', 'desc')->where('created_at', '>=', $timeWeek)->get(); + if ($items && count($items)) { + foreach ($items as $item) { + $name = strtotime($item->created_at); + $graphDataWeek[$name] = number_format($item->price, 4); } } - return $this->successResponse($users); + $items = TokenPrice::orderBy('created_at', 'desc')->where('created_at', '>=', $timeMonth)->get(); + if ($items && count($items)) { + foreach ($items as $item) { + $name = strtotime($item->created_at); + $graphDataMonth[$name] = number_format($item->price, 4); + } + } + + $items = TokenPrice::orderBy('created_at', 'desc')->where('created_at', '>=', $timeYear)->get(); + if ($items && count($items)) { + foreach ($items as $item) { + $name = strtotime($item->created_at); + $graphDataYear[$name] = number_format($item->price, 4); + } + } + + return $this->successResponse([ + 'day' => $graphDataDay, + 'week' => $graphDataWeek, + 'month' => $graphDataMonth, + 'year' => $graphDataYear, + ]); + } + + /** + * verify file casper singer + */ + public function uploadMembershipFile(Request $request) + { + try { + // Validator + $validator = Validator::make($request->all(), [ + 'file' => 'required|mimes:pdf,docx,doc,txt,rtf|max:100000', + ]); + + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $filenameWithExt = $request->file('file')->getClientOriginalName(); + //Get just filename + $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME); + // Get just ext + $extension = $request->file('file')->getClientOriginalExtension(); + // new filename hash + $filenamehash = md5(Str::random(10) . '_' . (string)time()); + // Filename to store + $fileNameToStore = $filenamehash . '.' . $extension; + + // S3 File Upload + $S3 = new S3Client([ + 'version' => 'latest', + 'region' => getenv('AWS_DEFAULT_REGION'), + 'credentials' => [ + 'key' => getenv('AWS_ACCESS_KEY_ID'), + 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), + ], + ]); + + $s3result = $S3->putObject([ + 'Bucket' => getenv('AWS_BUCKET'), + 'Key' => 'client_uploads/' . $fileNameToStore, + 'SourceFile' => $request->file('file') + ]); + + // $ObjectURL = 'https://'.getenv('AWS_BUCKET').'.s3.amazonaws.com/'.$fileNameToStore; + $ObjectURL = $s3result['ObjectURL'] ?? getenv('SITE_URL') . '/not-found'; + MembershipAgreementFile::where('id', '>', 0)->delete(); + $membershipAgreementFile = new MembershipAgreementFile(); + $membershipAgreementFile->name = $filenameWithExt; + $membershipAgreementFile->path = $ObjectURL; + $membershipAgreementFile->url = $ObjectURL; + $membershipAgreementFile->save(); + DB::table('users')->update(['membership_agreement' => 0]); + return $this->successResponse($membershipAgreementFile); + } catch (\Exception $ex) { + return $this->errorResponse(__('Failed upload file'), Response::HTTP_BAD_REQUEST, $ex->getMessage()); + } + } + + public function getMembershipFile() + { + $membershipAgreementFile = MembershipAgreementFile::first(); + return $this->successResponse($membershipAgreementFile); } } diff --git a/app/Http/Controllers/Api/V1/AuthController.php b/app/Http/Controllers/Api/V1/AuthController.php index ac3c1139..e13a9d31 100644 --- a/app/Http/Controllers/Api/V1/AuthController.php +++ b/app/Http/Controllers/Api/V1/AuthController.php @@ -2,14 +2,19 @@ namespace App\Http\Controllers\Api\V1; +use App\Console\Helper; + use App\Http\Controllers\Controller; +use App\Http\EmailerHelper; use App\Http\Requests\Api\LoginRequest; use App\Http\Requests\Api\RegisterEntityRequest; use App\Http\Requests\Api\RegisterIndividualRequest; use App\Http\Requests\Api\ResetPasswordRequest; use App\Http\Requests\Api\SendResetPasswordMailRequeslRequest; +use App\Mail\LoginTwoFA; use App\Mail\ResetPasswordMail; use App\Mail\UserVerifyMail; +use App\Models\IpHistory; use App\Models\User; use App\Models\VerifyUser; use App\Repositories\UserRepository; @@ -19,7 +24,9 @@ use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Mail; +use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; +use Laravel\Passport\Token; class AuthController extends Controller { @@ -41,6 +48,10 @@ public function __construct( $this->verifyUserRepo = $verifyUserRepo; } + public function testHash() { + exit(Hash::make('ledgerleapllc')); + } + /** * Auth user function * @@ -52,6 +63,30 @@ public function login(LoginRequest $request) { $user = $this->userRepo->first(['email' => $request->email]); if ($user && Hash::check($request->password, $user->password)) { + if ($user->banned == 1) { + return $this->errorResponse('User banned', Response::HTTP_BAD_REQUEST); + } + if ($user->twoFA_login) { + $code = strtoupper(Str::random(6)); + $user->twoFA_login_active = 1; + $user->save(); + VerifyUser::where('email', $user->email)->where('type', VerifyUser::TYPE_LOGIN_TWO_FA)->delete(); + $verify = new VerifyUser(); + $verify->email = $user->email; + $verify->type = VerifyUser::TYPE_LOGIN_TWO_FA; + $verify->code = $code; + $verify->created_at = now(); + $verify->save(); + Mail::to($user)->send(new LoginTwoFA($code)); + } + $user->last_login_at = now(); + $user->last_login_ip_address = request()->ip(); + $user->save(); + $ipHistory = new IpHistory(); + $ipHistory->user_id = $user->id; + $ipHistory->ip_address = request()->ip(); + $ipHistory->save(); + Helper::getAccountInfoStandard($user); return $this->createTokenFromUser($user); } @@ -73,7 +108,6 @@ public function registerEntity(RegisterEntityRequest $request) $data['password'] = bcrypt($request->password); $data['last_login_at'] = now(); $data['type'] = User::TYPE_ENTITY; - $data['member_status'] = User::STATUS_INCOMPLETE; $user = $this->userRepo->create($data); $code = generateString(7); $userVerify = $this->verifyUserRepo->updateOrCreate( @@ -86,10 +120,16 @@ public function registerEntity(RegisterEntityRequest $request) 'created_at' => now() ] ); - if ($userVerify) { - Mail::to($user->email)->send(new UserVerifyMail($code)); - } + Mail::to($user->email)->send(new UserVerifyMail($code)); DB::commit(); + $user->pending_node = 1; + $user->last_login_at = now(); + $user->last_login_ip_address = request()->ip(); + $user->save(); + $ipHistory = new IpHistory(); + $ipHistory->user_id = $user->id; + $ipHistory->ip_address = request()->ip(); + $ipHistory->save(); return $this->createTokenFromUser($user); } catch (\Exception $e) { DB::rollBack(); @@ -109,10 +149,10 @@ public function registerIndividual(RegisterIndividualRequest $request) try { DB::beginTransaction(); $data = $request->all(); + $data['password'] = bcrypt($request->password); $data['last_login_at'] = now(); $data['type'] = User::TYPE_INDIVIDUAL; - $data['member_status'] = User::STATUS_INCOMPLETE; $user = $this->userRepo->create($data); $code = generateString(7); $userVerify = $this->verifyUserRepo->updateOrCreate( @@ -122,13 +162,19 @@ public function registerIndividual(RegisterIndividualRequest $request) ], [ 'code' => $code, - 'created_at' => now() + 'created_at' => now(), ] ); - if ($userVerify) { - Mail::to($user->email)->send(new UserVerifyMail($code)); - } + Mail::to($user->email)->send(new UserVerifyMail($code)); DB::commit(); + $user->pending_node = 1; + $user->last_login_at = now(); + $user->last_login_ip_address = request()->ip(); + $user->save(); + $ipHistory = new IpHistory(); + $ipHistory->user_id = $user->id; + $ipHistory->ip_address = request()->ip(); + $ipHistory->save(); return $this->createTokenFromUser($user); } catch (\Exception $e) { DB::rollBack(); @@ -153,6 +199,8 @@ public function verifyEmail(Request $request) if ($this->checCode($verifyUser)) { $user->update(['email_verified_at' => now()]); $verifyUser->delete(); + $emailerData = EmailerHelper::getEmailerData(); + EmailerHelper::triggerUserEmail($user->email, 'Welcome to the Casper', $emailerData, $user); return $this->metaSuccess(); } return $this->errorResponse(__('api.error.code_not_found'), Response::HTTP_BAD_REQUEST); @@ -180,7 +228,8 @@ public function sendResetLinkEmail(SendResetPasswordMailRequeslRequest $request) return $this->errorResponse(__('api.error.email_not_found'), Response::HTTP_BAD_REQUEST); } $code = Str::random(60); - $url = $request->header('origin') ?? $request->root(); + // $url = $request->header('origin') ?? $request->root(); + $url = getenv('SITE_URL'); $resetUrl = $url . '/update-password?code=' . $code . '&email=' . urlencode($request->email); $passwordReset = $this->verifyUserRepo->updateOrCreate( [ @@ -262,8 +311,49 @@ public function resendVerifyEmail(Request $request) throw $e; } } + + public function registerSubAdmin(Request $request) + { + + $validator = Validator::make($request->all(), [ + 'first_name' => 'required|regex:/^[A-Za-z. ]{1,255}$/', + 'last_name' => 'required|regex:/^[A-Za-z. ]{1,255}$/', + 'email' => 'required|email|max:256', + 'code' => 'required', + 'password' => 'required|min:8|max:80', + ]); + + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + $user = User::where('email', $request->email)->where('member_status', 'invited')->where('role', 'sub-admin')->first(); + if (!$user) { + return $this->errorResponse('There is no admin user with this email', Response::HTTP_BAD_REQUEST); + } + $verify = VerifyUser::where('email', $request->email)->where('type', VerifyUser::TYPE_INVITE_ADMIN)->where('code', $request->code)->first(); + if (!$verify) { + return $this->errorResponse('Fail register sub-amdin', Response::HTTP_BAD_REQUEST); + } + $user->first_name = $request->first_name; + $user->last_name = $request->last_name; + $user->password = bcrypt($request->password); + $user->last_login_at = now(); + $user->last_login_ip_address = request()->ip(); + $user->member_status = 'active'; + $user->save(); + $ipHistory = new IpHistory(); + $ipHistory->user_id = $user->id; + $ipHistory->ip_address = request()->ip(); + $ipHistory->save(); + $verify->delete(); + return $this->createTokenFromUser($user); + } + public function createTokenFromUser($user, $info = []) { + Token::where([ + 'user_id' => $user->id + ])->delete(); $token = $user->createToken(config('auth.secret_code')); return $this->responseToken($token, $user->toArray()); } diff --git a/app/Http/Controllers/Api/V1/ContactController.php b/app/Http/Controllers/Api/V1/ContactController.php new file mode 100644 index 00000000..7e9e2187 --- /dev/null +++ b/app/Http/Controllers/Api/V1/ContactController.php @@ -0,0 +1,78 @@ +<?php + +namespace App\Http\Controllers\Api\V1; + +use App\Http\Controllers\Controller; +use App\Mail\ContactUsMail; +use App\Models\ContactRecipient; +use App\Models\ContactUs; +use Illuminate\Http\Request; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Mail; +use Illuminate\Support\Facades\Validator; + +class ContactController extends Controller +{ + public function submitContact(Request $request) + { + $user_id = null; + if(auth()->user()) { + $user_id = auth()->user()->id; + } + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:255', + 'email' => 'required|email', + 'message' => 'required', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + $contactUs = new ContactUs(); + $contactUs->user_id = $user_id; + $contactUs->name = $request->name; + $contactUs->email = $request->email; + $contactUs->message = $request->message; + $contactUs->save(); + $contactRecipients = ContactRecipient::get(); + if (count($contactRecipients) > 0) { + foreach ($contactRecipients as $item) { + Mail::to($item->email)->send(new ContactUsMail($contactUs)); + } + } + return $this->metaSuccess(); + } + + public function getContactRecipients(Request $request) + { + $limit = $request->limit ?? 50; + $sort_key = $request->sort_key ?? 'created_at'; + $sort_direction = $request->sort_direction ?? 'desc'; + $contactRecipients = ContactRecipient::orderBy($sort_key, $sort_direction)->paginate($limit); + return $this->successResponse($contactRecipients); + } + + public function addContactRecipients(Request $request) + { + $validator = Validator::make($request->all(), [ + 'email' => 'required|email', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + $contactRecipient = ContactRecipient::where('email', $request->email)->first(); + if ($contactRecipient) { + return $this->errorResponse('This email has already exist', Response::HTTP_BAD_REQUEST); + } else { + $contactRecipient = new ContactRecipient(); + $contactRecipient->email = $request->email; + $contactRecipient->save(); + return $this->metaSuccess(); + } + } + + public function deleteContactRecipients($id) + { + ContactRecipient::where('id', $id)->delete(); + return $this->metaSuccess(); + } +} diff --git a/app/Http/Controllers/Api/V1/DiscussionController.php b/app/Http/Controllers/Api/V1/DiscussionController.php new file mode 100644 index 00000000..91e8c286 --- /dev/null +++ b/app/Http/Controllers/Api/V1/DiscussionController.php @@ -0,0 +1,372 @@ +<?php + +namespace App\Http\Controllers\Api\V1; + +use App\Http\Controllers\Controller; +use Illuminate\Http\Request; +use App\Repositories\UserRepository; +use App\Repositories\DiscussionRepository; +use App\Repositories\DiscussionCommentRepository; +use App\Repositories\DiscussionPinRepository; +use App\Repositories\DiscussionVoteRepository; +use App\Repositories\DiscussionRemoveNewRepository; +use Illuminate\Support\Facades\Validator; +use App\Models\Discussion; +use App\Models\DiscussionComment; +use App\Models\DiscussionPin; +use App\Models\DiscussionRemoveNew; +use Carbon\Carbon; +use Illuminate\Http\Response; +use App\Facades\Paginator; + +class DiscussionController extends Controller +{ + private $userRepo; + private $discussionRepo; + private $discussionPinRep; + private $discussionVoteRepo; + private $discussionCommentRepo; + private $discussionRemoveNewRepo; + + + public function __construct( + UserRepository $userRepo, + DiscussionRepository $discussionRepo, + DiscussionPinRepository $discussionPinRepo, + DiscussionVoteRepository $discussionVoteRepo, + DiscussionCommentRepository $discussionCommentRepo, + DiscussionRemoveNewRepository $discussionRemoveNewRepo + ) { + $this->userRepo = $userRepo; + $this->discussionRepo = $discussionRepo; + $this->discussionPinRepo = $discussionPinRepo; + $this->discussionVoteRepo = $discussionVoteRepo; + $this->discussionCommentRepo = $discussionCommentRepo; + $this->discussionRemoveNewRepo = $discussionRemoveNewRepo; + } + + public function getTrending(Request $request) + { + $limit = $request->limit ?? 50; + $user = auth()->user(); + $trendings = Discussion::where('likes', '!=', 0)->where('is_draft', 0)->take(9)->orderBy('likes', 'desc')->paginate($limit); + $count = Discussion::where('likes', '!=', 0)->where('is_draft', 0)->orderBy('likes', 'desc')->count(); + if ($count >= 9) { + return $this->successResponse($trendings); + } else { + $remains = 9 - $count; + $trending_ids = $trendings->pluck('id'); + // $removed_ids = DiscussionRemoveNew::where(['user_id' => $user->id])->pluck('discussion_id'); + $news = Discussion::whereNotIn('id', $trending_ids) + // ->whereNotIn('id', $removed_ids) + ->where('is_draft', 0) + ->take($remains)->orderBy('id', 'desc')->get(); + $trendingArray = $trendings->toArray() ; + $trendingArray['data'] = array_merge($trendingArray['data'], $news->toArray()); + + return $this->successResponse( [ + 'data' => $trendingArray['data'] + ]); + } + } + + // Get Discussions + public function getDiscussions(Request $request) + { + $data = array(); + $limit = $request->limit ?? 50; + $user = auth()->user(); + $data = Discussion::with(['user', 'user.profile'])->where('discussions.is_draft', 0) + ->leftJoin('discussion_pins', function ($query) use ($user) { + $query->on('discussion_pins.discussion_id', '=', 'discussions.id') + ->where('discussion_pins.user_id', $user->id); + }) + ->leftJoin('discussion_votes', function ($query) use ($user) { + $query->on('discussion_votes.discussion_id', '=', 'discussions.id') + ->where('discussion_votes.user_id', $user->id);; + }) + ->select([ + 'discussions.*', + 'discussion_pins.id as is_pin', + 'discussion_votes.id as is_vote', + 'discussion_votes.is_like as is_like', + ])->orderBy('discussions.created_at', 'DESC')->paginate($limit); + + return $this->successResponse($data); + } + + public function getPinnedDiscussions(Request $request) + { + $limit = $request->limit ?? 50; + $user = auth()->user(); + $data = DiscussionPin::where('discussion_pins.user_id', $user->id)->with('user') + ->join('discussions', 'discussions.id', '=', 'discussion_pins.discussion_id') + ->leftJoin('discussion_votes', function ($query) use ($user) { + $query->on('discussion_votes.discussion_id', '=', 'discussions.id') + ->where('discussion_votes.user_id', $user->id);; + }) + ->select([ + 'discussions.*', + 'discussion_votes.id as is_vote', + 'discussion_pins.discussion_id', + 'discussion_votes.is_like as is_like', + ])->orderBy('discussion_pins.created_at', 'DESC')->paginate($limit); + return $this->successResponse($data); + } + + public function getMyDiscussions(Request $request) + { + $limit = $request->limit ?? 50; + $user = auth()->user(); + $data = Discussion::with(['user', 'user.profile'])->where('discussions.is_draft', 0) + ->where('discussions.user_id', $user->id) + ->leftJoin('discussion_pins', function ($query) use ($user) { + $query->on('discussion_pins.discussion_id', '=', 'discussions.id') + ->where('discussion_pins.user_id', $user->id); + }) + ->leftJoin('discussion_votes', function ($query) use ($user) { + $query->on('discussion_votes.discussion_id', '=', 'discussions.id') + ->where('discussion_votes.user_id', $user->id);; + }) + ->select([ + 'discussions.*', + 'discussion_pins.id as is_pin', + 'discussion_votes.id as is_vote', + 'discussion_votes.is_like as is_like', + ])->orderBy('discussions.created_at', 'DESC')->paginate($limit); + + return $this->successResponse($data); + } + + public function getDiscussion(Request $request, $id) + { + $user = auth()->user(); + $discussion = Discussion::with(['user', 'user.profile']) + ->where('discussions.id', $id) + ->leftJoin('discussion_pins', function ($query) use ($user) { + $query->on('discussion_pins.discussion_id', '=', 'discussions.id') + ->where('discussion_pins.user_id', $user->id); + }) + ->leftJoin('discussion_votes', function ($query) use ($user) { + $query->on('discussion_votes.discussion_id', '=', 'discussions.id') + ->where('discussion_votes.user_id', $user->id);; + }) + ->select([ + 'discussions.*', + 'discussion_pins.id as is_pin', + 'discussion_votes.id as is_vote', + 'discussion_votes.is_like as is_like', + ])->first(); + $discussion->read = $discussion->read + 1; + $discussion->save(); + $discussion->total_pinned = DiscussionPin::where('discussion_id', $id)->count(); + return $this->successResponse($discussion); + } + + public function updateDiscussion($id, Request $request) { + $validator = Validator::make($request->all(), [ + 'title' => 'required', + 'description' => 'required', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $user = auth()->user(); + $discussion = $this->discussionRepo->update($id, [ + "title" => $request->title, + "description" => $request->description, + ]); + + return $this->successResponse($discussion); + } + + public function postDiscussion(Request $request) + { + $validator = Validator::make($request->all(), [ + 'title' => 'required', + 'description' => 'required', + // 'is_draft' => 'required|in:0,1' + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $user = auth()->user(); + $discussion = $this->discussionRepo->create([ + "title" => $request->title, + "description" => $request->description, + "user_id" => $user->id, + "is_draft" => (int) $request->get('is_draft'), + ]); + + return $this->successResponse($discussion); + } + + public function publishDraftDiscussion($id) + { + $discussion = Discussion::where('id', $id)->where('is_draft', 1)->first(); + if($discussion) { + $discussion->is_draft = 0; + $discussion->save(); + } + return $this->metaSuccess(); + } + + public function createComment(Request $request, $id) + { + $data = array(); + $user = auth()->user(); + $validator = Validator::make($request->all(), [ + 'description' => 'required' + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $model_data = [ + "user_id" => $user->id, + "discussion_id" => $id, + "description" => $request->description + ]; + + $data['comment'] = $this->discussionCommentRepo->create($model_data); + $discussion = $this->discussionRepo->find($id); + $discussion->comments = $discussion->comments + 1; + $discussion->save(); + + $data['comment']['user'] = $user; + + return $this->successResponse($data); + } + + public function updateComment(Request $request, $id) + { + $data = array(); + $user = auth()->user(); + $validator = Validator::make($request->all(), [ + 'description' => 'required', + 'comment_id' => 'required' + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + $comment = DiscussionComment::where('discussion_id', $request->comment_id)->where('user_id', $user->id)->first(); + if ($comment) { + $comment->description = $request->description; + $comment->save(); + return $this->successResponse($comment); + } + return $this->errorResponse('Invalid discussion id', Response::HTTP_BAD_REQUEST); + } + + public function setVote(Request $request, $id) + { + $data = array(); + $user = auth()->user(); + $validator = Validator::make($request->all(), [ + 'is_like' => 'required|boolean' + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $discussion = $this->discussionRepo->find($id); + if ($discussion == null) { + return $this->errorResponse('Invalid discussion id', Response::HTTP_BAD_REQUEST); + } + $is_like = $request->is_like; + $vote = $this->discussionVoteRepo->first(['discussion_id' => $id, 'user_id' => $user->id]); + if ($discussion->user_id != $user->id) { + if ($vote == null) { + $vote = $this->discussionVoteRepo->create([ + 'discussion_id' => $id, + 'user_id' => $user->id, + "is_like" => $is_like + ]); + if ($is_like) { + $discussion->likes = $discussion->likes + 1; + } else { + $discussion->dislikes = $discussion->dislikes + 1; + } + $discussion->save(); + } else { + if ($vote->is_like != $is_like) { + $vote = $this->discussionVoteRepo->update($vote->id, [ + 'is_like' => $is_like + ]); + if ($is_like) { + $discussion->dislikes = $discussion->dislikes - 1; + $discussion->likes = $discussion->likes + 1; + } else { + $discussion->dislikes = $discussion->dislikes + 1; + $discussion->likes = $discussion->likes - 1; + } + } + $discussion->save(); + } + return $this->successResponse([ + 'discussion' => $discussion, + 'vote' => $vote + ]); + } + return $this->errorResponse('Can not vote for my discussion', Response::HTTP_BAD_REQUEST); + } + + public function setPin(Request $request, $id) + { + $data = array(); + $user = auth()->user(); + $pinned = $this->discussionPinRepo->first(['discussion_id' => $id, 'user_id' => $user->id]); + if ($pinned == null) { + $this->discussionPinRepo->create(['discussion_id' => $id, 'user_id' => $user->id]); + } else { + $this->discussionPinRepo->deleteConditions(['discussion_id' => $id, 'user_id' => $user->id]); + } + return $this->metaSuccess(); + } + + public function removeNewMark(Request $request, $id) + { + $user = auth()->user(); + $this->discussionRemoveNewRepo->deleteConditions([['created_at', '<=', Carbon::now()->subDays(3)]]); + $this->discussionRemoveNewRepo->create(['discussion_id' => $id, 'user_id' => $user->id]); + + return $this->metaSuccess(); + } + + public function getComment(Request $request, $id) + { + $limit = $request->limit ?? 50; + $user = auth()->user(); + $data = DiscussionComment::with(['user', 'user.profile']) + ->where('discussion_comments.discussion_id', $id) + ->select([ + 'discussion_comments.*', + ])->orderBy('discussion_comments.created_at', 'DESC')->paginate($limit); + + return $this->successResponse($data); + } + + public function getDraftDiscussions(Request $request) + { + $limit = $request->limit ?? 50; + $user = auth()->user(); + $data = Discussion::with(['user', 'user.profile'])->where('discussions.is_draft', 1) + ->where('discussions.user_id', $user->id) + ->orderBy('discussions.created_at', 'DESC')->paginate($limit); + return $this->successResponse($data); + } + + public function deleteDraftDiscussions($id) + { + $user = auth()->user(); + $discussion = Discussion::where('id', $id)->where('discussions.is_draft', 1)->where('discussions.user_id', $user->id)->first(); + if($discussion) { + $discussion->delete(); + return $this->metaSuccess(); + } else { + return $this->errorResponse('Can not delete draft', Response::HTTP_BAD_REQUEST); + } + } +} diff --git a/app/Http/Controllers/Api/V1/HellosignController.php b/app/Http/Controllers/Api/V1/HellosignController.php index 02d98906..38a14ff4 100644 --- a/app/Http/Controllers/Api/V1/HellosignController.php +++ b/app/Http/Controllers/Api/V1/HellosignController.php @@ -16,8 +16,8 @@ public function hellosignHook(Request $request) if (!$payload) return "error"; $data = json_decode($payload, true); - $api_key = 'e0c85dde1ba2697d4236a6bc6c98ed2d3ca7e3b1cb375f35b286f2c0d07b22d8'; - + $api_key = env('HELLOSIGN_API_KEY_HOOK'); + if (!is_array($data)) return "error"; $md5_header_check = base64_encode(hash_hmac('md5', $payload, $api_key)); diff --git a/app/Http/Controllers/Api/V1/InstallController.php b/app/Http/Controllers/Api/V1/InstallController.php new file mode 100644 index 00000000..6639faa6 --- /dev/null +++ b/app/Http/Controllers/Api/V1/InstallController.php @@ -0,0 +1,111 @@ +<?php + +namespace App\Http\Controllers\Api\V1; + +use App\Http\Controllers\Controller; +use App\Http\EmailerHelper; +use App\Mail\AdminAlert; +use App\Models\EmailerTriggerAdmin; +use App\Models\EmailerTriggerUser; +use App\Models\Setting; +use App\Models\User; + +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Mail; + +class InstallController extends Controller +{ + public function install() + { + /* Setting */ + $names = [ + 'quorum_rate_ballot' => '50', + ]; + foreach ($names as $name => $value) { + $setting = Setting::where('name', $name)->first(); + if (!$setting) { + $setting = new Setting; + $setting->name = $name; + $setting->value = $value; + $setting->save(); + } + } + echo "Setting created<br/>"; + } + + public function installEmailer() { + + // Setup User + $userData = [ + [ + 'title' => 'Welcome to the Casper', + 'subject' => 'Welcome to the Casper Association portal!', + 'content' => 'Welcome to the Casper Association,<br/><br/>To access your member portal you must complete 3 simple steps that you can find once you log in.<br/><br/>#1. E-sign the terms of the portal.<br/><br/>#2. Verify your node. For this step you will need to enter the public address for your node. Next, you will be given a file to sign locally on your node (for security) by following the instructions provided in this process. You will the upload the signed file to verify that you own the provided public address.<br/><br/>#3. Upload a letter of motivation. This is the final step for membership and requires you to write and upload a letter of motivation explaining why you would like to be a member. Remember, members are able to vote about important matters effecting the Casper network. For this reason, we like to know why everyone is here. Feel free to explain why you like Casper, why you are running a node, and why you want to be able to vote and participate as a member. Don\'t over-think it but be detailed. There are no wrong answers here!<br/><br/>Please reply to this email if you need help' + ], + [ + 'title' => 'Your Node is Verified', + 'subject' => 'Your Node is Verified', + 'content' => 'Well done! Your public node [node address] is verified as owned by you. If you have not yet completed the remaining on-boarding steps, please remember you need to e-sign the documents and upload a letter of motivation prior to accessing the member\'s dashboard.' + ], + [ + 'title' => 'Your letter of motivation is received', + 'subject' => 'Your letter of motivation is received', + 'content' => 'Thank you. Your letter of motivation has been received. Please allow our team up to 72 hours to review this letter. You will receive further communication once this process is complete.' + ], + [ + 'title' => 'Your letter of motivation is APPROVED', + 'subject' => 'Your letter of motivation is APPROVED', + 'content' => 'Well done! Your letter of motivation has been approved. Please log in to your portal and complete any on-boarding steps that are not yet finished. If this is your last step then you will now have access to the member\'s dashboard.' + ], + [ + 'title' => 'Congratulations', + 'subject' => 'User [email] has uploaded a letter of motivation', + 'content' => 'Excellent work! You have completed all the required steps to access the member\'s dashboard.<br/><br/>Please log in to explore. You now have access to the following:<br/>- Node and network metrics<br/>- Discussion previews<br/>- Viewing previous votes<br/><br/>To fully unlock your dashboard\'s features, you will need to verify yourself inside the portal. This will grant you the Casper Red Checkmark, proving to the network that you are a Verified Member worthy of a higher level of trust. This process is free and takes only 5 minutes of your time.<br/><br/>Verified Members access all membership perks more likely to be trusted by the public for staking delegation and even get access to a public profile. It\'s a very fast process to upgrade to a Verified Member. Just look for the get verified links on the dashboard.<br/><br/>Verified Members can do the following:<br/>- Start and participate in member discussions<br/>- Vote on protocol updates or changes<br/>- Display a page to verify their status to the public<br/>- Access member benefits and perks<br/>- View all network and node metrics<br/>- Easily view details earnings from staking<br/>- Track all health metrics for their node<br/>' + ], + ]; + + EmailerTriggerUser::where('id', '>', 0)->delete(); + + if (count($userData)) { + foreach ($userData as $item) { + $record = EmailerTriggerUser::where('title', $item['title'])->first(); + if ($record) $record->delete(); + + $record = new EmailerTriggerUser; + $record->title = $item['title']; + $record->subject = $item['subject']; + $record->content = $item['content']; + $record->save(); + } + } + + // Setup Admin + $adminData = [ + [ + 'title' => 'User uploads a letter', + 'subject' => 'User [email] has uploaded a letter of motivation', + 'content' => 'Please log in to the portal to review the letter of motivation for [email] in the Admin\'s "Intake" tab.' + ], + [ + 'title' => 'KYC or AML need review', + 'subject' => 'KYC or AML for [name] needs review', + 'content' => 'Please log in to the portal and go to the lower "Verifications" table in the Admin\'s "Intake" tab. You must click the review button next to user [name] to review this users information and select a further action based on the organization\'s guidelines' + ], + ]; + + EmailerTriggerAdmin::where('id', '>', 0)->delete(); + + if (count($adminData)) { + foreach ($adminData as $item) { + $record = EmailerTriggerAdmin::where('title', $item['title'])->first(); + if ($record) $record->delete(); + + $record = new EmailerTriggerAdmin; + $record->title = $item['title']; + $record->subject = $item['subject']; + $record->content = $item['content']; + $record->save(); + } + } + } +} diff --git a/app/Http/Controllers/Api/V1/MetricController.php b/app/Http/Controllers/Api/V1/MetricController.php new file mode 100644 index 00000000..f4a7bb09 --- /dev/null +++ b/app/Http/Controllers/Api/V1/MetricController.php @@ -0,0 +1,393 @@ +<?php + +namespace App\Http\Controllers\Api\V1; + +use App\Http\Controllers\Controller; + +use App\Models\Metric; +use App\Models\MonitoringCriteria; +use App\Models\Node; +use App\Models\NodeInfo; +use App\Models\User; +use App\Models\Setting; + +use Illuminate\Http\Request; +use Illuminate\Http\Response; + +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\Validator; + +class MetricController extends Controller +{ + public function getMetric() + { + $user = auth()->user(); + $max_update_responsiveness = DB::select("SELECT max(update_responsiveness) as max_update_responsiveness FROM + ( + SELECT MAX(update_responsiveness) as update_responsiveness FROM metric + UNION + SELECT MAX(update_responsiveness) as update_responsiveness FROM node_info + ) AS results + ;"); + $max_update_responsiveness = $max_update_responsiveness[0]->max_update_responsiveness ?? 0; + + $max_peers = DB::select("SELECT max(peers) as max_peers FROM + ( + SELECT MAX(peers) as peers FROM metric + UNION + SELECT MAX(peers) as peers FROM node_info + ) AS results + ;"); + $max_peers = $max_peers[0]->max_peers ?? 0; + $max_block_height = Node::max('block_height'); + $max_uptime = DB::select("SELECT max(uptime) as max_uptime FROM + ( + SELECT MAX(uptime) as uptime FROM metric + UNION + SELECT MAX(uptime) as uptime FROM node_info + ) AS results + ;"); + $max_uptime = $max_uptime[0]->max_uptime ?? 0; + $latest = Node::where('node_address', strtolower($user->public_address_node))->whereNotnull('protocol_version')->orderBy('created_at', 'desc')->first(); + if (!$latest) { + $latest = new Node(); + } + $latest_block_height = $latest->block_height ?? null; + $latest_update_responsiveness = $latest->update_responsiveness ?? null; + $latest_peers = $latest->peers ?? null; + + $metric = Metric::where('user_id', $user->id)->first(); + if (!$metric) { + $metric = new Metric(); + } + $metric_uptime = $metric->uptime ?? null; + $metric_block_height = $metric->block_height_average ? ($max_block_height - $metric->block_height_average) : null; + $metric_update_responsiveness = $metric->update_responsiveness ?? null; + $metric_peers = $metric->peers ?? null; + + $nodeInfo = NodeInfo::where('node_address', strtolower($user->public_address_node))->first(); + if (!$nodeInfo) { + $nodeInfo = new NodeInfo(); + } + $latest_uptime = $nodeInfo->uptime ?? null; + $nodeInfo_uptime = $nodeInfo->uptime ?? null; + $nodeInfo_block_height = $nodeInfo->block_height ?? null; + $nodeInfo_update_responsiveness = $nodeInfo->update_responsiveness ?? null; + $nodeInfo_peers = $nodeInfo->peers ?? null; + + $metric->avg_uptime = $nodeInfo_uptime ?? $metric_uptime; + $metric->avg_block_height_average = $nodeInfo_block_height ?? $metric_block_height; + $metric->avg_update_responsiveness = $nodeInfo_update_responsiveness ?? $metric_update_responsiveness; + $metric->avg_peers = $nodeInfo_peers ?? $metric_peers; + + $metric->max_peers = $max_peers; + $metric->max_update_responsiveness = $max_update_responsiveness; + $metric->max_block_height_average = $max_block_height; + $metric->max_uptime = $max_uptime; + + $metric->peers = $latest_peers ?? $metric_peers; + $metric->update_responsiveness = $latest_update_responsiveness ?? $metric_update_responsiveness; + $metric->block_height_average = $latest_block_height ?? $metric_block_height; + $metric->uptime = $latest_uptime ?? $metric_uptime; + + $monitoringCriteria = MonitoringCriteria::get(); + $nodeInfo = NodeInfo::where('node_address', strtolower($user->public_address_node))->first(); + + $rank = $user->rank; + $totalCount = User::select([ + 'id as user_id', + 'public_address_node', + 'is_fail_node', + 'rank', + ]) + ->where('banned', 0) + ->whereNotNull('public_address_node') + ->get() + ->count(); + + $delegators = 0; + $stake_amount = 0; + $self_stake_amount = 0; + if ($nodeInfo) { + $delegators = $nodeInfo->delegators_count; + $stake_amount = $nodeInfo->total_staked_amount; + $self_stake_amount = $nodeInfo->self_staked_amount; + } + $mbs = NodeInfo::max('mbs'); + $metric->mbs = $mbs; + $metric->rank = $rank; + $metric->totalCount = $totalCount; + $metric->delegators = $delegators; + $metric->stake_amount = $stake_amount; + $metric->self_stake_amount = $self_stake_amount; + $metric['node_status'] = $user->node_status; + $metric['monitoring_criteria'] = $monitoringCriteria; + + $setting = Setting::where('name', 'peers')->first(); + if ($setting) { + $metric['peers_setting'] = (int) $setting->value; + } else { + $metric['peers_setting'] = 0; + } + + return $this->successResponse($metric); + } + + public function updateMetric(Request $request, $id) + { + $validator = Validator::make($request->all(), [ + 'uptime' => 'nullable|numeric|between:0,100', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $user = User::where('id', $id)->where('role', 'member')->first(); + if (!$user) { + return $this->errorResponse('User not found', Response::HTTP_BAD_REQUEST); + } + $metric = Metric::where('user_id', $id)->first(); + if (!$metric) { + $metric = new Metric(); + } + if (isset($request->uptime) && $request->uptime != null) { + $metric->uptime = $request->uptime; + } + if (isset($request->block_height_average) && $request->block_height_average != null) { + $metric->block_height_average = $request->block_height_average; + } + if (isset($request->update_responsiveness) && $request->update_responsiveness != null) { + $metric->update_responsiveness = $request->update_responsiveness; + } + if (isset($request->peers) && $request->peers != null) { + $metric->peers = $request->peers; + } + $metric->user_id = $id; + $metric->save(); + return $this->successResponse($metric); + } + + public function getMetricUser($id) + { + $user = User::find($id); + if (!$user) { + return $this->successResponse([]); + } + + $max_update_responsiveness = DB::select("SELECT max(update_responsiveness) as max_update_responsiveness FROM + ( + SELECT MAX(update_responsiveness) as update_responsiveness FROM metric + UNION + SELECT MAX(update_responsiveness) as update_responsiveness FROM node_info + ) AS results + ;"); + $max_update_responsiveness = $max_update_responsiveness[0]->max_update_responsiveness ?? 0; + + $max_peers = DB::select("SELECT max(peers) as max_peers FROM + ( + SELECT MAX(peers) as peers FROM metric + UNION + SELECT MAX(peers) as peers FROM node_info + ) AS results + ;"); + $max_peers = $max_peers[0]->max_peers ?? 0; + $max_block_height = Node::max('block_height'); + $max_uptime = DB::select("SELECT max(uptime) as max_uptime FROM + ( + SELECT MAX(uptime) as uptime FROM metric + UNION + SELECT MAX(uptime) as uptime FROM node_info + ) AS results + ;"); + $max_uptime = $max_uptime[0]->max_uptime ?? 0; + $latest = Node::where('node_address', strtolower($user->public_address_node)) + ->whereNotnull('protocol_version') + ->orderBy('created_at', 'desc') + ->first(); + if (!$latest) { + $latest = new Node(); + } + $latest_block_height = $latest->block_height ?? null; + $latest_update_responsiveness = $latest->update_responsiveness ?? null; + $latest_peers = $latest->peers ?? null; + + $metric = Metric::where('user_id', $user->id)->first(); + if (!$metric) { + $metric = new Metric(); + } + $metric_uptime = $metric->uptime ?? null; + $metric_block_height = $metric->block_height_average ? ($max_block_height - $metric->block_height_average) : null; + $metric_update_responsiveness = $metric->update_responsiveness ?? null; + $metric_peers = $metric->peers ?? null; + + $nodeInfo = NodeInfo::where('node_address', strtolower($user->public_address_node))->first(); + if (!$nodeInfo) { + $nodeInfo = new NodeInfo(); + } + $latest_uptime = $nodeInfo->uptime ?? null; + $nodeInfo_uptime = $nodeInfo->uptime ?? null; + $nodeInfo_block_height = $nodeInfo->block_height ?? null; + $nodeInfo_update_responsiveness = $nodeInfo->update_responsiveness ?? null; + $nodeInfo_peers = $nodeInfo->peers ?? null; + + $metric->avg_uptime = $nodeInfo_uptime ?? $metric_uptime; + $metric->avg_block_height_average = $nodeInfo_block_height ?? $metric_block_height; + $metric->avg_update_responsiveness = $nodeInfo_update_responsiveness ?? $metric_update_responsiveness; + $metric->avg_peers = $nodeInfo_peers ?? $metric_peers; + + $metric->max_peers = $max_peers; + $metric->max_update_responsiveness = $max_update_responsiveness; + $metric->max_block_height_average = $max_block_height; + $metric->max_uptime = $max_uptime; + + $metric->peers = $latest_peers ?? $metric_peers; + $metric->update_responsiveness = $latest_update_responsiveness ?? $metric_update_responsiveness; + $metric->block_height_average = $latest_block_height ?? $metric_block_height; + $metric->uptime = $latest_uptime ?? $metric_uptime; + + $monitoringCriteria = MonitoringCriteria::get(); + $nodeInfo = NodeInfo::where('node_address', strtolower($user->public_address_node))->first(); + + $rank = $user->rank; + $totalCount = User::select([ + 'id as user_id', + 'public_address_node', + 'is_fail_node', + 'rank', + ]) + ->where('banned', 0) + ->whereNotNull('public_address_node') + ->get() + ->count(); + + $delegators = 0; + $stake_amount = 0; + $self_stake_amount = 0; + if ($nodeInfo) { + $delegators = $nodeInfo->delegators_count; + $stake_amount = $nodeInfo->total_staked_amount; + $self_stake_amount = $nodeInfo->self_staked_amount; + } + $mbs = NodeInfo::max('mbs'); + $metric->mbs = $mbs; + $metric->rank = $rank; + $metric->totalCount = $totalCount; + $metric->delegators = $delegators; + $metric->stake_amount = $stake_amount; + $metric->self_stake_amount = $self_stake_amount; + $metric['node_status'] = $user->node_status; + $metric['monitoring_criteria'] = $monitoringCriteria; + + return $this->successResponse($metric); + } + + public function getMetricUserOld($id) + { + $metric = Metric::where('user_id', $id)->first(); + if (!$metric) { + return $this->successResponse([]); + } + return $this->successResponse($metric); + } + + public function getMetricUserByNodeName($node) + { + $node = strtolower($node); + $user = User::where('public_address_node', $node)->first(); + if ($user) { + $max_update_responsiveness = DB::select("SELECT max(update_responsiveness) as max_update_responsiveness FROM + ( + SELECT MAX(update_responsiveness) as update_responsiveness FROM metric + UNION + SELECT MAX(update_responsiveness) as update_responsiveness FROM node_info + ) AS results + ;"); + $max_update_responsiveness = $max_update_responsiveness[0]->max_update_responsiveness ?? 0; + + $max_peers = DB::select("SELECT max(peers) as max_peers FROM + ( + SELECT MAX(peers) as peers FROM metric + UNION + SELECT MAX(peers) as peers FROM node_info + ) AS results + ;"); + $max_peers = $max_peers[0]->max_peers ?? 0; + $max_block_height = Node::max('block_height'); + $max_uptime = DB::select("SELECT max(uptime) as max_uptime FROM + ( + SELECT MAX(uptime) as uptime FROM metric + UNION + SELECT MAX(uptime) as uptime FROM node_info + ) AS results + ;"); + $max_uptime = $max_uptime[0]->max_uptime ?? 0; + + $latest = Node::where('node_address', strtolower($user->public_address_node))->whereNotnull('protocol_version')->orderBy('created_at', 'desc')->first(); + if (!$latest) { + $latest = new Node(); + } + $latest_block_height = $latest->block_height ?? null; + $latest_update_responsiveness = $latest->update_responsiveness ?? null; + $latest_peers = $latest->peers ?? null; + + $metric = Metric::where('user_id', $user->id)->first(); + if (!$metric) { + $metric = new Metric(); + } + $metric_uptime = $metric->uptime ?? null; + $metric_block_height = $metric->block_height_average ? ($max_block_height - $metric->block_height_average) : null; + $metric_update_responsiveness = $metric->update_responsiveness ?? null; + $metric_peers = $metric->peers ?? null; + + $nodeInfo = NodeInfo::where('node_address', strtolower($user->public_address_node))->first(); + if (!$nodeInfo) { + $nodeInfo = new NodeInfo(); + } + $latest_uptime = $nodeInfo->uptime ?? null; + $nodeInfo_uptime = $nodeInfo->uptime ?? null; + $nodeInfo_block_height = $nodeInfo->block_height ?? null; + $nodeInfo_peers = $nodeInfo->peers ?? null; + $nodeInfo_update_responsiveness = $nodeInfo->update_responsiveness ?? null; + + $metric->avg_uptime = $nodeInfo_uptime ?? $metric_uptime; + $metric->avg_block_height_average = $nodeInfo_block_height ?? $metric_block_height; + $metric->avg_update_responsiveness = $nodeInfo_update_responsiveness ?? $metric_update_responsiveness; + $metric->avg_peers = $nodeInfo_peers ?? $metric_peers; + + $metric->max_peers = $max_peers; + $metric->max_update_responsiveness = $max_update_responsiveness; + $metric->max_block_height_average = $max_block_height; + $metric->max_uptime = $max_uptime; + + $metric->peers = $latest_peers ?? $metric_peers; + $metric->update_responsiveness = $latest_update_responsiveness ?? $metric_update_responsiveness; + $metric->block_height_average = $latest_block_height ?? $metric_block_height; + $metric->uptime = $latest_uptime ?? $metric_uptime; + + $monitoringCriteria = MonitoringCriteria::get(); + $nodeInfo = NodeInfo::where('node_address', strtolower($user->public_address_node))->first(); + $rank = $user->rank; + $delegators = 0; + $stake_amount = 0; + $self_stake_amount = 0; + $is_open_port = 0; + if ($nodeInfo) { + $delegators = $nodeInfo->delegators_count; + $stake_amount = $nodeInfo->total_staked_amount; + $self_stake_amount = $nodeInfo->self_staked_amount; + $is_open_port = $nodeInfo->is_open_port; + } + $mbs = NodeInfo::max('mbs'); + $metric->mbs = $mbs; + $metric->rank = $rank; + $metric->is_open_port = $is_open_port; + $metric->delegators = $delegators; + $metric->self_stake_amount = $self_stake_amount; + $metric['node_status'] = $user->node_status; + $metric['monitoring_criteria'] = $monitoringCriteria; + return $this->successResponse($metric); + } + return $this->successResponse([]); + } +} diff --git a/app/Http/Controllers/Api/V1/NotificationController.php b/app/Http/Controllers/Api/V1/NotificationController.php new file mode 100644 index 00000000..d1f5358b --- /dev/null +++ b/app/Http/Controllers/Api/V1/NotificationController.php @@ -0,0 +1,367 @@ +<?php + +namespace App\Http\Controllers\Api\V1; + +use App\Http\Controllers\Controller; +use App\Models\Notification; +use App\Models\NotificationView; +use App\Models\User; +use Carbon\Carbon; +use Illuminate\Http\Request; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Validator; + +class NotificationController extends Controller +{ + public function getHighPriority() + { + $data = Notification::where('high_priority', 1)->where('type', 'Banner')->first(); + return $this->successResponse($data); + } + + public function getNotificationUser(Request $request) + { + $data = []; + $type = $request->type ?? ''; + $user = auth()->user(); + $ids = NotificationView::join('notification', 'notification.id', '=', 'notification_view.notification_id') + ->where('visibility', 'visible') + ->where(function ($query) { + $query->where(function ($query) { + $query->where('type', 'Popup') + ->where('show_login', 0);}) + ->orWhere(function ($query) { + $query->where('type', 'Banner') + ->whereNotNull('notification_view.dismissed_at'); + }); + })->where('notification_view.user_id', $user->id) + ->select(['notification_view.notification_id'])->groupBy('notification_view.notification_id')->get(); + if ($type) { + $data = Notification::where('visibility', 'visible') + ->where('type', $type) + ->whereNotIn('id', $ids)->get(); + } else { + $data = Notification::where('visibility', 'visible')->whereNotIn('id', $ids)->get(); + } + + return $this->successResponse($data); + } + + public function dismiss($id) + { + $user = auth()->user(); + $notification = Notification::where('id', $id)->where('type', 'Banner')->where('visibility', 'visible')->first(); + if (!$notification) { + return $this->errorResponse('Not found notification', Response::HTTP_BAD_REQUEST); + } + $notificationView = NotificationView::where('notification_id', $id)->where('user_id', $user->id)->first(); + if (!$notificationView) { + $notificationView = new notificationView(); + $notificationView->user_id = $user->id; + $notificationView->notification_id = $id; + $notificationView->first_view_at = now(); + $notificationView->dismissed_at = now(); + $notificationView->save(); + + $notification->total_views = $notification->total_views + 1; + $notification->save(); + } else { + if (!$notificationView->dismissed_at) { + $notificationView->dismissed_at = now(); + $notificationView->save(); + } + } + + return $this->metaSuccess(); + } + + public function clickCTA($id) + { + $user = auth()->user(); + $notification = Notification::where('id', $id)->where('visibility', 'visible')->first(); + if (!$notification) { + return $this->errorResponse('Not found notification', Response::HTTP_BAD_REQUEST); + } + $notificationView = NotificationView::where('notification_id', $id)->where('user_id', $user->id)->first(); + if (!$notificationView) { + $notificationView = new notificationView(); + $notificationView->user_id = $user->id; + $notificationView->notification_id = $id; + $notificationView->first_view_at = now(); + $notificationView->cta_click_at = now(); + $notificationView->cta_click_count = $notificationView->cta_click_count + 1; + $notificationView->save(); + + $notification->total_views = $notification->total_views + 1; + $notification->save(); + } else { + if (!$notificationView->cta_click_at) { + $notificationView->cta_click_at = now(); + } + $notificationView->cta_click_count = $notificationView->cta_click_count + 1; + $notificationView->save(); + } + + return $this->metaSuccess(); + } + + public function updateView($id) + { + $user = auth()->user(); + $notification = Notification::where('id', $id)->where('visibility', 'visible')->first(); + if (!$notification) { + return $this->errorResponse('Not found notification', Response::HTTP_BAD_REQUEST); + } + $notificationView = NotificationView::where('notification_id', $id)->where('user_id', $user->id)->first(); + if (!$notificationView) { + $notificationView = new notificationView(); + $notificationView->user_id = $user->id; + $notificationView->notification_id = $id; + $notificationView->first_view_at = now(); + $notificationView->save(); + + $notification->total_views = $notification->total_views + 1; + $notification->save(); + } + + return $this->metaSuccess(); + } + + public function getNotification(Request $request) + { + $limit = $request->limit ?? 50; + $sort_key = $request->sort_key ?? 'created_at'; + $sort_direction = $request->sort_direction ?? 'desc'; + if (isset($request->setting)) { + $notification = Notification::where('setting', $request->setting)->orderBy($sort_key, $sort_direction)->paginate($limit); + } else { + $notification = Notification::orderBy($sort_key, $sort_direction)->paginate($limit); + } + $ids = []; + foreach ($notification as $notif) { + array_push($ids, $notif->id); + } + $count = User::where('role', 'member')->whereNotNull('letter_verified_at') + ->whereNotNull('node_verified_at')->whereNotNull('signature_request_id') + ->orderBy($sort_key, $sort_direction)->count(); + $data = ["notifications" => $notification, "total_member" => $count, "ids" => $ids]; + return $this->successResponse($data); + } + + public function getUserViewLogs(Request $request, $id) + { + $limit = $request->limit ?? 50; + $sort_key = $request->sort_key ?? 'created_at'; + $sort_direction = $request->sort_direction ?? 'desc'; + $notification = Notification::where('id', $id)->first(); + if (!$notification) { + return $this->errorResponse('Not found notification', Response::HTTP_BAD_REQUEST); + } + $count = User::where('role', 'member')->whereNotNull('letter_verified_at') + ->whereNotNull('node_verified_at')->whereNotNull('signature_request_id') + ->orderBy($sort_key, $sort_direction)->count(); + + $notificationView = NotificationView::where('notification_id', $id) + ->orderBy($sort_key, $sort_direction) + ->with('user')->paginate($limit); + $data = ["notification" => $notification, "total_member" => $count, "users" => $notificationView]; + return $this->successResponse($data); + } + + public function createNotification(Request $request) + { + $validatorType = Validator::make($request->all(), [ + 'type' => 'required|in:Banner,Popup', + 'have_action' => 'required|in:0,1', + 'action_link' => 'nullable|url', + 'start_date' => 'nullable|date_format:Y-m-d', + 'end_date' => 'nullable|date_format:Y-m-d|after_or_equal:today', + 'setting' => 'required|in:0,1', + 'body' => 'required|string|max:200', + ]); + if ($validatorType->fails()) { + return $this->validateResponse($validatorType->errors()); + } + $type = $request->type; + if ($type == 'Banner') { + $validator = Validator::make($request->all(), [ + 'high_priority' => 'required|in:0,1', + 'allow_dismiss_btn' => 'required|in:0,1', + 'title' => 'required|string|max:60', + ]); + } else { + $validator = Validator::make($request->all(), [ + 'show_login' => 'required|in:0,1', + 'title' => 'required|string|max:150', + 'btn_text' => 'nullable|string|max:25', + ]); + } + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $now = Carbon::now()->format('Y-m-d'); + $notification = new Notification(); + $startDate = $request->start_date; + $endDate = $request->end_date; + $setting = $request->setting; + $visibility = 'hidden'; + $status = 'OFF'; + + if ($startDate && $endDate && $startDate > $endDate) { + return $this->errorResponse('End date must greater than start date', Response::HTTP_BAD_REQUEST); + } + + $notification->type = $type; + $notification->title = $request->title; + $notification->body = $request->body; + $notification->have_action = $request->have_action; + $notification->action_link = $request->action_link; + $notification->start_date = $request->start_date; + $notification->end_date = $request->end_date; + $notification->setting = $request->setting; + if ($type == 'Banner') { + $notification->high_priority = $request->high_priority; + $notification->allow_dismiss_btn = $request->allow_dismiss_btn; + } else { + $notification->show_login = $request->show_login; + $notification->btn_text = $request->btn_text; + } + + // check visibility and status + if ($setting == 1) { + if ($startDate && $endDate && ($now >= $startDate && $now <= $endDate)) { + $visibility = 'visible'; + $status = 'active'; + } + if (!$startDate && !$endDate) { + $visibility = 'visible'; + $status = 'active'; + } + if ($endDate && $endDate >= $now) { + $visibility = 'visible'; + $status = 'active'; + } + if ($startDate && $startDate > $now) { + $visibility = 'hidden'; + $status = 'waiting'; + } + if ($startDate && $startDate <= $now) { + $visibility = 'visible'; + $status = 'active'; + } + } else { + $visibility = 'hidden'; + $status = 'OFF'; + } + $notification->visibility = $visibility; + $notification->status = $status; + $notification->save(); + return $this->successResponse($notification); + } + + public function updateNotification(Request $request, $id) + { + $validatorType = Validator::make($request->all(), [ + 'type' => 'required|in:Banner,Popup', + 'have_action' => 'required|in:0,1', + 'action_link' => 'nullable|url', + 'start_date' => 'nullable|date_format:Y-m-d', + 'end_date' => 'nullable|date_format:Y-m-d|after_or_equal:today', + 'setting' => 'required|in:0,1', + 'body' => 'required|string|max:200', + ]); + if ($validatorType->fails()) { + return $this->validateResponse($validatorType->errors()); + } + $type = $request->type; + if ($type == 'Banner') { + $validator = Validator::make($request->all(), [ + 'high_priority' => 'required|in:0,1', + 'allow_dismiss_btn' => 'required|in:0,1', + 'title' => 'required|string|max:60', + ]); + } else { + $validator = Validator::make($request->all(), [ + 'show_login' => 'required|in:0,1', + 'title' => 'required|string|max:150', + 'btn_text' => 'nullable|string|max:25', + ]); + } + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $now = Carbon::now()->format('Y-m-d'); + $notification = Notification::where('id', $id)->first(); + if (!$notification) { + return $this->errorResponse('Not found notification', Response::HTTP_BAD_REQUEST); + } + $startDate = $request->start_date; + $endDate = $request->end_date; + $setting = $request->setting; + $visibility = 'hidden'; + $status = 'OFF'; + + if ($startDate && $endDate && $startDate > $endDate) { + return $this->errorResponse('End date must greater than start date', Response::HTTP_BAD_REQUEST); + } + + $notification->type = $type; + $notification->title = $request->title; + $notification->body = $request->body; + $notification->have_action = $request->have_action; + $notification->action_link = $request->action_link; + $notification->start_date = $request->start_date; + $notification->end_date = $request->end_date; + $notification->setting = $request->setting; + if ($type == 'Banner') { + $notification->high_priority = $request->high_priority; + $notification->allow_dismiss_btn = $request->allow_dismiss_btn; + } else { + $notification->show_login = $request->show_login; + $notification->btn_text = $request->btn_text; + } + + // check visibility and status + if ($setting == 1) { + if ($startDate && $endDate && ($now >= $startDate && $now <= $endDate)) { + $visibility = 'visible'; + $status = 'active'; + } + if (!$startDate && !$endDate) { + $visibility = 'visible'; + $status = 'active'; + } + if ($endDate && $endDate >= $now) { + $visibility = 'visible'; + $status = 'active'; + } + if ($startDate && $startDate > $now) { + $visibility = 'hidden'; + $status = 'waiting'; + } + if ($startDate && $startDate <= $now) { + $visibility = 'visible'; + $status = 'active'; + } + } else { + $visibility = 'hidden'; + $status = 'OFF'; + } + $notification->visibility = $visibility; + $notification->status = $status; + $notification->save(); + return $this->successResponse($notification); + } + + public function getNotificationDetail($id) + { + $notification = Notification::where('id', $id)->first(); + if (!$notification) { + return $this->errorResponse('Not found notification', Response::HTTP_BAD_REQUEST); + } + + return $this->successResponse($notification); + } +} diff --git a/app/Http/Controllers/Api/V1/PerkController.php b/app/Http/Controllers/Api/V1/PerkController.php new file mode 100644 index 00000000..dc2bef5a --- /dev/null +++ b/app/Http/Controllers/Api/V1/PerkController.php @@ -0,0 +1,314 @@ +<?php + +namespace App\Http\Controllers\Api\V1; + +use App\Http\Controllers\Controller; + +use App\Models\Perk; +use App\Models\PerkResult; + +use Carbon\Carbon; + +use Illuminate\Http\Request; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Str; + +use Aws\S3\S3Client; + +class PerkController extends Controller +{ + public function createPerk(Request $request) { + $validator = Validator::make($request->all(), [ + 'title' => 'required|string|max:70', + 'content' => 'required', + 'action_link' => 'required|url', + 'image' => 'required|mimes:jpeg,jpg,png,gif|max:100000', + 'start_date' => 'required|nullable|date_format:Y-m-d', + 'end_date' => 'required|nullable|date_format:Y-m-d|after_or_equal:today', + 'start_time' => 'required|nullable|date_format:H:i:s', + 'end_time' => 'required|nullable|date_format:H:i:s', + 'setting' => 'required|in:0,1', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + $user = auth()->user(); + $now = Carbon::now()->format('Y-m-d'); + $perk = new Perk(); + $startDate = $request->start_date; + $endDate = $request->end_date; + $setting = $request->setting; + $visibility = 'hidden'; + $status = 'inactive'; + + if ($startDate && $endDate && $startDate > $endDate) { + return $this->errorResponse('End date must greater than start date', Response::HTTP_BAD_REQUEST); + } + + $perk->user_id = $user->id; + $perk->title = $request->title; + $perk->content = $request->content; + $perk->action_link = $request->action_link; + $perk->start_date = $request->start_date; + $perk->end_date = $request->end_date; + $perk->start_time = $request->start_time; + $perk->end_time = $request->end_time; + $perk->setting = $request->setting; + + $filenameWithExt = $request->file('image')->getClientOriginalName(); + //Get just filename + $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME); + // Get just ext + $extension = $request->file('image')->getClientOriginalExtension(); + + $filenamehash = md5(Str::random(10) . '_' . (string)time()); + // Filename to store + $fileNameToStore = $filenamehash . '.' . $extension; + + // S3 file upload + $S3 = new S3Client([ + 'version' => 'latest', + 'region' => getenv('AWS_DEFAULT_REGION'), + 'credentials' => [ + 'key' => getenv('AWS_ACCESS_KEY_ID'), + 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), + ], + ]); + + $s3result = $S3->putObject([ + 'Bucket' => getenv('AWS_BUCKET'), + 'Key' => 'client_uploads/' . $fileNameToStore, + 'SourceFile' => $request->file('image') + ]); + + // $ObjectURL = 'https://'.getenv('AWS_BUCKET').'.s3.amazonaws.com/client_uploads/'.$fileNameToStore; + $ObjectURL = $s3result['ObjectURL'] ?? getenv('SITE_URL') . '/not-found'; + $perk->image = $ObjectURL; + + // check visibility and status + if ($setting == 1) { + if ($startDate && $endDate && ($now >= $startDate && $now <= $endDate)) { + $visibility = 'visible'; + $status = 'active'; + } + if (!$startDate && !$endDate) { + $visibility = 'visible'; + $status = 'active'; + } + if ($endDate && $endDate >= $now) { + $visibility = 'visible'; + $status = 'active'; + } + if ($startDate && $startDate > $now) { + $visibility = 'hidden'; + $status = 'waiting'; + } + if ($startDate && $startDate <= $now) { + $visibility = 'visible'; + $status = 'active'; + } + } else { + $visibility = 'hidden'; + $status = 'inactive'; + } + $perk->visibility = $visibility; + $perk->status = $status; + $perk->save(); + return $this->successResponse($perk); + } + + public function getPerksAdmin(Request $request) + { + $limit = $request->limit ?? 50; + $sort_key = $request->sort_key ?? 'end_date'; + $sort_direction = $request->sort_direction ?? 'desc'; + if (isset($request->setting)) { + $perks = Perk::where('setting', $request->setting)->orderBy($sort_key, $sort_direction)->paginate($limit); + } else { + $perks = Perk::orderBy($sort_key, $sort_direction)->paginate($limit); + } + return $this->successResponse($perks); + } + + public function getPerkDetailAdmin($id) + { + $perk = Perk::where('id', $id)->first(); + if (!$perk) { + return $this->errorResponse('Not found perk', Response::HTTP_BAD_REQUEST); + } + return $this->successResponse($perk); + } + public function updatePerk(Request $request, $id) + { + $data = $request->all(); + $validator = Validator::make($request->all(), [ + 'title' => 'nullable|string|max:70', + 'content' => 'nullable', + 'action_link' => 'nullable|url', + 'image' => 'nullable|mimes:jpeg,jpg,png,gif|max:100000', + 'start_date' => 'required|nullable', + 'end_date' => 'required|nullable', + 'start_time' => 'required|nullable|date_format:H:i:s', + 'end_time' => 'required|nullable|date_format:H:i:s', + 'setting' => 'nullable|in:0,1', + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $user = auth()->user(); + $now = Carbon::now()->format('Y-m-d'); + $perk = Perk::where('id', $id)->first(); + if (!$perk) { + return $this->errorResponse('Not found perk', Response::HTTP_BAD_REQUEST); + } + $startDate = array_key_exists('start_date', $data) ? $request->start_date : $perk->start_date; + $endDate = array_key_exists('end_date', $data) ? $request->end_date : $perk->end_date; + $setting = isset($request->setting) ? $request->setting : $perk->setting; + + $visibility = 'hidden'; + $status = 'inactive'; + if ($startDate && $endDate && $startDate > $endDate) { + return $this->errorResponse('End date must greater than start date', Response::HTTP_BAD_REQUEST); + } + if ($request->title) { + $perk->title = $request->title; + } + if ($request->content) { + $perk->content = $request->content; + } + + $perk->start_date = $request->start_date; + $perk->end_date = $request->end_date; + $perk->start_time = $request->start_time; + $perk->end_time = $request->end_time; + + if (isset($request->setting)) { + $perk->setting = $request->setting; + } + if ($request->hasFile('image')) { + $extension = $request->file('image')->getClientOriginalExtension(); + $filenamehash = md5(Str::random(10) . '_' . (string)time()); + $fileNameToStore = $filenamehash . '.' . $extension; + + // S3 file upload + $S3 = new S3Client([ + 'version' => 'latest', + 'region' => getenv('AWS_DEFAULT_REGION'), + 'credentials' => [ + 'key' => getenv('AWS_ACCESS_KEY_ID'), + 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), + ], + ]); + + $s3result = $S3->putObject([ + 'Bucket' => getenv('AWS_BUCKET'), + 'Key' => 'client_uploads/'.$fileNameToStore, + 'SourceFile' => $request->file('image') + ]); + + // $ObjectURL = 'https://'.getenv('AWS_BUCKET').'.s3.amazonaws.com/client_uploads/'.$fileNameToStore; + $ObjectURL = $s3result['ObjectURL'] ?? getenv('SITE_URL').'/not-found'; + $perk->image = $ObjectURL; + } + + // check visibility and status + if ($setting == 1) { + if ($startDate && $endDate && ($now >= $startDate && $now <= $endDate)) { + $visibility = 'visible'; + $status = 'active'; + } + if (!$startDate && !$endDate) { + $visibility = 'visible'; + $status = 'active'; + } + if ($endDate && $endDate >= $now) { + $visibility = 'visible'; + $status = 'active'; + } + if ($endDate && $endDate < $now) { + $visibility = 'hidden'; + $status = 'expired'; + } + if ($startDate && $startDate > $now) { + $visibility = 'hidden'; + $status = 'waiting'; + } + if ($startDate && $startDate <= $now) { + $visibility = 'visible'; + $status = 'active'; + } + } else { + $visibility = 'hidden'; + $status = 'inactive'; + } + $perk->visibility = $visibility; + $perk->status = $status; + $perk->save(); + return $this->successResponse($perk); + } + + public function deletePerk($id) + { + PerkResult::where('perk_id', $id)->delete(); + Perk::where('id', $id)->delete(); + return $this->metaSuccess(); + } + + public function getPerkResultAdmin(Request $request, $id) + { + $limit = $request->limit ?? 50; + $sort_key = $request->sort_key ?? 'perk_result.created_at'; + $sort_direction = $request->sort_direction ?? 'desc'; + $perk = PerkResult::join('perk', 'perk_result.perk_id', '=', 'perk.id') + ->join('users', 'perk.user_id', '=', 'users.id')->where('perk_result.perk_id', $id) + ->select([ + 'perk_result.user_id', + 'perk_result.perk_id', + 'perk_result.created_at', + 'perk_result.views', + 'perk.total_views', + 'perk.total_clicks', + 'users.email', + ])->orderBy($sort_key, $sort_direction)->paginate($limit); + return $this->successResponse($perk); + } + + public function getPerksUser(Request $request) + { + $user = auth()->user(); + $limit = $request->limit ?? 50; + $sort_key = $request->sort_key ?? 'created_at'; + $sort_direction = $request->sort_direction ?? 'desc'; + $perks = Perk::where('visibility', 'visible')->orderBy($sort_key, $sort_direction)->paginate($limit); + return $this->successResponse($perks); + } + + public function getPerkDetailUser($id) + { + $user = auth()->user(); + $perk = Perk::where('visibility', 'visible')->where('id', $id)->first(); + if (!$perk) { + return $this->errorResponse('Not found perk', Response::HTTP_BAD_REQUEST); + } + $perkResul = PerkResult::where('perk_id', $id)->where('user_id', $user->id)->first(); + if ($perkResul) { + $perk->total_views = $perk->total_views + 1; + + $perkResul->views = $perkResul->views +1; + $perkResul->save(); + } else { + $newPerkResult = new PerkResult(); + $newPerkResult->perk_id = $id; + $newPerkResult->user_id = $user->id; + $newPerkResult->views = 1; + $newPerkResult->save(); + + $perk->total_views = $perk->total_views + 1; + $perk->total_clicks = $perk->total_clicks + 1; + } + $perk->save(); + return $this->successResponse($perk); + } +} diff --git a/app/Http/Controllers/Api/V1/UserController.php b/app/Http/Controllers/Api/V1/UserController.php index 9eb7545e..e78acfc9 100644 --- a/app/Http/Controllers/Api/V1/UserController.php +++ b/app/Http/Controllers/Api/V1/UserController.php @@ -2,7 +2,11 @@ namespace App\Http\Controllers\Api\V1; +use App\Console\Helper; + use App\Http\Controllers\Controller; +use App\Http\EmailerHelper; + use App\Http\Requests\Api\AddOwnerNodeRequest; use App\Http\Requests\Api\ChangeEmailRequest; use App\Http\Requests\Api\ChangePasswordRequest; @@ -10,22 +14,46 @@ use App\Http\Requests\Api\SubmitKYCRequest; use App\Http\Requests\Api\SubmitPublicAddressRequest; use App\Http\Requests\Api\VerifyFileCasperSignerRequest; + use App\Mail\AddNodeMail; +use App\Mail\LoginTwoFA; +use App\Mail\UserConfirmEmail; use App\Mail\UserVerifyMail; + +use App\Models\Ballot; +use App\Models\BallotFile; +use App\Models\BallotFileView; +use App\Models\LockRules; +use App\Models\Metric; +use App\Models\MonitoringCriteria; +use App\Models\DiscussionPin; +use App\Models\Donation; +use App\Models\MembershipAgreementFile; +use App\Models\Node; +use App\Models\NodeInfo; use App\Models\OwnerNode; use App\Models\Profile; +use App\Models\Shuftipro; use App\Models\ShuftiproTemp; use App\Models\User; use App\Models\VerifyUser; +use App\Models\Vote; +use App\Models\VoteResult; + use App\Repositories\OwnerNodeRepository; use App\Repositories\ProfileRepository; use App\Repositories\UserRepository; use App\Repositories\VerifyUserRepository; + use App\Services\CasperSignature; use App\Services\CasperSigVerify; -use App\Services\ShuftiproCheck; +use App\Services\NodeHelper; use App\Services\Test; -use Exception; +use App\Services\ChecksumValidator; +use App\Services\ShuftiproCheck as ServicesShuftiproCheck; + +use Carbon\Carbon; + use Illuminate\Validation\Rule; use Illuminate\Http\Request; use Illuminate\Http\Response; @@ -35,6 +63,11 @@ use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Str; + +use Aws\S3\S3Client; + +use Exception; class UserController extends Controller { @@ -61,6 +94,110 @@ public function __construct( $this->ownerNodeRepo = $ownerNodeRepo; } + public function getMemberCountInfo() { + $data = [ + 'total' => 0, + 'verified' => 0, + ]; + + $data['total'] = User::count(); + $data['verified'] = User::join('profile', 'profile.user_id', '=', 'users.id') + ->where('profile.status', 'approved') + ->whereNotNull('users.public_address_node') + ->get() + ->count(); + + return $this->successResponse($data); + } + + // Get Verified Members + public function getVerifiedMembers() { + $data = []; + $limit = $request->limit ?? 50; + $user = auth()->user(); + + $data = User::select([ + 'users.id', + 'users.pseudonym', + 'users.public_address_node', + 'users.node_status', + 'profile.extra_status', + ]) + ->join('profile', 'profile.user_id', '=', 'users.id') + ->where('profile.status', 'approved') + ->whereNotNull('users.public_address_node') + ->paginate($limit); + + return $this->successResponse($data); + } + + // Shuftipro Webhook + public function updateShuftiproStatus() { + $json = file_get_contents('php://input'); + + if ($json) { + $data = json_decode($json, true); + + if ($data && isset($data['reference'])) { + $shuftiproCheck = new ServicesShuftiproCheck(); + + $reference_id = $data['reference']; + + $record = Shuftipro::where('reference_id', $reference_id)->first(); + $recordTemp = ShuftiproTemp::where('reference_id', $reference_id)->first(); + + if (!$recordTemp) { + return; + } + + if ($record) { + if (isset($data['event']) && $data['event'] == 'request.deleted') { + // Reset Action + $user = User::find($record->user_id); + + if ($user) { + $user_id = $user->id; + $profile = Profile::where('user_id', $user_id)->first(); + + if ($profile) { + $profile->status = null; + $profile->save(); + } + + Shuftipro::where('user_id', $user->id)->delete(); + ShuftiproTemp::where('user_id', $user->id)->delete(); + } + return; + } + $shuftiproCheck->handleExisting($record); + } else { + $events = [ + 'verification.accepted', + 'verification.declined', + ]; + if (isset($data['event']) && in_array($data['event'], $events)) { + $user = User::find($recordTemp->user_id); + + if ($user) { + $user_id = $user->id; + $profile = Profile::where('user_id', $user_id)->first(); + + if ($profile) { + $profile->status = 'pending'; + $profile->save(); + } + + $recordTemp->status = 'booked'; + $recordTemp->save(); + + $shuftiproCheck->handle($recordTemp); + } + } + } + } + } + } + /** * change email */ @@ -109,7 +246,9 @@ public function changePassword(ChangePasswordRequest $request) */ public function getProfile() { - $user = auth()->user()->load('profile'); + $user = auth()->user()->load(['profile', 'permissions', 'shuftipro', 'shuftiproTemp']); + Helper::getAccountInfoStandard($user); + $user->metric = Helper::getNodeInfo($user); return $this->successResponse($user); } @@ -130,23 +269,47 @@ public function uploadLetter(Request $request) try { // Validator $validator = Validator::make($request->all(), [ - 'file' => 'required|mimes:pdf|max:20000', + 'file' => 'required|mimes:pdf,docx,doc,txt,rtf|max:20000', ]); + if ($validator->fails()) { return $this->validateResponse($validator->errors()); } + $user = auth()->user(); $filenameWithExt = $request->file('file')->getClientOriginalName(); //Get just filename $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME); // Get just ext $extension = $request->file('file')->getClientOriginalExtension(); + // new filename hash + $filenamehash = md5(Str::random(10) . '_' . (string)time()); // Filename to store - $fileNameToStore = $filename . '_' . time() . '.' . $extension; - // Upload Image - $path = $request->file('file')->storeAs('users', $fileNameToStore); - $user->letter_file = $path; + $fileNameToStore = $filenamehash . '.' . $extension; + + // S3 file upload + $S3 = new S3Client([ + 'version' => 'latest', + 'region' => getenv('AWS_DEFAULT_REGION'), + 'credentials' => [ + 'key' => getenv('AWS_ACCESS_KEY_ID'), + 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), + ], + ]); + + $s3result = $S3->putObject([ + 'Bucket' => getenv('AWS_BUCKET'), + 'Key' => 'letters_of_motivation/'.$fileNameToStore, + 'SourceFile' => $request->file('file') + ]); + + $ObjectURL = $s3result['ObjectURL'] ?? getenv('SITE_URL').'/not-found'; + $user->letter_file = $ObjectURL; + $user->letter_rejected_at = null; $user->save(); + $emailerData = EmailerHelper::getEmailerData(); + EmailerHelper::triggerAdminEmail('User uploads a letter', $emailerData, $user); + EmailerHelper::triggerUserEmail($user->email, 'Your letter of motivation is received', $emailerData, $user); return $this->metaSuccess(); } catch (\Exception $ex) { return $this->errorResponse(__('Failed upload file'), Response::HTTP_BAD_REQUEST, $ex->getMessage()); @@ -162,14 +325,26 @@ public function sendHellosignRequest() if ($user) { $client_key = config('services.hellosign.api_key'); $client_id = config('services.hellosign.client_id'); - $template_id = '7de53a8a63cbcb8a6119589e1cd5e624fac8358a'; + $template_id = '80392797521f1adb88743f75ea04203a6504ef81'; $client = new \HelloSign\Client($client_key); $request = new \HelloSign\TemplateSignatureRequest; - $request->enableTestMode(); + $whitelist = [ + 'http://casper.local', + 'http://casper.local/', + 'https://backend.caspermember.com', + 'https://backend.caspermember.com/', + 'https://stage.membersbackend.casper.network', + 'https://stage.membersbackend.casper.network/', + ]; + + if (in_array(env('APP_URL'), $whitelist)) { + $request->enableTestMode(); + } + $request->setTemplateId($template_id); - $request->setSubject('User Agreement'); - $request->setSigner('User', $user->email, $user->first_name . ' ' . $user->last_name); + $request->setSubject('Member Agreement'); + $request->setSigner('Member', $user->email, $user->first_name . ' ' . $user->last_name); $request->setCustomFieldValue('FullName', $user->first_name . ' ' . $user->last_name); $request->setCustomFieldValue('FullName2', $user->first_name . ' ' . $user->last_name); $request->setClientId($client_id); @@ -189,6 +364,10 @@ public function sendHellosignRequest() $sign_url = $response->getSignUrl(); $user->update(['signature_request_id' => $signature_request_id]); + $emailerData = EmailerHelper::getEmailerData(); + if ($user->letter_verified_at && $user->signature_request_id && $user->node_verified_at) { + EmailerHelper::triggerUserEmail($user->email, 'Congratulations', $emailerData, $user); + } return $this->successResponse([ 'signature_request_id' => $signature_request_id, 'url' => $sign_url, @@ -196,65 +375,31 @@ public function sendHellosignRequest() } return $this->errorResponse(__('Hellosign request fail'), Response::HTTP_BAD_REQUEST); } + /** - * verify bypass + * submit node address */ - public function verifyBypass(Request $request) + public function submitPublicAddress(SubmitPublicAddressRequest $request) { $user = auth()->user(); - // Validator - $validator = Validator::make($request->all(), [ - 'type' => 'required' - ]); - if ($validator->fails()) { - return $this->validateResponse($validator->errors()); - } - if ($request->type == 'hellosign') { - $user->signature_request_id = 'signature_' . $user->id . '._id'; - $user->hellosign_form = 'hellosign_form_' . $user->id; - $user->letter_file = 'leteter_file.pdf'; - $user->save(); - } - if ($request->type == 'verify-node') { - $user->public_address_node = 'public_address_node' . $user->id ; - $user->node_verified_at = now(); - $user->message_content = 'message_content'; - $user->signed_file = 'signture'; - $user->save(); - } + $address = strtolower($request->public_address); - if ($request->type == 'submit-kyc') { - $user->kyc_verified_at = now(); - $user->save(); - if(!$user->profile) { - $profile = new Profile(); - $profile->user_id = $user->id; - $profile->first_name = $user->first_name; - $profile->last_name = $user->last_name; - $profile->dob = '1990-01-01'; - $profile->country_citizenship ='United States'; - $profile->country_residence = 'United States'; - $profile->address = 'New York'; - $profile->city = 'New York'; - $profile->zip = '10025'; - $profile->type_owner_node = 1; - $profile->type = $user->type; - $profile->save(); - } + $public_address_temp = (new ChecksumValidator())->do($address); + $public_address = strtolower($address); + $correct_checksum = (int) (new ChecksumValidator($public_address_temp))->do(); + if (!$correct_checksum) { + return $this->errorResponse(__('Please provide valid address'), Response::HTTP_BAD_REQUEST); } - return $this->metaSuccess(); - } + $tempUser = User::where('public_address_node', $public_address)->first(); + if ($tempUser) { + return $this->errorResponse(__('The address is already used by other user'), Response::HTTP_BAD_REQUEST); + } + + $user->update(['public_address_node' => $public_address]); - /** - * submit node address - */ - public function submitPublicAddress(SubmitPublicAddressRequest $request) - { - $user = auth()->user(); - $user->update(['public_address_node' => $request->public_address]); return $this->metaSuccess(); } @@ -264,7 +409,7 @@ public function submitPublicAddress(SubmitPublicAddressRequest $request) public function getMessageContent() { $user = auth()->user(); - $timestamp = date('m/d/Y'); + $timestamp = date('d/m/Y'); $message = "Please use the Casper Signature python tool to sign this message! " . $timestamp; $user->update(['message_content' => $message]); $filename = 'message.txt'; @@ -282,16 +427,13 @@ public function verifyFileCasperSigner(VerifyFileCasperSignerRequest $request) $casperSigVerify = new CasperSigVerify(); $user = auth()->user(); $message = $user->message_content; - $public_validator_key = $user->public_address_node; + $public_validator_key = strtolower($user->public_address_node); $file = $request->file; $name = $file->getClientOriginalName(); $hexstring = $file->get(); - if ( - $hexstring && - $name == 'signature' - ) { + if ($hexstring && $name == 'signature') { $verified = $casperSigVerify->verify( trim($hexstring), $public_validator_key, @@ -299,13 +441,36 @@ public function verifyFileCasperSigner(VerifyFileCasperSignerRequest $request) ); // $verified = true; if ($verified) { + $filenamehash = md5(Str::random(10) . '_' . (string)time()); + + // S3 file upload + $S3 = new S3Client([ + 'version' => 'latest', + 'region' => getenv('AWS_DEFAULT_REGION'), + 'credentials' => [ + 'key' => getenv('AWS_ACCESS_KEY_ID'), + 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), + ], + ]); + + $s3result = $S3->putObject([ + 'Bucket' => getenv('AWS_BUCKET'), + 'Key' => 'signatures/'.$filenamehash, + 'SourceFile' => $request->file('file') + ]); - $fullpath = 'sigfned_file/' . $user->id . '/signature'; - Storage::disk('local')->put($fullpath, trim($hexstring)); - // $url = Storage::disk('local')->url($fullpath); - $user->signed_file = $fullpath; + // $ObjectURL = 'https://'.getenv('AWS_BUCKET').'.s3.amazonaws.com/signatures/'.$filenamehash; + $ObjectURL = $s3result['ObjectURL'] ?? getenv('SITE_URL').'/not-found'; + $user->signed_file = $ObjectURL; $user->node_verified_at = now(); $user->save(); + $emailerData = EmailerHelper::getEmailerData(); + + EmailerHelper::triggerUserEmail($user->email, 'Your Node is Verified', $emailerData, $user); + + if ($user->letter_verified_at && $user->signature_request_id && $user->node_verified_at) { + EmailerHelper::triggerUserEmail($user->email, 'Congratulations', $emailerData, $user); + } return $this->metaSuccess(); } else { return $this->errorResponse(__('Failed verification'), Response::HTTP_BAD_REQUEST); @@ -332,6 +497,8 @@ public function functionSubmitKYC(SubmitKYCRequest $request) ], $data ); + $user->reset_kyc = 0; + $user->save(); return $this->metaSuccess(); } @@ -348,45 +515,6 @@ public function verifyOwnerNode(Request $request) return $this->metaSuccess(); } - /** - * add owner node - */ - public function addOwnerNode(AddOwnerNodeRequest $request) - { - try { - $user = auth()->user(); - $data = $request->validated(); - $ownerNodes = []; - $percents = 0; - foreach ($data as $value) { - $percents += $value['percent']; - $value['user_id'] = $user->id; - $value['created_at'] = now(); - array_push($ownerNodes, $value); - } - if ($percents >= 100) { - return $this->errorResponse(__('Total percent must less 100'), Response::HTTP_BAD_REQUEST); - } - - OwnerNode::where('user_id', $user->id)->delete(); - OwnerNode::insert($ownerNodes); - $user->update(['kyc_verified_at' => now()]); - - $url = $request->header('origin') ?? $request->root(); - $resetUrl = $url . '/register-type'; - foreach ($ownerNodes as $node) { - $email = $node['email']; - $user = User::where('email', $email)->first(); - if (!$user) { - Mail::to($email)->send(new AddNodeMail($resetUrl)); - } - } - return $this->metaSuccess(); - } catch (\Exception $ex) { - return $this->errorResponse(__('api.error.internal_error'), Response::HTTP_INTERNAL_SERVER_ERROR); - } - } - /** * get Owner nodes */ @@ -453,6 +581,32 @@ public function saveShuftiproTemp(Request $request) return $this->metaSuccess(); } + // Delete Shuftipro Temp Status + public function deleteShuftiproTemp(Request $request) + { + $user = auth()->user(); + // Validator + $validator = Validator::make($request->all(), [ + 'reference_id' => 'required' + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $user_id = $user->id; + $reference_id = $request->reference_id; + $profile = Profile::where('user_id', $user_id)->first(); + if ($profile) { + $profile->status = null; + $profile->save(); + } + + Shuftipro::where('user_id', $user_id)->delete(); + ShuftiproTemp::where('user_id', $user_id)->delete(); + + return $this->metaSuccess(); + } + // Update Shuftipro Temp Status public function updateShuftiProTemp(Request $request) { @@ -467,45 +621,829 @@ public function updateShuftiProTemp(Request $request) $user_id = $user->id; $reference_id = $request->reference_id; - + $profile = Profile::where('user_id', $user_id)->first(); + if ($profile) { + $profile->status = 'pending'; + $profile->save(); + } $record = ShuftiproTemp::where('user_id', $user_id) ->where('reference_id', $reference_id) ->first(); if ($record) { $record->status = 'booked'; $record->save(); - // check shuftipro - $shuftiproCheck = new ShuftiproCheck(); - $shuftiproCheck->handle($record); + $emailerData = EmailerHelper::getEmailerData(); + EmailerHelper::triggerAdminEmail('KYC or AML need review', $emailerData, $user); return $this->metaSuccess(); } - return $this->errorResponse('Fail submit AML', Response::HTTP_BAD_REQUEST); } - // Update Shuftipro Temp Status - public function updateTypeOwnerNode(Request $request) + // get vote list + public function getVotes(Request $request) + { + $status = $request->status ?? 'active'; + $limit = $request->limit ?? 50; + $sort_key = $request->sort_key ?? ''; + $sort_direction = $request->sort_direction ?? ''; + if (!$sort_key) $sort_key = 'ballot.id'; + if (!$sort_direction) $sort_direction = 'desc'; + + if ($status != 'active' && $status != 'finish') { + return $this->errorResponse('Paramater invalid (status is active or finish)', Response::HTTP_BAD_REQUEST); + } + + if ($status == 'active') { + $query = Ballot::where('status', 'active'); + } else { + $query = Ballot::where('status', '<>', 'active'); + } + $data = $query->with('vote')->orderBy($sort_key, $sort_direction)->paginate($limit); + + return $this->successResponse($data); + } + + // get vote detail + public function getVoteDetail($id) { $user = auth()->user(); - // Validator + $ballot = Ballot::with(['vote', 'voteResults.user', 'files'])->where('id', $id)->first(); + if (!$ballot) { + return $this->errorResponse('Not found ballot', Response::HTTP_BAD_REQUEST); + } + foreach ($ballot->files as $file) { + $ballotFileView = BallotFileView::where('ballot_file_id', $file->id)->where('user_id', $user->id)->first(); + $file->is_viewed = $ballotFileView ? 1 : 0; + } + $ballot->user_vote = VoteResult::where('user_id', $user->id)->where('ballot_id', $ballot->id)->first(); + return $this->successResponse($ballot); + } + + // vote the ballot + public function vote($id, Request $request) + { + $user = auth()->user(); + $vote = $request->vote; + if (!$vote || ($vote != 'for' && $vote != 'against')) { + return $this->errorResponse('Paramater invalid (vote is for or against)', Response::HTTP_BAD_REQUEST); + } + $ballot = Ballot::where('id', $id)->first(); + if (!$ballot) { + return $this->errorResponse('Not found ballot', Response::HTTP_BAD_REQUEST); + } + $voteResult = VoteResult::where('user_id', $user->id)->where('ballot_id', $ballot->id)->first(); + if ($voteResult) { + if ($vote == $voteResult->type) { + return $this->metaSuccess(); + } else { + $voteResult->type = $vote; + $voteResult->updated_at = now(); + if ($vote == 'for') { + $ballot->vote->for_value = $ballot->vote->for_value + 1; + $ballot->vote->against_value = $ballot->vote->against_value - 1; + } else { + $ballot->vote->for_value = $ballot->vote->for_value - 1; + $ballot->vote->against_value = $ballot->vote->against_value + 1; + } + $ballot->vote->updated_at = now(); + $ballot->vote->save(); + $voteResult->save(); + } + } else { + $voteResult = new VoteResult(); + $voteResult->user_id = $user->id; + $voteResult->ballot_id = $ballot->id; + $voteResult->vote_id = $ballot->vote->id; + $voteResult->type = $vote; + $voteResult->save(); + if ($vote == 'for') { + $ballot->vote->for_value = $ballot->vote->for_value + 1; + } else { + $ballot->vote->against_value = $ballot->vote->against_value + 1; + } + $ballot->vote->result_count = $ballot->vote->result_count + 1; + $ballot->vote->updated_at = now(); + $ballot->vote->save(); + } + return $this->metaSuccess(); + } + + public function submitViewFileBallot(Request $request, $fileId) + { + $user = auth()->user(); + $ballotFile = BallotFile::where('id', $fileId)->first(); + if (!$ballotFile) { + return $this->errorResponse('Not found ballot file', Response::HTTP_BAD_REQUEST); + } + $ballotFileView = BallotFileView::where('ballot_file_id', $ballotFile->id)->where('user_id', $user->id)->first(); + if ($ballotFileView) { + return $this->metaSuccess(); + } + $ballotFileView = new BallotFileView(); + $ballotFileView->ballot_file_id = $ballotFile->id; + $ballotFileView->ballot_id = $ballotFile->ballot_id; + $ballotFileView->user_id = $user->id; + $ballotFileView->save(); + return $this->metaSuccess(); + } + /** + * verify file casper singer + */ + public function uploadAvatar(Request $request) + { + try { + // Validator + $validator = Validator::make($request->all(), [ + 'avatar' => 'sometimes|mimes:jpeg,jpg,png,gif,webp|max:100000', + ]); + + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + + $user = auth()->user(); + $filenameWithExt = $request->file('avatar')->getClientOriginalName(); + //Get just filename + $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME); + // Get just ext + $extension = $request->file('avatar')->getClientOriginalExtension(); + // new filename hash + $filenamehash = md5(Str::random(10) . '_' . (string)time()); + // Filename to store + $fileNameToStore = $filenamehash . '.' . $extension; + + // S3 file upload + $S3 = new S3Client([ + 'version' => 'latest', + 'region' => getenv('AWS_DEFAULT_REGION'), + 'credentials' => [ + 'key' => getenv('AWS_ACCESS_KEY_ID'), + 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), + ], + ]); + + $s3result = $S3->putObject([ + 'Bucket' => getenv('AWS_BUCKET'), + 'Key' => 'client_uploads/' . $fileNameToStore, + 'SourceFile' => $request->file('avatar'), + ]); + + // $ObjectURL = 'https://'.getenv('AWS_BUCKET').'.s3.amazonaws.com/client_uploads/'.$fileNameToStore; + $user->avatar = $s3result['ObjectURL'] ?? getenv('SITE_URL') . '/not-found'; + $user->save(); + return $this->metaSuccess(); + + /* old + $filenameWithExt = $request->file('avatar')->getClientOriginalName(); + //Get just filename + $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME); + // Get just ext + $extension = $request->file('avatar')->getClientOriginalExtension(); + // Filename to store + $fileNameToStore = $filename . '_' . time() . '.' . $extension; + // Upload Image + $path = $request->file('avatar')->storeAs('users/avatar', $fileNameToStore); + $user->avatar = $path; + $user->save(); + return $this->metaSuccess(); + */ + } catch (\Exception $ex) { + return $this->errorResponse(__('Failed upload avatar'), Response::HTTP_BAD_REQUEST, $ex->getMessage()); + } + } + + public function getMembers(Request $request) + { + $search = $request->search; + $limit = $request->limit ?? 50; + + $slide_value_uptime = $request->uptime ?? 0; + $slide_value_update_responsiveness = $request->update_responsiveness ?? 0; + $slide_value_delegotors = $request->delegators ?? 0; + $slide_value_stake_amount = $request->stake_amount ?? 0; + $slide_delegation_rate = $request->delegation_rate ?? 0; + + $max_uptime = Node::max('uptime'); + $max_uptime = $max_uptime * 100; + + $max_delegators = NodeInfo::max('delegators_count'); + if(!$max_delegators || $max_delegators < 1) $max_delegators = 1; + + $max_stake_amount = NodeInfo::max('total_staked_amount'); + if(!$max_stake_amount || $max_stake_amount < 1) $max_stake_amount = 1; + + $sort_key = $request->sort_key ?? 'created_at'; + + $users = User::with(['metric', 'nodeInfo', 'profile']) + ->whereHas('nodeInfo') + ->where('role', 'member') + ->where(function ($query) use ($search) { + if ($search) { + $query->where('users.first_name', 'like', '%' . $search . '%') + ->orWhere('users.last_name', 'like', '%' . $search . '%'); + } + }) + ->get(); + + foreach ($users as $user) { + $latest = Node::where('node_address', strtolower($user->public_address_node)) + ->whereNotnull('protocol_version') + ->orderBy('created_at', 'desc') + ->first(); + if (!$latest) { + $latest = new Node(); + } + + $user->status = isset($user->profile) && isset($user->profile->status) ? $user->profile->status : ''; + + $uptime_nodeInfo = $user->nodeInfo->uptime; + $uptime_node = isset($latest->uptime) && $latest->uptime ? $latest->uptime * 100 : null; + $uptime_metric = isset($user->metric) && isset($user->metric->uptime) ? $user->metric->uptime : null; + + $res_nodeInfo = $user->nodeInfo->update_responsiveness ?? null; + $res_node = $latest->update_responsiveness ?? null; + $res_metric = $metric->update_responsiveness ?? null; + + $uptime = $uptime_nodeInfo ? $uptime_nodeInfo : ($uptime_node ? $uptime_node : ($uptime_metric ? $uptime_metric : 1)); + $res = $res_nodeInfo ? $res_nodeInfo : ($res_node ? $res_node : ($res_metric ? $res_metric : 0)); + + $delegation_rate = isset($user->nodeInfo->delegation_rate) && $user->nodeInfo->delegation_rate ? $user->nodeInfo->delegation_rate / 100 : 1; + if ($delegation_rate > 1) { + $delegation_rate = 1; + } + $delegators_count = isset($user->nodeInfo->delegators_count) && $user->nodeInfo->delegators_count ? $user->nodeInfo->delegators_count : 0; + $total_staked_amount = isset($user->nodeInfo->total_staked_amount) && $user->nodeInfo->total_staked_amount ? $user->nodeInfo->total_staked_amount : 0; + + $uptime_score = (float) (($slide_value_uptime * $uptime) / 100); + $delegation_rate_score = (float) (($slide_delegation_rate * (1 - $delegation_rate)) / 100); + $delegators_count_score = (float) ($delegators_count / $max_delegators) * $slide_value_delegotors; + $total_staked_amount_score = (float) ($total_staked_amount / $max_stake_amount) * $slide_value_stake_amount; + $res_score = (float) (($slide_value_update_responsiveness * $res) / 100); + + $user->uptime = $uptime; + $user->delegation_rate = $delegation_rate; + $user->delegators_count = $delegators_count; + $user->total_staked_amount = $total_staked_amount; + $user->totalScore = $uptime_score + $delegation_rate_score + $delegators_count_score + $total_staked_amount_score + $res_score; + } + + $users = $users->sortByDesc($sort_key)->values(); + $users = Helper::paginate($users, $limit, $request->page); + return $this->successResponse($users); + } + + public function getMembersOld(Request $request) + { + $search = $request->search; + $limit = $request->limit ?? 50; + $slide_value_uptime = $request->uptime ?? 0; + $slide_value_update_responsiveness = $request->update_responsiveness ?? 0; + $slide_value_delegotors = $request->delegators ?? 0; + $slide_value_stake_amount = $request->stake_amount ?? 0; + $slide_delegation_rate = $request->delegation_rate ?? 0; + + $max_uptime = Node::max('uptime'); + $max_uptime = $max_uptime * 100; + $max_delegators = NodeInfo::max('delegators_count'); + if($max_delegators < 1) $max_delegators = 1; + $max_stake_amount = NodeInfo::max('total_staked_amount'); + if($max_stake_amount < 1) $max_stake_amount = 1; + + $sort_key = $request->sort_key ?? ''; + $sort_direction = $request->sort_direction ?? ''; + if (!$sort_key) $sort_key = 'created_at'; + if (!$sort_direction) $sort_direction = 'desc'; + + $users = User::with(['metric']) + ->where('role', 'member') + ->leftJoin('node_info', 'users.public_address_node', '=', 'node_info.node_address') + ->leftJoin('profile', 'users.id', '=', 'profile.user_id') + ->where(function ($query) use ($search) { + if ($search) { + $query->where('users.first_name', 'like', '%' . $search . '%') + ->orWhere('users.last_name', 'like', '%' . $search . '%'); + } + }) + ->select([ + 'users.id', + 'users.created_at', + 'users.first_name', + 'users.last_name', + 'users.kyc_verified_at', + 'users.pseudonym', + 'profile.status', + 'node_info.uptime', + 'node_info.delegation_rate', + 'node_info.delegators_count', + 'node_info.total_staked_amount', + ]) + ->get(); + + foreach ($users as $user) { + if (!$user->metric && !$user->nodeInfo) { + $user->totalScore = 0; + continue; + } + + $latest = Node::where('node_address', strtolower($user->public_address_node)) + ->whereNotnull('protocol_version') + ->orderBy('created_at', 'desc') + ->first(); + if (!$latest) { + $latest = new Node(); + } + + $delegation_rate = $user->delegation_rate ? $user->delegation_rate / 100 : 1; + + $latest_uptime_node = isset($latest->uptime) ? $latest->uptime * 100 : null; + $latest_update_responsiveness_node = $latest->update_responsiveness ?? null; + $metric = $user->metric; + if (!$metric) { + $metric = new Metric(); + } + $latest_uptime_metric = $metric->uptime ? $metric->uptime : null; + $latest_update_responsiveness_metric = $metric->update_responsiveness ? $metric->update_responsiveness : null; + + $latest_uptime = $latest_uptime_node ?? $latest_uptime_metric ?? 1; + $latest_update_responsiveness = $latest_update_responsiveness_node ?? $latest_update_responsiveness_metric ?? 1; + + // $delegators_count = $user->delegators_count ? $user->nodeInfo->delegators_count : 0; + $delegators_count = $user->delegators_count ? $user->delegators_count : 0; + // $total_staked_amount = $user->total_staked_amount ? $user->nodeInfo->total_staked_amount : 0; + $total_staked_amount = $user->total_staked_amount ? $user->total_staked_amount : 0; + + $uptime_score = ($slide_value_uptime * $latest_uptime) / 100; + $update_responsiveness_score = ($slide_value_update_responsiveness * $latest_update_responsiveness) / 100; + $dellegator_score = ($delegators_count / $max_delegators) * $slide_value_delegotors; + $satke_amount_score = ($total_staked_amount / $max_stake_amount) * $slide_value_stake_amount; + $delegation_rate_score = ($slide_delegation_rate * (1 - $delegation_rate)) / 100; + $totalScore = $uptime_score + $update_responsiveness_score + $dellegator_score + $satke_amount_score + $delegation_rate_score; + + $user->totalScore = $totalScore; + $user->uptime = $user->uptime ? $user->uptime : $metric->uptime; + } + if ($sort_key == 'totalScore') { + $users = $users->sortByDesc('totalScore')->values(); + } else { + $users = $users->sortByDesc('created_at')->values(); + } + $users = Helper::paginate($users, $limit, $request->page); + return $this->successResponse($users); + } + + public function getMemberDetail($id) + { + $user = User::where('id', $id)->first(); + Helper::getAccountInfoStandard($user); + + if (!$user || $user->role == 'admin') { + return $this->errorResponse(__('api.error.not_found'), Response::HTTP_NOT_FOUND); + } + $user->metric = Helper::getNodeInfo($user); + $response = $user->load(['profile']); + + unset($response->last_login_at); + unset($response->last_login_ip_address); + + if(isset($response->profile)) { + unset($response->profile->dob); + unset($response->profile->address); + unset($response->profile->city); + unset($response->profile->zip); + } + + return $this->successResponse($response); + } + + public function getCaKycHash($hash) + { + if(!ctype_xdigit($hash)) { + return $this->errorResponse(__('api.error.not_found'), Response::HTTP_NOT_FOUND); + } + + $selection = DB::select(" + SELECT a.casper_association_kyc_hash as proof_hash, b.reference_id, b.status, c.pseudonym + FROM profile as a + LEFT JOIN shuftipro AS b + ON a.user_id = b.user_id + LEFT JOIN users AS c + ON b.user_id = c.id + WHERE a.casper_association_kyc_hash = '$hash' + "); + $selection = $selection[0] ?? array(); + + return $this->successResponse($selection); + } + + public function getMyVotes(Request $request) + { + $limit = $request->limit ?? 50; + $user = auth()->user(); + $data = VoteResult::where('vote_result.user_id', $user->id) + ->join('ballot', function ($query) use ($user) { + $query->on('vote_result.ballot_id', '=', 'ballot.id'); + }) + ->join('vote', function ($query) use ($user) { + $query->on('vote.ballot_id', '=', 'vote_result.ballot_id'); + }) + ->select([ + 'vote.*', + 'ballot.*', + 'vote_result.created_at as date_placed', + 'vote_result.type as voteType', + ])->orderBy('vote_result.created_at', 'DESC')->paginate($limit); + return $this->successResponse($data); + } + + public function checkCurrentPassword(Request $request) + { + $user = auth()->user(); + if (Hash::check($request->current_password, $user->password)) { + return $this->metaSuccess(); + } else { + return $this->errorResponse(__('Invalid password'), Response::HTTP_BAD_REQUEST); + } + } + + public function settingUser(Request $request) + { + $user = auth()->user(); + if ($request->new_password) { + $user->password = bcrypt($request->new_password); + } + + if ($request->username) { + $checkUsername = User::where('username', $request->username) + ->where('username', '!=', $user->username) + ->first(); + if ($checkUsername) { + return $this->errorResponse(__('this username has already been taken'), Response::HTTP_BAD_REQUEST); + } + $user->username = $request->username; + } + + if (isset($request->twoFA_login)) { + $user->twoFA_login = $request->twoFA_login; + } + + if ($request->email && $request->email != $user->email) { + $emailParam = $request->email; + + $checkEmail = User::where(function ($query) use ($emailParam) { + $query->where('email', $emailParam) + ->orWhere('new_email', $emailParam); + }) + ->where('id', '!=', $user->id) + ->first(); + + $currentEmail = $user->email; + $newEmail = $request->email; + if ($checkEmail) { + return $this->errorResponse(__('this email has already been taken'), Response::HTTP_BAD_REQUEST); + } + $user->new_email = $newEmail; + + // Current Email + $codeCurrentEmail = Str::random(6); + $url = $request->header('origin') ?? $request->root(); + $urlCurrentEmail = $url . '/change-email/cancel-changes?code=' . $codeCurrentEmail . '&email=' . urlencode($currentEmail); + $newMemberData = [ + 'title' => 'Are you trying to update your email?', + 'content' => 'You recently requested to update your email address with the Casper Association Portal. If this is correct, click the link sent to your new email address to activate it. <br> If you did not initiate this update, your account could be compromised. Click the button to cancel the change', + 'url' => $urlCurrentEmail, + 'action' => 'cancel' + ]; + Mail::to($currentEmail)->send(new UserConfirmEmail($newMemberData['title'], $newMemberData['content'], $newMemberData['url'], $newMemberData['action'])); + VerifyUser::where('email', $currentEmail)->where('type', VerifyUser::TYPE_CANCEL_EMAIL)->delete(); + $verify = new VerifyUser(); + $verify->code = $codeCurrentEmail; + $verify->email = $currentEmail; + $verify->type = VerifyUser::TYPE_CANCEL_EMAIL; + $verify->created_at = now(); + $verify->save(); + + // new email + $codeNewEmail = Str::random(6); + $urlNewEmail = $url . '/change-email/confirm?code=' . $codeNewEmail . '&email=' . urlencode($newEmail); + $newMemberData = [ + 'title' => 'You recently updated your email', + 'content' => 'You recently requested to update your email address with the Casper Association Portal. If this is correct, click the button below to confirm the change. <br> If you received this email in error, you can simply delete it', + 'url' => $urlNewEmail, + 'action' => 'confirm' + ]; + Mail::to($newEmail)->send(new UserConfirmEmail($newMemberData['title'], $newMemberData['content'], $newMemberData['url'], $newMemberData['action'])); + VerifyUser::where('email', $newEmail)->where('type', VerifyUser::TYPE_CONFIRM_EMAIL)->delete(); + $verify = new VerifyUser(); + $verify->email = $newEmail; + $verify->code = $codeNewEmail; + $verify->type = VerifyUser::TYPE_CONFIRM_EMAIL; + $verify->created_at = now(); + $verify->save(); + } + $user->save(); + + return $this->successResponse($user); + } + + public function cancelChangeEmail(Request $request) + { + $verify = VerifyUser::where('email', $request->email)->where('type', VerifyUser::TYPE_CANCEL_EMAIL) + ->where('code', $request->code)->first(); + if ($verify) { + $user = User::where('email', $request->email)->first(); + if ($user) { + $user->new_email = null; + $user->save(); + $verify->delete(); + VerifyUser::where('email', $user->new_email)->where('type', VerifyUser::TYPE_CONFIRM_EMAIL)->delete(); + return $this->successResponse($user); + } + return $this->errorResponse(__('Fail cancel change email'), Response::HTTP_BAD_REQUEST); + } + return $this->errorResponse(__('Fail cancel change email'), Response::HTTP_BAD_REQUEST); + } + + public function confirmChangeEmail(Request $request) + { + $verify = VerifyUser::where('email', $request->email) + ->where('type', VerifyUser::TYPE_CONFIRM_EMAIL) + ->where('code', $request->code) + ->first(); + if ($verify) { + $user = User::where('new_email', $request->email)->first(); + if ($user) { + VerifyUser::where('email', $user->email)->where('type', VerifyUser::TYPE_CANCEL_EMAIL)->delete(); + $user->new_email = null; + $user->email = $request->email; + $user->save(); + $verify->delete(); + return $this->successResponse($user); + } + return $this->errorResponse(__('Fail confirm change email'), Response::HTTP_BAD_REQUEST); + } + return $this->errorResponse(__('Fail confirm change email'), Response::HTTP_BAD_REQUEST); + } + + public function checkLogin2FA(Request $request) + { + $user = auth()->user(); + $verify = VerifyUser::where('email', $user->email) + ->where('type', VerifyUser::TYPE_LOGIN_TWO_FA) + ->where('code', $request->code) + ->first(); + if ($verify) { + $verify->delete(); + $user->twoFA_login_active = 0; + $user->save(); + return $this->metaSuccess(); + } + return $this->errorResponse(__('Fail check twoFA code'), Response::HTTP_BAD_REQUEST); + } + + public function resend2FA() + { + $user = auth()->user(); + if ($user->twoFA_login == 1) { + VerifyUser::where('email', $user->email)->where('type', VerifyUser::TYPE_LOGIN_TWO_FA)->delete(); + $code = Str::random(6); + $verify = new VerifyUser(); + $verify->email = $user->email; + $verify->type = VerifyUser::TYPE_LOGIN_TWO_FA; + $verify->code = $code; + $verify->created_at = now(); + $verify->save(); + Mail::to($user)->send(new LoginTwoFA($code)); + return $this->metaSuccess(); + } + return $this->errorResponse(__('Please enable 2Fa setting'), Response::HTTP_BAD_REQUEST); + } + + public function getLockRules() + { + $user = auth()->user(); + + $ruleKycNotVerify = LockRules::where('type', 'kyc_not_verify')->where('is_lock', 1) + ->orderBy('id', 'ASC')->select(['id', 'screen'])->get(); + $ruleKycNotVerify1 = array_map(function ($object) { + return $object->screen; + }, $ruleKycNotVerify->all()); + $ruleStatusIsPoor = LockRules::where('type', 'status_is_poor')->where('is_lock', 1) + ->orderBy('id', 'ASC')->select(['id', 'screen'])->get(); + $ruleStatusIsPoor1 = array_map(function ($object) { + return $object->screen; + }, $ruleStatusIsPoor->all()); + + $data = [ + 'kyc_not_verify' => $ruleKycNotVerify1, + 'status_is_poor' => $ruleStatusIsPoor1, + 'node_status' => $user->node_status + ]; + return $this->successResponse($data); + } + + public function getListNodes(Request $request) + { + $limit = $request->limit ?? 50; + $nodes = User::select([ + 'users.id as user_id', + 'users.public_address_node', + 'users.is_fail_node', + 'users.pseudonym', + 'users.rank', + 'profile.blockchain_name', + 'profile.blockchain_desc', + ]) + ->leftjoin('profile', 'profile.user_id', '=', 'users.id') + ->where('users.banned', 0) + ->whereNotNull('users.public_address_node') + ->orderBy('users.rank', 'asc') + ->paginate($limit); + + return $this->successResponse($nodes); + } + + public function infoDashboard() + { + $user = auth()->user(); + $delegators = 0; + $stake_amount = 0; + $nodeInfo = NodeInfo::where('node_address', strtolower($user->public_address_node))->first(); + if ($nodeInfo) { + $delegators = $nodeInfo->delegators_count; + $stake_amount = $nodeInfo->total_staked_amount; + } + $totalPin = DiscussionPin::where('user_id', $user->id)->count(); + $response['totalNewDiscusstion'] = $user->new_threads; + $response['totalPinDiscusstion'] = $totalPin; + $response['rank'] = $user->rank; + $response['delegators'] = $delegators; + $response['stake_amount'] = $stake_amount; + return $this->successResponse($response); + } + + public function getEarningByNode($node) + { + $node = strtolower($node); + $user = User::where('public_address_node', $node)->first(); + $nodeInfo = NodeInfo::where('node_address', $node)->first(); + $mbs = NodeInfo::max('mbs'); + if ($user && $nodeInfo) { + return $this->successResponse([ + 'daily_earning' => $nodeInfo->daily_earning, + 'total_earning' => $nodeInfo->total_earning, + 'mbs' => $mbs, + ]); + } else { + return $this->successResponse([ + 'mbs' => $mbs, + ]); + } + } + + public function getChartEarningByNode($node) + { + $node = strtolower($node); + $user = User::where('public_address_node', $node)->first(); + if ($user) { + $nodeHelper = new NodeHelper(); + $result_day = $nodeHelper->getValidatorRewards($node, 'day'); + $result_week = $nodeHelper->getValidatorRewards($node, 'week'); + $result_month = $nodeHelper->getValidatorRewards($node, 'month'); + $result_year = $nodeHelper->getValidatorRewards($node, 'year'); + return $this->successResponse([ + 'day' => $result_day, + 'week' => $result_week, + 'month' => $result_month, + 'year' => $result_year, + ]); + } else { + return $this->successResponse(null); + } + } + + public function getMembershipFile() + { + $membershipAgreementFile = MembershipAgreementFile::first(); + return $this->successResponse($membershipAgreementFile); + } + + public function membershipAgreement() + { + $user = auth()->user(); + $user->membership_agreement = 1; + $user->save(); + return $this->metaSuccess(); + } + + public function checkResetKyc() + { + $user = auth()->user(); + $user->reset_kyc = 0; + $user->save(); + return $this->metaSuccess(); + } + + public function getDonationSessionId(Request $request) + { + $sessionId = $request->get('sessionId'); + $flag = false; + + if ($sessionId) { + \Stripe\Stripe::setApiKey(env('STRIPE_SEC_KEY')); + $sessionData = \Stripe\Checkout\Session::retrieve($sessionId); + + if ($sessionData && isset($sessionData->id) && isset($sessionData->status) && $sessionData->status == 'complete') { + $donation = Donation::where('checkout_session_id', $sessionId)->first(); + if ($donation) { + $donation->status = 'complete'; + $donation->save(); + } + $flag = true; + } + } + + return $this->successResponse([ + 'success' => $flag, + ]); + } + + public function submitDonation(Request $request) + { $validator = Validator::make($request->all(), [ - 'type' => [ - 'required', - Rule::in([1, 2]), - ], + 'first_name' => 'required|regex:/^[A-Za-z. ]{1,255}$/', + 'last_name' => 'nullable|regex:/^[A-Za-z. ]{1,255}$/', + 'email' => 'required|email|max:256', + 'amount' => 'required', + 'message' => 'nullable|max:5000', ]); + if ($validator->fails()) { return $this->validateResponse($validator->errors()); } - if ($user->profile) { - $user->profile->type_owner_node = $request->type; - $user->profile->save(); - if ($request->type == 1) { - $user->kyc_verified_at = now(); - $user->save(); + + \Stripe\Stripe::setApiKey(env('STRIPE_SEC_KEY')); + + $productId = env('STRIPE_PRODUCTION_ID'); + $amount = (int) $request->amount * 100; + + $allPrices = \Stripe\Price::all(); + $priceId = null; + + if ($allPrices && isset($allPrices['data']) && count($allPrices['data'])) { + foreach ($allPrices['data'] as $item) { + if ((int) $item->unit_price == $amount) { + $priceId = $item->id; + break; + } } - return $this->metaSuccess(); } - return $this->errorResponse('Fail update type', Response::HTTP_BAD_REQUEST); + + try { + if (!$priceId) { + $priceObject = \Stripe\Price::create([ + 'unit_amount' => $amount, + 'currency' => 'usd', + 'product' => $productId, + ]); + $priceId = $priceObject->id; + } + + $url = $request->header('origin') ?? $request->root(); + $checkoutSession = \Stripe\Checkout\Session::create([ + 'success_url' => $url . '/donate?session_id={CHECKOUT_SESSION_ID}', + 'cancel_url' => $url . '/donate', + 'customer_email' => $request->email, + 'mode' => 'payment', + 'line_items' => [[ + 'price' => $priceId, + 'quantity' => 1, + ]] + ]); + + if ($checkoutSession && isset($checkoutSession->url) && isset($checkoutSession->id)) { + $checkoutSessionId = $checkoutSession->id; + + $donation = Donation::where('checkout_session_id', $checkoutSessionId)->first(); + if (!$donation) { + $donation = new Donation(); + $donation->first_name = $request->first_name; + $donation->last_name = $request->last_name; + $donation->email = $request->email; + $donation->amount = $request->amount; + $donation->message = $request->message; + $donation->checkout_session_id = $checkoutSessionId; + $donation->status = 'pending'; + $donation->save(); + } + + return $this->successResponse([ + 'url' => $checkoutSession->url, + ]); + } else { + return $this->errorResponse(__('Invalid payment request'), Response::HTTP_BAD_REQUEST); + } + } catch (\Exception $ex) { + return $this->errorResponse(__('Invalid payment request'), Response::HTTP_BAD_REQUEST); + } } } diff --git a/app/Http/Controllers/Api/V1/VerificationController.php b/app/Http/Controllers/Api/V1/VerificationController.php new file mode 100644 index 00000000..08c2d92d --- /dev/null +++ b/app/Http/Controllers/Api/V1/VerificationController.php @@ -0,0 +1,190 @@ +<?php + +namespace App\Http\Controllers\Api\V1; + +use App\Http\Controllers\Controller; + +use App\Models\DocumentFile; +use App\Models\Profile; +use App\Models\User; + +use Carbon\Carbon; + +use Illuminate\Http\Request; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Str; + +use Aws\S3\S3Client; + +class VerificationController extends Controller +{ + public function submitNode(Request $request) { + // Validator + $validator1 = Validator::make($request->all(), [ + 'type' => 'required|in:entity,individual' + ]); + if ($validator1->fails()) { + return $this->validateResponse($validator1->errors()); + } + $type = $request->type; + $user = auth()->user(); + $profile = Profile::where('user_id', $user->id)->first(); + if (!$profile) { + $profile = new Profile(); + $profile->user_id = $user->id; + } + $profile->type = $type; + + if ($type == 'entity') { + $validator2 = Validator::make($request->all(), [ + 'entity_name' => 'required', + 'entity_type' => 'required', + 'entity_registration_number' => 'required', + 'entity_registration_country' => 'required', + 'vat_number' => 'required' + ]); + if ($validator2->fails()) { + return $this->validateResponse($validator2->errors()); + } + + $profile->entity_name = $request->entity_name; + $profile->entity_type = $request->entity_type; + $profile->entity_registration_number = $request->entity_registration_number; + $profile->entity_registration_country = $request->entity_registration_country; + $profile->vat_number = $request->vat_number; + } else { + $profile->entity_name = null; + $profile->entity_type = null; + $profile->entity_registration_number = null; + $profile->entity_registration_country = null; + $profile->vat_number = null; + } + $userData = User::where('id', $user->id)->first(); + $userData->type = $type; + $userData->save(); + $profile->save(); + return $this->metaSuccess(); + } + + public function submitDetail(Request $request) { + // Validator + $validator1 = Validator::make($request->all(), [ + 'type' => 'required|in:entity,individual', + 'first_name' => 'required', + 'last_name' => 'required', + 'country_citizenship' => 'required', + // 'page_number' => 'required|integer', + 'dob' => 'required', + ]); + + if ($validator1->fails()) { + return $this->validateResponse($validator1->errors()); + } + $user = auth()->user(); + $type = $request->type; + $profile = Profile::where('user_id', $user->id)->first(); + if (!$profile) { + return $this->errorResponse(__('Pofile not exist'), Response::HTTP_BAD_REQUEST); + } + $profile->first_name = $request->first_name; + $profile->last_name = $request->last_name; + $profile->country_citizenship = $request->country_citizenship; + $profile->dob = Carbon::parse($request->dob)->format('Y-m-d'); + if ($type == 'entity') { + $profile->page_is_representative = $request->page_is_representative?? ''; + $profile->page_number = $request->page_number; + } + $userData = User::where('id', $user->id)->first(); + $userData->first_name = $request->first_name; + $userData->last_name = $request->last_name; + $userData->save(); + $profile->save(); + + return $this->metaSuccess(); + } + + public function uploadDocument(Request $request) { + try { + // Validator + $validator = Validator::make($request->all(), [ + 'files' => 'array', + 'files.*' => 'file|max:100000|mimes:pdf,docx,doc,txt,rtf' + ]); + if ($validator->fails()) { + return $this->validateResponse($validator->errors()); + } + $user = auth()->user(); + if ($request->hasFile('files')) { + $files = $request->file('files'); + foreach ($files as $file) { + $name = $file->getClientOriginalName(); + $extension = $file->getClientOriginalExtension(); + $filenamehash = md5(Str::random(10) . '_' . (string)time()); + $fileNameToStore = $filenamehash . '.' . $extension; + + // S3 file upload + $S3 = new S3Client([ + 'version' => 'latest', + 'region' => getenv('AWS_DEFAULT_REGION'), + 'credentials' => [ + 'key' => getenv('AWS_ACCESS_KEY_ID'), + 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), + ], + ]); + + $s3result = $S3->putObject([ + 'Bucket' => getenv('AWS_BUCKET'), + 'Key' => 'documents/'.$fileNameToStore, + 'SourceFile' => $file + ]); + + // $ObjectURL = 'https://'.getenv('AWS_BUCKET').'.s3.amazonaws.com/documents/'.$fileNameToStore; + $ObjectURL = $s3result['ObjectURL'] ?? getenv('SITE_URL').'/not-found'; + $documentFile = DocumentFile::where('user_id', $user->id)->where('name', $name)->first(); + + if (!$documentFile) { + $documentFile = new DocumentFile(); + $documentFile->user_id = $user->id; + $documentFile->name = $name; + $documentFile->path = $ObjectURL; + $documentFile->url = $ObjectURL; + $documentFile->save(); + } + + /* old + $name = $file->getClientOriginalName(); + $folder = 'document/' . $user->id; + $path = $file->storeAs($folder, $name); + $url = Storage::url($path); + $documentFile = DocumentFile::where('user_id', $user->id)->where('name', $name)->first(); + if (!$documentFile) { + $documentFile = new DocumentFile(); + $documentFile->user_id = $user->id; + $documentFile->name = $name; + $documentFile->path = $path; + $documentFile->url = $url; + $documentFile->save(); + } + */ + } + } + $response = DocumentFile::where('user_id', $user->id)->get(); + return $this->successResponse($response); + } catch (\Exception $ex) { + return $this->errorResponse(__('Failed upload file'), Response::HTTP_BAD_REQUEST, $ex->getMessage()); + } + } + + public function removeDocument($id) { + $user = auth()->user(); + $documentFile = DocumentFile::where('user_id', $user->id)->where('id', $id)->first(); + if ($documentFile) { + Storage::delete($documentFile->path); + $documentFile->delete(); + } + $response = DocumentFile::where('user_id', $user->id)->get(); + return $this->successResponse($response); + } +} diff --git a/app/Http/EmailerHelper.php b/app/Http/EmailerHelper.php new file mode 100644 index 00000000..17c6e4e6 --- /dev/null +++ b/app/Http/EmailerHelper.php @@ -0,0 +1,89 @@ +<?php + +namespace App\Http; + +use App\Mail\AdminAlert; +use App\Mail\UserAlert; +use App\Models\EmailerAdmin; +use App\Models\EmailerTriggerAdmin; +use App\Models\EmailerTriggerUser; +use Illuminate\Support\Facades\Mail; + +class EmailerHelper { + // Get Emailer Data + public static function getEmailerData() { + $data = [ + 'admins' => [], + 'triggerAdmin' => [], + 'triggerUser' => [], + 'triggerMember' => [] + ]; + + $admins = EmailerAdmin::where('id', '>', 0)->orderBy('email', 'asc')->get(); + $triggerAdmin = EmailerTriggerAdmin::where('id', '>', 0)->orderBy('id', 'asc')->get(); + $triggerUser = EmailerTriggerUser::where('id', '>', 0)->orderBy('id', 'asc')->get(); + + if ($admins && count($admins)) { + foreach ($admins as $admin) { + $data['admins'][] = $admin->email; + } + } + + if ($triggerAdmin && count($triggerAdmin)) { + foreach ($triggerAdmin as $item) { + if ((int) $item->enabled) + $data['triggerAdmin'][$item->title] = $item; + else + $data['triggerAdmin'][$item->title] = null; + } + } + + if ($triggerUser && count($triggerUser)) { + foreach ($triggerUser as $item) { + if ((int) $item->enabled) + $data['triggerUser'][$item->title] = $item; + else + $data['triggerUser'][$item->title] = null; + } + } + return $data; + } + + // Send Admin Email + public static function triggerAdminEmail($title, $emailerData, $user = null) { + if (count($emailerData['admins'] ?? [])) { + $item = $emailerData['triggerAdmin'][$title] ?? null; + if ($item) { + $content = $item['content']; + $subject =$item['subject']; + if ($user) { + $name = $user->first_name . ' ' . $user->last_name; + $content = str_replace('[name]', $name, $content); + $subject = str_replace('[name]', $name, $subject); + $content = str_replace('[email]', $user->email, $content); + $subject = str_replace('[email]', $user->email, $subject); + } + Mail::to($emailerData['admins'])->send(new AdminAlert($subject, $content)); + } + } + } + + // Send User Email + public static function triggerUserEmail($to, $title, $emailerData, $user = null) { + $item = $emailerData['triggerUser'][$title] ?? null; + if ($item) { + $content = $item['content']; + $subject =$item['subject']; + + if ($user) { + $name = $user->first_name . ' ' . $user->last_name; + $content = str_replace('[name]', $name, $content); + $subject = str_replace('[name]', $name, $subject); + $content = str_replace('[email]', $user->email, $content); + $content = str_replace('[node address]', $user->public_address_node, $content); + $subject = str_replace('[email]', $user->email, $subject); + } + Mail::to($to)->send(new UserAlert($subject, $content)); + } + } +} \ No newline at end of file diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index d6bd5227..ef444905 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -63,5 +63,7 @@ class Kernel extends HttpKernel 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 'role_admin' =>\App\Http\Middleware\CheckRoleAdmin::class, + 'user_banned' =>\App\Http\Middleware\CheckUserBanned::class, + 'permission' =>\App\Http\Middleware\CheckPermission::class, ]; } diff --git a/app/Http/Middleware/CheckPermission.php b/app/Http/Middleware/CheckPermission.php new file mode 100644 index 00000000..5b99d1c2 --- /dev/null +++ b/app/Http/Middleware/CheckPermission.php @@ -0,0 +1,36 @@ +<?php + +namespace App\Http\Middleware; + +use App\Models\Permission; +use App\Traits\ApiResponser; +use Closure; +use Illuminate\Http\Request; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Auth; + +class CheckPermission +{ + use ApiResponser; + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle(Request $request, Closure $next, $permission) + { + $user = Auth::user(); + if ($user->role == 'admin') { + return $next($request); + } + if ($user->role = 'sub-admin') { + $permission = Permission::where('user_id', $user->id)->where('name', $permission)->first(); + if ($permission && $permission->is_permission == 1) { + return $next($request); + } + } + return $this->errorResponse(__('api.error.forbidden'), Response::HTTP_FORBIDDEN); + } +} diff --git a/app/Http/Middleware/CheckRoleAdmin.php b/app/Http/Middleware/CheckRoleAdmin.php index 8a24791d..03184415 100644 --- a/app/Http/Middleware/CheckRoleAdmin.php +++ b/app/Http/Middleware/CheckRoleAdmin.php @@ -21,7 +21,7 @@ class CheckRoleAdmin public function handle(Request $request, Closure $next) { $user = Auth::user(); - if ($user->role == 'admin') { + if ($user->role == 'admin' || $user->role == 'sub-admin') { return $next($request); } return $this->errorResponse(__('api.error.forbidden'), Response::HTTP_FORBIDDEN); diff --git a/app/Http/Middleware/CheckUserBanned.php b/app/Http/Middleware/CheckUserBanned.php new file mode 100644 index 00000000..bb13748b --- /dev/null +++ b/app/Http/Middleware/CheckUserBanned.php @@ -0,0 +1,36 @@ +<?php + +namespace App\Http\Middleware; + +use App\Traits\ApiResponser; +use Closure; +use Illuminate\Http\Request; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Auth; + +class CheckUserBanned +{ + use ApiResponser; + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle(Request $request, Closure $next) + { + $user = Auth::user(); + if ($user->banned == 1) { + return $this->errorResponse(__('api.error.forbidden'), Response::HTTP_FORBIDDEN, 'User banned'); + } + if($request->path() != 'api/v1/users/resend-2fa' && $request->path() != 'api/v1/users/check-login-2fa'){ + if ($user->twoFA_login == 1 && $user->twoFA_login_active == 1) { + return $this->errorResponse(__('Please login again with 2Fa code.'), Response::HTTP_FORBIDDEN, ''); + } + } + + return $next($request); + } +} diff --git a/app/Http/Requests/Api/RegisterEntityRequest.php b/app/Http/Requests/Api/RegisterEntityRequest.php index e6b899be..514f4f1e 100644 --- a/app/Http/Requests/Api/RegisterEntityRequest.php +++ b/app/Http/Requests/Api/RegisterEntityRequest.php @@ -33,7 +33,7 @@ public function rules() 'last_name' => 'required|regex:/^[A-Za-z. ]{1,255}$/', 'email' => 'required|email|max:256|unique:users', 'password' => 'required|min:8|max:80', - 'pseudonym' => 'required|alpha_num|max:200', + 'pseudonym' => 'required|alpha_num|max:200|unique:users', 'telegram' => 'nullable|regex:/^[@][a-zA-Z0-9_-]+$/', ]; } diff --git a/app/Http/Requests/Api/RegisterIndividualRequest.php b/app/Http/Requests/Api/RegisterIndividualRequest.php index e25c434c..4cf1b969 100644 --- a/app/Http/Requests/Api/RegisterIndividualRequest.php +++ b/app/Http/Requests/Api/RegisterIndividualRequest.php @@ -28,7 +28,7 @@ public function rules() 'last_name' =>'required|regex:/^[A-Za-z. ]{2,255}$/', 'email' => 'required|email|max:256|unique:users', 'password' => 'required|min:8|max:80', - 'pseudonym' => 'required|alpha_num|max:200', + 'pseudonym' => 'required|alpha_num|max:200|unique:users', 'telegram' => 'nullable|regex:/^[@][a-zA-Z0-9_-]+$/', ]; } diff --git a/app/Mail/AdminAlert.php b/app/Mail/AdminAlert.php new file mode 100644 index 00000000..ba2e21b9 --- /dev/null +++ b/app/Mail/AdminAlert.php @@ -0,0 +1,44 @@ +<?php + +namespace App\Mail; + +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Mail\Mailable; +use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Config; + +class AdminAlert extends Mailable +{ + use Queueable, SerializesModels; + + protected $title = ""; + protected $content = ""; + + /** + * Create a new message instance. + * + * @return void + */ + public function __construct($title, $content) + { + $this->title = $title; + $this->content = $content; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + // dd(config('app.site_url')); + return $this->view('emails.admin_alert_email') + ->subject($this->title ?? "Notification") + ->with([ + 'title' => $this->title, + 'content' => $this->content + ]); + } +} diff --git a/app/Mail/ContactUsMail.php b/app/Mail/ContactUsMail.php new file mode 100644 index 00000000..89fbff82 --- /dev/null +++ b/app/Mail/ContactUsMail.php @@ -0,0 +1,35 @@ +<?php + +namespace App\Mail; + +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Mail\Mailable; +use Illuminate\Queue\SerializesModels; + +class ContactUsMail extends Mailable +{ + use Queueable, SerializesModels; + + /** + * Create a new message instance. + * + * @return void + */ + public function __construct($contact) + { + $this->contact = $contact; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.contact_us')->subject('Contact Us')->with([ + 'contact' => $this->contact + ]); + } +} diff --git a/app/Mail/InvitationMail.php b/app/Mail/InvitationMail.php new file mode 100644 index 00000000..82ca7a2b --- /dev/null +++ b/app/Mail/InvitationMail.php @@ -0,0 +1,36 @@ +<?php + +namespace App\Mail; + +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Mail\Mailable; +use Illuminate\Queue\SerializesModels; + +class InvitationMail extends Mailable +{ + use Queueable, SerializesModels; + protected $url = ''; + + /** + * Create a new message instance. + * + * @return void + */ + public function __construct($url) + { + $this->url = $url; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.invitation')->subject('Invitation')->with([ + 'url' => $this->url + ]); + } +} diff --git a/app/Mail/KYCApproved.php b/app/Mail/KYCApproved.php new file mode 100644 index 00000000..ea3af7e7 --- /dev/null +++ b/app/Mail/KYCApproved.php @@ -0,0 +1,34 @@ +<?php + +namespace App\Mail; + +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Mail\Mailable; +use Illuminate\Queue\SerializesModels; + +class KYCApproved extends Mailable +{ + use Queueable, SerializesModels; + + /** + * Create a new message instance. + * + * @return void + */ + public function __construct() + { + // + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.kyc_approved') + ->subject('Your KYC is approved'); + } +} diff --git a/app/Mail/KYCDenied.php b/app/Mail/KYCDenied.php new file mode 100644 index 00000000..11f51ffd --- /dev/null +++ b/app/Mail/KYCDenied.php @@ -0,0 +1,34 @@ +<?php + +namespace App\Mail; + +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Mail\Mailable; +use Illuminate\Queue\SerializesModels; + +class KYCDenied extends Mailable +{ + use Queueable, SerializesModels; + + /** + * Create a new message instance. + * + * @return void + */ + public function __construct() + { + // + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.kyc_denied') + ->subject('Your KYC is denied'); + } +} diff --git a/app/Mail/LoginTwoFA.php b/app/Mail/LoginTwoFA.php new file mode 100644 index 00000000..65ca2381 --- /dev/null +++ b/app/Mail/LoginTwoFA.php @@ -0,0 +1,35 @@ +<?php + +namespace App\Mail; + +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Mail\Mailable; +use Illuminate\Queue\SerializesModels; + +class LoginTwoFA extends Mailable +{ + use Queueable, SerializesModels; + + /** + * Create a new message instance. + * + * @return void + */ + public function __construct($code) + { + $this->code = $code; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.two_fa')->subject('Two Factor Auth')->with([ + 'code' => $this->code + ]); + } +} diff --git a/app/Mail/ResetKYC.php b/app/Mail/ResetKYC.php index 80cf2670..ace82102 100644 --- a/app/Mail/ResetKYC.php +++ b/app/Mail/ResetKYC.php @@ -30,7 +30,7 @@ public function __construct($text) public function build() { return $this->view('emails.reset_kyc') - ->subject('You need to submit KYC again') + ->subject('You need to verify your identity again') ->with([ 'text' => $this->text ]); diff --git a/app/Mail/UserAlert.php b/app/Mail/UserAlert.php new file mode 100644 index 00000000..6e20fb61 --- /dev/null +++ b/app/Mail/UserAlert.php @@ -0,0 +1,42 @@ +<?php + +namespace App\Mail; + +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Mail\Mailable; +use Illuminate\Queue\SerializesModels; + +class UserAlert extends Mailable +{ + use Queueable, SerializesModels; + + protected $title = ""; + protected $content = ""; + + /** + * Create a new message instance. + * + * @return void + */ + public function __construct($title, $content) + { + $this->title = $title; + $this->content = $content; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.user_alert_email') + ->subject($this->title ?? "Notification") + ->with([ + 'title' => $this->title, + 'content' => $this->content + ]); + } +} diff --git a/app/Mail/UserConfirmEmail.php b/app/Mail/UserConfirmEmail.php new file mode 100644 index 00000000..90557c33 --- /dev/null +++ b/app/Mail/UserConfirmEmail.php @@ -0,0 +1,43 @@ +<?php + +namespace App\Mail; + +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Mail\Mailable; +use Illuminate\Queue\SerializesModels; + +class UserConfirmEmail extends Mailable +{ + use Queueable, SerializesModels; + + /** + * Create a new message instance. + * + * @return void + */ + public function __construct($title, $content, $url , $action) + { + $this->title = $title; + $this->content = $content; + $this->url = $url; + $this->action = $action; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('emails.confirm_email') + ->subject($this->title ?? "Notification") + ->with([ + 'title' => $this->title, + 'content' => $this->content, + 'url' => $this->url, + 'action' => $this->action, + ]); + } +} diff --git a/app/Models/Ballot.php b/app/Models/Ballot.php new file mode 100644 index 00000000..0ef47417 --- /dev/null +++ b/app/Models/Ballot.php @@ -0,0 +1,40 @@ +<?php + +namespace App\Models; + +use Carbon\Carbon; +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class Ballot extends Model +{ + use HasFactory; + + protected $table = 'ballot'; + protected $guarded = []; + + public function getTimeEndAttribute($value) + { + return Carbon::parse($value); + } + + public function user() + { + return $this->belongsTo('App\Models\User', 'user_id', 'id'); + } + + public function files() + { + return $this->hasMany('App\Models\BallotFile', 'ballot_id'); + } + + public function vote() + { + return $this->hasOne('App\Models\Vote', 'ballot_id'); + } + + public function voteResults() + { + return $this->hasMany('App\Models\VoteResult', 'ballot_id'); + } +} diff --git a/app/Models/BallotFile.php b/app/Models/BallotFile.php new file mode 100644 index 00000000..17f6b6c8 --- /dev/null +++ b/app/Models/BallotFile.php @@ -0,0 +1,23 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class BallotFile extends Model +{ + use HasFactory; + + protected $table = 'ballot_file'; + protected $guarded = []; + + protected $appends = [ + 'file_url', + ]; + + public function getFileUrlAttribute() + { + return $this->url; + } +} diff --git a/app/Models/BallotFileView.php b/app/Models/BallotFileView.php new file mode 100644 index 00000000..e3ce5301 --- /dev/null +++ b/app/Models/BallotFileView.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class BallotFileView extends Model +{ + use HasFactory; + + protected $table = 'ballot_file_view'; + protected $guarded = []; + + public function user() + { + return $this->belongsTo('App\Models\User', 'user_id', 'id'); + } +} diff --git a/app/Models/ContactRecipient.php b/app/Models/ContactRecipient.php new file mode 100644 index 00000000..a3261515 --- /dev/null +++ b/app/Models/ContactRecipient.php @@ -0,0 +1,13 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class ContactRecipient extends Model +{ + use HasFactory; + protected $table = 'contact_recipient'; + protected $guarded = []; +} diff --git a/app/Models/ContactUs.php b/app/Models/ContactUs.php new file mode 100644 index 00000000..99759272 --- /dev/null +++ b/app/Models/ContactUs.php @@ -0,0 +1,13 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class ContactUs extends Model +{ + use HasFactory; + protected $table = 'contact_us'; + protected $guarded = []; +} diff --git a/app/Models/Discussion.php b/app/Models/Discussion.php new file mode 100644 index 00000000..c0e06bb7 --- /dev/null +++ b/app/Models/Discussion.php @@ -0,0 +1,42 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; +use Carbon\Carbon; + +class Discussion extends Model +{ + use HasFactory; + protected $guarded = []; + protected $hidden = ['updated_at']; + protected $appends = ['is_new', 'total_pinned']; + protected $with = ['user']; + + public function commentsList() + { + return $this->hasMany('App\Models\DiscussionComment'); + } + + public function user() + { + return $this->belongsTo('App\Models\User'); + } + + public function getIsNewAttribute() + { + $user = auth()->user(); + $notRemoved = DiscussionRemoveNew::where([ + 'user_id' => $user->id, + 'discussion_id' => $this->id + ])->first() == null; + $notOld = Carbon::now()->diffInDays(Carbon::parse($this->created_at)) < 3; + return $notOld && $notRemoved; + } + + public function getTotalPinnedAttribute() + { + return DiscussionPin::where('discussion_id', $this->id)->count(); + } +} diff --git a/app/Models/DiscussionComment.php b/app/Models/DiscussionComment.php new file mode 100644 index 00000000..772a1c2a --- /dev/null +++ b/app/Models/DiscussionComment.php @@ -0,0 +1,22 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class DiscussionComment extends Model +{ + use HasFactory; + protected $guarded = []; + protected $hidden = ['created_at', 'updated_at']; + protected $with = ['user']; + + public function discussion() { + return $this->belongsTo('App\Models\Discussion'); + } + + public function user() { + return $this->belongsTo('App\Models\User'); + } +} diff --git a/app/Models/DiscussionPin.php b/app/Models/DiscussionPin.php new file mode 100644 index 00000000..7f1dcbea --- /dev/null +++ b/app/Models/DiscussionPin.php @@ -0,0 +1,27 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class DiscussionPin extends Model +{ + use HasFactory; + protected $guarded = []; + protected $hidden = ['created_at', 'updated_at']; + protected $appends = ['total_pinned']; + protected $with = ['discussion']; + + public function discussion() { + return $this->belongsTo('App\Models\Discussion'); + } + public function user() { + return $this->belongsTo('App\Models\User'); + } + + public function getTotalPinnedAttribute() + { + return DiscussionPin::where('discussion_id', $this->discussion_id)->count(); + } +} diff --git a/app/Models/DiscussionRemoveNew.php b/app/Models/DiscussionRemoveNew.php new file mode 100644 index 00000000..d10c6d75 --- /dev/null +++ b/app/Models/DiscussionRemoveNew.php @@ -0,0 +1,18 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class DiscussionRemoveNew extends Model +{ + use HasFactory; + protected $guarded = []; + protected $hidden = ['created_at', 'updated_at']; + protected $with = ['discussion']; + + public function discussion() { + return $this->belongsTo('App\Models\Discussion'); + } +} diff --git a/app/Models/DiscussionVote.php b/app/Models/DiscussionVote.php new file mode 100644 index 00000000..fc29d550 --- /dev/null +++ b/app/Models/DiscussionVote.php @@ -0,0 +1,13 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class DiscussionVote extends Model +{ + use HasFactory; + protected $guarded = []; + protected $hidden = ['created_at', 'updated_at']; +} diff --git a/app/Models/DocumentFile.php b/app/Models/DocumentFile.php new file mode 100644 index 00000000..9d5fcf55 --- /dev/null +++ b/app/Models/DocumentFile.php @@ -0,0 +1,23 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class DocumentFile extends Model +{ + use HasFactory; + + protected $table = 'document_file'; + protected $guarded = []; + + protected $appends = [ + 'file_url', + ]; + + public function getFileUrlAttribute() + { + return $this->url; + } +} diff --git a/app/Models/Donation.php b/app/Models/Donation.php new file mode 100644 index 00000000..a788d103 --- /dev/null +++ b/app/Models/Donation.php @@ -0,0 +1,13 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class Donation extends Model +{ + use HasFactory; + protected $table = 'donation'; + protected $guarded = []; +} diff --git a/app/Models/EmailerAdmin.php b/app/Models/EmailerAdmin.php new file mode 100644 index 00000000..b02c9869 --- /dev/null +++ b/app/Models/EmailerAdmin.php @@ -0,0 +1,10 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Model; + +class EmailerAdmin extends Model +{ + protected $table = 'emailer_admin'; +} diff --git a/app/Models/EmailerTriggerAdmin.php b/app/Models/EmailerTriggerAdmin.php new file mode 100644 index 00000000..467eddf6 --- /dev/null +++ b/app/Models/EmailerTriggerAdmin.php @@ -0,0 +1,10 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Model; + +class EmailerTriggerAdmin extends Model +{ + protected $table = 'emailer_trigger_admin'; +} diff --git a/app/Models/EmailerTriggerUser.php b/app/Models/EmailerTriggerUser.php new file mode 100644 index 00000000..c44fbe43 --- /dev/null +++ b/app/Models/EmailerTriggerUser.php @@ -0,0 +1,10 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Model; + +class EmailerTriggerUser extends Model +{ + protected $table = 'emailer_trigger_user'; +} diff --git a/app/Models/IpHistory.php b/app/Models/IpHistory.php new file mode 100644 index 00000000..e612cf97 --- /dev/null +++ b/app/Models/IpHistory.php @@ -0,0 +1,14 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class IpHistory extends Model +{ + use HasFactory; + protected $table = 'ip_history'; + protected $guarded = []; + +} diff --git a/app/Models/KeyPeer.php b/app/Models/KeyPeer.php new file mode 100644 index 00000000..b8c68bfe --- /dev/null +++ b/app/Models/KeyPeer.php @@ -0,0 +1,14 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class KeyPeer extends Model +{ + use HasFactory; + + protected $table = 'key_peers'; + protected $guarded = []; +} diff --git a/app/Models/LockRules.php b/app/Models/LockRules.php new file mode 100644 index 00000000..d2cb8d8f --- /dev/null +++ b/app/Models/LockRules.php @@ -0,0 +1,12 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class LockRules extends Model +{ + use HasFactory; + protected $table = 'lock_rules'; +} diff --git a/app/Models/MembershipAgreementFile.php b/app/Models/MembershipAgreementFile.php new file mode 100644 index 00000000..ea1679cc --- /dev/null +++ b/app/Models/MembershipAgreementFile.php @@ -0,0 +1,22 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class MembershipAgreementFile extends Model +{ + use HasFactory; + protected $table = 'membership_agreement_file'; + protected $guarded = []; + + protected $appends = [ + 'file_url', + ]; + + public function getFileUrlAttribute() + { + return $this->url; + } +} diff --git a/app/Models/Metric.php b/app/Models/Metric.php new file mode 100644 index 00000000..8c2f0ebb --- /dev/null +++ b/app/Models/Metric.php @@ -0,0 +1,18 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class Metric extends Model +{ + use HasFactory; + protected $table = 'metric'; + protected $guarded = []; + + + public function user() { + return $this->belongsTo('App\Models\User', 'user_id', 'id'); + } +} diff --git a/app/Models/MonitoringCriteria.php b/app/Models/MonitoringCriteria.php new file mode 100644 index 00000000..d423a379 --- /dev/null +++ b/app/Models/MonitoringCriteria.php @@ -0,0 +1,12 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class MonitoringCriteria extends Model +{ + use HasFactory; + protected $table = 'monitoring_criteria'; +} diff --git a/app/Models/Node.php b/app/Models/Node.php new file mode 100644 index 00000000..8da0fa4e --- /dev/null +++ b/app/Models/Node.php @@ -0,0 +1,14 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class Node extends Model +{ + use HasFactory; + protected $table = 'nodes'; + + protected $guarded = []; +} diff --git a/app/Models/NodeInfo.php b/app/Models/NodeInfo.php new file mode 100644 index 00000000..a26364af --- /dev/null +++ b/app/Models/NodeInfo.php @@ -0,0 +1,14 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class NodeInfo extends Model +{ + use HasFactory; + protected $table = 'node_info'; + + protected $guarded = []; +} diff --git a/app/Models/Notification.php b/app/Models/Notification.php new file mode 100644 index 00000000..74885d7d --- /dev/null +++ b/app/Models/Notification.php @@ -0,0 +1,13 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Storage; + +class Notification extends Model +{ + use HasFactory; + protected $table = 'notification'; +} diff --git a/app/Models/NotificationView.php b/app/Models/NotificationView.php new file mode 100644 index 00000000..94215c43 --- /dev/null +++ b/app/Models/NotificationView.php @@ -0,0 +1,21 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Storage; + +class NotificationView extends Model +{ + use HasFactory; + protected $table = 'notification_view'; + + public function perk() { + return $this->belongsTo('App\Models\Notification', 'notification_id', 'id'); + } + + public function user() { + return $this->belongsTo('App\Models\User', 'user_id', 'id'); + } +} diff --git a/app/Models/Perk.php b/app/Models/Perk.php new file mode 100644 index 00000000..ff6cf5ef --- /dev/null +++ b/app/Models/Perk.php @@ -0,0 +1,37 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Storage; + +class Perk extends Model +{ + use HasFactory; + protected $table = 'perk'; + protected $guarded = []; + + /** + * The accessors to append to the model's array form. + * + * @var array + */ + protected $appends = [ + 'image_url', + ]; + + public function user() { + return $this->belongsTo('App\Models\User', 'user_id', 'id'); + } + + public function getImageUrlAttribute() + { + if(!$this->image) { + return null; + } + // $url = Storage::disk('local')->url($this->image); + // return asset($url); + return $this->image; + } +} diff --git a/app/Models/PerkResult.php b/app/Models/PerkResult.php new file mode 100644 index 00000000..afd1b263 --- /dev/null +++ b/app/Models/PerkResult.php @@ -0,0 +1,21 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class PerkResult extends Model +{ + use HasFactory; + protected $table = 'perk_result'; + protected $guarded = []; + + public function perk() { + return $this->belongsTo('App\Models\Perk', 'perk_id', 'id'); + } + + public function user() { + return $this->belongsTo('App\Models\User', 'user_id', 'id'); + } +} diff --git a/app/Models/Permission.php b/app/Models/Permission.php new file mode 100644 index 00000000..44fcd131 --- /dev/null +++ b/app/Models/Permission.php @@ -0,0 +1,14 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class Permission extends Model +{ + use HasFactory; + protected $table = 'permission'; + protected $guarded = []; + +} diff --git a/app/Models/Profile.php b/app/Models/Profile.php index 8cead144..280065fb 100644 --- a/app/Models/Profile.php +++ b/app/Models/Profile.php @@ -2,6 +2,7 @@ namespace App\Models; +use Carbon\Carbon; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -9,5 +10,12 @@ class Profile extends Model { use HasFactory; protected $table = 'profile'; - protected $guarded = []; + protected $guarded = []; + public function getDocumentVerifiedAtAttribute($value) + { + if ($value) { + return Carbon::parse($value); + } + return null; + } } diff --git a/app/Models/Setting.php b/app/Models/Setting.php new file mode 100644 index 00000000..c03b2a33 --- /dev/null +++ b/app/Models/Setting.php @@ -0,0 +1,13 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class Setting extends Model +{ + use HasFactory; + protected $table = 'settings'; + protected $guarded = []; +} diff --git a/app/Models/Shuftipro.php b/app/Models/Shuftipro.php index d73fd6de..59865c17 100644 --- a/app/Models/Shuftipro.php +++ b/app/Models/Shuftipro.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Storage; class Shuftipro extends Model { @@ -13,4 +14,22 @@ class Shuftipro extends Model protected $casts = [ 'data' => 'array' ]; + + public function getDocumentProofUrlAttribute() + { + if(!$this->document_proof) { + return null; + } + $url = Storage::disk('local')->url($this->document_proof); + return asset($url); + } + + public function getAddressProofUrlAttribute() + { + if(!$this->address_proof) { + return null; + } + $url = Storage::disk('local')->url($this->address_proof); + return asset($url); + } } diff --git a/app/Models/TokenPrice.php b/app/Models/TokenPrice.php new file mode 100644 index 00000000..a6d5981d --- /dev/null +++ b/app/Models/TokenPrice.php @@ -0,0 +1,12 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class TokenPrice extends Model +{ + use HasFactory; + protected $table = 'token_price'; +} diff --git a/app/Models/User.php b/app/Models/User.php index 75c30194..a312f445 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -7,13 +7,20 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; +use Illuminate\Support\Facades\Storage; + use Laravel\Passport\HasApiTokens; +use App\Models\Discussion; +use App\Models\DiscussionRemoveNew; + +use Carbon\Carbon; + class User extends Authenticatable { - use HasFactory, Notifiable, HasApiTokens, SoftDeletes; - const TYPE_INDIVIDUAL = 'Individual'; - const TYPE_ENTITY = 'Entity'; + use HasFactory, Notifiable, HasApiTokens; + const TYPE_INDIVIDUAL = 'individual'; + const TYPE_ENTITY = 'entity'; const STATUS_INCOMPLETE = 'Incomplete'; const STATUS_INTAKE = 'Intake'; @@ -52,6 +59,14 @@ class User extends Authenticatable 'signed_file', 'hellosign_form', 'letter_file', + 'banned', + 'letter_verified_at', + 'letter_rejected_at', + 'avatar', + 'average_peers', + 'validator_fee', + 'cspr_delegated', + 'cspr_self_staked', ]; /** @@ -72,7 +87,11 @@ class User extends Authenticatable */ protected $appends = [ 'full_name', - 'signed_file_url' + 'signed_file_url', + 'pinned', + 'new_threads', + 'letter_file_url', + 'avatar_url', ]; /** @@ -85,6 +104,7 @@ class User extends Authenticatable 'created_at' => 'datetime', 'updated_at' => 'datetime', 'node_verified_at' => 'datetime', + 'permissions' => 'array' ]; /** @@ -97,6 +117,36 @@ public function getFullNameAttribute() return "{$this->first_name} {$this->last_name}"; } + /** + * Get the user's full name. + * + * @return string + */ + public function getLetterFileUrlAttribute() + { + if(!$this->letter_file) { + return null; + } + // $url = Storage::disk('local')->url($this->letter_file); + // return asset($url); + return $this->letter_file; + } + + public function getAvatarUrlAttribute() + { + if(!$this->avatar) { + return null; + } + $url = ''; + if (strpos($this->avatar, 'http') !== false) { + $url = $this->avatar; + } else { + $url = Storage::disk('local')->url($this->avatar); + } + return $url; + } + + public function getSignedFileUrlAttribute() { return url('/') . $this->signed_file; @@ -118,4 +168,46 @@ public function shuftiproTemp() { public function ownerNodes() { return $this->hasMany('App\Models\OwnerNode', 'user_id'); } + + public function pinnedDiscussionsList() { + return $this->hasMany('App\Models\DiscussionPin'); + } + + public function myDiscussionsList() { + return $this->hasMany('App\Models\Discussion'); + } + + public function getPinnedAttribute() { + return $this->pinnedDiscussionsList()->count(); + } + + public function permissions() { + return $this->hasMany('App\Models\Permission', 'user_id'); + } + + public function ipHistories() { + return $this->hasMany('App\Models\IpHistory', 'user_id'); + } + + public function metric() { + return $this->hasOne('App\Models\Metric', 'user_id'); + } + + public function nodeInfo() { + return $this->hasOne('App\Models\NodeInfo', 'node_address', 'public_address_node'); + } + + public function getNewThreadsAttribute() { + $removedNews = DiscussionRemoveNew::where(['user_id' => $this->id])->pluck('discussion_id'); + $count = Discussion::whereNotIn('id', $removedNews) + ->whereDate('created_at', '>', Carbon::now()->subDays(3)) + ->count(); + + return $count; + } + + public function documentFiles() { + return $this->hasMany('App\Models\DocumentFile'); + } + } diff --git a/app/Models/VerifyUser.php b/app/Models/VerifyUser.php index a18457b8..59ea1e3b 100644 --- a/app/Models/VerifyUser.php +++ b/app/Models/VerifyUser.php @@ -12,6 +12,10 @@ class VerifyUser extends Model const TOKEN_LIFETIME = 300; const TYPE_VERIFY_EMAIL= 'verify_email'; const TYPE_RESET_PASSWORD= 'reset_password'; + const TYPE_CANCEL_EMAIL= 'cancel_email'; + const TYPE_CONFIRM_EMAIL= 'confirm_email'; + const TYPE_LOGIN_TWO_FA= 'login_twoFA'; + const TYPE_INVITE_ADMIN= 'invite_admin'; public $timestamps = false; public $primaryKey = 'email'; diff --git a/app/Models/Vote.php b/app/Models/Vote.php new file mode 100644 index 00000000..205e5c99 --- /dev/null +++ b/app/Models/Vote.php @@ -0,0 +1,21 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class Vote extends Model +{ + use HasFactory; + protected $table = 'vote'; + protected $guarded = []; + + public function ballot() { + return $this->hasOne('App\Models\Ballot', 'ballot_id', 'id'); + } + + public function voteResults() { + return $this->hasMany('App\Models\VoteResult', 'vote_id', 'id'); + } +} diff --git a/app/Models/VoteResult.php b/app/Models/VoteResult.php new file mode 100644 index 00000000..a2db5e15 --- /dev/null +++ b/app/Models/VoteResult.php @@ -0,0 +1,25 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class VoteResult extends Model +{ + use HasFactory; + protected $table = 'vote_result'; + protected $guarded = []; + + public function ballot() { + return $this->belongsTo('App\\Models\Ballot', 'id', 'ballot_id'); + } + + public function vote() { + return $this->belongsTo('App\Models\Vote', 'id', 'vote_id'); + } + + public function user() { + return $this->belongsTo('App\Models\User', 'user_id', 'id'); + } +} diff --git a/app/Repositories/Base/BaseRepository.php b/app/Repositories/Base/BaseRepository.php index 0d4baa46..04f700b3 100644 --- a/app/Repositories/Base/BaseRepository.php +++ b/app/Repositories/Base/BaseRepository.php @@ -154,6 +154,24 @@ public function delete($id) } } + /** + * Delete data. + * + * @param array $where [array input] + * + * @return object + */ + public function deleteConditions(array $where) + { + $data = null; + try { + $data = $this->model->where($where)->delete(); + return $data; + } catch (Exception $e) { + throw $e; + } + } + public function firstOrCreate(array $attributes, array $values = array()) { try { diff --git a/app/Repositories/DiscussionCommentRepository.php b/app/Repositories/DiscussionCommentRepository.php new file mode 100644 index 00000000..882069e6 --- /dev/null +++ b/app/Repositories/DiscussionCommentRepository.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Repositories; + +use App\Models\DiscussionComment; +use App\Repositories\Base\BaseRepository; + +class DiscussionCommentRepository extends BaseRepository +{ + /** + * Get model. + * + * @return string + */ + public function getModel() + { + return DiscussionComment::class; + } +} \ No newline at end of file diff --git a/app/Repositories/DiscussionPinRepository.php b/app/Repositories/DiscussionPinRepository.php new file mode 100644 index 00000000..939b6248 --- /dev/null +++ b/app/Repositories/DiscussionPinRepository.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Repositories; + +use App\Models\DiscussionPin; +use App\Repositories\Base\BaseRepository; + +class DiscussionPinRepository extends BaseRepository +{ + /** + * Get model. + * + * @return string + */ + public function getModel() + { + return DiscussionPin::class; + } +} \ No newline at end of file diff --git a/app/Repositories/DiscussionRemoveNewRepository.php b/app/Repositories/DiscussionRemoveNewRepository.php new file mode 100644 index 00000000..f900d94c --- /dev/null +++ b/app/Repositories/DiscussionRemoveNewRepository.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Repositories; + +use App\Models\DiscussionRemoveNew; +use App\Repositories\Base\BaseRepository; + +class DiscussionRemoveNewRepository extends BaseRepository +{ + /** + * Get model. + * + * @return string + */ + public function getModel() + { + return DiscussionRemoveNew::class; + } +} \ No newline at end of file diff --git a/app/Repositories/DiscussionRepository.php b/app/Repositories/DiscussionRepository.php new file mode 100644 index 00000000..0588e732 --- /dev/null +++ b/app/Repositories/DiscussionRepository.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Repositories; + +use App\Models\Discussion; +use App\Repositories\Base\BaseRepository; + +class DiscussionRepository extends BaseRepository +{ + /** + * Get model. + * + * @return string + */ + public function getModel() + { + return Discussion::class; + } +} \ No newline at end of file diff --git a/app/Repositories/DiscussionVoteRepository.php b/app/Repositories/DiscussionVoteRepository.php new file mode 100644 index 00000000..e3cabd4e --- /dev/null +++ b/app/Repositories/DiscussionVoteRepository.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Repositories; + +use App\Models\DiscussionVote; +use App\Repositories\Base\BaseRepository; + +class DiscussionVoteRepository extends BaseRepository +{ + /** + * Get model. + * + * @return string + */ + public function getModel() + { + return DiscussionVote::class; + } +} \ No newline at end of file diff --git a/app/Services/ChecksumValidator.php b/app/Services/ChecksumValidator.php new file mode 100644 index 00000000..47f07906 --- /dev/null +++ b/app/Services/ChecksumValidator.php @@ -0,0 +1,418 @@ +<?php + +namespace App\Services; + +class Blake2b { + const BLOCKBYTES = 128; + const OUTBYTES = 64; + const KEYBYTES = 64; + + public function __construct($size = 32) { + $this->size = $size; + + $this->iv = []; + $this->iv[0] = $this->new64(0x6a09e667, 0xf3bcc908); + $this->iv[1] = $this->new64(0xbb67ae85, 0x84caa73b); + $this->iv[2] = $this->new64(0x3c6ef372, 0xfe94f82b); + $this->iv[3] = $this->new64(0xa54ff53a, 0x5f1d36f1); + $this->iv[4] = $this->new64(0x510e527f, 0xade682d1); + $this->iv[5] = $this->new64(0x9b05688c, 0x2b3e6c1f); + $this->iv[6] = $this->new64(0x1f83d9ab, 0xfb41bd6b); + $this->iv[7] = $this->new64(0x5be0cd19, 0x137e2179); + } + + public function hash($data) { + $ctx = $this->init(null, $this->size); + $this->update($ctx, $data, strlen($data)); + return substr($this->finish($ctx), 0, $this->size); + } + + private function new64($high, $low) { + $i64 = []; + $i64[0] = $high & 0xffffffff; + $i64[1] = $low & 0xffffffff; + return $i64; + } + + private function to64($num) { + return $this->new64(0, $num & 0xffffffff); + } + + private function add64($x, $y) { + $l = ($x[1] + $y[1]) & 0xffffffff; + + if (PHP_INT_SIZE > 4) + $c = $l < $x[1] ? 1 : 0; + else { + if ((($x[1] < 0 && $y[1] < 0 )) || (($x[1] < 0 || $y[1] < 0 ) && $l >= 0)) + $c = 1; + else + $c = 0; + } + + return $this->new64($x[0] + $y[0] + $c, $l); + } + + private function add364($x, $y, $z) { + return $this->add64($x, $this->add64($y, $z)); + } + + private function xor64($x, $y) { + return $this->new64($x[0] ^ $y[0], $x[1] ^ $y[1]); + } + + private function rs($x, $s) { + if($s) + return ($x >> $s) & ~( 1 << ( 8 * PHP_INT_SIZE - 1 ) >> ( $s - 1 )); + return $x; + } + + private function rotr64($x, $c) { + $h0 = 0; + $l0 = 0; + $c = 64 - $c; + + if ($c < 32) { + $h0 = ($x[0] << $c) | $this->rs( $x[1] & ( ( 1 << $c ) - 1 ) << ( 32 - $c ), 32 - $c); + $l0 = $x[1] << $c; + } else + $h0 = $x[1] << ( $c - 32 ); + + $h1 = 0; + $l1 = 0; + $c1 = 64 - $c; + + if ($c1 < 32) { + $h1 = $this->rs($x[0], $c1); + $l1 = $this->rs($x[1], $c1) | ( $x[0] & ( ( 1 << $c1 ) - 1 ) ) << (32 - $c1); + } else + $l1 = $this->rs($x[0], $c1 - 32); + + return $this->new64($h0 | $h1, $l0 | $l1); + } + + private function flatten64($x) { + return ($x[0] * 4294967296 + $x[1]); + } + + private function load64($x, $i) { + $l = $x[$i] | ( $x[$i + 1] << 8 ) | ( $x[$i + 2] << 16 ) | ( $x[$i + 3] << 24 ); + $h = $x[$i + 4] | ( $x[$i + 5] << 8 ) | ( $x[$i + 6] << 16 ) | ( $x[$i + 7] << 24 ); + return $this->new64( $h, $l ); + } + + private $sigma = [ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], + [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ], + [ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ], + [ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ], + [ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ], + [ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ], + [ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ], + [ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ], + [ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ], + [ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 ], + [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], + [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] ]; + + private function context() { + $ctx = []; + $ctx[0] = []; // h + $ctx[1] = []; // t + $ctx[2] = []; // f + $ctx[3] = []; // buf + $ctx[4] = 0; // buflen + + for( $i = 8; $i--; ) + $ctx[0][$i] = $this->iv[$i]; + + for( $i = 256; $i--; ) + $ctx[3][$i] = 0; + + $zero = $this->new64( 0, 0 ); + $ctx[1][0] = $zero; + $ctx[1][1] = $zero; + $ctx[2][0] = $zero; + $ctx[2][1] = $zero; + + return $ctx; + } + + private function G( &$v, $m, $r, $i, $a, $b, $c, $d ) { + $v[$a] = $this->add364( $v[$a], $v[$b], $m[$this->sigma[$r][2 * $i]] ); + $v[$d] = $this->rotr64( $this->xor64( $v[$d], $v[$a] ), 32 ); + $v[$c] = $this->add64( $v[$c], $v[$d] ); + $v[$b] = $this->rotr64( $this->xor64( $v[$b], $v[$c] ), 24 ); + $v[$a] = $this->add364( $v[$a], $v[$b], $m[$this->sigma[$r][2 * $i + 1]] ); + $v[$d] = $this->rotr64( $this->xor64( $v[$d], $v[$a] ), 16 ); + $v[$c] = $this->add64( $v[$c], $v[$d] ); + $v[$b] = $this->rotr64( $this->xor64( $v[$b], $v[$c] ), 63 ); + } + + private function compress( &$ctx, $buf ) { + $m = []; + $v = []; + + for( $i = 16; $i--; ) + $m[$i] = $this->load64( $buf, $i * 8 ); + + for( $i = 8; $i--; ) + $v[$i] = $ctx[0][$i]; + + $v[ 8] = $this->iv[0]; + $v[ 9] = $this->iv[1]; + $v[10] = $this->iv[2]; + $v[11] = $this->iv[3]; + + $v[12] = $this->xor64( $ctx[1][0], $this->iv[4] ); + $v[13] = $this->xor64( $ctx[1][1], $this->iv[5] ); + $v[14] = $this->xor64( $ctx[2][0], $this->iv[6] ); + $v[15] = $this->xor64( $ctx[2][1], $this->iv[7] ); + + for( $r = 0; $r < 12; ++$r ) + { + $this->G( $v, $m, $r, 0, 0, 4, 8, 12 ); + $this->G( $v, $m, $r, 1, 1, 5, 9, 13 ); + $this->G( $v, $m, $r, 2, 2, 6, 10, 14 ); + $this->G( $v, $m, $r, 3, 3, 7, 11, 15 ); + $this->G( $v, $m, $r, 4, 0, 5, 10, 15 ); + $this->G( $v, $m, $r, 5, 1, 6, 11, 12 ); + $this->G( $v, $m, $r, 6, 2, 7, 8, 13 ); + $this->G( $v, $m, $r, 7, 3, 4, 9, 14 ); + } + + for( $i = 8; $i--; ) + $ctx[0][$i] = $this->xor64( $ctx[0][$i], $this->xor64( $v[$i], $v[$i + 8] ) ); + } + + private function increment_counter( &$ctx, $inc ) { + $t = $this->to64( $inc ); + $ctx[1][0] = $this->add64( $ctx[1][0], $t ); + if( $this->flatten64( $ctx[1][0] ) < $inc ) + $ctx[1][1] = $this->add64( $ctx[1][1], $this->to64( 1 ) ); + } + + private function update(&$ctx, $p, $plen) { + $offset = 0; $left = 0; $fill = 0; + + while($plen > 0) { + $left = $ctx[4]; + $fill = 256 - $left; + + if( $plen > $fill ) + { + for( $i = $fill; $i--; ) + $ctx[3][$i + $left] = ord( $p[$i + $offset] ); + + $ctx[4] += $fill; + + $this->increment_counter( $ctx, 128 ); + $this->compress( $ctx, $ctx[3] ); + + for( $i = 128; $i--; ) + $ctx[3][$i] = $ctx[3][$i + 128]; + + $ctx[4] -= 128; + $offset += $fill; + $plen -= $fill; + } else { + for( $i = $plen; $i--; ) + $ctx[3][$i + $left] = ord( $p[$i + $offset] ); + + $ctx[4] += $plen; + $offset += $plen; + $plen -= $plen; + } + } + } + + private function finish($ctx) { + if ($ctx[4] > 128) { + $this->increment_counter($ctx, 128); + $this->compress($ctx, $ctx[3]); + $ctx[4] -= 128; + for($i = $ctx[4]; $i--;) + $ctx[3][$i] = $ctx[3][$i + 128]; + } + + $this->increment_counter($ctx, $ctx[4]); + $ctx[2][0] = $this->new64(0xffffffff, 0xffffffff); + + for($i = 256 - $ctx[4]; $i--;) + $ctx[3][$i + $ctx[4]] = 0; + + $this->compress($ctx, $ctx[3]); + + $out = ''; + for ($i = 8; $i--;) { + $out .= pack('N', $ctx[0][$i][0]); + $out .= pack('N', $ctx[0][$i][1]); + } + return strrev($out); + } + + private function init($key = null, $outlen = 64) { + $klen = isset($key) ? count($key) : 0; + if ($klen > 64 || $outlen > 64) + return false; + + $ctx = $this->context(); + + $p = []; + for($i = 64; $i--;) + $p[$i] = 0; + + $p[0] = $outlen; // digest_length + $p[1] = $klen; // key_length + $p[2] = 1; // fanout + $p[3] = 1; // depth + + $ctx[0][0] = $this->xor64($ctx[0][0], $this->load64($p, 0)); + + if ($klen > 0) { + $block = []; + for ($i = 128; $i--;) $block[$i] = 0; + for ($i = $klen; $i--;) $block[$i] = $key[$i]; + $this->update($ctx, $block, 128); + } + + return $ctx; + } +} + +class ChecksumValidator { + function __construct($vid = null) { + $this->validator_id = null; + $this->keytag = '01'; + $this->algo = 'ed25519'; + + if($vid) { + $this->validator_id = $vid; + } + + $this->HEX_CHARS = array( + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', + 'A', 'B', 'C', 'D', 'E', 'F' + ); + + $this->SMALL_BYTES_COUNT = 75; + } + + function _blake_hash($public_key) { + $blake = new Blake2b($size = 32); + $hash = $blake->hash($public_key); + return $hash; + } + + function _bytes_to_nibbles($v) { + $output_nibbles = array(); + + foreach(str_split($v) as $byte) { + $byte = ord($byte); + $output_nibbles[] = ($byte >> 4); + $output_nibbles[] = ($byte & 0x0f); + } + + return $output_nibbles; + } + + function _bytes_to_bits_cycle($v) { + $_blake_hash = $this->_blake_hash($v); + $ret = array(); + + foreach(str_split($_blake_hash) as $b) { + $b = ord($b); + + for($j = 0; $j < 8; $j++) { + $ret[] = (($b >> $j) & 0x01); + } + } + + return $ret; + } + + function _encode($public_key) { + $nibbles = $this->_bytes_to_nibbles($public_key); + $hash_bits = $this->_bytes_to_bits_cycle($public_key); + $ret = array(); + $k = 0; + + foreach($nibbles as $nibble) { + if($nibble >= 10) { + if($hash_bits[$k] == 1) { + $nibble += 6; + } + + $k += 1; + } + + $ret[] = $this->HEX_CHARS[$nibble]; + } + + $join = array_reduce( + $ret, + function($out, $in) { + return ord($out) << 8 | ord($in); + } + ); + + $join = ''; + + foreach($ret as $char) { + $join = $join.$char; + } + + return $join; + } + + function do($_v = null) { + if($this->validator_id) { + $this->keytag = substr($this->validator_id, 0, 2); + $reference_validator_id = $this->validator_id; + $this->validator_id = strtolower(substr($reference_validator_id, 2)); + + if($this->keytag == '01') { + $this->algo = 'ed25519'; + } elseif ($this->keytag == '02') { + $this->algo = 'secp256k1'; + } else { + return false; + } + + $v = hex2bin($this->validator_id); + + if(mb_strlen($v, '8bit') > $this->SMALL_BYTES_COUNT) { + return true; + } + + $join = $this->keytag . $this->_encode($v); + + return $join == $reference_validator_id; + + } else { + if (!$_v) { + return false; + } + + $this->keytag = substr($_v, 0, 2); + $_v = substr($_v, 2); + + if($this->keytag == '01') { + $this->algo = 'ed25519'; + } elseif ($this->keytag == '02') { + $this->algo = 'secp256k1'; + } else { + return false; + } + + $v = hex2bin($_v); + + if(mb_strlen($v, '8bit') > $this->SMALL_BYTES_COUNT) { + return strtolower($_v); + } + + return $this->keytag . $this->_encode($v); + } + } +} +?> diff --git a/app/Services/NodeHelper.php b/app/Services/NodeHelper.php new file mode 100644 index 00000000..201ae556 --- /dev/null +++ b/app/Services/NodeHelper.php @@ -0,0 +1,155 @@ +<?php + +namespace App\Services; + +use App\Models\KeyPeer; +use App\Models\Node; +use App\Models\NodeInfo; +use App\Models\User; +use App\Models\Setting; + +use Carbon\Carbon; + +use Exception; + +use Illuminate\Http\Request; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\Validator; + +use GuzzleHttp\Client; +use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\Exception\ServerException; +use GuzzleHttp\Exception\BadResponseException; + +use App\Services\ChecksumValidator; + +class NodeHelper +{ + public function __construct() + { + $this->SEENA_API_KEY = getenv('SEENA_API_KEY'); + } + + public function getValidatorStanding() + { + $response = Http::withHeaders([ + 'Authorization' => "token $this->SEENA_API_KEY", + ])->withOptions([ + 'verify' => false, + ])->get('https://seena.ledgerleap.com/validator-standing'); + return $response->json(); + } + + public function getTotalRewards($validatorId) + { + $response = Http::withOptions([ + 'verify' => false, + ])->get("https://api.CSPR.live/validators/$validatorId/total-rewards"); + return $response->json(); + } + + public function updateStats() + { + $data = $this->getValidatorStanding(); + + $validator_standing = isset($data['validator_standing']) ? $data['validator_standing'] : null; + + $mbs = isset($data['MBS']) ? $data['MBS'] : 0; + $peers = isset($data['peers']) ? $data['peers'] : 0; + + $setting = Setting::where('name', 'peers')->first(); + if (!$setting) { + $setting = new Setting; + $setting->name = 'peers'; + $setting->value = ''; + $setting->save(); + } + $setting->value = $peers; + $setting->save(); + + $users = User::whereNotNull('public_address_node')->get(); + if ($validator_standing) { + // Refresh Validator Standing + foreach ($validator_standing as $key => $value) { + // $newKey = (new ChecksumValidator())->do($key); + $validator_standing[strtolower($key)] = $value; + } + + foreach ($users as $user) { + $validatorid = strtolower($user->public_address_node); + // $validatorid = (new ChecksumValidator())->do($validatorid); + + if (isset($validator_standing[$validatorid])) { + $info = $validator_standing[$validatorid]; + $fee = (float) $info['delegation_rate']; + + $user->pending_node = 0; + $user->validator_fee = round($fee, 2); + $user->save(); + + $totalRewards = $this->getTotalRewards($validatorid); + + $build_version = $info['build_version'] ?? null; + if ($build_version) { + $build_version = explode('-', $build_version); + $build_version = $build_version[0]; + } + + $is_open_port = isset($info['uptime']) && isset($info['update_responsiveness']) ? 1 : 0; + + NodeInfo::updateOrCreate( + [ + 'node_address' => $validatorid + ], + [ + 'delegators_count' => $info['delegator_count'] ?? 0, + 'total_staked_amount' => $info['total_stake'], + 'delegation_rate' => $info['delegation_rate'], + 'daily_earning' => $info['daily_earnings'] ?? 0, + 'self_staked_amount' => $info['self_stake'] ?? 0, + 'total_earning' => isset($totalRewards['data']) && $totalRewards['data'] > 0 ? $totalRewards['data'] / 1000000000 : 0, + 'is_open_port' => $is_open_port, + 'mbs' => $mbs, + 'update_responsiveness' => isset($info['update_responsiveness']) ? $info['update_responsiveness'] * 100 : 0, + 'uptime' => isset($info['uptime']) ? $info['uptime'] * 100 : 0, + 'block_height' => $info['block_height'] ?? 0, + 'peers' => $info['peer_count'] ?? 0, + ] + ); + + Node::updateOrCreate( + [ + 'node_address' => $validatorid + ], + [ + 'block_height' => $info['block_height'] ?? null, + 'protocol_version' => $build_version, + 'update_responsiveness' => isset($info['update_responsiveness']) ? $info['update_responsiveness'] * 100 : null, + 'uptime' => isset($info['uptime']) ? $info['uptime'] : null, + 'weight' => $info['daily_earnings'] ?? 0, + 'peers' => $info['peer_count'] ?? 0, + ] + ); + } + } + } + } + + public function getValidatorRewards($validatorId, $range) + { + $response = Http::withHeaders([ + 'Authorization' => "token $this->SEENA_API_KEY", + ])->withOptions([ + 'verify' => false, + ])->get("https://seena.ledgerleap.com/validator-rewards?validator_id=$validatorId&range=$range"); + $data = $response->json(); + if (isset($data['success']) && $data['success'] == false) { + return []; + } + return $data; + } +} diff --git a/app/Services/ShuftiproCheck.php b/app/Services/ShuftiproCheck.php index a1e58be5..ca03d253 100644 --- a/app/Services/ShuftiproCheck.php +++ b/app/Services/ShuftiproCheck.php @@ -2,35 +2,199 @@ namespace App\Services; +use App\Models\Profile; use App\Models\Shuftipro; use App\Models\ShuftiproTemp; use App\Models\User; + use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\Mail; + +use App\Mail\KYCApproved; +use App\Mail\KYCDenied; + +use Exception; class ShuftiproCheck { + public function handleExisting($item) { + $url = 'https://api.shuftipro.com/status'; + $client_id = config('services.shufti.client_id'); + $secret_key = config('services.shufti.client_secret'); - public function handle($item) - { - $keys = [ - 'production' => [ - 'clientId' => 'e4tot3Y50imDSYYsVcWQbpQqG4jmZ7i7XoblVDp3CavbFn9Tvr1613403633', - 'clientSecret' => '$2y$10$f5Q.YTY6bl2wvmbS.aT8pONrDSxieRzmzQQdH.2VJkFdj7cRaR05i' - ], - 'test' => [ - 'clientId' => 'KgeOivDVEpzTrAqkx8aBwLJenCgKnW4SSQDbv17hRq8fyhvZhD1612459148', - 'clientSecret' => '$2y$10$wHWfyqB/1dhfTKwQQnstv.k0y9z2gYHBhkkRMkBPtPPOpYODHi6l6' - ] + $auth = $client_id . ":" . $secret_key; + + $response = Http::withBasicAuth($client_id, $secret_key)->post($url, [ + 'reference' => $item->reference_id + ]); + + $data = $response->json(); + if (!$data || !is_array($data)) return; + + if (!isset($data['reference']) || !isset($data['event'])) { + return "error"; + } + + $events = [ + 'verification.accepted', + 'verification.declined', + 'verification.status.changed', ]; - // $mode = 'production'; - $mode = 'test'; + $user_id = (int) $item->user_id; + $reference_id = $data['reference']; + $event = $data['event']; + // Event Validation + if (!in_array($event, $events)) + return "error"; - $url = 'https://api.shuftipro.com/status'; - $client_id = $keys[$mode]['clientId']; - $secret_key = $keys[$mode]['clientSecret']; + $declined_reason = isset($data['declined_reason']) ? $data['declined_reason'] : null; + $proofs = isset($data['proofs']) ? $data['proofs'] : null; + $verification_result = isset($data['verification_result']) ? $data['verification_result'] : null; + $verification_data = isset($data['verification_data']) ? $data['verification_data'] : null; + + $is_successful = $event == 'verification.accepted' ? 1 : 0; + $status = $is_successful ? 'approved' : 'denied'; + + //Aml check + $aml_declined_reason = null; + $hit = null; + + if (isset($verification_data['background_checks']) && $verification_data['background_checks']['aml_data'] && $verification_data['background_checks']['aml_data']['hits']) { + $hits = $verification_data['background_checks']['aml_data']['hits']; + if (count($hits) > 0 && isset($hits[0]['fields']['Enforcement Type'])) { + $type = $hits[0]['fields']['Enforcement Type']; + if (count($type) > 0 && isset($type[0]['value'])) { + $aml_declined_reason = $type[0]['value']; + } + } + if (count($hits) > 0 ) { + $hit= $hits[0]; + } + } + + $data = json_encode([ + 'declined_reason' => $declined_reason, + 'event' => $event, + 'verification_result' => $verification_result, + 'aml_declined_reason' => $aml_declined_reason, + 'hit' => $hit, + ]); + + $document_proof = $address_proof = null; + $document_result = $address_result = $background_checks_result = 0; + + // Document Proof + if ($proofs && isset($proofs['document']) && isset($proofs['document']['proof'])) { + $document_proof = $proofs['document']['proof']; + } + + // Address Proof + if ($proofs && isset($proofs['address']) && isset($proofs['address']['proof'])) { + $address_proof = $proofs['address']['proof']; + } + + // Document Result + if ($verification_result && isset($verification_result['document'])) { + $zeroCount = $oneCount = 0; + foreach ($verification_result['document'] as $key => $value) { + if ($key == 'document_proof') continue; + + $value = (int) $value; + + if ($value) + $oneCount++; + else + $zeroCount++; + } + + if ($oneCount && !$zeroCount) + $document_result = 1; + } + + // Address Result + if ($verification_result && isset($verification_result['address'])) { + $zeroCount = $oneCount = 0; + foreach ($verification_result['address'] as $key => $value) { + if ($key == 'address_document_proof') continue; + + $value = (int) $value; + + if ($value) + $oneCount++; + else + $zeroCount++; + } + + if ($oneCount && !$zeroCount) + $address_result = 1; + } + + // Background Checks Result + if ( + $verification_result && + isset($verification_result['background_checks']) && + (int) $verification_result['background_checks'] === 1 + ) { + $background_checks_result = 1; + } + + $record = $item; + $record->user_id = $user_id; + $record->reference_id = $reference_id; + $record->is_successful = $is_successful; + $record->data = $data; + $record->document_result = $document_result; + $record->address_result = $address_result; + $record->background_checks_result = $background_checks_result; + $record->status = $status; + $record->reviewed = $is_successful ? 1 : 0; // No need to review successful ones + + if ($status == 'approved') { + $record->manual_approved_at = now(); + } + if ($document_proof) { + $record->document_proof = $document_proof; + } + if ($address_proof) { + $record->address_proof = $address_proof; + } + + $record->save(); + if ($status == "approved") { + $profile = Profile::where('user_id', $user_id)->first(); + if ($profile) { + $profile->status = 'approved'; + $profile->save(); + } + + $user = User::find($user_id); + if ($user) { + $user->kyc_verified_at = now(); + $user->approve_at = now(); + $user->save(); + + Mail::to($user->email)->send(new KYCApproved); + } + return 'success'; + } else { + $user = User::find($user_id); + if ($user) { + Mail::to($user->email)->send(new KYCDenied); + } + return 'fail'; + } + } + + public function handle($item) + { + $url = 'https://api.shuftipro.com/status'; + $client_id = config('services.shufti.client_id'); + $secret_key = config('services.shufti.client_secret'); + $auth = $client_id . ":" . $secret_key; $response = Http::withBasicAuth($client_id, $secret_key)->post($url, [ @@ -40,10 +204,7 @@ public function handle($item) $data = $response->json(); if (!$data || !is_array($data)) return; - if ( - !isset($data['reference']) || - !isset($data['event']) - ) { + if (!isset($data['reference']) || !isset($data['event'])) { return "error"; } @@ -76,43 +237,50 @@ public function handle($item) $is_successful = $event == 'verification.accepted' ? 1 : 0; $status = $is_successful ? 'approved' : 'denied'; + //Aml check + $aml_declined_reason = null; + $hit = null; + + if ( + isset($verification_data['background_checks']) && + $verification_data['background_checks']['aml_data'] && + $verification_data['background_checks']['aml_data']['hits'] + ) { + $hits = $verification_data['background_checks']['aml_data']['hits']; + if (count($hits) > 0 && isset($hits[0]['fields']['Enforcement Type'])) { + $type = $hits[0]['fields']['Enforcement Type']; + if (count($type) > 0 && isset($type[0]['value'])) { + $aml_declined_reason = $type[0]['value']; + } + } + if (count($hits) > 0 ) { + $hit= $hits[0]; + } + } $data = json_encode([ 'declined_reason' => $declined_reason, 'event' => $event, - 'proofs' => $proofs, 'verification_result' => $verification_result, - 'verification_data' => $verification_data + 'aml_declined_reason' => $aml_declined_reason, + 'hit' => $hit, ]); $document_proof = $address_proof = null; - $document_result = - $address_result = - $background_checks_result = 0; + $document_result = $address_result = $background_checks_result = 0; // Document Proof - if ( - $proofs && - isset($proofs['document']) && - isset($proofs['document']['proof']) - ) { + if ($proofs && isset($proofs['document']) && isset($proofs['document']['proof'])) { $document_proof = $proofs['document']['proof']; } // Address Proof - if ( - $proofs && - isset($proofs['address']) && - isset($proofs['address']['proof']) - ) { + if ($proofs && isset($proofs['address']) && isset($proofs['address']['proof'])) { $address_proof = $proofs['address']['proof']; } // Document Result - if ( - $verification_result && - isset($verification_result['document']) - ) { + if ($verification_result && isset($verification_result['document'])) { $zeroCount = $oneCount = 0; foreach ($verification_result['document'] as $key => $value) { if ($key == 'document_proof') continue; @@ -130,10 +298,7 @@ public function handle($item) } // Address Result - if ( - $verification_result && - isset($verification_result['address']) - ) { + if ($verification_result && isset($verification_result['address'])) { $zeroCount = $oneCount = 0; foreach ($verification_result['address'] as $key => $value) { if ($key == 'address_document_proof') continue; @@ -151,17 +316,12 @@ public function handle($item) } // Background Checks Result - if ( - $verification_result && - isset($verification_result['background_checks']) && - (int) $verification_result['background_checks'] === 1 - ) { + if ($verification_result && isset($verification_result['background_checks']) && (int) $verification_result['background_checks'] === 1) { $background_checks_result = 1; } Shuftipro::where('user_id', $user_id)->delete(); - $record = new Shuftipro(); $record->user_id = $user_id; $record->reference_id = $reference_id; @@ -173,22 +333,40 @@ public function handle($item) $record->status = $status; $record->reviewed = $is_successful ? 1 : 0; // No need to review successful ones - if ($document_proof) + if ($document_proof) { $record->document_proof = $document_proof; - if ($address_proof) + } + if ($address_proof) { $record->address_proof = $address_proof; - + } $record->save(); // Update Temp Record $temp->status = 'processed'; $temp->save(); - $user = User::find($user_id); - if ($status == "approved") { - $user->kyc_verified_at = now(); - $user->save(); + $profile = Profile::where('user_id', $user_id)->first(); + if ($profile) { + $profile->status = 'approved'; + $profile->save(); + } + + $user = User::find($user_id); + if ($user) { + $user->kyc_verified_at = now(); + $user->approve_at = now(); + $user->save(); + + Mail::to($user->email)->send(new KYCApproved); + } + return 'success'; + } else { + $user = User::find($user_id); + if ($user) { + Mail::to($user->email)->send(new KYCDenied); + } + return 'fail'; } } } diff --git a/composer.json b/composer.json index 5e2060ea..68831e6b 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "license": "MIT", "require": { "php": "^7.3|^8.0", + "aws/aws-sdk-php": "^3.176", "doctrine/dbal": "^3.1", "fideloper/proxy": "^4.4", "fruitcake/laravel-cors": "^2.0", @@ -14,7 +15,8 @@ "laravel/framework": "^8.40", "laravel/passport": "^10.1", "laravel/tinker": "^2.5", - "phpseclib/phpseclib": "~3.0" + "phpseclib/phpseclib": "~3.0", + "stripe/stripe-php": "^7.121" }, "require-dev": { "facade/ignition": "^2.5", diff --git a/composer.lock b/composer.lock index 68c8b017..d3846e4e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,35 +4,35 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5df2c62b1fe13563186eed0f05bf8380", + "content-hash": "16acde0192038c2d0d58b08808d29dfc", "packages": [ { "name": "asm89/stack-cors", - "version": "v2.0.3", + "version": "v2.1.1", "source": { "type": "git", "url": "https://github.com/asm89/stack-cors.git", - "reference": "9cb795bf30988e8c96dd3c40623c48a877bc6714" + "reference": "73e5b88775c64ccc0b84fb60836b30dc9d92ac4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/asm89/stack-cors/zipball/9cb795bf30988e8c96dd3c40623c48a877bc6714", - "reference": "9cb795bf30988e8c96dd3c40623c48a877bc6714", + "url": "https://api.github.com/repos/asm89/stack-cors/zipball/73e5b88775c64ccc0b84fb60836b30dc9d92ac4a", + "reference": "73e5b88775c64ccc0b84fb60836b30dc9d92ac4a", "shasum": "" }, "require": { - "php": "^7.0|^8.0", - "symfony/http-foundation": "~2.7|~3.0|~4.0|~5.0", - "symfony/http-kernel": "~2.7|~3.0|~4.0|~5.0" + "php": "^7.2|^8.0", + "symfony/http-foundation": "^4|^5|^6", + "symfony/http-kernel": "^4|^5|^6" }, "require-dev": { - "phpunit/phpunit": "^6|^7|^8|^9", + "phpunit/phpunit": "^7|^9", "squizlabs/php_codesniffer": "^3.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -58,138 +58,210 @@ ], "support": { "issues": "https://github.com/asm89/stack-cors/issues", - "source": "https://github.com/asm89/stack-cors/tree/v2.0.3" + "source": "https://github.com/asm89/stack-cors/tree/v2.1.1" }, - "time": "2021-03-11T06:42:03+00:00" + "time": "2022-01-18T09:12:03+00:00" }, { - "name": "brick/math", - "version": "0.9.2", + "name": "aws/aws-crt-php", + "version": "v1.0.2", "source": { "type": "git", - "url": "https://github.com/brick/math.git", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "3942776a8c99209908ee0b287746263725685732" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/3942776a8c99209908ee0b287746263725685732", + "reference": "3942776a8c99209908ee0b287746263725685732", "shasum": "" }, "require": { - "ext-json": "*", - "php": "^7.1 || ^8.0" + "php": ">=5.5" }, "require-dev": { - "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.3.2" + "phpunit/phpunit": "^4.8.35|^5.4.3" }, "type": "library", "autoload": { - "psr-4": { - "Brick\\Math\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache-2.0" ], - "description": "Arbitrary-precision arithmetic library", + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "description": "AWS Common Runtime for PHP", + "homepage": "http://aws.amazon.com/sdkforphp", "keywords": [ - "Arbitrary-precision", - "BigInteger", - "BigRational", - "arithmetic", - "bigdecimal", - "bignum", - "brick", - "math" + "amazon", + "aws", + "crt", + "sdk" ], "support": { - "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.2" + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.0.2" }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/brick/math", - "type": "tidelift" - } - ], - "time": "2021-01-20T22:51:39+00:00" + "time": "2021-09-03T22:57:30+00:00" }, { - "name": "composer/package-versions-deprecated", - "version": "1.11.99.2", + "name": "aws/aws-sdk-php", + "version": "3.212.3", "source": { "type": "git", - "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c" + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "1d3db6d276299136bcaa7896653be0dcd2aaa92a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c6522afe5540d5fc46675043d3ed5a45a740b27c", - "reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1d3db6d276299136bcaa7896653be0dcd2aaa92a", + "reference": "1d3db6d276299136bcaa7896653be0dcd2aaa92a", "shasum": "" }, "require": { - "composer-plugin-api": "^1.1.0 || ^2.0", - "php": "^7 || ^8" - }, - "replace": { - "ocramius/package-versions": "1.11.99" + "aws/aws-crt-php": "^1.0.2", + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", + "guzzlehttp/promises": "^1.4.0", + "guzzlehttp/psr7": "^1.7.0|^2.0", + "mtdowling/jmespath.php": "^2.6", + "php": ">=5.5" }, "require-dev": { - "composer/composer": "^1.9.3 || ^2.0@dev", - "ext-zip": "^1.13", - "phpunit/phpunit": "^6.5 || ^7" + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "nette/neon": "^2.3", + "paragonie/random_compat": ">= 2", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" }, - "type": "composer-plugin", + "type": "library", "extra": { - "class": "PackageVersions\\Installer", "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { + "files": [ + "src/functions.php" + ], "psr-4": { - "PackageVersions\\": "src/PackageVersions" + "Aws\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache-2.0" ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.212.3" + }, + "time": "2022-03-07T19:48:01+00:00" + }, + { + "name": "brick/math", + "version": "0.9.3", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "vimeo/psalm": "4.9.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Arbitrary-precision arithmetic library", + "keywords": [ + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "brick", + "math" ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "support": { - "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.2" + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.9.3" }, "funding": [ { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", + "url": "https://github.com/BenMorel", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "url": "https://tidelift.com/funding/github/packagist/brick/math", "type": "tidelift" } ], - "time": "2021-05-24T07:46:03+00:00" + "time": "2021-08-15T20:50:18+00:00" }, { "name": "defuse/php-encryption", @@ -257,26 +329,100 @@ }, "time": "2021-04-09T23:57:26+00:00" }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "0992cc19268b259a39e86f296da5f0677841f42c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/0992cc19268b259a39e86f296da5f0677841f42c", + "reference": "0992cc19268b259a39e86f296da5f0677841f42c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^3.14" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.1" + }, + "time": "2021-08-13T13:06:58+00:00" + }, { "name": "doctrine/cache", - "version": "1.11.3", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "3bb5588cec00a0268829cc4a518490df6741af9d" + "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/3bb5588cec00a0268829cc4a518490df6741af9d", - "reference": "3bb5588cec00a0268829cc4a518490df6741af9d", + "url": "https://api.github.com/repos/doctrine/cache/zipball/331b4d5dbaeab3827976273e9356b3b453c300ce", + "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce", "shasum": "" }, "require": { "php": "~7.1 || ^8.0" }, "conflict": { - "doctrine/common": ">2.2,<2.4", - "psr/cache": ">=3" + "doctrine/common": ">2.2,<2.4" }, "require-dev": { "alcaeus/mongo-php-adapter": "^1.1", @@ -285,8 +431,9 @@ "mongodb/mongodb": "^1.1", "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", "predis/predis": "~1.0", - "psr/cache": "^1.0 || ^2.0", - "symfony/cache": "^4.4 || ^5.2" + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "^4.4 || ^5.2 || ^6.0@dev", + "symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev" }, "suggest": { "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" @@ -338,7 +485,7 @@ ], "support": { "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/1.11.3" + "source": "https://github.com/doctrine/cache/tree/2.1.1" }, "funding": [ { @@ -354,39 +501,42 @@ "type": "tidelift" } ], - "time": "2021-05-25T09:01:55+00:00" + "time": "2021-07-17T14:49:29+00:00" }, { "name": "doctrine/dbal", - "version": "3.1.0", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "5ba62e7e40df119424866064faf2cef66cb5232a" + "reference": "35eae239ef515d55ebb24e9d4715cad09a4f58ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/5ba62e7e40df119424866064faf2cef66cb5232a", - "reference": "5ba62e7e40df119424866064faf2cef66cb5232a", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/35eae239ef515d55ebb24e9d4715cad09a4f58ed", + "reference": "35eae239ef515d55ebb24e9d4715cad09a4f58ed", "shasum": "" }, "require": { - "composer/package-versions-deprecated": "^1.11.99", - "doctrine/cache": "^1.0", + "composer-runtime-api": "^2", + "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", - "php": "^7.3 || ^8.0" + "php": "^7.3 || ^8.0", + "psr/cache": "^1|^2|^3", + "psr/log": "^1|^2|^3" }, "require-dev": { - "doctrine/coding-standard": "8.2.0", - "jetbrains/phpstorm-stubs": "2020.2", - "phpstan/phpstan": "0.12.81", - "phpstan/phpstan-strict-rules": "^0.12.2", - "phpunit/phpunit": "9.5.0", - "psalm/plugin-phpunit": "0.13.0", - "squizlabs/php_codesniffer": "3.6.0", - "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", - "vimeo/psalm": "4.6.4" + "doctrine/coding-standard": "9.0.0", + "jetbrains/phpstorm-stubs": "2021.1", + "phpstan/phpstan": "1.4.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "9.5.11", + "psalm/plugin-phpunit": "0.16.1", + "squizlabs/php_codesniffer": "3.6.2", + "symfony/cache": "^5.2|^6.0", + "symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0", + "vimeo/psalm": "4.16.1" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -446,7 +596,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.1.0" + "source": "https://github.com/doctrine/dbal/tree/3.3.2" }, "funding": [ { @@ -462,7 +612,7 @@ "type": "tidelift" } ], - "time": "2021-04-19T17:51:23+00:00" + "time": "2022-02-05T16:33:45+00:00" }, { "name": "doctrine/deprecations", @@ -603,34 +753,30 @@ }, { "name": "doctrine/inflector", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210" + "reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/9cf661f4eb38f7c881cac67c75ea9b00bf97b210", - "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89", + "reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^7.0", - "phpstan/phpstan": "^0.11", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-strict-rules": "^0.11", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "doctrine/coding-standard": "^8.2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "vimeo/psalm": "^4.10" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" @@ -678,7 +824,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.x" + "source": "https://github.com/doctrine/inflector/tree/2.0.4" }, "funding": [ { @@ -694,36 +840,32 @@ "type": "tidelift" } ], - "time": "2020-05-29T15:13:26+00:00" + "time": "2021-10-22T20:16:43+00:00" }, { "name": "doctrine/lexer", - "version": "1.2.1", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^8.2" + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.11" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" @@ -758,7 +900,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.1" + "source": "https://github.com/doctrine/lexer/tree/1.2.3" }, "funding": [ { @@ -774,33 +916,33 @@ "type": "tidelift" } ], - "time": "2020-05-25T17:44:05+00:00" + "time": "2022-02-28T11:07:21+00:00" }, { "name": "dragonmantank/cron-expression", - "version": "v3.1.0", + "version": "v3.3.1", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c" + "reference": "be85b3f05b46c39bbc0d95f6c071ddff669510fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c", - "reference": "7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/be85b3f05b46c39bbc0d95f6c071ddff669510fa", + "reference": "be85b3f05b46c39bbc0d95f6c071ddff669510fa", "shasum": "" }, "require": { "php": "^7.2|^8.0", - "webmozart/assert": "^1.7.0" + "webmozart/assert": "^1.0" }, "replace": { "mtdowling/cron-expression": "^1.0" }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-webmozart-assert": "^0.12.7", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-webmozart-assert": "^1.0", "phpunit/phpunit": "^7.0|^8.0|^9.0" }, "type": "library", @@ -827,7 +969,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.1.0" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.1" }, "funding": [ { @@ -835,7 +977,7 @@ "type": "github" } ], - "time": "2020-11-24T19:55:57+00:00" + "time": "2022-01-18T15:43:28+00:00" }, { "name": "egulias/email-validator", @@ -965,16 +1107,16 @@ }, { "name": "firebase/php-jwt", - "version": "v5.3.0", + "version": "v5.5.1", "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", - "reference": "3c2d70f2e64e2922345e89f2ceae47d2463faae1" + "reference": "83b609028194aa042ea33b5af2d41a7427de80e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/3c2d70f2e64e2922345e89f2ceae47d2463faae1", - "reference": "3c2d70f2e64e2922345e89f2ceae47d2463faae1", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b609028194aa042ea33b5af2d41a7427de80e6", + "reference": "83b609028194aa042ea33b5af2d41a7427de80e6", "shasum": "" }, "require": { @@ -983,6 +1125,9 @@ "require-dev": { "phpunit/phpunit": ">=4.8 <=9" }, + "suggest": { + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, "type": "library", "autoload": { "psr-4": { @@ -1013,34 +1158,32 @@ ], "support": { "issues": "https://github.com/firebase/php-jwt/issues", - "source": "https://github.com/firebase/php-jwt/tree/v5.3.0" + "source": "https://github.com/firebase/php-jwt/tree/v5.5.1" }, - "time": "2021-05-20T17:37:02+00:00" + "time": "2021-11-08T20:18:51+00:00" }, { "name": "fruitcake/laravel-cors", - "version": "v2.0.4", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/fruitcake/laravel-cors.git", - "reference": "a8ccedc7ca95189ead0e407c43b530dc17791d6a" + "reference": "783a74f5e3431d7b9805be8afb60fd0a8f743534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/a8ccedc7ca95189ead0e407c43b530dc17791d6a", - "reference": "a8ccedc7ca95189ead0e407c43b530dc17791d6a", + "url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/783a74f5e3431d7b9805be8afb60fd0a8f743534", + "reference": "783a74f5e3431d7b9805be8afb60fd0a8f743534", "shasum": "" }, "require": { "asm89/stack-cors": "^2.0.1", "illuminate/contracts": "^6|^7|^8|^9", "illuminate/support": "^6|^7|^8|^9", - "php": ">=7.2", - "symfony/http-foundation": "^4|^5", - "symfony/http-kernel": "^4.3.4|^5" + "php": ">=7.2" }, "require-dev": { - "laravel/framework": "^6|^7|^8", + "laravel/framework": "^6|^7.24|^8", "orchestra/testbench-dusk": "^4|^5|^6|^7", "phpunit/phpunit": "^6|^7|^8|^9", "squizlabs/php_codesniffer": "^3.5" @@ -1048,7 +1191,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.1-dev" }, "laravel": { "providers": [ @@ -1084,43 +1227,42 @@ ], "support": { "issues": "https://github.com/fruitcake/laravel-cors/issues", - "source": "https://github.com/fruitcake/laravel-cors/tree/v2.0.4" + "source": "https://github.com/fruitcake/laravel-cors/tree/v2.2.0" }, "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, { "url": "https://github.com/barryvdh", "type": "github" } ], - "time": "2021-04-26T11:24:25+00:00" + "time": "2022-02-23T14:25:13+00:00" }, { "name": "graham-campbell/result-type", - "version": "v1.0.1", + "version": "v1.0.4", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb" + "reference": "0690bde05318336c7221785f2a932467f98b64ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/7e279d2cd5d7fbb156ce46daada972355cea27bb", - "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/0690bde05318336c7221785f2a932467f98b64ca", + "reference": "0690bde05318336c7221785f2a932467f98b64ca", "shasum": "" }, "require": { - "php": "^7.0|^8.0", - "phpoption/phpoption": "^1.7.3" + "php": "^7.0 || ^8.0", + "phpoption/phpoption": "^1.8" }, "require-dev": { - "phpunit/phpunit": "^6.5|^7.5|^8.5|^9.0" + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "psr-4": { "GrahamCampbell\\ResultType\\": "src/" @@ -1133,7 +1275,8 @@ "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" } ], "description": "An Implementation Of The Result Type", @@ -1146,7 +1289,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.1" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.4" }, "funding": [ { @@ -1158,28 +1301,29 @@ "type": "tidelift" } ], - "time": "2020-04-13T13:17:36+00:00" + "time": "2021-11-21T21:41:47+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "7.3.0", + "version": "7.4.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7008573787b430c1c1f650e3722d9bba59967628" + "reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7008573787b430c1c1f650e3722d9bba59967628", - "reference": "7008573787b430c1c1f650e3722d9bba59967628", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee0a041b1760e6a53d2a39c8c34115adc2af2c79", + "reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.4", - "guzzlehttp/psr7": "^1.7 || ^2.0", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.8.3 || ^2.1", "php": "^7.2.5 || ^8.0", - "psr/http-client": "^1.0" + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" }, "provide": { "psr/http-client-implementation": "1.0" @@ -1189,7 +1333,7 @@ "ext-curl": "*", "php-http/client-integration-tests": "^3.0", "phpunit/phpunit": "^8.5.5 || ^9.3.5", - "psr/log": "^1.1" + "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { "ext-curl": "Required for CURL handler support", @@ -1199,35 +1343,59 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.3-dev" + "dev-master": "7.4-dev" } }, "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", "keywords": [ "client", "curl", @@ -1241,7 +1409,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.3.0" + "source": "https://github.com/guzzle/guzzle/tree/7.4.1" }, "funding": [ { @@ -1253,28 +1421,24 @@ "type": "github" }, { - "url": "https://github.com/alexeyshockov", - "type": "github" - }, - { - "url": "https://github.com/gmponos", - "type": "github" + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" } ], - "time": "2021-03-23T11:33:13+00:00" + "time": "2021-12-06T18:43:05+00:00" }, { "name": "guzzlehttp/promises", - "version": "1.4.1", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da", "shasum": "" }, "require": { @@ -1286,26 +1450,41 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.5-dev" } }, "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle promises library", @@ -1314,35 +1493,52 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.4.1" - }, - "time": "2021-03-07T09:25:29+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "1.8.2", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91" + "source": "https://github.com/guzzle/promises/tree/1.5.1" }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91", + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2021-10-22T20:56:57+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/089edd38f5b8abba6cb01567c2a8aaa47cec4c72", + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72", "shasum": "" }, "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" }, "provide": { + "psr/http-factory-implementation": "1.0", "psr/http-message-implementation": "1.0" }, "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + "bamarni/composer-bin-plugin": "^1.4.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.8 || ^9.3.10" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -1350,30 +1546,53 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "2.1-dev" } }, "autoload": { "psr-4": { "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, { "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" } ], "description": "PSR-7 message implementation that also provides common utility methods", @@ -1389,9 +1608,23 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.8.2" + "source": "https://github.com/guzzle/psr7/tree/2.1.0" }, - "time": "2021-04-26T09:17:50+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2021-10-06T17:43:30+00:00" }, { "name": "hellosign/hellosign-php-sdk", @@ -1438,16 +1671,16 @@ }, { "name": "laravel/framework", - "version": "v8.47.0", + "version": "v8.83.3", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "93db226946453f4285558b7c3166ddb6e7ea5400" + "reference": "b4ed222a188cca74ca9062296e525d26ae54a0ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/93db226946453f4285558b7c3166ddb6e7ea5400", - "reference": "93db226946453f4285558b7c3166ddb6e7ea5400", + "url": "https://api.github.com/repos/laravel/framework/zipball/b4ed222a188cca74ca9062296e525d26ae54a0ce", + "reference": "b4ed222a188cca74ca9062296e525d26ae54a0ce", "shasum": "" }, "require": { @@ -1457,34 +1690,37 @@ "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", - "league/commonmark": "^1.3", + "laravel/serializable-closure": "^1.0", + "league/commonmark": "^1.3|^2.0.2", "league/flysystem": "^1.1", "monolog/monolog": "^2.0", - "nesbot/carbon": "^2.31", + "nesbot/carbon": "^2.53.1", "opis/closure": "^3.6", "php": "^7.3|^8.0", "psr/container": "^1.0", + "psr/log": "^1.0|^2.0", "psr/simple-cache": "^1.0", - "ramsey/uuid": "^4.0", - "swiftmailer/swiftmailer": "^6.0", - "symfony/console": "^5.1.4", - "symfony/error-handler": "^5.1.4", - "symfony/finder": "^5.1.4", - "symfony/http-foundation": "^5.1.4", - "symfony/http-kernel": "^5.1.4", - "symfony/mime": "^5.1.4", - "symfony/process": "^5.1.4", - "symfony/routing": "^5.1.4", - "symfony/var-dumper": "^5.1.4", + "ramsey/uuid": "^4.2.2", + "swiftmailer/swiftmailer": "^6.3", + "symfony/console": "^5.4", + "symfony/error-handler": "^5.4", + "symfony/finder": "^5.4", + "symfony/http-foundation": "^5.4", + "symfony/http-kernel": "^5.4", + "symfony/mime": "^5.4", + "symfony/process": "^5.4", + "symfony/routing": "^5.4", + "symfony/var-dumper": "^5.4", "tijsverkoyen/css-to-inline-styles": "^2.2.2", - "vlucas/phpdotenv": "^5.2", - "voku/portable-ascii": "^1.4.8" + "vlucas/phpdotenv": "^5.4.1", + "voku/portable-ascii": "^1.6.1" }, "conflict": { "tightenco/collect": "<5.5.33" }, "provide": { - "psr/container-implementation": "1.0" + "psr/container-implementation": "1.0", + "psr/simple-cache-implementation": "1.0" }, "replace": { "illuminate/auth": "self.version", @@ -1520,22 +1756,24 @@ "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "^3.155", - "doctrine/dbal": "^2.6|^3.0", - "filp/whoops": "^2.8", + "aws/aws-sdk-php": "^3.198.1", + "doctrine/dbal": "^2.13.3|^3.1.4", + "filp/whoops": "^2.14.3", "guzzlehttp/guzzle": "^6.5.5|^7.0.1", "league/flysystem-cached-adapter": "^1.0", - "mockery/mockery": "^1.4.2", - "orchestra/testbench-core": "^6.8", + "mockery/mockery": "^1.4.4", + "orchestra/testbench-core": "^6.27", "pda/pheanstalk": "^4.0", - "phpunit/phpunit": "^8.5.8|^9.3.3", - "predis/predis": "^1.1.2", - "symfony/cache": "^5.1.4" + "phpunit/phpunit": "^8.5.19|^9.5.8", + "predis/predis": "^1.1.9", + "symfony/cache": "^5.4" }, "suggest": { - "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.155).", + "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.198.1).", "brianium/paratest": "Required to run tests in parallel (^6.0).", - "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.13.3|^3.1.4).", + "ext-bcmath": "Required to use the multiple_of validation rule.", "ext-ftp": "Required to use the Flysystem FTP driver.", "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", "ext-memcached": "Required to use the memcache cache driver.", @@ -1543,21 +1781,21 @@ "ext-posix": "Required to use all features of the queue worker.", "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", - "filp/whoops": "Required for friendly error pages in development (^2.8).", + "filp/whoops": "Required for friendly error pages in development (^2.14.3).", "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.5.5|^7.0.1).", "laravel/tinker": "Required to use the tinker console command (^2.0).", "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", - "mockery/mockery": "Required to use mocking (^1.4.2).", + "mockery/mockery": "Required to use mocking (^1.4.4).", "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", - "phpunit/phpunit": "Required to use assertions and run tests (^8.5.8|^9.3.3).", - "predis/predis": "Required to use the predis connector (^1.1.2).", + "phpunit/phpunit": "Required to use assertions and run tests (^8.5.19|^9.5.8).", + "predis/predis": "Required to use the predis connector (^1.1.9).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0|^6.0).", - "symfony/cache": "Required to PSR-6 cache bridge (^5.1.4).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^5.1.4).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0|^6.0|^7.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^5.4).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^5.4).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, @@ -1602,34 +1840,34 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-06-15T14:00:32+00:00" + "time": "2022-03-03T15:14:29+00:00" }, { "name": "laravel/passport", - "version": "v10.1.3", + "version": "v10.3.2", "source": { "type": "git", "url": "https://github.com/laravel/passport.git", - "reference": "a5e4471dd99b7638ab5ca3ecab6cd87cf37eb410" + "reference": "c56207e9a37c849da0164842a609a9f38747e95b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/passport/zipball/a5e4471dd99b7638ab5ca3ecab6cd87cf37eb410", - "reference": "a5e4471dd99b7638ab5ca3ecab6cd87cf37eb410", + "url": "https://api.github.com/repos/laravel/passport/zipball/c56207e9a37c849da0164842a609a9f38747e95b", + "reference": "c56207e9a37c849da0164842a609a9f38747e95b", "shasum": "" }, "require": { "ext-json": "*", "firebase/php-jwt": "^5.0", - "illuminate/auth": "^8.2", - "illuminate/console": "^8.2", - "illuminate/container": "^8.2", - "illuminate/contracts": "^8.2", - "illuminate/cookie": "^8.2", - "illuminate/database": "^8.2", - "illuminate/encryption": "^8.2", - "illuminate/http": "^8.2", - "illuminate/support": "^8.2", + "illuminate/auth": "^8.2|^9.0", + "illuminate/console": "^8.2|^9.0", + "illuminate/container": "^8.2|^9.0", + "illuminate/contracts": "^8.2|^9.0", + "illuminate/cookie": "^8.2|^9.0", + "illuminate/database": "^8.2|^9.0", + "illuminate/encryption": "^8.2|^9.0", + "illuminate/http": "^8.2|^9.0", + "illuminate/support": "^8.2|^9.0", "lcobucci/jwt": "^3.4|^4.0", "league/oauth2-server": "^8.2", "nyholm/psr7": "^1.3", @@ -1639,7 +1877,7 @@ }, "require-dev": { "mockery/mockery": "^1.0", - "orchestra/testbench": "^6.0", + "orchestra/testbench": "^6.0|^7.0", "phpunit/phpunit": "^9.3" }, "type": "library", @@ -1679,36 +1917,95 @@ "issues": "https://github.com/laravel/passport/issues", "source": "https://github.com/laravel/passport" }, - "time": "2021-04-06T14:30:45+00:00" + "time": "2022-02-15T21:44:15+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "9e4b005daa20b0c161f3845040046dc9ddc1d74e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/9e4b005daa20b0c161f3845040046dc9ddc1d74e", + "reference": "9e4b005daa20b0c161f3845040046dc9ddc1d74e", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "pestphp/pest": "^1.18", + "phpstan/phpstan": "^0.12.98", + "symfony/var-dumper": "^5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2022-02-11T19:23:53+00:00" }, { "name": "laravel/tinker", - "version": "v2.6.1", + "version": "v2.7.0", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "04ad32c1a3328081097a181875733fa51f402083" + "reference": "5f2f9815b7631b9f586a3de7933c25f9327d4073" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/04ad32c1a3328081097a181875733fa51f402083", - "reference": "04ad32c1a3328081097a181875733fa51f402083", + "url": "https://api.github.com/repos/laravel/tinker/zipball/5f2f9815b7631b9f586a3de7933c25f9327d4073", + "reference": "5f2f9815b7631b9f586a3de7933c25f9327d4073", "shasum": "" }, "require": { - "illuminate/console": "^6.0|^7.0|^8.0", - "illuminate/contracts": "^6.0|^7.0|^8.0", - "illuminate/support": "^6.0|^7.0|^8.0", + "illuminate/console": "^6.0|^7.0|^8.0|^9.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0", "php": "^7.2.5|^8.0", - "psy/psysh": "^0.10.4", - "symfony/var-dumper": "^4.3.4|^5.0" + "psy/psysh": "^0.10.4|^0.11.1", + "symfony/var-dumper": "^4.3.4|^5.0|^6.0" }, "require-dev": { "mockery/mockery": "~1.3.3|^1.4.2", "phpunit/phpunit": "^8.5.8|^9.3.3" }, "suggest": { - "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0)." + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0)." }, "type": "library", "extra": { @@ -1745,9 +2042,9 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.6.1" + "source": "https://github.com/laravel/tinker/tree/v2.7.0" }, - "time": "2021-03-02T16:53:12+00:00" + "time": "2022-01-10T08:52:49+00:00" }, { "name": "lcobucci/clock", @@ -1812,16 +2109,16 @@ }, { "name": "lcobucci/jwt", - "version": "4.1.4", + "version": "4.1.5", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "71cf170102c8371ccd933fa4df6252086d144de6" + "reference": "fe2d89f2eaa7087af4aa166c6f480ef04e000582" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/71cf170102c8371ccd933fa4df6252086d144de6", - "reference": "71cf170102c8371ccd933fa4df6252086d144de6", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/fe2d89f2eaa7087af4aa166c6f480ef04e000582", + "reference": "fe2d89f2eaa7087af4aa166c6f480ef04e000582", "shasum": "" }, "require": { @@ -1837,7 +2134,7 @@ "infection/infection": "^0.21", "lcobucci/coding-standard": "^6.0", "mikey179/vfsstream": "^1.6.7", - "phpbench/phpbench": "^1.0@alpha", + "phpbench/phpbench": "^1.0", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^0.12", "phpstan/phpstan-deprecation-rules": "^0.12", @@ -1870,7 +2167,7 @@ ], "support": { "issues": "https://github.com/lcobucci/jwt/issues", - "source": "https://github.com/lcobucci/jwt/tree/4.1.4" + "source": "https://github.com/lcobucci/jwt/tree/4.1.5" }, "funding": [ { @@ -1882,46 +2179,56 @@ "type": "patreon" } ], - "time": "2021-03-23T23:53:08+00:00" + "time": "2021-09-28T19:34:56+00:00" }, { "name": "league/commonmark", - "version": "1.6.4", + "version": "2.2.3", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "c3c8b7217c52572fb42aaf84211abccf75a151b2" + "reference": "47b015bc4e50fd4438c1ffef6139a1fb65d2ab71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c3c8b7217c52572fb42aaf84211abccf75a151b2", - "reference": "c3c8b7217c52572fb42aaf84211abccf75a151b2", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/47b015bc4e50fd4438c1ffef6139a1fb65d2ab71", + "reference": "47b015bc4e50fd4438c1ffef6139a1fb65d2ab71", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": "^7.1 || ^8.0" - }, - "conflict": { - "scrutinizer/ocular": "1.7.*" + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.15" }, "require-dev": { - "cebe/markdown": "~1.0", - "commonmark/commonmark.js": "0.29.2", - "erusev/parsedown": "~1.0", + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.30.0", + "commonmark/commonmark.js": "0.30.0", + "composer/package-versions-deprecated": "^1.8", + "erusev/parsedown": "^1.0", "ext-json": "*", "github/gfm": "0.29.0", - "michelf/php-markdown": "~1.4", - "mikehaertl/php-shellcommand": "^1.4", - "phpstan/phpstan": "^0.12.90", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.2", - "scrutinizer/ocular": "^1.5", - "symfony/finder": "^4.2" + "michelf/php-markdown": "^1.4", + "phpstan/phpstan": "^0.12.88 || ^1.0.0", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" }, - "bin": [ - "bin/commonmark" - ], "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.3-dev" + } + }, "autoload": { "psr-4": { "League\\CommonMark\\": "src" @@ -1939,7 +2246,7 @@ "role": "Lead Developer" } ], - "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and Github-Flavored Markdown (GFM)", + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", "homepage": "https://commonmark.thephpleague.com", "keywords": [ "commonmark", @@ -1953,15 +2260,12 @@ ], "support": { "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", "issues": "https://github.com/thephpleague/commonmark/issues", "rss": "https://github.com/thephpleague/commonmark/releases.atom", "source": "https://github.com/thephpleague/commonmark" }, "funding": [ - { - "url": "https://enjoy.gitstore.app/repositories/thephpleague/commonmark", - "type": "custom" - }, { "url": "https://www.colinodell.com/sponsor", "type": "custom" @@ -1974,16 +2278,94 @@ "url": "https://github.com/colinodell", "type": "github" }, - { - "url": "https://www.patreon.com/colinodell", - "type": "patreon" - }, { "url": "https://tidelift.com/funding/github/packagist/league/commonmark", "type": "tidelift" } ], - "time": "2021-06-19T20:08:14+00:00" + "time": "2022-02-26T21:24:45+00:00" + }, + { + "name": "league/config", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e", + "reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.90", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2021-08-14T12:15:32+00:00" }, { "name": "league/event", @@ -2041,16 +2423,16 @@ }, { "name": "league/flysystem", - "version": "1.1.3", + "version": "1.1.9", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "9be3b16c877d477357c015cec057548cf9b2a14a" + "reference": "094defdb4a7001845300334e7c1ee2335925ef99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/9be3b16c877d477357c015cec057548cf9b2a14a", - "reference": "9be3b16c877d477357c015cec057548cf9b2a14a", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/094defdb4a7001845300334e7c1ee2335925ef99", + "reference": "094defdb4a7001845300334e7c1ee2335925ef99", "shasum": "" }, "require": { @@ -2066,7 +2448,6 @@ "phpunit/phpunit": "^8.5.8" }, "suggest": { - "ext-fileinfo": "Required for MimeType", "ext-ftp": "Allows you to use FTP server storage", "ext-openssl": "Allows you to use FTPS server storage", "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", @@ -2124,7 +2505,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.x" + "source": "https://github.com/thephpleague/flysystem/tree/1.1.9" }, "funding": [ { @@ -2132,20 +2513,20 @@ "type": "other" } ], - "time": "2020-08-23T07:39:11+00:00" + "time": "2021-12-09T09:40:50+00:00" }, { "name": "league/mime-type-detection", - "version": "1.7.0", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3" + "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", - "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/aa70e813a6ad3d1558fc927863d47309b4c23e69", + "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69", "shasum": "" }, "require": { @@ -2153,7 +2534,7 @@ "php": "^7.2 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.18", + "friendsofphp/php-cs-fixer": "^3.2", "phpstan/phpstan": "^0.12.68", "phpunit/phpunit": "^8.5.8 || ^9.3" }, @@ -2176,7 +2557,7 @@ "description": "Mime-type detection for Flysystem", "support": { "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.7.0" + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.9.0" }, "funding": [ { @@ -2188,27 +2569,27 @@ "type": "tidelift" } ], - "time": "2021-01-18T20:58:21+00:00" + "time": "2021-11-21T11:48:40+00:00" }, { "name": "league/oauth2-server", - "version": "8.2.4", + "version": "8.3.3", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-server.git", - "reference": "622eaa1f28eb4a2dea0cfc7e4f5280fac794e83c" + "reference": "f5698a3893eda9a17bcd48636990281e7ca77b2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/622eaa1f28eb4a2dea0cfc7e4f5280fac794e83c", - "reference": "622eaa1f28eb4a2dea0cfc7e4f5280fac794e83c", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/f5698a3893eda9a17bcd48636990281e7ca77b2a", + "reference": "f5698a3893eda9a17bcd48636990281e7ca77b2a", "shasum": "" }, "require": { "defuse/php-encryption": "^2.2.1", "ext-json": "*", "ext-openssl": "*", - "lcobucci/jwt": "^3.4 || ^4.0", + "lcobucci/jwt": "^3.4.6 || ^4.0.4", "league/event": "^2.2", "php": "^7.2 || ^8.0", "psr/http-message": "^1.0.1" @@ -2267,7 +2648,7 @@ ], "support": { "issues": "https://github.com/thephpleague/oauth2-server/issues", - "source": "https://github.com/thephpleague/oauth2-server/tree/8.2.4" + "source": "https://github.com/thephpleague/oauth2-server/tree/8.3.3" }, "funding": [ { @@ -2275,28 +2656,28 @@ "type": "github" } ], - "time": "2020-12-10T11:35:44+00:00" + "time": "2021-10-11T20:41:49+00:00" }, { "name": "monolog/monolog", - "version": "2.2.0", + "version": "2.3.5", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", - "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd4380d6fc37626e2f799f29d91195040137eba9", + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9", "shasum": "" }, "require": { "php": ">=7.2", - "psr/log": "^1.0.1" + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "provide": { - "psr/log-implementation": "1.0.0" + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" }, "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", @@ -2304,14 +2685,14 @@ "elasticsearch/elasticsearch": "^7", "graylog2/gelf-php": "^1.4.2", "mongodb/mongodb": "^1.8", - "php-amqplib/php-amqplib": "~2.4", + "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", - "phpstan/phpstan": "^0.12.59", + "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", - "ruflin/elastica": ">=0.90 <7.0.1", + "ruflin/elastica": ">=0.90@dev", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { @@ -2319,8 +2700,11 @@ "doctrine/couchdb": "Allow sending log messages to a CouchDB server", "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", "ext-mbstring": "Allow to work properly with unicode symbols", "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", @@ -2359,125 +2743,336 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.2.0" + "source": "https://github.com/Seldaek/monolog/tree/2.3.5" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2021-10-01T21:08:31+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^1.4 || ^2.0", + "phpunit/phpunit": "^4.8.36 || ^7.5.15" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.6.1" + }, + "time": "2021-06-14T00:11:39+00:00" + }, + { + "name": "nesbot/carbon", + "version": "2.57.0", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "4a54375c21eea4811dbd1149fe6b246517554e78" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4a54375c21eea4811dbd1149fe6b246517554e78", + "reference": "4a54375c21eea4811dbd1149fe6b246517554e78", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" + }, + "require-dev": { + "doctrine/dbal": "^2.0 || ^3.0", + "doctrine/orm": "^2.7", + "friendsofphp/php-cs-fixer": "^3.0", + "kylekatarnls/multi-tester": "^2.0", + "phpmd/phpmd": "^2.9", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.54 || ^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.14", + "squizlabs/php_codesniffer": "^3.4" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-3.x": "3.x-dev", + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/briannesbitt/Carbon/issues", + "source": "https://github.com/briannesbitt/Carbon" + }, + "funding": [ + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2022-02-13T18:13:33+00:00" + }, + { + "name": "nette/schema", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/9a39cef03a5b34c7de64f551538cbba05c2be5df", + "reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df", + "shasum": "" + }, + "require": { + "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0", + "php": ">=7.1 <8.2" + }, + "require-dev": { + "nette/tester": "^2.3 || ^2.4", + "phpstan/phpstan-nette": "^0.12", + "tracy/tracy": "^2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] }, - "funding": [ + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ { - "url": "https://github.com/Seldaek", - "type": "github" + "name": "David Grudl", + "homepage": "https://davidgrudl.com" }, { - "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", - "type": "tidelift" + "name": "Nette Community", + "homepage": "https://nette.org/contributors" } ], - "time": "2020-12-14T13:15:25+00:00" + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.2.2" + }, + "time": "2021-10-15T11:40:02+00:00" }, { - "name": "nesbot/carbon", - "version": "2.49.0", + "name": "nette/utils", + "version": "v3.2.7", "source": { "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "93d9db91c0235c486875d22f1e08b50bdf3e6eee" + "url": "https://github.com/nette/utils.git", + "reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/93d9db91c0235c486875d22f1e08b50bdf3e6eee", - "reference": "93d9db91c0235c486875d22f1e08b50bdf3e6eee", + "url": "https://api.github.com/repos/nette/utils/zipball/0af4e3de4df9f1543534beab255ccf459e7a2c99", + "reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99", "shasum": "" }, "require": { - "ext-json": "*", - "php": "^7.1.8 || ^8.0", - "symfony/polyfill-mbstring": "^1.0", - "symfony/translation": "^3.4 || ^4.0 || ^5.0" + "php": ">=7.2 <8.2" + }, + "conflict": { + "nette/di": "<3.0.6" }, "require-dev": { - "doctrine/orm": "^2.7", - "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", - "kylekatarnls/multi-tester": "^2.0", - "phpmd/phpmd": "^2.9", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.54", - "phpunit/phpunit": "^7.5.20 || ^8.5.14", - "squizlabs/php_codesniffer": "^3.4" + "nette/tester": "~2.0", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" }, - "bin": [ - "bin/carbon" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev", - "dev-3.x": "3.x-dev" - }, - "laravel": { - "providers": [ - "Carbon\\Laravel\\ServiceProvider" - ] - }, - "phpstan": { - "includes": [ - "extension.neon" - ] + "dev-master": "3.2-dev" } }, "autoload": { - "psr-4": { - "Carbon\\": "src/Carbon/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" ], "authors": [ { - "name": "Brian Nesbitt", - "email": "brian@nesbot.com", - "homepage": "http://nesbot.com" + "name": "David Grudl", + "homepage": "https://davidgrudl.com" }, { - "name": "kylekatarnls", - "homepage": "http://github.com/kylekatarnls" + "name": "Nette Community", + "homepage": "https://nette.org/contributors" } ], - "description": "An API extension for DateTime that supports 281 different languages.", - "homepage": "http://carbon.nesbot.com", + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", "keywords": [ - "date", + "array", + "core", "datetime", - "time" + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" ], "support": { - "issues": "https://github.com/briannesbitt/Carbon/issues", - "source": "https://github.com/briannesbitt/Carbon" + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v3.2.7" }, - "funding": [ - { - "url": "https://opencollective.com/Carbon", - "type": "open_collective" - }, - { - "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", - "type": "tidelift" - } - ], - "time": "2021-06-02T07:31:40+00:00" + "time": "2022-01-24T11:29:14+00:00" }, { "name": "nikic/php-parser", - "version": "v4.10.5", + "version": "v4.13.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f" + "reference": "210577fe3cf7badcc5814d99455df46564f3c077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4432ba399e47c66624bc73c8c0f811e5c109576f", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077", "shasum": "" }, "require": { @@ -2518,22 +3113,22 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" }, - "time": "2021-05-03T19:11:20+00:00" + "time": "2021-11-30T19:35:32+00:00" }, { "name": "nyholm/psr7", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/Nyholm/psr7.git", - "reference": "23ae1f00fbc6a886cbe3062ca682391b9cc7c37b" + "reference": "1461e07a0f2a975a52082ca3b769ca912b816226" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Nyholm/psr7/zipball/23ae1f00fbc6a886cbe3062ca682391b9cc7c37b", - "reference": "23ae1f00fbc6a886cbe3062ca682391b9cc7c37b", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/1461e07a0f2a975a52082ca3b769ca912b816226", + "reference": "1461e07a0f2a975a52082ca3b769ca912b816226", "shasum": "" }, "require": { @@ -2547,7 +3142,7 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { - "http-interop/http-factory-tests": "^0.8", + "http-interop/http-factory-tests": "^0.9", "php-http/psr7-integration-tests": "^1.0", "phpunit/phpunit": "^7.5 || 8.5 || 9.4", "symfony/error-handler": "^4.4" @@ -2585,7 +3180,7 @@ ], "support": { "issues": "https://github.com/Nyholm/psr7/issues", - "source": "https://github.com/Nyholm/psr7/tree/1.4.0" + "source": "https://github.com/Nyholm/psr7/tree/1.5.0" }, "funding": [ { @@ -2597,20 +3192,20 @@ "type": "github" } ], - "time": "2021-02-18T15:41:32+00:00" + "time": "2022-02-02T18:37:57+00:00" }, { "name": "opis/closure", - "version": "3.6.2", + "version": "3.6.3", "source": { "type": "git", "url": "https://github.com/opis/closure.git", - "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6" + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6", - "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6", + "url": "https://api.github.com/repos/opis/closure/zipball/3d81e4309d2a927abbe66df935f4bb60082805ad", + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad", "shasum": "" }, "require": { @@ -2627,12 +3222,12 @@ } }, "autoload": { - "psr-4": { - "Opis\\Closure\\": "src/" - }, "files": [ "functions.php" - ] + ], + "psr-4": { + "Opis\\Closure\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2660,22 +3255,22 @@ ], "support": { "issues": "https://github.com/opis/closure/issues", - "source": "https://github.com/opis/closure/tree/3.6.2" + "source": "https://github.com/opis/closure/tree/3.6.3" }, - "time": "2021-04-09T13:42:10+00:00" + "time": "2022-01-27T09:35:39+00:00" }, { "name": "paragonie/constant_time_encoding", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c" + "reference": "9229e15f2e6ba772f0c55dd6986c563b937170a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", - "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/9229e15f2e6ba772f0c55dd6986c563b937170a8", + "reference": "9229e15f2e6ba772f0c55dd6986c563b937170a8", "shasum": "" }, "require": { @@ -2729,7 +3324,7 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2020-12-06T15:14:20+00:00" + "time": "2022-01-17T05:32:27+00:00" }, { "name": "paragonie/random_compat", @@ -2837,29 +3432,29 @@ }, { "name": "phpoption/phpoption", - "version": "1.7.5", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525" + "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", + "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0 || ^8.0" + "php": "^7.0 || ^8.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", - "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.8-dev" } }, "autoload": { @@ -2874,11 +3469,13 @@ "authors": [ { "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" }, { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" } ], "description": "Option Type for PHP", @@ -2890,7 +3487,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.7.5" + "source": "https://github.com/schmittjoh/php-option/tree/1.8.1" }, "funding": [ { @@ -2902,20 +3499,20 @@ "type": "tidelift" } ], - "time": "2020-07-20T17:29:33+00:00" + "time": "2021-12-04T23:24:31+00:00" }, { "name": "phpseclib/phpseclib", - "version": "3.0.9", + "version": "3.0.13", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "a127a5133804ff2f47ae629dd529b129da616ad7" + "reference": "1443ab79364eea48665fa8c09ac67f37d1025f7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/a127a5133804ff2f47ae629dd529b129da616ad7", - "reference": "a127a5133804ff2f47ae629dd529b129da616ad7", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/1443ab79364eea48665fa8c09ac67f37d1025f7e", + "reference": "1443ab79364eea48665fa8c09ac67f37d1025f7e", "shasum": "" }, "require": { @@ -2997,7 +3594,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.9" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.13" }, "funding": [ { @@ -3013,24 +3610,73 @@ "type": "tidelift" } ], - "time": "2021-06-14T06:54:45+00:00" + "time": "2022-01-30T08:50:05+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" }, { "name": "psr/container", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", "shasum": "" }, "require": { - "php": ">=7.2.0" + "php": ">=7.4.0" }, "type": "library", "autoload": { @@ -3059,9 +3705,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.1" + "source": "https://github.com/php-fig/container/tree/1.1.2" }, - "time": "2021-03-05T17:36:06+00:00" + "time": "2021-11-05T16:50:12+00:00" }, { "name": "psr/event-dispatcher", @@ -3376,29 +4022,32 @@ }, { "name": "psy/psysh", - "version": "v0.10.8", + "version": "v0.11.2", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "e4573f47750dd6c92dca5aee543fa77513cbd8d3" + "reference": "7f7da640d68b9c9fec819caae7c744a213df6514" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/e4573f47750dd6c92dca5aee543fa77513cbd8d3", - "reference": "e4573f47750dd6c92dca5aee543fa77513cbd8d3", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/7f7da640d68b9c9fec819caae7c744a213df6514", + "reference": "7f7da640d68b9c9fec819caae7c744a213df6514", "shasum": "" }, "require": { "ext-json": "*", "ext-tokenizer": "*", - "nikic/php-parser": "~4.0|~3.0|~2.0|~1.3", - "php": "^8.0 || ^7.0 || ^5.5.9", - "symfony/console": "~5.0|~4.0|~3.0|^2.4.2|~2.3.10", - "symfony/var-dumper": "~5.0|~4.0|~3.0|~2.7" + "nikic/php-parser": "^4.0 || ^3.1", + "php": "^8.0 || ^7.0.8", + "symfony/console": "^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^6.0 || ^5.0 || ^4.0 || ^3.4" + }, + "conflict": { + "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.2", - "hoa/console": "3.17.*" + "hoa/console": "3.17.05.02" }, "suggest": { "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", @@ -3413,7 +4062,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "0.10.x-dev" + "dev-main": "0.11.x-dev" } }, "autoload": { @@ -3445,9 +4094,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.10.8" + "source": "https://github.com/bobthecow/psysh/tree/v0.11.2" }, - "time": "2021-04-10T16:23:39+00:00" + "time": "2022-02-28T15:28:54+00:00" }, { "name": "ralouphie/getallheaders", @@ -3495,20 +4144,21 @@ }, { "name": "ramsey/collection", - "version": "1.1.3", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1" + "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", + "url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a", + "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a", "shasum": "" }, "require": { - "php": "^7.2 || ^8" + "php": "^7.3 || ^8", + "symfony/polyfill-php81": "^1.23" }, "require-dev": { "captainhook/captainhook": "^5.3", @@ -3518,6 +4168,7 @@ "hamcrest/hamcrest-php": "^2", "jangregor/phpstan-prophecy": "^0.8", "mockery/mockery": "^1.3", + "phpspec/prophecy-phpunit": "^2.0", "phpstan/extension-installer": "^1", "phpstan/phpstan": "^0.12.32", "phpstan/phpstan-mockery": "^0.12.5", @@ -3545,7 +4196,7 @@ "homepage": "https://benramsey.com" } ], - "description": "A PHP 7.2+ library for representing and manipulating collections.", + "description": "A PHP library for representing and manipulating collections.", "keywords": [ "array", "collection", @@ -3556,7 +4207,7 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.1.3" + "source": "https://github.com/ramsey/collection/tree/1.2.2" }, "funding": [ { @@ -3568,53 +4219,54 @@ "type": "tidelift" } ], - "time": "2021-01-21T17:40:04+00:00" + "time": "2021-10-10T03:01:02+00:00" }, { "name": "ramsey/uuid", - "version": "4.1.1", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "cd4032040a750077205918c86049aa0f43d22947" + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947", - "reference": "cd4032040a750077205918c86049aa0f43d22947", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", "shasum": "" }, "require": { "brick/math": "^0.8 || ^0.9", "ext-json": "*", - "php": "^7.2 || ^8", + "php": "^7.2 || ^8.0", "ramsey/collection": "^1.0", - "symfony/polyfill-ctype": "^1.8" + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php80": "^1.14" }, "replace": { "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "doctrine/annotations": "^1.8", - "goaop/framework": "^2", + "ergebnis/composer-normalize": "^2.15", "mockery/mockery": "^1.3", "moontoast/math": "^1.1", "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", "php-mock/php-mock-mockery": "^1.3", - "php-mock/php-mock-phpunit": "^2.5", "php-parallel-lint/php-parallel-lint": "^1.1", - "phpbench/phpbench": "^0.17.1", + "phpbench/phpbench": "^1.0", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^0.12", "phpstan/phpstan-mockery": "^0.12", "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^8.5", - "psy/psysh": "^0.10.0", - "slevomat/coding-standard": "^6.0", + "phpunit/phpunit": "^8.5 || ^9", + "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "3.9.4" + "vimeo/psalm": "^4.9" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", @@ -3627,23 +4279,25 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-main": "4.x-dev" + }, + "captainhook": { + "force-install": true } }, "autoload": { - "psr-4": { - "Ramsey\\Uuid\\": "src/" - }, "files": [ "src/functions.php" - ] + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", - "homepage": "https://github.com/ramsey/uuid", "keywords": [ "guid", "identifier", @@ -3651,29 +4305,92 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "rss": "https://github.com/ramsey/uuid/releases.atom", - "source": "https://github.com/ramsey/uuid" + "source": "https://github.com/ramsey/uuid/tree/4.2.3" }, "funding": [ { "url": "https://github.com/ramsey", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "time": "2021-09-25T23:10:38+00:00" + }, + { + "name": "stripe/stripe-php", + "version": "v7.121.0", + "source": { + "type": "git", + "url": "https://github.com/stripe/stripe-php.git", + "reference": "e36e7afb71ae5511aae23b52dca712a0ef06d981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stripe/stripe-php/zipball/e36e7afb71ae5511aae23b52dca712a0ef06d981", + "reference": "e36e7afb71ae5511aae23b52dca712a0ef06d981", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=5.6.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.5.0", + "phpstan/phpstan": "^1.2", + "phpunit/phpunit": "^5.7 || ^9.0", + "squizlabs/php_codesniffer": "^3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Stripe\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stripe and contributors", + "homepage": "https://github.com/stripe/stripe-php/contributors" } ], - "time": "2020-08-18T17:17:46+00:00" + "description": "Stripe PHP Library", + "homepage": "https://stripe.com/", + "keywords": [ + "api", + "payment processing", + "stripe" + ], + "support": { + "issues": "https://github.com/stripe/stripe-php/issues", + "source": "https://github.com/stripe/stripe-php/tree/v7.121.0" + }, + "time": "2022-03-30T15:51:23+00:00" }, { "name": "swiftmailer/swiftmailer", - "version": "v6.2.7", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "15f7faf8508e04471f666633addacf54c0ab5933" + "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/15f7faf8508e04471f666633addacf54c0ab5933", - "reference": "15f7faf8508e04471f666633addacf54c0ab5933", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8a5d5072dca8f48460fce2f4131fcc495eec654c", + "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c", "shasum": "" }, "require": { @@ -3685,7 +4402,7 @@ }, "require-dev": { "mockery/mockery": "^1.0", - "symfony/phpunit-bridge": "^4.4|^5.0" + "symfony/phpunit-bridge": "^4.4|^5.4" }, "suggest": { "ext-intl": "Needed to support internationalized email addresses" @@ -3723,7 +4440,7 @@ ], "support": { "issues": "https://github.com/swiftmailer/swiftmailer/issues", - "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.2.7" + "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.3.0" }, "funding": [ { @@ -3735,32 +4452,34 @@ "type": "tidelift" } ], - "time": "2021-03-09T12:30:35+00:00" + "abandoned": "symfony/mailer", + "time": "2021-10-18T15:26:12+00:00" }, { "name": "symfony/console", - "version": "v5.3.2", + "version": "v5.4.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "649730483885ff2ca99ca0560ef0e5f6b03f2ac1" + "reference": "d8111acc99876953f52fe16d4c50eb60940d49ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/649730483885ff2ca99ca0560ef0e5f6b03f2ac1", - "reference": "649730483885ff2ca99ca0560ef0e5f6b03f2ac1", + "url": "https://api.github.com/repos/symfony/console/zipball/d8111acc99876953f52fe16d4c50eb60940d49ad", + "reference": "d8111acc99876953f52fe16d4c50eb60940d49ad", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.15", - "symfony/service-contracts": "^1.1|^2", - "symfony/string": "^5.1" + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" }, "conflict": { + "psr/log": ">=3", "symfony/dependency-injection": "<4.4", "symfony/dotenv": "<5.1", "symfony/event-dispatcher": "<4.4", @@ -3768,16 +4487,16 @@ "symfony/process": "<4.4" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" + "psr/log": "^1|^2", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" }, "suggest": { "psr/log": "For using the console logger", @@ -3817,7 +4536,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.3.2" + "source": "https://github.com/symfony/console/tree/v5.4.5" }, "funding": [ { @@ -3833,24 +4552,25 @@ "type": "tidelift" } ], - "time": "2021-06-12T09:42:48+00:00" + "time": "2022-02-24T12:45:35+00:00" }, { "name": "symfony/css-selector", - "version": "v5.3.0", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814" + "reference": "b0a190285cd95cb019237851205b8140ef6e368e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", - "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/b0a190285cd95cb019237851205b8140ef6e368e", + "reference": "b0a190285cd95cb019237851205b8140ef6e368e", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -3882,7 +4602,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.3.0" + "source": "https://github.com/symfony/css-selector/tree/v5.4.3" }, "funding": [ { @@ -3898,20 +4618,20 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:40:38+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627" + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627", - "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", "shasum": "" }, "require": { @@ -3920,7 +4640,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3949,7 +4669,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" }, "funding": [ { @@ -3965,33 +4685,35 @@ "type": "tidelift" } ], - "time": "2021-03-23T23:28:01+00:00" + "time": "2021-07-12T14:48:14+00:00" }, { "name": "symfony/error-handler", - "version": "v5.3.0", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "0e6768b8c0dcef26df087df2bbbaa143867a59b2" + "reference": "c4ffc2cd919950d13c8c9ce32a70c70214c3ffc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/0e6768b8c0dcef26df087df2bbbaa143867a59b2", - "reference": "0e6768b8c0dcef26df087df2bbbaa143867a59b2", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/c4ffc2cd919950d13c8c9ce32a70c70214c3ffc5", + "reference": "c4ffc2cd919950d13c8c9ce32a70c70214c3ffc5", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/log": "^1.0", - "symfony/polyfill-php80": "^1.15", - "symfony/var-dumper": "^4.4|^5.0" + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^4.4|^5.0|^6.0" }, "require-dev": { - "symfony/deprecation-contracts": "^2.1", - "symfony/http-kernel": "^4.4|^5.0", - "symfony/serializer": "^4.4|^5.0" + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], "type": "library", "autoload": { "psr-4": { @@ -4018,7 +4740,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.3.0" + "source": "https://github.com/symfony/error-handler/tree/v5.4.3" }, "funding": [ { @@ -4034,27 +4756,27 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.3.0", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "67a5f354afa8e2f231081b3fa11a5912f933c3ce" + "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/67a5f354afa8e2f231081b3fa11a5912f933c3ce", - "reference": "67a5f354afa8e2f231081b3fa11a5912f933c3ce", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dec8a9f58d20df252b9cd89f1c6c1530f747685d", + "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/event-dispatcher-contracts": "^2", - "symfony/polyfill-php80": "^1.15" + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" }, "conflict": { "symfony/dependency-injection": "<4.4" @@ -4064,14 +4786,14 @@ "symfony/event-dispatcher-implementation": "2.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/error-handler": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/http-foundation": "^4.4|^5.0", - "symfony/service-contracts": "^1.1|^2", - "symfony/stopwatch": "^4.4|^5.0" + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0" }, "suggest": { "symfony/dependency-injection": "", @@ -4103,7 +4825,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.3.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.3" }, "funding": [ { @@ -4119,20 +4841,20 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11" + "reference": "66bea3b09be61613cd3b4043a65a8ec48cfa6d2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/69fee1ad2332a7cbab3aca13591953da9cdb7a11", - "reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/66bea3b09be61613cd3b4043a65a8ec48cfa6d2a", + "reference": "66bea3b09be61613cd3b4043a65a8ec48cfa6d2a", "shasum": "" }, "require": { @@ -4145,7 +4867,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -4162,88 +4884,27 @@ "MIT" ], "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.4.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-03-23T23:28:01+00:00" - }, - { - "name": "symfony/finder", - "version": "v5.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", - "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", - "shasum": "" - }, - "require": { - "php": ">=7.2.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Finds files and directories via an intuitive fluent interface", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "source": "https://github.com/symfony/finder/tree/v5.3.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.0" }, "funding": [ { @@ -4259,42 +4920,35 @@ "type": "tidelift" } ], - "time": "2021-05-26T12:52:38+00:00" + "time": "2021-07-12T14:48:14+00:00" }, { - "name": "symfony/http-client-contracts", - "version": "v2.4.0", + "name": "symfony/finder", + "version": "v5.4.3", "source": { "type": "git", - "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "7e82f6084d7cae521a75ef2cb5c9457bbda785f4" + "url": "https://github.com/symfony/finder.git", + "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/7e82f6084d7cae521a75ef2cb5c9457bbda785f4", - "reference": "7e82f6084d7cae521a75ef2cb5c9457bbda785f4", + "url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d", "shasum": "" }, "require": { - "php": ">=7.2.5" - }, - "suggest": { - "symfony/http-client-implementation": "" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, "autoload": { "psr-4": { - "Symfony\\Contracts\\HttpClient\\": "" - } + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4302,26 +4956,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to HTTP clients", + "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/finder/tree/v5.4.3" }, "funding": [ { @@ -4337,33 +4983,33 @@ "type": "tidelift" } ], - "time": "2021-04-11T23:07:08+00:00" + "time": "2022-01-26T16:34:36+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.3.2", + "version": "v5.4.6", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "7b6dd714d95106b831aaa7f3c9c612ab886516bd" + "reference": "34e89bc147633c0f9dd6caaaf56da3b806a21465" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7b6dd714d95106b831aaa7f3c9c612ab886516bd", - "reference": "7b6dd714d95106b831aaa7f3c9c612ab886516bd", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/34e89bc147633c0f9dd6caaaf56da3b806a21465", + "reference": "34e89bc147633c0f9dd6caaaf56da3b806a21465", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "require-dev": { "predis/predis": "~1.0", - "symfony/cache": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/mime": "^4.4|^5.0" + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/mime": "^4.4|^5.0|^6.0" }, "suggest": { "symfony/mime": "To use the file extension guesser" @@ -4394,7 +5040,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.3.2" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.6" }, "funding": [ { @@ -4410,36 +5056,35 @@ "type": "tidelift" } ], - "time": "2021-06-12T10:15:17+00:00" + "time": "2022-03-05T21:03:43+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.3.2", + "version": "v5.4.6", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "e7021165d9dbfb4051296b8de827e92c8a7b5c87" + "reference": "d41f29ae9af1b5f40c7ebcddf09082953229411d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e7021165d9dbfb4051296b8de827e92c8a7b5c87", - "reference": "e7021165d9dbfb4051296b8de827e92c8a7b5c87", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/d41f29ae9af1b5f40c7ebcddf09082953229411d", + "reference": "d41f29ae9af1b5f40c7ebcddf09082953229411d", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/log": "~1.0", - "symfony/deprecation-contracts": "^2.1", - "symfony/error-handler": "^4.4|^5.0", - "symfony/event-dispatcher": "^5.0", - "symfony/http-client-contracts": "^1.1|^2", - "symfony/http-foundation": "^5.3", + "psr/log": "^1|^2", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^5.0|^6.0", + "symfony/http-foundation": "^5.3.7|^6.0", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { - "symfony/browser-kit": "<4.4", + "symfony/browser-kit": "<5.4", "symfony/cache": "<5.0", "symfony/config": "<5.0", "symfony/console": "<4.4", @@ -4455,23 +5100,24 @@ "twig/twig": "<2.13" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^4.4|^5.0", - "symfony/config": "^5.0", - "symfony/console": "^4.4|^5.0", - "symfony/css-selector": "^4.4|^5.0", - "symfony/dependency-injection": "^5.3", - "symfony/dom-crawler": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/routing": "^4.4|^5.0", - "symfony/stopwatch": "^4.4|^5.0", - "symfony/translation": "^4.4|^5.0", - "symfony/translation-contracts": "^1.1|^2", + "symfony/browser-kit": "^5.4|^6.0", + "symfony/config": "^5.0|^6.0", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/css-selector": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^5.3|^6.0", + "symfony/dom-crawler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/http-client-contracts": "^1.1|^2|^3", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/routing": "^4.4|^5.0|^6.0", + "symfony/stopwatch": "^4.4|^5.0|^6.0", + "symfony/translation": "^4.4|^5.0|^6.0", + "symfony/translation-contracts": "^1.1|^2|^3", "twig/twig": "^2.13|^3.0.4" }, "suggest": { @@ -4506,7 +5152,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.3.2" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.6" }, "funding": [ { @@ -4522,28 +5168,28 @@ "type": "tidelift" } ], - "time": "2021-06-17T14:18:27+00:00" + "time": "2022-03-05T21:14:51+00:00" }, { "name": "symfony/mime", - "version": "v5.3.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "47dd7912152b82d0d4c8d9040dbc93d6232d472a" + "reference": "e1503cfb5c9a225350f549d3bb99296f4abfb80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/47dd7912152b82d0d4c8d9040dbc93d6232d472a", - "reference": "47dd7912152b82d0d4c8d9040dbc93d6232d472a", + "url": "https://api.github.com/repos/symfony/mime/zipball/e1503cfb5c9a225350f549d3bb99296f4abfb80f", + "reference": "e1503cfb5c9a225350f549d3bb99296f4abfb80f", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "egulias/email-validator": "~3.0.0", @@ -4554,10 +5200,10 @@ "require-dev": { "egulias/email-validator": "^2.1.10|^3.1", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/property-access": "^4.4|^5.1", - "symfony/property-info": "^4.4|^5.1", - "symfony/serializer": "^5.2" + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.1|^6.0", + "symfony/property-info": "^4.4|^5.1|^6.0", + "symfony/serializer": "^5.2|^6.0" }, "type": "library", "autoload": { @@ -4589,7 +5235,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.3.2" + "source": "https://github.com/symfony/mime/tree/v5.4.3" }, "funding": [ { @@ -4605,25 +5251,28 @@ "type": "tidelift" } ], - "time": "2021-06-09T10:58:01+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "30885182c981ab175d4d034db0f6f469898070ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, @@ -4638,12 +5287,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4668,7 +5317,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" }, "funding": [ { @@ -4684,25 +5333,28 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-10-20T20:35:02+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933" + "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/63b5bb7db83e5673936d6e3b8b3e022ff6474933", - "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f1aed619e28cb077fc83fac8c4c0383578356e40", + "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-iconv": "*" + }, "suggest": { "ext-iconv": "For best performance" }, @@ -4717,12 +5369,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Iconv\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Iconv\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4748,7 +5400,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.25.0" }, "funding": [ { @@ -4764,20 +5416,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2022-01-04T09:04:05+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab" + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/24b72c6baa32c746a4d0840147c9715e42bb68ab", - "reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", "shasum": "" }, "require": { @@ -4797,12 +5449,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4829,7 +5481,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" }, "funding": [ { @@ -4845,20 +5497,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2021-11-23T21:10:46+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" + "reference": "749045c69efb97c70d25d7463abba812e91f3a44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44", + "reference": "749045c69efb97c70d25d7463abba812e91f3a44", "shasum": "" }, "require": { @@ -4880,12 +5532,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4916,7 +5568,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.25.0" }, "funding": [ { @@ -4932,11 +5584,11 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2021-09-14T14:02:44+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -4965,12 +5617,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -5000,7 +5652,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" }, "funding": [ { @@ -5020,21 +5672,24 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-mbstring": "*" + }, "suggest": { "ext-mbstring": "For best performance" }, @@ -5049,12 +5704,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5080,7 +5735,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" }, "funding": [ { @@ -5096,11 +5751,11 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2021-11-30T18:21:41+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", @@ -5126,12 +5781,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5156,7 +5811,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.25.0" }, "funding": [ { @@ -5176,16 +5831,16 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", "shasum": "" }, "require": { @@ -5202,12 +5857,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -5235,7 +5890,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" }, "funding": [ { @@ -5251,20 +5906,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-06-05T21:20:04+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.23.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", "shasum": "" }, "require": { @@ -5281,12 +5936,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -5318,7 +5973,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" }, "funding": [ { @@ -5334,25 +5989,104 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-03-04T08:16:47+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-09-13T13:58:11+00:00" }, { "name": "symfony/process", - "version": "v5.3.2", + "version": "v5.4.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "714b47f9196de61a196d86c4bad5f09201b307df" + "reference": "95440409896f90a5f85db07a32b517ecec17fa4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/714b47f9196de61a196d86c4bad5f09201b307df", - "reference": "714b47f9196de61a196d86c4bad5f09201b307df", + "url": "https://api.github.com/repos/symfony/process/zipball/95440409896f90a5f85db07a32b517ecec17fa4c", + "reference": "95440409896f90a5f85db07a32b517ecec17fa4c", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -5380,7 +6114,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.3.2" + "source": "https://github.com/symfony/process/tree/v5.4.5" }, "funding": [ { @@ -5396,36 +6130,36 @@ "type": "tidelift" } ], - "time": "2021-06-12T10:15:01+00:00" + "time": "2022-01-30T18:16:22+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v2.1.0", + "version": "v2.1.2", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "81db2d4ae86e9f0049828d9343a72b9523884e5d" + "reference": "22b37c8a3f6b5d94e9cdbd88e1270d96e2f97b34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/81db2d4ae86e9f0049828d9343a72b9523884e5d", - "reference": "81db2d4ae86e9f0049828d9343a72b9523884e5d", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/22b37c8a3f6b5d94e9cdbd88e1270d96e2f97b34", + "reference": "22b37c8a3f6b5d94e9cdbd88e1270d96e2f97b34", "shasum": "" }, "require": { "php": ">=7.1", "psr/http-message": "^1.0", - "symfony/http-foundation": "^4.4 || ^5.0" + "symfony/http-foundation": "^4.4 || ^5.0 || ^6.0" }, "require-dev": { "nyholm/psr7": "^1.1", - "psr/log": "^1.1", - "symfony/browser-kit": "^4.4 || ^5.0", - "symfony/config": "^4.4 || ^5.0", - "symfony/event-dispatcher": "^4.4 || ^5.0", - "symfony/framework-bundle": "^4.4 || ^5.0", - "symfony/http-kernel": "^4.4 || ^5.0", - "symfony/phpunit-bridge": "^4.4.19 || ^5.2" + "psr/log": "^1.1 || ^2 || ^3", + "symfony/browser-kit": "^4.4 || ^5.0 || ^6.0", + "symfony/config": "^4.4 || ^5.0 || ^6.0", + "symfony/event-dispatcher": "^4.4 || ^5.0 || ^6.0", + "symfony/framework-bundle": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "^4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.4@dev || ^6.0" }, "suggest": { "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" @@ -5468,7 +6202,7 @@ ], "support": { "issues": "https://github.com/symfony/psr-http-message-bridge/issues", - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.0" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.2" }, "funding": [ { @@ -5484,26 +6218,26 @@ "type": "tidelift" } ], - "time": "2021-02-17T10:35:25+00:00" + "time": "2021-11-05T13:13:39+00:00" }, { "name": "symfony/routing", - "version": "v5.3.0", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "368e81376a8e049c37cb80ae87dbfbf411279199" + "reference": "44b29c7a94e867ccde1da604792f11a469958981" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/368e81376a8e049c37cb80ae87dbfbf411279199", - "reference": "368e81376a8e049c37cb80ae87dbfbf411279199", + "url": "https://api.github.com/repos/symfony/routing/zipball/44b29c7a94e867ccde1da604792f11a469958981", + "reference": "44b29c7a94e867ccde1da604792f11a469958981", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-php80": "^1.15" + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" }, "conflict": { "doctrine/annotations": "<1.12", @@ -5513,12 +6247,12 @@ }, "require-dev": { "doctrine/annotations": "^1.12", - "psr/log": "~1.0", - "symfony/config": "^5.3", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/http-foundation": "^4.4|^5.0", - "symfony/yaml": "^4.4|^5.0" + "psr/log": "^1|^2|^3", + "symfony/config": "^5.3|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4|^5.0|^6.0" }, "suggest": { "symfony/config": "For using the all-in-one router or any loader", @@ -5558,7 +6292,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.3.0" + "source": "https://github.com/symfony/routing/tree/v5.4.3" }, "funding": [ { @@ -5574,25 +6308,29 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb" + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", - "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/container": "^1.1" + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1" + }, + "conflict": { + "ext-psr": "<1.1|>=2" }, "suggest": { "symfony/service-implementation": "" @@ -5600,7 +6338,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -5637,7 +6375,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.0" }, "funding": [ { @@ -5653,20 +6391,20 @@ "type": "tidelift" } ], - "time": "2021-04-01T10:43:52+00:00" + "time": "2021-11-04T16:48:04+00:00" }, { "name": "symfony/string", - "version": "v5.3.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "0732e97e41c0a590f77e231afc16a327375d50b0" + "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/0732e97e41c0a590f77e231afc16a327375d50b0", - "reference": "0732e97e41c0a590f77e231afc16a327375d50b0", + "url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10", + "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10", "shasum": "" }, "require": { @@ -5677,20 +6415,23 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "~1.15" }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0", - "symfony/http-client": "^4.4|^5.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0" + "symfony/var-exporter": "^4.4|^5.0|^6.0" }, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\String\\": "" - }, "files": [ "Resources/functions.php" ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, "exclude-from-classmap": [ "/Tests/" ] @@ -5720,7 +6461,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.3.2" + "source": "https://github.com/symfony/string/tree/v5.4.3" }, "funding": [ { @@ -5736,31 +6477,32 @@ "type": "tidelift" } ], - "time": "2021-06-06T09:51:56+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/translation", - "version": "v5.3.2", + "version": "v5.4.6", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "7e2603bcc598e14804c4d2359d8dc4ee3c40391b" + "reference": "a7ca9fdfffb0174209440c2ffa1dee228e15d95b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/7e2603bcc598e14804c4d2359d8dc4ee3c40391b", - "reference": "7e2603bcc598e14804c4d2359d8dc4ee3c40391b", + "url": "https://api.github.com/repos/symfony/translation/zipball/a7ca9fdfffb0174209440c2ffa1dee228e15d95b", + "reference": "a7ca9fdfffb0174209440c2ffa1dee228e15d95b", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php80": "^1.16", "symfony/translation-contracts": "^2.3" }, "conflict": { "symfony/config": "<4.4", + "symfony/console": "<5.3", "symfony/dependency-injection": "<5.0", "symfony/http-kernel": "<5.0", "symfony/twig-bundle": "<5.0", @@ -5770,16 +6512,17 @@ "symfony/translation-implementation": "2.3" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^4.4|^5.0", - "symfony/console": "^4.4|^5.0", - "symfony/dependency-injection": "^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/http-kernel": "^5.0", - "symfony/intl": "^4.4|^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/http-client-contracts": "^1.1|^2.0|^3.0", + "symfony/http-kernel": "^5.0|^6.0", + "symfony/intl": "^4.4|^5.0|^6.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/service-contracts": "^1.1.2|^2", - "symfony/yaml": "^4.4|^5.0" + "symfony/service-contracts": "^1.1.2|^2|^3", + "symfony/yaml": "^4.4|^5.0|^6.0" }, "suggest": { "psr/log-implementation": "To use logging capability in translator", @@ -5815,7 +6558,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.3.2" + "source": "https://github.com/symfony/translation/tree/v5.4.6" }, "funding": [ { @@ -5831,20 +6574,20 @@ "type": "tidelift" } ], - "time": "2021-06-06T09:51:56+00:00" + "time": "2022-03-02T12:56:28+00:00" }, { "name": "symfony/translation-contracts", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "95c812666f3e91db75385749fe219c5e494c7f95" + "reference": "d28150f0f44ce854e942b671fc2620a98aae1b1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/95c812666f3e91db75385749fe219c5e494c7f95", - "reference": "95c812666f3e91db75385749fe219c5e494c7f95", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/d28150f0f44ce854e942b671fc2620a98aae1b1e", + "reference": "d28150f0f44ce854e942b671fc2620a98aae1b1e", "shasum": "" }, "require": { @@ -5856,7 +6599,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -5893,7 +6636,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/translation-contracts/tree/v2.5.0" }, "funding": [ { @@ -5909,26 +6652,26 @@ "type": "tidelift" } ], - "time": "2021-03-23T23:28:01+00:00" + "time": "2021-08-17T14:20:01+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.3.2", + "version": "v5.4.6", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "905a22c68b292ffb6f20d7636c36b220d1fba5ae" + "reference": "294e9da6e2e0dd404e983daa5aa74253d92c05d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/905a22c68b292ffb6f20d7636c36b220d1fba5ae", - "reference": "905a22c68b292ffb6f20d7636c36b220d1fba5ae", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/294e9da6e2e0dd404e983daa5aa74253d92c05d0", + "reference": "294e9da6e2e0dd404e983daa5aa74253d92c05d0", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "phpunit/phpunit": "<5.4.3", @@ -5936,8 +6679,9 @@ }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/uid": "^5.1|^6.0", "twig/twig": "^2.13|^3.0.4" }, "suggest": { @@ -5981,7 +6725,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.3.2" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.6" }, "funding": [ { @@ -5997,30 +6741,30 @@ "type": "tidelift" } ], - "time": "2021-06-06T09:51:56+00:00" + "time": "2022-03-02T12:42:23+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "2.2.3", + "version": "2.2.4", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "b43b05cf43c1b6d849478965062b6ef73e223bb5" + "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/b43b05cf43c1b6d849478965062b6ef73e223bb5", - "reference": "b43b05cf43c1b6d849478965062b6ef73e223bb5", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/da444caae6aca7a19c0c140f68c6182e337d5b1c", + "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "php": "^5.5 || ^7.0 || ^8.0", - "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0" + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10" }, "type": "library", "extra": { @@ -6048,37 +6792,37 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.3" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.4" }, - "time": "2020-07-13T06:12:54+00:00" + "time": "2021-12-08T09:12:39+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.3.0", + "version": "v5.4.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56" + "reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/b3eac5c7ac896e52deab4a99068e3f4ab12d9e56", - "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/264dce589e7ce37a7ba99cb901eed8249fbec92f", + "reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.0.1", + "graham-campbell/result-type": "^1.0.2", "php": "^7.1.3 || ^8.0", - "phpoption/phpoption": "^1.7.4", - "symfony/polyfill-ctype": "^1.17", - "symfony/polyfill-mbstring": "^1.17", - "symfony/polyfill-php80": "^1.17" + "phpoption/phpoption": "^1.8", + "symfony/polyfill-ctype": "^1.23", + "symfony/polyfill-mbstring": "^1.23.1", + "symfony/polyfill-php80": "^1.23.1" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", "ext-filter": "*", - "phpunit/phpunit": "^7.5.20 || ^8.5.14 || ^9.5.1" + "phpunit/phpunit": "^7.5.20 || ^8.5.21 || ^9.5.10" }, "suggest": { "ext-filter": "Required to use the boolean validator." @@ -6086,7 +6830,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3-dev" + "dev-master": "5.4-dev" } }, "autoload": { @@ -6101,13 +6845,13 @@ "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com", - "homepage": "https://gjcampbell.co.uk/" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" }, { "name": "Vance Lucas", "email": "vance@vancelucas.com", - "homepage": "https://vancelucas.com/" + "homepage": "https://github.com/vlucas" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -6118,7 +6862,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.3.0" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.4.1" }, "funding": [ { @@ -6130,20 +6874,20 @@ "type": "tidelift" } ], - "time": "2021-01-20T15:23:13+00:00" + "time": "2021-12-12T23:22:04+00:00" }, { "name": "voku/portable-ascii", - "version": "1.5.6", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", - "reference": "80953678b19901e5165c56752d087fc11526017c" + "reference": "87337c91b9dfacee02452244ee14ab3c43bc485a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/80953678b19901e5165c56752d087fc11526017c", - "reference": "80953678b19901e5165c56752d087fc11526017c", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/87337c91b9dfacee02452244ee14ab3c43bc485a", + "reference": "87337c91b9dfacee02452244ee14ab3c43bc485a", "shasum": "" }, "require": { @@ -6180,7 +6924,7 @@ ], "support": { "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/1.5.6" + "source": "https://github.com/voku/portable-ascii/tree/1.6.1" }, "funding": [ { @@ -6204,7 +6948,7 @@ "type": "tidelift" } ], - "time": "2020-11-12T00:07:28+00:00" + "time": "2022-01-24T18:55:24+00:00" }, { "name": "webmozart/assert", @@ -6268,29 +7012,30 @@ "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.0", + "doctrine/coding-standard": "^9", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" }, "type": "library", "autoload": { @@ -6317,7 +7062,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + "source": "https://github.com/doctrine/instantiator/tree/1.4.1" }, "funding": [ { @@ -6333,20 +7078,20 @@ "type": "tidelift" } ], - "time": "2020-11-10T18:47:58+00:00" + "time": "2022-03-03T08:28:38+00:00" }, { "name": "facade/flare-client-php", - "version": "1.8.1", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/facade/flare-client-php.git", - "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f" + "reference": "b2adf1512755637d0cef4f7d1b54301325ac78ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/47b639dc02bcfdfc4ebb83de703856fa01e35f5f", - "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/b2adf1512755637d0cef4f7d1b54301325ac78ed", + "reference": "b2adf1512755637d0cef4f7d1b54301325ac78ed", "shasum": "" }, "require": { @@ -6369,12 +7114,12 @@ } }, "autoload": { - "psr-4": { - "Facade\\FlareClient\\": "src" - }, "files": [ "src/helpers.php" - ] + ], + "psr-4": { + "Facade\\FlareClient\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6390,7 +7135,7 @@ ], "support": { "issues": "https://github.com/facade/flare-client-php/issues", - "source": "https://github.com/facade/flare-client-php/tree/1.8.1" + "source": "https://github.com/facade/flare-client-php/tree/1.9.1" }, "funding": [ { @@ -6398,28 +7143,28 @@ "type": "github" } ], - "time": "2021-05-31T19:23:29+00:00" + "time": "2021-09-13T12:16:46+00:00" }, { "name": "facade/ignition", - "version": "2.10.2", + "version": "2.17.5", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "43688227bbf27c43bc1ad83af224f135b6ef0ff4" + "reference": "1d71996f83c9a5a7807331b8986ac890352b7a0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/43688227bbf27c43bc1ad83af224f135b6ef0ff4", - "reference": "43688227bbf27c43bc1ad83af224f135b6ef0ff4", + "url": "https://api.github.com/repos/facade/ignition/zipball/1d71996f83c9a5a7807331b8986ac890352b7a0c", + "reference": "1d71996f83c9a5a7807331b8986ac890352b7a0c", "shasum": "" }, "require": { + "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", - "facade/flare-client-php": "^1.6", + "facade/flare-client-php": "^1.9.1", "facade/ignition-contracts": "^1.0.2", - "filp/whoops": "^2.4", "illuminate/support": "^7.0|^8.0", "monolog/monolog": "^2.0", "php": "^7.2.5|^8.0", @@ -6428,6 +7173,7 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", + "livewire/livewire": "^2.4", "mockery/mockery": "^1.3", "orchestra/testbench": "^5.0|^6.0", "psalm/plugin-laravel": "^1.2" @@ -6450,12 +7196,12 @@ } }, "autoload": { - "psr-4": { - "Facade\\Ignition\\": "src" - }, "files": [ "src/helpers.php" - ] + ], + "psr-4": { + "Facade\\Ignition\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6475,7 +7221,7 @@ "issues": "https://github.com/facade/ignition/issues", "source": "https://github.com/facade/ignition" }, - "time": "2021-06-11T06:57:25+00:00" + "time": "2022-02-23T18:31:24+00:00" }, { "name": "facade/ignition-contracts", @@ -6532,32 +7278,34 @@ }, { "name": "fakerphp/faker", - "version": "v1.14.1", + "version": "v1.19.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "ed22aee8d17c7b396f74a58b1e7fefa4f90d5ef1" + "reference": "d7f08a622b3346766325488aa32ddc93ccdecc75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/ed22aee8d17c7b396f74a58b1e7fefa4f90d5ef1", - "reference": "ed22aee8d17c7b396f74a58b1e7fefa4f90d5ef1", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/d7f08a622b3346766325488aa32ddc93ccdecc75", + "reference": "d7f08a622b3346766325488aa32ddc93ccdecc75", "shasum": "" }, "require": { "php": "^7.1 || ^8.0", - "psr/container": "^1.0", - "symfony/deprecation-contracts": "^2.2" + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" }, "conflict": { "fzaninotto/faker": "*" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", "ext-intl": "*", "symfony/phpunit-bridge": "^4.4 || ^5.2" }, "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", "ext-curl": "Required by Faker\\Provider\\Image to download images.", "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", @@ -6566,7 +7314,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "v1.15-dev" + "dev-main": "v1.19-dev" } }, "autoload": { @@ -6591,27 +7339,27 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v.1.14.1" + "source": "https://github.com/FakerPHP/Faker/tree/v1.19.0" }, - "time": "2021-03-30T06:27:33+00:00" + "time": "2022-02-02T17:38:57+00:00" }, { "name": "filp/whoops", - "version": "2.13.0", + "version": "2.14.5", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "2edbc73a4687d9085c8f20f398eebade844e8424" + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/2edbc73a4687d9085c8f20f398eebade844e8424", - "reference": "2edbc73a4687d9085c8f20f398eebade844e8424", + "url": "https://api.github.com/repos/filp/whoops/zipball/a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", "shasum": "" }, "require": { "php": "^5.5.9 || ^7.0 || ^8.0", - "psr/log": "^1.0.1" + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { "mockery/mockery": "^0.9 || ^1.0", @@ -6656,7 +7404,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.13.0" + "source": "https://github.com/filp/whoops/tree/2.14.5" }, "funding": [ { @@ -6664,7 +7412,7 @@ "type": "github" } ], - "time": "2021-06-04T12:00:00+00:00" + "time": "2022-01-07T12:00:00+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -6719,16 +7467,16 @@ }, { "name": "laravel/sail", - "version": "v1.8.1", + "version": "v1.13.5", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "77fb31eb48de9971af1fe0c6b47be3da6b869dfd" + "reference": "aeb6eeb55b22c328d2f301145b97288127691d48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/77fb31eb48de9971af1fe0c6b47be3da6b869dfd", - "reference": "77fb31eb48de9971af1fe0c6b47be3da6b869dfd", + "url": "https://api.github.com/repos/laravel/sail/zipball/aeb6eeb55b22c328d2f301145b97288127691d48", + "reference": "aeb6eeb55b22c328d2f301145b97288127691d48", "shasum": "" }, "require": { @@ -6775,20 +7523,20 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2021-06-08T15:18:38+00:00" + "time": "2022-02-17T19:59:03+00:00" }, { "name": "mockery/mockery", - "version": "1.4.3", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "d1339f64479af1bee0e82a0413813fe5345a54ea" + "reference": "c10a5f6e06fc2470ab1822fa13fa2a7380f8fbac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/d1339f64479af1bee0e82a0413813fe5345a54ea", - "reference": "d1339f64479af1bee0e82a0413813fe5345a54ea", + "url": "https://api.github.com/repos/mockery/mockery/zipball/c10a5f6e06fc2470ab1822fa13fa2a7380f8fbac", + "reference": "c10a5f6e06fc2470ab1822fa13fa2a7380f8fbac", "shasum": "" }, "require": { @@ -6845,43 +7593,44 @@ ], "support": { "issues": "https://github.com/mockery/mockery/issues", - "source": "https://github.com/mockery/mockery/tree/1.4.3" + "source": "https://github.com/mockery/mockery/tree/1.5.0" }, - "time": "2021-02-24T09:51:49+00:00" + "time": "2022-01-20T13:18:17+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6897,7 +7646,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" }, "funding": [ { @@ -6905,37 +7654,36 @@ "type": "tidelift" } ], - "time": "2020-11-13T09:40:50+00:00" + "time": "2022-03-03T13:19:32+00:00" }, { "name": "nunomaduro/collision", - "version": "v5.4.0", + "version": "v5.11.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "41b7e9999133d5082700d31a1d0977161df8322a" + "reference": "8b610eef8582ccdc05d8f2ab23305e2d37049461" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/41b7e9999133d5082700d31a1d0977161df8322a", - "reference": "41b7e9999133d5082700d31a1d0977161df8322a", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/8b610eef8582ccdc05d8f2ab23305e2d37049461", + "reference": "8b610eef8582ccdc05d8f2ab23305e2d37049461", "shasum": "" }, "require": { "facade/ignition-contracts": "^1.0", - "filp/whoops": "^2.7.2", + "filp/whoops": "^2.14.3", "php": "^7.3 || ^8.0", "symfony/console": "^5.0" }, "require-dev": { "brianium/paratest": "^6.1", "fideloper/proxy": "^4.4.1", - "friendsofphp/php-cs-fixer": "^2.17.3", "fruitcake/laravel-cors": "^2.0.3", - "laravel/framework": "^9.0", + "laravel/framework": "8.x-dev", "nunomaduro/larastan": "^0.6.2", "nunomaduro/mock-final-classes": "^1.0", - "orchestra/testbench": "^7.0", + "orchestra/testbench": "^6.0", "phpstan/phpstan": "^0.12.64", "phpunit/phpunit": "^9.5.0" }, @@ -6981,7 +7729,7 @@ }, "funding": [ { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", + "url": "https://www.paypal.com/paypalme/enunomaduro", "type": "custom" }, { @@ -6993,20 +7741,20 @@ "type": "patreon" } ], - "time": "2021-04-09T13:38:32+00:00" + "time": "2022-01-10T16:22:52+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { @@ -7051,22 +7799,22 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/master" + "source": "https://github.com/phar-io/manifest/tree/2.0.3" }, - "time": "2020-06-27T14:33:11+00:00" + "time": "2021-07-20T11:28:43+00:00" }, { "name": "phar-io/version", - "version": "3.1.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "bae7c545bef187884426f042434e561ab1ddb182" + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", - "reference": "bae7c545bef187884426f042434e561ab1ddb182", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { @@ -7102,9 +7850,9 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.1.0" + "source": "https://github.com/phar-io/version/tree/3.2.1" }, - "time": "2021-02-23T14:00:09+00:00" + "time": "2022-02-21T01:04:05+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -7161,16 +7909,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", "shasum": "" }, "require": { @@ -7181,7 +7929,8 @@ "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2" + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -7211,22 +7960,22 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" }, - "time": "2020-09-03T19:13:55+00:00" + "time": "2021-10-19T17:43:47+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.4.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", "shasum": "" }, "require": { @@ -7234,7 +7983,8 @@ "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "*" + "ext-tokenizer": "*", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -7260,39 +8010,39 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" }, - "time": "2020-09-17T18:55:26+00:00" + "time": "2022-01-04T19:58:01+00:00" }, { "name": "phpspec/prophecy", - "version": "1.13.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", + "php": "^7.2 || ~8.0, <8.2", "phpdocumentor/reflection-docblock": "^5.2", "sebastian/comparator": "^3.0 || ^4.0", "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^6.0", + "phpspec/phpspec": "^6.0 || ^7.0", "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -7327,29 +8077,29 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.13.0" + "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" }, - "time": "2021-03-17T13:42:18+00:00" + "time": "2021-12-08T12:19:24+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.6", + "version": "9.2.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f6293e1b30a2354e8428e004689671b83871edde" + "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", - "reference": "f6293e1b30a2354e8428e004689671b83871edde", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f", + "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", + "nikic/php-parser": "^4.13.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -7398,7 +8148,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15" }, "funding": [ { @@ -7406,20 +8156,20 @@ "type": "github" } ], - "time": "2021-03-28T07:26:59+00:00" + "time": "2022-03-07T09:28:20+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.5", + "version": "3.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { @@ -7458,7 +8208,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" }, "funding": [ { @@ -7466,7 +8216,7 @@ "type": "github" } ], - "time": "2020-09-28T05:57:25+00:00" + "time": "2021-12-02T12:48:52+00:00" }, { "name": "phpunit/php-invoker", @@ -7651,16 +8401,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.5", + "version": "9.5.17", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276" + "reference": "5c5abcfaa2cbd44b2203995d7a339ef910fe0c8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/89ff45ea9d70e35522fb6654a2ebc221158de276", - "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5c5abcfaa2cbd44b2203995d7a339ef910fe0c8f", + "reference": "5c5abcfaa2cbd44b2203995d7a339ef910fe0c8f", "shasum": "" }, "require": { @@ -7672,11 +8422,11 @@ "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", + "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-code-coverage": "^9.2.13", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -7690,7 +8440,7 @@ "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3.2", + "sebastian/type": "^2.3.4", "sebastian/version": "^3.0.2" }, "require-dev": { @@ -7711,11 +8461,11 @@ } }, "autoload": { - "classmap": [ - "src/" - ], "files": [ "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -7738,11 +8488,11 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.5" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.17" }, "funding": [ { - "url": "https://phpunit.de/donate.html", + "url": "https://phpunit.de/sponsors.html", "type": "custom" }, { @@ -7750,7 +8500,7 @@ "type": "github" } ], - "time": "2021-06-05T04:49:07+00:00" + "time": "2022-03-05T16:54:31+00:00" }, { "name": "sebastian/cli-parser", @@ -8181,16 +8931,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", "shasum": "" }, "require": { @@ -8239,14 +8989,14 @@ } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" }, "funding": [ { @@ -8254,20 +9004,20 @@ "type": "github" } ], - "time": "2020-09-28T05:24:23+00:00" + "time": "2021-11-11T14:18:36+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.3", + "version": "5.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", "shasum": "" }, "require": { @@ -8310,7 +9060,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" }, "funding": [ { @@ -8318,7 +9068,7 @@ "type": "github" } ], - "time": "2021-06-11T13:31:12+00:00" + "time": "2022-02-14T08:28:10+00:00" }, { "name": "sebastian/lines-of-code", @@ -8605,7 +9355,6 @@ "type": "github" } ], - "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { @@ -8719,16 +9468,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, "require": { @@ -8757,7 +9506,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/master" + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" }, "funding": [ { @@ -8765,7 +9514,7 @@ "type": "github" } ], - "time": "2020-07-12T23:59:07+00:00" + "time": "2021-07-28T10:34:58+00:00" } ], "aliases": [], @@ -8777,5 +9526,5 @@ "php": "^7.3|^8.0" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } diff --git a/config/app.php b/config/app.php index f572b646..f9034603 100644 --- a/config/app.php +++ b/config/app.php @@ -56,6 +56,8 @@ 'asset_url' => env('ASSET_URL', null), + 'site_url' => env('SITE_URL', null), + /* |-------------------------------------------------------------------------- | Application Timezone diff --git a/config/filesystems.php b/config/filesystems.php index 760ef972..ccbcd162 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -67,7 +67,7 @@ */ 'links' => [ - public_path('storage') => storage_path('app/public'), + public_path('storage') => storage_path('app'), ], ]; diff --git a/config/services.php b/config/services.php index 82e693d8..32caeffd 100644 --- a/config/services.php +++ b/config/services.php @@ -35,4 +35,13 @@ 'client_id' => env('HELLOSIGN_CLIENT_ID'), ], + 'shufti' => [ + 'client_id' => env('SHUFTI_CLIENT_ID'), + 'client_secret' => env('SHUFTI_CLIENT_SECRET'), + ], + + 'token_price' => [ + 'api_key' => env('COINMARKETCAP_KEY') + ] + ]; diff --git a/database/migrations/2021_06_18_142447_add_data_admin_user.php b/database/migrations/2021_06_18_142447_add_data_admin_user.php index 9709da6a..5286b210 100644 --- a/database/migrations/2021_06_18_142447_add_data_admin_user.php +++ b/database/migrations/2021_06_18_142447_add_data_admin_user.php @@ -5,6 +5,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\Log; class AddDataAdminUser extends Migration { @@ -21,7 +22,12 @@ public function up() $user->first_name = 'Ledger'; $user->last_name = 'Leap'; $user->email = 'ledgerleapllc@gmail.com'; - $user->password = Hash::make('ledgerleapllc'); + $random_password = Str::random(10); + $user->password = Hash::make($random_password); + Log::info('Created admin'); + Log::info('Email: '.$user->email); + Log::info('Password: '.$random_password); + Log::info(''); $user->email_verified_at = now(); $user->type = 'active'; $user->role = 'admin'; diff --git a/database/migrations/2021_06_28_164930_create_discussions_table.php b/database/migrations/2021_06_28_164930_create_discussions_table.php new file mode 100644 index 00000000..2d0ab188 --- /dev/null +++ b/database/migrations/2021_06_28_164930_create_discussions_table.php @@ -0,0 +1,38 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateDiscussionsTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('discussions', function (Blueprint $table) { + $table->id(); + $table->text('title'); + $table->longText('description'); + $table->bigInteger('user_id'); + $table->integer('comments')->default(0); + $table->integer('likes')->default(0); + $table->integer('dislikes')->default(0); + $table->integer('read')->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('discussions'); + } +} diff --git a/database/migrations/2021_06_28_165638_create_discussion_comments_table.php b/database/migrations/2021_06_28_165638_create_discussion_comments_table.php new file mode 100644 index 00000000..6436feae --- /dev/null +++ b/database/migrations/2021_06_28_165638_create_discussion_comments_table.php @@ -0,0 +1,34 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateDiscussionCommentsTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('discussion_comments', function (Blueprint $table) { + $table->id(); + $table->bigInteger('discussion_id'); + $table->bigInteger('user_id'); + $table->longText('description'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('discussion_comments'); + } +} diff --git a/database/migrations/2021_06_28_165938_create_discussion_votes_table.php b/database/migrations/2021_06_28_165938_create_discussion_votes_table.php new file mode 100644 index 00000000..0f25c4c6 --- /dev/null +++ b/database/migrations/2021_06_28_165938_create_discussion_votes_table.php @@ -0,0 +1,34 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateDiscussionVotesTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('discussion_votes', function (Blueprint $table) { + $table->id(); + $table->bigInteger('user_id'); + $table->bigInteger('discussion_id'); + $table->boolean('is_like'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('discussion_votes'); + } +} diff --git a/database/migrations/2021_06_28_170158_create_discussion_pins_table.php b/database/migrations/2021_06_28_170158_create_discussion_pins_table.php new file mode 100644 index 00000000..85981752 --- /dev/null +++ b/database/migrations/2021_06_28_170158_create_discussion_pins_table.php @@ -0,0 +1,33 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateDiscussionPinsTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('discussion_pins', function (Blueprint $table) { + $table->id(); + $table->bigInteger('user_id'); + $table->bigInteger('discussion_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('discussion_pins'); + } +} diff --git a/database/migrations/2021_06_29_131855_create_table_ballot.php b/database/migrations/2021_06_29_131855_create_table_ballot.php new file mode 100644 index 00000000..357f08eb --- /dev/null +++ b/database/migrations/2021_06_29_131855_create_table_ballot.php @@ -0,0 +1,38 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateTableBallot extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('ballot', function (Blueprint $table) { + $table->id(); + $table->foreignId('user_id')->constrained('users'); + $table->string('title'); + $table->text('description')->nullable(); + $table->integer('time')->nullable(); + $table->string('time_unit')->nullable(); + $table->timestamp('time_end')->nullable(); + $table->string('status')->default('active'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('ballot'); + } +} diff --git a/database/migrations/2021_06_29_133103_create_table_vote.php b/database/migrations/2021_06_29_133103_create_table_vote.php new file mode 100644 index 00000000..0c0cc674 --- /dev/null +++ b/database/migrations/2021_06_29_133103_create_table_vote.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateTableVote extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('vote', function (Blueprint $table) { + $table->id(); + $table->foreignId('ballot_id')->constrained('ballot'); + $table->integer('for_value')->default(0); + $table->integer('against_value')->default(0); + $table->integer('result_count')->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('vote'); + } +} diff --git a/database/migrations/2021_06_29_133255_create_vote_result_table.php b/database/migrations/2021_06_29_133255_create_vote_result_table.php new file mode 100644 index 00000000..39fdbe67 --- /dev/null +++ b/database/migrations/2021_06_29_133255_create_vote_result_table.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateVoteResultTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('vote_result', function (Blueprint $table) { + $table->id(); + $table->foreignId('ballot_id')->constrained('ballot'); + $table->foreignId('vote_id')->constrained('vote'); + $table->foreignId('user_id')->constrained('users'); + $table->enum('type', ['for', 'against'])->default('for'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('vote_result'); + } +} diff --git a/database/migrations/2021_06_29_160047_create_ballot_file_table.php b/database/migrations/2021_06_29_160047_create_ballot_file_table.php new file mode 100644 index 00000000..3b95187e --- /dev/null +++ b/database/migrations/2021_06_29_160047_create_ballot_file_table.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateBallotFileTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('ballot_file', function (Blueprint $table) { + $table->id(); + $table->foreignId('ballot_id')->constrained('ballot'); + $table->string('name')->nullable(); + $table->string('path')->nullable(); + $table->string('url')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('ballot_file'); + } +} diff --git a/database/migrations/2021_06_30_082242_create_setting_table.php b/database/migrations/2021_06_30_082242_create_setting_table.php new file mode 100644 index 00000000..5db14473 --- /dev/null +++ b/database/migrations/2021_06_30_082242_create_setting_table.php @@ -0,0 +1,33 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateSettingTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('settings', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('value'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('settings'); + } +} diff --git a/database/migrations/2021_06_30_161849_create_discussion_remove_news_table.php b/database/migrations/2021_06_30_161849_create_discussion_remove_news_table.php new file mode 100644 index 00000000..91f81419 --- /dev/null +++ b/database/migrations/2021_06_30_161849_create_discussion_remove_news_table.php @@ -0,0 +1,33 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateDiscussionRemoveNewsTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('discussion_remove_news', function (Blueprint $table) { + $table->id(); + $table->bigInteger('user_id'); + $table->bigInteger('discussion_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('discussion_remove_news'); + } +} diff --git a/database/migrations/2021_07_02_205525_update_user2_table.php b/database/migrations/2021_07_02_205525_update_user2_table.php new file mode 100644 index 00000000..36929236 --- /dev/null +++ b/database/migrations/2021_07_02_205525_update_user2_table.php @@ -0,0 +1,32 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser2Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function (Blueprint $table) { + $table->string('invite_link')->nullable(); + $table->string('reset_link')->nullable(); + $table->string('permissions')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_08_151020_update_user3_table.php b/database/migrations/2021_07_08_151020_update_user3_table.php new file mode 100644 index 00000000..deb33b9e --- /dev/null +++ b/database/migrations/2021_07_08_151020_update_user3_table.php @@ -0,0 +1,31 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser3Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function ($table) { + $table->timestamp('letter_verified_at')->nullable(); + $table->tinyInteger('banned')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_09_151020_update_profile1_table.php b/database/migrations/2021_07_09_151020_update_profile1_table.php new file mode 100644 index 00000000..98ada2e2 --- /dev/null +++ b/database/migrations/2021_07_09_151020_update_profile1_table.php @@ -0,0 +1,45 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\DB; + +class UpdateProfile1Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('profile', function ($table) { + $table->string('entity_name')->nullable(); + $table->string('entity_type')->nullable(); + $table->string('entity_registration_number')->nullable(); + $table->string('entity_registration_country')->nullable(); + $table->string('vat_number')->nullable(); + $table->string('page_is_representative')->nullable(); + }); + + DB::statement("ALTER TABLE profile modify first_name varchar(255) NULL"); + DB::statement("ALTER TABLE profile modify last_name varchar(255) NULL"); + DB::statement("ALTER TABLE profile modify country_citizenship varchar(255) NULL"); + DB::statement("ALTER TABLE profile modify country_residence varchar(255) NULL"); + DB::statement("ALTER TABLE profile modify address varchar(255) NULL"); + DB::statement("ALTER TABLE profile modify city varchar(255) NULL"); + DB::statement("ALTER TABLE profile modify zip varchar(255) NULL"); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_09_160047_create_document_file_table.php b/database/migrations/2021_07_09_160047_create_document_file_table.php new file mode 100644 index 00000000..066a03a7 --- /dev/null +++ b/database/migrations/2021_07_09_160047_create_document_file_table.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateDocumentFileTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('document_file', function (Blueprint $table) { + $table->id(); + $table->foreignId('user_id')->constrained('users'); + $table->string('name')->nullable(); + $table->string('path')->nullable(); + $table->string('url')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('document_file'); + } +} diff --git a/database/migrations/2021_07_10_151020_update_profile2_table.php b/database/migrations/2021_07_10_151020_update_profile2_table.php new file mode 100644 index 00000000..67e66e61 --- /dev/null +++ b/database/migrations/2021_07_10_151020_update_profile2_table.php @@ -0,0 +1,29 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\DB; + +class UpdateProfile2Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + DB::statement("ALTER TABLE profile modify status varchar(255) NULL"); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_10_151020_update_users_type_table.php b/database/migrations/2021_07_10_151020_update_users_type_table.php new file mode 100644 index 00000000..aef93c80 --- /dev/null +++ b/database/migrations/2021_07_10_151020_update_users_type_table.php @@ -0,0 +1,31 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\DB; + +class UpdateUsersTypeTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + DB::statement("update users set type = 'individual' where type = 'Individual'"); + DB::statement("update users set type = 'entity' where type = 'Entity'"); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_11_023901_update_profile3_table.php b/database/migrations/2021_07_11_023901_update_profile3_table.php new file mode 100644 index 00000000..12f558de --- /dev/null +++ b/database/migrations/2021_07_11_023901_update_profile3_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateProfile3Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('profile', function ($table) { + $table->timestamp('document_verified_at')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_12_160944_update_user4_table.php b/database/migrations/2021_07_12_160944_update_user4_table.php new file mode 100644 index 00000000..c3e4f239 --- /dev/null +++ b/database/migrations/2021_07_12_160944_update_user4_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser4Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function ($table) { + $table->timestamp('letter_rejected_at')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_14_170709_create_emailer_admin_table.php b/database/migrations/2021_07_14_170709_create_emailer_admin_table.php new file mode 100644 index 00000000..107659f8 --- /dev/null +++ b/database/migrations/2021_07_14_170709_create_emailer_admin_table.php @@ -0,0 +1,32 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateEmailerAdminTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('emailer_admin', function (Blueprint $table) { + $table->id(); + $table->string('email'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('emailer_admin'); + } +} diff --git a/database/migrations/2021_07_14_182755_create_emailer_trigger_admin_table.php b/database/migrations/2021_07_14_182755_create_emailer_trigger_admin_table.php new file mode 100644 index 00000000..3cb08ab2 --- /dev/null +++ b/database/migrations/2021_07_14_182755_create_emailer_trigger_admin_table.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateEmailerTriggerAdminTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('emailer_trigger_admin', function (Blueprint $table) { + $table->id(); + $table->string('title'); + $table->text('content'); + $table->boolean('enabled')->default(false); + $table->string('subject')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('emailer_trigger_admin'); + } +} diff --git a/database/migrations/2021_07_14_182807_create_emailer_trigger_user_table.php b/database/migrations/2021_07_14_182807_create_emailer_trigger_user_table.php new file mode 100644 index 00000000..c9d0658a --- /dev/null +++ b/database/migrations/2021_07_14_182807_create_emailer_trigger_user_table.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateEmailerTriggerUserTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('emailer_trigger_user', function (Blueprint $table) { + $table->id(); + $table->string('title'); + $table->text('content'); + $table->boolean('enabled')->default(false); + $table->string('subject')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('emailer_trigger_user'); + } +} diff --git a/database/migrations/2021_07_16_062506_update_user5_table.php b/database/migrations/2021_07_16_062506_update_user5_table.php new file mode 100644 index 00000000..58fc4f2c --- /dev/null +++ b/database/migrations/2021_07_16_062506_update_user5_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser5Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function ($table) { + $table->string('avatar')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_18_062506_update_user6_table.php b/database/migrations/2021_07_18_062506_update_user6_table.php new file mode 100644 index 00000000..21898a20 --- /dev/null +++ b/database/migrations/2021_07_18_062506_update_user6_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser6Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function ($table) { + $table->timestamp('approve_at')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_19_081841_update_user7_table.php b/database/migrations/2021_07_19_081841_update_user7_table.php new file mode 100644 index 00000000..13cf6416 --- /dev/null +++ b/database/migrations/2021_07_19_081841_update_user7_table.php @@ -0,0 +1,33 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser7Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function ($table) { + $table->integer('average_peers')->nullable()->default(0); + $table->float('validator_fee')->nullable()->default(0); + $table->integer('cspr_delegated')->nullable()->default(0); + $table->integer('cspr_self_staked')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_22_123548_update_user9_table.php b/database/migrations/2021_07_22_123548_update_user9_table.php new file mode 100644 index 00000000..88cb153b --- /dev/null +++ b/database/migrations/2021_07_22_123548_update_user9_table.php @@ -0,0 +1,33 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser9Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function ($table) { + $table->string('new_email')->nullable(); + $table->string('username')->nullable(); + $table->tinyInteger('twoFA_login')->nullable()->default(0); + $table->tinyInteger('twoFA_login_active')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_07_22_162808_create_metric_table.php b/database/migrations/2021_07_22_162808_create_metric_table.php new file mode 100644 index 00000000..fa092d49 --- /dev/null +++ b/database/migrations/2021_07_22_162808_create_metric_table.php @@ -0,0 +1,36 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateMetricTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('metric', function (Blueprint $table) { + $table->id(); + $table->foreignId('user_id')->constrained('users'); + $table->float('uptime')->nullable(); + $table->integer('block_height_average')->nullable(); + $table->float('update_responsiveness')->nullable(); + $table->float('peers')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('metric'); + } +} diff --git a/database/migrations/2021_07_23_123615_create_perk_table.php b/database/migrations/2021_07_23_123615_create_perk_table.php new file mode 100644 index 00000000..040bca19 --- /dev/null +++ b/database/migrations/2021_07_23_123615_create_perk_table.php @@ -0,0 +1,43 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreatePerkTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('perk', function (Blueprint $table) { + $table->id(); + $table->foreignId('user_id')->constrained('users'); + $table->string('title'); + $table->text('content')->nullable(); + $table->string('action_link')->nullable(); + $table->string('image')->nullable(); + $table->date('start_date')->nullable(); + $table->date('end_date')->nullable(); + $table->string('status')->nullable(); + $table->string('visibility')->nullable(); + $table->tinyInteger('setting')->nullable()->default(0); + $table->integer('total_views')->nullable()->default(0); + $table->integer('total_clicks')->nullable()->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('perk'); + } +} diff --git a/database/migrations/2021_07_24_131933_create_perk_result_table.php b/database/migrations/2021_07_24_131933_create_perk_result_table.php new file mode 100644 index 00000000..b4f7d206 --- /dev/null +++ b/database/migrations/2021_07_24_131933_create_perk_result_table.php @@ -0,0 +1,34 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreatePerkResultTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('perk_result', function (Blueprint $table) { + $table->id(); + $table->foreignId('user_id')->constrained('users'); + $table->foreignId('perk_id')->constrained('perk'); + $table->integer('views')->nullable()->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('perk_result'); + } +} diff --git a/database/migrations/2021_07_24_162808_create_monitoring_criteria_table.php b/database/migrations/2021_07_24_162808_create_monitoring_criteria_table.php new file mode 100644 index 00000000..618fc866 --- /dev/null +++ b/database/migrations/2021_07_24_162808_create_monitoring_criteria_table.php @@ -0,0 +1,48 @@ +<?php + +use App\Models\MonitoringCriteria; +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Schema; + +class CreateMonitoringCriteriaTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('monitoring_criteria', function (Blueprint $table) { + $table->id(); + $table->string('type')->nullable(); + $table->string('warning_level')->nullable(); + $table->string('probation_start')->nullable(); + $table->string('frame_calculate_unit')->nullable(); + $table->string('frame_calculate_value')->nullable(); + $table->string('given_to_correct_unit')->nullable(); + $table->string('given_to_correct_value')->nullable(); + $table->string('system_check_unit')->nullable(); + $table->string('system_check_value')->nullable(); + $table->timestamps(); + }); + $uptime = ['type'=>'uptime']; + DB::table('monitoring_criteria')->insert($uptime); + $blockHeight = ['type'=>'block-height']; + DB::table('monitoring_criteria')->insert($blockHeight); + $updateResponsiveness = ['type'=>'update-responsiveness']; + DB::table('monitoring_criteria')->insert($updateResponsiveness); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('monitoring_criteria'); + } +} diff --git a/database/migrations/2021_07_27_123615_create_notification_table.php b/database/migrations/2021_07_27_123615_create_notification_table.php new file mode 100644 index 00000000..a780848d --- /dev/null +++ b/database/migrations/2021_07_27_123615_create_notification_table.php @@ -0,0 +1,46 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateNotificationTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('notification', function (Blueprint $table) { + $table->id(); + $table->string('type'); + $table->string('title'); + $table->text('body')->nullable(); + $table->tinyInteger('show_login')->nullable()->default(0); + $table->tinyInteger('allow_dismiss_btn')->nullable()->default(0); + $table->tinyInteger('high_priority')->nullable()->default(0); + $table->tinyInteger('have_action')->nullable()->default(0); + $table->string('action_link')->nullable(); + $table->string('btn_text')->nullable(); + $table->date('start_date')->nullable(); + $table->date('end_date')->nullable(); + $table->tinyInteger('setting')->nullable()->default(0); + $table->integer('total_views')->nullable()->default(0); + $table->string('status')->nullable(); + $table->string('visibility')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('perk'); + } +} diff --git a/database/migrations/2021_07_27_143215_create_notification_view_table.php b/database/migrations/2021_07_27_143215_create_notification_view_table.php new file mode 100644 index 00000000..a6a6c6c1 --- /dev/null +++ b/database/migrations/2021_07_27_143215_create_notification_view_table.php @@ -0,0 +1,37 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateNotificationViewTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('notification_view', function (Blueprint $table) { + $table->id(); + $table->foreignId('user_id')->constrained('users'); + $table->foreignId('notification_id')->constrained('notification'); + $table->date('first_view_at')->nullable(); + $table->date('dismissed_at')->nullable(); + $table->date('cta_click_at')->nullable(); + $table->integer('cta_click_count')->nullable()->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('perk'); + } +} diff --git a/database/migrations/2021_07_31_071536_create_ip_history_table.php b/database/migrations/2021_07_31_071536_create_ip_history_table.php new file mode 100644 index 00000000..85669712 --- /dev/null +++ b/database/migrations/2021_07_31_071536_create_ip_history_table.php @@ -0,0 +1,33 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateIpHistoryTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('ip_history', function (Blueprint $table) { + $table->id(); + $table->integer('user_id'); + $table->string('ip_address'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('ip_history'); + } +} diff --git a/database/migrations/2021_07_31_071929_create_permission_table.php b/database/migrations/2021_07_31_071929_create_permission_table.php new file mode 100644 index 00000000..ca3ecdb9 --- /dev/null +++ b/database/migrations/2021_07_31_071929_create_permission_table.php @@ -0,0 +1,34 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreatePermissionTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('permission', function (Blueprint $table) { + $table->id(); + $table->integer('user_id'); + $table->string('name'); + $table->tinyInteger('is_permission')->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('permission'); + } +} diff --git a/database/migrations/2021_07_31_080637_update_user10_table.php b/database/migrations/2021_07_31_080637_update_user10_table.php new file mode 100644 index 00000000..ac6f0c4b --- /dev/null +++ b/database/migrations/2021_07_31_080637_update_user10_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser10Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function (Blueprint $table) { + $table->string('last_login_ip_address')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_08_10_125003_update_user11table.php b/database/migrations/2021_08_10_125003_update_user11table.php new file mode 100644 index 00000000..5ce613e3 --- /dev/null +++ b/database/migrations/2021_08_10_125003_update_user11table.php @@ -0,0 +1,32 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser11table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function (Blueprint $table) { + $table->string('node_status')->nullable(); + $table->bigInteger('cspr_delegated')->change(); + $table->bigInteger('cspr_self_staked')->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_08_10_125626_update_metric_table.php b/database/migrations/2021_08_10_125626_update_metric_table.php new file mode 100644 index 00000000..645915a0 --- /dev/null +++ b/database/migrations/2021_08_10_125626_update_metric_table.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateMetricTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('metric', function ($table) { + $table->timestamp('uptime_time_start')->nullable(); + $table->timestamp('block_height_average_time_start')->nullable(); + $table->timestamp('update_responsiveness_time_start')->nullable(); + $table->timestamp('uptime_time_end')->nullable(); + $table->timestamp('block_height_average_time_end')->nullable(); + $table->timestamp('update_responsiveness_time_end')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_08_11_081808_update_user12_table.php b/database/migrations/2021_08_11_081808_update_user12_table.php new file mode 100644 index 00000000..c96d415f --- /dev/null +++ b/database/migrations/2021_08_11_081808_update_user12_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser12Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function (Blueprint $table) { + $table->tinyInteger('is_fail_node')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_08_11_162808_create_lock_rules_table.php b/database/migrations/2021_08_11_162808_create_lock_rules_table.php new file mode 100644 index 00000000..66d8b0ae --- /dev/null +++ b/database/migrations/2021_08_11_162808_create_lock_rules_table.php @@ -0,0 +1,49 @@ +<?php + +use App\Models\MonitoringCriteria; +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Schema; + +class CreateLockRulesTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('lock_rules', function (Blueprint $table) { + $table->id(); + $table->string('type')->nullable(); + $table->string('screen')->nullable(); + $table->boolean('is_lock')->nullable(); + $table->timestamps(); + }); + + $arr = [['type'=>'kyc_not_verify', 'screen' => 'nodes', 'is_lock' => false, 'created_at' => now()], + ['type'=>'kyc_not_verify', 'screen' => 'discussions', 'is_lock' => false, 'created_at' => now()], + ['type'=>'kyc_not_verify', 'screen' => 'votes', 'is_lock' => false, 'created_at' => now()], + ['type'=>'kyc_not_verify', 'screen' => 'perks', 'is_lock' => false, 'created_at' => now()], + ['type'=>'status_is_poor', 'screen' => 'nodes', 'is_lock' => false, 'created_at' => now()], + ['type'=>'status_is_poor', 'screen' => 'discussions', 'is_lock' => false, 'created_at' => now()], + ['type'=>'status_is_poor', 'screen' => 'votes', 'is_lock' => false, 'created_at' => now()], + ['type'=>'status_is_poor', 'screen' => 'perks', 'is_lock' => false, 'created_at' => now()]]; + + foreach ($arr as $item) { + DB::table('lock_rules')->insert($item); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('lock_rules'); + } +} diff --git a/database/migrations/2021_08_12_154417_update_node_status.php b/database/migrations/2021_08_12_154417_update_node_status.php new file mode 100644 index 00000000..5dbeb23e --- /dev/null +++ b/database/migrations/2021_08_12_154417_update_node_status.php @@ -0,0 +1,33 @@ +<?php + +use App\Models\User; +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodeStatus extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + $users = User::where('node_status', 'Ok')->get(); + foreach($users as $user) { + $user->node_status = 'Online'; + $user->save(); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_08_14_214333_create_token_price_table.php b/database/migrations/2021_08_14_214333_create_token_price_table.php new file mode 100644 index 00000000..bccf3c84 --- /dev/null +++ b/database/migrations/2021_08_14_214333_create_token_price_table.php @@ -0,0 +1,32 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateTokenPriceTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('token_price', function (Blueprint $table) { + $table->id(); + $table->double('price', 8, 2); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('token_price'); + } +} diff --git a/database/migrations/2021_08_17_161014_create_nodes_table.php b/database/migrations/2021_08_17_161014_create_nodes_table.php new file mode 100644 index 00000000..3ec70f52 --- /dev/null +++ b/database/migrations/2021_08_17_161014_create_nodes_table.php @@ -0,0 +1,41 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateNodesTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('nodes', function (Blueprint $table) { + $table->id(); + $table->string('node_address'); + $table->float('uptime')->nullable(); + $table->integer('block_height')->nullable(); + $table->float('update_responsiveness')->nullable(); + $table->integer('peers')->nullable(); + $table->string('block_hash')->nullable(); + $table->string('decoded_peers')->nullable(); + $table->integer('era_id')->nullable(); + $table->string('activation_point')->nullable(); + $table->string('protocol_version')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('nodes'); + } +} diff --git a/database/migrations/2021_08_18_075843_create_node_info.php b/database/migrations/2021_08_18_075843_create_node_info.php new file mode 100644 index 00000000..8da7dabd --- /dev/null +++ b/database/migrations/2021_08_18_075843_create_node_info.php @@ -0,0 +1,41 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateNodeInfo extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('node_info', function (Blueprint $table) { + $table->id(); + $table->string('node_address'); + $table->float('uptime')->nullable(); + $table->integer('block_height_average')->nullable(); + $table->float('update_responsiveness')->nullable(); + $table->integer('peers')->nullable(); + $table->integer('block_height')->nullable(); + $table->integer('delegators_count')->nullable(); + $table->float('delegation_rate')->nullable(); + $table->bigInteger('self_staked_amount')->nullable(); + $table->bigInteger('total_staked_amount')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('node_info'); + } +} diff --git a/database/migrations/2021_08_18_080141_create_key_peers_table.php b/database/migrations/2021_08_18_080141_create_key_peers_table.php new file mode 100644 index 00000000..91a8cf06 --- /dev/null +++ b/database/migrations/2021_08_18_080141_create_key_peers_table.php @@ -0,0 +1,33 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateKeyPeersTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('key_peers', function (Blueprint $table) { + $table->id(); + $table->string('ip'); + $table->string('public_key'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('key_peers'); + } +} diff --git a/database/migrations/2021_08_20_024328_create_ballot_file_view.php b/database/migrations/2021_08_20_024328_create_ballot_file_view.php new file mode 100644 index 00000000..5aff29f9 --- /dev/null +++ b/database/migrations/2021_08_20_024328_create_ballot_file_view.php @@ -0,0 +1,34 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateBallotFileView extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('ballot_file_view', function (Blueprint $table) { + $table->id(); + $table->integer('ballot_file_id'); + $table->integer('ballot_id'); + $table->integer('user_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('ballot_file_view'); + } +} diff --git a/database/migrations/2021_08_24_091001_update_user14_table.php b/database/migrations/2021_08_24_091001_update_user14_table.php new file mode 100644 index 00000000..38be26ba --- /dev/null +++ b/database/migrations/2021_08_24_091001_update_user14_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser14Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function (Blueprint $table) { + $table->integer('rank')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_08_25_140218_update_node_table.php b/database/migrations/2021_08_25_140218_update_node_table.php new file mode 100644 index 00000000..102affba --- /dev/null +++ b/database/migrations/2021_08_25_140218_update_node_table.php @@ -0,0 +1,31 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodeTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('nodes', function (Blueprint $table) { + $table->float('weight', 30, 2)->nullable(); + $table->timestamp('timestamp')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_09_10_140824_update_discusstion_table.php b/database/migrations/2021_09_10_140824_update_discusstion_table.php new file mode 100644 index 00000000..159f5482 --- /dev/null +++ b/database/migrations/2021_09_10_140824_update_discusstion_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateDiscusstionTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('discussions', function (Blueprint $table) { + $table->tinyInteger('is_draft')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_09_16_155430_update_node_info_table.php b/database/migrations/2021_09_16_155430_update_node_info_table.php new file mode 100644 index 00000000..c67eb967 --- /dev/null +++ b/database/migrations/2021_09_16_155430_update_node_info_table.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodeInfoTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('node_info', function ($table) { + $table->timestamp('uptime_time_start')->nullable(); + $table->timestamp('block_height_average_time_start')->nullable(); + $table->timestamp('update_responsiveness_time_start')->nullable(); + $table->timestamp('uptime_time_end')->nullable(); + $table->timestamp('block_height_average_time_end')->nullable(); + $table->timestamp('update_responsiveness_time_end')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_09_30_075649_create_contact_us_table.php b/database/migrations/2021_09_30_075649_create_contact_us_table.php new file mode 100644 index 00000000..17eb0188 --- /dev/null +++ b/database/migrations/2021_09_30_075649_create_contact_us_table.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateContactUsTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('contact_us', function (Blueprint $table) { + $table->id(); + $table->integer('user_id'); + $table->string('name'); + $table->string('email'); + $table->text('message'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('contact_us'); + } +} diff --git a/database/migrations/2021_09_30_080443_create_contact_recipient_table.php b/database/migrations/2021_09_30_080443_create_contact_recipient_table.php new file mode 100644 index 00000000..c48f94dd --- /dev/null +++ b/database/migrations/2021_09_30_080443_create_contact_recipient_table.php @@ -0,0 +1,32 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateContactRecipientTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('contact_recipient', function (Blueprint $table) { + $table->id(); + $table->string('email'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('contact_recipient'); + } +} diff --git a/database/migrations/2021_09_30_135247_update_user16_table.php b/database/migrations/2021_09_30_135247_update_user16_table.php new file mode 100644 index 00000000..c31169c7 --- /dev/null +++ b/database/migrations/2021_09_30_135247_update_user16_table.php @@ -0,0 +1,31 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser16Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + + Schema::table('users', function (Blueprint $table) { + $table->tinyInteger('membership_agreement')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_09_30_140056_create_membership_agreement_file_table.php b/database/migrations/2021_09_30_140056_create_membership_agreement_file_table.php new file mode 100644 index 00000000..40880cd0 --- /dev/null +++ b/database/migrations/2021_09_30_140056_create_membership_agreement_file_table.php @@ -0,0 +1,34 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateMembershipAgreementFileTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('membership_agreement_file', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('path'); + $table->string('url'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('membership_agreement_file'); + } +} diff --git a/database/migrations/2021_10_05_093429_update_user17_table.php b/database/migrations/2021_10_05_093429_update_user17_table.php new file mode 100644 index 00000000..bdc3c0fd --- /dev/null +++ b/database/migrations/2021_10_05_093429_update_user17_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser17Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function (Blueprint $table) { + $table->tinyInteger('reset_kyc')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_10_05_152720_update_node_info3_table.php b/database/migrations/2021_10_05_152720_update_node_info3_table.php new file mode 100644 index 00000000..1a605306 --- /dev/null +++ b/database/migrations/2021_10_05_152720_update_node_info3_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodeInfo3Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('node_info', function ($table) { + $table->float('daily_earning')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_10_05_153722_update_node_info4_table.php b/database/migrations/2021_10_05_153722_update_node_info4_table.php new file mode 100644 index 00000000..0adb0c1e --- /dev/null +++ b/database/migrations/2021_10_05_153722_update_node_info4_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodeInfo4Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('node_info', function ($table) { + $table->float('total_earning')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_10_05_154724_update_node_info5_table.php b/database/migrations/2021_10_05_154724_update_node_info5_table.php new file mode 100644 index 00000000..d54a01ba --- /dev/null +++ b/database/migrations/2021_10_05_154724_update_node_info5_table.php @@ -0,0 +1,31 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodeInfo5Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('node_info', function ($table) { + $table->float('daily_earning', 30, 8)->change(); + $table->float('total_earning', 30, 8)->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_10_11_032821_create_donation_table.php b/database/migrations/2021_10_11_032821_create_donation_table.php new file mode 100644 index 00000000..9894189e --- /dev/null +++ b/database/migrations/2021_10_11_032821_create_donation_table.php @@ -0,0 +1,36 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateDonationTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('donation', function (Blueprint $table) { + $table->id(); + $table->string('first_name'); + $table->string('last_name')->nullable(); + $table->string('email'); + $table->float('amount', 15, 2); + $table->text('message')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('donation'); + } +} diff --git a/database/migrations/2021_10_11_132245_update_node_info7_table.php b/database/migrations/2021_10_11_132245_update_node_info7_table.php new file mode 100644 index 00000000..edd1b078 --- /dev/null +++ b/database/migrations/2021_10_11_132245_update_node_info7_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodeInfo7Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('node_info', function ($table) { + $table->tinyInteger('is_open_port')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_10_13_151407_update_node_info8_table.php b/database/migrations/2021_10_13_151407_update_node_info8_table.php new file mode 100644 index 00000000..7838098a --- /dev/null +++ b/database/migrations/2021_10_13_151407_update_node_info8_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodeInfo8Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('node_info', function ($table) { + $table->integer('mbs')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_10_14_081527_update_contact_us_table.php b/database/migrations/2021_10_14_081527_update_contact_us_table.php new file mode 100644 index 00000000..e6964ff5 --- /dev/null +++ b/database/migrations/2021_10_14_081527_update_contact_us_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateContactUsTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('contact_us', function (Blueprint $table) { + $table->integer('user_id')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_10_15_135631_update_token_price_table.php b/database/migrations/2021_10_15_135631_update_token_price_table.php new file mode 100644 index 00000000..a8346cf3 --- /dev/null +++ b/database/migrations/2021_10_15_135631_update_token_price_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateTokenPriceTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('token_price', function (Blueprint $table) { + $table->float('price', 10, 4)->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_10_31_133016_update_profile_table.php b/database/migrations/2021_10_31_133016_update_profile_table.php new file mode 100644 index 00000000..fa16e218 --- /dev/null +++ b/database/migrations/2021_10_31_133016_update_profile_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateProfileTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('profile', function (Blueprint $table) { + $table->integer('page_number')->default(0)->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_11_12_200412_update_table_ballot.php b/database/migrations/2021_11_12_200412_update_table_ballot.php new file mode 100644 index 00000000..eca3b398 --- /dev/null +++ b/database/migrations/2021_11_12_200412_update_table_ballot.php @@ -0,0 +1,33 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateTableBallot extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('ballot', function (Blueprint $table) { + $table->string('start_date')->nullable(); + $table->string('start_time')->nullable(); + $table->string('end_date')->nullable(); + $table->string('end_time')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_11_14_134555_update_perk_table.php b/database/migrations/2021_11_14_134555_update_perk_table.php new file mode 100644 index 00000000..9553d015 --- /dev/null +++ b/database/migrations/2021_11_14_134555_update_perk_table.php @@ -0,0 +1,31 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdatePerkTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('perk', function (Blueprint $table) { + $table->string('start_time')->nullable(); + $table->string('end_time')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_12_24_014338_update_nodes_table.php b/database/migrations/2021_12_24_014338_update_nodes_table.php new file mode 100644 index 00000000..8a025995 --- /dev/null +++ b/database/migrations/2021_12_24_014338_update_nodes_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodesTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('nodes', function (Blueprint $table) { + $table->boolean('refreshed')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_12_24_014437_update_node_info9_table.php b/database/migrations/2021_12_24_014437_update_node_info9_table.php new file mode 100644 index 00000000..1b45c3e8 --- /dev/null +++ b/database/migrations/2021_12_24_014437_update_node_info9_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateNodeInfo9Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('node_info', function (Blueprint $table) { + $table->boolean('refreshed')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_12_24_014822_update_user18_table.php b/database/migrations/2021_12_24_014822_update_user18_table.php new file mode 100644 index 00000000..09c7c237 --- /dev/null +++ b/database/migrations/2021_12_24_014822_update_user18_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUser18Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function (Blueprint $table) { + $table->boolean('refreshed')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2022_03_02_151335_update_users_19_table.php b/database/migrations/2022_03_02_151335_update_users_19_table.php new file mode 100644 index 00000000..ac575694 --- /dev/null +++ b/database/migrations/2022_03_02_151335_update_users_19_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateUsers19Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('users', function (Blueprint $table) { + $table->boolean('pending_node')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2022_03_16_011737_update_profile4_table.php b/database/migrations/2022_03_16_011737_update_profile4_table.php new file mode 100644 index 00000000..6711d6a2 --- /dev/null +++ b/database/migrations/2022_03_16_011737_update_profile4_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateProfile4Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('profile', function ($table) { + $table->string('extra_status')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2022_04_05_013348_update_donation_table.php b/database/migrations/2022_04_05_013348_update_donation_table.php new file mode 100644 index 00000000..97c61575 --- /dev/null +++ b/database/migrations/2022_04_05_013348_update_donation_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateDonationTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('donation', function ($table) { + $table->string('checkout_session_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2022_04_05_031545_update_donation_2_table.php b/database/migrations/2022_04_05_031545_update_donation_2_table.php new file mode 100644 index 00000000..49a1f688 --- /dev/null +++ b/database/migrations/2022_04_05_031545_update_donation_2_table.php @@ -0,0 +1,30 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdateDonation2Table extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('donation', function ($table) { + $table->string('status')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2022_04_07_195619_account_info_standard.php b/database/migrations/2022_04_07_195619_account_info_standard.php new file mode 100644 index 00000000..15fa957f --- /dev/null +++ b/database/migrations/2022_04_07_195619_account_info_standard.php @@ -0,0 +1,32 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class AccountInfoStandard extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('profile', function ($table) { + $table->string('casper_association_kyc_hash')->nullable(); + $table->string('blockchain_name')->nullable(); + $table->string('blockchain_desc')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/public/logo/casper-logo.png b/public/logo/casper-logo.png new file mode 100644 index 00000000..b326508f Binary files /dev/null and b/public/logo/casper-logo.png differ diff --git a/public/logo/logo.png b/public/logo/logo.png new file mode 100644 index 00000000..ed3961a9 Binary files /dev/null and b/public/logo/logo.png differ diff --git a/public/user-guide.pdf b/public/user-guide.pdf new file mode 100644 index 00000000..c0e31a07 Binary files /dev/null and b/public/user-guide.pdf differ diff --git a/resources/views/emails/admin_alert_email.blade.php b/resources/views/emails/admin_alert_email.blade.php new file mode 100644 index 00000000..0271aae1 --- /dev/null +++ b/resources/views/emails/admin_alert_email.blade.php @@ -0,0 +1,171 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } + + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } + + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">{!! $title !!}</h2> + <div class="divider"></div> + <div id="content-html"> + {!! $content !!} + </div> + <div id="button-link"> + <a class="button-link" href="{{ config('app.site_url') }}"> + Go to Member's Portal + </a> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/resources/views/emails/confirm_email.blade.php b/resources/views/emails/confirm_email.blade.php new file mode 100644 index 00000000..548ffb01 --- /dev/null +++ b/resources/views/emails/confirm_email.blade.php @@ -0,0 +1,175 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } + + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } + + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">{!! $title !!}</h2> + <div class="divider"></div> + <div id="content-html"> + {!! $content !!} + </div> + <div id="button-link"> + <a class="button-link" href="{{ $url }}"> + @if($action =='cancel') + Cancel Change + @else + Confirm Change + @endif + </a> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/resources/views/emails/contact_us.blade.php b/resources/views/emails/contact_us.blade.php new file mode 100644 index 00000000..029d9347 --- /dev/null +++ b/resources/views/emails/contact_us.blade.php @@ -0,0 +1,168 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } + + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } + + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">Contact Us</h2> + <div class="divider"></div> + <div id="content-html"> + <p>Name : {{ $contact->name }}</p> + <p>Email : {{ $contact->email }}</p> + <p>Message : {!! $contact->message !!}</p> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/resources/views/emails/invitation.blade.php b/resources/views/emails/invitation.blade.php new file mode 100644 index 00000000..5a0c322b --- /dev/null +++ b/resources/views/emails/invitation.blade.php @@ -0,0 +1,171 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } + + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } + + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">Admin Privileges Granted</h2> + <div class="divider"></div> + <div id="content-html"> + You have been invited to become an admin of the Casper Association Portal. Click the link and create a password you can use to login. + </div> + <div id="button-link"> + <a class="button-link" href="{{ $url }}"> + Create Password + </a> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/resources/views/emails/kyc_approved.blade.php b/resources/views/emails/kyc_approved.blade.php new file mode 100644 index 00000000..cdfc4b35 --- /dev/null +++ b/resources/views/emails/kyc_approved.blade.php @@ -0,0 +1,171 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } + + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } + + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">Your KYC is approved</h2> + <div class="divider"></div> + <div id="content-html"> + Good news, your KYC in the Casper Association portal was approved. You now have access to all member areas. + </div> + <div id="button-link"> + <a class="button-link" href="{{ config('app.site_url') }}"> + Go to Member's Portal + </a> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/resources/views/emails/kyc_denied.blade.php b/resources/views/emails/kyc_denied.blade.php new file mode 100644 index 00000000..f2d3666b --- /dev/null +++ b/resources/views/emails/kyc_denied.blade.php @@ -0,0 +1,171 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } + + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } + + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">Your KYC is denied</h2> + <div class="divider"></div> + <div id="content-html"> + We're sorry, your KYC in the Casper Association portal was denied. Your admin has been notified and we're looking into the cause. You may need to re-submit your documents. + </div> + <div id="button-link"> + <a class="button-link" href="{{ config('app.site_url') }}"> + Go to Member's Portal + </a> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/resources/views/emails/reset_kyc.blade.php b/resources/views/emails/reset_kyc.blade.php index dc559381..e14a6924 100644 --- a/resources/views/emails/reset_kyc.blade.php +++ b/resources/views/emails/reset_kyc.blade.php @@ -15,7 +15,7 @@ </head> <body class="clean-body" style="margin: 0; padding: 0; -webkit-text-size-adjust: 100%; background-color: #FFFFFF;"> - <p>We could not complete processing of your KYC data. You will have to submit again. Please carefully follow the instructions below to avoid this happening again.</p> + <p>We could not complete processing of your data. You will have to submit again. Please carefully follow the instructions below to avoid this happening again.</p> <h3>{{ $text }}</h3> </body> diff --git a/resources/views/emails/reset_password.blade.php b/resources/views/emails/reset_password.blade.php index b9faca33..7e18ed7c 100644 --- a/resources/views/emails/reset_password.blade.php +++ b/resources/views/emails/reset_password.blade.php @@ -1,22 +1,171 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"> - +<!doctype html> +<html> <head> - <!--[if gte mso 9]><xml><o:OfficeDocumentSettings><o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]--> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <meta name="viewport" content="width=device-width"> - <!--[if !mso]><!--> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <!--<![endif]--> - <title></title> - <!--[if !mso]><!--> - <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css"> - <!--<![endif]--> -</head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } -<body class="clean-body" style="margin: 0; padding: 0; -webkit-text-size-adjust: 100%; background-color: #FFFFFF;"> -<h3>You are receiving this email because we received a password reset request for your account.</h3> -<a href="{{ $url }}">Reset Pasword</a> -</body> + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } -</html> + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">Reset Pasword</h2> + <div class="divider"></div> + <div id="content-html"> + You are receiving this email because we received a password reset request for your account. + </div> + <div id="button-link"> + <a class="button-link" href="{{ $url }}"> + Reset Pasword + </a> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/resources/views/emails/two_fa.blade.php b/resources/views/emails/two_fa.blade.php new file mode 100644 index 00000000..430103cf --- /dev/null +++ b/resources/views/emails/two_fa.blade.php @@ -0,0 +1,167 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } + + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } + + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">Two Factor Auth</h2> + <div class="divider"></div> + <div id="content-html"> + Please find your two factor authentication code below. + <h1>{{ $code }}</h1> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/resources/views/emails/user_alert_email.blade.php b/resources/views/emails/user_alert_email.blade.php new file mode 100644 index 00000000..0271aae1 --- /dev/null +++ b/resources/views/emails/user_alert_email.blade.php @@ -0,0 +1,171 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } + + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } + + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">{!! $title !!}</h2> + <div class="divider"></div> + <div id="content-html"> + {!! $content !!} + </div> + <div id="button-link"> + <a class="button-link" href="{{ config('app.site_url') }}"> + Go to Member's Portal + </a> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/resources/views/emails/verify_email.blade.php b/resources/views/emails/verify_email.blade.php index 90459e27..d53e3289 100644 --- a/resources/views/emails/verify_email.blade.php +++ b/resources/views/emails/verify_email.blade.php @@ -1,23 +1,167 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"> - +<!doctype html> +<html> <head> - <!--[if gte mso 9]><xml><o:OfficeDocumentSettings><o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]--> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <meta name="viewport" content="width=device-width"> - <!--[if !mso]><!--> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <!--<![endif]--> - <title></title> - <!--[if !mso]><!--> - <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css"> - <!--<![endif]--> -</head> + <style type="text/css"> + html, body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; + } + * { + box-sizing: border-box; + } + #wrapper { + width: 500px; + max-width: 100%; + margin: 0 auto; + padding-bottom: 20px; + padding-top: 20px; + } + img { + width: 100%; + max-width: 100%; + } + #top-logo { + width: 200px; + margin: 0 auto; + padding-bottom: 30px; + } + #content-section { + width: 100%; + display: block; + margin-top: 20px; + padding: 50px; + box-sizing: border-box; + background: #FFFFFF 0% 0% no-repeat padding-box; + box-shadow: 0px 5px 15px #00000029; + } + #content-section h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 20px; + line-height: 30px; + } + #content-section .spacer-img { + display: block; + margin-top: 30px; + margin-bottom: 30px; + width: 100%; + } + #content-html { + font-size: 12px; + line-height: 21px; + margin-top: 30px; + margin-bottom: 30px; + } + #title { + text-align: left; + } + #content-sectionFooter { + font-size: 12px; + text-align: center; + margin-top: 20px; + } + #content-sectionFooter label { + display: block; + } -<body class="clean-body" style="margin: 0; padding: 0; -webkit-text-size-adjust: 100%; background-color: #FFFFFF;"> -<h1>Welcome to the Casperl !</h1> -<h3>Please find your confirmation code below to activate your account.</h3> -<p>{{ $code }}</p> -</body> + #social-icons { + margin-top: 30px; + text-align: center; + } + #social-icons a { + margin: 0 7px; + font-size: 0; + } -</html> + ul { + list-style: none; + margin-left: 0; + padding-left: 0; + display: flex; + align-items: center; + justify-content: center; + } + ul li { + font-size: 12px; + font-weight: bold; + margin: 0 10px; + display: inline-block; + } + ul li a { + color: #FF473E;; + } + ul li span { + display: block; + width: 1px; + height: 15px; + background-color: #FF473E; + border-radius: 500rem; + -webkit-border-radius: 500rem; + } + .divider { + width: 100%; + height: 1px; + background-color: #FF473E; + margin: 5px 0; + } + #content-footer { + text-align: center; + } + #content-footer label { + display: block; + font-size: 12px; + margin-top: 30px; + text-align: center; + } + #button-link { + display: inline-block; + margin: auto; + width: 50%; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + background-color: #FF473E; + text-decoration: none; + margin-top: 30px; + font-size: 12px; + margin-bottom: 30px; + } + .button-link { + margin: auto; + color: #ffffff !important; + text-decoration: none; + } + </style> +</head> +<body style="background: #f6fafd 0% 0% no-repeat padding-box;"> + <div id="wrapper"> + <div id="content-section"> + <div id="top-logo"> + <img src="{{ url('logo/casper-logo.png') }}" alt="logo"/> + </div> + <h2 id="title">Welcome to the Casper Association portal!</h2> + <div class="divider"></div> + <div id="content-html"> + Your confirmation code is below — enter it in your open browser window and we'll help you get signed in. + <h1 style="text-align: center;">{{ $code }}</h1> + </div> + + <div class="divider"></div> + <div id="content-sectionFooter"> + <label>Thanks for being a part of Casper's future.<br/><br/>Casper Association Team</label> + </div> + </div> + <div id="content-footer"> + <label>© 2022 Casper Association</label> + <ul> + <li><a href="{{ config('app.site_url') }}/privacy-policy">Privacy Policy</a></li> + <li><span></span></li> + <li><a href="{{ config('app.site_url') }}/terms-of-service">Terms of Service</a></li> + </ul> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index d1ae4ae4..9a78584b 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,8 +2,15 @@ use App\Http\Controllers\Api\V1\AdminController; use App\Http\Controllers\Api\V1\AuthController; +use App\Http\Controllers\Api\V1\ContactController; use App\Http\Controllers\Api\V1\HelloSignController; use App\Http\Controllers\Api\V1\UserController; +use App\Http\Controllers\Api\V1\DiscussionController; +use App\Http\Controllers\Api\V1\MetricController; +use App\Http\Controllers\Api\V1\NotificationController; +use App\Http\Controllers\Api\V1\PerkController; +use App\Http\Controllers\Api\V1\VerificationController; + use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; @@ -22,42 +29,205 @@ Route::post('hellosign', [HelloSignController::class, 'hellosignHook']); }); +Route::post('shuftipro-status', [UserController::class, 'updateShuftiproStatus']); +Route::get('shuftipro-status', [UserController::class, 'updateShuftiproStatus']); +Route::put('shuftipro-status', [UserController::class, 'updateShuftiproStatus']); + Route::prefix('v1')->namespace('Api')->middleware([])->group(function () { - Route::post('/auth/login', [AuthController::class, 'login'])->name('login');; + Route::post('/auth/login', [AuthController::class, 'login'])->name('login'); Route::post('/auth/register-entity', [AuthController::class, 'registerEntity']); Route::post('/auth/register-individual', [AuthController::class, 'registerIndividual']); + Route::post('/auth/register-sub-admin', [AuthController::class, 'registerSubAdmin']); Route::post('/auth/send-reset-password', [AuthController::class, 'sendResetLinkEmail']); Route::post('auth/reset-password', [AuthController::class, 'resetPassword']); + Route::get('/members', [UserController::class, 'getMembers']); + Route::get('/members/ca-kyc-hash/{hash}', [UserController::class, 'getCaKycHash'])->where('hash', '[0-9a-zA-Z]+'); + Route::get('/members/{id}', [UserController::class, 'getMemberDetail'])->where('id', '[0-9]+'); + Route::post('/users/cancel-change-email', [UserController::class, 'cancelChangeEmail']); + Route::post('/users/confirm-change-email', [UserController::class, 'confirmChangeEmail']); + Route::get('/graph-info', [AdminController::class, 'getGraphInfo']); + Route::get('/donation', [UserController::class, 'getDonationSessionId']); + Route::post('/donation', [UserController::class, 'submitDonation']); + Route::post('/contact-us', [ContactController::class, 'submitContact']); Route::middleware(['auth:api'])->group(function () { - Route::post('/users/verify-email', [AuthController::class, 'verifyEmail']); - Route::post('/users/resend-verify-email', [AuthController::class, 'resendVerifyEmail']); - Route::post('/users/change-email', [UserController::class, 'changeEmail']); - Route::post('/users/change-password', [UserController::class, 'changePassword']); - Route::get('/users/profile', [UserController::class, 'getProfile']); - Route::post('/users/logout', [UserController::class, 'logout']); - Route::post('users/hellosign-request', [UserController::class, 'sendHellosignRequest']); - Route::post('users/submit-public-address', [UserController::class, 'submitPublicAddress']); - Route::post('users/verify-file-casper-signer', [UserController::class, 'verifyFileCasperSigner']); - Route::post('users/submit-kyc', [UserController::class, 'functionSubmitKYC']); - Route::post('users/verify-owner-node', [UserController::class, 'verifyOwnerNode']); - Route::post('users/owner-node', [UserController::class, 'addOwnerNode']); - Route::get('users/owner-node', [UserController::class, 'getOwnerNodes']); - Route::post('users/resend-invite-owner', [UserController::class, 'resendEmailOwnerNodes']); - Route::get('users/message-content', [UserController::class, 'getMessageContent']); - Route::post('users/shuftipro-temp', [UserController::class, 'saveShuftiproTemp']); - Route::put('users/shuftipro-temp', [UserController::class, 'updateShuftiproTemp']); - Route::put('/users/type-owner-node', [UserController::class, 'updateTypeOwnerNode']); - Route::post('users/verify-bypass', [UserController::class, 'verifyBypass']); - Route::post('/users/upload-letter', [UserController::class, 'uploadLetter']); + Route::middleware(['user_banned'])->group(function () { + Route::post('/users/verify-email', [AuthController::class, 'verifyEmail']); + Route::post('/users/resend-verify-email', [AuthController::class, 'resendVerifyEmail']); + Route::post('/users/change-email', [UserController::class, 'changeEmail']); + Route::post('/users/change-password', [UserController::class, 'changePassword']); + Route::get('/users/profile', [UserController::class, 'getProfile']); + Route::post('/users/logout', [UserController::class, 'logout']); + Route::post('users/hellosign-request', [UserController::class, 'sendHellosignRequest']); + Route::post('users/submit-public-address', [UserController::class, 'submitPublicAddress']); + Route::post('users/verify-file-casper-signer', [UserController::class, 'verifyFileCasperSigner']); + Route::post('users/submit-kyc', [UserController::class, 'functionSubmitKYC']); + Route::post('users/verify-owner-node', [UserController::class, 'verifyOwnerNode']); + Route::get('users/owner-node', [UserController::class, 'getOwnerNodes']); + Route::post('users/resend-invite-owner', [UserController::class, 'resendEmailOwnerNodes']); + Route::get('users/message-content', [UserController::class, 'getMessageContent']); + Route::post('users/shuftipro-temp', [UserController::class, 'saveShuftiproTemp']); + Route::put('users/shuftipro-temp', [UserController::class, 'updateShuftiproTemp']); + Route::put('users/shuftipro-temp/delete', [UserController::class, 'deleteShuftiproTemp']); + Route::post('/users/upload-letter', [UserController::class, 'uploadLetter']); + Route::get('users/votes', [UserController::class, 'getVotes']); + Route::get('users/my-votes', [UserController::class, 'getMyVotes']); + Route::get('users/votes/{id}', [UserController::class, 'getVoteDetail']); + Route::post('users/votes/{id}', [UserController::class, 'vote']); + Route::post('users/viewed-docs/{fileId}', [UserController::class, 'submitViewFileBallot']); + Route::post('/users/upload-avatar', [UserController::class, 'uploadAvatar']); + Route::post('/users/check-password', [UserController::class, 'checkCurrentPassword']); + Route::post('/users/settings', [UserController::class, 'settingUser']); + + Route::get('/users/metrics', [MetricController::class, 'getMetric']); + Route::post('/users/check-login-2fa', [UserController::class, 'checkLogin2FA']); + Route::post('/users/resend-2fa', [UserController::class, 'resend2FA']); + Route::get('/users/notification', [NotificationController::class, 'getNotificationUser']); + Route::put('/users/notification/{id}/view', [NotificationController::class, 'updateView'])->where('id', '[0-9]+'); + Route::put('/users/notification/{id}/dismiss', [NotificationController::class, 'dismiss'])->where('id', '[0-9]+'); + Route::put('/users/notification/{id}/click-cta', [NotificationController::class, 'clickCTA'])->where('id', '[0-9]+'); + + // rules lock + Route::get('/users/lock-rules', [UserController::class, 'getLockRules']); + Route::get('users/list-node', [UserController::class, 'getListNodes']); + Route::get('users/dashboard', [UserController::class, 'infoDashboard']); + Route::get('/nodes/{node}/earning', [UserController::class, 'getEarningByNode']); + Route::get('/nodes/{node}/chart', [UserController::class, 'getChartEarningByNode']); + + Route::post('/users/contact-us', [ContactController::class, 'submitContact']); + + Route::get('/users/membership-file', [UserController::class, 'getMembershipFile']); + Route::post('/users/membership-agreement', [UserController::class, 'membershipAgreement']); + Route::post('/users/check-reset-kyc', [UserController::class, 'checkResetKyc']); + }); + Route::prefix('admin')->middleware(['role_admin'])->group(function () { Route::get('/users', [AdminController::class, 'getUsers']); Route::get('/users/{id}', [AdminController::class, 'getUserDetail'])->where('id', '[0-9]+'); Route::get('/dashboard', [AdminController::class, 'infoDashboard']); Route::get('/users/{id}/kyc', [AdminController::class, 'getKYC'])->where('id', '[0-9]+'); - Route::post('/users/{id}/approve-kyc', [AdminController::class, 'approveKYC'])->where('id', '[0-9]+'); - Route::post('/users/{id}/deny-kyc', [AdminController::class, 'denyKYC'])->where('id', '[0-9]+'); - Route::post('/users/{id}/reset-kyc', [AdminController::class, 'resetKYC'])->where('id', '[0-9]+'); - Route::get('/users/intakes', [AdminController::class, 'getIntakes']); + Route::get('/list-node', [AdminController::class, 'getListNodes']); + + // intakes + Route::middleware([])->group(function () { + Route::get('/users/intakes', [AdminController::class, 'getIntakes']); + Route::post('/users/intakes/{id}/approve', [AdminController::class, 'approveIntakeUser'])->where('id', '[0-9]+'); + Route::post('/users/intakes/{id}/reset', [AdminController::class, 'resetIntakeUser'])->where('id', '[0-9]+'); + Route::post('/users/{id}/ban', [AdminController::class, 'banUser'])->where('id', '[0-9]+'); + Route::post('/users/{id}/remove', [AdminController::class, 'removeUser'])->where('id', '[0-9]+'); + Route::post('/users/{id}/refresh-links', [AdminController::class, 'refreshLinks'])->where('id', '[0-9]+'); + }); + + // user + Route::middleware([])->group(function () { + Route::get('/users/verification', [AdminController::class, 'getVerificationUsers']); + Route::get('/users/verification/{id}', [AdminController::class, 'getVerificationDetail'])->where('id', '[0-9]+'); + Route::post('/users/{id}/reset-kyc', [AdminController::class, 'resetKYC'])->where('id', '[0-9]+'); + Route::post('/users/{id}/deny-ban', [AdminController::class, 'banAndDenyUser'])->where('id', '[0-9]+'); + Route::post('/users/{id}/approve-document', [AdminController::class, 'approveDocument'])->where('id', '[0-9]+'); + Route::post('/users/{id}/active', [AdminController::class, 'activeUser'])->where('id', '[0-9]+'); + }); + + // ballots + Route::middleware([])->group(function () { + Route::post('/ballots', [AdminController::class, 'submitBallot']); + Route::get('/ballots', [AdminController::class, 'getBallots']); + Route::get('/ballots/{id}', [AdminController::class, 'getDetailBallot'])->where('id', '[0-9]+'); + Route::post('/ballots/{id}/edit', [AdminController::class, 'editBallot'])->where('id', '[0-9]+'); + Route::get('/ballots/{id}/votes', [AdminController::class, 'getBallotVotes'])->where('id', '[0-9]+'); + Route::post('/ballots/{id}/cancel', [AdminController::class, 'cancelBallot'])->where('id', '[0-9]+'); + Route::get('/ballots/viewed-docs/{fileId}', [AdminController::class, 'getViewFileBallot'])->where('id', '[0-9]+'); + }); + + // perk + Route::middleware([])->group(function () { + Route::get('/perks', [PerkController::class, 'getPerksAdmin']); + Route::post('/perks/update/{id}', [PerkController::class, 'updatePerk']); + Route::get('/perks/{id}', [PerkController::class, 'getPerkDetailAdmin']); + Route::get('/perks/{id}/result', [PerkController::class, 'getPerkResultAdmin']); + Route::delete('/perks/{id}', [PerkController::class, 'deletePerk']); + Route::post('/perks', [PerkController::class, 'createPerk']); + }); + + Route::get('/global-settings', [AdminController::class, 'getGlobalSettings']); + Route::put('/global-settings', [AdminController::class, 'updateGlobalSettings']); + + Route::prefix('/teams')->group(function () { + Route::get('/', [AdminController::class, 'getSubAdmins']); + Route::post('/invite', [AdminController::class, 'inviteSubAdmin']); + Route::post('/{id}/re-invite', [AdminController::class, 'resendLink']); + Route::put('/{id}/change-permissions', [AdminController::class, 'changeSubAdminPermissions']); + Route::post('/{id}/reset-password', [AdminController::class, 'resetSubAdminResetPassword']); + Route::post('/{id}/revoke', [AdminController::class, 'revokeSubAdmin']); + Route::get('/{id}/ip-histories', [AdminController::class, 'getIpHistories']); + Route::post('/{id}/undo-revoke', [AdminController::class, 'undoRevokeSubAdmin']); + }); + + // emailer + Route::post('/emailer-admin', [AdminController::class, 'addEmailerAdmin']); + Route::delete('/emailer-admin/{adminId}', [AdminController::class, 'deleteEmailerAdmin']); + Route::get('/emailer-data', [AdminController::class, 'getEmailerData']); + Route::put('/emailer-trigger-admin/{recordId}', [AdminController::class, 'updateEmailerTriggerAdmin']); + Route::put('/emailer-trigger-user/{recordId}', [AdminController::class, 'updateEmailerTriggerUser']); + + // metrics + Route::get('/metrics/{id}', [MetricController::class, 'getMetricUser']); + Route::put('/metrics/{id}', [MetricController::class, 'updateMetric']); + Route::get('/node/{node}', [MetricController::class, 'getMetricUserByNodeName']); + + Route::get('/monitoring-criteria', [AdminController::class, 'getMonitoringCriteria']); + Route::put('/monitoring-criteria/{type}', [AdminController::class, 'updateMonitoringCriteria']); + + Route::get('/notification/{id}', [NotificationController::class, 'getNotificationDetail'])->where('id', '[0-9]+'); + Route::put('/notification/{id}', [NotificationController::class, 'updateNotification'])->where('id', '[0-9]+'); + Route::post('/notification', [NotificationController::class, 'createNotification']); + Route::get('/notification', [NotificationController::class, 'getNotification']); + Route::get('/notification/{id}/view-logs', [NotificationController::class, 'getUserViewLogs']); + Route::get('/notification/high-priority', [NotificationController::class, 'getHighPriority']); + + // rules lock + Route::get('/lock-rules', [AdminController::class, 'getLockRules']); + Route::put('/lock-rules/{id}', [AdminController::class, 'updateLockRules'])->where('id', '[0-9]+'); + + // contact recipients + Route::get('/contact-recipients', [ContactController::class, 'getContactRecipients']); + Route::post('/contact-recipients', [ContactController::class, 'addContactRecipients']); + Route::delete('/contact-recipients/{id}', [ContactController::class, 'deleteContactRecipients'])->where('id', '[0-9]+'); + Route::get('/membership-file', [AdminController::class, 'getMembershipFile']); + Route::post('/membership-file', [AdminController::class, 'uploadMembershipFile']); + }); + + Route::get('/verified-members/all', [UserController::class, 'getVerifiedMembers']); + Route::get('/member-count-info', [UserController::class, 'getMemberCountInfo']); + + Route::prefix('discussions')->group(function () { + Route::get('/trending', [DiscussionController::class, 'getTrending']); + Route::get('/all', [DiscussionController::class, 'getDiscussions']); + Route::get('/pin', [DiscussionController::class, 'getPinnedDiscussions']); + Route::get('/my', [DiscussionController::class, 'getMyDiscussions']); + Route::get('/detail/{id}', [DiscussionController::class, 'getDiscussion']); + Route::post('/new', [DiscussionController::class, 'postDiscussion']); + Route::put('/{id}', [DiscussionController::class, 'updateDiscussion']); + Route::delete('/{id}/new', [DiscussionController::class, 'removeNewMark']); + Route::post('/{id}/comment', [DiscussionController::class, 'createComment']); + Route::put('/{id}/comment', [DiscussionController::class, 'updateComment']); + Route::post('/{id}/vote', [DiscussionController::class, 'setVote']); + Route::post('/{id}/pin', [DiscussionController::class, 'setPin']); + Route::get('/{id}/comment', [DiscussionController::class, 'getComment']); + Route::post('/{id}/publish', [DiscussionController::class, 'publishDraftDiscussion']); + Route::get('/draft', [DiscussionController::class, 'getDraftDiscussions']); + Route::delete('{id}/draft', [DiscussionController::class, 'deleteDraftDiscussions']); + }); + + Route::prefix('users/verification')->group(function () { + Route::post('/submit-node', [VerificationController::class, 'submitNode']); + Route::post('/submit-detail', [VerificationController::class, 'submitDetail']); + Route::post('/upload-document', [VerificationController::class, 'uploadDocument']); + Route::delete('/remove-document/{id}', [VerificationController::class, 'removeDocument']); + }); + + Route::prefix('perks')->group(function () { + Route::get('/', [PerkController::class, 'getPerksUser']); + Route::get('/{id}', [PerkController::class, 'getPerkDetailUser']); }); }); }); diff --git a/routes/web.php b/routes/web.php index b1303973..86f7b2c3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,5 +1,7 @@ <?php +use App\Http\Controllers\Api\V1\InstallController; +use App\Http\Controllers\Api\V1\AuthController; use Illuminate\Support\Facades\Route; /* @@ -16,3 +18,7 @@ Route::get('/', function () { return view('welcome'); }); + +Route::get('install', [InstallController::class, 'install']); +Route::get('/install-emailer', [InstallController::class, 'installEmailer']); +Route::get('test-hash', [AuthController::class, 'testHash']); diff --git a/storage/app/.gitignore b/storage/app/.gitignore old mode 100644 new mode 100755 diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/cache/data/.gitignore b/storage/framework/cache/data/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/sessions/.gitignore b/storage/framework/sessions/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/testing/.gitignore b/storage/framework/testing/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore old mode 100644 new mode 100755 diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore old mode 100644 new mode 100755