Skip to content

Commit 60717eb

Browse files
author
Jon Waldstein
committed
refactor: update campaign schema to match response
1 parent ddd084b commit 60717eb

File tree

4 files changed

+159
-36
lines changed

4 files changed

+159
-36
lines changed

src/API/REST/V3/Routes/Campaigns/RegisterCampaignRoutes.php

Lines changed: 96 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
use Give\API\REST\V3\Routes\Campaigns\Permissions\CampaignPermissions;
77
use Give\API\REST\V3\Routes\Campaigns\ValueObjects\CampaignRoute;
88
use Give\Campaigns\Controllers\CampaignRequestController;
9+
use Give\Campaigns\ValueObjects\CampaignGoalType;
10+
use Give\Campaigns\ValueObjects\CampaignStatus;
11+
use Give\Campaigns\ValueObjects\CampaignType;
912
use WP_REST_Request;
1013
use WP_REST_Server;
1114

@@ -142,6 +145,7 @@ public function registerGetCampaigns()
142145
'default' => '',
143146
],
144147
],
148+
'schema' => [$this, 'getSchema'],
145149
]
146150
);
147151
}
@@ -249,7 +253,7 @@ public function registerCreateCampaign()
249253
'required' => false,
250254
'validate_callback' => 'rest_parse_date',
251255
'sanitize_callback' => function ($value) {
252-
return new DateTime($value);
256+
return new DateTime($value, wp_timezone());
253257
},
254258
],
255259
'endDateTime' => [
@@ -258,7 +262,7 @@ public function registerCreateCampaign()
258262
'required' => false,
259263
'validate_callback' => 'rest_parse_date',
260264
'sanitize_callback' => function ($value) {
261-
return new DateTime($value);
265+
return new DateTime($value, wp_timezone());
262266
},
263267
],
264268
] ),
@@ -313,61 +317,126 @@ public function getSchema(): array
313317
'id' => [
314318
'type' => 'integer',
315319
'description' => esc_html__('Campaign ID', 'give'),
320+
'readonly' => true,
321+
],
322+
'pagePermalink' => [
323+
'type' => ['string', 'null'],
324+
'description' => esc_html__('Campaign page permalink', 'give'),
325+
'readonly' => true,
316326
],
317327
'title' => [
318328
'type' => 'string',
319329
'description' => esc_html__('Campaign title', 'give'),
320330
'minLength' => 3,
321331
'maxLength' => 128,
322-
'errorMessage' => esc_html__('Campaign title is required', 'give'),
332+
'required' => true,
323333
],
324334
'status' => [
325-
'enum' => ['active', 'inactive', 'draft', 'pending', 'processing', 'failed', 'archived'],
335+
'enum' => [CampaignStatus::ACTIVE,CampaignStatus::ARCHIVED],
326336
'description' => esc_html__('Campaign status', 'give'),
337+
'default' => CampaignStatus::ACTIVE,
327338
],
328339
'shortDescription' => [
329-
'type' => 'string',
340+
'type' => ['string', 'null'],
330341
'description' => esc_html__('Campaign short description', 'give'),
331342
'maxLength' => 120,
332343
],
344+
'longDescription' => [
345+
'type' => ['string', 'null'],
346+
'description' => esc_html__('Campaign long description', 'give'),
347+
],
348+
'logo' => [
349+
'type' => ['string', 'null'],
350+
'format' => 'uri',
351+
'description' => esc_html__('Campaign logo URL', 'give'),
352+
],
353+
'image' => [
354+
'type' => ['string', 'null'],
355+
'format' => 'uri',
356+
'description' => esc_html__('Campaign featured image URL', 'give'),
357+
],
333358
'primaryColor' => [
334-
'type' => 'string',
359+
'type' => ['string', 'null'],
335360
'description' => esc_html__('Primary color for the campaign', 'give'),
336361
],
337362
'secondaryColor' => [
338-
'type' => 'string',
363+
'type' => ['string', 'null'],
339364
'description' => esc_html__('Secondary color for the campaign', 'give'),
340365
],
341366
'goal' => [
342-
'type' => 'number',
367+
'type' => 'integer',
343368
'description' => esc_html__('Campaign goal', 'give'),
344369
'errorMessage' => esc_html__('Must be a number', 'give'),
345-
],
346-
'goalProgress' => [
347-
'type' => 'number',
348-
'description' => esc_html__('Campaign goal progress', 'give'),
370+
'required' => true,
349371
],
350372
'goalType' => [
351-
'enum' => [
352-
'amount',
353-
'donations',
354-
'donors',
355-
'amountFromSubscriptions',
356-
'subscriptions',
357-
'donorsFromSubscriptions',
358-
],
373+
'enum' => array_values(CampaignGoalType::toArray()),
359374
'description' => esc_html__('Campaign goal type', 'give'),
375+
'required' => true,
376+
],
377+
'goalStats' => [
378+
'type' => 'object',
379+
'description' => esc_html__('Campaign goal statistics', 'give'),
380+
'readonly' => true,
381+
'properties' => [
382+
'actual' => [
383+
'type' => ['integer', 'number'],
384+
'description' => esc_html__('Actual progress value', 'give'),
385+
],
386+
'actualFormatted' => [
387+
'type' => ['string', 'number'],
388+
'description' => esc_html__('Formatted actual progress', 'give'),
389+
],
390+
'percentage' => [
391+
'type' => 'number',
392+
'description' => esc_html__('Progress percentage', 'give'),
393+
],
394+
'goal' => [
395+
'type' => ['integer', 'number'],
396+
'description' => esc_html__('Goal value', 'give'),
397+
],
398+
'goalFormatted' => [
399+
'type' => ['string', 'number'],
400+
'description' => esc_html__('Formatted goal value', 'give'),
401+
],
402+
],
403+
],
404+
'type' => [
405+
'type' => 'string',
406+
'enum' => array_values(CampaignType::toArray()),
407+
'description' => esc_html__('Campaign type', 'give'),
408+
'default' => CampaignType::CORE,
360409
],
361410
'defaultFormId' => [
362411
'type' => 'integer',
363412
'description' => esc_html__('Default campaign form ID', 'give'),
413+
'readonly' => true,
414+
],
415+
'defaultFormTitle' => [
416+
'type' => 'string',
417+
'description' => esc_html__('Default campaign form title', 'give'),
418+
'readonly' => true,
364419
],
365420
'pageId' => [
366-
'type' => 'integer',
421+
'type' => ['integer', 'null'],
367422
'description' => esc_html__('Campaign page ID', 'give'),
368423
],
424+
'startDate' => [
425+
'type' => ['string', 'null'],
426+
'description' => esc_html__('Campaign start date (Y-m-d H:i:s)', 'give'),
427+
'format' => 'date-time',
428+
],
429+
'endDate' => [
430+
'type' => ['string', 'null'],
431+
'description' => esc_html__('Campaign end date (Y-m-d H:i:s) or null', 'give'),
432+
'format' => 'date-time',
433+
],
434+
'createdAt' => [
435+
'type' => ['string', 'null'],
436+
'description' => esc_html__('Campaign creation date (Y-m-d H:i:s)', 'give'),
437+
'format' => 'date-time',
438+
],
369439
],
370-
'required' => ['id', 'title', 'goal', 'goalType'],
371440
'allOf' => [
372441
[
373442
'if' => [
@@ -381,7 +450,7 @@ public function getSchema(): array
381450
'properties' => [
382451
'goal' => [
383452
//'minimum' => 1,
384-
'type' => 'number',
453+
'type' => 'integer',
385454
],
386455
],
387456
'errorMessage' => [
@@ -403,7 +472,7 @@ public function getSchema(): array
403472
'properties' => [
404473
'goal' => [
405474
'minimum' => 1,
406-
'type' => 'number',
475+
'type' => 'integer',
407476
],
408477
],
409478
'errorMessage' => [
@@ -425,7 +494,7 @@ public function getSchema(): array
425494
'properties' => [
426495
'goal' => [
427496
'minimum' => 1,
428-
'type' => 'number',
497+
'type' => 'integer',
429498
],
430499
],
431500
'errorMessage' => [
@@ -447,7 +516,7 @@ public function getSchema(): array
447516
'properties' => [
448517
'goal' => [
449518
'minimum' => 1,
450-
'type' => 'number',
519+
'type' => 'integer',
451520
],
452521
],
453522
'errorMessage' => [
@@ -469,7 +538,7 @@ public function getSchema(): array
469538
'properties' => [
470539
'goal' => [
471540
'minimum' => 1,
472-
'type' => 'number',
541+
'type' => 'integer',
473542
],
474543
],
475544
'errorMessage' => [

src/Campaigns/ViewModels/CampaignViewModel.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ public function exports(): array
7272
? $this->campaign->getGoalStats()
7373
: $this->data->getGoalData($this->campaign),
7474
'status' => $this->campaign->status->getValue(),
75-
'startDate' => Temporal::getFormattedDateTime($this->campaign->startDate),
75+
'startDate' => Temporal::getFormattedDateTimeUsingTimeZoneAndFormatSettings($this->campaign->startDate),
7676
'endDate' => $this->campaign->endDate
77-
? Temporal::getFormattedDateTime($this->campaign->endDate)
77+
? Temporal::getFormattedDateTimeUsingTimeZoneAndFormatSettings($this->campaign->endDate)
7878
: null,
79-
'createdAt' => Temporal::getFormattedDateTime($this->campaign->createdAt),
79+
'createdAt' => Temporal::getFormattedDateTimeUsingTimeZoneAndFormatSettings($this->campaign->createdAt),
8080
];
8181
}
8282

src/Campaigns/resources/admin/components/CampaignFormModal/index.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {getGiveCampaignsListTableWindowData} from '../CampaignsListTable';
1818
import {amountFormatter} from '@givewp/campaigns/utils';
1919
import TextareaControl from '../CampaignDetailsPage/Components/TextareaControl';
2020
import {CampaignGoalInputAttributes, isValidGoalType} from '../../constants/goalInputAttributes';
21+
import { formatToDateTimeLocalInput } from '@givewp/admin/common';
2122

2223
const {currency, isRecurringEnabled} = getGiveCampaignsListTableWindowData();
2324
const currencyFormatter = amountFormatter(currency);
@@ -122,10 +123,8 @@ export default function CampaignFormModal({isOpen, handleClose, apiSettings, tit
122123
image: campaign?.image ?? '',
123124
goalType: campaign?.goalType ?? 'amount',
124125
goal: campaign?.goal ?? null,
125-
startDateTime: getDateString(
126-
campaign?.startDateTime?.date ? new Date(campaign?.startDateTime?.date) : getNextSharpHour(1)
127-
),
128-
endDateTime: campaign?.endDateTime?.date ? getDateString(new Date(campaign.startDateTime.date)) : '',
126+
startDateTime: formatToDateTimeLocalInput(campaign?.startDateTime?.date ?? ''),
127+
endDateTime: formatToDateTimeLocalInput(campaign?.endDateTime?.date ?? ''),
129128
},
130129
});
131130

@@ -172,8 +171,8 @@ export default function CampaignFormModal({isOpen, handleClose, apiSettings, tit
172171
}
173172

174173
try {
175-
inputs.startDateTime = getDateString(new Date(inputs.startDateTime));
176-
inputs.endDateTime = inputs.endDateTime && getDateString(new Date(inputs.endDateTime));
174+
inputs.startDateTime = formatToDateTimeLocalInput(inputs.startDateTime);
175+
inputs.endDateTime = inputs.endDateTime && formatToDateTimeLocalInput(inputs.endDateTime);
177176

178177
const endpoint = campaign?.id ? `/campaign/${campaign.id}` : '';
179178
const response = await API.fetchWithArgs(endpoint, inputs, 'POST');
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Give\Tests\Unit\API\REST\V3\Routes\Campaigns;
4+
5+
use Exception;
6+
use Give\API\REST\V3\Routes\Campaigns\ValueObjects\CampaignRoute;
7+
use Give\Campaigns\Models\Campaign;
8+
use Give\Donations\Models\Donation;
9+
use WP_REST_Server;
10+
use Give\Tests\RestApiTestCase;
11+
use Give\Tests\TestTraits\RefreshDatabase;
12+
use Give\Tests\TestTraits\HasDefaultWordPressUsers;
13+
use Give\Tests\Unit\API\REST\V3\SchemaValidationTrait;
14+
15+
class CampaignSchemaTest extends RestApiTestCase
16+
{
17+
use RefreshDatabase;
18+
use HasDefaultWordPressUsers;
19+
use SchemaValidationTrait;
20+
21+
/**
22+
* @unreleased
23+
*/
24+
public function testCampaignSchemaShouldMatchActualResponse()
25+
{
26+
$campaign = Campaign::factory()->create();
27+
$donations = Donation::factory()->count(3)->create([
28+
'campaignId' => $campaign->id,
29+
'formId' => $campaign->defaultFormId,
30+
]);
31+
32+
// Get the schema via OPTIONS request
33+
$schemaRoute = '/' . CampaignRoute::NAMESPACE . '/' . CampaignRoute::CAMPAIGNS;
34+
$schemaRequest = $this->createRequest('OPTIONS', $schemaRoute, [], 'administrator');
35+
$schemaResponse = $this->dispatchRequest($schemaRequest);
36+
$schemaJson = json_encode($schemaResponse->get_data());
37+
$schema = json_decode($schemaJson, true);
38+
39+
// Get actual campaign data
40+
$dataRoute = '/' . CampaignRoute::NAMESPACE . '/' . 'campaigns' . '/' . $campaign->id;
41+
$dataRequest = $this->createRequest(WP_REST_Server::READABLE, $dataRoute, [], 'administrator');
42+
$dataResponse = $this->dispatchRequest($dataRequest);
43+
$actualDataJson = json_encode($dataResponse->get_data());
44+
$actualData = json_decode($actualDataJson, true);
45+
46+
// Validate that all required schema properties exist in actual response
47+
$this->validateSchemaProperties($schema, $actualData);
48+
49+
// Validate data types match schema
50+
$this->validateDataTypes($schema, $actualData);
51+
52+
// Validate enum values match schema
53+
$this->validateEnumValues($schema, $actualData);
54+
}
55+
}

0 commit comments

Comments
 (0)