Skip to content

Commit

Permalink
Merge pull request #5184 from onepercentclub/hotfix/BB-20295-change-e…
Browse files Browse the repository at this point in the history
…mail-content

Change email for team joined + test
  • Loading branch information
gannetson committed Aug 8, 2022
2 parents 1d6d26f + 8d6a16e commit d72cc53
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 44 deletions.
56 changes: 56 additions & 0 deletions bluebottle/activities/tests/test_triggers.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,62 @@ def test_withdrawn(self):
for contribution in self.participant.contributions.all():
self.assertEqual(contribution.status, TimeContributionStateMachine.failed.value)

def test_fill_team_activity(self):
self.activity.capacity = 2
self.activity.team_activity = 'teams'
self.activity.save()

captain = PeriodParticipantFactory.create(
activity=self.activity,
user=BlueBottleUserFactory.create(),
as_relation='user',
)
participant = PeriodParticipantFactory.create(
activity=self.activity,
user=BlueBottleUserFactory.create(),
as_relation='user',
team=captain.team
)
self.activity.refresh_from_db()
self.assertEqual(
self.activity.status,
'open'
)
PeriodParticipantFactory.create(
activity=self.activity,
user=BlueBottleUserFactory.create(),
as_relation='user',
)
self.assertEqual(
self.activity.status,
'full'
)

captain.states.withdraw(save=True)
self.assertEqual(
captain.team.status,
'open',
)
self.assertEqual(
self.activity.status,
'full',
)
self.assertEqual(
participant.status,
'accepted',
)
self.model = captain.team
self.model.states.withdraw(save=True)

self.assertStatus(
captain.team,
'withdrawn',
)
self.assertStatus(
self.activity,
'open',
)

def test_reapply(self):
self.create()

Expand Down
83 changes: 63 additions & 20 deletions bluebottle/activities/triggers.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
from bluebottle.activities.models import Organizer, EffortContribution, Team
from bluebottle.fsm.triggers import (
TriggerManager, TransitionTrigger, ModelDeletedTrigger, register
)
from bluebottle.fsm.effects import TransitionEffect, RelatedTransitionEffect
from bluebottle.notifications.effects import NotificationEffect

from bluebottle.activities.states import (
ActivityStateMachine, OrganizerStateMachine, ContributionStateMachine,
EffortContributionStateMachine, TeamStateMachine
)
from bluebottle.activities.effects import (
CreateOrganizer, CreateOrganizerContribution, SetContributionDateEffect,
TeamContributionTransitionEffect, ResetTeamParticipantsEffect
)

from bluebottle.activities.messages import (
TeamAddedMessage, TeamCancelledMessage, TeamReopenedMessage, TeamAcceptedMessage, TeamAppliedMessage,
TeamWithdrawnMessage, TeamWithdrawnActivityOwnerMessage, TeamCancelledTeamCaptainMessage,
TeamReappliedMessage
TeamAddedMessage, TeamReopenedMessage, TeamAcceptedMessage, TeamAppliedMessage,
TeamWithdrawnMessage, TeamWithdrawnActivityOwnerMessage, TeamReappliedMessage, TeamCancelledMessage,
TeamCancelledTeamCaptainMessage
)
from bluebottle.activities.models import Organizer, EffortContribution, Team
from bluebottle.activities.states import (
ActivityStateMachine, OrganizerStateMachine, ContributionStateMachine,
EffortContributionStateMachine, TeamStateMachine
)
from bluebottle.fsm.effects import TransitionEffect, RelatedTransitionEffect
from bluebottle.fsm.triggers import (
TriggerManager, TransitionTrigger, ModelDeletedTrigger, register
)

from bluebottle.time_based.states import ParticipantStateMachine
from bluebottle.impact.effects import UpdateImpactGoalEffect
from bluebottle.notifications.effects import NotificationEffect
from bluebottle.time_based.states import ParticipantStateMachine, TimeBasedStateMachine


def initiative_is_approved(effect):
Expand Down Expand Up @@ -232,6 +229,31 @@ def needs_review(effect):
return hasattr(effect.instance.activity, 'review') and effect.instance.activity.review


def team_activity_will_be_full(effect):
"""
the activity is full
"""
activity = effect.instance.activity
accepted_teams = activity.teams.filter(status__in=['open', 'running', 'finished']).count() + 1
return not hasattr(activity, 'capacity') or (
activity.capacity and
activity.capacity <= accepted_teams
)


def team_activity_will_not_be_full(effect):
"""
the activity is full
"""
activity = effect.instance.activity
accepted_teams = activity.teams.filter(status__in=['open', 'running', 'finished']).count() - 1

return (
not getattr(activity, 'capacity', False) or
activity.capacity > accepted_teams
)


@register(Team)
class TeamTriggers(TriggerManager):
triggers = [
Expand Down Expand Up @@ -266,13 +288,23 @@ class TeamTriggers(TriggerManager):
'members',
ParticipantStateMachine.accept,
conditions=[needs_review]
)
),
RelatedTransitionEffect(
'activity',
TimeBasedStateMachine.lock,
conditions=[team_activity_will_be_full]
),
]
),

TransitionTrigger(
TeamStateMachine.cancel,
effects=[
RelatedTransitionEffect(
'activity',
TimeBasedStateMachine.reopen,
conditions=[team_activity_will_not_be_full]
),
TeamContributionTransitionEffect(ContributionStateMachine.fail),
NotificationEffect(TeamCancelledMessage),
NotificationEffect(TeamCancelledTeamCaptainMessage)
Expand All @@ -282,6 +314,11 @@ class TeamTriggers(TriggerManager):
TransitionTrigger(
TeamStateMachine.withdraw,
effects=[
RelatedTransitionEffect(
'activity',
TimeBasedStateMachine.reopen,
conditions=[team_activity_will_not_be_full]
),
TeamContributionTransitionEffect(ContributionStateMachine.fail),
NotificationEffect(TeamWithdrawnMessage),
NotificationEffect(TeamWithdrawnActivityOwnerMessage)
Expand All @@ -294,7 +331,10 @@ class TeamTriggers(TriggerManager):
NotificationEffect(TeamReopenedMessage),
TeamContributionTransitionEffect(
ContributionStateMachine.reset,
contribution_conditions=[activity_is_active, contributor_is_active]
contribution_conditions=[
activity_is_active,
contributor_is_active
]
),

]
Expand All @@ -305,7 +345,10 @@ class TeamTriggers(TriggerManager):
effects=[
TeamContributionTransitionEffect(
ContributionStateMachine.reset,
contribution_conditions=[activity_is_active, contributor_is_active]
contribution_conditions=[
activity_is_active,
contributor_is_active
]
),
NotificationEffect(TeamReappliedMessage),
NotificationEffect(TeamAddedMessage)
Expand Down
3 changes: 2 additions & 1 deletion bluebottle/test/test_runner.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import locale
from builtins import range

from django.conf import settings
from django.db import connection, IntegrityError
from django_slowtests.testrunner import DiscoverSlowestTestsRunner
from djmoney.contrib.exchange.models import Rate, ExchangeBackend
Expand All @@ -11,7 +12,7 @@

class MultiTenantRunner(DiscoverSlowestTestsRunner, InitProjectDataMixin):
def setup_databases(self, *args, **kwargs):

self.keepdb = getattr(settings, 'KEEPDB', self.keepdb)
parallel = self.parallel
self.parallel = 0
result = super(MultiTenantRunner, self).setup_databases(**kwargs)
Expand Down
4 changes: 4 additions & 0 deletions bluebottle/test/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,10 @@ def _hasEffect(self, effect_cls, model=None):
if effect == effect_cls(model):
return effect

def assertStatus(self, obj, status):
obj.refresh_from_db()
return self.assertEqual(obj.status, status)

def assertTransitionEffect(self, transition, model=None):
if not self._hasTransitionEffect(transition, model):
self.fail('Transition effect "{}" not triggered'.format(transition))
Expand Down
10 changes: 8 additions & 2 deletions bluebottle/time_based/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ class TimeBasedActivity(Activity):
(True, 'Yes, anywhere/online'),
(False, 'No, enter a location')
)
capacity = models.PositiveIntegerField(_('attendee limit'), null=True, blank=True)
capacity = models.PositiveIntegerField(
_('attendee limit'),
help_text=_('Number of participants or teams that can join'),
null=True, blank=True)

old_is_online = models.NullBooleanField(
_('is online'),
Expand Down Expand Up @@ -64,7 +67,10 @@ class TimeBasedActivity(Activity):
on_delete=models.SET_NULL
)

review = models.NullBooleanField(_('review participants'), null=True, default=None)
review = models.NullBooleanField(
_('review participants'),
help_text=_('Activity manager accepts or rejects participants or teams'),
null=True, default=None)

preparation = models.DurationField(
_('Preparation time'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@
<b>{{ title }}</b>
</p>

{% if duration %}
{% include 'mails/messages/partial/period.html' %}
{% else %}
{% include 'mails/messages/partial/slots.html' %}

{% endif %}
<p>
The activity manager will be in touch to confirm details such as time, date and location. You can start inviting team members, or wait until the details have been set.
</p>

<p>
<i>
Expand Down
20 changes: 19 additions & 1 deletion bluebottle/time_based/tests/test_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
ParticipantWithdrewNotification, NewParticipantNotification, ParticipantAddedOwnerNotification,
ParticipantRemovedOwnerNotification, ParticipantJoinedNotification, ParticipantAppliedNotification,
SlotCancelledNotification, ParticipantAddedNotification, TeamParticipantAddedNotification,
TeamSlotChangedNotification
TeamSlotChangedNotification, TeamParticipantJoinedNotification
)
from bluebottle.time_based.tests.factories import DateActivityFactory, DateParticipantFactory, \
DateActivitySlotFactory, PeriodActivityFactory, PeriodParticipantFactory, TeamSlotFactory
Expand Down Expand Up @@ -232,6 +232,24 @@ def test_participant_joined_notification(self):
'Go to the activity page to see the times in your own timezone and add them to your calendar.'
)

def test_team_joined_notification(self):
self.activity.team_activity = 'teams'
self.activity.save()
self.obj.team = TeamFactory.create()
self.obj.save()
self.message_class = TeamParticipantJoinedNotification
self.create()
self.assertRecipients([self.supporter])
self.assertSubject('You have registered your team for "Save the world!"')
self.assertActionLink(self.activity.get_absolute_url())
self.assertActionTitle('View activity')
self.assertBodyNotContains(
'Go to the activity page to see the times in your own timezone and add them to your calendar.'
)
self.assertBodyContains(
'The activity manager will be in touch to confirm details'
)

def test_new_participant_notification(self):
self.message_class = ParticipantAppliedNotification
self.create()
Expand Down
Loading

0 comments on commit d72cc53

Please sign in to comment.