Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Epic: Campaigns #7506

Draft
wants to merge 88 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
9482b84
chore: Add Campaigns domain
kjohnson Aug 21, 2024
3a9a502
chore: Add Campaigns service provider
kjohnson Aug 21, 2024
a56ea7b
Feature: add campaigns menu item and initial empty page (#7511)
glaubersilva Aug 22, 2024
3741176
Create campaign tables (#7519)
alaca Aug 27, 2024
b13f5ff
Feature: Add Campaign model and repository (#7520)
alaca Aug 28, 2024
3f1b23f
Merge branch 'develop' into epic/campaigns
kjohnson Aug 28, 2024
0b24a19
Feature: Add migration to create initial campaigns from existing dona…
kjohnson Aug 28, 2024
f12b328
Feature: Add campaign pages (#7510)
kjohnson Sep 3, 2024
99d42e5
Feature: add list table for campaigns (#7524)
glaubersilva Sep 5, 2024
fac70e4
Feature: Relate Campaigns to Donation Forms with one-to-many relation…
kjohnson Sep 5, 2024
e288b63
Feature: add campaign details page (#7531)
glaubersilva Sep 6, 2024
979c5c0
Refactor: Exclude P2P Campaigns from core query (#7534)
kjohnson Sep 10, 2024
aa54987
Refactor: Update Forms to Campaigns migration (#7532)
kjohnson Sep 12, 2024
9be3b13
Merge branch 'develop' into epic/campaigns
kjohnson Sep 12, 2024
05fe5be
Feature: Add query builder for Campaign Donations (#7544)
kjohnson Sep 18, 2024
4314f8b
Merge branch 'develop' into epic/campaigns
kjohnson Sep 18, 2024
9bbaa90
Merge branch 'develop' into epic/campaigns
kjohnson Sep 20, 2024
38ca04d
Feature: add campaign details page header with tabs, save buttons, an…
glaubersilva Sep 23, 2024
155924a
Feature: Add endpoint for Campaign Overview Statistics (#7545)
kjohnson Sep 25, 2024
da95ba6
Merge branch 'develop' into epic/campaigns
kjohnson Sep 25, 2024
67011c2
Feature: add create new campaign flow (#7543)
glaubersilva Oct 1, 2024
e961e42
Feature: Campaign Settings tab (#7547)
alaca Oct 1, 2024
7abceb8
Feature: add Forms tab to the campaign details page (#7555)
glaubersilva Oct 3, 2024
92e2ae4
Feature: Add campaign overview statistics (#7559)
kjohnson Oct 4, 2024
5a4570c
Refactor: add new styles for list table views (#7558)
glaubersilva Oct 8, 2024
49678f6
Merge branch 'develop' into epic/campaigns
glaubersilva Oct 8, 2024
bb241ae
fix: fatal errors while updating goal and goalType
glaubersilva Oct 8, 2024
41a64c3
fix: campaign status filter
glaubersilva Oct 8, 2024
380ebc5
fix: migration missing campaign id
glaubersilva Oct 8, 2024
3e40b7c
fix: missing tab navigation through browser back and forward buttons
glaubersilva Oct 8, 2024
63219f8
Feature: Archive campaigns (#7565)
alaca Oct 14, 2024
520f2a3
Feature: add campaign goal types for recurring donations (#7567)
glaubersilva Oct 14, 2024
834138e
Merge branch 'develop' into epic/campaigns
glaubersilva Oct 14, 2024
3618252
Chore: Replace test data from Campaign Stats (#7574)
kjohnson Oct 17, 2024
c9e164b
Feature: Form inherits campaign goal (#7569)
alaca Oct 22, 2024
d2a5dd0
Feature: add Option-Based Form Editor feature flag (#7571)
glaubersilva Oct 22, 2024
f799ebc
Feature: add update default form method and missing tests for new met…
glaubersilva Oct 25, 2024
78417d7
Refactor: Update goal progress widget styles (#7591)
kjohnson Oct 28, 2024
54a6279
Feature: Add campaign default form widget (#7584)
kjohnson Oct 31, 2024
18d4c4c
Fix: Check for campaign goal before calculating percentage (#7596)
kjohnson Nov 4, 2024
937c430
Feature: Associate upgraded form to a campaign (#7592)
alaca Nov 6, 2024
1864e84
Feature: add merge campaigns methods (#7597)
glaubersilva Nov 6, 2024
09dce3d
Feature: add merge campaigns endpoint (#7605)
glaubersilva Nov 6, 2024
1dc7949
Fix: remove unnecessary error message when selecting the initial goal…
glaubersilva Nov 7, 2024
cef7414
Fix: goal creation modal should not highlight previous button (#7611)
glaubersilva Nov 7, 2024
1bbd809
Feature: add "Make as default" action to the forms list view (#7606)
glaubersilva Nov 8, 2024
462bd8c
Feature: add merge campaigns UI (#7612)
glaubersilva Nov 8, 2024
f112d87
Update campaign design implementation (#7613)
kjohnson Nov 8, 2024
bcc93c0
Fix: Prevent page refresh when opening the Create Campaign Modal (#7608)
kjohnson Nov 8, 2024
9fe6d37
Feature: add campaign page settings (#7624)
glaubersilva Nov 19, 2024
0409274
Merge branch 'develop' into epic/campaigns
glaubersilva Nov 20, 2024
3ccb57a
refactor: hide the "Switch to Legacy View" button
glaubersilva Nov 20, 2024
45bfa95
Feature: Add revenue data to Campaign Overview (#7588)
kjohnson Nov 20, 2024
da7aa04
Feature: Default form tooltip (#7590)
alaca Nov 21, 2024
670498e
Fix: Update styles for archive campaign modal UI (#7618)
jdghinson Nov 21, 2024
4bc0ecf
Refactor: Update goal progress with campaign entity (#7628)
kjohnson Nov 21, 2024
fd2f0d3
Merge branch 'develop' into epic/campaigns
jonwaldstein Nov 22, 2024
6a0ffad
Merge branch 'develop' into epic/campaigns
glaubersilva Dec 3, 2024
9db67ba
Refactor: Default form (#7616)
alaca Dec 4, 2024
1804935
Feature: Update Campaign Donation Query (#7630)
alaca Dec 4, 2024
25ac81c
Refactor: Campaign status changes (#7639)
alaca Dec 4, 2024
79b02b7
Refactor: Default form functionality (#7640)
alaca Dec 6, 2024
6c67a30
Feature: Add deferred resolution to model factory definitions (#7626)
kjohnson Dec 6, 2024
899fa1b
Refactor: use DonationForm model to create default campaign form (#7638)
JoshuaHungDinh Dec 9, 2024
c9c3e4f
Fix: make entity prop optional (#7644)
alaca Dec 10, 2024
a4648f6
Merge branch 'develop' into epic/campaigns
glaubersilva Dec 10, 2024
3b8580c
Fix: adjust Campaign overview tab styles (#7636)
JoshuaHungDinh Dec 11, 2024
a26e2f6
Refactor: change font-size for modal input descriptions (#7650)
glaubersilva Dec 20, 2024
7dd1436
Refactor: migrate v2 forms to campaigns and add upgraded forms as cam…
glaubersilva Dec 23, 2024
f74bfa9
Merge branch 'develop' into epic/campaigns
glaubersilva Dec 23, 2024
623a3d9
Refactor: adjust Campaign settings page styles (#7646)
JoshuaHungDinh Jan 7, 2025
042ca2b
Refactor: update list table confirmation modals (#7649)
JoshuaHungDinh Jan 7, 2025
63ed1f5
Refactor: Improve Campaign Overview page styling and structure (#7666)
JoshuaHungDinh Jan 13, 2025
a9ba5df
Feature: Add campaign title block (#7648)
pauloiankoski Jan 16, 2025
22bbb3b
Feature: add Campaign Cover Block (#7701)
JoshuaHungDinh Feb 2, 2025
74b417f
Feature: ListTable configuration (#7678)
alaca Feb 3, 2025
760a4bc
Feature: Campaign Donate Button block (#7687)
alaca Feb 3, 2025
d149099
chore: merge develop and fix conflicts
Feb 5, 2025
3056b51
Feature: Add Campaign Donors block (#7700)
pauloiankoski Feb 6, 2025
ca092ad
Feature: Add Campaign Donations block (#7703)
pauloiankoski Feb 6, 2025
d051ea2
Fix: prevent donation details page fatal error (#7711)
jonwaldstein Feb 10, 2025
eab7e73
Fix: Prevent NaN error in Campaign Overview Stat Widget (#7698)
kjohnson Feb 10, 2025
9980846
Feature: Register campaign theme color settings (#7707)
pauloiankoski Feb 13, 2025
dc82528
Refactor: Remove Edit button from default form widget (#7728)
pauloiankoski Feb 13, 2025
6175641
Fix: View Campaign Button (#7721)
alaca Feb 13, 2025
de80d9b
Refactor: update Campaign details to remove hardcoded USD and locale …
jonwaldstein Feb 13, 2025
c655c07
Feature: add campaign stats block (#7726)
JoshuaHungDinh Feb 13, 2025
fb9fb72
Feature: Campaign Goal Block (#7702)
alaca Feb 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor: Update Forms to Campaigns migration (#7532)
  • Loading branch information
kjohnson authored Sep 12, 2024
commit aa5498709c7f2c67299f89e571cf4ee32d7874b5
161 changes: 122 additions & 39 deletions src/Campaigns/Migrations/MigrateFormsToCampaignForms.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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';
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions src/Campaigns/Models/Campaign.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}
16 changes: 16 additions & 0 deletions tests/Unit/Campaigns/Models/CampaignModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Loading