Separated laravel app to its own folder (#540)

This commit is contained in:
Julien Nahum
2024-08-26 18:24:56 +02:00
committed by GitHub
parent 39b8df5eed
commit 5bd1dda504
546 changed files with 124 additions and 143 deletions

View File

@@ -0,0 +1,112 @@
<?php
namespace App\Http\Controllers\Webhook;
use App\Http\Controllers\Controller;
use App\Jobs\Billing\RemoveWorkspaceGuests;
use App\Models\License;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\UnauthorizedException;
class AppSumoController extends Controller
{
public function handle(Request $request)
{
$this->validateSignature($request);
if ($request->test) {
Log::info('[APPSUMO] test request received', $request->toArray());
return $this->success([
'message' => 'Webhook received.',
'event' => $request->event,
'success' => true,
]);
}
Log::info('[APPSUMO] request received', $request->toArray());
// Call the right function depending on the event using match()
match ($request->event) {
'activate' => $this->handleActivateEvent($request),
'upgrade', 'downgrade' => $this->handleChangeEvent($request),
'deactivate' => $this->handleDeactivateEvent($request),
default => null,
};
return $this->success([
'message' => 'Webhook received.',
'event' => $request->event,
'success' => true,
]);
}
private function handleActivateEvent($request)
{
$this->createLicense($request->json()->all());
}
private function handleChangeEvent($request)
{
$license = $this->deactivateLicense($request->prev_license_key);
$this->createLicense(array_merge($request->json()->all(), [
'user_id' => $license->user_id,
]));
}
private function handleDeactivateEvent($request)
{
$license = $this->deactivateLicense($request->license_key);
RemoveWorkspaceGuests::dispatch($license->user);
}
private function createLicense(array $licenseData): License
{
$license = License::firstOrNew([
'license_key' => $licenseData['license_key'],
'license_provider' => 'appsumo',
'status' => License::STATUS_ACTIVE,
]);
$license->meta = $licenseData;
$license->user_id = $licenseData['user_id'] ?? null;
$license->save();
Log::info(
'[APPSUMO] creating new license',
[
'license_key' => $license->license_key,
'license_id' => $license->id,
]
);
return $license;
}
private function deactivateLicense(string $licenseKey): License
{
$license = License::where([
'license_key' => $licenseKey,
'license_provider' => 'appsumo',
])->firstOrFail();
$license->update([
'status' => License::STATUS_INACTIVE,
]);
Log::info('[APPSUMO] De-activating license', [
'license_key' => $licenseKey,
'license_id' => $license->id,
]);
return $license;
}
private function validateSignature(Request $request)
{
$signature = $request->header('x-appsumo-signature');
$payload = $request->getContent();
if ($signature === hash_hmac('sha256', $payload, config('services.appsumo.api_key'))) {
throw new UnauthorizedException('Invalid signature.');
}
}
}

View File

@@ -0,0 +1,136 @@
<?php
namespace App\Http\Controllers\Webhook;
use App\Notifications\Subscription\FailedPaymentNotification;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\App;
use Laravel\Cashier\Http\Controllers\WebhookController;
use Stripe\Subscription as StripeSubscription;
class StripeController extends WebhookController
{
public function handleCustomerSubscriptionCreated(array $payload)
{
return parent::handleCustomerSubscriptionCreated($payload);
}
/**
* Override to add a sleep, and to detect plan upgrades
*
* @return \Symfony\Component\HttpFoundation\Response|void
*/
protected function handleCustomerSubscriptionUpdated(array $payload)
{
sleep(1);
if ($user = $this->getUserByStripeId($payload['data']['object']['customer'])) {
$data = $payload['data']['object'];
$subscription = $user->subscriptions()->firstOrNew(['stripe_id' => $data['id']]);
if (
isset($data['status']) &&
$data['status'] === StripeSubscription::STATUS_INCOMPLETE_EXPIRED
) {
$subscription->items()->delete();
$subscription->delete();
return;
}
$subscription->type = $subscription->type ?? $data['metadata']['name'] ?? $this->newSubscriptionName($payload);
$mainItem = $this->getMainSubscriptionLineItem($data['items']['data']);
$isSinglePrice = count($data['items']['data']) === 1;
// Price...
$subscription->stripe_price = $isSinglePrice ? $mainItem['price']['id'] : null;
// Type - previously (Name)
$subscription->type = $this->getSubscriptionName($mainItem['price']['product']);
// Quantity...
$subscription->quantity = $isSinglePrice && isset($mainItem['quantity']) ? $mainItem['quantity'] : null;
// Trial ending date...
if (isset($data['trial_end'])) {
$trialEnd = Carbon::createFromTimestamp($data['trial_end']);
if (! $subscription->trial_ends_at || $subscription->trial_ends_at->ne($trialEnd)) {
$subscription->trial_ends_at = $trialEnd;
}
}
// Cancellation date...
if (isset($data['cancel_at_period_end'])) {
if ($data['cancel_at_period_end']) {
$subscription->ends_at = $subscription->onTrial()
? $subscription->trial_ends_at
: Carbon::createFromTimestamp($data['current_period_end']);
} elseif (isset($data['cancel_at'])) {
$subscription->ends_at = Carbon::createFromTimestamp($data['cancel_at']);
} else {
$subscription->ends_at = null;
}
}
// Status...
if (isset($data['status'])) {
$subscription->stripe_status = $data['status'];
}
$subscription->save();
// Update subscription items...
if (isset($data['items'])) {
$prices = [];
foreach ($data['items']['data'] as $item) {
$prices[] = $item['price']['id'];
$subscription->items()->updateOrCreate([
'stripe_id' => $item['id'],
], [
'stripe_product' => $item['price']['product'],
'stripe_price' => $item['price']['id'],
'quantity' => $item['quantity'] ?? null,
]);
}
// Delete items that aren't attached to the subscription anymore...
$subscription->items()->whereNotIn('stripe_price', $prices)->delete();
}
}
return $this->successMethod();
}
protected function handleChargeFailed(array $payload)
{
if ($user = $this->getUserByStripeId($payload['data']['object']['customer'])) {
$user->notify(new FailedPaymentNotification());
}
return $this->successMethod();
}
private function getMainSubscriptionLineItem(array $items)
{
return collect($items)->first(function ($item) {
return in_array($this->getSubscriptionName($item['price']['product']), ['default']);
});
}
private function getSubscriptionName(string $stripeProductId)
{
$config = App::environment() == 'production' ? config('pricing.production') : config('pricing.test');
foreach ($config as $plan => $data) {
if ($stripeProductId == $config[$plan]['product_id']) {
return $plan;
}
}
return 'default';
}
}