Skip to content

Commit

Permalink
Merge 8553b7c into 8ffbcc1
Browse files Browse the repository at this point in the history
  • Loading branch information
gannetson committed Oct 4, 2022
2 parents 8ffbcc1 + 8553b7c commit 3d8dd80
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ install:
- pip install pip==20.2.1
- pip install setuptools
- pip install wheel==0.29.0
- pip install --upgrade -I flake8==3.9.2
- pip install --upgrade -I flake8==5.0.4
- pip install -e .[test] --trusted-host github.com
before_script:
- flake8 .
Expand Down
8 changes: 6 additions & 2 deletions bluebottle/activities/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,6 @@ def save_model(self, request, obj, form, change):

office_fields = (
'office_location',
'office_restriction',
)

description_fields = (
Expand Down Expand Up @@ -430,7 +429,12 @@ def get_fieldsets(self, request, obj=None):
(_('Description'), {'fields': self.get_description_fields(request, obj)}),
(_('Status'), {'fields': self.get_status_fields(request, obj)}),
]
if settings.enable_office_regions:

if Location.objects.count():
if settings.enable_office_restrictions and 'office_restriction' not in self.office_fields:
self.office_fields += (
'office_restriction',
)
fieldsets.insert(1, (
_('Office'), {'fields': self.office_fields}
))
Expand Down
29 changes: 24 additions & 5 deletions bluebottle/activities/documents.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from builtins import str

from django_elasticsearch_dsl import Document, fields
from elasticsearch_dsl.field import DateRange

from bluebottle.activities.models import Activity
from bluebottle.funding.models import Donor
from bluebottle.initiatives.models import Initiative, Theme
from bluebottle.members.models import Member
from bluebottle.utils.documents import MultiTenantIndex
from bluebottle.activities.models import Activity
from bluebottle.utils.search import Search
from elasticsearch_dsl.field import DateRange
from bluebottle.members.models import Member

from bluebottle.initiatives.models import Initiative, Theme


class DateRangeField(fields.DEDField, DateRange):
Expand Down Expand Up @@ -110,6 +110,16 @@ class ActivityDocument(Document):
}
)

office_restriction = fields.NestedField(
attr='office_restriction',
properties={
'restriction': fields.TextField(),
'office': fields.LongField(),
'office_subregion': fields.LongField(),
'office_region': fields.LongField(),
}
)

contributors = fields.DateField()
contributor_count = fields.IntegerField()
donation_count = fields.IntegerField()
Expand Down Expand Up @@ -233,6 +243,15 @@ def prepare_location(self, instance):
})
return locations

def prepare_office_restriction(self, instance):
office = instance.office_location
return {
'restriction': instance.office_restriction,
'office': office.id if office else None,
'subregion': office.subregion.id if office and office.subregion_id else None,
'region': office.subregion.region.id if office and office.subregion and office.subregion.region else None
}

def prepare_expertise(self, instance):
if hasattr(instance, 'expertise') and instance.expertise:
return [
Expand Down
30 changes: 27 additions & 3 deletions bluebottle/activities/filters.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import re
import dateutil
from datetime import datetime, time

import dateutil
from django.conf import settings

from elasticsearch_dsl.function import ScriptScore
from elasticsearch_dsl.query import (
FunctionScore, SF, Terms, Term, Nested, Q, Range, ConstantScore
)
from elasticsearch_dsl.function import ScriptScore

from bluebottle.activities.documents import activity
from bluebottle.geo.models import Location
from bluebottle.initiatives.models import InitiativePlatformSettings
from bluebottle.utils.filters import ElasticSearchFilter


Expand All @@ -34,6 +36,7 @@ class ActivitySearchFilter(ElasticSearchFilter):
'status',
'upcoming',
'location.id',
'office',
'segment',
'team_activity',
'initiative.id',
Expand Down Expand Up @@ -162,6 +165,27 @@ def get_upcoming_filter(self, value, request):
if value == 'false':
return Terms(status=['succeeded', 'partially_funded'])

def get_office_filter(self, value, request):
office = Location.objects.filter(id=value).first()
initiative_settings = InitiativePlatformSettings.load()
if initiative_settings.enable_office_restrictions:
return Nested(
path='office_restriction',
query=Term(
office_restriction__restriction='all'
) | (
Term(office_restriction__office=office.id) &
Term(office_restriction__restriction='office')
) | (
Term(office_restriction__subregion=office.subregion.id) &
Term(office_restriction__restriction='office_subregion')
) | (
Term(office_restriction__region=office.subregion.region.id) &
Term(office_restriction__restriction='office_region')
)
)
return []

def get_duration_filter(self, value, request):
start = request.GET.get('filter[start]')
end = request.GET.get('filter[end]')
Expand Down
92 changes: 92 additions & 0 deletions bluebottle/activities/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from bluebottle.activities.utils import TeamSerializer, InviteSerializer
from bluebottle.activities.serializers import TeamTransitionSerializer
from bluebottle.funding.tests.factories import FundingFactory, DonorFactory
from bluebottle.offices.tests.factories import OfficeRegionFactory, OfficeSubRegionFactory
from bluebottle.time_based.serializers import PeriodParticipantSerializer
from bluebottle.time_based.tests.factories import (
DateActivityFactory, PeriodActivityFactory, DateParticipantFactory, PeriodParticipantFactory,
Expand Down Expand Up @@ -1031,6 +1032,97 @@ def test_filter_segment_mismatch(self):

self.assertEqual(data['meta']['pagination']['count'], 0)

def test_filter_by_office(self):

europe = OfficeRegionFactory.create(name='Europe')
africa = OfficeRegionFactory.create(name='Africa')
netherlands = OfficeSubRegionFactory.create(
region=europe,
name='The Netherlands'
)
bulgaria = OfficeSubRegionFactory.create(
region=europe,
name='Bulgaria'
)
namibia = OfficeSubRegionFactory.create(
region=africa,
name='Nambibia'
)
amsterdam = LocationFactory.create(name='Amsterdam', subregion=netherlands)
leiden = LocationFactory.create(name='Leiden', subregion=netherlands)
lyutidol = LocationFactory.create(name='Lyutidol', subregion=bulgaria)
windhoek = LocationFactory.create(name='Windhoek', subregion=namibia)

DateActivityFactory.create(
office_location=leiden,
status='open',
office_restriction='office'
)
DateActivityFactory.create(
office_location=amsterdam,
status='open',
office_restriction='office_subregion'
)
DateActivityFactory.create(
office_location=amsterdam,
status='open',
office_restriction='office_subregion'
)
DateActivityFactory.create(
office_location=lyutidol,
status='open',
office_restriction='office_region'
)
DateActivityFactory.create(
office_location=windhoek,
status='open',
office_restriction='all'
)
DateActivityFactory.create(
office_location=windhoek,
status='open',
office_restriction='office_region'
)
platform = InitiativePlatformSettings.load()
platform.enable_office_restrictions = False
platform.save()

user = BlueBottleUserFactory.create()
response = self.client.get(self.url, user=user)
data = json.loads(response.content)
self.assertEqual(data['meta']['pagination']['count'], 6)

user = BlueBottleUserFactory.create()
response = self.client.get(f'{self.url}?filter[office]={windhoek.id}', user=user)
data = json.loads(response.content)
self.assertEqual(data['meta']['pagination']['count'], 6)

platform = InitiativePlatformSettings.load()
platform.enable_office_restrictions = True
platform.save()

user = BlueBottleUserFactory.create()
response = self.client.get(self.url, user=user)
data = json.loads(response.content)
self.assertEqual(data['meta']['pagination']['count'], 6)

user = BlueBottleUserFactory.create()
response = self.client.get(f'{self.url}?filter[office]={windhoek.id}', user=user)
data = json.loads(response.content)
self.assertEqual(data['meta']['pagination']['count'], 2)

response = self.client.get(f'{self.url}?filter[office]={leiden.id}', user=user)
data = json.loads(response.content)
self.assertEqual(data['meta']['pagination']['count'], 5)

response = self.client.get(f'{self.url}?filter[office]={lyutidol.id}', user=user)
data = json.loads(response.content)
self.assertEqual(data['meta']['pagination']['count'], 2)

response = self.client.get(f'{self.url}?filter[office]={amsterdam.id}', user=user)
data = json.loads(response.content)
self.assertEqual(data['meta']['pagination']['count'], 4)

def test_search(self):
first = DateActivityFactory.create(
title='Lorem ipsum dolor sit amet',
Expand Down
3 changes: 2 additions & 1 deletion bluebottle/initiatives/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ class InitiativePlatformSettingsAdmin(BasePlatformSettingsAdmin):
(_('Options'), {
'fields': (
'contact_method', 'require_organization',
'enable_impact', 'enable_office_regions', 'enable_multiple_dates',
'enable_impact', 'enable_office_regions', 'enable_office_restrictions',
'enable_multiple_dates',
'enable_open_initiatives', 'enable_participant_exports',
'enable_matching_emails',
)
Expand Down
22 changes: 22 additions & 0 deletions bluebottle/initiatives/migrations/0042_auto_20220928_1600.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 2.2.24 on 2022-09-28 14:00

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import multiselectfield.db.fields
import parler.fields


class Migration(migrations.Migration):

dependencies = [
('initiatives', '0041_merge_20220906_0704'),
]

operations = [
migrations.AddField(
model_name='initiativeplatformsettings',
name='enable_office_restrictions',
field=models.BooleanField(default=False, help_text='Allow activity managers to specify office restrictions on activities.'),
),
]
4 changes: 4 additions & 0 deletions bluebottle/initiatives/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,10 @@ class InitiativePlatformSettings(BasePlatformSettings):
default=False,
help_text=_("Allow admins to add (sub)regions to their offices.")
)
enable_office_restrictions = models.BooleanField(
default=False,
help_text=_("Allow activity managers to specify office restrictions on activities.")
)
enable_multiple_dates = models.BooleanField(
default=False,
help_text=_("Enable date activities to have multiple slots.")
Expand Down
1 change: 1 addition & 0 deletions bluebottle/initiatives/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ class Meta(object):
'contact_method',
'enable_impact',
'enable_office_regions',
'enable_office_restrictions',
'enable_multiple_dates',
'enable_participant_exports',
'enable_open_initiatives',
Expand Down
10 changes: 5 additions & 5 deletions bluebottle/statistics/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,19 +144,19 @@ def setUp(self):
self.user = BlueBottleUserFactory()

activity1 = DateActivityFactory.create()
activity1.created = now().replace(year=2020, month=6)
activity1.created = now().replace(year=2020, month=6, day=12)
activity1.save()
activity2 = DateActivityFactory.create()
activity2.created = now().replace(year=2021, month=10)
activity2.created = now().replace(year=2021, month=10, day=12)
activity2.save()

slot1 = activity1.slots.first()
slot1.start = now().replace(year=2020, month=6)
slot1.start = now().replace(year=2020, month=6, day=12)
slot1.duration = datetime.timedelta(hours=4)
slot1.save()

slot2 = activity2.slots.first()
slot2.start = now().replace(year=2021, month=1)
slot2.start = now().replace(year=2021, month=1, day=12)
slot2.duration = datetime.timedelta(hours=8)
slot2.save()

Expand All @@ -183,7 +183,7 @@ def setUp(self):

donations = DonorFactory.create_batch(3)
for don in donations:
don.created = now().replace(year=2021, month=2)
don.created = now().replace(year=2021, month=2, day=12)
don.save()

Contribution.objects.update(status='succeeded')
Expand Down

0 comments on commit 3d8dd80

Please sign in to comment.