api( 'patreon', 'patreon_api', [ 'method' => 'POST', 'endpoint' => 'token', 'arguments' => [ 'grant_type' => 'authorization_code', 'code' => $code, 'redirect_uri' => $this->setting->get('patreon_redirect_uri') ] ] ); // Make sure we got the expected result. if ( isset($response['access_token']) === false || isset($response['refresh_token']) === false ) { throw new cora\exception('Could not get first Patreon token.', 10100); } $new_patreon_token = [ 'access_token' => $response['access_token'], 'refresh_token' => $response['refresh_token'], 'deleted' => false ]; /** * Look for existing tokens (in case access was revoked and then * re-granted). Include deleted tokens and revive that row since each user * is limited to one token row. */ $existing_patreon_token = $this->read([ 'deleted' => [0, 1] ]); if (count($existing_patreon_token) > 0) { $this->update(array_merge( ['patreon_token_id' => $existing_patreon_token[0]['patreon_token_id']], $new_patreon_token )); } else { $this->create($new_patreon_token); } return $this->read()[0]; } /** * Get some new tokens. A database lock is obtained prior to getting a token * so that no other API call can attempt to get a token at the same time. * This way if two API calls fire off to patreon at the same time, then * return at the same time, then call token->refresh() at the same time, * only one can run and actually refresh at a time. If the transactionless * one runs after that's fine as it will look up the token prior to * refreshing. */ public function refresh() { $database = cora\database::get_transactionless_instance(); $lock_name = 'patreon_token->refresh(' . $this->session->get_user_id() . ')'; $database->get_lock($lock_name, 3); $patreon_tokens = $database->read( 'patreon_token', [ 'user_id' => $this->session->get_user_id(), 'deleted' => false ] ); if(count($patreon_tokens) === 0) { throw new cora\exception('Could not refresh Patreon token; no token found.', 10101); } $patreon_token = $patreon_tokens[0]; $response = $this->api( 'patreon', 'patreon_api', [ 'method' => 'POST', 'endpoint' => 'token', 'arguments' => [ 'grant_type' => 'refresh_token', 'refresh_token' => $patreon_token['refresh_token'] ] ] ); if ( isset($response['access_token']) === false || isset($response['refresh_token']) === false ) { $this->delete($patreon_token['patreon_token_id']); $database->release_lock($lock_name); throw new cora\exception('Could not refresh Patreon token; Patreon returned no token.', 10102, true, null, false); } $patreon_token = $database->update( 'patreon_token', [ 'patreon_token_id' => $patreon_token['patreon_token_id'], 'access_token' => $response['access_token'], 'refresh_token' => $response['refresh_token'], 'timestamp' => date('Y-m-d H:i:s') ] ); $database->release_lock($lock_name); return $patreon_token; } /** * Delete a Patreon token and log the user out. Make sure to delete the * token prior to logging out so the right permissions are present. * * @param int $id * * @return int */ public function delete($id) { return parent::delete($id); } }