Skip to content

Commit

Permalink
Merge branch 'refactor/campaigns-design-review-GIVE-1343' of github.c…
Browse files Browse the repository at this point in the history
…om:impress-org/give into refactor/campaigns-design-review-GIVE-1343
  • Loading branch information
kjohnson committed Nov 7, 2024
2 parents d969f83 + 4777057 commit f57154e
Show file tree
Hide file tree
Showing 11 changed files with 398 additions and 6 deletions.
10 changes: 10 additions & 0 deletions src/Campaigns/Models/Campaign.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,16 @@ public function delete(): bool
return give(CampaignRepository::class)->delete($this);
}

/**
* @unreleased
*
* @throws Exception
*/
public function merge(Campaign ...$campaignsToMerge): bool
{
return give(CampaignRepository::class)->mergeCampaigns($this, ...$campaignsToMerge);
}

/**
* @unreleased
*
Expand Down
57 changes: 57 additions & 0 deletions src/Campaigns/Repositories/CampaignRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,63 @@ public function delete(Campaign $campaign): bool
return true;
}

/**
* @unreleased
*
* @throws Exception
*/
public function mergeCampaigns(Campaign $destinationCampaign, Campaign ...$campaignsToMerge): bool
{
// Make sure the destination campaign ID will not be included into $campaignsToMergeIds
$campaignsToMergeIds = array_column($campaignsToMerge, 'id');
if ($key = array_search($destinationCampaign->id, $campaignsToMergeIds)) {
unset($campaignsToMergeIds[$key]);
}

Hooks::doAction('givewp_campaigns_merging', $destinationCampaign, $campaignsToMergeIds);

DB::query('START TRANSACTION');

try {
// Convert $campaignsToMergeIds to string to use it in the queries
$campaignsToMergeIdsString = implode(', ', $campaignsToMergeIds);

// Migrate revenue entries from campaigns to merge to the destination campaign
DB::query(
DB::prepare("UPDATE " . DB::prefix('give_revenue') . " SET campaign_id = %d WHERE campaign_id IN ($campaignsToMergeIdsString)",
[
$destinationCampaign->id,
])
);

// Migrate forms from campaigns to merge to the destination campaign
DB::query(
DB::prepare("UPDATE " . DB::prefix('give_campaign_forms') . " SET is_default = 0, campaign_id = %d WHERE campaign_id IN ($campaignsToMergeIdsString)",
[
$destinationCampaign->id,
])
);

// Delete campaigns to merge now that we already migrated the necessary data to the destination campaign
DB::query("DELETE FROM " . DB::prefix('give_campaigns') . " WHERE id IN ($campaignsToMergeIdsString)");
} catch (Exception $exception) {
DB::query('ROLLBACK');

Log::error('Failed merging campaigns into destination campaign', [
'campaignsToMergeIds' => $campaignsToMergeIds,
'destinationCampaign' => compact('destinationCampaign'),
]);

throw new $exception('Failed merging campaigns into destination campaign');
}

DB::query('COMMIT');

Hooks::doAction('givewp_campaigns_merged', $destinationCampaign, $campaignsToMergeIds);

return true;
}

/**
* @unreleased
*/
Expand Down
65 changes: 65 additions & 0 deletions src/Campaigns/Routes/MergeCampaigns.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Give\Campaigns\Routes;

use Exception;
use Give\API\RestRoute;
use Give\Campaigns\Models\Campaign;
use Give\Campaigns\ValueObjects\CampaignRoute;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
* @unreleased
*/
class MergeCampaigns implements RestRoute
{
/**
* @unreleased
*/
public function registerRoute()
{
register_rest_route(
CampaignRoute::NAMESPACE,
CampaignRoute::CAMPAIGN . '/merge',
[
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [$this, 'handleRequest'],
'permission_callback' => function () {
return current_user_can('manage_options');
},
],
'args' => [
'id' => [
'type' => 'integer',
'required' => true,
],
'campaignsToMergeIds' => [
'type' => 'array',
'required' => true,
'items' => [
'type' => 'integer',
],
],
],
]
);
}

/**
* @unreleased
*
* @throws Exception
*/
public function handleRequest(WP_REST_Request $request): WP_REST_Response
{
$destinationCampaign = Campaign::find($request->get_param('id'));
$campaignsToMerge = Campaign::query()->whereIn('id', $request->get_param('campaignsToMergeIds'))->getAll();

$campaignsMerged = $destinationCampaign->merge(...$campaignsToMerge);

return new WP_REST_Response($campaignsMerged);
}
}
3 changes: 2 additions & 1 deletion src/Campaigns/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ private function registerRoutes()
Hooks::addAction('rest_api_init', Routes\GetCampaignsListTable::class, 'registerRoute');
Hooks::addAction('rest_api_init', Routes\DeleteCampaignListTable::class, 'registerRoute');
Hooks::addAction('rest_api_init', Routes\GetCampaignStatistics::class, 'registerRoute');
Hooks::addAction('rest_api_init', Routes\MergeCampaigns::class, 'registerRoute');
}

/**
Expand Down Expand Up @@ -138,7 +139,7 @@ private function setupCampaignForms()
if ( ! defined('GIVE_IS_ALL_STATS_COLUMNS_ASYNC_ON_ADMIN_FORM_LIST_VIEWS')) {
define('GIVE_IS_ALL_STATS_COLUMNS_ASYNC_ON_ADMIN_FORM_LIST_VIEWS', false);
}

Hooks::addAction('save_post_give_forms', AddCampaignFormFromRequest::class, 'optionBasedFormEditor', 10, 3);
Hooks::addAction('givewp_donation_form_created', AddCampaignFormFromRequest::class, 'visualFormBuilder');
Hooks::addAction('givewp_campaign_created', CreateDefaultCampaignForm::class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
GoalInputAttributes,
GoalTypeOption as GoalTypeOptionType,
} from './types';
import {useEffect, useRef, useState} from 'react';
import {useRef, useState} from 'react';
import {Currency, Upload} from '../Inputs';
import {
AmountFromSubscriptionsIcon,
Expand Down Expand Up @@ -146,15 +146,15 @@ export default function CampaignFormModal({isOpen, handleClose, apiSettings, tit
const goal = watch('goal');

const getFormModalTitle = () => {
switch(step) {
switch (step) {
case 1:
return __('Tell us about your fundraising cause', 'give');
case 2:
return __('Set up your campaign goal', 'give');
}

return null;
}
};

const goalInputAttributes: {[selectedGoalType: string]: GoalInputAttributes} = {
amount: {
Expand Down Expand Up @@ -395,7 +395,7 @@ export default function CampaignFormModal({isOpen, handleClose, apiSettings, tit
) : (
<input
type="number"
{...register('goal', {required: __('The campaign must have a goal!', 'give')})}
{...register('goal', {valueAsNumber: true})}
aria-invalid={errors.goal ? 'true' : 'false'}
placeholder={goalInputAttributes[selectedGoalType].placeholder}
/>
Expand Down
7 changes: 7 additions & 0 deletions src/FormMigration/Controllers/MigrationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Give\FormMigration\Controllers;

use Give\Campaigns\Repositories\CampaignRepository;
use Give\DonationForms\V2\Models\DonationForm;
use Give\FormMigration\Concerns\Blocks\BlockDifference;
use Give\FormMigration\DataTransferObjects\FormMigrationPayload;
Expand Down Expand Up @@ -50,6 +51,12 @@ public function __invoke(DonationForm $formV2)
->process($payload)
->finally(function(FormMigrationPayload $payload) {
$payload->formV3->save();

// Associate upgraded form to a campaign
$campaignRepository = give(CampaignRepository::class);
$campaign = $campaignRepository->getByFormId($payload->formV2->id);
$campaignRepository->addCampaignForm($campaign, $payload->formV3->id);

Log::info(esc_html__('Form migrated from v2 to v3.', 'give'), $this->debugContext);
});

Expand Down
10 changes: 10 additions & 0 deletions src/FormMigration/Controllers/TransferController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Give\FormMigration\Controllers;

use Give\Campaigns\Repositories\CampaignRepository;
use Give\DonationForms\V2\Models\DonationForm;
use Give\DonationForms\ValueObjects\DonationFormStatus;
use Give\FormMigration\Actions\GetMigratedFormId;
Expand Down Expand Up @@ -35,6 +36,15 @@ public function __invoke(DonationForm $formV2, TransferOptions $options)
TransferFormUrl::from($formV2->id)->to($v3FormId);
TransferDonations::from($formV2->id)->to($v3FormId);

// Promote upgraded form to default form
$campaignRepository = give(CampaignRepository::class);
$campaign = $campaignRepository->getByFormId($formV2->id);
$defaultForm = $campaign->defaultForm();

if ($defaultForm->id === $formV2->id) {
$campaignRepository->updateDefaultCampaignForm($campaign, $v3FormId);
}

if($options->shouldDelete()) {
wp_trash_post($formV2->id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public function testShouldMigrateFormV2ToV3(): void
{
$formV2 = $this->createSimpleDonationForm();

$this->createCampaignForDonationForm($formV2->id);

$request = $this->getMockRequest(WP_REST_Server::CREATABLE);

$controller = new MigrationController($request);
Expand Down
Loading

0 comments on commit f57154e

Please sign in to comment.