├── .gitignore
├── LICENSE.md
├── License.txt
├── README.md
├── pytest.ini
├── sample_bot.py
├── setup.cfg
├── setup.py
├── tests
├── __init__.py
└── api
│ ├── __init__.py
│ ├── messages
│ ├── __init__.py
│ ├── test_contact_message.py
│ ├── test_file_message.py
│ ├── test_get_message.py
│ ├── test_keyboard_message.py
│ ├── test_location_message.py
│ ├── test_picture_message.py
│ ├── test_rich_media_message.py
│ ├── test_sticker_message.py
│ ├── test_text_message.py
│ ├── test_url_message.py
│ └── test_video_message.py
│ ├── test_api.py
│ ├── test_api_request_sender.py
│ ├── test_data
│ └── unicode_request
│ ├── test_message_sender.py
│ └── viber_requests
│ ├── __init__.py
│ ├── test_create_request.py
│ ├── test_viber_conversation_started_request.py
│ ├── test_viber_delivered_request.py
│ ├── test_viber_failed_request.py
│ ├── test_viber_message_request.py
│ ├── test_viber_seen_request.py
│ ├── test_viber_subscribed_request.py
│ └── test_viber_unsubscribed_request.py
└── viberbot
├── __init__.py
├── api
├── __init__.py
├── api.py
├── api_request_sender.py
├── bot_configuration.py
├── consts.py
├── event_type.py
├── message_sender.py
├── messages
│ ├── __init__.py
│ ├── contact_message.py
│ ├── data_types
│ │ ├── __init__.py
│ │ ├── contact.py
│ │ └── location.py
│ ├── file_message.py
│ ├── keyboard_message.py
│ ├── location_message.py
│ ├── message.py
│ ├── message_type.py
│ ├── picture_message.py
│ ├── rich_media_message.py
│ ├── sticker_message.py
│ ├── text_message.py
│ ├── typed_message.py
│ ├── url_message.py
│ └── video_message.py
├── user_profile.py
└── viber_requests
│ ├── __init__.py
│ ├── viber_conversation_started_request.py
│ ├── viber_delivered_request.py
│ ├── viber_failed_request.py
│ ├── viber_message_request.py
│ ├── viber_request.py
│ ├── viber_seen_request.py
│ ├── viber_subscribed_request.py
│ └── viber_unsubscribed_request.py
└── version.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | .project
3 | *.pyc
4 | *.log
5 | *.user
6 |
7 |
8 | *.jar
9 | *.class
10 | .classpath
11 | *.prefs
12 | git.properties
13 | .idea
14 | *.iml
15 | .gradle
16 |
17 | # Byte-compiled / optimized / DLL files
18 | __pycache__/
19 | *.py[cod]
20 | *$py.class
21 |
22 | # C extensions
23 | *.so
24 |
25 | # Distribution / packaging
26 | .Python
27 | build/
28 | develop-eggs/
29 | dist/
30 | downloads/
31 | eggs/
32 | .eggs/
33 | lib/
34 | lib64/
35 | parts/
36 | sdist/
37 | var/
38 | wheels/
39 | *.egg-info/
40 | .installed.cfg
41 | *.egg
42 |
43 | # PyInstaller
44 | # Usually these files are written by a python script from a template
45 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
46 | *.manifest
47 | *.spec
48 |
49 | # Installer logs
50 | pip-log.txt
51 | pip-delete-this-directory.txt
52 |
53 | # Unit test / coverage reports
54 | htmlcov/
55 | .tox/
56 | .coverage
57 | .coverage.*
58 | .cache
59 | nosetests.xml
60 | coverage.xml
61 | *.cover
62 | .hypothesis/
63 |
64 | # Translations
65 | *.mo
66 | *.pot
67 |
68 | # Django stuff:
69 | *.log
70 | local_settings.py
71 |
72 | # Flask stuff:
73 | instance/
74 | .webassets-cache
75 |
76 | # Scrapy stuff:
77 | .scrapy
78 |
79 | # Sphinx documentation
80 | docs/_build/
81 |
82 | # PyBuilder
83 | target/
84 |
85 | # Jupyter Notebook
86 | .ipynb_checkpoints
87 |
88 | # pyenv
89 | .python-version
90 |
91 | # celery beat schedule file
92 | celerybeat-schedule
93 |
94 | # SageMath parsed files
95 | *.sage.py
96 |
97 | # Environments
98 | .env
99 | .venv
100 | env/
101 | venv/
102 | ENV/
103 |
104 | # Spyder project settings
105 | .spyderproject
106 | .spyproject
107 |
108 | # Rope project settings
109 | .ropeproject
110 |
111 | # mkdocs documentation
112 | /site
113 |
114 | # mypy
115 | .mypy_cache/
116 |
117 | .DS_Store
118 | .idea/
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | Copyright 2016 Viber Media S.à r.l.
178 |
179 | Licensed under the Apache License, Version 2.0 (the "License");
180 | you may not use this file except in compliance with the License.
181 | You may obtain a copy of the License at
182 |
183 | http://www.apache.org/licenses/LICENSE-2.0
184 |
185 | Unless required by applicable law or agreed to in writing, software
186 | distributed under the License is distributed on an "AS IS" BASIS,
187 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
188 | See the License for the specific language governing permissions and
189 | limitations under the License.
190 |
191 |
--------------------------------------------------------------------------------
/License.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | Copyright 2016 Viber Media S.à r.l.
178 |
179 | Licensed under the Apache License, Version 2.0 (the "License");
180 | you may not use this file except in compliance with the License.
181 | You may obtain a copy of the License at
182 |
183 | http://www.apache.org/licenses/LICENSE-2.0
184 |
185 | Unless required by applicable law or agreed to in writing, software
186 | distributed under the License is distributed on an "AS IS" BASIS,
187 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
188 | See the License for the specific language governing permissions and
189 | limitations under the License.
190 |
191 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Viber Python Bot API
2 |
3 | Use this library to develop a bot for Viber platform.
4 | The library is available on **[GitHub](https://github.com/Viber/viber-bot-python)** as well as a package on [PyPI](https://pypi.python.org/pypi/viberbot/).
5 |
6 | This package can be imported using pip by adding the following to your `requirements.txt`:
7 |
8 | ```python
9 | viberbot==1.0.11
10 | ```
11 |
12 | ## License
13 |
14 | This library is released under the terms of the Apache 2.0 license. See [License](https://github.com/Viber/viber-bot-python/blob/master/LICENSE.md) for more information.
15 |
16 | ## Library Prerequisites
17 |
18 | 1. python >= 2.7.0
19 | 1. An Active Viber account on a platform which supports Public Accounts/ bots (iOS/Android). This account will automatically be set as the account administrator during the account creation process.
20 | 1. Active Public Account/ bot - Create an account [here](https://developers.viber.com/docs/general/get-started).
21 | 1. Account authentication token - unique account identifier used to validate your account in all API requests. Once your account is created your authentication token will appear in the account’s “edit info” screen (for admins only). Each request posted to Viber by the account will need to contain the token.
22 | 1. Webhook - Please use a server endpoint URL that supports HTTPS. If you deploy on your own custom server, you'll need a trusted (ca.pem) certificate, not self-signed. Read our [blog post](https://developers.viber.com/blog/2017/05/24/test-your-bots-locally) on how to test your bot locally.
23 |
24 |
25 | ## Contributing
26 |
27 | If you think that there's a bug or there's anything else needed to be changed and you want to change it yourself, you can always create a new Pull request.
28 | Please make sure that your change doesn't break anything and all the unit tests passes.
29 | Also, please make sure that the current tests cover your change, if not please add tests.
30 |
31 | We are using pytest, so if you want to run the tests from the commandline just follow the relevant steps after cloning the repo and creating your branch:
32 |
33 |
34 | ```
35 | # installing the dependencies:
36 | python setup.py develop
37 |
38 | # run the unit tests
39 | python -m pytest
40 | ```
41 |
42 | ## Let's get started!
43 |
44 |
45 | ### Installing
46 |
47 | Creating a basic Viber bot is simple:
48 |
49 | 1. Install the library with pip `pip install viberbot`
50 | 2. Import `viberbot.api` library to your project
51 | 3. Create a Public Account or bot and use the API key from [https://developers.viber.com](https://developers.viber.com)
52 | 4. Configure your bot as described in the documentation below
53 | 5. Start your web server
54 | 6. Call `set_webhook(url)` with your web server url
55 |
56 | ## A simple Echo Bot
57 |
58 | ### Firstly, let's import and configure our bot
59 |
60 | ```python
61 | from viberbot import Api
62 | from viberbot.api.bot_configuration import BotConfiguration
63 |
64 | bot_configuration = BotConfiguration(
65 | name='PythonSampleBot',
66 | avatar='http://viber.com/avatar.jpg',
67 | auth_token='YOUR_AUTH_TOKEN_HERE'
68 | )
69 | viber = Api(bot_configuration)
70 | ```
71 |
72 | ### Create an HTTPS server
73 |
74 | Next thing you should do is starting a https server.
75 | and yes, as we said in the prerequisites it has to be https server. Create a server however you like, for example with `Flask`:
76 |
77 | ```python
78 | from flask import Flask, request, Response
79 |
80 | app = Flask(__name__)
81 |
82 | @app.route('/incoming', methods=['POST'])
83 | def incoming():
84 | logger.debug("received request. post data: {0}".format(request.get_data()))
85 | # handle the request here
86 | return Response(status=200)
87 |
88 | context = ('server.crt', 'server.key')
89 | app.run(host='0.0.0.0', port=443, debug=True, ssl_context=context)
90 | ```
91 |
92 | ### Setting a webhook
93 |
94 | After the server is up and running you can set a webhook.
95 | Viber will push messages sent to this URL. web server should be internet-facing.
96 |
97 | ```python
98 | viber.set_webhook('https://mybotwebserver.com:443/')
99 | ```
100 |
101 | ### Logging
102 |
103 | This library uses the standard python logger. If you want to see its logs you can configure the logger:
104 |
105 | ```python
106 | logger = logging.getLogger()
107 | logger.setLevel(logging.DEBUG)
108 | handler = logging.StreamHandler()
109 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
110 | handler.setFormatter(formatter)
111 | logger.addHandler(handler)
112 | ```
113 |
114 | ### Do you supply a basic types of messages?
115 | Well, funny you ask. Yes we do. All the Message types are located in `viberbot.api.messages` package. Here's some examples:
116 |
117 | ```python
118 | from viberbot.api.messages import (
119 | TextMessage,
120 | ContactMessage,
121 | PictureMessage,
122 | VideoMessage
123 | )
124 | from viberbot.api.messages.data_types.contact import Contact
125 |
126 | # creation of text message
127 | text_message = TextMessage(text="sample text message!")
128 |
129 | # creation of contact message
130 | contact = Contact(name="Viber user", phone_number="0123456789")
131 | contact_message = ContactMessage(contact=contact)
132 |
133 | # creation of picture message
134 | picture_message = PictureMessage(text="Check this", media="http://site.com/img.jpg")
135 |
136 | # creation of video message
137 | video_message = VideoMessage(media="http://mediaserver.com/video.mp4", size=4324)
138 | ```
139 |
140 | Have you noticed how we created the `TextMessage`? There's a all bunch of message types you should get familiar with.
141 |
142 | * [Text Message](#TextMessage)
143 | * [Url Message](#UrlMessage)
144 | * [Contact Message](#ContactMessage)
145 | * [Picture Message](#PictureMessage)
146 | * [Video Message](#VideoMessage)
147 | * [Location Message](#LocationMessage)
148 | * [Sticker Message](#StickerMessage)
149 | * [Rich Media Message](#RichMediaMessage)
150 | * [Keyboard Message](#KeyboardMessage)
151 |
152 | Creating them is easy! Every message object has it's own unique constructor corresponding to it's API implementation, click on them to see it!
153 | Check out the full API documentation for more advanced uses.
154 |
155 | ### Let's add it all up and reply with a message!
156 |
157 | ```python
158 | from flask import Flask, request, Response
159 | from viberbot import Api
160 | from viberbot.api.bot_configuration import BotConfiguration
161 | from viberbot.api.messages import VideoMessage
162 | from viberbot.api.messages.text_message import TextMessage
163 | import logging
164 |
165 | from viberbot.api.viber_requests import ViberConversationStartedRequest
166 | from viberbot.api.viber_requests import ViberFailedRequest
167 | from viberbot.api.viber_requests import ViberMessageRequest
168 | from viberbot.api.viber_requests import ViberSubscribedRequest
169 | from viberbot.api.viber_requests import ViberUnsubscribedRequest
170 |
171 | app = Flask(__name__)
172 | viber = Api(BotConfiguration(
173 | name='PythonSampleBot',
174 | avatar='http://site.com/avatar.jpg',
175 | auth_token='445da6az1s345z78-dazcczb2542zv51a-e0vc5fva17480im9'
176 | ))
177 |
178 |
179 | @app.route('/', methods=['POST'])
180 | def incoming():
181 | logger.debug("received request. post data: {0}".format(request.get_data()))
182 | # every viber message is signed, you can verify the signature using this method
183 | if not viber.verify_signature(request.get_data(), request.headers.get('X-Viber-Content-Signature')):
184 | return Response(status=403)
185 |
186 | # this library supplies a simple way to receive a request object
187 | viber_request = viber.parse_request(request.get_data())
188 |
189 | if isinstance(viber_request, ViberMessageRequest):
190 | message = viber_request.message
191 | # lets echo back
192 | viber.send_messages(viber_request.sender.id, [
193 | message
194 | ])
195 | elif isinstance(viber_request, ViberSubscribedRequest):
196 | viber.send_messages(viber_request.get_user.id, [
197 | TextMessage(text="thanks for subscribing!")
198 | ])
199 | elif isinstance(viber_request, ViberFailedRequest):
200 | logger.warn("client failed receiving message. failure: {0}".format(viber_request))
201 |
202 | return Response(status=200)
203 |
204 | if __name__ == "__main__":
205 | context = ('server.crt', 'server.key')
206 | app.run(host='0.0.0.0', port=443, debug=True, ssl_context=context)
207 | ```
208 |
209 | As you can see there's a bunch of `Request` types here's a list of them.
210 |
211 | ## Viber API
212 |
213 | ### Api class
214 |
215 | `from viberbot import Api`
216 |
217 | * Api
218 | * [init(bot\_configuration)](#new-Api())
219 | * [.set\_webhook(url, webhook_events)](#set_webhook) ⇒ `List of registered event_types`
220 | * [.unset\_webhook()](#unset_webhook) ⇒ `None`
221 | * [.get\_account_info()](#get_account_info) ⇒ `object`
222 | * [.verify\_signature(request\_data, signature)](#verify_signature) ⇒ `boolean`
223 | * [.parse\_request(request\_data)](#parse_request) ⇒ `ViberRequest`
224 | * [.send\_messages(to, messages)](#send_messages) ⇒ `list of message tokens sent`
225 | * [.get\_online(viber\_user\_ids)](#get_online) ⇒ `dictionary of users status`
226 | * [.get\_user_details(viber\_user\_id)](#get_user_details) ⇒ `dictionary of user's data`
227 | * [.post\_messages\_to\_public\_account(to, messages)](#post_to_pa) ⇒ `list of message tokens sent`
228 |
229 |
230 |
231 | ### New Api()
232 |
233 | | Param | Type | Description |
234 | | --- | --- | --- |
235 | | bot\_configuration | `object` | `BotConfiguration` |
236 |
237 |
238 |
239 | ### Api.set\_webhook(url)
240 |
241 | | Param | Type | Description |
242 | | --- | --- | --- |
243 | | url | `string` | Your web server url |
244 | | webhook\_events | `list` | optional list of subscribed events |
245 |
246 | Returns `List of registered event_types`.
247 |
248 | ```python
249 | event_types = viber.set_webhook('https://example.com/incoming')
250 | ```
251 |
252 |
253 |
254 | ### Api.unset\_webhook()
255 |
256 | Returns `None`.
257 |
258 | ```python
259 | viber.unset_webhook()
260 | ```
261 |
262 |
263 |
264 | ### Api.get\_account\_info()
265 |
266 | Returns an `object` [with the following JSON](https://developers.viber.com/docs/api/rest-bot-api/#get-account-info).
267 |
268 | ```python
269 | account_info = viber.get_account_info()
270 | ```
271 |
272 |
273 |
274 | ### Api.verify\_signature(request\_data, signature)
275 |
276 | | Param | Type | Description |
277 | | --- | --- | --- |
278 | | request\_data | `string` | the post data from request |
279 | | signature | `string` | sent as header `X-Viber-Content-Signature` |
280 |
281 |
282 | Returns a `boolean` suggesting if the signature is valid.
283 |
284 | ```python
285 | if not viber.verify_signature(request.get_data(), request.headers.get('X-Viber-Content-Signature')):
286 | return Response(status=403)
287 | ```
288 |
289 |
290 |
291 | ### Api.parse\_request(request\_data)
292 |
293 | | Param | Type | Description |
294 | | --- | --- | --- |
295 | | request\_data | `string` | the post data from request |
296 |
297 | Returns a `ViberRequest` object.
298 |
299 | There's a list of [ViberRequest objects](#ViberRequest)
300 |
301 | ```python
302 | viber_request = viber.parse_request(request.get_data())
303 | ```
304 |
305 |
306 |
307 | ### Api.send\_messages(to, messages)
308 |
309 | | Param | Type | Description |
310 | | --- | --- | --- |
311 | | to | `string` | Viber user id |
312 | | messages | `list` | list of `Message` objects |
313 |
314 | Returns `list` of message tokens of the messages sent.
315 |
316 | ```python
317 | tokens = viber.send_messages(to=viber_request.get_sender().get_id(),
318 | messages=[TextMessage(text="sample message")])
319 | ```
320 |
321 |
322 |
323 | ### Api.post\_messages\_to\_public\_account(to, messages)
324 |
325 | | Param | Type | Description |
326 | | --- | --- | --- |
327 | | sender | `string` | Viber user id |
328 | | messages | `list` | list of `Message` objects |
329 |
330 | Returns `list` of message tokens of the messages sent.
331 |
332 | ```python
333 | tokens = viber.post_messages_to_public_account(sender=viber_request.get_sender().get_id(),
334 | messages=[TextMessage(text="sample message")])
335 | ```
336 |
337 |
338 |
339 | ### Api.get\_online(viber\_user\_ids)
340 |
341 | | Param | Type | Description |
342 | | --- | --- | --- |
343 | | viber\_user\_ids | `array of strings` | Array of Viber user ids |
344 |
345 | Returns a `dictionary of users`.
346 |
347 | ```python
348 | users = Api.get_online(["user1id", "user2id"])
349 | ```
350 |
351 |
352 |
353 | ### Api.get\_user\_details(viber\_user\_id)
354 |
355 | | Param | Type | Description |
356 | | --- | --- | --- |
357 | | viber\_user\_ids | `string` | Viber user id |
358 |
359 | The `get_user_details` function will fetch the details of a specific Viber user based on his unique user ID. The user ID can be obtained from the callbacks sent to the account regarding user's actions. This request can be sent twice during a 12 hours period for each user ID.
360 |
361 | ```python
362 | user_data = Api.get_user_details("userId")
363 | ```
364 |
365 |
366 |
367 | ### Request object
368 |
369 | | Param | Type | Notes |
370 | | --- | --- | --- |
371 | | event\_type | `string` | according to `EventTypes` enum |
372 | | timestamp | `long` | Epoch of request time |
373 |
374 | * ViberRequest
375 | * .event\_type ⇒ `string `
376 | * .timestamp ⇒ `long`
377 |
378 |
379 |
380 | #### ViberConversationStartedRequest object
381 |
382 | Inherits from [ViberRequest](#ViberRequest)
383 |
384 | Conversation started event fires when a user opens a conversation with the Public Account/ bot using the “message” button (found on the account’s info screen) or using a [deep link](https://developers.viber.com/docs/tools/deep-links).
385 |
386 | This event is **not** considered a subscribe event and doesn't allow the account to send messages to the user; however, it will allow sending one "welcome message" to the user. See [sending a welcome message](#SendingWelcomeMessage) below for more information.
387 |
388 | | Param | Type | Notes |
389 | | --- | --- | --- |
390 | | event\_type | `string` | always equals to the value of `EventType.CONVERSATION_STARTED` |
391 | | message\_token | `string` | Unique ID of the message |
392 | | type | `string` | The specific type of `conversation_started` event. |
393 | | context | `string` | Any additional parameters added to the deep link used to access the conversation passed as a string |
394 | | user | `UserProfile` | the user started the conversation [UserProfile](#UserProfile) |
395 | | subscribed | `boolean` | Indicates whether a user is already subscribed |
396 |
397 | * ViberConversationStartedRequest
398 | * message\_token ⇒ `string`
399 | * type ⇒ `string`
400 | * context ⇒ `string`
401 | * user ⇒ `UserProfile`
402 |
403 | #### ViberDeliveredRequest object
404 |
405 | Inherits from [ViberRequest](#ViberRequest)
406 |
407 | | Param | Type | Notes |
408 | | --- | --- | --- |
409 | | event\_type | `string` | always equals to the value of `EventType.DELIVERED` |
410 | | message\_token | `string` | Unique ID of the message |
411 | | user\_id | `string` | Unique Viber user id |
412 |
413 | * ViberDeliveredRequest
414 | * message\_token ⇒ `string`
415 | * user\_id ⇒ `string`
416 |
417 | #### ViberFailedRequest object
418 |
419 | Inherits from [ViberRequest](#ViberRequest)
420 |
421 | | Param | Type | Notes |
422 | | --- | --- | --- |
423 | | event\_type | `string` | always equals to the value of `EventType.FAILED` |
424 | | message\_token | `string` | Unique ID of the message |
425 | | user\_id | `string` | Unique Viber user id |
426 | | desc | `string` | Failure description |
427 |
428 | * ViberFailedRequest
429 | * message\_token ⇒ `string`
430 | * user\_id ⇒ `string`
431 | * desc ⇒ `string`
432 |
433 | #### ViberMessageRequest object
434 |
435 | Inherits from [ViberRequest](#ViberRequest)
436 |
437 | | Param | Type | Notes |
438 | | --- | --- | --- |
439 | | event\_type | `string` | always equals to the value of `EventType.MESSAGE` |
440 | | message\_token | `string` | Unique ID of the message |
441 | | message | `Message` | `Message` object |
442 | | sender | `UserProfile` | the user started the conversation [UserProfile](#UserProfile) |
443 |
444 | * ViberMessageRequest
445 | * message\_token ⇒ `string`
446 | * message ⇒ `Message`
447 | * sender ⇒ `UserProfile`
448 |
449 | #### ViberSeenRequest object
450 |
451 | Inherits from [ViberRequest](#ViberRequest)
452 |
453 | | Param | Type | Notes |
454 | | --- | --- | --- |
455 | | event\_type | `string` | always equals to the value of `EventType.SEEN` |
456 | | message\_token | `string` | Unique ID of the message |
457 | | user\_id | `string` | Unique Viber user id |
458 |
459 | * ViberSeenRequest
460 | * message\_token ⇒ `string`
461 | * user\_id ⇒ `string`
462 |
463 | #### ViberSubscribedRequest object
464 |
465 | Inherits from [ViberRequest](#ViberRequest)
466 |
467 | | Param | Type | Notes |
468 | | --- | --- | --- |
469 | | event\_type | `string` | always equals to the value of `EventType.SUBSCRIBED` |
470 | | user | `UserProfile` | the user started the conversation [UserProfile](#UserProfile) |
471 |
472 | * ViberSubscribedRequest
473 | * user ⇒ `UserProfile`
474 |
475 | #### ViberUnsubscribedRequest object
476 |
477 | Inherits from [ViberRequest](#ViberRequest)
478 |
479 | | Param | Type | Notes |
480 | | --- | --- | --- |
481 | | event\_type | `string` | always equals to the value of `EventType.UNSUBSCRIBED` |
482 | | user\_id | `string` | Unique Viber user id |
483 |
484 | * ViberUnsubscribedRequest
485 | * get\_user\_id() ⇒ `string`
486 |
487 |
488 |
489 | ### UserProfile object
490 |
491 | | Param | Type | Notes |
492 | | --- | --- | --- |
493 | | id | `string` | --- |
494 | | name | `string` | --- |
495 | | avatar | `string` | Avatar URL |
496 | | country | `string` | **currently set in `CONVERSATION_STARTED` event only** |
497 | | language | `string` | **currently set in `CONVERSATION_STARTED` event only** |
498 |
499 |
500 |
501 | ### Message Object
502 |
503 | **Common Members for `Message` interface**:
504 |
505 | | Param | Type | Description |
506 | | --- | --- | --- |
507 | | timestamp | `long` | Epoch time |
508 | | keyboard | `JSON` | keyboard JSON |
509 | | trackingData | `JSON` | JSON Tracking Data from Viber Client |
510 |
511 | **Common Constructor Arguments `Message` interface**:
512 |
513 | | Param | Type | Description |
514 | | --- | --- | --- |
515 | | optionalKeyboard | `JSON` | [Writing Custom Keyboards](https://developers.viber.com/docs/tools/keyboards) |
516 | | optionalTrackingData | `JSON` | Data to be saved on Viber Client device, and sent back each time message is received |
517 |
518 |
519 |
520 | #### TextMessage object
521 |
522 | | Member | Type
523 | | --- | --- |
524 | | text | `string` |
525 |
526 | ```python
527 | message = TextMessage(text="my text message")
528 | ```
529 |
530 |
531 |
532 | #### URLMessage object
533 |
534 | | Member | Type | Description |
535 | | --- | --- | --- |
536 | | media | `string` | URL string |
537 |
538 | ```python
539 | message = URLMessage(media="http://my.siteurl.com")
540 | ```
541 |
542 |
543 |
544 | #### ContactMessage object
545 |
546 | | Member | Type
547 | | --- | --- |
548 | | contact | `Contact` |
549 |
550 | ```python
551 | from viberbot.api.messages.data_types.contact import Contact
552 |
553 | contact = Contact(name="Viber user", phone_number="+0015648979", avatar="http://link.to.avatar")
554 | contact_message = ContactMessage(contact=contact)
555 | ```
556 |
557 |
558 |
559 | #### PictureMessage object
560 |
561 | | Member | Type | Description |
562 | | --- | --- | --- |
563 | | media | `string` | url of the message (jpeg only) |
564 | | text | `string` | |
565 | | thumbnail | `string` | |
566 |
567 | ```python
568 | message = PictureMessage(media="http://www.thehindubusinessline.com/multimedia/dynamic/01458/viber_logo_JPG_1458024f.jpg", text="Viber logo")
569 | ```
570 |
571 |
572 |
573 | #### VideoMessage object
574 |
575 | | Member | Type | Description |
576 | | --- | --- | --- |
577 | | media | `string` | url of the video |
578 | | size | `int` | |
579 | | thumbnail | `string` | |
580 | | duration | `int` | |
581 |
582 | ```python
583 | message = VideoMessage(media="http://site.com/video.mp4", size=21499)
584 | ```
585 |
586 |
587 |
588 | #### LocationMessage object
589 |
590 | | Member | Type
591 | | --- | --- |
592 | | location | `Location` |
593 |
594 | ```python
595 | from viberbot.api.messages.data_types.location import Location
596 |
597 | location = Location(lat=0.0, lon=0.0)
598 | location_message = LocationMessage(location=location)
599 | ```
600 |
601 |
602 |
603 | #### StickerMessage object
604 |
605 | | Member | Type
606 | | --- | --- |
607 | | sticker\_id | `int` |
608 |
609 | ```python
610 | message = StickerMessage(sticker_id=40100)
611 | ```
612 |
613 |
614 |
615 | #### FileMessage object
616 |
617 | | Member | Type
618 | | --- | --- |
619 | | media | `string` |
620 | | size | `long` |
621 | | file\_name | `string` |
622 |
623 | ```python
624 | message = FileMessage(media=url, size=sizeInBytes, file_name=file_name)
625 | ```
626 |
627 |
628 |
629 | #### RichMediaMessage object
630 |
631 | | Member | Type
632 | | --- | --- |
633 | | rich\_media | `string` (JSON) |
634 |
635 | ```python
636 | SAMPLE_RICH_MEDIA = """{
637 | "BgColor": "#69C48A",
638 | "Buttons": [
639 | {
640 | "Columns": 6,
641 | "Rows": 1,
642 | "BgColor": "#454545",
643 | "BgMediaType": "gif",
644 | "BgMedia": "http://www.url.by/test.gif",
645 | "BgLoop": true,
646 | "ActionType": "open-url",
647 | "Silent": true,
648 | "ActionBody": "www.tut.by",
649 | "Image": "www.tut.by/img.jpg",
650 | "TextVAlign": "middle",
651 | "TextHAlign": "left",
652 | "Text": "example button",
653 | "TextOpacity": 10,
654 | "TextSize": "regular"
655 | }
656 | ]
657 | }"""
658 |
659 | SAMPLE_ALT_TEXT = "upgrade now!"
660 |
661 | message = RichMediaMessage(rich_media=SAMPLE_RICH_MEDIA, alt_text=SAMPLE_ALT_TEXT)
662 | ```
663 |
664 |
665 |
666 | #### KeyboardMessage object
667 |
668 | | Member | Type
669 | | --- | --- |
670 | | keyboard | `JSON` |
671 | | tracking_data | `JSON` |
672 |
673 | ```python
674 | message = KeyboardMessage(tracking_data=tracking_data, keyboard=keyboard)
675 | ```
676 |
677 |
678 |
679 | ### Sending a welcome message
680 |
681 | The Viber API allows sending messages to users only after they subscribe to the account. However, Viber will allow the account to send one “welcome message” to a user as the user opens the conversation, before the user subscribes.
682 |
683 | The welcome message will be sent as a response to a `conversation_started` callback, which will be received from Viber once the user opens the conversation with the account. To learn more about this event and when is it triggered see [`Conversation started`](#ConversationStarted) in the callbacks section.
684 |
685 | #### Welcome message flow
686 |
687 | Sending a welcome message will be done according to the following flow:
688 |
689 | 1. User opens 1-on-1 conversation with account.
690 | 2. Viber server send `conversation_started` even to PA’s webhook.
691 | 3. The account receives the `conversation_started` and responds with an HTTP response which includes the welcome message as the response body.
692 |
693 | The welcome message will be a JSON constructed according to the send_message requests structure, but without the `receiver` parameter. An example welcome message would look like this:
694 |
695 | ```python
696 | @app.route('/', methods=['POST'])
697 | def incoming():
698 | viber_request = viber.parse_request(request.get_data())
699 |
700 | if isinstance(viber_request, ViberConversationStartedRequest) :
701 | viber.send_messages(viber_request.get_user().get_id(), [
702 | TextMessage(text="Welcome!")
703 | ])
704 |
705 | return Response(status=200)
706 | ```
707 |
708 | ## Community
709 |
710 | Join the conversation on **[Gitter](https://gitter.im/viber/bot-python)**.
711 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | testpaths = tests
3 | python_files = *_test.py test_*.py *_tests.py
--------------------------------------------------------------------------------
/sample_bot.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, Response
2 | from viberbot import Api
3 | from viberbot.api.bot_configuration import BotConfiguration
4 | from viberbot.api.messages.text_message import TextMessage
5 | from viberbot.api.viber_requests import ViberConversationStartedRequest
6 | from viberbot.api.viber_requests import ViberFailedRequest
7 | from viberbot.api.viber_requests import ViberMessageRequest
8 | from viberbot.api.viber_requests import ViberSubscribedRequest
9 | from viberbot.api.viber_requests import ViberUnsubscribedRequest
10 |
11 | import time
12 | import logging
13 | import sched
14 | import threading
15 |
16 | logger = logging.getLogger()
17 | logger.setLevel(logging.DEBUG)
18 | handler = logging.StreamHandler()
19 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
20 | handler.setFormatter(formatter)
21 | logger.addHandler(handler)
22 |
23 | app = Flask(__name__)
24 | viber = Api(BotConfiguration(
25 | name='PythonSampleBot',
26 | avatar='http://viber.com/avatar.jpg',
27 | auth_token='YOUR_AUTH_TOKEN_HERE'
28 | ))
29 |
30 | @app.route('/', methods=['POST'])
31 | def incoming():
32 | logger.debug("received request. post data: {0}".format(request.get_data()))
33 |
34 | viber_request = viber.parse_request(request.get_data().decode('utf8'))
35 |
36 | if isinstance(viber_request, ViberMessageRequest):
37 | message = viber_request.message
38 | viber.send_messages(viber_request.sender.id, [
39 | message
40 | ])
41 | elif isinstance(viber_request, ViberConversationStartedRequest) \
42 | or isinstance(viber_request, ViberSubscribedRequest) \
43 | or isinstance(viber_request, ViberUnsubscribedRequest):
44 | viber.send_messages(viber_request.sender.id, [
45 | TextMessage(None, None, viber_request.get_event_type())
46 | ])
47 | elif isinstance(viber_request, ViberFailedRequest):
48 | logger.warn("client failed receiving message. failure: {0}".format(viber_request))
49 |
50 | return Response(status=200)
51 |
52 | def set_webhook(viber):
53 | viber.set_webhook('https://mybotwebserver.com:8443/')
54 |
55 | if __name__ == "__main__":
56 | scheduler = sched.scheduler(time.time, time.sleep)
57 | scheduler.enter(5, 1, set_webhook, (viber,))
58 | t = threading.Thread(target=scheduler.run)
59 | t.start()
60 |
61 | context = ('server.crt', 'server.key')
62 | app.run(host='0.0.0.0', port=8443, debug=True, ssl_context=context)
63 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | description-file = README.md
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 | exec(open('viberbot/version.py').read())
3 | setup(
4 | name='viberbot',
5 | version=__version__,
6 | packages=['viberbot', 'viberbot.api', 'viberbot.api.viber_requests',
7 | 'viberbot.api.messages', 'viberbot.api.messages.data_types'],
8 | install_requires=['future', 'requests'],
9 | tests_require=['pytest'],
10 | url='https://github.com/Viber/viber-bot-python',
11 | )
12 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Viber/viber-bot-python/5cfe34e3b7d1c98afdf5d2c09a4c5722a61f008f/tests/__init__.py
--------------------------------------------------------------------------------
/tests/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Viber/viber-bot-python/5cfe34e3b7d1c98afdf5d2c09a4c5722a61f008f/tests/api/__init__.py
--------------------------------------------------------------------------------
/tests/api/messages/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Viber/viber-bot-python/5cfe34e3b7d1c98afdf5d2c09a4c5722a61f008f/tests/api/messages/__init__.py
--------------------------------------------------------------------------------
/tests/api/messages/test_contact_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import ContactMessage
2 | from viberbot.api.messages import MessageType
3 | from viberbot.api.messages.data_types.contact import Contact
4 |
5 | SAMPLE_TRACKING_DATA = "tracking data!"
6 | SAMPLE_KEYBOARD = """{
7 | "Type": "keyboard",
8 | "DefaultHeight": true,
9 | "BgColor": "#FFFFFF",
10 | "Buttons": [
11 | {
12 | "Columns": 6,
13 | "Rows": 1,
14 | "BgColor": "#2db9b9",
15 | "BgMediaType": "gif",
16 | "BgMedia": "http://www.url.by/test.gif",
17 | "BgLoop": true,
18 | "ActionType": "open-url",
19 | "ActionBody": "www.tut.by",
20 | "Image": "www.tut.by/img.jpg",
21 | "Text": "Key text",
22 | "TextVAlign": "middle",
23 | "TextHAlign": "center",
24 | "TextOpacity": 60,
25 | "TextSize": "regular"
26 | }
27 | ]
28 | }"""
29 | SAMPLE_CONTACT_NAME = "contact name"
30 | SAMPLE_PHONE_NUMBER = "052947378493"
31 | SAMPLE_AVATAR = "awesomeavatar"
32 | SAMPLE_CONTACT = Contact(SAMPLE_CONTACT_NAME, SAMPLE_PHONE_NUMBER, SAMPLE_AVATAR)
33 |
34 |
35 | def test_creation():
36 | contact_message = ContactMessage(
37 | tracking_data=SAMPLE_TRACKING_DATA,
38 | keyboard=SAMPLE_KEYBOARD,
39 | contact=SAMPLE_CONTACT)
40 |
41 | assert contact_message.keyboard == SAMPLE_KEYBOARD
42 | assert contact_message.tracking_data == SAMPLE_TRACKING_DATA
43 | assert contact_message.contact == SAMPLE_CONTACT
44 |
45 |
46 | def test_from_dict():
47 | message_dict = dict(
48 | tracking_data=SAMPLE_TRACKING_DATA,
49 | keyboard=SAMPLE_KEYBOARD,
50 | contact=dict(name=SAMPLE_CONTACT_NAME, phone_number=SAMPLE_PHONE_NUMBER)
51 | )
52 |
53 | contact_message = ContactMessage().from_dict(message_dict)
54 |
55 | assert contact_message.keyboard == SAMPLE_KEYBOARD
56 | assert contact_message.tracking_data == SAMPLE_TRACKING_DATA
57 | assert contact_message.contact == SAMPLE_CONTACT
58 |
59 |
60 | def test_to_dict():
61 | message_dict = dict(
62 | type=MessageType.CONTACT,
63 | tracking_data=SAMPLE_TRACKING_DATA,
64 | keyboard=SAMPLE_KEYBOARD,
65 | contact=dict(name=SAMPLE_CONTACT_NAME, phone_number=SAMPLE_PHONE_NUMBER, avatar=SAMPLE_AVATAR))
66 |
67 | contact_message_dict = ContactMessage(tracking_data=SAMPLE_TRACKING_DATA,
68 | keyboard=SAMPLE_KEYBOARD,
69 | contact=SAMPLE_CONTACT).to_dict()
70 |
71 | assert message_dict == contact_message_dict
72 |
73 |
74 | def test_validate_no_contact():
75 | contact_message = ContactMessage(tracking_data=SAMPLE_TRACKING_DATA)
76 | assert not contact_message.validate()
77 |
78 |
79 | def test_validate_success():
80 | contact_message = ContactMessage(tracking_data=SAMPLE_TRACKING_DATA, contact=SAMPLE_CONTACT)
81 | assert contact_message.validate()
82 |
83 |
84 | def test_validate_missing_contact_param():
85 | contact_message = ContactMessage(tracking_data=SAMPLE_TRACKING_DATA, contact=Contact(name=SAMPLE_CONTACT_NAME))
86 | assert not contact_message.validate()
87 |
88 | contact_message = ContactMessage(tracking_data=SAMPLE_TRACKING_DATA, contact=Contact(phone_number=SAMPLE_PHONE_NUMBER))
89 | assert not contact_message.validate()
--------------------------------------------------------------------------------
/tests/api/messages/test_file_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import FileMessage
2 | from viberbot.api.messages import MessageType
3 |
4 | SAMPLE_TRACKING_DATA = "some tracking data"
5 | SAMPLE_KEYBOARD = """{
6 | "Type": "keyboard",
7 | "DefaultHeight": true,
8 | "BgColor": "#FFFFFF",
9 | "Buttons": [
10 | {
11 | "Columns": 6,
12 | "Rows": 1,
13 | "BgColor": "#2db9b9",
14 | "BgMediaType": "gif",
15 | "BgMedia": "http://www.url.by/test.gif",
16 | "BgLoop": true,
17 | "ActionType": "open-url",
18 | "ActionBody": "www.tut.by",
19 | "Image": "www.tut.by/img.jpg",
20 | "Text": "Key text",
21 | "TextVAlign": "middle",
22 | "TextHAlign": "center",
23 | "TextOpacity": 60,
24 | "TextSize": "regular"
25 | }
26 | ]
27 | }"""
28 | SAMPLE_MEDIA = "http://www.site.com/research.pdf"
29 | SAMPLE_SIZE = 1000
30 | SAMPLE_FILE_NAME = "research.pdf"
31 |
32 |
33 | def test_creation():
34 | file_message = FileMessage(
35 | tracking_data=SAMPLE_TRACKING_DATA,
36 | keyboard=SAMPLE_KEYBOARD,
37 | media=SAMPLE_MEDIA,
38 | size=SAMPLE_SIZE,
39 | file_name=SAMPLE_FILE_NAME
40 | )
41 |
42 | assert file_message.tracking_data == SAMPLE_TRACKING_DATA
43 | assert file_message.keyboard == SAMPLE_KEYBOARD
44 | assert file_message.media == SAMPLE_MEDIA
45 | assert file_message.size == SAMPLE_SIZE
46 | assert file_message.file_name == SAMPLE_FILE_NAME
47 |
48 |
49 | def test_from_dict():
50 | message_dict = dict(
51 | tracking_data=SAMPLE_TRACKING_DATA,
52 | keyboard=SAMPLE_KEYBOARD,
53 | media=SAMPLE_MEDIA,
54 | size=SAMPLE_SIZE,
55 | file_name=SAMPLE_FILE_NAME
56 | )
57 |
58 | file_message = FileMessage().from_dict(message_dict)
59 |
60 | assert file_message.tracking_data == SAMPLE_TRACKING_DATA
61 | assert file_message.keyboard == SAMPLE_KEYBOARD
62 | assert file_message.media == SAMPLE_MEDIA
63 | assert file_message.size == SAMPLE_SIZE
64 | assert file_message.file_name == SAMPLE_FILE_NAME
65 |
66 |
67 | def test_to_dict():
68 | message_dict = dict(
69 | type=MessageType.FILE,
70 | tracking_data=SAMPLE_TRACKING_DATA,
71 | keyboard=SAMPLE_KEYBOARD,
72 | media=SAMPLE_MEDIA,
73 | size=SAMPLE_SIZE,
74 | file_name=SAMPLE_FILE_NAME
75 | )
76 |
77 | file_message_dict = FileMessage(
78 | tracking_data=SAMPLE_TRACKING_DATA,
79 | keyboard=SAMPLE_KEYBOARD,
80 | media=SAMPLE_MEDIA,
81 | size=SAMPLE_SIZE,
82 | file_name=SAMPLE_FILE_NAME
83 | ).to_dict()
84 |
85 | assert message_dict == file_message_dict
86 |
87 |
88 | def test_validate_success():
89 | file_message = FileMessage(
90 | media=SAMPLE_MEDIA,
91 | size=SAMPLE_SIZE,
92 | file_name=SAMPLE_FILE_NAME
93 | )
94 |
95 | assert file_message.validate()
96 |
97 |
98 | def test_validate_missing_params():
99 | file_message = FileMessage(
100 | size=SAMPLE_SIZE,
101 | file_name=SAMPLE_FILE_NAME
102 | )
103 |
104 | assert not file_message.validate()
105 |
106 | file_message = FileMessage(
107 | media=SAMPLE_MEDIA,
108 | file_name=SAMPLE_FILE_NAME
109 | )
110 |
111 | assert not file_message.validate()
112 |
113 | file_message = FileMessage(
114 | media=SAMPLE_MEDIA,
115 | size=SAMPLE_SIZE
116 | )
117 |
118 | assert not file_message.validate()
119 |
120 |
121 |
--------------------------------------------------------------------------------
/tests/api/messages/test_get_message.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import json
3 |
4 | import pytest
5 |
6 | from viberbot.api.messages import ContactMessage
7 | from viberbot.api.messages import FileMessage
8 | from viberbot.api.messages import LocationMessage
9 | from viberbot.api.messages import PictureMessage
10 | from viberbot.api.messages import TextMessage
11 | from viberbot.api.messages import URLMessage
12 | from viberbot.api.messages import VideoMessage
13 | from viberbot.api.messages import get_message
14 |
15 |
16 | def test_contact_message():
17 | contact_message_data = """
18 | {
19 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
20 | "receiver": "01234567890A=",
21 | "sender":
22 | {
23 | "name": "yarden from the pa",
24 | "avatar": "http://avatar_url"
25 | },
26 | "tracking_data": "tracking data",
27 | "type": "contact",
28 | "contact": {
29 | "name": "Alex",
30 | "phone_number": "+972511123123"
31 | }
32 | }
33 | """
34 |
35 | contact_message = get_message(json.loads(contact_message_data))
36 | assert isinstance(contact_message, ContactMessage)
37 |
38 |
39 | def test_file_message():
40 | file_message_data = """
41 | {
42 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
43 | "receiver": "01234567890A=",
44 | "sender":
45 | {
46 | "name": "yarden from the pa",
47 | "avatar": "http://avatar_url"
48 | },
49 | "tracking_data": "tracking data",
50 | "type": "file",
51 | "media": "http://www.images.com/file.doc",
52 | "size": 10000,
53 | "file_name": "name_of_file.doc"
54 | }
55 | """
56 |
57 | file_message = get_message(json.loads(file_message_data))
58 | assert isinstance(file_message, FileMessage)
59 |
60 |
61 | def test_location_message():
62 | location_message_data = """
63 | {
64 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
65 | "receiver": "01234567890A=",
66 | "sender":
67 | {
68 | "name": "yarden from the pa",
69 | "avatar": "http://avatar_url"
70 | },
71 | "tracking_data": "tracking data",
72 | "type": "location",
73 | "location": {"lat": "37.7898", "lon": "-122.3942"}
74 | }
75 | """
76 |
77 | location_message = get_message(json.loads(location_message_data))
78 | assert isinstance(location_message, LocationMessage)
79 |
80 |
81 | def test_picture_message():
82 | picture_message_data = """
83 | {
84 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
85 | "receiver": "01234567890A=",
86 | "sender":
87 | {
88 | "name": "yarden from the pa",
89 | "avatar": "http://avatar_url"
90 | },
91 | "tracking_data": "tracking data",
92 | "type": "picture",
93 | "text": "Photo description",
94 | "media": "http://www.images.com/img.jpg",
95 | "thumbnail": "http://www.images.com/thumb.jpg"
96 | }
97 | """
98 |
99 | picture_message = get_message(json.loads(picture_message_data))
100 | assert isinstance(picture_message, PictureMessage)
101 |
102 |
103 | def test_text_message():
104 | text_message_data = """
105 | {
106 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
107 | "receiver": "01234567890A=",
108 | "sender":
109 | {
110 | "name": "yarden from the pa",
111 | "avatar": "http://avatar_url"
112 | },
113 | "tracking_data": "tracking data",
114 | "type": "text",
115 | "text": "a message from pa"
116 | }
117 | """
118 |
119 | text_message = get_message(json.loads(text_message_data))
120 | assert isinstance(text_message, TextMessage)
121 |
122 |
123 | def test_url_message():
124 | url_message_data = """
125 | {
126 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
127 | "receiver": "01234567890A=",
128 | "sender":
129 | {
130 | "name": "yarden from the pa",
131 | "avatar": "http://avatar_url"
132 | },
133 | "tracking_data": "tracking data",
134 | "type": "url",
135 | "media": "http://www.website.com/go_here"
136 | }
137 | """
138 |
139 | url_message = get_message(json.loads(url_message_data))
140 | assert isinstance(url_message, URLMessage)
141 |
142 |
143 | def test_video_message():
144 | video_message_data = """
145 | {
146 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
147 | "receiver": "01234567890A=",
148 | "sender":
149 | {
150 | "name": "yarden from the pa",
151 | "avatar": "http://avatar_url"
152 | },
153 | "tracking_data": "tracking data",
154 | "type": "video",
155 | "media": "http://www.images.com/video.mp4",
156 | "thumbnail": "http://www.images.com/thumb.jpg",
157 | "size": 10000,
158 | "duration": 10
159 | }
160 | """
161 |
162 | video_message = get_message(json.loads(video_message_data))
163 | assert isinstance(video_message, VideoMessage)
164 |
165 |
166 | def test_unknown_type():
167 | with pytest.raises(Exception) as exc:
168 | message_data = """
169 | {
170 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
171 | "receiver": "01234567890A=",
172 | "sender":
173 | {
174 | "name": "yarden from the pa",
175 | "avatar": "http://avatar_url"
176 | },
177 | "tracking_data": "tracking data",
178 | "type": "NotExists"
179 | }
180 | """
181 |
182 | get_message(json.loads(message_data))
183 | assert exc.value.message.startswith("message type 'NotExists' is not supported")
184 |
185 |
186 | def test_get_text_message_unicode():
187 | text_message_data = u"""
188 | {
189 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
190 | "receiver": "01234567890A=",
191 | "sender":
192 | {
193 | "name": "שם בעברית",
194 | "avatar": "http://avatar_url"
195 | },
196 | "tracking_data": "へぶる。塞末タヨハ協責ウワ格子しむ",
197 | "type": "text",
198 | "text": "הודעה יפה"
199 | }
200 | """
201 |
202 | text_message = get_message(json.loads(text_message_data))
203 | assert isinstance(text_message, TextMessage)
204 |
205 |
206 | def test_get_message_missing_type():
207 | with pytest.raises(Exception) as exc:
208 | message_data = """
209 | {
210 | "auth_token": "4453b6ac1s345678-e02c5f12174805f9-daec9cbb5448c51r",
211 | "receiver": "01234567890A=",
212 | "sender":
213 | {
214 | "name": "yarden from the pa",
215 | "avatar": "http://avatar_url"
216 | }
217 | }
218 | """
219 |
220 | get_message(json.loads(message_data))
221 | assert exc.value.message.startswith("message data doesn't contain a type")
222 |
--------------------------------------------------------------------------------
/tests/api/messages/test_keyboard_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import KeyboardMessage
2 |
3 | SAMPLE_TRACKING_DATA = "some tracking data"
4 | SAMPLE_KEYBOARD = {
5 | "Type": "keyboard",
6 | "Revision": 1,
7 | "Buttons": [
8 | {
9 | "Columns": 3,
10 | "Rows": 2,
11 | "BgColor": "#e6f5ff",
12 | "BgMedia": "http://www.jqueryscript.net/images/Simplest-Responsive-jQuery-Image-Lightbox-Plugin-simple-lightbox.jpg",
13 | "BgMediaType": "picture",
14 | "BgLoop": True,
15 | "ActionType": "reply",
16 | "ActionBody": "whatwhatwhatwhatwhatwhat"
17 | }
18 | ]
19 | }
20 |
21 |
22 | def test_creation():
23 | keyboard_message = KeyboardMessage(
24 | tracking_data=SAMPLE_TRACKING_DATA,
25 | keyboard=SAMPLE_KEYBOARD
26 | )
27 |
28 | assert keyboard_message.tracking_data == SAMPLE_TRACKING_DATA
29 | assert keyboard_message.keyboard == SAMPLE_KEYBOARD
30 |
31 |
32 | def test_to_dict():
33 | message_dict = dict(
34 | tracking_data=SAMPLE_TRACKING_DATA,
35 | keyboard=SAMPLE_KEYBOARD
36 | )
37 |
38 | keyboard_message_dict = KeyboardMessage(
39 | tracking_data=SAMPLE_TRACKING_DATA,
40 | keyboard=SAMPLE_KEYBOARD
41 | ).to_dict()
42 |
43 | assert message_dict == keyboard_message_dict
44 |
45 |
46 | def test_from_dict():
47 | message_dict = dict(
48 | tracking_data=SAMPLE_TRACKING_DATA,
49 | keyboard=SAMPLE_KEYBOARD
50 | )
51 |
52 | keyboard_message = KeyboardMessage().from_dict(message_dict)
53 |
54 | assert keyboard_message.tracking_data == SAMPLE_TRACKING_DATA
55 | assert keyboard_message.keyboard == SAMPLE_KEYBOARD
56 |
57 |
58 | def test_validate_success():
59 | keyboard_message = KeyboardMessage(
60 | tracking_data=SAMPLE_TRACKING_DATA,
61 | keyboard=SAMPLE_KEYBOARD
62 | )
63 |
64 | assert keyboard_message.validate()
65 |
66 |
67 | def test_validate_failure():
68 | keyboard_message = KeyboardMessage(
69 | tracking_data=SAMPLE_TRACKING_DATA
70 | )
71 |
72 | assert not keyboard_message.validate()
73 |
--------------------------------------------------------------------------------
/tests/api/messages/test_location_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import LocationMessage
2 | from viberbot.api.messages import MessageType
3 | from viberbot.api.messages.data_types.location import Location
4 |
5 | SAMPLE_TRACKING_DATA = "some tracking data"
6 | SAMPLE_KEYBOARD = """{
7 | "Type": "keyboard",
8 | "DefaultHeight": true,
9 | "BgColor": "#FFFFFF",
10 | "Buttons": [
11 | {
12 | "Columns": 6,
13 | "Rows": 1,
14 | "BgColor": "#2db9b9",
15 | "BgMediaType": "gif",
16 | "BgMedia": "http://www.url.by/test.gif",
17 | "BgLoop": true,
18 | "ActionType": "open-url",
19 | "ActionBody": "www.tut.by",
20 | "Image": "www.tut.by/img.jpg",
21 | "Text": "Key text",
22 | "TextVAlign": "middle",
23 | "TextHAlign": "center",
24 | "TextOpacity": 60,
25 | "TextSize": "regular"
26 | }
27 | ]
28 | }"""
29 | SAMPLE_LATITUDE = 10.7
30 | SAMPLE_LONGITUDE = -10.1
31 | SAMPLE_LOCATION = Location(SAMPLE_LATITUDE, SAMPLE_LONGITUDE)
32 |
33 |
34 | def test_creation():
35 | location_message = LocationMessage(
36 | tracking_data=SAMPLE_TRACKING_DATA,
37 | keyboard=SAMPLE_KEYBOARD,
38 | location=SAMPLE_LOCATION
39 | )
40 |
41 | assert location_message.tracking_data == SAMPLE_TRACKING_DATA
42 | assert location_message.keyboard == SAMPLE_KEYBOARD
43 | assert location_message.location == SAMPLE_LOCATION
44 |
45 |
46 | def test_from_dict():
47 | message_dict = dict(
48 | tracking_data=SAMPLE_TRACKING_DATA,
49 | keyboard=SAMPLE_KEYBOARD,
50 | location=dict(lat=SAMPLE_LATITUDE, lon=SAMPLE_LONGITUDE)
51 | )
52 |
53 | location_message = LocationMessage().from_dict(message_dict)
54 |
55 | assert location_message.tracking_data == SAMPLE_TRACKING_DATA
56 | assert location_message.keyboard == SAMPLE_KEYBOARD
57 | assert location_message.location == SAMPLE_LOCATION
58 |
59 |
60 | def test_to_dict():
61 | message_dict = dict(
62 | type=MessageType.LOCATION,
63 | tracking_data=SAMPLE_TRACKING_DATA,
64 | keyboard=SAMPLE_KEYBOARD,
65 | location=dict(lat=SAMPLE_LATITUDE, lon=SAMPLE_LONGITUDE)
66 | )
67 |
68 | location_message_dict = LocationMessage(
69 | tracking_data=SAMPLE_TRACKING_DATA,
70 | keyboard=SAMPLE_KEYBOARD,
71 | location=SAMPLE_LOCATION
72 | ).to_dict()
73 |
74 | assert message_dict == location_message_dict
75 |
76 |
77 | def test_validate_success():
78 | location_message = LocationMessage(
79 | tracking_data=SAMPLE_TRACKING_DATA,
80 | keyboard=SAMPLE_KEYBOARD,
81 | location=SAMPLE_LOCATION
82 | )
83 |
84 | assert location_message.validate()
85 |
86 |
87 | def test_validate_failure():
88 | location_message = LocationMessage(
89 | tracking_data=SAMPLE_TRACKING_DATA,
90 | keyboard=SAMPLE_KEYBOARD
91 | )
92 | assert not location_message.validate()
93 |
94 | location_message = LocationMessage(
95 | tracking_data=SAMPLE_TRACKING_DATA,
96 | keyboard=SAMPLE_KEYBOARD,
97 | location=Location()
98 | )
99 | assert not location_message.validate()
100 |
101 | location_message = LocationMessage(
102 | tracking_data=SAMPLE_TRACKING_DATA,
103 | keyboard=SAMPLE_KEYBOARD,
104 | location=Location(lat=SAMPLE_LATITUDE)
105 | )
106 | assert not location_message.validate()
107 |
108 | location_message = LocationMessage(
109 | tracking_data=SAMPLE_TRACKING_DATA,
110 | keyboard=SAMPLE_KEYBOARD,
111 | location=Location(lon=SAMPLE_LONGITUDE)
112 | )
113 | assert not location_message.validate()
114 |
115 |
116 | def test_validate_out_of_range():
117 | OUT_OF_RANGE_LATITUDE = 200
118 | OUT_OF_RANGE_LONGITUDE = 200
119 |
120 | location_message = LocationMessage(
121 | tracking_data=SAMPLE_TRACKING_DATA,
122 | keyboard=SAMPLE_KEYBOARD,
123 | location=Location(lat=SAMPLE_LATITUDE, lon=OUT_OF_RANGE_LONGITUDE)
124 | )
125 | assert not location_message.validate()
126 |
127 | location_message = LocationMessage(
128 | tracking_data=SAMPLE_TRACKING_DATA,
129 | keyboard=SAMPLE_KEYBOARD,
130 | location=Location(lat=OUT_OF_RANGE_LATITUDE, lon=SAMPLE_LONGITUDE)
131 | )
132 | assert not location_message.validate()
133 |
134 |
135 |
--------------------------------------------------------------------------------
/tests/api/messages/test_picture_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import MessageType
2 | from viberbot.api.messages import PictureMessage
3 |
4 | SAMPLE_TRACKING_DATA = "some tracking data"
5 | SAMPLE_KEYBOARD = """{
6 | "Type": "keyboard",
7 | "DefaultHeight": true,
8 | "BgColor": "#FFFFFF",
9 | "Buttons": [
10 | {
11 | "Columns": 6,
12 | "Rows": 1,
13 | "BgColor": "#2db9b9",
14 | "BgMediaType": "gif",
15 | "BgMedia": "http://www.url.by/test.gif",
16 | "BgLoop": true,
17 | "ActionType": "open-url",
18 | "ActionBody": "www.tut.by",
19 | "Image": "www.tut.by/img.jpg",
20 | "Text": "Key text",
21 | "TextVAlign": "middle",
22 | "TextHAlign": "center",
23 | "TextOpacity": 60,
24 | "TextSize": "regular"
25 | }
26 | ]
27 | }"""
28 | SAMPLE_TEXT = "bridge"
29 | SAMPLE_MEDIA = "http://www.site.com/bridge.jpg"
30 | SAMPLE_THUMBNAIL = "http://www.site.com/bridgethumb.jpg"
31 |
32 |
33 | def test_creation():
34 | picture_message = PictureMessage(
35 | tracking_data=SAMPLE_TRACKING_DATA,
36 | keyboard=SAMPLE_KEYBOARD,
37 | text=SAMPLE_TEXT,
38 | media=SAMPLE_MEDIA,
39 | thumbnail=SAMPLE_THUMBNAIL
40 | )
41 |
42 | assert picture_message.tracking_data == SAMPLE_TRACKING_DATA
43 | assert picture_message.keyboard == SAMPLE_KEYBOARD
44 | assert picture_message.media == SAMPLE_MEDIA
45 | assert picture_message.text == SAMPLE_TEXT
46 | assert picture_message.thumbnail == SAMPLE_THUMBNAIL
47 |
48 |
49 | def test_from_dict():
50 | message_dict = dict(
51 | tracking_data=SAMPLE_TRACKING_DATA,
52 | keyboard=SAMPLE_KEYBOARD,
53 | text=SAMPLE_TEXT,
54 | media=SAMPLE_MEDIA,
55 | thumbnail=SAMPLE_THUMBNAIL
56 | )
57 |
58 | picture_message = PictureMessage().from_dict(message_dict)
59 |
60 | assert picture_message.tracking_data == SAMPLE_TRACKING_DATA
61 | assert picture_message.keyboard == SAMPLE_KEYBOARD
62 | assert picture_message.media == SAMPLE_MEDIA
63 | assert picture_message.text == SAMPLE_TEXT
64 | assert picture_message.thumbnail == SAMPLE_THUMBNAIL
65 |
66 |
67 | def test_to_dict():
68 | message_dict = dict(
69 | type=MessageType.PICTURE,
70 | tracking_data=SAMPLE_TRACKING_DATA,
71 | keyboard=SAMPLE_KEYBOARD,
72 | text=SAMPLE_TEXT,
73 | media=SAMPLE_MEDIA,
74 | thumbnail=SAMPLE_THUMBNAIL
75 | )
76 |
77 | picture_message_dict = PictureMessage(
78 | tracking_data=SAMPLE_TRACKING_DATA,
79 | keyboard=SAMPLE_KEYBOARD,
80 | text=SAMPLE_TEXT,
81 | media=SAMPLE_MEDIA,
82 | thumbnail=SAMPLE_THUMBNAIL
83 | ).to_dict()
84 |
85 | assert message_dict == picture_message_dict
86 |
87 |
88 | def test_validate_success():
89 | picture_message = PictureMessage(
90 | tracking_data=SAMPLE_TRACKING_DATA,
91 | keyboard=SAMPLE_KEYBOARD,
92 | text=SAMPLE_TEXT,
93 | media=SAMPLE_MEDIA,
94 | thumbnail=SAMPLE_THUMBNAIL
95 | )
96 |
97 | assert picture_message.validate()
98 |
99 |
100 | def test_validate_failure():
101 | picture_message = PictureMessage(
102 | tracking_data=SAMPLE_TRACKING_DATA,
103 | keyboard=SAMPLE_KEYBOARD,
104 | text=SAMPLE_TEXT,
105 | thumbnail=SAMPLE_THUMBNAIL
106 | )
107 |
108 | assert not picture_message.validate()
109 |
--------------------------------------------------------------------------------
/tests/api/messages/test_rich_media_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import MessageType
2 | from viberbot.api.messages import RichMediaMessage
3 |
4 | SAMPLE_TRACKING_DATA = "some tracking data"
5 | SAMPLE_KEYBOARD = """{
6 | "Type": "keyboard",
7 | "DefaultHeight": true,
8 | "BgColor": "#FFFFFF",
9 | "Buttons": [
10 | {
11 | "Columns": 6,
12 | "Rows": 1,
13 | "BgColor": "#2db9b9",
14 | "BgMediaType": "gif",
15 | "BgMedia": "http://www.url.by/test.gif",
16 | "BgLoop": true,
17 | "ActionType": "open-url",
18 | "ActionBody": "www.tut.by",
19 | "Image": "www.tut.by/img.jpg",
20 | "Text": "Key text",
21 | "TextVAlign": "middle",
22 | "TextHAlign": "center",
23 | "TextOpacity": 60,
24 | "TextSize": "regular"
25 | }
26 | ]
27 | }"""
28 | SAMPLE_RICH_MEDIA = """{
29 | "DefaultHeight": true,
30 | "BgColor": "#69C48A",
31 | "Buttons": [
32 | {
33 | "Columns": 6,
34 | "Rows": 1,
35 | "BgColor": "#454545",
36 | "BgMediaType": "gif",
37 | "BgMedia": "http://www.url.by/test.gif",
38 | "BgLoop": true,
39 | "ActionType": "open-url",
40 | "Silent": true,
41 | "ActionBody": "www.tut.by",
42 | "Image": "www.tut.by/img.jpg",
43 | "TextVAlign": "middle",
44 | "TextHAlign": "left",
45 | "Text": "Viber is the best company",
46 | "TextOpacity": 10,
47 | "TextSize": "regular"
48 | }
49 | ]
50 | }"""
51 | SAMPLE_ALT_TEXT = "upgrade now!"
52 |
53 |
54 | def test_creation():
55 | text_message = RichMediaMessage(
56 | tracking_data=SAMPLE_TRACKING_DATA,
57 | keyboard=SAMPLE_KEYBOARD,
58 | rich_media=SAMPLE_RICH_MEDIA,
59 | alt_text=SAMPLE_ALT_TEXT
60 | )
61 |
62 | assert text_message.tracking_data == SAMPLE_TRACKING_DATA
63 | assert text_message.keyboard == SAMPLE_KEYBOARD
64 | assert text_message.rich_media == SAMPLE_RICH_MEDIA
65 | assert text_message.alt_text == SAMPLE_ALT_TEXT
66 |
67 |
68 | def test_to_dict():
69 | message_dict = dict(
70 | type=MessageType.RICH_MEDIA,
71 | tracking_data=SAMPLE_TRACKING_DATA,
72 | keyboard=SAMPLE_KEYBOARD,
73 | rich_media=SAMPLE_RICH_MEDIA,
74 | alt_text=SAMPLE_ALT_TEXT
75 | )
76 |
77 | rich_media_message_dict = RichMediaMessage(
78 | tracking_data=SAMPLE_TRACKING_DATA,
79 | keyboard=SAMPLE_KEYBOARD,
80 | rich_media=SAMPLE_RICH_MEDIA,
81 | alt_text=SAMPLE_ALT_TEXT
82 | ).to_dict()
83 |
84 | assert message_dict == rich_media_message_dict
85 |
86 |
87 | def test_from_dict():
88 | message_dict = dict(
89 | tracking_data=SAMPLE_TRACKING_DATA,
90 | keyboard=SAMPLE_KEYBOARD,
91 | rich_media=SAMPLE_RICH_MEDIA,
92 | alt_text=SAMPLE_ALT_TEXT
93 | )
94 |
95 | text_message = RichMediaMessage().from_dict(message_dict)
96 |
97 | assert text_message.tracking_data == SAMPLE_TRACKING_DATA
98 | assert text_message.keyboard == SAMPLE_KEYBOARD
99 | assert text_message.rich_media == SAMPLE_RICH_MEDIA
100 | assert text_message.alt_text == SAMPLE_ALT_TEXT
101 |
102 |
103 | def test_validate_success():
104 | text_message = RichMediaMessage(
105 | tracking_data=SAMPLE_TRACKING_DATA,
106 | keyboard=SAMPLE_KEYBOARD,
107 | rich_media=SAMPLE_RICH_MEDIA
108 | )
109 |
110 | assert text_message.validate()
111 |
112 |
113 | def test_validate_failure():
114 | text_message = RichMediaMessage(
115 | tracking_data=SAMPLE_TRACKING_DATA,
116 | keyboard=SAMPLE_KEYBOARD
117 | )
118 |
119 | assert not text_message.validate()
120 |
--------------------------------------------------------------------------------
/tests/api/messages/test_sticker_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import MessageType
2 | from viberbot.api.messages import StickerMessage
3 |
4 | SAMPLE_TRACKING_DATA = "some tracking data"
5 | SAMPLE_KEYBOARD = """{
6 | "Type": "keyboard",
7 | "DefaultHeight": true,
8 | "BgColor": "#FFFFFF",
9 | "Buttons": [
10 | {
11 | "Columns": 6,
12 | "Rows": 1,
13 | "BgColor": "#2db9b9",
14 | "BgMediaType": "gif",
15 | "BgMedia": "http://www.url.by/test.gif",
16 | "BgLoop": true,
17 | "ActionType": "open-url",
18 | "ActionBody": "www.tut.by",
19 | "Image": "www.tut.by/img.jpg",
20 | "Text": "Key text",
21 | "TextVAlign": "middle",
22 | "TextHAlign": "center",
23 | "TextOpacity": 60,
24 | "TextSize": "regular"
25 | }
26 | ]
27 | }"""
28 | SAMPLE_STICKER_ID = 40100
29 |
30 |
31 | def test_creation():
32 | sticker_message = StickerMessage(
33 | tracking_data=SAMPLE_TRACKING_DATA,
34 | keyboard=SAMPLE_KEYBOARD,
35 | sticker_id=SAMPLE_STICKER_ID
36 | )
37 |
38 | assert sticker_message.tracking_data == SAMPLE_TRACKING_DATA
39 | assert sticker_message.keyboard == SAMPLE_KEYBOARD
40 | assert sticker_message.sticker_id == SAMPLE_STICKER_ID
41 |
42 |
43 | def test_to_dict():
44 | message_dict = dict(
45 | type=MessageType.STICKER,
46 | tracking_data=SAMPLE_TRACKING_DATA,
47 | keyboard=SAMPLE_KEYBOARD,
48 | sticker_id=SAMPLE_STICKER_ID
49 | )
50 |
51 | sticker_message_dict = StickerMessage(
52 | tracking_data=SAMPLE_TRACKING_DATA,
53 | keyboard=SAMPLE_KEYBOARD,
54 | sticker_id=SAMPLE_STICKER_ID
55 | ).to_dict()
56 |
57 | assert message_dict == sticker_message_dict
58 |
59 |
60 | def test_from_dict():
61 | message_dict = dict(
62 | tracking_data=SAMPLE_TRACKING_DATA,
63 | keyboard=SAMPLE_KEYBOARD,
64 | sticker_id=SAMPLE_STICKER_ID
65 | )
66 |
67 | sticker_message = StickerMessage().from_dict(message_dict)
68 |
69 | assert sticker_message.tracking_data == SAMPLE_TRACKING_DATA
70 | assert sticker_message.keyboard == SAMPLE_KEYBOARD
71 | assert sticker_message.sticker_id == SAMPLE_STICKER_ID
72 |
73 |
74 | def test_validate_success():
75 | sticker_message = StickerMessage(
76 | tracking_data=SAMPLE_TRACKING_DATA,
77 | keyboard=SAMPLE_KEYBOARD,
78 | sticker_id=SAMPLE_STICKER_ID
79 | )
80 |
81 | assert sticker_message.validate()
82 |
83 |
84 | def test_validate_failure():
85 | sticker_message = StickerMessage(
86 | tracking_data=SAMPLE_TRACKING_DATA,
87 | keyboard=SAMPLE_KEYBOARD
88 | )
89 |
90 | assert not sticker_message.validate()
91 |
--------------------------------------------------------------------------------
/tests/api/messages/test_text_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import MessageType
2 | from viberbot.api.messages import TextMessage
3 |
4 | SAMPLE_TRACKING_DATA = "some tracking data"
5 | SAMPLE_KEYBOARD = """{
6 | "Type": "keyboard",
7 | "DefaultHeight": true,
8 | "BgColor": "#FFFFFF",
9 | "Buttons": [
10 | {
11 | "Columns": 6,
12 | "Rows": 1,
13 | "BgColor": "#2db9b9",
14 | "BgMediaType": "gif",
15 | "BgMedia": "http://www.url.by/test.gif",
16 | "BgLoop": true,
17 | "ActionType": "open-url",
18 | "ActionBody": "www.tut.by",
19 | "Image": "www.tut.by/img.jpg",
20 | "Text": "Key text",
21 | "TextVAlign": "middle",
22 | "TextHAlign": "center",
23 | "TextOpacity": 60,
24 | "TextSize": "regular"
25 | }
26 | ]
27 | }"""
28 | SAMPLE_TEXT = "sample text"
29 |
30 |
31 | def test_creation():
32 | text_message = TextMessage(
33 | tracking_data=SAMPLE_TRACKING_DATA,
34 | keyboard=SAMPLE_KEYBOARD,
35 | text=SAMPLE_TEXT
36 | )
37 |
38 | assert text_message.tracking_data == SAMPLE_TRACKING_DATA
39 | assert text_message.keyboard == SAMPLE_KEYBOARD
40 | assert text_message.text == SAMPLE_TEXT
41 |
42 |
43 | def test_to_dict():
44 | message_dict = dict(
45 | type=MessageType.TEXT,
46 | tracking_data=SAMPLE_TRACKING_DATA,
47 | keyboard=SAMPLE_KEYBOARD,
48 | text=SAMPLE_TEXT
49 | )
50 |
51 | text_message_dict = TextMessage(
52 | tracking_data=SAMPLE_TRACKING_DATA,
53 | keyboard=SAMPLE_KEYBOARD,
54 | text=SAMPLE_TEXT
55 | ).to_dict()
56 |
57 | assert message_dict == text_message_dict
58 |
59 |
60 | def test_from_dict():
61 | message_dict = dict(
62 | tracking_data=SAMPLE_TRACKING_DATA,
63 | keyboard=SAMPLE_KEYBOARD,
64 | text=SAMPLE_TEXT
65 | )
66 |
67 | text_message = TextMessage().from_dict(message_dict)
68 |
69 | assert text_message.tracking_data == SAMPLE_TRACKING_DATA
70 | assert text_message.keyboard == SAMPLE_KEYBOARD
71 | assert text_message.text == SAMPLE_TEXT
72 |
73 |
74 | def test_validate_success():
75 | text_message = TextMessage(
76 | tracking_data=SAMPLE_TRACKING_DATA,
77 | keyboard=SAMPLE_KEYBOARD,
78 | text=SAMPLE_TEXT
79 | )
80 |
81 | assert text_message.validate()
82 |
83 |
84 | def test_validate_failure():
85 | text_message = TextMessage(
86 | tracking_data=SAMPLE_TRACKING_DATA,
87 | keyboard=SAMPLE_KEYBOARD
88 | )
89 |
90 | assert not text_message.validate()
91 |
--------------------------------------------------------------------------------
/tests/api/messages/test_url_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import MessageType
2 | from viberbot.api.messages import URLMessage
3 |
4 | SAMPLE_TRACKING_DATA = "some tracking data"
5 | SAMPLE_KEYBOARD = """{
6 | "Type": "keyboard",
7 | "DefaultHeight": true,
8 | "BgColor": "#FFFFFF",
9 | "Buttons": [
10 | {
11 | "Columns": 6,
12 | "Rows": 1,
13 | "BgColor": "#2db9b9",
14 | "BgMediaType": "gif",
15 | "BgMedia": "http://www.url.by/test.gif",
16 | "BgLoop": true,
17 | "ActionType": "open-url",
18 | "ActionBody": "www.tut.by",
19 | "Image": "www.tut.by/img.jpg",
20 | "Text": "Key text",
21 | "TextVAlign": "middle",
22 | "TextHAlign": "center",
23 | "TextOpacity": 60,
24 | "TextSize": "regular"
25 | }
26 | ]
27 | }"""
28 | SAMPLE_URL = "http://www.google.com"
29 |
30 |
31 | def test_creation():
32 | url_message = URLMessage(
33 | tracking_data=SAMPLE_TRACKING_DATA,
34 | keyboard=SAMPLE_KEYBOARD,
35 | media=SAMPLE_URL
36 | )
37 |
38 | assert url_message.tracking_data == SAMPLE_TRACKING_DATA
39 | assert url_message.keyboard == SAMPLE_KEYBOARD
40 | assert url_message.media == SAMPLE_URL
41 |
42 |
43 | def test_to_dict():
44 | message_dict = dict(
45 | type=MessageType.URL,
46 | tracking_data=SAMPLE_TRACKING_DATA,
47 | keyboard=SAMPLE_KEYBOARD,
48 | media=SAMPLE_URL
49 | )
50 |
51 | url_message_dict = URLMessage(
52 | tracking_data=SAMPLE_TRACKING_DATA,
53 | keyboard=SAMPLE_KEYBOARD,
54 | media=SAMPLE_URL
55 | ).to_dict()
56 |
57 | assert message_dict == url_message_dict
58 |
59 |
60 | def test_from_dict():
61 | message_dict = dict(
62 | tracking_data=SAMPLE_TRACKING_DATA,
63 | keyboard=SAMPLE_KEYBOARD,
64 | media=SAMPLE_URL
65 | )
66 |
67 | url_message = URLMessage().from_dict(message_dict)
68 |
69 | assert url_message.tracking_data == SAMPLE_TRACKING_DATA
70 | assert url_message.keyboard == SAMPLE_KEYBOARD
71 | assert url_message.media == SAMPLE_URL
72 |
73 |
74 | def test_validate_success():
75 | url_message = URLMessage(
76 | tracking_data=SAMPLE_TRACKING_DATA,
77 | keyboard=SAMPLE_KEYBOARD,
78 | media=SAMPLE_URL
79 | )
80 |
81 | assert url_message.validate()
82 |
83 |
84 | def test_validate_failure():
85 | url_message = URLMessage(
86 | tracking_data=SAMPLE_TRACKING_DATA,
87 | keyboard=SAMPLE_KEYBOARD
88 | )
89 |
90 | assert not url_message.validate()
91 |
--------------------------------------------------------------------------------
/tests/api/messages/test_video_message.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages import MessageType
2 | from viberbot.api.messages import VideoMessage
3 |
4 | SAMPLE_TRACKING_DATA = "some tracking data"
5 | SAMPLE_KEYBOARD = """{
6 | "Type": "keyboard",
7 | "DefaultHeight": true,
8 | "BgColor": "#FFFFFF",
9 | "Buttons": [
10 | {
11 | "Columns": 6,
12 | "Rows": 1,
13 | "BgColor": "#2db9b9",
14 | "BgMediaType": "gif",
15 | "BgMedia": "http://www.url.by/test.gif",
16 | "BgLoop": true,
17 | "ActionType": "open-url",
18 | "ActionBody": "www.tut.by",
19 | "Image": "www.tut.by/img.jpg",
20 | "Text": "Key text",
21 | "TextVAlign": "middle",
22 | "TextHAlign": "center",
23 | "TextOpacity": 60,
24 | "TextSize": "regular"
25 | }
26 | ]
27 | }"""
28 | SAMPLE_MEDIA = "http://www.site.com/bridge.mp4"
29 | SAMPLE_THUMBNAIL = "http://www.site.com/bridgethumb.jpg"
30 | SAMPLE_SIZE = 1000
31 | SAMPLE_DURATION = 10
32 | SAMPLE_TEXT = "see my video!"
33 |
34 |
35 | def test_creation():
36 | video_message = VideoMessage(
37 | tracking_data=SAMPLE_TRACKING_DATA,
38 | keyboard=SAMPLE_KEYBOARD,
39 | media=SAMPLE_MEDIA,
40 | thumbnail=SAMPLE_THUMBNAIL,
41 | size=SAMPLE_SIZE,
42 | duration=SAMPLE_DURATION,
43 | text=SAMPLE_TEXT
44 | )
45 |
46 | assert video_message.tracking_data == SAMPLE_TRACKING_DATA
47 | assert video_message.keyboard == SAMPLE_KEYBOARD
48 | assert video_message.media == SAMPLE_MEDIA
49 | assert video_message.size == SAMPLE_SIZE
50 | assert video_message.thumbnail == SAMPLE_THUMBNAIL
51 | assert video_message.duration == SAMPLE_DURATION
52 | assert video_message.text == SAMPLE_TEXT
53 |
54 |
55 | def test_from_dict():
56 | message_dict = dict(
57 | tracking_data=SAMPLE_TRACKING_DATA,
58 | keyboard=SAMPLE_KEYBOARD,
59 | media=SAMPLE_MEDIA,
60 | thumbnail=SAMPLE_THUMBNAIL,
61 | size=SAMPLE_SIZE,
62 | duration=SAMPLE_DURATION,
63 | text=SAMPLE_TEXT
64 | )
65 |
66 | video_message = VideoMessage().from_dict(message_dict)
67 |
68 | assert video_message.tracking_data == SAMPLE_TRACKING_DATA
69 | assert video_message.keyboard == SAMPLE_KEYBOARD
70 | assert video_message.media == SAMPLE_MEDIA
71 | assert video_message.size == SAMPLE_SIZE
72 | assert video_message.thumbnail == SAMPLE_THUMBNAIL
73 | assert video_message.duration == SAMPLE_DURATION
74 | assert video_message.text == SAMPLE_TEXT
75 |
76 |
77 | def test_to_dict():
78 | message_dict = dict(
79 | type=MessageType.VIDEO,
80 | tracking_data=SAMPLE_TRACKING_DATA,
81 | keyboard=SAMPLE_KEYBOARD,
82 | media=SAMPLE_MEDIA,
83 | thumbnail=SAMPLE_THUMBNAIL,
84 | size=SAMPLE_SIZE,
85 | duration=SAMPLE_DURATION,
86 | text=SAMPLE_TEXT
87 | )
88 |
89 | video_message_dict = VideoMessage(
90 | tracking_data=SAMPLE_TRACKING_DATA,
91 | keyboard=SAMPLE_KEYBOARD,
92 | media=SAMPLE_MEDIA,
93 | thumbnail=SAMPLE_THUMBNAIL,
94 | size=SAMPLE_SIZE,
95 | duration=SAMPLE_DURATION,
96 | text=SAMPLE_TEXT
97 | ).to_dict()
98 |
99 | assert message_dict == video_message_dict
100 |
101 |
102 | def test_validate_success():
103 | video_message = VideoMessage(
104 | media=SAMPLE_MEDIA,
105 | size=SAMPLE_SIZE
106 | )
107 |
108 | assert video_message.validate()
109 |
110 |
111 | def test_validate_failure():
112 | video_message = VideoMessage(
113 | tracking_data=SAMPLE_TRACKING_DATA,
114 | keyboard=SAMPLE_KEYBOARD,
115 | thumbnail=SAMPLE_THUMBNAIL,
116 | size=SAMPLE_SIZE,
117 | duration=SAMPLE_DURATION
118 | )
119 |
120 | assert not video_message.validate()
121 |
122 | video_message = VideoMessage(
123 | tracking_data=SAMPLE_TRACKING_DATA,
124 | keyboard=SAMPLE_KEYBOARD,
125 | media=SAMPLE_MEDIA,
126 | thumbnail=SAMPLE_THUMBNAIL,
127 | duration=SAMPLE_DURATION
128 | )
129 |
130 | assert not video_message.validate()
131 |
--------------------------------------------------------------------------------
/tests/api/test_api.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import pytest
4 |
5 | from viberbot import Api
6 | from viberbot import BotConfiguration
7 | from viberbot.api.viber_requests import ViberMessageRequest
8 |
9 | VIBER_BOT_CONFIGURATION = BotConfiguration("44dafb7e0f40021e-61a47a1e6778d187-f2c5a676a07050b3", "testbot", "http://avatars.com/")
10 |
11 |
12 | def test_verify_signature():
13 | valid_signature = 'd21b343448c8aee33b8e93768ef6ceb64a6ba6163099973a2b8bd028fea510ef'
14 | message = "{\"event\":\"webhook\",\"timestamp\":4977069964384421269,\"message_token\":1478683725125}".encode("utf-8")
15 |
16 | viber = Api(VIBER_BOT_CONFIGURATION)
17 | assert viber.verify_signature(message, valid_signature)
18 |
19 |
20 | def test_verify_signature_failure():
21 | invalid_signature = 'aaaaaaaaaaaaaaaaaaaaaa'
22 | message = "{\"event\":\"webhook\"}".encode("utf-8")
23 |
24 | viber = Api(VIBER_BOT_CONFIGURATION)
25 | assert not viber.verify_signature(message, invalid_signature)
26 |
27 |
28 | def test_parse_request_not_json():
29 | viber = Api(VIBER_BOT_CONFIGURATION)
30 |
31 | with pytest.raises(ValueError) as exc:
32 | viber.parse_request("dsfdfdsf\#")
33 |
34 |
35 | def test_parse_request_unicode():
36 | viber = Api(VIBER_BOT_CONFIGURATION)
37 |
38 | with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_data', 'unicode_request')) as f:
39 | req = f.read()
40 | viber_request = viber.parse_request(req)
41 | assert isinstance(viber_request, ViberMessageRequest)
42 |
--------------------------------------------------------------------------------
/tests/api/test_api_request_sender.py:
--------------------------------------------------------------------------------
1 | import json
2 | import logging
3 |
4 | import pytest
5 |
6 | from viberbot.api.api_request_sender import ApiRequestSender
7 | from viberbot.api.bot_configuration import BotConfiguration
8 | from viberbot.api.consts import BOT_API_ENDPOINT, VIBER_BOT_USER_AGENT
9 | from viberbot.api.event_type import EventType
10 |
11 |
12 | class Stub(object): pass
13 |
14 |
15 | def stub(*args): pass
16 |
17 |
18 | VIBER_BOT_API_URL = "http://site.com"
19 | VIBER_BOT_CONFIGURATION = BotConfiguration("auth-token-sample", "testbot", "http://avatars.com/")
20 |
21 |
22 | def test_set_webhook_sanity():
23 | webhook_events = [EventType.DELIVERED, EventType.UNSUBSCRIBED, EventType.SEEN]
24 | url = "http://sample.url.com"
25 |
26 | def post_request(endpoint, payload):
27 | request = json.loads(payload)
28 | assert endpoint == BOT_API_ENDPOINT.SET_WEBHOOK
29 | assert request['auth_token'] == VIBER_BOT_CONFIGURATION.auth_token
30 | assert request['event_types'] == webhook_events
31 | assert request['url'] == url
32 | return dict(status=0, event_types=webhook_events)
33 |
34 | request_sender = ApiRequestSender(logging.getLogger(), VIBER_BOT_API_URL, VIBER_BOT_CONFIGURATION, VIBER_BOT_USER_AGENT)
35 | request_sender.post_request = post_request
36 |
37 | request_sender.set_webhook(url=url, webhook_events=webhook_events)
38 |
39 |
40 | def test_set_webhook_failure():
41 | webhook_events = [EventType.DELIVERED, EventType.UNSUBSCRIBED, EventType.SEEN]
42 | url = "http://sample.url.com"
43 |
44 | def post_request(endpoint, payload):
45 | return dict(status=1, status_message="failed")
46 |
47 | request_sender = ApiRequestSender(logging.getLogger(), VIBER_BOT_API_URL, VIBER_BOT_CONFIGURATION, VIBER_BOT_USER_AGENT)
48 | request_sender.post_request = post_request
49 | with pytest.raises(Exception) as exc:
50 | request_sender.set_webhook(url=url, webhook_events=webhook_events)
51 |
52 | assert exc.value.message.startswith("failed with status: 1, message: failed")
53 |
54 |
55 | def test_post_request_success(monkeypatch):
56 | def callback(endpoint, data, headers):
57 | request = json.loads(data)
58 | assert endpoint == VIBER_BOT_API_URL + "/" + BOT_API_ENDPOINT.GET_ACCOUNT_INFO
59 | assert request['auth_token'] == VIBER_BOT_CONFIGURATION.auth_token
60 | assert headers['User-Agent'] == VIBER_BOT_USER_AGENT
61 | response = Stub()
62 | response.raise_for_status = stub
63 | response.text = "{}"
64 |
65 | return response
66 |
67 | monkeypatch.setattr("requests.post", callback)
68 |
69 | request_sender = ApiRequestSender(logging.getLogger(), VIBER_BOT_API_URL, VIBER_BOT_CONFIGURATION, VIBER_BOT_USER_AGENT)
70 | request_sender.get_account_info()
71 |
72 |
73 | def test_post_request_json_exception(monkeypatch):
74 | def callback(endpoint, data, headers):
75 | request = json.loads(data)
76 | assert endpoint == VIBER_BOT_API_URL + "/" + BOT_API_ENDPOINT.GET_ACCOUNT_INFO
77 | assert request['auth_token'] == VIBER_BOT_CONFIGURATION.auth_token
78 | assert headers['User-Agent'] == VIBER_BOT_USER_AGENT
79 | response = Stub()
80 | response.raise_for_status = stub
81 | response.text = "not a json{/"
82 |
83 | return response
84 |
85 | monkeypatch.setattr("requests.post", callback)
86 | request_sender = ApiRequestSender(logging.getLogger(), VIBER_BOT_API_URL, VIBER_BOT_CONFIGURATION, VIBER_BOT_USER_AGENT)
87 |
88 | with pytest.raises(Exception) as exc:
89 | request_sender.get_account_info()
90 |
91 |
92 | def test_get_online_status_fail(monkeypatch):
93 | def callback(endpoint, data, headers):
94 | request = json.loads(data)
95 | assert endpoint == VIBER_BOT_API_URL + "/" + BOT_API_ENDPOINT.GET_ONLINE
96 | assert request['auth_token'] == VIBER_BOT_CONFIGURATION.auth_token
97 | assert headers['User-Agent'] == VIBER_BOT_USER_AGENT
98 | response = Stub()
99 | response.raise_for_status = stub
100 | response.text = "{\"status\": 1, \"status_message\": \"fail\"}"
101 |
102 | return response
103 |
104 | monkeypatch.setattr("requests.post", callback)
105 | request_sender = ApiRequestSender(logging.getLogger(), VIBER_BOT_API_URL, VIBER_BOT_CONFIGURATION, VIBER_BOT_USER_AGENT)
106 |
107 | with pytest.raises(Exception) as exc:
108 | request_sender.get_online_status(ids=["0123456789="])
109 |
110 | assert exc.value.message.startswith("failed with status:")
111 |
112 |
113 | def test_get_online_missing_ids(monkeypatch):
114 | monkeypatch.setattr("requests.post", stub)
115 | request_sender = ApiRequestSender(logging.getLogger(), VIBER_BOT_API_URL, VIBER_BOT_CONFIGURATION, VIBER_BOT_USER_AGENT)
116 |
117 | with pytest.raises(Exception) as exc:
118 | request_sender.get_online_status(ids=None)
119 |
120 | assert exc.value.message.startswith("missing parameter ids, should be a list of viber memberIds")
121 |
122 |
123 | def test_get_online_success(monkeypatch):
124 | def callback(endpoint, data, headers):
125 | request = json.loads(data)
126 | assert endpoint == VIBER_BOT_API_URL + "/" + BOT_API_ENDPOINT.GET_ONLINE
127 | assert request['auth_token'] == VIBER_BOT_CONFIGURATION.auth_token
128 | response = Stub()
129 | response.raise_for_status = stub
130 | response.text = "{\"status\": 0, \"status_message\": \"OK\", \"users\": []}"
131 |
132 | return response
133 |
134 | monkeypatch.setattr("requests.post", callback)
135 | request_sender = ApiRequestSender(logging.getLogger(), VIBER_BOT_API_URL, VIBER_BOT_CONFIGURATION, VIBER_BOT_USER_AGENT)
136 |
137 | request_sender.get_online_status(ids=["03249305A="])
138 |
139 |
140 | def test_get_user_details_success(monkeypatch):
141 | def callback(endpoint, data, headers):
142 | request = json.loads(data)
143 | assert endpoint == VIBER_BOT_API_URL + "/" + BOT_API_ENDPOINT.GET_USER_DETAILS
144 | assert request['auth_token'] == VIBER_BOT_CONFIGURATION.auth_token
145 | response = Stub()
146 | response.raise_for_status = stub
147 | response.text = "{\"status\": 0, \"status_message\": \"OK\", \"user\": {}}"
148 |
149 | return response
150 |
151 | monkeypatch.setattr("requests.post", callback)
152 | request_sender = ApiRequestSender(logging.getLogger(), VIBER_BOT_API_URL, VIBER_BOT_CONFIGURATION, VIBER_BOT_USER_AGENT)
153 |
154 | request_sender.get_user_details(user_id="03249305A=")
155 |
--------------------------------------------------------------------------------
/tests/api/test_data/unicode_request:
--------------------------------------------------------------------------------
1 | {
2 | "event": "message",
3 | "timestamp": 1457764197627,
4 | "message_token": 4912661846655238145,
5 | "sender": {
6 | "id": "01234567890A=",
7 | "name": "ふで都急ぼちラり面関ごル期販ずラ否裁ぞるめ数努むや正記味てょ",
8 | "avatar": "http://avatar_url",
9 | "api_version": 2
10 | },
11 | "message": {
12 | "type": "text",
13 | "text": "批封廟根縄華勢田郎報株聞。変宝長独部鉱内出殺反提似惑金参勧車査真測。見名基現画府日室事集百藤米。発目本当党考万名東拓学早職表治月佐。町要静子呉遊推写間確長無読死覧件一盛治融。",
14 | "tracking_data": "אל תעקוב אחרי!"
15 | },
16 | "silent": false
17 | }
--------------------------------------------------------------------------------
/tests/api/test_message_sender.py:
--------------------------------------------------------------------------------
1 | import json
2 | import logging
3 |
4 | import pytest
5 |
6 | from viberbot.api.bot_configuration import BotConfiguration
7 | from viberbot.api.consts import BOT_API_ENDPOINT
8 | from viberbot.api.message_sender import MessageSender
9 | from viberbot.api.messages import TextMessage
10 |
11 | LOGGER = logging.getLogger('.')
12 | VIBER_BOT_CONFIGURATION = BotConfiguration("auth-token-sample", "testbot", "http://avatars.com/")
13 |
14 | class Stub(object): pass
15 |
16 |
17 | def stub(*args): pass
18 |
19 |
20 | def test_send_message_sanity():
21 | to = "012345A="
22 | text = "hi!"
23 | message_token = "a token"
24 | chat_id = 'my chat id sample'
25 |
26 | def post_request(endpoint, payload):
27 | data = json.loads(payload)
28 | assert endpoint == BOT_API_ENDPOINT.SEND_MESSAGE
29 | assert data['auth_token'] == VIBER_BOT_CONFIGURATION.auth_token
30 | assert data['receiver'] == to
31 | assert data['sender']['name'] == VIBER_BOT_CONFIGURATION.name
32 | assert data['sender']['avatar'] == VIBER_BOT_CONFIGURATION.avatar
33 | assert data['text'] == text
34 | assert data['chat_id'] == chat_id
35 | return dict(status=0, message_token=message_token)
36 |
37 | request_sender = Stub()
38 | request_sender.post_request = post_request
39 |
40 | text_message = TextMessage(text=text)
41 |
42 | message_sender = MessageSender(LOGGER, request_sender, VIBER_BOT_CONFIGURATION)
43 | token = message_sender.send_message(
44 | to, VIBER_BOT_CONFIGURATION.name, VIBER_BOT_CONFIGURATION.avatar, text_message, chat_id)
45 | assert token == message_token
46 |
47 |
48 | def test_post_to_public_account_sanity():
49 | sender = "012345A="
50 | text = "hi!"
51 | message_token = "a token"
52 |
53 | def post_request(endpoint, payload):
54 | data = json.loads(payload)
55 | assert endpoint == BOT_API_ENDPOINT.POST
56 | assert data['auth_token'] == VIBER_BOT_CONFIGURATION.auth_token
57 | assert data['from'] == sender
58 | assert data['sender']['name'] == VIBER_BOT_CONFIGURATION.name
59 | assert data['sender']['avatar'] == VIBER_BOT_CONFIGURATION.avatar
60 | assert data['text'] == text
61 | return dict(status=0, message_token=message_token)
62 |
63 | request_sender = Stub()
64 | request_sender.post_request = post_request
65 |
66 | text_message = TextMessage(text=text)
67 |
68 | message_sender = MessageSender(LOGGER, request_sender, VIBER_BOT_CONFIGURATION)
69 | token = message_sender.post_to_public_account(
70 | sender, VIBER_BOT_CONFIGURATION.name, VIBER_BOT_CONFIGURATION.avatar, text_message)
71 | assert token == message_token
72 |
73 |
74 | def test_message_invalid():
75 | to = "012345A="
76 |
77 | def post_request(endpoint, payload):
78 | pytest.fail("message sender not supposed to call post_request")
79 |
80 | request_sender = Stub()
81 | request_sender.post_request = post_request
82 |
83 | text_message = TextMessage(text=None)
84 |
85 | message_sender = MessageSender(LOGGER, request_sender, VIBER_BOT_CONFIGURATION)
86 | with pytest.raises(Exception) as exc:
87 | message_sender.send_message(to, VIBER_BOT_CONFIGURATION.name, VIBER_BOT_CONFIGURATION.avatar, text_message)
88 |
89 | assert exc.value.message.startswith("failed validating message:")
90 |
91 |
92 | def test_send_result_failed():
93 | to = "012345A="
94 | text = "hi!"
95 |
96 | def post_request(endpoint, payload):
97 | data = json.loads(payload)
98 | return dict(status=1, status_message="failed")
99 |
100 | request_sender = Stub()
101 | request_sender.post_request = post_request
102 |
103 | text_message = TextMessage(text=text)
104 |
105 | message_sender = MessageSender(LOGGER, request_sender, VIBER_BOT_CONFIGURATION)
106 | with pytest.raises(Exception) as exc:
107 | message_sender.send_message(to, VIBER_BOT_CONFIGURATION.name, VIBER_BOT_CONFIGURATION.avatar, text_message)
108 |
109 | assert exc.value.message.startswith("failed with status: 1, message: failed")
110 |
111 |
112 | def test_post_message_to_public_account_failed():
113 | sender = "012345A="
114 | text = "hi!"
115 |
116 | def post_request(endpoint, payload):
117 | data = json.loads(payload)
118 | return dict(status=1, status_message="failed")
119 |
120 | request_sender = Stub()
121 | request_sender.post_request = post_request
122 |
123 | text_message = TextMessage(text=text)
124 |
125 | message_sender = MessageSender(LOGGER, request_sender, VIBER_BOT_CONFIGURATION)
126 | with pytest.raises(Exception) as exc:
127 | message_sender.post_to_public_account(
128 | sender, VIBER_BOT_CONFIGURATION.name, VIBER_BOT_CONFIGURATION.avatar, text_message)
129 |
130 | assert exc.value.message.startswith("failed with status: 1, message: failed")
--------------------------------------------------------------------------------
/tests/api/viber_requests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Viber/viber-bot-python/5cfe34e3b7d1c98afdf5d2c09a4c5722a61f008f/tests/api/viber_requests/__init__.py
--------------------------------------------------------------------------------
/tests/api/viber_requests/test_create_request.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | import pytest
4 | from viberbot.api.messages import MessageType
5 | from viberbot.api.viber_requests import create_request
6 |
7 |
8 | def test_create_request_missing_event():
9 | sample_request = dict(
10 | timestamp=datetime.now(),
11 | message_token="912661846655238145",
12 | sender=dict(
13 | id="01234567890A=",
14 | name="viberUser",
15 | avatar="http://avatar_url"
16 | ),
17 | message=dict(
18 | type=MessageType.TEXT,
19 | text="HI!"
20 | ))
21 |
22 | with pytest.raises(Exception) as exc:
23 | create_request(sample_request)
24 | assert exc.value.message.startswith("request is missing field 'event'")
--------------------------------------------------------------------------------
/tests/api/viber_requests/test_viber_conversation_started_request.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from viberbot.api.event_type import EventType
4 | from viberbot.api.viber_requests import ViberConversationStartedRequest
5 | from viberbot.api.viber_requests import create_request
6 |
7 | SAMPLE_REQUEST = dict(
8 | event=EventType.CONVERSATION_STARTED,
9 | timestamp=datetime.now(),
10 | message_token="912661846655238145",
11 | type="open",
12 | context="context info",
13 | subscribed=True,
14 | user=dict(
15 | id="01234567890A=",
16 | name="viberUser",
17 | avatar="http://avatar_url",
18 | country="IL",
19 | language="en"
20 | ))
21 |
22 |
23 | def test_create_request():
24 | request = create_request(SAMPLE_REQUEST)
25 |
26 | assert isinstance(request, ViberConversationStartedRequest)
27 | assert request.event_type == SAMPLE_REQUEST['event']
28 | assert request.timestamp == SAMPLE_REQUEST['timestamp']
29 | assert request.message_token == SAMPLE_REQUEST['message_token']
30 | assert request.type == SAMPLE_REQUEST['type']
31 | assert request.context == SAMPLE_REQUEST['context']
32 | assert request.user.id == SAMPLE_REQUEST['user']['id']
33 | assert request.user.name == SAMPLE_REQUEST['user']['name']
34 | assert request.user.avatar == SAMPLE_REQUEST['user']['avatar']
35 | assert request.user.country == SAMPLE_REQUEST['user']['country']
36 | assert request.user.language == SAMPLE_REQUEST['user']['language']
37 | assert request.subscribed == SAMPLE_REQUEST['subscribed']
38 |
39 |
40 | def test_missing_user_optional_params():
41 | request_dict = dict(
42 | event=EventType.CONVERSATION_STARTED,
43 | timestamp=datetime.now(),
44 | message_token="912661846655238145",
45 | type="open",
46 | context="context info",
47 | user=dict(
48 | id="01234567890A=",
49 | name="viberUser"
50 | ))
51 |
52 | request = create_request(request_dict) # should not fail
53 |
54 | assert isinstance(request, ViberConversationStartedRequest)
55 | assert request.event_type == request_dict['event']
56 | assert request.timestamp == request_dict['timestamp']
57 | assert request.message_token == request_dict['message_token']
58 | assert request.type == request_dict['type']
59 | assert request.context == request_dict['context']
60 | assert request.user.id == request_dict['user']['id']
61 | assert request.user.name == request_dict['user']['name']
62 | assert request.user.avatar is None
63 | assert request.user.country is None
64 | assert request.user.language is None
65 | assert request.subscribed is None
66 |
--------------------------------------------------------------------------------
/tests/api/viber_requests/test_viber_delivered_request.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from viberbot.api.event_type import EventType
4 | from viberbot.api.viber_requests import ViberDeliveredRequest
5 | from viberbot.api.viber_requests import create_request
6 |
7 | SAMPLE_REQUEST = dict(
8 | event=EventType.DELIVERED,
9 | timestamp=datetime.now(),
10 | message_token="912661846655238145",
11 | user_id="01234567890A=",
12 | chat_id="3456675689-45345-35346235"
13 | )
14 |
15 |
16 | def test_create_request():
17 | request = create_request(SAMPLE_REQUEST)
18 |
19 | assert isinstance(request, ViberDeliveredRequest)
20 | assert request.event_type == SAMPLE_REQUEST['event']
21 | assert request.timestamp == SAMPLE_REQUEST['timestamp']
22 | assert request.message_token == SAMPLE_REQUEST['message_token']
23 | assert request.user_id == SAMPLE_REQUEST['user_id']
24 | assert request.chat_id == SAMPLE_REQUEST['chat_id']
25 |
--------------------------------------------------------------------------------
/tests/api/viber_requests/test_viber_failed_request.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from viberbot.api.event_type import EventType
4 | from viberbot.api.viber_requests import ViberFailedRequest
5 | from viberbot.api.viber_requests import create_request
6 |
7 | SAMPLE_REQUEST = dict(
8 | event=EventType.FAILED,
9 | timestamp=datetime.now(),
10 | message_token="912661846655238145",
11 | user_id="01234567890A=",
12 | desc="failure desc"
13 | )
14 |
15 |
16 | def test_create_request():
17 | request = create_request(SAMPLE_REQUEST)
18 |
19 | assert isinstance(request, ViberFailedRequest)
20 | assert request.event_type == SAMPLE_REQUEST['event']
21 | assert request.timestamp == SAMPLE_REQUEST['timestamp']
22 | assert request.meesage_token == SAMPLE_REQUEST['message_token']
23 | assert request.user_id == SAMPLE_REQUEST['user_id']
24 | assert request.desc == SAMPLE_REQUEST['desc']
25 |
--------------------------------------------------------------------------------
/tests/api/viber_requests/test_viber_message_request.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from viberbot.api.event_type import EventType
4 | from viberbot.api.messages import MessageType
5 | from viberbot.api.messages import TextMessage
6 | from viberbot.api.viber_requests import ViberMessageRequest
7 | from viberbot.api.viber_requests import create_request
8 |
9 | SAMPLE_REQUEST = dict(
10 | event=EventType.MESSAGE,
11 | timestamp=datetime.now(),
12 | message_token="912661846655238145",
13 | sender=dict(
14 | id="01234567890A=",
15 | name="viberUser",
16 | avatar="http://avatar_url"
17 | ),
18 | message=dict(
19 | type=MessageType.TEXT,
20 | text="HI!"
21 | ),
22 | silent=True)
23 |
24 |
25 | def test_create_request():
26 | request = create_request(SAMPLE_REQUEST)
27 |
28 | assert isinstance(request, ViberMessageRequest)
29 | assert request.event_type == SAMPLE_REQUEST['event']
30 | assert request.timestamp == SAMPLE_REQUEST['timestamp']
31 | assert request.message_token == SAMPLE_REQUEST['message_token']
32 | assert request.silent == SAMPLE_REQUEST['silent']
33 | assert request.sender.id == SAMPLE_REQUEST['sender']['id']
34 | assert request.sender.name == SAMPLE_REQUEST['sender']['name']
35 | assert request.sender.avatar == SAMPLE_REQUEST['sender']['avatar']
36 | assert isinstance(request.message, TextMessage)
37 |
38 |
39 | def test_user_has_no_avatar():
40 | SAMPLE_REQUEST = dict(
41 | event=EventType.MESSAGE,
42 | timestamp=datetime.now(),
43 | message_token="912661846655238145",
44 | sender=dict(
45 | id="01234567890A=",
46 | name="viberUser"
47 | ),
48 | message=dict(
49 | type=MessageType.TEXT,
50 | text="HI!"
51 | ),
52 | silent=False)
53 | request = create_request(SAMPLE_REQUEST)
54 |
55 | assert isinstance(request, ViberMessageRequest)
56 | assert request.event_type == SAMPLE_REQUEST['event']
57 | assert request.timestamp == SAMPLE_REQUEST['timestamp']
58 | assert request.message_token == SAMPLE_REQUEST['message_token']
59 | assert request.sender.id == SAMPLE_REQUEST['sender']['id']
60 | assert request.sender.name == SAMPLE_REQUEST['sender']['name']
61 | assert isinstance(request.message, TextMessage)
62 |
63 |
64 | def test_request_is_chat_extension():
65 | SAMPLE_REQUEST = dict(
66 | event=EventType.MESSAGE,
67 | timestamp=datetime.now(),
68 | message_token="912661846655238145",
69 | chat_id=5048086924903818307,
70 | reply_type='message',
71 | sender=dict(
72 | id="01234567890A=",
73 | name="viberUser"
74 | ),
75 | message=dict(
76 | type=MessageType.TEXT,
77 | text="HI!"
78 | ),
79 | silent=False)
80 | request = create_request(SAMPLE_REQUEST)
81 |
82 | assert isinstance(request, ViberMessageRequest)
83 | assert request.event_type == SAMPLE_REQUEST['event']
84 | assert request.timestamp == SAMPLE_REQUEST['timestamp']
85 | assert request.message_token == SAMPLE_REQUEST['message_token']
86 | assert request.sender.id == SAMPLE_REQUEST['sender']['id']
87 | assert request.sender.name == SAMPLE_REQUEST['sender']['name']
88 | assert request.chat_id == SAMPLE_REQUEST['chat_id']
89 | assert request.reply_type == SAMPLE_REQUEST['reply_type']
90 | assert isinstance(request.message, TextMessage)
--------------------------------------------------------------------------------
/tests/api/viber_requests/test_viber_seen_request.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from viberbot.api.event_type import EventType
4 | from viberbot.api.viber_requests import ViberSeenRequest
5 | from viberbot.api.viber_requests import create_request
6 |
7 | SAMPLE_REQUEST = dict(
8 | event=EventType.SEEN,
9 | timestamp=datetime.now(),
10 | message_token="912661846655238145",
11 | user_id="01234567890A="
12 | )
13 |
14 |
15 | def test_create_request():
16 | request = create_request(SAMPLE_REQUEST)
17 |
18 | assert isinstance(request, ViberSeenRequest)
19 | assert request.event_type == SAMPLE_REQUEST['event']
20 | assert request.timestamp == SAMPLE_REQUEST['timestamp']
21 | assert request.meesage_token == SAMPLE_REQUEST['message_token']
22 | assert request.user_id == SAMPLE_REQUEST['user_id']
23 |
--------------------------------------------------------------------------------
/tests/api/viber_requests/test_viber_subscribed_request.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from viberbot.api.event_type import EventType
4 | from viberbot.api.viber_requests import ViberSubscribedRequest
5 | from viberbot.api.viber_requests import create_request
6 |
7 | SAMPLE_REQUEST = dict(
8 | event=EventType.SUBSCRIBED,
9 | timestamp=datetime.now(),
10 | user=dict(
11 | id="01234567890A=",
12 | name="viberUser",
13 | avatar="http://avatar_url",
14 | country="IL",
15 | language="en"
16 | ))
17 |
18 |
19 | def test_create_request():
20 | request = create_request(SAMPLE_REQUEST)
21 |
22 | assert isinstance(request, ViberSubscribedRequest)
23 | assert request.event_type == SAMPLE_REQUEST['event']
24 | assert request.timestamp == SAMPLE_REQUEST['timestamp']
25 | assert request.user.id == SAMPLE_REQUEST['user']['id']
26 | assert request.user.name == SAMPLE_REQUEST['user']['name']
27 | assert request.user.avatar == SAMPLE_REQUEST['user']['avatar']
28 | assert request.user.country == SAMPLE_REQUEST['user']['country']
29 | assert request.user.language == SAMPLE_REQUEST['user']['language']
30 |
--------------------------------------------------------------------------------
/tests/api/viber_requests/test_viber_unsubscribed_request.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from viberbot.api.event_type import EventType
4 | from viberbot.api.viber_requests import ViberUnsubscribedRequest
5 | from viberbot.api.viber_requests import create_request
6 |
7 | SAMPLE_REQUEST = dict(
8 | event=EventType.UNSUBSCRIBED,
9 | timestamp=datetime.now(),
10 | user_id="01234567890A="
11 | )
12 |
13 |
14 | def test_create_request():
15 | request = create_request(SAMPLE_REQUEST)
16 |
17 | assert isinstance(request, ViberUnsubscribedRequest)
18 | assert request.event_type == SAMPLE_REQUEST['event']
19 | assert request.timestamp == SAMPLE_REQUEST['timestamp']
20 | assert request.user_id == SAMPLE_REQUEST['user_id']
21 |
--------------------------------------------------------------------------------
/viberbot/__init__.py:
--------------------------------------------------------------------------------
1 | from .api.api import Api
2 | from .api.bot_configuration import BotConfiguration
3 | from .version import __version__
4 |
5 | __all__ = ['Api', 'BotConfiguration']
6 | __version__ = __version__
7 |
8 |
--------------------------------------------------------------------------------
/viberbot/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Viber/viber-bot-python/5cfe34e3b7d1c98afdf5d2c09a4c5722a61f008f/viberbot/api/__init__.py
--------------------------------------------------------------------------------
/viberbot/api/api.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import hmac
3 | import json
4 | import logging
5 |
6 | from viberbot.api.consts import VIBER_BOT_API_URL, VIBER_BOT_USER_AGENT
7 | from viberbot.api.viber_requests import create_request
8 | from viberbot.api.api_request_sender import ApiRequestSender
9 | from viberbot.api.message_sender import MessageSender
10 |
11 |
12 | class Api(object):
13 | def __init__(self, bot_configuration):
14 | self._logger = logging.getLogger('viber.bot.api')
15 | self._bot_configuration = bot_configuration
16 | self._request_sender = ApiRequestSender(self._logger, VIBER_BOT_API_URL, bot_configuration, VIBER_BOT_USER_AGENT)
17 | self._message_sender = MessageSender(self._logger, self._request_sender, bot_configuration)
18 |
19 | @property
20 | def name(self):
21 | return self._bot_configuration.name
22 |
23 | @property
24 | def avatar(self):
25 | return self._bot_configuration.avatar
26 |
27 | def set_webhook(self, url, webhook_events=None, is_inline=False):
28 | self._logger.debug(u"setting webhook to url: {0}".format(url))
29 | return self._request_sender.set_webhook(url, webhook_events, is_inline)
30 |
31 | def unset_webhook(self):
32 | self._logger.debug("unsetting webhook")
33 | return self._request_sender.set_webhook('')
34 |
35 | def get_online(self, ids):
36 | return self._request_sender.get_online_status(ids)
37 |
38 | def get_user_details(self, user_id):
39 | return self._request_sender.get_user_details(user_id)
40 |
41 | def get_account_info(self):
42 | self._logger.debug("requesting account info")
43 | account_info = self._request_sender.get_account_info()
44 | self._logger.debug(u"received account info: {0}".format(account_info))
45 | return account_info
46 |
47 | def verify_signature(self, request_data, signature):
48 | return signature == self._calculate_message_signature(request_data)
49 |
50 | def parse_request(self, request_data):
51 | self._logger.debug("parsing request")
52 | request_dict = json.loads(request_data.decode() if isinstance(
53 | request_data, bytes) else request_data)
54 | request = create_request(request_dict)
55 | self._logger.debug(u"parsed request={0}".format(request))
56 | return request
57 |
58 | def send_messages(self, to, messages, chat_id=None):
59 | """
60 | :param to: Viber user id
61 | :param messages: list of Message objects to be sent
62 | :param chat_id: Optional. String. Indicates that this is a message sent in inline conversation.
63 | :return: list of tokens of the sent messages
64 | """
65 | self._logger.debug("going to send messages: {0}, to: {1}".format(messages, to))
66 | if not isinstance(messages, list):
67 | messages = [messages]
68 |
69 | sent_messages_tokens = []
70 |
71 | for message in messages:
72 | token = self._message_sender.send_message(
73 | to, self._bot_configuration.name, self._bot_configuration.avatar, message, chat_id)
74 | sent_messages_tokens.append(token)
75 |
76 | return sent_messages_tokens
77 |
78 | def post_messages_to_public_account(self, sender, messages):
79 | if not isinstance(messages, list):
80 | messages = [messages]
81 |
82 | sent_messages_tokens = []
83 |
84 | for message in messages:
85 | token = self._message_sender.post_to_public_account(
86 | sender, self._bot_configuration.name, self._bot_configuration.avatar, message)
87 | sent_messages_tokens.append(token)
88 |
89 | return sent_messages_tokens
90 |
91 | def _calculate_message_signature(self, message):
92 | return hmac.new(
93 | bytes(self._bot_configuration.auth_token.encode('ascii')),
94 | msg=message,
95 | digestmod=hashlib.sha256)\
96 | .hexdigest()
97 |
--------------------------------------------------------------------------------
/viberbot/api/api_request_sender.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from requests import RequestException
3 | import traceback
4 | from viberbot.api.consts import BOT_API_ENDPOINT
5 | import json
6 |
7 |
8 | class ApiRequestSender(object):
9 | def __init__(self, logger, viber_bot_api_url, bot_configuration, viber_bot_user_agent):
10 | self._logger = logger
11 | self._viber_bot_api_url = viber_bot_api_url
12 | self._bot_configuration = bot_configuration
13 | self._user_agent = viber_bot_user_agent
14 |
15 | def set_webhook(self, url, webhook_events=None, is_inline=False):
16 | payload = {
17 | 'auth_token': self._bot_configuration.auth_token,
18 | 'url': url,
19 | 'is_inline': is_inline
20 | }
21 |
22 | if webhook_events is not None:
23 | if not isinstance(webhook_events, list):
24 | webhook_events = [webhook_events]
25 | payload['event_types'] = webhook_events
26 |
27 | result = self.post_request(
28 | endpoint=BOT_API_ENDPOINT.SET_WEBHOOK,
29 | payload=json.dumps(payload))
30 |
31 | if not result['status'] == 0:
32 | raise Exception(u"failed with status: {0}, message: {1}".format(result['status'], result['status_message']))
33 |
34 | return result['event_types']
35 |
36 | def get_account_info(self):
37 | payload = {
38 | 'auth_token': self._bot_configuration.auth_token
39 | }
40 | return self.post_request(
41 | endpoint=BOT_API_ENDPOINT.GET_ACCOUNT_INFO,
42 | payload=json.dumps(payload))
43 |
44 | def post_request(self, endpoint, payload):
45 | try:
46 | headers = requests.utils.default_headers()
47 | headers.update({
48 | 'User-Agent': self._user_agent
49 | })
50 | response = requests.post(self._viber_bot_api_url + '/' + endpoint, data=payload, headers=headers)
51 | response.raise_for_status()
52 | return json.loads(response.text)
53 | except RequestException as e:
54 | self._logger.error(
55 | u"failed to post request to endpoint={0}, with payload={1}. error is: {2}"
56 | .format(endpoint, payload, traceback.format_exc()))
57 | raise e
58 | except Exception as ex:
59 | self._logger.error(
60 | u"unexpected Exception while trying to post request. error is: {0}"
61 | .format(traceback.format_exc()))
62 | raise ex
63 |
64 | def get_online_status(self, ids=[]):
65 | if ids is None or not isinstance(ids, list) or len(ids) == 0:
66 | raise Exception(u"missing parameter ids, should be a list of viber memberIds")
67 |
68 | payload = {
69 | 'auth_token': self._bot_configuration.auth_token,
70 | 'ids': ids
71 | }
72 | result = self.post_request(
73 | endpoint=BOT_API_ENDPOINT.GET_ONLINE,
74 | payload=json.dumps(payload))
75 |
76 | if not result['status'] == 0:
77 | raise Exception(u"failed with status: {0}, message: {1}".format(result['status'], result['status_message']))
78 |
79 | return result['users']
80 |
81 | def get_user_details(self, user_id):
82 | if user_id is None:
83 | raise Exception(u"missing parameter id")
84 |
85 | payload = {
86 | 'auth_token': self._bot_configuration.auth_token,
87 | 'id': user_id
88 | }
89 | result = self.post_request(
90 | endpoint=BOT_API_ENDPOINT.GET_USER_DETAILS,
91 | payload=json.dumps(payload))
92 |
93 | if not result['status'] == 0:
94 | raise Exception(u"failed with status: {0}, message: {1}".format(result['status'], result['status_message']))
95 |
96 | return result['user']
97 |
98 |
99 |
--------------------------------------------------------------------------------
/viberbot/api/bot_configuration.py:
--------------------------------------------------------------------------------
1 | class BotConfiguration(object):
2 | def __init__(self, auth_token, name, avatar):
3 | self._auth_token = auth_token
4 | self._name = name
5 | self._avatar = avatar
6 |
7 | @property
8 | def name(self):
9 | return self._name
10 |
11 | @property
12 | def avatar(self):
13 | return self._avatar
14 |
15 | @property
16 | def auth_token(self):
17 | return self._auth_token
18 |
--------------------------------------------------------------------------------
/viberbot/api/consts.py:
--------------------------------------------------------------------------------
1 | from ..version import __version__
2 |
3 | VIBER_BOT_API_URL = "https://chatapi.viber.com/pa"
4 | VIBER_BOT_USER_AGENT = "ViberBot-Python/" + __version__
5 |
6 |
7 | class BOT_API_ENDPOINT(object):
8 | SET_WEBHOOK = 'set_webhook'
9 | GET_ACCOUNT_INFO = 'get_account_info'
10 | SEND_MESSAGE = 'send_message'
11 | GET_ONLINE = 'get_online'
12 | GET_USER_DETAILS = 'get_user_details'
13 | POST = 'post'
14 |
--------------------------------------------------------------------------------
/viberbot/api/event_type.py:
--------------------------------------------------------------------------------
1 | class EventType(object):
2 | SEEN = 'seen'
3 | CONVERSATION_STARTED = 'conversation_started'
4 | DELIVERED = 'delivered'
5 | MESSAGE = 'message'
6 | SUBSCRIBED = 'subscribed'
7 | UNSUBSCRIBED = 'unsubscribed'
8 | FAILED = 'failed'
9 | WEBHOOK = 'webhook'
10 |
--------------------------------------------------------------------------------
/viberbot/api/message_sender.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from viberbot.api.consts import BOT_API_ENDPOINT
4 |
5 |
6 | class MessageSender(object):
7 | def __init__(self, logger, request_sender, bot_configuration):
8 | self._logger = logger
9 | self._request_sender = request_sender
10 | self._bot_configuration = bot_configuration
11 |
12 | def send_message(self, to, sender_name, sender_avatar, message, chat_id=None):
13 | if not message.validate():
14 | self._logger.error(u"failed validating message: {0}".format(message))
15 | raise Exception("failed validating message: {0}".format(message))
16 |
17 | payload = self._prepare_payload(
18 | message=message,
19 | receiver=to,
20 | sender_name=sender_name,
21 | sender_avatar=sender_avatar,
22 | chat_id=chat_id
23 | )
24 |
25 | self._logger.debug(u"going to send message: {0}".format(payload))
26 |
27 | return self._post_request(BOT_API_ENDPOINT.SEND_MESSAGE, payload)
28 |
29 | def post_to_public_account(self, sender, sender_name, sender_avatar, message):
30 | if not message.validate():
31 | self._logger.error(u"failed validating message: {0}".format(message))
32 | raise Exception("failed validating message: {0}".format(message))
33 |
34 | if sender is None:
35 | raise Exception(u"missing parameter sender")
36 |
37 | payload = self._prepare_payload(
38 | message=message,
39 | sender=sender,
40 | sender_name=sender_name,
41 | sender_avatar=sender_avatar
42 | )
43 |
44 | self._logger.debug(u"going to send message: {0}".format(payload))
45 |
46 | return self._post_request(BOT_API_ENDPOINT.POST, payload)
47 |
48 | def _post_request(self, endpoint, payload):
49 | result = self._request_sender.post_request(
50 | endpoint, json.dumps(payload))
51 |
52 | if not result['status'] == 0:
53 | raise Exception(u"failed with status: {0}, message: {1}".format(result['status'], result['status_message']))
54 |
55 | return result['message_token']
56 |
57 | def _prepare_payload(self, message, sender_name, sender_avatar, sender=None, receiver=None, chat_id=None):
58 | payload = message.to_dict()
59 | payload.update({
60 | 'auth_token': self._bot_configuration.auth_token,
61 | 'from': sender,
62 | 'receiver': receiver,
63 | 'sender': {
64 | 'name': sender_name,
65 | 'avatar': sender_avatar
66 | },
67 | "chat_id": chat_id
68 | })
69 |
70 | return self._remove_empty_fields(payload)
71 |
72 | def _remove_empty_fields(self, message):
73 | return {k: v for k, v in message.items() if v is not None}
74 |
--------------------------------------------------------------------------------
/viberbot/api/messages/__init__.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.messages.contact_message import ContactMessage
2 | from viberbot.api.messages.file_message import FileMessage
3 | from viberbot.api.messages.picture_message import PictureMessage
4 | from viberbot.api.messages.sticker_message import StickerMessage
5 | from viberbot.api.messages.url_message import URLMessage
6 | from viberbot.api.messages.video_message import VideoMessage
7 | from viberbot.api.messages.message_type import MessageType
8 | from viberbot.api.messages.text_message import TextMessage
9 | from viberbot.api.messages.location_message import LocationMessage
10 | from viberbot.api.messages.rich_media_message import RichMediaMessage
11 | from viberbot.api.messages.keyboard_message import KeyboardMessage
12 |
13 | MESSAGE_TYPE_TO_CLASS = {
14 | MessageType.URL: URLMessage,
15 | MessageType.LOCATION: LocationMessage,
16 | MessageType.PICTURE: PictureMessage,
17 | MessageType.CONTACT: ContactMessage,
18 | MessageType.FILE: FileMessage,
19 | MessageType.TEXT: TextMessage,
20 | MessageType.VIDEO: VideoMessage,
21 | MessageType.STICKER: StickerMessage,
22 | MessageType.RICH_MEDIA: RichMediaMessage,
23 | MessageType.KEYBOARD: KeyboardMessage
24 | }
25 |
26 |
27 | def get_message(message_dict):
28 | if 'type' not in message_dict:
29 | raise Exception("message data doesn't contain a type")
30 |
31 | if message_dict['type'] not in MESSAGE_TYPE_TO_CLASS:
32 | raise Exception(u"message type '{0}' is not supported".format(message_dict['type']))
33 |
34 | return MESSAGE_TYPE_TO_CLASS[message_dict['type']]().from_dict(message_dict)
35 |
36 |
37 | __all__ = [
38 | 'TextMessage', 'ContactMessage', 'FileMessage', 'LocationMessage',
39 | 'PictureMessage', 'StickerMessage', 'URLMessage', 'VideoMessage',
40 | 'RichMediaMessage', 'MessageType', 'KeyboardMessage']
41 |
--------------------------------------------------------------------------------
/viberbot/api/messages/contact_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.data_types.contact import Contact
3 | from viberbot.api.messages.typed_message import TypedMessage
4 | from viberbot.api.messages.message_type import MessageType
5 |
6 |
7 | class ContactMessage(TypedMessage):
8 | def __init__(self, tracking_data=None, keyboard=None, contact=None, min_api_version=None):
9 | super(ContactMessage, self).__init__(MessageType.CONTACT, tracking_data, keyboard, min_api_version)
10 | self._contact = contact
11 |
12 | def to_dict(self):
13 | message_data = super(ContactMessage, self).to_dict()
14 | if self._contact is not None:
15 | message_data['contact'] = self._contact.to_dict()
16 | return message_data
17 |
18 | def from_dict(self, message_data):
19 | super(ContactMessage, self).from_dict(message_data)
20 | if 'contact' in message_data:
21 | self._contact = Contact().from_dict(message_data['contact'])
22 | return self
23 |
24 | @property
25 | def contact(self):
26 | return self._contact
27 |
28 | def validate(self):
29 | return super(ContactMessage, self).validate() \
30 | and self._contact is not None \
31 | and self._contact.name is not None \
32 | and self._contact.phone_number is not None
33 |
34 | @python_2_unicode_compatible
35 | def __str__(self):
36 | return u"ContactMessage [{0}, contact={1}]". \
37 | format(
38 | super(ContactMessage, self).__str__(),
39 | self._contact)
40 |
--------------------------------------------------------------------------------
/viberbot/api/messages/data_types/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Viber/viber-bot-python/5cfe34e3b7d1c98afdf5d2c09a4c5722a61f008f/viberbot/api/messages/data_types/__init__.py
--------------------------------------------------------------------------------
/viberbot/api/messages/data_types/contact.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 |
3 |
4 | class Contact(object):
5 | def __init__(self, name=None, phone_number=None, avatar=None):
6 | self._name = name
7 | self._phone_number = phone_number
8 | self._avatar = avatar
9 |
10 | def from_dict(self, contact):
11 | if 'name' in contact:
12 | self._name = contact['name']
13 | if 'phone_number' in contact:
14 | self._phone_number = contact['phone_number']
15 | if 'avatar' in contact:
16 | self._avatar = contact['avatar']
17 | return self
18 |
19 | def to_dict(self):
20 | return {
21 | 'name': self._name,
22 | 'phone_number': self._phone_number,
23 | 'avatar': self._avatar
24 | }
25 |
26 | @property
27 | def name(self):
28 | return self._name
29 |
30 | @property
31 | def phone_number(self):
32 | return self._phone_number
33 |
34 | def __eq__(self, other):
35 | return self._name == other.name and self._phone_number == other.phone_number
36 |
37 | @python_2_unicode_compatible
38 | def __str__(self):
39 | return u"Contact[name={0}, phone_number={1}, avatar={2}]".format(self._name, self._phone_number, self._avatar)
40 |
--------------------------------------------------------------------------------
/viberbot/api/messages/data_types/location.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 |
3 |
4 | class LocationConsts(object):
5 | MAX_LONGITUDE = 180
6 | MIN_LONGITUDE = -180
7 | MAX_LATITUDE = 90
8 | MIN_LATITUDE = -90
9 |
10 |
11 | class Location(object):
12 | def __init__(self, lat=None, lon=None):
13 | self._lat = lat
14 | self._lon = lon
15 |
16 | def from_dict(self, location):
17 | if 'lat' in location:
18 | self._lat = location['lat']
19 | if 'lon' in location:
20 | self._lon = location['lon']
21 | return self
22 |
23 | def to_dict(self):
24 | return {
25 | 'lat': self._lat,
26 | 'lon': self._lon
27 | }
28 |
29 | @property
30 | def latitude(self):
31 | return self._lat
32 |
33 | @property
34 | def longitude(self):
35 | return self._lon
36 |
37 | def validate(self):
38 | if self._lat is None or self._lon is None:
39 | return False
40 | if self._lat >= LocationConsts.MAX_LATITUDE or self._lat <= LocationConsts.MIN_LATITUDE:
41 | return False
42 | if self._lon >= LocationConsts.MAX_LONGITUDE or self._lon <= LocationConsts.MIN_LONGITUDE:
43 | return False
44 | return True
45 |
46 | def __eq__(self, other):
47 | return self._lat == other.latitude and self._lon == other.longitude
48 |
49 | @python_2_unicode_compatible
50 | def __str__(self):
51 | return u"Location[lat={0}, lon={1}]".format(self._lat, self._lon)
52 |
--------------------------------------------------------------------------------
/viberbot/api/messages/file_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.typed_message import TypedMessage
3 | from viberbot.api.messages.message_type import MessageType
4 |
5 |
6 | class FileMessage(TypedMessage):
7 | def __init__(self, tracking_data=None, keyboard=None, media=None, size=None, file_name=None, min_api_version=None):
8 | super(FileMessage, self).__init__(MessageType.FILE, tracking_data, keyboard, min_api_version)
9 | self._media = media
10 | self._size = size
11 | self._file_name = file_name
12 |
13 | def to_dict(self):
14 | message_data = super(FileMessage, self).to_dict()
15 | message_data['media'] = self._media
16 | message_data['size'] = self._size
17 | message_data['file_name'] = self._file_name
18 | return message_data
19 |
20 | def from_dict(self, message_data):
21 | super(FileMessage, self).from_dict(message_data)
22 | if 'media' in message_data:
23 | self._media = message_data['media']
24 | if 'size' in message_data:
25 | self._size = message_data['size']
26 | if 'file_name' in message_data:
27 | self._file_name = message_data['file_name']
28 | return self
29 |
30 | @property
31 | def media(self):
32 | return self._media
33 |
34 | @property
35 | def size(self):
36 | return self._size
37 |
38 | @property
39 | def file_name(self):
40 | return self._file_name
41 |
42 | def validate(self):
43 | return super(FileMessage, self).validate() \
44 | and self._media is not None \
45 | and self._size is not None \
46 | and self._file_name is not None
47 |
48 | @python_2_unicode_compatible
49 | def __str__(self):
50 | return u"FileMessage [{0}, media={1}, size={2}, file_name={3}]". \
51 | format(
52 | super(FileMessage, self).__str__(),
53 | self._media,
54 | self._size,
55 | self._file_name)
56 |
--------------------------------------------------------------------------------
/viberbot/api/messages/keyboard_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.message import Message
3 |
4 |
5 | class KeyboardMessage(Message):
6 | def __init__(self, tracking_data=None, keyboard=None, min_api_version=None):
7 | super(KeyboardMessage, self).__init__(tracking_data, keyboard, min_api_version)
8 |
9 | def to_dict(self):
10 | return super(KeyboardMessage, self).to_dict()
11 |
12 | def from_dict(self, message_data):
13 | super(KeyboardMessage, self).from_dict(message_data)
14 | return self
15 |
16 | def validate(self):
17 | return self._keyboard is not None
18 |
19 | @python_2_unicode_compatible
20 | def __str__(self):
21 | return u"KeyboardMessage [{0}]".format(super(KeyboardMessage, self).__str__())
22 |
--------------------------------------------------------------------------------
/viberbot/api/messages/location_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.data_types.location import Location
3 | from viberbot.api.messages.typed_message import TypedMessage
4 | from viberbot.api.messages.message_type import MessageType
5 |
6 |
7 | class LocationMessage(TypedMessage):
8 | def __init__(self, tracking_data=None, keyboard=None, location=None, min_api_version=None):
9 | super(LocationMessage, self).__init__(MessageType.LOCATION, tracking_data, keyboard, min_api_version)
10 | self._location = location
11 |
12 | def to_dict(self):
13 | message_data = super(LocationMessage, self).to_dict()
14 | if self._location is not None:
15 | message_data['location'] = self._location.to_dict()
16 | return message_data
17 |
18 | def from_dict(self, message_data):
19 | super(LocationMessage, self).from_dict(message_data)
20 | if 'location' in message_data:
21 | self._location = Location().from_dict(message_data['location'])
22 | return self
23 |
24 | @property
25 | def location(self):
26 | return self._location
27 |
28 | def validate(self):
29 | return super(LocationMessage, self).validate() \
30 | and self._location and self._location.validate()
31 |
32 | @python_2_unicode_compatible
33 | def __str__(self):
34 | return u"LocationMessage [{0}, contact={1}]"\
35 | .format(
36 | super(LocationMessage, self).__str__(),
37 | self._location)
38 |
--------------------------------------------------------------------------------
/viberbot/api/messages/message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from abc import abstractmethod
3 |
4 |
5 | class Message(object):
6 | def __init__(self, tracking_data=None, keyboard=None, min_api_version=None, alt_text=None):
7 | self._tracking_data = tracking_data
8 | self._keyboard = keyboard
9 | self._min_api_version = min_api_version
10 | self._alt_text = alt_text
11 |
12 | @abstractmethod
13 | def to_dict(self):
14 | message_data = {}
15 | if self._tracking_data:
16 | message_data['tracking_data'] = self._tracking_data
17 | if self._keyboard:
18 | message_data['keyboard'] = self._keyboard
19 | if self._min_api_version:
20 | message_data['min_api_version'] = self._min_api_version
21 | if self._alt_text:
22 | message_data['alt_text'] = self._alt_text
23 | return message_data
24 |
25 | @abstractmethod
26 | def from_dict(self, message_data):
27 | if 'tracking_data' in message_data:
28 | self._tracking_data = message_data['tracking_data']
29 | if 'keyboard' in message_data:
30 | self._keyboard = message_data['keyboard']
31 | if 'min_api_version' in message_data:
32 | self._min_api_version = message_data['min_api_version']
33 | return self
34 |
35 | @property
36 | def keyboard(self):
37 | return self._keyboard
38 |
39 | @property
40 | def tracking_data(self):
41 | return self._tracking_data
42 |
43 | @property
44 | def min_api_version(self):
45 | return self._min_api_version
46 |
47 | @abstractmethod
48 | def validate(self):
49 | """
50 | validates message has all the required fields before send
51 | """
52 | pass
53 |
54 | @python_2_unicode_compatible
55 | def __str__(self):
56 | return u"tracking_data={0}, keyboard={1}, min_api_version={2}"\
57 | .format(
58 | self._tracking_data,
59 | self._keyboard,
60 | self._min_api_version)
61 |
--------------------------------------------------------------------------------
/viberbot/api/messages/message_type.py:
--------------------------------------------------------------------------------
1 | class MessageType(object):
2 | RICH_MEDIA = 'rich_media'
3 | STICKER = 'sticker'
4 | URL = 'url'
5 | LOCATION = 'location'
6 | CONTACT = 'contact'
7 | FILE = 'file'
8 | TEXT = 'text'
9 | PICTURE = 'picture'
10 | VIDEO = 'video'
11 | KEYBOARD = 'keyboard'
12 |
--------------------------------------------------------------------------------
/viberbot/api/messages/picture_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.typed_message import TypedMessage
3 | from viberbot.api.messages.message_type import MessageType
4 |
5 |
6 | class PictureMessage(TypedMessage):
7 | def __init__(self, tracking_data=None, keyboard=None, text=None, media=None, thumbnail=None, min_api_version=None):
8 | super(PictureMessage, self).__init__(MessageType.PICTURE, tracking_data, keyboard, min_api_version)
9 | self._text = text or ''
10 | self._media = media
11 | self._thumbnail = thumbnail
12 |
13 | def to_dict(self):
14 | message_data = super(PictureMessage, self).to_dict()
15 | message_data['text'] = self._text
16 | message_data['media'] = self._media
17 | message_data['thumbnail'] = self._thumbnail
18 | return message_data
19 |
20 | def from_dict(self, message_data):
21 | super(PictureMessage, self).from_dict(message_data)
22 | if 'text' in message_data:
23 | self._text = message_data['text'] or ''
24 | if 'media' in message_data:
25 | self._media = message_data['media']
26 | if 'thumbnail' in message_data:
27 | self._thumbnail = message_data['thumbnail']
28 | return self
29 |
30 | def validate(self):
31 | return super(PictureMessage, self).validate() \
32 | and self._text is not None and self._media is not None
33 |
34 | @property
35 | def text(self):
36 | return self._text
37 |
38 | @property
39 | def media(self):
40 | return self._media
41 |
42 | @property
43 | def thumbnail(self):
44 | return self._thumbnail
45 |
46 | @python_2_unicode_compatible
47 | def __str__(self):
48 | return u"PictureMessage [{0}, text={1}, media={2}, thumbnail={3}]"\
49 | .format(
50 | super(PictureMessage, self).__str__(),
51 | self._text,
52 | self._media,
53 | self._thumbnail)
54 |
--------------------------------------------------------------------------------
/viberbot/api/messages/rich_media_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.typed_message import TypedMessage
3 | from viberbot.api.messages.message_type import MessageType
4 |
5 |
6 | class RichMediaMessage(TypedMessage):
7 | def __init__(self, tracking_data=None, keyboard=None, rich_media=None, min_api_version=None, alt_text=None):
8 | super(RichMediaMessage, self).__init__(MessageType.RICH_MEDIA, tracking_data, keyboard, min_api_version)
9 | self._rich_media = rich_media
10 | self._alt_text = alt_text
11 |
12 | def to_dict(self):
13 | message_data = super(RichMediaMessage, self).to_dict()
14 | message_data['rich_media'] = self._rich_media
15 | message_data['alt_text'] = self._alt_text
16 | return message_data
17 |
18 | def from_dict(self, message_data):
19 | super(RichMediaMessage, self).from_dict(message_data)
20 | if 'rich_media' in message_data:
21 | self._rich_media = message_data['rich_media']
22 | if 'alt_text' in message_data:
23 | self._alt_text = message_data['alt_text']
24 | return self
25 |
26 | def validate(self):
27 | return super(RichMediaMessage, self).validate() \
28 | and self._rich_media is not None
29 |
30 | @property
31 | def rich_media(self):
32 | return self._rich_media
33 |
34 | @property
35 | def alt_text(self):
36 | return self._alt_text
37 |
38 | @python_2_unicode_compatible
39 | def __str__(self):
40 | return u"RichMediaMessage [{0}, rich_media={1}]"\
41 | .format(
42 | super(RichMediaMessage, self).__str__(),
43 | self._rich_media,
44 | self._alt_text)
45 |
--------------------------------------------------------------------------------
/viberbot/api/messages/sticker_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.typed_message import TypedMessage
3 | from viberbot.api.messages.message_type import MessageType
4 |
5 |
6 | class StickerMessage(TypedMessage):
7 | def __init__(self, tracking_data=None, keyboard=None, sticker_id=None, min_api_version=None):
8 | super(StickerMessage, self).__init__(MessageType.STICKER, tracking_data, keyboard, min_api_version)
9 | self._sticker_id = sticker_id
10 |
11 | def to_dict(self):
12 | message_data = super(StickerMessage, self).to_dict()
13 | message_data['sticker_id'] = self._sticker_id
14 | return message_data
15 |
16 | def from_dict(self, message_data):
17 | super(StickerMessage, self).from_dict(message_data)
18 | if 'sticker_id' in message_data:
19 | self._sticker_id = message_data['sticker_id']
20 | return self
21 |
22 | @property
23 | def sticker_id(self):
24 | return self._sticker_id
25 |
26 | def validate(self):
27 | return super(StickerMessage, self).validate() \
28 | and self._sticker_id is not None
29 |
30 | @python_2_unicode_compatible
31 | def __str__(self):
32 | return u"StickerMessage [{0}, sticker_id={1}]".format(super(StickerMessage, self).__str__(), self._sticker_id)
33 |
--------------------------------------------------------------------------------
/viberbot/api/messages/text_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.typed_message import TypedMessage
3 | from viberbot.api.messages.message_type import MessageType
4 |
5 |
6 | class TextMessage(TypedMessage):
7 | def __init__(self, tracking_data=None, keyboard=None, text=None, min_api_version=None):
8 | super(TextMessage, self).__init__(MessageType.TEXT, tracking_data, keyboard, min_api_version)
9 | self._text = text
10 |
11 | def to_dict(self):
12 | message_data = super(TextMessage, self).to_dict()
13 | message_data['text'] = self._text
14 | return message_data
15 |
16 | def from_dict(self, message_data):
17 | super(TextMessage, self).from_dict(message_data)
18 | if 'text' in message_data:
19 | self._text = message_data['text']
20 | return self
21 |
22 | def validate(self):
23 | return super(TextMessage, self).validate() \
24 | and self._text is not None
25 |
26 | @property
27 | def text(self):
28 | return self._text
29 |
30 | @python_2_unicode_compatible
31 | def __str__(self):
32 | return u"TextMessage [{0}, text={1}]".format(super(TextMessage, self).__str__(), self._text)
33 |
--------------------------------------------------------------------------------
/viberbot/api/messages/typed_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from abc import abstractmethod
3 | from viberbot.api.messages.message import Message
4 |
5 |
6 | class TypedMessage(Message):
7 | def __init__(self, message_type, tracking_data=None, keyboard=None, min_api_version=None, alt_text=None):
8 | super(TypedMessage, self).__init__(tracking_data, keyboard, min_api_version, alt_text)
9 | self._message_type = message_type
10 |
11 | @abstractmethod
12 | def to_dict(self):
13 | message_data = super(TypedMessage, self).to_dict()
14 | message_data['type'] = self._message_type
15 | return message_data
16 |
17 | @abstractmethod
18 | def from_dict(self, message_data):
19 | super(TypedMessage, self).from_dict(message_data)
20 | return self
21 |
22 | @abstractmethod
23 | def validate(self):
24 | """
25 | validates message has all the required fields before send
26 | """
27 | return self._message_type is not None
28 |
29 | @python_2_unicode_compatible
30 | def __str__(self):
31 | return super(TypedMessage, self).__str__()
32 |
--------------------------------------------------------------------------------
/viberbot/api/messages/url_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.typed_message import TypedMessage
3 | from viberbot.api.messages.message_type import MessageType
4 |
5 |
6 | class URLMessage(TypedMessage):
7 | def __init__(self, tracking_data=None, keyboard=None, media=None, min_api_version=None):
8 | super(URLMessage, self).__init__(MessageType.URL, tracking_data, keyboard, min_api_version)
9 | self._media = media
10 |
11 | def to_dict(self):
12 | message_data = super(URLMessage, self).to_dict()
13 | message_data['media'] = self._media
14 | return message_data
15 |
16 | def from_dict(self, message_data):
17 | super(URLMessage, self).from_dict(message_data)
18 | if 'media' in message_data:
19 | self._media = message_data['media']
20 | return self
21 |
22 | @property
23 | def media(self):
24 | return self._media
25 |
26 | def validate(self):
27 | return super(URLMessage, self).validate() \
28 | and self._media is not None
29 |
30 | @python_2_unicode_compatible
31 | def __str__(self):
32 | return u"URLMessage [{0}, media={1}]".format(super(URLMessage, self).__str__(), self._media)
33 |
--------------------------------------------------------------------------------
/viberbot/api/messages/video_message.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.messages.typed_message import TypedMessage
3 | from viberbot.api.messages.message_type import MessageType
4 |
5 |
6 | class VideoMessage(TypedMessage):
7 | def __init__(self, tracking_data=None, keyboard=None, media=None, thumbnail=None, size=None, text=None, duration=None, min_api_version=None):
8 | super(VideoMessage, self).__init__(MessageType.VIDEO, tracking_data, keyboard, min_api_version)
9 | self._media = media
10 | self._thumbnail = thumbnail
11 | self._size = size
12 | self._duration = duration
13 | self._text = text
14 |
15 | def to_dict(self):
16 | message_data = super(VideoMessage, self).to_dict()
17 | message_data['media'] = self._media
18 | message_data['thumbnail'] = self._thumbnail
19 | message_data['size'] = self._size
20 | message_data['duration'] = self._duration
21 | message_data['text'] = self._text
22 | return message_data
23 |
24 | def from_dict(self, message_data):
25 | super(VideoMessage, self).from_dict(message_data)
26 | if 'media' in message_data:
27 | self._media = message_data['media']
28 | if 'thumbnail' in message_data:
29 | self._thumbnail = message_data['thumbnail']
30 | if 'size' in message_data:
31 | self._size = message_data['size']
32 | if 'duration' in message_data:
33 | self._duration = message_data['duration']
34 | if 'text' in message_data:
35 | self._text = message_data['text']
36 | return self
37 |
38 | def validate(self):
39 | return super(VideoMessage, self).validate() \
40 | and self._media is not None \
41 | and self._size is not None
42 |
43 | @property
44 | def media(self):
45 | return self._media
46 |
47 | @property
48 | def thumbnail(self):
49 | return self._thumbnail
50 |
51 | @property
52 | def size(self):
53 | return self._size
54 |
55 | @property
56 | def duration(self):
57 | return self._duration
58 |
59 | @property
60 | def text(self):
61 | return self._text
62 |
63 | @python_2_unicode_compatible
64 | def __str__(self):
65 | return u"VideoMessage [{0}, media={1}, thumbnail={2}, size={3}, duration={4} text={5}]".\
66 | format(
67 | super(VideoMessage, self).__str__(),
68 | self._media,
69 | self._thumbnail,
70 | self._size,
71 | self._duration,
72 | self._text)
73 |
--------------------------------------------------------------------------------
/viberbot/api/user_profile.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 |
3 |
4 | class UserProfile(object):
5 | def __init__(self, name=None, avatar=None, user_id=None, country=None, language=None, api_version=None):
6 | self._name = name
7 | self._avatar = avatar
8 | self._id = user_id
9 | self._country = country
10 | self._language = language
11 | self._api_version = api_version
12 |
13 | @property
14 | def name(self):
15 | return self._name
16 |
17 | @property
18 | def avatar(self):
19 | return self._avatar
20 |
21 | @property
22 | def id(self):
23 | return self._id
24 |
25 | @property
26 | def country(self):
27 | return self._country
28 |
29 | @property
30 | def language(self):
31 | return self._language
32 |
33 | @property
34 | def api_version(self):
35 | return self._api_version
36 |
37 | def from_dict(self, user_dict):
38 | if 'name' in user_dict:
39 | self._name = user_dict['name']
40 | if 'avatar' in user_dict:
41 | self._avatar = user_dict['avatar']
42 | if 'id' in user_dict:
43 | self._id = user_dict['id']
44 | if 'country' in user_dict:
45 | self._country = user_dict['country']
46 | if 'language' in user_dict:
47 | self._language = user_dict['language']
48 | if 'api_version' in user_dict:
49 | self._api_version = user_dict['api_version']
50 | return self
51 |
52 | @python_2_unicode_compatible
53 | def __str__(self):
54 | return u"UserProfile[name={0}, avatar={1}, id={2}, country={3}, language={4}, api_version={5}"\
55 | .format(
56 | self._name,
57 | self._avatar,
58 | self._id,
59 | self._country,
60 | self._language,
61 | self._api_version)
62 |
--------------------------------------------------------------------------------
/viberbot/api/viber_requests/__init__.py:
--------------------------------------------------------------------------------
1 | from viberbot.api.event_type import EventType
2 | from viberbot.api.viber_requests.viber_conversation_started_request import ViberConversationStartedRequest
3 | from viberbot.api.viber_requests.viber_delivered_request import ViberDeliveredRequest
4 | from viberbot.api.viber_requests.viber_failed_request import ViberFailedRequest
5 | from viberbot.api.viber_requests.viber_message_request import ViberMessageRequest
6 | from viberbot.api.viber_requests.viber_request import ViberRequest
7 | from viberbot.api.viber_requests.viber_seen_request import ViberSeenRequest
8 | from viberbot.api.viber_requests.viber_subscribed_request import ViberSubscribedRequest
9 | from viberbot.api.viber_requests.viber_unsubscribed_request import ViberUnsubscribedRequest
10 |
11 | EVENT_TYPE_TO_CLASS = {
12 | EventType.MESSAGE: ViberMessageRequest,
13 | EventType.FAILED: ViberFailedRequest,
14 | EventType.CONVERSATION_STARTED: ViberConversationStartedRequest,
15 | EventType.DELIVERED: ViberDeliveredRequest,
16 | EventType.SEEN: ViberSeenRequest,
17 | EventType.SUBSCRIBED: ViberSubscribedRequest,
18 | EventType.UNSUBSCRIBED: ViberUnsubscribedRequest,
19 | EventType.WEBHOOK: ViberRequest
20 | }
21 |
22 |
23 | def create_request(request_dict):
24 | if 'event' not in request_dict:
25 | raise Exception("request is missing field 'event'")
26 |
27 | if request_dict['event'] not in EVENT_TYPE_TO_CLASS:
28 | raise Exception("event type '{0}' is not supported".format(request_dict['event']))
29 |
30 | return EVENT_TYPE_TO_CLASS[request_dict['event']]().from_dict(request_dict)
31 |
32 |
33 | __all__ = [
34 | 'ViberConversationStartedRequest', 'ViberDeliveredRequest', 'ViberFailedRequest', 'ViberMessageRequest',
35 | 'ViberSeenRequest', 'ViberSubscribedRequest', 'ViberUnsubscribedRequest']
36 |
--------------------------------------------------------------------------------
/viberbot/api/viber_requests/viber_conversation_started_request.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.event_type import EventType
3 | from viberbot.api.user_profile import UserProfile
4 | from viberbot.api.viber_requests.viber_request import ViberRequest
5 |
6 |
7 | class ViberConversationStartedRequest(ViberRequest):
8 | def __init__(self):
9 | super(ViberConversationStartedRequest, self).__init__(EventType.CONVERSATION_STARTED)
10 | self._message_token = None
11 | self._type = None
12 | self._context = None
13 | self._user = None
14 | self._api_version = None
15 | self._subscribed = None
16 |
17 | def from_dict(self, request_dict):
18 | super(ViberConversationStartedRequest, self).from_dict(request_dict)
19 | self._message_token = request_dict['message_token']
20 | self._type = request_dict['type']
21 | if 'context' in request_dict:
22 | self._context = request_dict['context']
23 | self._user = UserProfile().from_dict(request_dict['user'])
24 | if 'api_version' in request_dict:
25 | self._api_version = request_dict['api_version']
26 | if 'subscribed' in request_dict:
27 | self._subscribed = request_dict['subscribed']
28 | return self
29 |
30 | @property
31 | def user(self):
32 | return self._user
33 |
34 | @property
35 | def type(self):
36 | return self._type
37 |
38 | @property
39 | def context(self):
40 | return self._context
41 |
42 | @property
43 | def message_token(self):
44 | return self._message_token
45 |
46 | @property
47 | def api_version(self):
48 | return self._api_version
49 |
50 | @property
51 | def subscribed(self):
52 | return self._subscribed
53 |
54 | @python_2_unicode_compatible
55 | def __str__(self):
56 | return u"ViberConversationStartedRequest [{0}, message_token={1}, type={2}, context{3}, user={4} subscribed={5}]"\
57 | .format(
58 | super(ViberConversationStartedRequest, self).__str__(),
59 | self._message_token,
60 | self._type,
61 | self._context,
62 | self._user,
63 | self._subscribed)
64 |
--------------------------------------------------------------------------------
/viberbot/api/viber_requests/viber_delivered_request.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.event_type import EventType
3 | from viberbot.api.viber_requests.viber_request import ViberRequest
4 |
5 |
6 | class ViberDeliveredRequest(ViberRequest):
7 | def __init__(self):
8 | super(ViberDeliveredRequest, self).__init__(EventType.DELIVERED)
9 | self._message_token = None
10 | self._user_id = None
11 | self._chat_id = None
12 |
13 | def from_dict(self, request_dict):
14 | super(ViberDeliveredRequest, self).from_dict(request_dict)
15 | self._message_token = request_dict['message_token']
16 | self._user_id = request_dict.get('user_id', None)
17 | self._chat_id = request_dict.get('chat_id', None)
18 | return self
19 |
20 | @property
21 | def message_token(self):
22 | return self._message_token
23 |
24 | @property
25 | def user_id(self):
26 | return self._user_id
27 |
28 | @property
29 | def chat_id(self):
30 | return self._chat_id
31 |
32 | @python_2_unicode_compatible
33 | def __str__(self):
34 | return u"ViberDeliveredRequest [{0}, message_token={1}, user_id={2}]" \
35 | .format(
36 | super(ViberDeliveredRequest, self).__str__(),
37 | self._message_token,
38 | self._user_id)
39 |
--------------------------------------------------------------------------------
/viberbot/api/viber_requests/viber_failed_request.py:
--------------------------------------------------------------------------------
1 | import warnings
2 | from future.utils import python_2_unicode_compatible
3 | from viberbot.api.event_type import EventType
4 | from viberbot.api.viber_requests.viber_request import ViberRequest
5 |
6 |
7 | class ViberFailedRequest(ViberRequest):
8 | def __init__(self):
9 | super(ViberFailedRequest, self).__init__(EventType.FAILED)
10 | self._message_token = None
11 | self._user_id = None
12 | self._desc = None
13 |
14 | def from_dict(self, request_dict):
15 | super(ViberFailedRequest, self).from_dict(request_dict)
16 | self._message_token = request_dict['message_token']
17 | self._user_id = request_dict['user_id']
18 | self._desc = request_dict['desc']
19 | return self
20 |
21 | @property
22 | def meesage_token(self):
23 | warnings.warn('Property `meesage_token` had typo and now is deprecated, please use `message_token` instead')
24 | return self._message_token
25 |
26 | @property
27 | def message_token(self):
28 | return self._message_token
29 |
30 | @property
31 | def user_id(self):
32 | return self._user_id
33 |
34 | @property
35 | def desc(self):
36 | return self._desc
37 |
38 | @python_2_unicode_compatible
39 | def __str__(self):
40 | return u"ViberFailedRequest [{0}, message_token={1}, user_id={2}, desc={3}]" \
41 | .format(
42 | super(ViberFailedRequest, self).__str__(),
43 | self._message_token,
44 | self._user_id,
45 | self._desc)
46 |
--------------------------------------------------------------------------------
/viberbot/api/viber_requests/viber_message_request.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api import messages
3 | from viberbot.api.event_type import EventType
4 | from viberbot.api.user_profile import UserProfile
5 | from viberbot.api.viber_requests.viber_request import ViberRequest
6 |
7 |
8 | class ViberMessageRequest(ViberRequest):
9 | def __init__(self):
10 | super(ViberMessageRequest, self).__init__(EventType.MESSAGE)
11 | self._message = None
12 | self._sender = None
13 | self._message_token = None
14 | self._chat_id = None
15 | self._reply_type = None
16 | self._silent = None
17 |
18 | def from_dict(self, request_dict):
19 | super(ViberMessageRequest, self).from_dict(request_dict)
20 | self._message = messages.get_message(request_dict['message'])
21 | self._sender = UserProfile().from_dict(request_dict['sender'])
22 | self._message_token = request_dict['message_token']
23 | self._silent = request_dict.get('silent', None)
24 | self._reply_type = request_dict.get('reply_type', None)
25 | self._chat_id = request_dict.get('chat_id', None)
26 | return self
27 |
28 | @property
29 | def message(self):
30 | return self._message
31 |
32 | @property
33 | def sender(self):
34 | return self._sender
35 |
36 | @property
37 | def message_token(self):
38 | return self._message_token
39 |
40 | @property
41 | def chat_id(self):
42 | return self._chat_id
43 |
44 | @property
45 | def reply_type(self):
46 | return self._reply_type
47 |
48 | @property
49 | def silent(self):
50 | return self._silent
51 |
52 | @python_2_unicode_compatible
53 | def __str__(self):
54 | return u"ViberMessageRequest [{0}, message_token={1}, sender={2}, " \
55 | u"message={3}, chat_id={4}, reply_type={5}, silent={6}]" \
56 | .format(
57 | super(ViberMessageRequest, self).__str__(),
58 | self._message_token,
59 | self._sender,
60 | self._message,
61 | self._chat_id,
62 | self._reply_type,
63 | self._silent)
64 |
--------------------------------------------------------------------------------
/viberbot/api/viber_requests/viber_request.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 |
3 |
4 | class ViberRequest(object):
5 | def __init__(self, event_type=None):
6 | self._event_type = event_type
7 | self._timestamp = None
8 |
9 | def from_dict(self, request_dict):
10 | self._timestamp = request_dict['timestamp']
11 | if self._event_type is None:
12 | self._event_type = request_dict['event']
13 | return self
14 |
15 | @property
16 | def event_type(self):
17 | return self._event_type
18 |
19 | @property
20 | def timestamp(self):
21 | return self._timestamp
22 |
23 | @python_2_unicode_compatible
24 | def __str__(self):
25 | return u"event_type={0}, timestamp={1}".format(self._event_type, self._timestamp)
26 |
--------------------------------------------------------------------------------
/viberbot/api/viber_requests/viber_seen_request.py:
--------------------------------------------------------------------------------
1 | import warnings
2 | from future.utils import python_2_unicode_compatible
3 | from ..event_type import EventType
4 | from viberbot.api.viber_requests.viber_request import ViberRequest
5 |
6 |
7 | class ViberSeenRequest(ViberRequest):
8 | def __init__(self):
9 | super(ViberSeenRequest, self).__init__(EventType.SEEN)
10 | self._message_token = None
11 | self._user_id = None
12 |
13 | def from_dict(self, request_dict):
14 | super(ViberSeenRequest, self).from_dict(request_dict)
15 | self._message_token = request_dict['message_token']
16 | self._user_id = request_dict['user_id']
17 | return self
18 |
19 | @property
20 | def meesage_token(self):
21 | warnings.warn('Property `meesage_token` had typo and now is deprecated, please use `message_token` instead')
22 | return self._message_token
23 |
24 | @property
25 | def message_token(self):
26 | return self._message_token
27 |
28 | @property
29 | def user_id(self):
30 | return self._user_id
31 |
32 | @python_2_unicode_compatible
33 | def __str__(self):
34 | return u"ViberSeenRequest [{0}, message_token={1}, user_id={2}]" \
35 | .format(super(ViberSeenRequest, self).__str__(), self._message_token, self._user_id)
36 |
--------------------------------------------------------------------------------
/viberbot/api/viber_requests/viber_subscribed_request.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.event_type import EventType
3 | from viberbot.api.user_profile import UserProfile
4 | from viberbot.api.viber_requests.viber_request import ViberRequest
5 |
6 |
7 | class ViberSubscribedRequest(ViberRequest):
8 | def __init__(self):
9 | super(ViberSubscribedRequest, self).__init__(EventType.SUBSCRIBED)
10 | self._user = None
11 | self._api_version = None
12 |
13 | def from_dict(self, request_dict):
14 | super(ViberSubscribedRequest, self).from_dict(request_dict)
15 | self._user = UserProfile().from_dict(request_dict['user'])
16 | if 'api_version' in request_dict:
17 | self._api_version = request_dict['api_version']
18 | return self
19 |
20 | @property
21 | def user(self):
22 | return self._user
23 |
24 | @property
25 | def api_version(self):
26 | return self._api_version
27 |
28 | @python_2_unicode_compatible
29 | def __str__(self):
30 | return u"ViberSubscribedRequest [{0}, user={1}]" \
31 | .format(super(ViberSubscribedRequest, self).__str__(), self._user)
32 |
--------------------------------------------------------------------------------
/viberbot/api/viber_requests/viber_unsubscribed_request.py:
--------------------------------------------------------------------------------
1 | from future.utils import python_2_unicode_compatible
2 | from viberbot.api.event_type import EventType
3 | from viberbot.api.viber_requests.viber_request import ViberRequest
4 |
5 |
6 | class ViberUnsubscribedRequest(ViberRequest):
7 | def __init__(self):
8 | super(ViberUnsubscribedRequest, self).__init__(EventType.UNSUBSCRIBED)
9 | self._user_id = None
10 |
11 | def from_dict(self, request_dict):
12 | super(ViberUnsubscribedRequest, self).from_dict(request_dict)
13 | self._user_id = request_dict['user_id']
14 | return self
15 |
16 | @property
17 | def user_id(self):
18 | return self._user_id
19 |
20 | @python_2_unicode_compatible
21 | def __str__(self):
22 | return u"ViberUnsubscribedRequest [{0}, user_id={1}]" \
23 | .format(super(ViberUnsubscribedRequest, self).__str__(), self._user_id)
24 |
--------------------------------------------------------------------------------
/viberbot/version.py:
--------------------------------------------------------------------------------
1 | __version__ = '1.0.12'
2 |
--------------------------------------------------------------------------------