AdminApi   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 276
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 49
c 1
b 0
f 0
dl 0
loc 276
ccs 71
cts 71
cp 1
rs 10
wmc 21

21 Methods

Rating   Name   Duplication   Size   Complexity  
A source() 0 5 1
A themes() 0 3 1
A get() 0 5 1
A users() 0 3 1
A upload() 0 7 1
A webhooks() 0 3 1
A pages() 0 3 1
A site() 0 3 1
A __construct() 0 7 1
A tiers() 0 3 1
A members() 0 3 1
A offers() 0 3 1
A getHttpClient() 0 4 1
A activate() 0 6 1
A images() 0 3 1
A create() 0 7 1
A update() 0 9 1
A posts() 0 3 1
A adminToken() 0 19 1
A tags() 0 3 1
A delete() 0 7 1
1
<?php
2
3
namespace Igorsgm\Ghost\Apis;
4
5
use Firebase\JWT\JWT;
6
use Igorsgm\Ghost\Models\Resources\Image;
7
use Igorsgm\Ghost\Models\Resources\Member;
8
use Igorsgm\Ghost\Models\Resources\Offer;
9
use Igorsgm\Ghost\Models\Resources\Page;
10
use Igorsgm\Ghost\Models\Resources\Post;
11
use Igorsgm\Ghost\Models\Resources\Site;
12
use Igorsgm\Ghost\Models\Resources\Tag;
13
use Igorsgm\Ghost\Models\Resources\Theme;
14
use Igorsgm\Ghost\Models\Resources\Tier;
15
use Igorsgm\Ghost\Models\Resources\User;
16
use Igorsgm\Ghost\Models\Resources\Webhook;
17
use Igorsgm\Ghost\Responses\ErrorResponse;
18
use Igorsgm\Ghost\Responses\SuccessResponse;
19
use Illuminate\Support\Facades\Http;
20
21
class AdminApi extends BaseApi
22
{
23
    public string $resourceSlug = '';
24
25
    private string $adminToken;
26
27
    /**
28
     * @param  array  $params  Here you can provide 'key', 'domain', 'version' to override the default ones.
29
     */
30 73
    public function __construct(array $params = [])
31
    {
32 73
        $this->key = data_get($params, 'key') ?? config('ghost.admin_key');
33 73
        $this->domain = data_get($params, 'domain') ?? config('ghost.admin_domain');
34 73
        $this->version = data_get($params, 'version') ?? config('ghost.ghost_api_version');
35 73
        $this->baseUrl = sprintf('%s/ghost/api/v%s/admin', rtrim($this->domain, '/'), $this->version);
36 73
        $this->adminToken = $this->adminToken($this->key);
37
    }
38
39
    /**
40
     * Generates JSON Web Token (JWT) from Ghost Admin API key
41
     *
42
     * @return string
43
     *
44
     * @read https://ghost.org/docs/admin-api/#token-authentication
45
     */
46 73
    private function adminToken($adminKey)
47
    {
48
        //Step 1: Split the API key by the : into an id and a secret
49 73
        [$id, $secret] = explode(':', $adminKey);
50
51
        // Step 3: Decode the hexadecimal secret into the original binary byte array
52 73
        $decodedSecret = pack('H*', $secret);
53
54
        //Step 3: Pass these values to JWT library, ensuring that the header and payload are correct.
55 73
        $payload = [
56 73
            'exp' => strtotime('+10 minutes'), //expiration Unix timestamp
57 73
            'iat' => time(), //Issued at Time, Unix timestamp
58 73
            'aud' => "/v$this->version/admin/", //audience
59 73
        ];
60
61
        //debug. return original payload
62
        //$decoded = JWT::decode($token, $decodedSecret, ['HS256']);
63
64 73
        return JWT::encode($payload, $decodedSecret, 'HS256', $id);
65
    }
66
67
    /**
68
     * @return \Illuminate\Http\Client\PendingRequest
69
     */
70 60
    private function getHttpClient()
71
    {
72 60
        return Http::withHeaders([
73 60
            'Authorization' => 'Ghost '.$this->adminToken,
74 60
        ]);
75
    }
76
77
    /**
78
     * @return SuccessResponse|ErrorResponse
79
     */
80 39
    public function get()
81
    {
82 39
        $response = $this->getHttpClient()->get($this->makeApiUrl());
83
84 39
        return $this->handleResponse($response);
85
    }
86
87
    /**
88
     * @return SuccessResponse|ErrorResponse
89
     */
90 9
    public function create(array $data)
91
    {
92 9
        $response = $this->getHttpClient()->post($this->makeApiUrl(), [
93 9
            $this->resource->getResourceName() => [$data],
94 9
        ]);
95
96 9
        return $this->handleResponse($response);
97
    }
98
99
    /**
100
     * @return SuccessResponse|ErrorResponse
101
     */
102 7
    public function update(string $id, array $data)
103
    {
104 7
        $this->resourceId = $id;
105
106 7
        $response = $this->getHttpClient()->put($this->makeApiUrl(), [
107 7
            $this->resource->getResourceName() => [$data],
108 7
        ]);
109
110 7
        return $this->handleResponse($response);
111
    }
112
113
    /**
114
     * @return SuccessResponse|ErrorResponse
115
     */
116 4
    public function delete(string $id)
117
    {
118 4
        $this->resourceId = $id;
119
120 4
        $response = $this->getHttpClient()->delete($this->makeApiUrl());
121
122 4
        return $this->handleResponse($response);
123
    }
124
125
    /**
126
     * @param  string  $filePath  The path to the file you want to upload
127
     * @param  string  $ref  (optional) A reference or identifier for the image, e.g. the original filename and path.
128
     *                       Will be returned as-is in the API response, making it useful for finding & replacing
129
     *                       local image paths after uploads.
130
     * @return ErrorResponse|SuccessResponse
131
     */
132 2
    public function upload($filePath, $ref = null)
133
    {
134 2
        $response = $this->getHttpClient()
135 2
            ->attach('file', file_get_contents($filePath), basename($filePath))
136 2
            ->post($this->makeApiUrl('/upload'), array_filter(compact('ref')));
137
138 2
        return $this->handleResponse($response);
139
    }
140
141
    /**
142
     * Activate a theme
143
     *
144
     * @return ErrorResponse|SuccessResponse
145
     */
146 1
    public function activate(string $themeName)
147
    {
148 1
        $this->resourceId = $themeName;
149 1
        $response = $this->getHttpClient()->put($this->makeApiUrl('/activate'));
150
151 1
        return $this->handleResponse($response);
152
    }
153
154
    /**
155
     * The post creation/update endpoint is also able to convert HTML into mobiledoc.
156
     * The conversion generates the best available mobiledoc representation,
157
     * meaning this operation is lossy and the HTML rendered by Ghost may be different from the source HTML.
158
     * For the best results ensure your HTML is well-formed, e.g. uses block and inline elements correctly.
159
     */
160 3
    public function source(string $source): AdminApi
161
    {
162 3
        $this->source = $source;
163
164 3
        return $this;
165
    }
166
167
    /**
168
     * Posts are the primary resource in a Ghost site, providing means for publishing, managing and displaying content.
169
     * At the heart of every post is a mobiledoc field, containing a standardised JSON-based representation of your
170
     * content, which can be rendered in multiple formats.
171
     * Methods: Browse, Read, Edit, Add, Delete
172
     *
173
     * @see https://ghost.org/docs/admin-api/#posts
174
     */
175 12
    public function posts(): AdminApi
176
    {
177 12
        return $this->setResource(Post::class);
178
    }
179
180
    /**
181
     * Pages are static resources that are not included in channels or collections on the Ghost front-end.
182
     * They are identical to posts in terms of request and response structure when working with the APIs.
183
     * Methods: Browse, Read, Edit, Add, Delete
184
     *
185
     * @see https://ghost.org/docs/admin-api/#pages
186
     */
187 12
    public function pages(): AdminApi
188
    {
189 12
        return $this->setResource(Page::class);
190
    }
191
192
    /**
193
     * Methods: Browse, Read, Edit, Add, Delete
194
     */
195 11
    public function tags(): AdminApi
196
    {
197 11
        return $this->setResource(Tag::class);
198
    }
199
200
    /**
201
     * Tiers allow publishers to create multiple options for an audience to become paid subscribers.
202
     * Each tier can have its own price points, benefits, and content access levels.
203
     * Ghost connects tiers directly to the publication’s Stripe account.
204
     * Methods: Browse, Read, Edit, Add
205
     *
206
     * @see https://ghost.org/docs/admin-api/#tiers
207
     */
208 10
    public function tiers(): AdminApi
209
    {
210 10
        return $this->setResource(Tier::class);
211
    }
212
213
    /**
214
     * Use offers to create a discount or special price for members signing up on a tier.
215
     * Methods: Browse, Read, Edit, Add
216
     *
217
     * @see https://ghost.org/docs/admin-api/#offers
218
     */
219 6
    public function offers(): AdminApi
220
    {
221 6
        return $this->setResource(Offer::class);
222
    }
223
224
    /**
225
     * The member's resource provides an endpoint for fetching, creating, and updating member data.
226
     * Methods: Browse, Read, Edit, Add
227
     *
228
     * @see https://ghost.org/docs/admin-api/#members
229
     */
230 6
    public function members(): AdminApi
231
    {
232 6
        return $this->setResource(Member::class);
233
    }
234
235
    /**
236
     * Methods: Browse, Read
237
     *
238
     * @see https://ghost.org/docs/admin-api/#users
239
     */
240 3
    public function users(): AdminApi
241
    {
242 3
        return $this->setResource(User::class);
243
    }
244
245
    /**
246
     * Sending images to Ghost via the API allows you to upload images one at a time, and store them with a storage
247
     * adapter. The default adapter stores files locally in /content/images/ without making any modifications,
248
     * except for sanitising the filename.
249
     *
250
     * Methods: Upload
251
     *
252
     * @see https://ghost.org/docs/admin-api/#images
253
     */
254 2
    public function images(): AdminApi
255
    {
256 2
        return $this->setResource(Image::class);
257
    }
258
259
    /**
260
     * Themes can be uploaded from a local ZIP archive and activated.
261
     *
262
     * Methods: Upload, Activate
263
     *
264
     * @see https://ghost.org/docs/admin-api/#themes
265
     */
266 3
    public function themes(): AdminApi
267
    {
268 3
        return $this->setResource(Theme::class);
269
    }
270
271
    /**
272
     * Methods: Read
273
     *
274
     * @see https://ghost.org/docs/admin-api/#site
275
     */
276 2
    public function site(): AdminApi
277
    {
278 2
        return $this->setResource(Site::class);
279
    }
280
281
    /**
282
     * Webhooks allow you to build or set up custom integrations, which subscribe to certain events in Ghost.
283
     * When one of such events is triggered, Ghost sends an HTTP POST payload to the webhook’s configured URL.
284
     * For instance, when a new post is published Ghost can send a notification to configured endpoint to trigger
285
     * a search index re-build, Slack notification, or whole site deploy.
286
     *
287
     * Methods: Edit, Add, Delete
288
     *
289
     * @see https://ghost.org/docs/admin-api/#webhooks
290
     *
291
     * @read https://ghost.org/integrations/custom-integrations/#api-webhook-integrations
292
     * @read https://ghost.org/docs/webhooks/
293
     */
294 4
    public function webhooks(): AdminApi
295
    {
296 4
        return $this->setResource(Webhook::class);
297
    }
298
}
299