laravel-in-app-purchases icon indicating copy to clipboard operation
laravel-in-app-purchases copied to clipboard

Storing all interactions as backup for resolving future issues

Open lahivee opened this issue 4 years ago • 9 comments

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.

lahivee avatar Jan 05 '21 05:01 lahivee

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

Iamscaredofcode avatar Jan 05 '21 07:01 Iamscaredofcode

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!

imdhemy avatar Jan 07 '21 12:01 imdhemy

+1

HilalLko avatar Jan 13 '21 09:01 HilalLko

+1

decodedmrq avatar Mar 27 '21 07:03 decodedmrq

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.
];

mreall avatar Aug 08 '21 00:08 mreall

The middleware for saving the purchase notifications sounds like a great idea! 🚀 Feel free to submit a PR of this addition.

Congratulations @mreall! 🎉

imdhemy avatar Aug 08 '21 11:08 imdhemy

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 avatar Oct 02 '21 11:10 vesper8

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

imdhemy avatar Oct 16 '21 10:10 imdhemy

+1

EzimetYusup avatar Dec 04 '22 03:12 EzimetYusup