laravel-in-app-purchases
laravel-in-app-purchases copied to clipboard
Storing all interactions as backup for resolving future issues
Hi!
first off thank you for this amazing package!
I have an idea for improvement to prevent possible future issues:
I suggest storing all server notifications and receipt validations in a DB table in case we need to resolve customer issues in the future as a backup.
There may be errors with our application or anything else, and this could potentially save us a lot of troubles in the future.
That's a good idea in my opinion. I have have had some problems in the past where such a log would have helped .....
just created this account to +1
Sounds great!😍🔥 @lahivee @Iamscaredofcode
I'm actually thinking about providing a control panel to monitor subscriptions and products. For sure your idea is a good starting point. I'll work on it ASAP, and for sure your contributions are welcomed!
+1
+1
This would be an awesome feature. I recommend making it optional.
Until this feature is implemented, I came up with a workaround using a middleware. Sharing here for anyone else who might be interested.
Create a new middleware file app\Http\MIddleware\SavePurchaseNotification.php
. Note that validateRequest
only validates the App Store request currently. You should add a validation for Google if you use the Play Store.
<?php
namespace App\Http\Middleware;
use Closure;
use App\PurchaseNotification;
class SavePurchaseNotification
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->routeIs('purchase.serverNotifications.*')) {
$path = explode('/', $request->path());
$source = array_pop($path);
if ($this->validateRequest($source, $request->password)) {
PurchaseNotification::create([
'source' => $source,
'type' => $request->notification_type,
'payload' => json_encode($request->except(['password'])),
]);
}
}
return $next($request);
}
/**
* Private Methods
*/
/**
* Make sure the request came from a trusted source.
*
* @param String $source The source pulled from the url path.
* @param String $password The share secret provided by the store.
*/
private function validateRequest($source, $password)
{
switch ($source) {
case 'apple':
if ($password === config('services.app_store.shared_secret')) {
return true;
}
}
return false;
}
}
Update app\Http\Kernel.php
protected $middlewareGroups = [
// Other middleware groups.
// Create a new middleware group.
'purchase' => [
'throttle:120,1',
\App\Http\Middleware\SavePurchaseNotification::class,
],
];
protected $middlewarePriority = [
// Other middleware classes.
// Add new middleware class.
\App\Http\Middleware\SavePurchaseNotification::class,
];
Create a new database table purchase_notifications
php artisan make:model PurchaseNotification --migration
Update the new migration file
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePurchaseNotificationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('purchase_notifications', function (Blueprint $table) {
$table->id();
$table->string('source', 15);
$table->string('type', 50);
$table->text('payload');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('purchase_notifications');
}
}
Add the fillable columns to the new PurchaseNotification
model by updating app\PurchaseNotification
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PurchaseNotification extends Model
{
protected $fillable = ['source', 'type', 'payload'];
}
In the config file created by this plugin config/purchase.php
, add the new middleware group.
// Your other code.
return [
'routing' => [
// Add the new 'purchase' middleware group.
'middleware' => 'purchase',
],
// Your other code.
];
The middleware for saving the purchase notifications sounds like a great idea! 🚀 Feel free to submit a PR of this addition.
Congratulations @mreall! 🎉
Thanks for sharing your middleware! I had also started logging all my events by doing something similar except that I added my logger as a trait inside each of the listeners. Your solution seems perhaps a bit cleaner. I will implement both and see which one I like over time.
As for the idea of creating a dashboard to monitor all this purchase activity, that sounds like an amazing idea @imdhemy ! Are you still planning to add it to this great package?
@vesper8,
Please keep us posted about your findings of middleware vs the trait, which one is better from your point of view.
Yes, this is still planned, Currently, I'm focusing on a big refactoring with some bug fixes, reported or not.
+1