Skip to content
67 changes: 66 additions & 1 deletion linebot/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
MessageDeliveryBroadcastResponse, MessageDeliveryMulticastResponse,
MessageDeliveryPushResponse, MessageDeliveryReplyResponse,
InsightMessageDeliveryResponse, InsightFollowersResponse, InsightDemographicResponse,
InsightMessageEventResponse, BroadcastResponse,
InsightMessageEventResponse, BroadcastResponse, NarrowcastResponse,
MessageProgressNarrowcastResponse,
)


Expand Down Expand Up @@ -210,6 +211,70 @@ def broadcast(self, messages, notification_disabled=False, timeout=None):

return BroadcastResponse(request_id=response.headers.get('X-Line-Request-Id'))

def narrowcast(self, messages, recipient=None, filter=None, limit=None, timeout=None):
"""Call multicast API.

https://developers.line.biz/en/reference/messaging-api/#send-narrowcast-message

Sends push messages to multiple users at any time.
Messages cannot be sent to groups or rooms.

:param messages: Messages.
Max: 5
:type messages: T <= :py:class:`linebot.models.send_messages.SendMessage` |
list[T <= :py:class:`linebot.models.send_messages.SendMessage`]
:param recipient: audience object of recipient
:type recipient: T <= :py:class:`linebot.models.recipient.AudienceRecipient`
:param filter: demographic filter of recipient
:type filter: T <= :py:class:`linebot.models.filter.DemographicFilter`
:param limit: limit on this narrowcast
:type limit: T <= :py:class:`linebot.models.limit.Limit`
:param timeout: (optional) How long to wait for the server
to send data before giving up, as a float,
or a (connect timeout, read timeout) float tuple.
Default is self.http_client.timeout
:type timeout: float | tuple(float, float)
:rtype: :py:class:`linebot.models.responses.NarrowcastResponse`
"""
if not isinstance(messages, (list, tuple)):
messages = [messages]

data = {
'messages': [message.as_json_dict() for message in messages],
'recipient': recipient.as_json_dict(),
'filter': filter.as_json_dict(),
'limit': limit.as_json_dict(),
}

response = self._post(
'/v2/bot/message/narrowcast', data=json.dumps(data), timeout=timeout
)

return NarrowcastResponse(request_id=response.headers.get('X-Line-Request-Id'))

def get_progress_status_narrowcast(self, request_id, timeout=None):
"""Get progress status of narrowcast messages sent.

https://developers.line.biz/en/reference/messaging-api/#get-narrowcast-progress-status

Gets the number of messages sent with the /bot/message/progress/narrowcast endpoint.

:param str request_id: request ID of narrowcast.
:param timeout: (optional) How long to wait for the server
to send data before giving up, as a float,
or a (connect timeout, read timeout) float tuple.
Default is self.http_client.timeout
:type timeout: float | tuple(float, float)
:rtype: :py:class:`linebot.models.responses.MessageDeliveryBroadcastResponse`
"""
response = self._get(
'/v2/bot/message/progress/narrowcast?requestId={request_id}'.format(
request_id=request_id),
timeout=timeout
)

return MessageProgressNarrowcastResponse.new_from_json_dict(response.json)

def get_message_delivery_broadcast(self, date, timeout=None):
"""Get number of sent broadcast messages.

Expand Down
27 changes: 27 additions & 0 deletions linebot/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@
Beacon,
Link,
)
from .filter import( # noqa
DemographicFilter,
GenderFilter,
AppTypeFilter,
AreaFilter,
AgeFilter,
SubscriptionPeriodFilter,
)

from .flex_message import ( # noqa
FlexSendMessage,
FlexContainer,
Expand Down Expand Up @@ -93,6 +102,11 @@
MessageInsight,
ClickInsight,
)

from .limit import ( # noqa
Limit,
)

from .messages import ( # noqa
Message,
TextMessage,
Expand All @@ -103,6 +117,17 @@
StickerMessage,
FileMessage,
)

from .operator import ( # noqa
And,
Or,
Not
)

from .recipient import ( # noqa
AudienceRecipient
)

from .responses import ( # noqa
Profile,
MemberIds,
Expand All @@ -122,6 +147,8 @@
InsightDemographicResponse,
InsightMessageEventResponse,
BroadcastResponse,
NarrowcastResponse,
MessageProgressNarrowcastResponse,
)
from .rich_menu import ( # noqa
RichMenu,
Expand Down
165 changes: 165 additions & 0 deletions linebot/models/filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# -*- coding: utf-8 -*-

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

"""linebot.models.filter module."""

from __future__ import unicode_literals

from abc import ABCMeta

from future.utils import with_metaclass

from .base import Base


class Filter(with_metaclass(ABCMeta, Base)):
"""Filter.
https://developers.line.biz/en/reference/messaging-api/#narrowcast-demographic-filter
A filter is the top-level structure of a demographic element.
"""

def __init__(self, **kwargs):
"""__init__ method.
:param kwargs:
"""
super(Filter, self).__init__(**kwargs)

self.type = None


class DemographicFilter(Filter):
"""DemographicFilter.
https://developers.line.biz/en/reference/messaging-api/#narrowcast-demographic-filter
Demographic filter objects represent criteria (e.g. age, gender, OS, region,
and friendship duration) on which to filter the list of recipients.
You can filter recipients based on a combination of different criteria using
logical operator objects.
"""

def __init__(self, criteria=None, **kwargs):
"""__init__ method.
:param criteria: Combination of different criteria using logical
operator objects.
:type criteria: :py:class:`linebot.model.DemographicFilter` |
:py:class:`linebot.model.Operator`
:param kwargs:
"""
super(DemographicFilter, self).__init__(**kwargs)

self.demographic = criteria


class GenderFilter(Filter):
"""GenderFilter."""

def __init__(self, one_of=[], **kwargs):
"""__init__ method.
:param one_of: Send messages to users of a given gender. One of:
male: Users who identify as male
female: Users who identify as female
:type one_of: list[str]
"""
super(GenderFilter, self).__init__(**kwargs)

self.type = "gender"
self.one_of = one_of


class AppTypeFilter(Filter):
"""AppTypeFilter."""

def __init__(self, one_of=[], **kwargs):
"""__init__ method.
:param one_of: Send messages to users of the specified OS. One of:
ios: Users who using iOS.
android: Users who using Android.
:type one_of: list[str]
"""
super(AppTypeFilter, self).__init__(**kwargs)

self.type = "appType"
self.one_of = one_of


class AreaFilter(Filter):
"""AreaFilter."""

def __init__(self, one_of=[], **kwargs):
"""__init__ method.
:param one_of: Send messages to users in the specified region.
:type one_of: list[str]
"""
super(AreaFilter, self).__init__(**kwargs)

self.type = "area"
self.one_of = one_of


class AgeFilter(Filter):
"""AgeFilter.
This lets you filter recipients with a given age range.
"""

def __init__(self, gte=None, lt=None, **kwargs):
"""__init__ method.
Be sure to specify either gte, lt, or both.
:param gte: Send messages to users at least as old as the specified age.
:type gte: str
:param lt: Send messages to users younger than the specified age.
You can specify the same values as for the gte property.
:type lt: str
"""
super(AgeFilter, self).__init__(**kwargs)

self.type = "age"
self.gte = gte
self.lt = lt


class SubscriptionPeriodFilter(Filter):
"""SubscriptionPeriodFilter.
This lets you filter recipients with a given range of friendship durations.
"""

def __init__(self, gte=None, lt=None, **kwargs):
"""__init__ method.
Be sure to specify either gte, lt, or both.
:param gte: Send messages to users who have been friends of yours for
at least the specified number of days
:type gte: str
:param lt: Send messages to users who have been friends of yours for
less than the specified number of days.
You can specify the same values as for the gte property.
:type lt: str
"""
super(SubscriptionPeriodFilter, self).__init__(**kwargs)

self.type = "subscriptionPeriod"
self.gte = gte
self.lt = lt
40 changes: 40 additions & 0 deletions linebot/models/limit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

"""linebot.models.recipient module."""

from __future__ import unicode_literals

from abc import ABCMeta

from future.utils import with_metaclass

from .base import Base


class Limit(with_metaclass(ABCMeta, Base)):
"""Limit.

https://developers.line.biz/en/reference/messaging-api/#send-narrowcast-message

"""

def __init__(self, max=None, **kwargs):
"""__init__ method.

:param kwargs:
"""
super(Limit, self).__init__(**kwargs)

self.max = max
Loading