Skip to content

Commit 423b53c

Browse files
authored
Replaced demo with local instance url in OpenApiDocs (#34)
* Replaced demo with local instance url in OpenApiDocs * Refactored path resolved to emit event to grab cloud path, instead of directly coupling to cloud * fix import * removed more demo references * remove mentions of demo in annotation generator docs
1 parent 880dac3 commit 423b53c

6 files changed

Lines changed: 159 additions & 103 deletions

File tree

Annotations/AnnotationGenerator.php

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ protected function getApplicableDemoExampleUrls(string $pluginName, string $meth
845845
}
846846
}
847847

848-
$exampleUrl = 'https://demo.matomo.cloud/' . $exampleUrl;
848+
$exampleUrl = $this->prependInstanceUrl($exampleUrl);
849849
return [
850850
'xml' => $exampleUrl . '&format=xml&token_auth=anonymous',
851851
'json' => $exampleUrl . '&format=JSON&token_auth=anonymous',
@@ -854,7 +854,7 @@ protected function getApplicableDemoExampleUrls(string $pluginName, string $meth
854854
}
855855

856856
/**
857-
* Query demo.matomo.cloud for report metadata which can later be used to help determine good example URLs for
857+
* Query for report metadata which can later be used to help determine good example URLs for
858858
* specific API endpoints. This method is only used when the example URL can't be determined using the default
859859
* method. This only works for endpoints associated with reports and have metadata provided by the containing
860860
* plugin. The response is cached as a property so the request is only made once regardless of how many times this
@@ -871,7 +871,7 @@ protected function getDemoReportMetadata(): array
871871
return $this->reportMetadata;
872872
}
873873

874-
$url = 'https://demo.matomo.cloud/index.php?module=API&method=API.getReportMetadata&format=JSON&idSite=1&hideMetricsDoc=0&showSubtableReports=0&filter_limit=-1&period=day';
874+
$url = $this->getReportMetadataUrl();
875875
try {
876876
$response = Http::sendHttpRequestBy(
877877
Http::getTransportMethod(),
@@ -903,11 +903,10 @@ protected function getDemoReportMetadata(): array
903903

904904
/**
905905
* Take the example URL and query the endpoint for an example response, hiding subtables. If a response isn't
906-
* received from demo.matomo.cloud, it can try using a temporary token to make the request against the current
906+
* received, it can try using a temporary token to make the request against the current
907907
* instance of Matomo.
908908
*
909-
* @param string $url The full example URL. E.g.
910-
* https://demo.matomo.cloud/?module=API&method=CustomReports.getConfiguredReports&idSite=1&format=xml&token_auth=anonymous
909+
* @param string $url The full example URL.
911910
* @param bool $useLocalToken A boolean indicating whether to get a temporary token and try the request against the
912911
* currently running Matomo instance.
913912
* @param bool $ignoreCached A boolean indicating whether the cached response file should be ignored. Default is
@@ -948,7 +947,6 @@ protected function getExampleIfAvailable(string $url, bool $useLocalToken = fals
948947
if ($useLocalToken) {
949948
$token = Piwik::requestTemporarySystemAuthToken('OpenApiDocs', 24);
950949
$tempUrl = str_replace('&token_auth=anonymous', '&token_auth=' . $token, $tempUrl);
951-
$tempUrl = str_replace('https://demo.matomo.cloud/', SettingsPiwik::getPiwikUrl(), $tempUrl);
952950
}
953951
try {
954952
$response = Http::sendHttpRequestBy(
@@ -1050,6 +1048,24 @@ protected function writeFile(string $filePath, string $contents)
10501048
return $this->artifactWriter->writeFile($filePath, $contents);
10511049
}
10521050

1051+
protected function getInstanceUrl(): string
1052+
{
1053+
return rtrim(SettingsPiwik::getPiwikUrl(), '/') . '/';
1054+
}
1055+
1056+
protected function prependInstanceUrl(string $path): string
1057+
{
1058+
return $this->getInstanceUrl() . ltrim($path, '/');
1059+
}
1060+
1061+
protected function getReportMetadataUrl(): string
1062+
{
1063+
return $this->prependInstanceUrl(
1064+
'index.php?module=API&method=API.getReportMetadata&format=JSON&idSite=1&hideMetricsDoc=0'
1065+
. '&showSubtableReports=0&filter_limit=-1&period=day'
1066+
);
1067+
}
1068+
10531069
/**
10541070
* Try to build an example URL for a specific API method using report metadata. This queries the demo server for
10551071
* report metadata to get examples of existing reports which can be used as example URLS. If no metadata matches the
@@ -1094,7 +1110,7 @@ protected function getReportExampleUrlFromMetadata(string $pluginName, string $m
10941110
);
10951111

10961112
// Use the JSON format for the test. If we get a valid response, return the URL without format.
1097-
if (!empty($this->getExampleIfAvailable('https://demo.matomo.cloud/' . $url . '&format=JSON'))) {
1113+
if (!empty($this->getExampleIfAvailable($this->prependInstanceUrl($url . '&format=JSON')))) {
10981114
return $url;
10991115
}
11001116
}

Annotations/GlobalApiComponents.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,14 @@
3636
* securityScheme="MatomoToken",
3737
* type="http",
3838
* scheme="bearer",
39-
* description="Matomo API token passed in the Authorization header as a bearer token. For demo.matomo.cloud requests, use the anonymous token value: anonymous."
39+
* description="Matomo API token passed in the Authorization header as a bearer token."
4040
* )
4141
*
4242
* @OA\Server(
4343
* url=LOCAL_MATOMO_SERVER_URL,
4444
* description="Current Matomo instance"
4545
* )
4646
*
47-
* @OA\Server(
48-
* url="https://demo.matomo.cloud/",
49-
* description="Matomo demo server"
50-
* )
51-
*
5247
* Generic Error object
5348
* @OA\Schema(
5449
* schema="GenericSuccess",

Specs/PathResolver.php

Lines changed: 20 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,30 @@
1111

1212
namespace Piwik\Plugins\OpenApiDocs\Specs;
1313

14-
use Piwik\Container\Container;
15-
use Piwik\Container\StaticContainer;
1614
use Piwik\Plugin\Manager;
15+
use Piwik\Piwik;
1716
use Piwik\Plugins\OpenApiDocs\OpenApiDocs;
1817

1918
class PathResolver
2019
{
21-
private const SHARED_BASE_SUBDIRECTORY = '/OpenApiDocs/';
20+
private const ARTIFACT_BASE_SUBDIRECTORY = '/tmp/';
2221

23-
private const SHARED_SPECS_SUBDIRECTORY = '/OpenApiDocs/specs/';
22+
private const SPECS_SUBDIRECTORY = 'specs/';
2423

25-
private const SHARED_ANNOTATIONS_SUBDIRECTORY = '/OpenApiDocs/annotations/';
24+
private const ANNOTATIONS_SUBDIRECTORY = 'annotations/';
2625

27-
private const SHARED_RESPONSES_SUBDIRECTORY = '/OpenApiDocs/responses/';
26+
private const RESPONSES_SUBDIRECTORY = 'responses/';
2827

2928
private $pluginDirectory;
3029

31-
private $isCloudActivated;
32-
33-
private $container;
34-
35-
public function __construct(?string $pluginDirectory = null, ?bool $isCloudActivated = null, ?Container $container = null)
30+
public function __construct(?string $pluginDirectory = null)
3631
{
3732
$this->pluginDirectory = $pluginDirectory ?? Manager::getInstance()::getPluginDirectory('OpenApiDocs');
38-
$this->isCloudActivated = $isCloudActivated ?? Manager::getInstance()->isPluginActivated('Cloud');
39-
$this->container = $container ?? $this->getStaticContainer();
4033
}
4134

4235
public function getSpecDirectory(): string
4336
{
44-
return $this->getArtifactDirectory(self::SHARED_SPECS_SUBDIRECTORY, OpenApiDocs::GENERATED_SPECS_PATH);
37+
return $this->getArtifactDirectory(self::SPECS_SUBDIRECTORY);
4538
}
4639

4740
public function getSpecFilePath(
@@ -54,7 +47,7 @@ public function getSpecFilePath(
5447

5548
public function getAnnotationsDirectory(): string
5649
{
57-
return $this->getArtifactDirectory(self::SHARED_ANNOTATIONS_SUBDIRECTORY, OpenApiDocs::GENERATED_ANNOTATIONS_PATH);
50+
return $this->getArtifactDirectory(self::ANNOTATIONS_SUBDIRECTORY);
5851
}
5952

6053
public function getAnnotationFilePath(string $pluginName): string
@@ -69,53 +62,34 @@ public function getApiMethodInfoFilePath(string $fileBaseName): string
6962

7063
public function getResponsesDirectory(): string
7164
{
72-
return $this->getArtifactDirectory(self::SHARED_RESPONSES_SUBDIRECTORY, OpenApiDocs::EXAMPLE_RESPONSES_PATH);
65+
return $this->getArtifactDirectory(self::RESPONSES_SUBDIRECTORY);
7366
}
7467

7568
public function getExampleResponseFilePath(string $pluginName, string $methodName, string $format): string
7669
{
7770
return $this->getResponsesDirectory() . $pluginName . '.' . $methodName . '.' . strtolower($format);
7871
}
7972

80-
private function getArtifactDirectory(string $sharedSubdirectory, string $fallbackPath): string
73+
private function getArtifactDirectory(string $subdirectory): string
8174
{
82-
$sharedPath = $this->getSharedArtifactDirectory($sharedSubdirectory);
83-
if ($sharedPath !== null) {
84-
return $sharedPath;
85-
}
86-
87-
return $this->pluginDirectory . $fallbackPath;
75+
return $this->getArtifactBasePath() . $subdirectory;
8876
}
8977

90-
private function getSharedArtifactDirectory(string $sharedSubdirectory): ?string
78+
private function getArtifactBasePath(): string
9179
{
92-
if (!$this->isCloudActivated || $this->container === null || !$this->container->has('CloudDistributedCachePath')) {
93-
return null;
94-
}
80+
$defaultArtifactBasePath = $this->pluginDirectory . self::ARTIFACT_BASE_SUBDIRECTORY;
81+
$artifactBasePath = $defaultArtifactBasePath;
82+
$this->dispatchArtifactBasePathEvent($artifactBasePath);
9583

96-
$sharedBasePath = trim((string) $this->container->get('CloudDistributedCachePath'));
97-
if ($sharedBasePath === '') {
98-
return null;
84+
if (empty($artifactBasePath)) {
85+
$artifactBasePath = $defaultArtifactBasePath;
9986
}
10087

101-
if (!$this->isUsableSharedBasePath($sharedBasePath)) {
102-
return null;
103-
}
104-
105-
return rtrim($sharedBasePath, '/\\') . self::SHARED_BASE_SUBDIRECTORY . ltrim(substr($sharedSubdirectory, strlen(self::SHARED_BASE_SUBDIRECTORY)), '/\\');
88+
return rtrim($artifactBasePath, '/\\') . '/';
10689
}
10790

108-
protected function isUsableSharedBasePath(string $sharedBasePath): bool
91+
protected function dispatchArtifactBasePathEvent(?string &$artifactBasePath): void
10992
{
110-
return is_dir($sharedBasePath) && is_writable($sharedBasePath);
111-
}
112-
113-
private function getStaticContainer(): ?Container
114-
{
115-
try {
116-
return StaticContainer::getContainer();
117-
} catch (\Throwable $e) {
118-
return null;
119-
}
93+
Piwik::postEvent('OpenApiDocs.getArtifactBasePath', [&$artifactBasePath]);
12094
}
12195
}

tests/Resources/MockAnnotationGenerator.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ public function getDemoReportMetadata(): array
6060
/**
6161
* @inheritDoc
6262
*/
63-
public function getExampleIfAvailable(string $url, bool $useLocalToken = false): string
63+
public function getExampleIfAvailable(string $url, bool $useLocalToken = false, bool $ignoreCached = false): string
6464
{
65-
return parent::getExampleIfAvailable($url, $useLocalToken);
65+
return parent::getExampleIfAvailable($url, $useLocalToken, $ignoreCached);
6666
}
6767

6868
/**
@@ -73,6 +73,16 @@ public function getReportExampleUrlFromMetadata(string $pluginName, string $meth
7373
return parent::getReportExampleUrlFromMetadata($pluginName, $methodName);
7474
}
7575

76+
public function getReportMetadataUrl(): string
77+
{
78+
return parent::getReportMetadataUrl();
79+
}
80+
81+
public function prependInstanceUrl(string $path): string
82+
{
83+
return parent::prependInstanceUrl($path);
84+
}
85+
7686
/**
7787
* @inheritDoc
7888
*/

tests/Unit/AnnotationGeneratorTest.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Piwik\API\NoDefaultValue;
1919
use Piwik\Plugins\OpenApiDocs\Annotations\AnnotationGenerator;
2020
use Piwik\Plugins\OpenApiDocs\OpenApiDocs;
21+
use Piwik\Plugins\OpenApiDocs\tests\Resources\MockAnnotationGenerator;
2122

2223
/**
2324
* @group OpenApiDocs
@@ -286,6 +287,89 @@ public function testBuildAnnotationForMethod(): void
286287
$this->expectNotToPerformAssertions();
287288
}
288289

290+
public function testGetApplicableDemoExampleUrlsUsesCurrentInstanceUrl(): void
291+
{
292+
$generator = $this->getMockBuilder(DocumentationGenerator::class)
293+
->disableOriginalConstructor()
294+
->onlyMethods(['getExampleUrl'])
295+
->getMock();
296+
$generator->expects($this->once())
297+
->method('getExampleUrl')
298+
->with('\\Piwik\\Plugins\\API\\API', 'get', [
299+
'idSite' => 1,
300+
'period' => 'day',
301+
'date' => 'today',
302+
])
303+
->willReturn('index.php?module=API&method=API.get&idSite=1&period=day&date=today');
304+
305+
$annotationGenerator = new class ($generator) extends MockAnnotationGenerator {
306+
protected function getInstanceUrl(): string
307+
{
308+
return 'https://local.matomo.test/';
309+
}
310+
};
311+
312+
$this->assertSame([
313+
'xml' => 'https://local.matomo.test/index.php?module=API&method=API.get&idSite=1&period=day&date=today&format=xml&token_auth=anonymous',
314+
'json' => 'https://local.matomo.test/index.php?module=API&method=API.get&idSite=1&period=day&date=today&format=JSON&token_auth=anonymous',
315+
'tsv' => 'https://local.matomo.test/index.php?module=API&method=API.get&idSite=1&period=day&date=today&format=Tsv&token_auth=anonymous',
316+
], $annotationGenerator->getApplicableDemoExampleUrls('API', 'get', []));
317+
}
318+
319+
public function testGetReportMetadataUrlUsesCurrentInstanceUrl(): void
320+
{
321+
$annotationGenerator = new class (new DocumentationGenerator()) extends MockAnnotationGenerator {
322+
protected function getInstanceUrl(): string
323+
{
324+
return 'https://local.matomo.test/';
325+
}
326+
};
327+
328+
$this->assertSame(
329+
'https://local.matomo.test/index.php?module=API&method=API.getReportMetadata&format=JSON&idSite=1'
330+
. '&hideMetricsDoc=0&showSubtableReports=0&filter_limit=-1&period=day',
331+
$annotationGenerator->getReportMetadataUrl()
332+
);
333+
}
334+
335+
public function testGetReportExampleUrlFromMetadataUsesCurrentInstanceUrl(): void
336+
{
337+
$annotationGenerator = new class (new DocumentationGenerator()) extends MockAnnotationGenerator {
338+
public $receivedUrl = null;
339+
340+
protected function getInstanceUrl(): string
341+
{
342+
return 'https://local.matomo.test/';
343+
}
344+
345+
public function getDemoReportMetadata(): array
346+
{
347+
return [[
348+
'module' => 'VisitsSummary',
349+
'action' => 'get',
350+
'imageGraphUrl' => 'index.php?module=API&method=ImageGraph.get&apiModule=VisitsSummary&apiAction=get&idSite=1&period=day&date=today',
351+
]];
352+
}
353+
354+
public function getExampleIfAvailable(string $url, bool $useLocalToken = false, bool $ignoreCached = false): string
355+
{
356+
$this->receivedUrl = $url;
357+
return '{"result":"ok"}';
358+
}
359+
};
360+
361+
$result = $annotationGenerator->getReportExampleUrlFromMetadata('VisitsSummary', 'get');
362+
363+
$this->assertSame(
364+
'index.php?module=API&method=VisitsSummary.get&idSite=1&period=day&date=today',
365+
$result
366+
);
367+
$this->assertSame(
368+
'https://local.matomo.test/index.php?module=API&method=VisitsSummary.get&idSite=1&period=day&date=today&format=JSON',
369+
$annotationGenerator->receivedUrl
370+
);
371+
}
372+
289373
public function testGetParamInfoFromDocBlock(): void
290374
{
291375
// TODO - Update to use resource file and/or dataprovider to test more than one comment block

0 commit comments

Comments
 (0)