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 @@ -

-

-Build Status -Total Downloads -Latest Stable Version -License +

+# 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 +``` + +

+ ## 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 @@ +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 @@ +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 @@ +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:
"; + + foreach($persons_stuck_in_pending as $p) { + $body .= ''.(string)$index.'. '; + $body .= $p['name'].', '.$p['email'].'
'; + $index += 1; + } + } + + $index = 1; + + if($persons_stuck_denied) { + if($persons_stuck_in_pending) { + $body .= "

"; + } + + $body .= "Members denied by Shufti. Not reviewed yet:
"; + + foreach($persons_stuck_denied as $p) { + $body .= ''.(string)$index.'. '; + $body .= $p['name'].', '.$p['email'].'
'; + $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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ + 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 @@ +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 @@ $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 @@ +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 @@ +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 @@ + '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
"; + } + + public function installEmailer() { + + // Setup User + $userData = [ + [ + 'title' => 'Welcome to the Casper', + 'subject' => 'Welcome to the Casper Association portal!', + 'content' => 'Welcome to the Casper Association,

To access your member portal you must complete 3 simple steps that you can find once you log in.

#1. E-sign the terms of the portal.

#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.

#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!

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.

Please log in to explore. You now have access to the following:
- Node and network metrics
- Discussion previews
- Viewing previous votes

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.

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.

Verified Members can do the following:
- Start and participate in member discussions
- Vote on protocol updates or changes
- Display a page to verify their status to the public
- Access member benefits and perks
- View all network and node metrics
- Easily view details earnings from staking
- Track all health metrics for their node
' + ], + ]; + + 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 @@ +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 @@ +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 @@ +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.
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.
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 @@ +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 @@ + [], + '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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ + '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 @@ + '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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ + + + + + + +
+
+ +

{!! $title !!}

+
+
+ {!! $content !!} +
+ + +
+
+ +
+
+ +
+ + \ 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 @@ + + + + + + +
+
+ +

{!! $title !!}

+
+
+ {!! $content !!} +
+ + +
+
+ +
+
+ +
+ + \ 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 @@ + + + + + + +
+
+ +

Contact Us

+
+
+

Name : {{ $contact->name }}

+

Email : {{ $contact->email }}

+

Message : {!! $contact->message !!}

+
+ +
+
+ +
+
+ +
+ + \ 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 @@ + + + + + + +
+
+ +

Admin Privileges Granted

+
+
+ 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. +
+ + +
+
+ +
+
+ +
+ + \ 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 @@ + + + + + + +
+
+ +

Your KYC is approved

+
+
+ Good news, your KYC in the Casper Association portal was approved. You now have access to all member areas. +
+ + +
+
+ +
+
+ +
+ + \ 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 @@ + + + + + + +
+
+ +

Your KYC is denied

+
+
+ 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. +
+ + +
+
+ +
+
+ +
+ + \ 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 @@ -

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.

+

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.

{{ $text }}

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 @@ - - - + + - - - - - - - - - - - + + + +
+
+ +

Reset Pasword

+
+
+ You are receiving this email because we received a password reset request for your account. +
+ + +
+
+ +
+
+ +
+ + \ 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 @@ + + + + + + +
+
+ +

Two Factor Auth

+
+
+ Please find your two factor authentication code below. +

{{ $code }}

+
+ +
+
+ +
+
+ +
+ + \ 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 @@ + + + + + + +
+
+ +

{!! $title !!}

+
+
+ {!! $content !!} +
+ + +
+
+ +
+
+ +
+ + \ 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 @@ - - - + + - - - - - - - - - - - + + + +
+
+ +

Welcome to the Casper Association portal!

+
+
+ Your confirmation code is below — enter it in your open browser window and we'll help you get signed in. +

{{ $code }}

+
+ +
+
+ +
+
+ +
+ + \ 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 @@