Skip to content

Commit 7b71a22

Browse files
committed
escape semicolons when serializing aggregated activities
1 parent 85fdd54 commit 7b71a22

File tree

1 file changed

+39
-37
lines changed

1 file changed

+39
-37
lines changed

stream_framework/serializers/aggregated_activity_serializer.py

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from stream_framework.utils import epoch_to_datetime, datetime_to_epoch
66
from stream_framework.serializers.base import BaseAggregatedSerializer
77
import six
8+
import re
89

910

1011
class AggregatedActivitySerializer(BaseAggregatedSerializer):
@@ -23,7 +24,6 @@ class AggregatedActivitySerializer(BaseAggregatedSerializer):
2324
#: indicates if dumps returns dehydrated aggregated activities
2425
dehydrate = True
2526
identifier = 'v3'
26-
reserved_characters = [';', ',', ';;']
2727
date_fields = ['created_at', 'updated_at', 'seen_at', 'read_at']
2828

2929
activity_serializer_class = ActivitySerializer
@@ -55,7 +55,8 @@ def dumps(self, aggregated):
5555
else:
5656
for activity in aggregated.activities:
5757
serialized = activity_serializer.dumps(activity)
58-
check_reserved(serialized, [';', ';;'])
58+
# we use semicolons as delimiter, so need to escape
59+
serialized = serialized.replace(";", "\;")
5960
serialized_activities.append(serialized)
6061

6162
serialized_activities_part = ';'.join(serialized_activities)
@@ -71,41 +72,42 @@ def dumps(self, aggregated):
7172

7273
def loads(self, serialized_aggregated):
7374
activity_serializer = self.activity_serializer_class(Activity)
74-
try:
75-
serialized_aggregated = serialized_aggregated[2:]
76-
parts = serialized_aggregated.split(';;')
77-
# start with the group
78-
group = parts[0]
79-
aggregated = self.aggregated_activity_class(group)
80-
81-
# get the date and activities
82-
date_dict = dict(zip(self.date_fields, parts[1:5]))
83-
for k, v in date_dict.items():
84-
date_value = None
85-
if v != '-1':
86-
date_value = epoch_to_datetime(float(v))
87-
setattr(aggregated, k, date_value)
88-
89-
# write the activities
90-
serializations = parts[5].split(';')
91-
if self.dehydrate:
92-
activity_ids = list(map(int, serializations))
93-
aggregated._activity_ids = activity_ids
94-
aggregated.dehydrated = True
95-
else:
96-
activities = [activity_serializer.loads(s)
97-
for s in serializations]
98-
aggregated.activities = activities
99-
aggregated.dehydrated = False
100-
101-
# write the minimized activities
102-
minimized = int(parts[6])
103-
aggregated.minimized_activities = minimized
104-
105-
return aggregated
106-
except Exception as e:
107-
msg = six.text_type(e)
108-
raise SerializationException(msg)
75+
serialized_aggregated = serialized_aggregated[2:]
76+
parts = serialized_aggregated.split(';;')
77+
# start with the group
78+
group = parts[0]
79+
aggregated = self.aggregated_activity_class(group)
80+
81+
# get the date and activities
82+
date_dict = dict(zip(self.date_fields, parts[1:5]))
83+
for k, v in date_dict.items():
84+
date_value = None
85+
if v != '-1':
86+
date_value = epoch_to_datetime(float(v))
87+
setattr(aggregated, k, date_value)
88+
89+
# looks for ; not \;
90+
unescaped_semicolons_regex = re.compile("(?<=[^\\\]);")
91+
# write the activities
92+
serializations = unescaped_semicolons_regex.split(parts[5])
93+
if self.dehydrate:
94+
activity_ids = list(map(int, serializations))
95+
aggregated._activity_ids = activity_ids
96+
aggregated.dehydrated = True
97+
else:
98+
activities = []
99+
for s in serializations:
100+
s = s.replace("\;", ";")
101+
deserialized = activity_serializer.loads(s)
102+
activities.append(deserialized)
103+
aggregated.activities = activities
104+
aggregated.dehydrated = False
105+
106+
# write the minimized activities
107+
minimized = int(parts[6])
108+
aggregated.minimized_activities = minimized
109+
110+
return aggregated
109111

110112

111113
class NotificationSerializer(AggregatedActivitySerializer):

0 commit comments

Comments
 (0)