mirror of
https://gh.llkk.cc/https://github.com/CaptainCore/captaincore-manager.git
synced 2025-10-03 14:04:44 +08:00
472 lines
No EOL
20 KiB
PHP
472 lines
No EOL
20 KiB
PHP
<?php
|
|
|
|
namespace CaptainCore;
|
|
|
|
class Account {
|
|
|
|
protected $account_id = "";
|
|
|
|
public function __construct( $account_id = "", $admin = false ) {
|
|
if ( ( new User )->verify_accounts( [ $account_id ] ) ) {
|
|
$this->account_id = $account_id;
|
|
}
|
|
if ( $admin ) {
|
|
$this->account_id = $account_id;
|
|
}
|
|
}
|
|
|
|
public function get() {
|
|
$account = ( new Accounts )->get( $this->account_id );
|
|
$account->defaults = json_decode( $account->defaults );
|
|
$account->plan = json_decode( $account->plan );
|
|
$account->metrics = json_decode( $account->metrics );
|
|
return $account;
|
|
}
|
|
|
|
|
|
public function get_raw() {
|
|
|
|
self::calculate_totals();
|
|
|
|
// Fetch site from database
|
|
$account = ( new Accounts )->get( $this->account_id );
|
|
|
|
// Shared with permissions
|
|
$account_ids = self::shared_with();
|
|
$account_ids[] = $this->account_id;
|
|
|
|
// Fetch relating data
|
|
$account->users = ( new AccountUser )->where( [ "account_id" => $this->account_id ] );
|
|
$account->domains = ( new AccountDomain )->where( [ "account_id" => $this->account_id ] );
|
|
$account->sites = ( new AccountSite )->where( [ "account_id" => $this->account_id ] );
|
|
|
|
return $account;
|
|
|
|
}
|
|
|
|
public function sync() {
|
|
|
|
$command = "account sync {$this->account_id}";
|
|
|
|
// Disable https when debug enabled
|
|
if ( defined( 'CAPTAINCORE_DEBUG' ) ) {
|
|
add_filter( 'https_ssl_verify', '__return_false' );
|
|
}
|
|
|
|
$data = [
|
|
'timeout' => 45,
|
|
'headers' => [
|
|
'Content-Type' => 'application/json; charset=utf-8',
|
|
'token' => CAPTAINCORE_CLI_TOKEN
|
|
],
|
|
'body' => json_encode( [ "command" => $command ]),
|
|
'method' => 'POST',
|
|
'data_format' => 'body'
|
|
];
|
|
|
|
// Add command to dispatch server
|
|
$response = wp_remote_post( CAPTAINCORE_CLI_ADDRESS . "/run/background", $data );
|
|
if ( is_wp_error( $response ) ) {
|
|
$error_message = $response->get_error_message();
|
|
return "Something went wrong: $error_message";
|
|
}
|
|
|
|
return $response["body"];
|
|
}
|
|
|
|
public function assign_sites( $site_ids = [] ) {
|
|
|
|
$accountsite = new AccountSite();
|
|
|
|
// Fetch current records
|
|
$current_site_ids = array_column ( $accountsite->where( [ "account_id" => $this->account_id ] ), "site_id" );
|
|
|
|
// Removed current records not found new records.
|
|
foreach ( array_diff( $current_site_ids, $site_ids ) as $site_id ) {
|
|
$records = $accountsite->where( [ "account_id" => $this->account_id, "site_id" => $site_id ] );
|
|
foreach ( $records as $record ) {
|
|
$accountsite->delete( $record->account_site_id );
|
|
}
|
|
}
|
|
|
|
// Add new records
|
|
foreach ( array_diff( $site_ids, $current_site_ids ) as $site_id ) {
|
|
$accountsite->insert( [ "account_id" => $this->account_id, "site_id" => $site_id ] );
|
|
}
|
|
|
|
}
|
|
|
|
public function fetch() {
|
|
if ( $this->account_id == "" ) {
|
|
return [];
|
|
}
|
|
$user_id = get_current_user_id();
|
|
$account = $this->account();
|
|
$record = [
|
|
"timeline" => $this->process_logs(),
|
|
"account" => $account,
|
|
"invites" => $this->invites(),
|
|
"users" => $this->users(),
|
|
"domains" => $this->domains(),
|
|
"sites" => $this->sites(),
|
|
"usage_breakdown" => $this->usage_breakdown(),
|
|
"owner" => false,
|
|
];
|
|
|
|
if ( $user_id == $account["plan"]->billing_user_id ) {
|
|
$record["owner"] = true;
|
|
}
|
|
|
|
return $record;
|
|
}
|
|
|
|
public function account() {
|
|
$account = ( new Accounts )->get( $this->account_id );
|
|
$defaults = json_decode( $account->defaults );
|
|
$plan = json_decode( $account->plan );
|
|
$plan->name = empty( $plan->name ) ? "" : $plan->name;
|
|
$plan->addons = empty( $plan->addons ) ? [] : $plan->addons;
|
|
$plan->limits = empty( $plan->limits ) ? (object) [ "storage" => 0, "visits" => 0, "sites" => 0 ] : $plan->limits;
|
|
$plan->interval = empty( $plan->interval ) ? "12" : $plan->interval;
|
|
$plan->billing_user_id = empty( $plan->billing_user_id ) ? 0 : (int) $plan->billing_user_id;
|
|
if ( ! is_array( $defaults->users ) ) {
|
|
$defaults->users = [];
|
|
}
|
|
return [
|
|
"account_id" => $this->account_id,
|
|
"name" => html_entity_decode( $account->name ),
|
|
"plan" => $plan,
|
|
"metrics" => json_decode( $account->metrics ),
|
|
"defaults" => $defaults,
|
|
];
|
|
}
|
|
|
|
public function invites() {
|
|
$invites = new Invites();
|
|
return $invites->where( [ "account_id" => $this->account_id, "accepted_at" => "0000-00-00 00:00:00" ] );
|
|
}
|
|
|
|
public function domains() {
|
|
$account_ids = self::shared_with();
|
|
$account_ids[] = $this->account_id;
|
|
$results = ( new AccountDomain )->fetch_domains( [ "account_id" => $account_ids ] );
|
|
return $results;
|
|
}
|
|
|
|
public function sites() {
|
|
if ( $this->account_id == "" ) {
|
|
return [];
|
|
}
|
|
// Fetch sites assigned as owners
|
|
$all_site_ids = [];
|
|
$site_ids = array_column( ( new Sites )->where( [ "account_id" => $this->account_id, "status" => "active" ] ), "site_id" );
|
|
foreach ( $site_ids as $site_id ) {
|
|
$all_site_ids[] = $site_id;
|
|
}
|
|
// Fetch sites assigned as shared access
|
|
$site_ids = ( new AccountSite )->select_active_sites( 'site_id', [ "account_id" => $this->account_id ] );
|
|
foreach ( $site_ids as $site_id ) {
|
|
$all_site_ids[] = $site_id;
|
|
}
|
|
|
|
$results = [];
|
|
$all_site_ids = array_unique( $all_site_ids );
|
|
|
|
foreach ($all_site_ids as $site_id) {
|
|
$site = ( new Sites )->get( $site_id );
|
|
$details = json_decode( $site->details );
|
|
$results[] = [
|
|
"site_id" => $site_id,
|
|
"name" => $site->name,
|
|
"visits" => $details->visits,
|
|
"storage" => $details->storage,
|
|
];
|
|
}
|
|
usort( $results, "sort_by_name" );
|
|
return $results;
|
|
}
|
|
|
|
public function process_logs() {
|
|
$Parsedown = new \Parsedown();
|
|
$site_ids = array_column( self::sites(), "site_id" );
|
|
$fetch_process_logs = ( new ProcessLogSite )->fetch_process_logs( [ "site_id" => $site_ids ] );
|
|
$process_logs = [];
|
|
foreach ( $fetch_process_logs as $result ) {
|
|
$sites_for_process = ( new ProcessLogSite )->fetch_sites_for_process_log( [ "process_log_id" => $result->process_log_id ] );
|
|
// Filter out sites which account doesn't have access to.
|
|
foreach ($sites_for_process as $key => $site) {
|
|
if ( in_array( $site->site_id, $site_ids ) ) {
|
|
continue;
|
|
}
|
|
unset( $sites_for_process[$key] );
|
|
}
|
|
$websites = [];
|
|
foreach ($sites_for_process as $site_for_process) {
|
|
$websites[] = $site_for_process;
|
|
}
|
|
$item = ( new ProcessLogs )->get( $result->process_log_id );
|
|
$item->created_at = strtotime( $item->created_at );
|
|
$item->name = $result->name;
|
|
$item->description_raw = $item->description;
|
|
$item->description = $Parsedown->text( $item->description );
|
|
$item->author = get_the_author_meta( 'display_name', $item->user_id );
|
|
$item->websites = $websites;
|
|
$process_logs[] = $item;
|
|
}
|
|
return $process_logs;
|
|
}
|
|
|
|
public function shared_with() {
|
|
// Fetch sites assigned as owners
|
|
$all_site_ids = [];
|
|
$site_ids = array_column( ( new Sites )->where( [ "account_id" => $this->account_id, "status" => "active" ] ), "site_id" );
|
|
foreach ( $site_ids as $site_id ) {
|
|
$all_site_ids[] = $site_id;
|
|
}
|
|
// Fetch sites assigned as shared access
|
|
$site_ids = ( new AccountSite )->select_active_sites( 'site_id', [ "account_id" => $this->account_id ] );
|
|
foreach ( $site_ids as $site_id ) {
|
|
$all_site_ids[] = $site_id;
|
|
}
|
|
|
|
$all_site_ids = array_unique( $all_site_ids );
|
|
$account_ids = [];
|
|
|
|
foreach ($all_site_ids as $site_id) {
|
|
$account_ids[] = ( new Sites )->get( $site_id )->account_id;
|
|
}
|
|
return array_unique( $account_ids );
|
|
}
|
|
|
|
public function users() {
|
|
$permissions = ( new AccountUser )->where( [ "account_id" => $this->account_id ] );
|
|
$results = [];
|
|
foreach( $permissions as $permission ) {
|
|
$user = get_userdata( $permission->user_id );
|
|
$results[] = [
|
|
"user_id" => $user->ID,
|
|
"name" => $user->display_name,
|
|
"email" => $user->user_email,
|
|
"level" => ucfirst( $permission->level ),
|
|
];
|
|
}
|
|
return $results;
|
|
}
|
|
|
|
public function usage_breakdown() {
|
|
$account = self::get();
|
|
$site_ids = array_column( ( new Sites )->where( [ "account_id" => $this->account_id, "status" => "active" ] ), "site_id" );
|
|
|
|
$hosting_plan = $account->plan->name;
|
|
$addons = empty( $account->plan->usage->addons ) ? [] : $account->plan->usage->addons;
|
|
$storage = $account->plan->usage->storage;
|
|
$visits = $account->plan->usage->visits;
|
|
$visits_plan_limit = $account->plan->limits->visits;
|
|
$storage_limit = $account->plan->limits->storage;
|
|
$sites_limit = $account->plan->limits->sites;
|
|
|
|
if ( isset( $visits ) ) {
|
|
$visits_percent = round( $visits / $visits_plan_limit * 100, 0 );
|
|
}
|
|
|
|
$storage_gbs = round( $storage / 1024 / 1024 / 1024, 1 );
|
|
$storage_percent = round( $storage_gbs / $storage_limit * 100, 0 );
|
|
|
|
$result_sites = [];
|
|
|
|
foreach ( $site_ids as $site_id ) {
|
|
$site = ( new Site( $site_id ))->get();
|
|
$website_for_customer_storage = $site->storage;
|
|
$website_for_customer_visits = $site->visits;
|
|
$result_sites[] = [
|
|
'name' => $site->name,
|
|
'storage' => $website_for_customer_storage,
|
|
'visits' => $website_for_customer_visits
|
|
];
|
|
}
|
|
|
|
return [
|
|
'sites' => $result_sites,
|
|
'total' => [
|
|
"{$storage_percent}% storage<br /><strong>{$storage_gbs}GB/{$storage_limit}GB</strong>",
|
|
"{$visits_percent}% traffic<br /><strong>" . number_format( $visits ) . "</strong> <small>Yearly Estimate</small>"
|
|
]
|
|
];
|
|
|
|
}
|
|
|
|
public function invite( $email ) {
|
|
|
|
// Add account ID to current user
|
|
if ( email_exists( $email ) ) {
|
|
$user = get_user_by( 'email', $email );
|
|
$accounts = array_column( ( new AccountUser )->where( [ "user_id" => $user->ID ] ), "account_id" );
|
|
$accounts[] = $this->account_id;
|
|
( new User( $user->ID, true ) )->assign_accounts( array_unique( $accounts ) );
|
|
$this->calculate_totals();
|
|
return [ "message" => "Account already exists. Adding permissions for existing user." ];
|
|
}
|
|
|
|
$time_now = date("Y-m-d H:i:s");
|
|
$token = bin2hex( openssl_random_pseudo_bytes( 24 ) );
|
|
$new_invite = [
|
|
'email' => $email,
|
|
'account_id' => $this->account_id,
|
|
'created_at' => $time_now,
|
|
'updated_at' => $time_now,
|
|
'token' => $token
|
|
];
|
|
$invite = new Invites();
|
|
$invite_id = $invite->insert( $new_invite );
|
|
|
|
// Send out invite email
|
|
$invite_url = home_url() . "/account/?account={$this->account_id}&token={$token}";
|
|
$name = ( new Accounts )->get( $this->account_id )->name;
|
|
$subject = "Hosting account invite";
|
|
$body = "You've been granted access to account '$name'. Click here to accept:<br /><br /><a href=\"{$invite_url}\">$invite_url</a>";
|
|
$headers = [ 'Content-Type: text/html; charset=UTF-8' ];
|
|
|
|
wp_mail( $email, $subject, $body, $headers );
|
|
|
|
return [ "message" => "Invite has been sent." ];
|
|
}
|
|
|
|
public function calculate_totals() {
|
|
$metrics = [
|
|
"sites" => count( $this->sites() ),
|
|
"users" => count( $this->users() ),
|
|
"domains" => count( $this->domains() ),
|
|
];
|
|
( new Accounts )->update( [ "metrics" => json_encode( $metrics ) ], [ "account_id" => $this->account_id ] );
|
|
return [ "message" => "Account metrics updated." ];
|
|
}
|
|
|
|
public function calculate_usage() {
|
|
$account = self::get();
|
|
$sites = $this->sites();
|
|
$account->plan->usage->storage = array_sum ( array_column( $sites, "storage" ) );
|
|
$account->plan->usage->visits = array_sum ( array_column( $sites, "visits" ) );
|
|
$account->plan->usage->sites = count( $sites );
|
|
( new Accounts )->update( [ "plan" => json_encode( $account->plan ) ], [ "account_id" => $this->account_id ] );
|
|
}
|
|
|
|
|
|
public function process_renewals() {
|
|
$response = [];
|
|
$accounts = ( new Accounts )->select( 'account_id' );
|
|
foreach ( $accounts as $account_id ) {
|
|
$account = ( new Accounts )->get( $account_id );
|
|
$plan = json_decode( $account->plan );
|
|
if ( $plan->next_renewal != "" ) {
|
|
$result = (object) [
|
|
'account_id' => $account->account_id,
|
|
'renewal' => $plan->next_renewal,
|
|
'plan' => (int) $plan->billing_user_id,
|
|
];
|
|
}
|
|
$response[] = $result;
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
public function generate_order() {
|
|
$configurations = ( new Configurations )->get();
|
|
$account = ( new Accounts )->get( $this->account_id );
|
|
$plan = json_decode( $account->plan );
|
|
$customer = new \WC_Customer( $plan->billing_user_id );
|
|
$address = $customer->get_billing();
|
|
$order = wc_create_order( [ 'customer_id' => $plan->billing_user_id ] );
|
|
|
|
$site_names = array_column( self::sites(), "name" );
|
|
sort( $site_names );
|
|
$site_names = implode( ", ", $site_names );
|
|
|
|
if ( ! empty( $address ) ) {
|
|
$order->set_address( $address, 'billing' );
|
|
}
|
|
|
|
$line_item_id = $order->add_product( get_product( $configurations->woocommerce->hosting_plan ), 1 );
|
|
|
|
$order->get_items()[ $line_item_id ]->set_subtotal( $plan->price );
|
|
$order->get_items()[ $line_item_id ]->set_total( $plan->price );
|
|
$order->get_items()[ $line_item_id ]->add_meta_data( "Details", $plan->name . "\n\n" . $site_names );
|
|
$order->get_items()[ $line_item_id ]->save_meta_data();
|
|
$order->get_items()[ $line_item_id ]->save();
|
|
|
|
if ( $plan->addons && count( $plan->addons ) > 0 ) {
|
|
foreach ( $plan->addons as $addon ) {
|
|
$line_item_id = $order->add_product( get_product( $configurations->woocommerce->addons ), $addon->quantity );
|
|
$order->get_items()[ $line_item_id ]->set_subtotal( $addon->price * $addon->quantity );
|
|
$order->get_items()[ $line_item_id ]->set_total( $addon->price * $addon->quantity );
|
|
$order->get_items()[ $line_item_id ]->add_meta_data( "Details", $addon->name );
|
|
$order->get_items()[ $line_item_id ]->save_meta_data();
|
|
$order->get_items()[ $line_item_id ]->save();
|
|
}
|
|
}
|
|
|
|
if ( $plan->usage->sites > $plan->limits->sites ) {
|
|
$price = $configurations->usage_pricing->sites->cost;
|
|
if ( $plan->interval != $configurations->usage_pricing->sites->interval ) {
|
|
$price = $configurations->usage_pricing->sites->cost / ($configurations->usage_pricing->sites->interval / $plan->interval );
|
|
}
|
|
$quantity = $plan->usage->sites - $plan->limits->sites;
|
|
$total = $price * $quantity;
|
|
$line_item_id = $order->add_product( get_product( $configurations->woocommerce->usage ), $quantity );
|
|
$order->get_items()[ $line_item_id ]->set_subtotal( $total );
|
|
$order->get_items()[ $line_item_id ]->set_total( $total );
|
|
$order->get_items()[ $line_item_id ]->add_meta_data( "Details", "Extra Sites" );
|
|
$order->get_items()[ $line_item_id ]->save_meta_data();
|
|
$order->get_items()[ $line_item_id ]->save();
|
|
}
|
|
|
|
if ( $plan->usage->storage > ( $plan->limits->storage * 1024 * 1024 * 1024 ) ) {
|
|
$price = $configurations->usage_pricing->storage->cost;
|
|
if ( $plan->interval != $configurations->usage_pricing->storage->interval ) {
|
|
$price = $configurations->usage_pricing->storage->cost / ( $configurations->usage_pricing->storage->interval / $plan->interval );
|
|
}
|
|
$extra_storage = ( $plan->usage->storage / 1024 / 1024 / 1024 ) - $plan->limits->storage;
|
|
$quantity = ceil ( $extra_storage / $configurations->usage_pricing->storage->quantity );
|
|
$total = $price * $quantity;
|
|
$line_item_id = $order->add_product( get_product( $configurations->woocommerce->usage ), $quantity );
|
|
$order->get_items()[ $line_item_id ]->set_subtotal( $total );
|
|
$order->get_items()[ $line_item_id ]->set_total( $total );
|
|
$order->get_items()[ $line_item_id ]->add_meta_data( "Details", "Extra Storage" );
|
|
$order->get_items()[ $line_item_id ]->save_meta_data();
|
|
$order->get_items()[ $line_item_id ]->save();
|
|
}
|
|
|
|
if ( $plan->usage->visits > $plan->limits->visits ) {
|
|
$price = $configurations->usage_pricing->traffic->cost;
|
|
if ( $plan->interval != $configurations->usage_pricing->traffic->interval ) {
|
|
$price = $configurations->usage_pricing->traffic->cost / ( $configurations->usage_pricing->traffic->interval / $plan->interval );
|
|
}
|
|
$quantity = ceil ( ( $plan->usage->visits - $plan->limits->visits ) / $configurations->usage_pricing->traffic->quantity );
|
|
$total = $price * $quantity;
|
|
$line_item_id = $order->add_product( get_product( $configurations->woocommerce->usage ), $quantity );
|
|
$order->get_items()[ $line_item_id ]->set_subtotal( $total );
|
|
$order->get_items()[ $line_item_id ]->set_total( $total );
|
|
$order->get_items()[ $line_item_id ]->add_meta_data( "Details", "Extra Visits" );
|
|
$order->get_items()[ $line_item_id ]->save_meta_data();
|
|
$order->get_items()[ $line_item_id ]->save();
|
|
}
|
|
|
|
// Set payment method
|
|
$order->calculate_totals();
|
|
|
|
if ( $plan->auto_pay == "true" ) {
|
|
$payment_id = ( new \WC_Payment_Tokens )->get_customer_default_token( $plan->billing_user_id )->get_id();
|
|
( new User( $plan->billing_user_id, true ) )->pay_invoice( $order->get_id(), $payment_id );
|
|
return;
|
|
}
|
|
|
|
WC()->mailer()->customer_invoice( $order );
|
|
$order->add_order_note( __( 'Order details manually sent to customer.', 'woocommerce' ), false, true );
|
|
do_action( 'woocommerce_after_resend_order_email', $order, 'customer_invoice' );
|
|
}
|
|
|
|
public function delete() {
|
|
( new Accounts )->delete( [ "account_id" => $this->account_id ] );
|
|
}
|
|
|
|
} |