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
OpAND,
OpOR,
OpNOT
)

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
133 changes: 133 additions & 0 deletions linebot/models/filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# -*- 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):
"""Demographic.

https://developers.line.biz/en/reference/messaging-api/#narrowcast-demographic-filter

A demogrphic filter is the top-level structure of a demographic element.
"""

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

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

self.demographic = condition


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

def __init__(self, one_of=[], **kwargs):
"""__init__ method.

:param header: Style of the header block
:type header: :py:class:`linebot.models.flex_message.BlockStyle`
"""
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.

"""
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.

"""
super(AreaFilter, self).__init__(**kwargs)

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


class AgeFilter(Filter):
"""AgeFilter
"""

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

"""
super(AgeFilter, self).__init__(**kwargs)

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


class SubscriptionPeriodFilter(Filter):
"""SubscriptionPeriodFilter
"""

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

"""
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
86 changes: 86 additions & 0 deletions linebot/models/operator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# -*- 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 Operator(with_metaclass(ABCMeta, Base)):
"""Operator.

https://developers.line.biz/en/reference/messaging-api/#narrowcast-demographic-filter

A operator is the top-level structure of a demographic element.
"""

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

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

self.type = "operator"


class OpAND(Operator):
"""OpAND
"""

def __init__(self, *args, **kwargs):
"""__init__ method.

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

setattr(self, 'and', args)


class OpOR(Operator):
"""OpOR
"""

def __init__(self, *args, **kwargs):
"""__init__ method.

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

setattr(self, 'or', args)


class OpNOT(Operator):
"""OpNOT
"""

def __init__(self, arg, **kwargs):
"""__init__ method.

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

setattr(self, 'not', arg)
Loading