diff --git a/src/Campaigns/Migrations/MigrateFormsToCampaignForms.php b/src/Campaigns/Migrations/MigrateFormsToCampaignForms.php index 5f8f529cd3..49a791709b 100644 --- a/src/Campaigns/Migrations/MigrateFormsToCampaignForms.php +++ b/src/Campaigns/Migrations/MigrateFormsToCampaignForms.php @@ -2,14 +2,11 @@ namespace Give\Campaigns\Migrations; -use DateTime; -use Give\Campaigns\Models\Campaign; -use Give\Campaigns\ValueObjects\CampaignStatus; -use Give\Campaigns\ValueObjects\CampaignType; -use Give\DonationForms\Models\DonationForm; -use Give\DonationForms\ValueObjects\DonationFormStatus; use Give\Framework\Database\DB; +use Give\Framework\Database\Exceptions\DatabaseQueryException; use Give\Framework\Migrations\Contracts\Migration; +use Give\Framework\Migrations\Exceptions\DatabaseMigrationException; +use Give\Framework\QueryBuilder\JoinQueryBuilder; /** * @unreleased @@ -29,66 +26,152 @@ public static function id(): string */ public static function timestamp(): int { - return strtotime('2024-08-21'); + return strtotime('2024-08-26 00:00:01'); } /** * @unreleased * @inheritDoc + * @throws \Exception */ public function run() { - foreach(DonationForm::query()->getAll() ?? [] as $form) { - $this->createParentCampaignForDonationForm($form); - } + DB::transaction(function() { + try { + array_map([$this, 'createCampaignForForm'], $this->getFormData()); + array_map([$this, 'addUpgradedFormToCampaign'], $this->getUpgradedFormData()); + } catch (DatabaseQueryException $exception) { + DB::rollback(); + throw new DatabaseMigrationException('An error occurred while creating initial campaigns', 0, $exception); + } + }); + } + + /** + * @unreleased + */ + protected function getFormData(): array + { + $query = DB::table('posts', 'forms') + ->select( + ['forms.ID', 'id'], + ['forms.post_title', 'title'], + ['forms.post_status', 'status'], + ['forms.post_date', 'createdAt'] + ) + ->where('forms.post_type', 'give_forms'); + + $query->select(['formmeta.meta_value', 'settings']) + ->join(function (JoinQueryBuilder $builder) { + $builder + ->leftJoin('give_formmeta', 'formmeta') + ->on('formmeta.form_id', 'forms.ID'); + }) + ->where('formmeta.meta_key', 'formBuilderSettings'); + + // Exclude forms already associated with a campaign (ie Peer-to-peer). + $query->join(function (JoinQueryBuilder $builder) { + $builder + ->leftJoin('give_campaigns', 'campaigns') + ->on('campaigns.form_id', 'forms.ID'); + }) + ->whereIsNull('campaigns.id'); + + // Exclude forms with an `upgraded` status, which are archived. + $query->where('forms.post_status', 'upgraded', '!='); + + return $query->getAll(); } /** * @unreleased + * @return array [{formId, campaignId, migratedFormId}] */ - public function createParentCampaignForDonationForm(DonationForm $form) + protected function getUpgradedFormData(): array { - $campaign = Campaign::create([ - 'type' => CampaignType::CORE(), - 'title' => $form->title, - 'shortDescription' => $form->settings->formExcerpt, - 'longDescription' => $form->settings->description, - 'logo' => $form->settings->designSettingsLogoUrl, - 'image' => $form->settings->designSettingsImageUrl, - 'primaryColor' => $form->settings->primaryColor, - 'secondaryColor' => $form->settings->secondaryColor, - 'goal' => (int) $form->settings->goalAmount, - 'status' => $this->mapFormStatusToCampaignStatus($form->status), - 'startDate' => new DateTime($form->settings->goalStartDate), - 'endDate' => new DateTime($form->settings->goalEndDate), - ]); + return DB::table('posts', 'forms') + ->select(['forms.ID', 'formId'], ['campaign_forms.campaign_id', 'campaignId']) + ->attachMeta('give_formmeta', 'ID', 'form_id', 'migratedFormId') + ->join(function (JoinQueryBuilder $builder) { + $builder + ->rightJoin('give_campaign_forms', 'campaign_forms') + ->on('campaign_forms.form_id', 'forms.ID'); + }) + ->where('forms.post_type', 'give_forms') + ->whereIsNotNull('give_formmeta_attach_meta_migratedFormId.meta_value') + ->getAll(); + } + + /** + * @unreleased + */ + public function createCampaignForForm($formData): void + { + $formId = $formData->id; + $formTitle = $formData->title; + $formStatus = $formData->status; + $formCreatedAt = $formData->createdAt; + $formSettings = json_decode($formData->settings); + + $campaignId = DB::table('give_campaigns') + ->insert([ + 'campaign_type' => 'core', + 'campaign_title' => $formTitle, + 'status' => $this->mapFormToCampaignStatus($formStatus), + 'short_desc' => $formSettings->formExcerpt, + 'long_desc' => $formSettings->description, + 'campaign_logo' => $formSettings->designSettingsLogoUrl, + 'campaign_image' => $formSettings->designSettingsImageUrl, + 'primary_color' => $formSettings->primaryColor, + 'secondary_color' => $formSettings->secondaryColor, + 'campaign_goal' => $formSettings->goalAmount, + 'start_date' => $formSettings->goalStartDate, + 'end_date' => $formSettings->goalEndDate, + 'date_created' => $formCreatedAt, + ]); DB::table('give_campaign_forms') ->insert([ - 'form_id' => $form->id, - 'campaign_id' => $campaign->id, + 'form_id' => $formId, + 'campaign_id' => $campaignId, + 'is_default' => true, ]); } - /** + /** + * @param $data + */ + protected function addUpgradedFormToCampaign($data): void + { + DB::table('give_campaign_forms') + ->insert([ + 'form_id' => $data->migratedFormId, + 'campaign_id' => $data->campaignId, + ]); + } + + /** * @unreleased */ - public function mapFormStatusToCampaignStatus(DonationFormStatus $status) + public function mapFormToCampaignStatus(string $status): string { switch ($status) { - case DonationFormStatus::PUBLISHED(): - case DonationFormStatus::UPGRADED(): // TODO: How do we handle upgraded, non-upgraded forms? - case DonationFormStatus::PRIVATE(): // TODO: How do we handle Private forms? - return CampaignStatus::ACTIVE(); - case DonationFormStatus::PENDING(): - return CampaignStatus::PENDING(); + case 'pending': + return 'pending'; + + case 'draft': + return 'draft'; + + case 'trash': + return 'inactive'; - case DonationFormStatus::DRAFT(): - return CampaignStatus::DRAFT(); + case 'publish': + case 'private': + return 'active'; - case DonationFormStatus::TRASH(): - return CampaignStatus::INACTIVE(); + default: // TODO: How do we handle an unknown form status? + return 'inactive'; } } } diff --git a/src/Campaigns/Migrations/Tables/CreateCampaignFormsTable.php b/src/Campaigns/Migrations/Tables/CreateCampaignFormsTable.php index 49c32034c2..92e58b6c57 100644 --- a/src/Campaigns/Migrations/Tables/CreateCampaignFormsTable.php +++ b/src/Campaigns/Migrations/Tables/CreateCampaignFormsTable.php @@ -51,6 +51,7 @@ public function run(): void $sql = "CREATE TABLE $table ( campaign_id INT UNSIGNED NOT NULL, form_id INT UNSIGNED NOT NULL, + is_default BOOLEAN NOT NULL DEFAULT 0, KEY form_id (form_id), KEY campaign_id (campaign_id), PRIMARY KEY (campaign_id, form_id) diff --git a/src/Campaigns/Models/Campaign.php b/src/Campaigns/Models/Campaign.php index a858c6f7bf..c22f8e438e 100644 --- a/src/Campaigns/Models/Campaign.php +++ b/src/Campaigns/Models/Campaign.php @@ -59,6 +59,16 @@ class Campaign extends Model implements ModelCrud, ModelHasFactory 'createdAt' => DateTime::class, ]; + /** + * @unreleased + */ + public function form(): DonationForm + { + return $this->forms() + ->where('campaign_forms.is_default', true) + ->get(); + } + /** * @unreleased */ diff --git a/tests/Unit/Campaigns/Migrations/MigrateFormsToCampaignFormsTest.php b/tests/Unit/Campaigns/Migrations/MigrateFormsToCampaignFormsTest.php index 382a955979..b763b7653b 100644 --- a/tests/Unit/Campaigns/Migrations/MigrateFormsToCampaignFormsTest.php +++ b/tests/Unit/Campaigns/Migrations/MigrateFormsToCampaignFormsTest.php @@ -5,6 +5,7 @@ use Give\Campaigns\Migrations\MigrateFormsToCampaignForms; use Give\Campaigns\Models\Campaign; use Give\DonationForms\Models\DonationForm; +use Give\DonationForms\ValueObjects\DonationFormStatus; use Give\Framework\Database\DB; use Give\Tests\TestCase; use Give\Tests\TestTraits\RefreshDatabase; @@ -24,11 +25,82 @@ public function testCreatesParentCampaignForDonationForm() $form = DonationForm::factory()->create(); $migration = new MigrateFormsToCampaignForms(); - $migration->createParentCampaignForDonationForm($form); + $migration->run(); $relationship = DB::table('give_campaign_forms')->where('form_id', $form->id)->get(); $this->assertNotNull(Campaign::find($relationship->campaign_id)); $this->assertEquals($form->id, $relationship->form_id); } + + /** + * @unreleased + */ + public function testExistingPeerToPeerCampaignFormsAreNotMigrated() + { + $form = DonationForm::factory()->create(); + DB::table('give_campaigns')->insert([ + 'form_id' => $form->id, + ]); + + $migration = new MigrateFormsToCampaignForms(); + $migration->run(); + + $relationship = DB::table('give_campaign_forms')->where('form_id', $form->id)->get(); + + $this->assertNull($relationship); + $this->assertEquals(1, DB::table('give_campaigns')->count()); + } + + /** + * @unreleased + */ + public function testUpgradedFormsAreNotMigrated() + { + $form = DonationForm::factory()->create([ + 'status' => DonationFormStatus::UPGRADED(), + ]); + + $migration = new MigrateFormsToCampaignForms(); + $migration->run(); + + $relationship = DB::table('give_campaign_forms')->where('form_id', $form->id)->get(); + + $this->assertNull($relationship); + $this->assertEquals(0, DB::table('give_campaigns')->count()); + } + + /** + * @unreleased + */ + public function testMigratedFormsAreDefault() + { + $form = DonationForm::factory()->create(); + + $migration = new MigrateFormsToCampaignForms(); + $migration->run(); + + $relationship = DB::table('give_campaign_forms')->where('form_id', $form->id)->get(); + + $this->assertEquals(1, $relationship->is_default); + } + + /** + * @unreleased + */ + public function testUpgradedFormsAreNotDefault() + { + $form1 = DonationForm::factory()->create([ + 'status' => DonationFormStatus::UPGRADED(), + ]); + $form2 = DonationForm::factory()->create(); + give_update_meta($form2->id, 'migratedFormId', $form1->id); + + $migration = new MigrateFormsToCampaignForms(); + $migration->run(); + + $relationship = DB::table('give_campaign_forms')->where('form_id', $form1->id)->get(); + + $this->assertEquals(0, $relationship->is_default); + } } diff --git a/tests/Unit/Campaigns/Models/CampaignModelTest.php b/tests/Unit/Campaigns/Models/CampaignModelTest.php index 5b3b20abda..d421f736cc 100644 --- a/tests/Unit/Campaigns/Models/CampaignModelTest.php +++ b/tests/Unit/Campaigns/Models/CampaignModelTest.php @@ -42,4 +42,20 @@ public function testCampaignHasManyForms() $this->assertEquals(2, $campaign->forms()->count()); } + + /** + * @unreleased + */ + public function testCampaignHasDefaultForm() + { + $campaign = Campaign::factory()->create(); + $form1 = DonationForm::factory()->create(); + $form2 = DonationForm::factory()->create(); + + $db = DB::table('give_campaign_forms'); + $db->insert(['form_id' => $form1->id, 'campaign_id' => $campaign->id, 'is_default' => 1]); + $db->insert(['form_id' => $form2->id, 'campaign_id' => $campaign->id]); + + $this->assertEquals($form1->id, $campaign->form()->id); + } }