eveseat/eveapi

View on GitHub
src/Jobs/Contracts/Character/Items.php

Summary

Maintainability
D
1 day
Test Coverage
<?php

/*
 * This file is part of SeAT
 *
 * Copyright (C) 2015 to present Leon Jacobs
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

namespace Seat\Eveapi\Jobs\Contracts\Character;

use Illuminate\Support\Facades\Redis;
use Seat\Eseye\Exceptions\RequestFailedException;
use Seat\Eveapi\Exception\DeletedContractException;
use Seat\Eveapi\Exception\EmptyContractException;
use Seat\Eveapi\Exception\InvalidContractTypeException;
use Seat\Eveapi\Jobs\AbstractAuthCharacterJob;
use Seat\Eveapi\Models\Contracts\ContractDetail;
use Seat\Eveapi\Models\Contracts\ContractItem;
use Seat\Eveapi\Models\RefreshToken;

/**
 * Class Items.
 *
 * @package Seat\Eveapi\Jobs\Contracts\Character
 */
class Items extends AbstractAuthCharacterJob
{
    /**
     * The number of seconds for a single throttle cycle.
     */
    const DELAY = 12;

    /**
     * The maximum number of requests that can be made per
     * throttling cycle.
     */
    const REQUESTS_LIMIT = 15;

    /**
     * @var int
     */
    protected $contract_id;

    /**
     * @var string
     */
    protected $method = 'get';

    /**
     * @var string
     */
    protected $endpoint = '/characters/{character_id}/contracts/{contract_id}/items/';

    /**
     * @var string
     */
    protected $version = 'v1';

    /**
     * @var string
     */
    protected $scope = 'esi-contracts.read_character_contracts.v1';

    /**
     * @var array
     */
    protected $tags = ['character', 'contract'];

    /**
     * Items constructor.
     *
     * @param  \Seat\Eveapi\Models\RefreshToken  $token
     * @param  int  $contract_id
     */
    public function __construct(RefreshToken $token, int $contract_id)
    {
        $this->contract_id = $contract_id;

        array_push($this->tags, $contract_id);

        parent::__construct($token);
    }

    /**
     * Execute the job.
     *
     * @return void
     *
     * @throws \Exception
     */
    public function handle()
    {

        $contract = ContractDetail::find($this->contract_id);

        if ($contract->type == 'courier')
            throw new InvalidContractTypeException();

        if ($contract->status == 'deleted')
            throw new DeletedContractException();

        if ($contract->volume <= 0)
            throw new EmptyContractException();

        if ($contract->lines->isNotEmpty())
            return;

        // The number of requests made in the current throttle cycle.
        // https://github.com/ccpgames/esi-issues/issues/636
        // > The way it works is you can make 20 requests per 10 seconds
        // > for a contract tied to a specific character ID.

        Redis::throttle(implode(':', ['characters', $this->getCharacterId(), 'contracts']))
            ->allow(self::REQUESTS_LIMIT)
            ->every(self::DELAY)
            ->then(function () {

            try {
                $response = $this->retrieve([
                    'character_id' => $this->getCharacterId(),
                    'contract_id' => $this->contract_id,
                ]);

                $items = $response->getBody();

                collect($items)->each(function ($item) {

                    ContractItem::updateOrCreate([
                        'record_id' => $item->record_id,
                    ], [
                        'contract_id' => $this->contract_id,
                        'type_id' => $item->type_id,
                        'quantity' => $item->quantity,
                        'raw_quantity' => $item->raw_quantity ?? null,
                        'is_singleton' => $item->is_singleton,
                        'is_included' => $item->is_included,
                    ]);
                });
            } catch (RequestFailedException $e) {
                if (strtolower($e->getError()) == 'contract not found!') {
                    ContractDetail::where('contract_id', $this->contract_id)
                        ->update([
                            'status' => 'deleted',
                        ]);

                    return;
                }

                throw $e;
            }
        }, function () {

            return $this->release(self::DELAY);
        });
    }
}