Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
thalia
concrexit
Commits
cee45c7c
Unverified
Commit
cee45c7c
authored
Aug 24, 2016
by
Luuk Scholten
Committed by
Thom Wiggers
Aug 25, 2016
Browse files
Add api for getting birthdays of users
parent
841970ff
Changes
8
Hide whitespace changes
Inline
Side-by-side
website/members/api/__init__.py
0 → 100644
View file @
cee45c7c
website/members/api/serializers.py
0 → 100644
View file @
cee45c7c
from
django.urls
import
reverse
from
events.api.serializers
import
CalenderJSSerializer
from
members.models
import
Member
class
MemberBirthdaySerializer
(
CalenderJSSerializer
):
class
Meta
(
CalenderJSSerializer
.
Meta
):
model
=
Member
def
_start
(
self
,
instance
):
return
instance
.
birthday
def
_end
(
self
,
instance
):
pass
def
_all_day
(
self
,
instance
):
return
True
def
_is_birthday
(
self
,
instance
):
return
True
def
_url
(
self
,
instance
):
return
reverse
(
'#'
)
def
_title
(
self
,
instance
):
return
instance
.
display_name
()
def
_description
(
self
,
instance
):
membership
=
instance
.
current_membership
if
membership
and
membership
.
type
==
'honorary'
:
return
instance
.
membership
.
get_type_display
()
return
''
def
_background_color
(
self
,
instance
):
membership
=
instance
.
current_membership
if
membership
and
membership
.
type
==
'honorary'
:
return
'#E62272'
return
'black'
def
_text_color
(
self
,
instance
):
return
'white'
website/members/api/urls.py
0 → 100644
View file @
cee45c7c
from
rest_framework
import
routers
from
members.api
import
viewsets
router
=
routers
.
SimpleRouter
()
router
.
register
(
r
'members'
,
viewsets
.
MemberViewset
)
urlpatterns
=
router
.
urls
website/members/api/viewsets.py
0 → 100644
View file @
cee45c7c
from
django.utils
import
timezone
from
rest_framework
import
viewsets
from
rest_framework.decorators
import
list_route
from
datetime
import
datetime
import
copy
from
rest_framework.exceptions
import
ParseError
from
rest_framework.response
import
Response
from
members.api.serializers
import
MemberBirthdaySerializer
from
members.models
import
Member
class
MemberViewset
(
viewsets
.
ViewSet
):
queryset
=
Member
.
objects
.
all
()
def
_get_birthdays
(
self
,
member
,
start
,
end
):
birthdays
=
[]
start_year
=
max
(
start
.
year
,
member
.
birthday
.
year
)
for
year
in
range
(
start_year
,
end
.
year
+
1
):
bday
=
copy
.
deepcopy
(
member
)
bday
.
birthday
=
bday
.
birthday
.
replace
(
year
=
year
)
if
start
.
date
()
<=
bday
.
birthday
<=
end
.
date
():
birthdays
.
append
(
bday
)
return
birthdays
@
list_route
()
def
birthdays
(
self
,
request
):
try
:
start
=
timezone
.
make_aware
(
datetime
.
strptime
(
request
.
query_params
[
'start'
],
'%Y-%m-%d'
)
)
end
=
timezone
.
make_aware
(
datetime
.
strptime
(
request
.
query_params
[
'end'
],
'%Y-%m-%d'
)
)
except
:
raise
ParseError
(
detail
=
'start or end query parameters invalid'
)
queryset
=
(
Member
.
active_members
.
with_birthdays_in_range
(
start
,
end
)
.
filter
(
show_birthday
=
True
)
)
queryset
.
prefetch_related
(
'membership_get'
)
all_birthdays
=
[
self
.
_get_birthdays
(
m
,
start
,
end
)
for
m
in
queryset
.
all
()
]
birthdays
=
[
x
for
sublist
in
all_birthdays
for
x
in
sublist
]
serializer
=
MemberBirthdaySerializer
(
birthdays
,
many
=
True
)
return
Response
(
serializer
.
data
)
website/members/fixtures/members.json
View file @
cee45c7c
...
...
@@ -130,5 +130,15 @@
"direct_debit_authorized"
:
false
,
"bank_account"
:
""
}
},
{
"model"
:
"members.membership"
,
"pk"
:
1
,
"fields"
:
{
"type"
:
"member"
,
"user"
:
1
,
"since"
:
"1980-01-01"
,
"until"
:
null
}
}
]
website/members/models.py
View file @
cee45c7c
...
...
@@ -4,6 +4,9 @@ from django.db.models import Q
from
django.core
import
validators
from
django.conf
import
settings
from
django.utils.translation
import
ugettext_lazy
as
_
from
datetime
import
timedelta
import
operator
from
functools
import
reduce
from
localflavor.generic.countries.sepa
import
IBAN_SEPA_COUNTRIES
from
localflavor.generic.models
import
IBANField
...
...
@@ -19,6 +22,25 @@ class ActiveMemberManager(models.Manager):
.
filter
(
Q
(
user__membership__until__isnull
=
True
)
|
Q
(
user__membership__until__gt
=
timezone
.
now
().
date
())))
def
with_birthdays_in_range
(
self
,
from_date
,
to_date
):
queryset
=
self
.
get_queryset
().
filter
(
birthday__lte
=
to_date
)
if
(
to_date
-
from_date
).
days
>=
366
:
# 366 is important to also account for leap years
# Everyone that's born before to_date has a birthday
return
queryset
delta
=
to_date
-
from_date
dates
=
[
from_date
+
timedelta
(
days
=
i
)
for
i
in
range
(
delta
.
days
+
1
)]
monthdays
=
[
{
"birthday__month"
:
d
.
month
,
"birthday__day"
:
d
.
day
}
for
d
in
dates
]
# Don't get me started (basically, we are making a giant OR query with
# all days and months that are in the range)
query
=
reduce
(
operator
.
or_
,
[
Q
(
**
d
)
for
d
in
monthdays
])
return
queryset
.
filter
(
query
)
class
Member
(
models
.
Model
):
"""This class describes a member"""
...
...
website/members/tests.py
View file @
cee45c7c
# Create your tests here.
from
datetime
import
datetime
from
django.test
import
TestCase
from
django.utils
import
timezone
from
members.models
import
Member
class
MemberBirthdayTest
(
TestCase
):
fixtures
=
[
'members.json'
]
def
_make_date
(
self
,
date
):
return
timezone
.
make_aware
(
datetime
.
strptime
(
date
,
'%Y-%m-%d'
))
def
_get_members
(
self
,
start
,
end
):
start_date
=
self
.
_make_date
(
start
)
end_date
=
self
.
_make_date
(
end
)
return
Member
.
active_members
.
with_birthdays_in_range
(
start_date
,
end_date
)
def
_assert_none
(
self
,
start
,
end
):
members
=
self
.
_get_members
(
start
,
end
)
self
.
assertEquals
(
len
(
members
),
0
)
def
_assert_thom
(
self
,
start
,
end
):
members
=
self
.
_get_members
(
start
,
end
)
self
.
assertEquals
(
len
(
members
),
1
)
self
.
assertEquals
(
members
[
0
].
get_full_name
(),
'Thom Wiggers'
)
def
test_one_year_contains_birthday
(
self
):
self
.
_assert_thom
(
'2016-03-02'
,
'2016-08-08'
)
def
test_one_year_not_contains_birthday
(
self
):
self
.
_assert_none
(
'2016-01-01'
,
'2016-02-01'
)
def
test_span_year_contains_birthday
(
self
):
self
.
_assert_thom
(
'2015-08-09'
,
'2016-08-08'
)
def
test_span_year_not_contains_birthday
(
self
):
self
.
_assert_none
(
'2015-12-25'
,
'2016-03-01'
)
def
test_span_multiple_years_contains_birthday
(
self
):
self
.
_assert_thom
(
'2012-12-31'
,
'2016-01-01'
)
def
test_range_before_person_born
(
self
):
self
.
_assert_none
(
'1985-12-12'
,
'1985-12-13'
)
def
test_person_born_in_range_in_one_year
(
self
):
self
.
_assert_thom
(
'1993-01-01'
,
'1993-04-01'
)
def
test_person_born_in_range_spanning_one_year
(
self
):
self
.
_assert_thom
(
'1992-12-31'
,
'1993-04-01'
)
def
test_person_born_in_range_spanning_multiple_years
(
self
):
self
.
_assert_thom
(
'1992-12-31'
,
'1995-01-01'
)
website/thaliawebsite/urls.py
View file @
cee45c7c
...
...
@@ -65,6 +65,7 @@ urlpatterns = [
url
(
r
'^private-thumbnails/(?P<size_fit>\d+x\d+_[01])/(?P<path>.*)'
,
private_thumbnails
,
name
=
'private-thumbnails'
),
url
(
r
'^api/'
,
include
([
url
(
r
'^'
,
include
(
'events.api.urls'
)),
url
(
r
'^'
,
include
(
'members.api.urls'
)),
])),
# Default login helpers
url
(
r
'^'
,
include
(
'django.contrib.auth.urls'
)),
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment