Oh Dear is the all-in-one monitoring tool for your entire website. We monitor uptime, SSL certificates, broken links, scheduled tasks and more. You'll get a notifications for us when something's wrong. All that paired with a developer friendly API and kick-ass documentation. O, and you'll also be able to create a public status page under a minute. Start monitoring using our free trial now.

Selling digital products using Laravel part 3: Giving customers access to private repositories on Github

Original – by Freek Van der Herten – 3 minute read

Wouldn't it be great if we could automatically give customers access to the private repositories on GitHub for the products they bought? Let's take a look at how this is handled at spatie.be

Some of the products we sell, like Mailcoach, have source code that resides in a private repository.

screenshot

We automatically give our customers access to the repos containing the source code of bought products. This is quite nice because our more technical users can directly create issues and submit PRs. Even though it is a private repo, we still got some open source vibes there. For Mailcoach, there's a small friendly community helping each other and fixing things. Of course, because it's a paid product, my team members and I still do the bulk of the work.

Let's take a look at how that repository access is automatically granted. In the previous part, you might have noticed that RestoreRepositoryAccessAction being called in the GitHubSocialiteController. An action is a class that encapsulates logic that is being called from several places. We talk some more about actions in our Laravel Beyond CRUD course.

Let's take a look at the execute method of RestoreRepositoryAccessAction.

public function execute(User $user): void
{
    $user->purchases
        ->where('has_repository_access', false)
        ->filter(fn(Purchase $purchase) => $purchase->purchasable->repository_access)
        ->reject(fn(Purchase $purchase) => $purchase->license && $purchase->license->isExpired())
        ->each(function (Purchase $purchase) use ($user) {
            $this->gitHubApi->inviteToRepo(
                $user->github_username,
                $purchase->purchasable->repository_access
            );

            $purchase->update(['has_repository_access' => true]);
        });
}

This collection chain filters out the non-expired purchases (with a non-expired license) of the given user. If the user's purchasable has repository access, we'll use the GitHub API to invite that user to the repo. GitHub will mail the user an invite.

That GitHub class used in the code above is a simple wrapper class around the knplabs/github-api package.

If the license of a product that has a private repository expires, the repository access will be revoked. This is done in the RevokeRepositoryAccessForExpiredLicensesCommand, which is scheduled to run daily.

class RevokeRepositoryAccessForExpiredLicensesCommand extends Command
{
    public $signature = 'revoke-repository-access-for-expired-licenses';

    public function handle(GitHubApi $gitHubApi)
    {
        $this->info('Revoking access to repositories for expired licenses...');

        Purchase::query()
            ->whereHas('license', fn(Builder $query) => $query->whereExpired())
            ->where('has_repository_access', true)
            ->cursor()
            ->each(function (Purchase $purchase) use ($gitHubApi) {
                $gitHubApi->revokeAccessToRepo(
                    $purchase->user->github_username,
                    $purchase->purchasable->repository_access
                );

                $purchase->update(['has_repository_access' => false]);
            });

        $this->info('All done!');
    }
}

This series is continued in part 4: Making a sale using Paddle.

Share Post LinkedIn

I write about Laravel, PHP, AI and building better software.

Every two weeks, I share practical tips, tutorials, and behind-the-scenes insights from maintaining 300+ open source packages. Join thousands of developers who read along.

No spam. Unsubscribe anytime. You can also follow me on X.

Found something interesting to share?

The community section is a place where developers share links to articles, tutorials and videos. Submit a link and help fellow developers discover great content. As a thank you, you'll receive a coupon for a discount on Spatie products.