Merge pull request #496 from rubenlagus/dev

Dev
This commit is contained in:
Ruben Bermudez 2018-07-27 01:52:02 +02:00 committed by GitHub
commit 01765d07a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
283 changed files with 6721 additions and 3979 deletions

251
Bots.ipr
View File

@ -18,6 +18,7 @@
<outputRelativeToContentRoot value="true" />
<module name="telegrambots" />
<module name="telegrambots-abilities" />
<module name="telegrambots-chat-session-bot" />
<module name="telegrambots-extensions" />
<module name="telegrambots-meta" />
<module name="telegrambots-spring-boot-starter" />
@ -33,6 +34,7 @@
<module name="Bots" target="1.5" />
<module name="telegrambots" target="1.8" />
<module name="telegrambots-abilities" target="1.8" />
<module name="telegrambots-chat-session-bot" target="1.8" />
<module name="telegrambots-extensions" target="1.8" />
<module name="telegrambots-meta" target="1.8" />
<module name="telegrambots-spring-boot-starter" target="1.8" />
@ -242,6 +244,8 @@
<general>
<show-object-navigation-gutter value="false" />
<show-spec-declaration-navigation-gutter value="true" />
<enable-spellchecking value="true" />
<enable-reference-spellchecking value="false" />
</general>
<confirmations>
<save-changes value="false" />
@ -500,6 +504,7 @@
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
<file url="file://$PROJECT_DIR$/telegrambots" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/telegrambots-abilities" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/telegrambots-chat-session-bot" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/telegrambots-extensions" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/telegrambots-meta" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/telegrambots-spring-boot-starter" charset="UTF-8" />
@ -838,6 +843,7 @@
<module fileurl="file://$PROJECT_DIR$/Bots.iml" filepath="$PROJECT_DIR$/Bots.iml" />
<module fileurl="file://$PROJECT_DIR$/telegrambots/telegrambots.iml" filepath="$PROJECT_DIR$/telegrambots/telegrambots.iml" />
<module fileurl="file://$PROJECT_DIR$/telegrambots-abilities/telegrambots-abilities.iml" filepath="$PROJECT_DIR$/telegrambots-abilities/telegrambots-abilities.iml" />
<module fileurl="file://$PROJECT_DIR$/telegrambots-chat-session-bot/telegrambots-chat-session-bot.iml" filepath="$PROJECT_DIR$/telegrambots-chat-session-bot/telegrambots-chat-session-bot.iml" />
<module fileurl="file://$PROJECT_DIR$/telegrambots-extensions/telegrambots-extensions.iml" filepath="$PROJECT_DIR$/telegrambots-extensions/telegrambots-extensions.iml" />
<module fileurl="file://$PROJECT_DIR$/telegrambots-meta/telegrambots-meta.iml" filepath="$PROJECT_DIR$/telegrambots-meta/telegrambots-meta.iml" />
<module fileurl="file://$PROJECT_DIR$/telegrambots-spring-boot-starter/telegrambots-spring-boot-starter.iml" filepath="$PROJECT_DIR$/telegrambots-spring-boot-starter/telegrambots-spring-boot-starter.iml" />
@ -978,6 +984,17 @@
<root url="jar://$MAVEN_REPOSITORY$/com/google/inject/guice/4.1.0/guice-4.1.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: commons-beanutils:commons-beanutils:1.9.3">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/commons-beanutils/commons-beanutils/1.9.3/commons-beanutils-1.9.3.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/commons-beanutils/commons-beanutils/1.9.3/commons-beanutils-1.9.3-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/commons-beanutils/commons-beanutils/1.9.3/commons-beanutils-1.9.3-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: commons-codec:commons-codec:1.9">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/commons-codec/commons-codec/1.9/commons-codec-1.9.jar!/" />
@ -989,6 +1006,17 @@
<root url="jar://$MAVEN_REPOSITORY$/commons-codec/commons-codec/1.9/commons-codec-1.9-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: commons-collections:commons-collections:3.2.2">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: commons-io:commons-io:2.5">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.5/commons-io-2.5.jar!/" />
@ -1154,37 +1182,147 @@
<root url="jar://$MAVEN_REPOSITORY$/org/apache/httpcomponents/httpmime/4.5.3/httpmime-4.5.3-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.eclipse.collections:eclipse-collections-api:7.1.1">
<library name="Maven: org.apache.shiro:shiro-cache:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-api/7.1.1/eclipse-collections-api-7.1.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-cache/1.4.0/shiro-cache-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-api/7.1.1/eclipse-collections-api-7.1.1-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-cache/1.4.0/shiro-cache-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-api/7.1.1/eclipse-collections-api-7.1.1-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-cache/1.4.0/shiro-cache-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.eclipse.collections:eclipse-collections-forkjoin:7.1.1">
<library name="Maven: org.apache.shiro:shiro-config-core:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-forkjoin/7.1.1/eclipse-collections-forkjoin-7.1.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-config-core/1.4.0/shiro-config-core-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-forkjoin/7.1.1/eclipse-collections-forkjoin-7.1.1-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-config-core/1.4.0/shiro-config-core-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-forkjoin/7.1.1/eclipse-collections-forkjoin-7.1.1-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-config-core/1.4.0/shiro-config-core-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.eclipse.collections:eclipse-collections:7.1.1">
<library name="Maven: org.apache.shiro:shiro-config-ogdl:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections/7.1.1/eclipse-collections-7.1.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-config-ogdl/1.4.0/shiro-config-ogdl-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections/7.1.1/eclipse-collections-7.1.1-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-config-ogdl/1.4.0/shiro-config-ogdl-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections/7.1.1/eclipse-collections-7.1.1-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-config-ogdl/1.4.0/shiro-config-ogdl-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.shiro:shiro-core:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-core/1.4.0/shiro-core-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-core/1.4.0/shiro-core-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-core/1.4.0/shiro-core-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.shiro:shiro-crypto-cipher:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-crypto-cipher/1.4.0/shiro-crypto-cipher-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-crypto-cipher/1.4.0/shiro-crypto-cipher-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-crypto-cipher/1.4.0/shiro-crypto-cipher-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.shiro:shiro-crypto-core:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-crypto-core/1.4.0/shiro-crypto-core-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-crypto-core/1.4.0/shiro-crypto-core-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-crypto-core/1.4.0/shiro-crypto-core-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.shiro:shiro-crypto-hash:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-crypto-hash/1.4.0/shiro-crypto-hash-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-crypto-hash/1.4.0/shiro-crypto-hash-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-crypto-hash/1.4.0/shiro-crypto-hash-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.shiro:shiro-event:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-event/1.4.0/shiro-event-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-event/1.4.0/shiro-event-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-event/1.4.0/shiro-event-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.shiro:shiro-lang:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-lang/1.4.0/shiro-lang-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-lang/1.4.0/shiro-lang-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-lang/1.4.0/shiro-lang-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.assertj:assertj-core:3.9.1">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/assertj/assertj-core/3.9.1/assertj-core-3.9.1.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/assertj/assertj-core/3.9.1/assertj-core-3.9.1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/assertj/assertj-core/3.9.1/assertj-core-3.9.1-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.eclipse.collections:eclipse-collections-api:7.1.2">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-api/7.1.2/eclipse-collections-api-7.1.2.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-api/7.1.2/eclipse-collections-api-7.1.2-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-api/7.1.2/eclipse-collections-api-7.1.2-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.eclipse.collections:eclipse-collections-forkjoin:7.1.2">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-forkjoin/7.1.2/eclipse-collections-forkjoin-7.1.2.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-forkjoin/7.1.2/eclipse-collections-forkjoin-7.1.2-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections-forkjoin/7.1.2/eclipse-collections-forkjoin-7.1.2-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.eclipse.collections:eclipse-collections:7.1.2">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections/7.1.2/eclipse-collections-7.1.2.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections/7.1.2/eclipse-collections-7.1.2-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/collections/eclipse-collections/7.1.2/eclipse-collections-7.1.2-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.glassfish.grizzly:grizzly-framework:2.3.28">
@ -1528,81 +1666,114 @@
<root url="jar://$MAVEN_REPOSITORY$/org/mockito/mockito-all/2.0.2-beta/mockito-all-2.0.2-beta-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot-autoconfigure:1.5.10.RELEASE">
<library name="Maven: org.slf4j:slf4j-api:1.7.21">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-autoconfigure/1.5.10.RELEASE/spring-boot-autoconfigure-1.5.10.RELEASE.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-autoconfigure/1.5.10.RELEASE/spring-boot-autoconfigure-1.5.10.RELEASE-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-autoconfigure/1.5.10.RELEASE/spring-boot-autoconfigure-1.5.10.RELEASE-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot:1.5.10.RELEASE">
<library name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.0.2.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot/1.5.10.RELEASE/spring-boot-1.5.10.RELEASE.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-autoconfigure/2.0.2.RELEASE/spring-boot-autoconfigure-2.0.2.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot/1.5.10.RELEASE/spring-boot-1.5.10.RELEASE-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-autoconfigure/2.0.2.RELEASE/spring-boot-autoconfigure-2.0.2.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot/1.5.10.RELEASE/spring-boot-1.5.10.RELEASE-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-autoconfigure/2.0.2.RELEASE/spring-boot-autoconfigure-2.0.2.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-aop:4.3.14.RELEASE">
<library name="Maven: org.springframework.boot:spring-boot-test:2.0.2.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-aop/4.3.14.RELEASE/spring-aop-4.3.14.RELEASE.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-test/2.0.2.RELEASE/spring-boot-test-2.0.2.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-aop/4.3.14.RELEASE/spring-aop-4.3.14.RELEASE-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-test/2.0.2.RELEASE/spring-boot-test-2.0.2.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-aop/4.3.14.RELEASE/spring-aop-4.3.14.RELEASE-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-test/2.0.2.RELEASE/spring-boot-test-2.0.2.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-beans:4.3.14.RELEASE">
<library name="Maven: org.springframework.boot:spring-boot:2.0.2.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/4.3.14.RELEASE/spring-beans-4.3.14.RELEASE.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot/2.0.2.RELEASE/spring-boot-2.0.2.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/4.3.14.RELEASE/spring-beans-4.3.14.RELEASE-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot/2.0.2.RELEASE/spring-boot-2.0.2.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/4.3.14.RELEASE/spring-beans-4.3.14.RELEASE-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot/2.0.2.RELEASE/spring-boot-2.0.2.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-context:4.3.14.RELEASE">
<library name="Maven: org.springframework:spring-aop:5.0.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/4.3.14.RELEASE/spring-context-4.3.14.RELEASE.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-aop/5.0.6.RELEASE/spring-aop-5.0.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/4.3.14.RELEASE/spring-context-4.3.14.RELEASE-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-aop/5.0.6.RELEASE/spring-aop-5.0.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/4.3.14.RELEASE/spring-context-4.3.14.RELEASE-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-aop/5.0.6.RELEASE/spring-aop-5.0.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-core:4.3.14.RELEASE">
<library name="Maven: org.springframework:spring-beans:5.0.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/4.3.14.RELEASE/spring-core-4.3.14.RELEASE.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/5.0.6.RELEASE/spring-beans-5.0.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/4.3.14.RELEASE/spring-core-4.3.14.RELEASE-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/5.0.6.RELEASE/spring-beans-5.0.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/4.3.14.RELEASE/spring-core-4.3.14.RELEASE-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/5.0.6.RELEASE/spring-beans-5.0.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-expression:4.3.14.RELEASE">
<library name="Maven: org.springframework:spring-context:5.0.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-expression/4.3.14.RELEASE/spring-expression-4.3.14.RELEASE.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/5.0.6.RELEASE/spring-context-5.0.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-expression/4.3.14.RELEASE/spring-expression-4.3.14.RELEASE-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/5.0.6.RELEASE/spring-context-5.0.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-expression/4.3.14.RELEASE/spring-expression-4.3.14.RELEASE-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/5.0.6.RELEASE/spring-context-5.0.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-core:5.0.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/5.0.6.RELEASE/spring-core-5.0.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/5.0.6.RELEASE/spring-core-5.0.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/5.0.6.RELEASE/spring-core-5.0.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-expression:5.0.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-expression/5.0.6.RELEASE/spring-expression-5.0.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-expression/5.0.6.RELEASE/spring-expression-5.0.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-expression/5.0.6.RELEASE/spring-expression-5.0.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-jcl:5.0.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-jcl/5.0.6.RELEASE/spring-jcl-5.0.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-jcl/5.0.6.RELEASE/spring-jcl-5.0.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-jcl/5.0.6.RELEASE/spring-jcl-5.0.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.telegram:telegrambots-meta:3.5">

View File

@ -27,7 +27,7 @@ Just import add the library to your project with one of these options:
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>3.6.1</version>
<version>4.0.0</version>
</dependency>
```
@ -43,7 +43,7 @@ In order to use Long Polling mode, just create your own bot extending `org.teleg
If you like to use Webhook, extend `org.telegram.telegrambots.bots.TelegramWebhookBot`
Once done, you just need to create a `org.telegram.telegrambots.TelegramBotsApi`and register your bots:
Once done, you just need to create a `org.telegram.telegrambots.meta.TelegramBotsApi`and register your bots:
```java
@ -93,6 +93,12 @@ This library use [Telegram bot API](https://core.telegram.org/bots), you can fin
## Questions or Suggestions
Feel free to create issues [here](https://github.com/rubenlagus/TelegramBots/issues) as you need or join the [chat](https://telegram.me/JavaBotsApi)
## Powered by Intellij
<p align="center">
<a href="https://www.jetbrains.com"><img src="jetbrains.png" width="75"></a>
</p>
## License
MIT License

View File

@ -1,3 +1,13 @@
### <a id="4.0.0"></a>4.0.0 ###
1. Support for Api Version [4.0](https://core.telegram.org/bots/api-changelog#july-26-2018)
2. Abilities: Internationalization
3. Socks 5 support
4. Improved spring boot start configuration
5. Removed previously deprecated methods
6. Support usage in Java 9 (library is still using java 8)
**[[How to update to version 4.0.0|How-To-Update#4.0.0]]**
### <a id="3.6.1"></a>3.6.1 ###
1. Support for proxy connections
2. New module for Spring

View File

@ -1,11 +1,11 @@
* [Terminated by other long poll or webhook](#terminted_by_other)
* ["No implementation for org.telegram.telegrambots.generics.BotSession was bound"](#no_implementation_was_bound)
* ["No implementation for org.telegram.telegrambots.meta.generics.BotSession was bound"](#no_implementation_was_bound)
## <a id="terminted_by_other"></a>Terminated by other long poll or webhook ##
It means that you have already a running instance of your bot. To solve it, close all running ones and then you can start a new instance.
## <a id="no_implementation_was_bound"></a>No implementation for org.telegram.telegrambots.generics.BotSession was bound ##
## <a id="no_implementation_was_bound"></a>No implementation for org.telegram.meta.telegrambots.generics.BotSession was bound ##
Please follow the steps as explained [here](https://github.com/rubenlagus/TelegramBots/wiki/How-To-Update#to-version-243) in "How To Update"
> At the beginning of your program (before creating your TelegramBotsApi instance, add the following line:
```

View File

@ -88,7 +88,7 @@ There are several method to send a photo to an user using `sendPhoto` method: Wi
sendPhotoRequest.setPhoto(url);
try {
// Execute the method
sendPhoto(sendPhotoRequest);
execute(sendPhotoRequest);
} catch (TelegramApiException e) {
e.printStackTrace();
}
@ -103,7 +103,7 @@ There are several method to send a photo to an user using `sendPhoto` method: Wi
sendPhotoRequest.setPhoto(fileId);
try {
// Execute the method
sendPhoto(sendPhotoRequest);
execute(sendPhotoRequest);
} catch (TelegramApiException e) {
e.printStackTrace();
}
@ -118,7 +118,7 @@ There are several method to send a photo to an user using `sendPhoto` method: Wi
sendPhotoRequest.setNewPhoto(new File(filePath));
try {
// Execute the method
sendPhoto(sendPhotoRequest);
execute(sendPhotoRequest);
} catch (TelegramApiException e) {
e.printStackTrace();
}
@ -144,7 +144,7 @@ if (update.hasMessage() && update.getMessage().hasPhoto()) {
.setPhoto(f_id)
.setCaption("Photo");
try {
sendPhoto(msg); // Call method to send the photo
execute(msg); // Call method to send the photo
} catch (TelegramApiException e) {
e.printStackTrace();
}

View File

@ -11,7 +11,7 @@ First you need ot get the library and add it to your project. There are few poss
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>3.6.1</version>
<version>4.0.0</version>
</dependency>
```
* With **Gradle**:

View File

@ -1,3 +1,9 @@
### <a id="4.0.0"></a>To version 4.0.0 ###
1. Replace removed method from AbsSender with `execute` requests.
2. Everything under "Telegrambots-meta" has been moved to package `org.telegram.telegrambots.meta`.
3. `close` method has been removed from `BotSession`, use `stop` instead.
4. All methods that are intended to upload files are using now `InputMedia` and `InputFile`.
### <a id="2.4.3"></a>To version 2.4.3 ###
1. Replace `BotOptions` by `DefaultBotOptions`.
2. At the beginning of your program (before creating your `TelegramBotsApi` or `Bot` instance, add the following line:

View File

@ -31,7 +31,7 @@ public class MyBot extends AbilityBot {
Now you are able to set up your proxy
#### without authentication
#### Without authentication
```java
public class Main {
@ -51,13 +51,12 @@ public class Main {
TelegramBotsApi botsApi = new TelegramBotsApi();
// Set up Http proxy
DefaultBotOptions botOptions = ApiContext.getInstance(DefaultBotOptions.class);
DefaultBotOptions botOptions = ApiContext.getInstance(DefaultBotOptions.class);
HttpHost httpHost = new HttpHost(PROXY_HOST, PROXY_PORT);
RequestConfig requestConfig = RequestConfig.custom().setProxy(httpHost).setAuthenticationEnabled(false).build();
botOptions.setRequestConfig(requestConfig);
botOptions.setHttpProxy(httpHost);
botOptions.setProxyHost(PROXY_HOST);
botOptions.setProxyPort(PROXY_PORT);
// Select proxy type: [HTTP|SOCKS4|SOCKS5] (default: NO_PROXY)
botOptions.setProxyType(DefaultBotOptions.ProxyType.SOCKS5);
// Register your newly created AbilityBot
MyBot bot = new MyBot(BOT_TOKEN, BOT_NAME, botOptions);
@ -89,25 +88,26 @@ public class Main {
public static void main(String[] args) {
try {
// Create the Authenticator that will return auth's parameters for proxy authentication
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(PROXY_USER, PROXY_PASSWORD.toCharArray());
}
});
ApiContextInitializer.init();
// Create the TelegramBotsApi object to register your bots
TelegramBotsApi botsApi = new TelegramBotsApi();
// Set up Http proxy
DefaultBotOptions botOptions = ApiContext.getInstance(DefaultBotOptions.class);
DefaultBotOptions botOptions = ApiContext.getInstance(DefaultBotOptions.class);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(PROXY_HOST, PROXY_PORT),
new UsernamePasswordCredentials(PROXY_USER, PROXY_PASSWORD));
HttpHost httpHost = new HttpHost(PROXY_HOST, PROXY_PORT);
RequestConfig requestConfig = RequestConfig.custom().setProxy(httpHost).setAuthenticationEnabled(true).build();
botOptions.setRequestConfig(requestConfig);
botOptions.setCredentialsProvider(credsProvider);
botOptions.setHttpProxy(httpHost);
botOptions.setProxyHost(PROXY_HOST);
botOptions.setProxyPort(PROXY_PORT);
// Select proxy type: [HTTP|SOCKS4|SOCKS5] (default: NO_PROXY)
botOptions.setProxyType(DefaultBotOptions.ProxyType.SOCKS5);
// Register your newly created AbilityBot
MyBot bot = new MyBot(BOT_TOKEN, BOT_NAME, botOptions);
@ -119,4 +119,6 @@ public class Main {
}
}
}
```
```
If you need something more complex than one proxy, then you can create more complex Authenticator that will check host and other parameters of proxy and return auth values based on them (for more information see code of java.net.Authenticator class)

View File

@ -88,7 +88,7 @@ import org.telegram.abilitybots.api.db.MapDBContext;
import org.telegram.abilitybots.api.objects.EndUser;
import org.telegram.abilitybots.api.objects.MessageContext;
import org.telegram.abilitybots.api.sender.MessageSender;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.Update;
import static org.mockito.Mockito.*;

View File

@ -9,7 +9,7 @@ As with any Java project, you will need to set your dependencies.
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>3.6.1</version>
<version>4.0.0</version>
</dependency>
```
* **Gradle**
@ -102,8 +102,9 @@ If you're in doubt that you're missing some code, the full code example can be i
Go ahead and "/hello" to your bot. It should respond back with "Hello World!".
Since you've implemented an AbilityBot, you get **factory abilities** as well. Try:
* /commands - Prints all commands supported by the bot
* This will essentially print "hello - says hello world!". Yes! This is the information we supplied to the ability. The bot prints the commands in the format accepted by BotFather. So, whenever you change, add or remove commands, you can simply /commands and forward that message to BotFather.
* /report - Prints all user-defined commands supported by the bot
* This will essentially print "hello - says hello world!". Yes! This is the information we supplied to the ability. The bot prints the commands in the format accepted by BotFather. So, whenever you change, add or remove commands, you can simply /report and forward that message to BotFather.
* /commands - Prints all commands exposed by the bot (factory and user-defined, with and without info)
* /claim - Claims this bot
* /backup - returns a backup of the bot database
* /recover - recovers the database

BIN
jetbrains.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@ -7,7 +7,7 @@
<groupId>org.telegram</groupId>
<artifactId>Bots</artifactId>
<packaging>pom</packaging>
<version>3.6.1</version>
<version>4.0.0</version>
<modules>
<module>telegrambots</module>
@ -15,6 +15,7 @@
<module>telegrambots-extensions</module>
<module>telegrambots-abilities</module>
<module>telegrambots-spring-boot-starter</module>
<module>telegrambots-chat-session-bot</module>
</modules>
<licenses>
@ -27,6 +28,6 @@
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
<bots.version>3.6.1</bots.version>
<bots.version>4.0.0</bots.version>
</properties>
</project>

View File

@ -18,7 +18,7 @@ Usage
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>3.6.1</version>
<version>4.0.0</version>
</dependency>
```

View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>3.6.1</version>
<version>4.0.0</version>
<packaging>jar</packaging>
<name>Telegram Ability Bot</name>
@ -65,7 +65,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<bots.version>3.6.1</bots.version>
<bots.version>4.0.0</bots.version>
<commonslang.version>3.5</commonslang.version>
<mapdb.version>3.0.4</mapdb.version>
<guava.version>19.0</guava.version>

View File

@ -1,138 +1,23 @@
package org.telegram.abilitybots.api.bot;
import org.apache.commons.io.IOUtils;
import org.telegram.abilitybots.api.db.DBContext;
import org.telegram.abilitybots.api.objects.*;
import org.telegram.abilitybots.api.sender.DefaultSender;
import org.telegram.abilitybots.api.sender.MessageSender;
import org.telegram.abilitybots.api.sender.SilentSender;
import org.telegram.abilitybots.api.util.AbilityUtils;
import org.telegram.abilitybots.api.util.Pair;
import org.telegram.abilitybots.api.util.Trio;
import org.telegram.telegrambots.api.methods.GetFile;
import org.telegram.telegrambots.api.methods.groupadministration.GetChatAdministrators;
import org.telegram.telegrambots.api.methods.send.SendDocument;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.exceptions.TelegramApiException;
import org.telegram.telegrambots.logging.BotLogger;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.util.WebhookUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;
import static java.time.ZonedDateTime.now;
import static java.util.Arrays.stream;
import static java.util.Objects.nonNull;
import static java.util.Optional.ofNullable;
import static java.util.function.Function.identity;
import static java.util.regex.Pattern.CASE_INSENSITIVE;
import static java.util.regex.Pattern.compile;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static jersey.repackaged.com.google.common.base.Throwables.propagate;
import static org.telegram.abilitybots.api.db.MapDBContext.onlineInstance;
import static org.telegram.abilitybots.api.objects.Ability.builder;
import static org.telegram.abilitybots.api.objects.EndUser.fromUser;
import static org.telegram.abilitybots.api.objects.Flag.*;
import static org.telegram.abilitybots.api.objects.Locality.*;
import static org.telegram.abilitybots.api.objects.MessageContext.newContext;
import static org.telegram.abilitybots.api.objects.Privacy.*;
import static org.telegram.abilitybots.api.util.AbilityUtils.*;
/**
* The <b>father</b> of all ability bots. Bots that need to utilize abilities need to extend this bot.
* <p>
* It's important to note that this bot strictly extends {@link TelegramLongPollingBot}.
* <p>
* All bots extending the {@link AbilityBot} get implicit abilities:
* <ul>
* <li>/claim - Claims this bot</li>
* <ul>
* <li>Sets the user as the {@link Privacy#CREATOR} of the bot</li>
* <li>Only the user with the ID returned by {@link AbilityBot#creatorId()} can genuinely claim the bot</li>
* </ul>
* <li>/commands - reports all user-defined commands (abilities)</li>
* <ul>
* <li>The same format acceptable by BotFather</li>
* </ul>
* <li>/backup - returns a backup of the bot database</li>
* <li>/recover - recovers the database</li>
* <li>/promote <code>@username</code> - promotes user to bot admin</li>
* <li>/demote <code>@username</code> - demotes bot admin to user</li>
* <li>/ban <code>@username</code> - bans the user from accessing your bot commands and features</li>
* <li>/unban <code>@username</code> - lifts the ban from the user</li>
* </ul>
* <p>
* Additional information of the implicit abilities are present in the methods that declare them.
* <p>
* The two most important handles in the AbilityBot are the {@link DBContext} <b><code>db</code></b> and the {@link MessageSender} <b><code>sender</code></b>.
* All bots extending AbilityBot can use both handles in their update consumers.
* The default AbilityBot class implements {@link LongPollingBot}. It delegates all updates to a {@link TelegramLongPollingBot} instance.
*
* @author Abbas Abou Daya
*/
public abstract class AbilityBot extends TelegramLongPollingBot {
private static final String TAG = AbilityBot.class.getSimpleName();
// DB objects
public static final String ADMINS = "ADMINS";
public static final String USERS = "USERS";
public static final String USER_ID = "USER_ID";
public static final String BLACKLIST = "BLACKLIST";
// Factory commands
protected static final String DEFAULT = "default";
protected static final String CLAIM = "claim";
protected static final String BAN = "ban";
protected static final String PROMOTE = "promote";
protected static final String DEMOTE = "demote";
protected static final String UNBAN = "unban";
protected static final String BACKUP = "backup";
protected static final String RECOVER = "recover";
protected static final String COMMANDS = "commands";
// Messages
protected static final String RECOVERY_MESSAGE = "I am ready to receive the backup file. Please reply to this message with the backup file attached.";
protected static final String RECOVER_SUCCESS = "I have successfully recovered.";
// DB and sender
protected final DBContext db;
protected MessageSender sender;
protected SilentSender silent;
// Bot token and username
private final String botToken;
private final String botUsername;
// Ability registry
private Map<String, Ability> abilities;
// Reply registry
private List<Reply> replies;
public abstract int creatorId();
public abstract class AbilityBot extends BaseAbilityBot implements LongPollingBot {
protected AbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions botOptions) {
super(botOptions);
this.botToken = botToken;
this.botUsername = botUsername;
this.db = db;
this.sender = new DefaultSender(this);
silent = new SilentSender(sender);
registerAbilities();
super(botToken, botUsername, db, botOptions);
}
protected AbilityBot(String botToken, String botUsername, DBContext db) {
@ -147,610 +32,13 @@ public abstract class AbilityBot extends TelegramLongPollingBot {
this(botToken, botUsername, onlineInstance(botUsername));
}
/**
* @return the map of ID -> EndUser
*/
protected Map<Integer, EndUser> users() {
return db.getMap(USERS);
}
/**
* @return the map of Username -> ID
*/
protected Map<String, Integer> userIds() {
return db.getMap(USER_ID);
}
/**
* @return a blacklist containing all the IDs of the banned users
*/
protected Set<Integer> blacklist() {
return db.getSet(BLACKLIST);
}
/**
* @return an admin set of all the IDs of bot administrators
*/
protected Set<Integer> admins() {
return db.getSet(ADMINS);
}
/**
* This method contains the stream of actions that are applied on any update.
* <p>
* It will correctly handle addition of users into the DB and the execution of abilities and replies.
*
* @param update the update received by Telegram's API
*/
@Override
public void onUpdateReceived(Update update) {
BotLogger.info(format("New update [%s] received at %s", update.getUpdateId(), now()), format("%s - %s", TAG, botUsername));
BotLogger.info(update.toString(), TAG);
long millisStarted = System.currentTimeMillis();
Stream.of(update)
.filter(this::checkGlobalFlags)
.filter(this::checkBlacklist)
.map(this::addUser)
.filter(this::filterReply)
.map(this::getAbility)
.filter(this::validateAbility)
.filter(this::checkPrivacy)
.filter(this::checkLocality)
.filter(this::checkInput)
.filter(this::checkMessageFlags)
.map(this::getContext)
.map(this::consumeUpdate)
.forEach(this::postConsumption);
long processingTime = System.currentTimeMillis() - millisStarted;
BotLogger.info(format("Processing of update [%s] ended at %s%n---> Processing time: [%d ms] <---%n", update.getUpdateId(), now(), processingTime), format("%s - %s", TAG, botUsername));
super.onUpdateReceived(update);
}
@Override
public String getBotToken() {
return botToken;
}
@Override
public String getBotUsername() {
return botUsername;
}
/**
* Test the update against the provided global flags. The default implementation is a passthrough to all updates.
* <p>
* This method should be <b>overridden</b> if the user wants to restrict bot usage to only certain updates.
*
* @param update a Telegram {@link Update}
* @return <tt>true</tt> if the update satisfies the global flags
*/
protected boolean checkGlobalFlags(Update update) {
return true;
}
/**
* Gets the user with the specified username.
*
* @param username the username of the required user
* @return the user
*/
protected EndUser getUser(String username) {
Integer id = userIds().get(username.toLowerCase());
if (id == null) {
throw new IllegalStateException(format("Could not find ID corresponding to username [%s]", username));
}
return getUser(id);
}
/**
* Gets the user with the specified ID.
*
* @param id the id of the required user
* @return the user
*/
protected EndUser getUser(int id) {
EndUser endUser = users().get(id);
if (endUser == null) {
throw new IllegalStateException(format("Could not find user corresponding to id [%d]", id));
}
return endUser;
}
/**
* Gets the user with the specified username. If user was not found, the bot will send a message on Telegram.
*
* @param username the username of the required user
* @return the id of the user
*/
protected int getUserIdSendError(String username, long chatId) {
try {
return getUser(username).id();
} catch (IllegalStateException ex) {
silent.send(format("Sorry, I could not find the user [%s].", username), chatId);
throw propagate(ex);
}
}
/**
* <p>
* Format of the report:
* <p>
* [command1] - [description1]
* <p>
* [command2] - [description2]
* <p>
* ...
* <p>
* Once you invoke it, the bot will send the available commands to the chat. This is a public ability so anyone can invoke it.
* <p>
* Usage: <code>/commands</code>
*
* @return the ability to report commands defined by the child bot.
*/
public Ability reportCommands() {
return builder()
.name(COMMANDS)
.locality(ALL)
.privacy(PUBLIC)
.input(0)
.action(ctx -> {
String commands = abilities.entrySet().stream()
.filter(entry -> nonNull(entry.getValue().info()))
.map(entry -> {
String name = entry.getValue().name();
String info = entry.getValue().info();
return format("%s - %s", name, info);
})
.sorted()
.reduce((a, b) -> format("%s%n%s", a, b))
.orElse("No public commands found.");
silent.send(commands, ctx.chatId());
})
.build();
}
/**
* This backup ability returns the object defined by {@link DBContext#backup()} as a message document.
* <p>
* This is a high-profile ability and is restricted to the CREATOR only.
* <p>
* Usage: <code>/backup</code>
*
* @return the ability to back-up the database of the bot
*/
public Ability backupDB() {
return builder()
.name(BACKUP)
.locality(USER)
.privacy(CREATOR)
.input(0)
.action(ctx -> {
File backup = new File("backup.json");
try (PrintStream printStream = new PrintStream(backup)) {
printStream.print(db.backup());
sender.sendDocument(new SendDocument()
.setNewDocument(backup)
.setChatId(ctx.chatId())
);
} catch (FileNotFoundException e) {
BotLogger.error("Error while fetching backup", TAG, e);
} catch (TelegramApiException e) {
BotLogger.error("Error while sending document/backup file", TAG, e);
}
})
.build();
}
/**
* Recovers the bot database using {@link DBContext#recover(Object)}.
* <p>
* The bot recovery process hugely depends on the implementation of the recovery method of {@link DBContext}.
* <p>
* Usage: <code>/recover</code>
*
* @return the ability to recover the database of the bot
*/
public Ability recoverDB() {
return builder()
.name(RECOVER)
.locality(USER)
.privacy(CREATOR)
.input(0)
.action(ctx -> silent.forceReply(RECOVERY_MESSAGE, ctx.chatId()))
.reply(update -> {
Long chatId = update.getMessage().getChatId();
String fileId = update.getMessage().getDocument().getFileId();
try (FileReader reader = new FileReader(downloadFileWithId(fileId))) {
String backupData = IOUtils.toString(reader);
if (db.recover(backupData)) {
silent.send(RECOVER_SUCCESS, chatId);
} else {
silent.send("Oops, something went wrong during recovery.", chatId);
}
} catch (Exception e) {
BotLogger.error("Could not recover DB from backup", TAG, e);
silent.send("I have failed to recover.", chatId);
}
}, MESSAGE, DOCUMENT, REPLY, isReplyTo(RECOVERY_MESSAGE))
.build();
}
/**
* Banned users are accumulated in the blacklist. Use {@link DBContext#getSet(String)} with name specified by {@link AbilityBot#BLACKLIST}.
* <p>
* Usage: <code>/ban @username</code>
* <p>
* <u>Note that admins who try to ban the creator, get banned.</u>
*
* @return the ability to ban the user from any kind of <b>bot interaction</b>
*/
public Ability banUser() {
return builder()
.name(BAN)
.locality(ALL)
.privacy(ADMIN)
.input(1)
.action(ctx -> {
String username = stripTag(ctx.firstArg());
int userId = getUserIdSendError(username, ctx.chatId());
String bannedUser;
// Protection from abuse
if (userId == creatorId()) {
userId = ctx.user().id();
bannedUser = isNullOrEmpty(ctx.user().username()) ? addTag(ctx.user().username()) : ctx.user().shortName();
} else {
bannedUser = addTag(username);
}
Set<Integer> blacklist = blacklist();
if (blacklist.contains(userId))
silent.sendMd(format("%s is already *banned*.", escape(bannedUser)), ctx.chatId());
else {
blacklist.add(userId);
silent.sendMd(format("%s is now *banned*.", escape(bannedUser)), ctx.chatId());
}
})
.post(commitTo(db))
.build();
}
/**
* Usage: <code>/unban @username</code>
*
* @return the ability to unban a user
*/
public Ability unbanUser() {
return builder()
.name(UNBAN)
.locality(ALL)
.privacy(ADMIN)
.input(1)
.action(ctx -> {
String username = stripTag(ctx.firstArg());
Integer userId = getUserIdSendError(username, ctx.chatId());
Set<Integer> blacklist = blacklist();
if (!blacklist.remove(userId))
silent.sendMd(format("@%s is *not* on the *blacklist*.", escape(username)), ctx.chatId());
else {
silent.sendMd(format("@%s, your ban has been *lifted*.", escape(username)), ctx.chatId());
}
})
.post(commitTo(db))
.build();
}
/**
* @return the ability to promote a user to a bot admin
*/
public Ability promoteAdmin() {
return builder()
.name(PROMOTE)
.locality(ALL)
.privacy(ADMIN)
.input(1)
.action(ctx -> {
String username = stripTag(ctx.firstArg());
Integer userId = getUserIdSendError(username, ctx.chatId());
Set<Integer> admins = admins();
if (admins.contains(userId))
silent.sendMd(format("@%s is already an *admin*.", escape(username)), ctx.chatId());
else {
admins.add(userId);
silent.sendMd(format("@%s has been *promoted*.", escape(username)), ctx.chatId());
}
}).post(commitTo(db))
.build();
}
/**
* @return the ability to demote an admin to a user
*/
public Ability demoteAdmin() {
return builder()
.name(DEMOTE)
.locality(ALL)
.privacy(ADMIN)
.input(1)
.action(ctx -> {
String username = stripTag(ctx.firstArg());
Integer userId = getUserIdSendError(username, ctx.chatId());
Set<Integer> admins = admins();
if (admins.remove(userId)) {
silent.sendMd(format("@%s has been *demoted*.", escape(username)), ctx.chatId());
} else {
silent.sendMd(format("@%s is *not* an *admin*.", escape(username)), ctx.chatId());
}
})
.post(commitTo(db))
.build();
}
/**
* Regular users and admins who try to claim the bot will get <b>banned</b>.
*
* @return the ability to claim yourself as the master and creator of the bot
*/
public Ability claimCreator() {
return builder()
.name(CLAIM)
.locality(ALL)
.privacy(PUBLIC)
.input(0)
.action(ctx -> {
if (ctx.user().id() == creatorId()) {
Set<Integer> admins = admins();
int id = creatorId();
long chatId = ctx.chatId();
if (admins.contains(id))
silent.send("You're already my master.", chatId);
else {
admins.add(id);
silent.send("You're now my master.", chatId);
}
} else {
// This is not a joke
abilities.get(BAN).action().accept(newContext(ctx.update(), ctx.user(), ctx.chatId(), ctx.user().username()));
}
})
.post(commitTo(db))
.build();
}
/**
* Registers the declared abilities using method reflection. Also, replies are accumulated using the built abilities and standalone methods that return a Reply.
* <p>
* <b>Only abilities and replies with the <u>public</u> accessor are registered!</b>
*/
private void registerAbilities() {
try {
abilities = stream(this.getClass().getMethods())
.filter(method -> method.getReturnType().equals(Ability.class))
.map(this::returnAbility)
.collect(toMap(ability -> ability.name().toLowerCase(), identity()));
Stream<Reply> methodReplies = stream(this.getClass().getMethods())
.filter(method -> method.getReturnType().equals(Reply.class))
.map(this::returnReply);
Stream<Reply> abilityReplies = abilities.values().stream()
.flatMap(ability -> ability.replies().stream());
replies = Stream.concat(methodReplies, abilityReplies).collect(toList());
} catch (IllegalStateException e) {
BotLogger.error(TAG, "Duplicate names found while registering abilities. Make sure that the abilities declared don't clash with the reserved ones.", e);
throw propagate(e);
}
}
/**
* Invokes the method and retrieves its return {@link Ability}.
*
* @param method a method that returns an ability
* @return the ability returned by the method
*/
private Ability returnAbility(Method method) {
try {
return (Ability) method.invoke(this);
} catch (IllegalAccessException | InvocationTargetException e) {
BotLogger.error("Could not add ability", TAG, e);
throw propagate(e);
}
}
/**
* Invokes the method and retrieves its returned Reply.
*
* @param method a method that returns a reply
* @return the reply returned by the method
*/
private Reply returnReply(Method method) {
try {
return (Reply) method.invoke(this);
} catch (IllegalAccessException | InvocationTargetException e) {
BotLogger.error("Could not add reply", TAG, e);
throw propagate(e);
}
}
private void postConsumption(Pair<MessageContext, Ability> pair) {
ofNullable(pair.b().postAction())
.ifPresent(consumer -> consumer.accept(pair.a()));
}
Pair<MessageContext, Ability> consumeUpdate(Pair<MessageContext, Ability> pair) {
pair.b().action().accept(pair.a());
return pair;
}
Pair<MessageContext, Ability> getContext(Trio<Update, Ability, String[]> trio) {
Update update = trio.a();
EndUser user = fromUser(AbilityUtils.getUser(update));
return Pair.of(newContext(update, user, getChatId(update), trio.c()), trio.b());
}
boolean checkBlacklist(Update update) {
Integer id = AbilityUtils.getUser(update).getId();
return id == creatorId() || !blacklist().contains(id);
}
boolean checkInput(Trio<Update, Ability, String[]> trio) {
String[] tokens = trio.c();
int abilityTokens = trio.b().tokens();
boolean isOk = abilityTokens == 0 || (tokens.length > 0 && tokens.length == abilityTokens);
if (!isOk)
silent.send(format("Sorry, this feature requires %d additional %s.", abilityTokens, abilityTokens == 1 ? "input" : "inputs"), getChatId(trio.a()));
return isOk;
}
boolean checkLocality(Trio<Update, Ability, String[]> trio) {
Update update = trio.a();
Locality locality = isUserMessage(update) ? USER : GROUP;
Locality abilityLocality = trio.b().locality();
boolean isOk = abilityLocality == ALL || locality == abilityLocality;
if (!isOk)
silent.send(format("Sorry, %s-only feature.", abilityLocality.toString().toLowerCase()), getChatId(trio.a()));
return isOk;
}
boolean checkPrivacy(Trio<Update, Ability, String[]> trio) {
Update update = trio.a();
EndUser user = fromUser(AbilityUtils.getUser(update));
Privacy privacy;
int id = user.id();
privacy = isCreator(id) ? CREATOR : isAdmin(id) ? ADMIN : isGroupAdmin(update, id)? GROUP_ADMIN : PUBLIC;
boolean isOk = privacy.compareTo(trio.b().privacy()) >= 0;
if (!isOk)
silent.send("Sorry, you don't have the required access level to do that.", getChatId(trio.a()));
return isOk;
}
private boolean isGroupAdmin(Update update, int id) {
GetChatAdministrators admins = new GetChatAdministrators().setChatId(getChatId(update));
return isGroupUpdate(update) && silent.execute(admins)
.orElse(new ArrayList<>()).stream()
.anyMatch(member -> member.getUser().getId() == id);
}
private boolean isCreator(int id) {
return id == creatorId();
}
private boolean isAdmin(Integer id) {
return admins().contains(id);
}
boolean validateAbility(Trio<Update, Ability, String[]> trio) {
return trio.b() != null;
}
Trio<Update, Ability, String[]> getAbility(Update update) {
// Handle updates without messages
// Passing through this function means that the global flags have passed
Message msg = update.getMessage();
if (!update.hasMessage() || !msg.hasText())
return Trio.of(update, abilities.get(DEFAULT), new String[]{});
String[] tokens = msg.getText().split(" ");
if (tokens[0].startsWith("/")) {
String abilityToken = stripBotUsername(tokens[0].substring(1)).toLowerCase();
Ability ability = abilities.get(abilityToken);
tokens = Arrays.copyOfRange(tokens, 1, tokens.length);
return Trio.of(update, ability, tokens);
} else {
Ability ability = abilities.get(DEFAULT);
return Trio.of(update, ability, tokens);
}
}
private String stripBotUsername(String token) {
return compile(format("@%s", botUsername), CASE_INSENSITIVE)
.matcher(token)
.replaceAll("");
}
Update addUser(Update update) {
EndUser endUser = fromUser(AbilityUtils.getUser(update));
users().compute(endUser.id(), (id, user) -> {
if (user == null) {
updateUserId(user, endUser);
return endUser;
}
if (!user.equals(endUser)) {
updateUserId(user, endUser);
return endUser;
}
return user;
});
db.commit();
return update;
}
private void updateUserId(EndUser oldUser, EndUser newUser) {
if (oldUser != null && oldUser.username() != null) {
// Remove old username -> ID
userIds().remove(oldUser.username());
}
if (newUser.username() != null) {
// Add new mapping with the new username
userIds().put(newUser.username().toLowerCase(), newUser.id());
}
}
boolean filterReply(Update update) {
return replies.stream()
.filter(reply -> reply.isOkFor(update))
.map(reply -> {
reply.actOn(update);
return false;
})
.reduce(true, Boolean::logicalAnd);
}
boolean checkMessageFlags(Trio<Update, Ability, String[]> trio) {
Ability ability = trio.b();
Update update = trio.a();
// The following variable is required to avoid bug #JDK-8044546
BiFunction<Boolean, Predicate<Update>, Boolean> flagAnd = (flag, nextFlag) -> flag && nextFlag.test(update);
return ability.flags().stream()
.reduce(true, flagAnd, Boolean::logicalAnd);
}
private File downloadFileWithId(String fileId) throws TelegramApiException {
return sender.downloadFile(sender.execute(new GetFile().setFileId(fileId)));
}
private String escape(String username) {
return username.replace("_", "\\_");
public void clearWebhook() throws TelegramApiRequestException {
WebhookUtils.clearWebhook(this);
}
}

View File

@ -0,0 +1,56 @@
package org.telegram.abilitybots.api.bot;
import org.telegram.abilitybots.api.db.DBContext;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.bots.TelegramWebhookBot;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.generics.WebhookBot;
import org.telegram.telegrambots.util.WebhookUtils;
import static org.telegram.abilitybots.api.db.MapDBContext.onlineInstance;
/**
* A {@link WebhookBot}-flavor AbilityBot. It delegates all updates to a {@link TelegramWebhookBot} instance.
*
* @author Abbas Abou Daya
*/
@SuppressWarnings("WeakerAccess")
public abstract class AbilityWebhookBot extends BaseAbilityBot implements WebhookBot {
private final String botPath;
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, DefaultBotOptions botOptions) {
super(botToken, botUsername, db, botOptions);
this.botPath = botPath;
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db) {
this(botToken, botUsername, botPath, db, new DefaultBotOptions());
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DefaultBotOptions botOptions) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), botOptions);
}
protected AbilityWebhookBot(String botToken, String botUsername, String botPath) {
this(botToken, botUsername, botPath, onlineInstance(botUsername));
}
@Override
public BotApiMethod onWebhookUpdateReceived(Update update) {
super.onUpdateReceived(update);
return null;
}
@Override
public void setWebhook(String url, String publicCertificatePath) throws TelegramApiRequestException {
WebhookUtils.setWebhook(this, url, publicCertificatePath);
}
@Override
public String getBotPath() {
return botPath;
}
}

View File

@ -0,0 +1,861 @@
package org.telegram.abilitybots.api.bot;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import org.apache.commons.io.IOUtils;
import org.jetbrains.annotations.NotNull;
import org.telegram.abilitybots.api.db.DBContext;
import org.telegram.abilitybots.api.objects.*;
import org.telegram.abilitybots.api.sender.DefaultSender;
import org.telegram.abilitybots.api.sender.MessageSender;
import org.telegram.abilitybots.api.sender.SilentSender;
import org.telegram.abilitybots.api.util.AbilityUtils;
import org.telegram.abilitybots.api.util.Pair;
import org.telegram.abilitybots.api.util.Trio;
import org.telegram.telegrambots.meta.api.methods.GetFile;
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators;
import org.telegram.telegrambots.meta.api.methods.send.SendDocument;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.bots.DefaultAbsSender;
import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.logging.BotLogger;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.MultimapBuilder.hashKeys;
import static java.lang.String.format;
import static java.time.ZonedDateTime.now;
import static java.util.Arrays.stream;
import static java.util.Comparator.comparing;
import static java.util.Objects.nonNull;
import static java.util.Optional.ofNullable;
import static java.util.regex.Pattern.CASE_INSENSITIVE;
import static java.util.regex.Pattern.compile;
import static java.util.stream.Collectors.joining;
import static jersey.repackaged.com.google.common.base.Throwables.propagate;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.telegram.abilitybots.api.objects.Ability.builder;
import static org.telegram.abilitybots.api.objects.Flag.*;
import static org.telegram.abilitybots.api.objects.Locality.*;
import static org.telegram.abilitybots.api.objects.MessageContext.newContext;
import static org.telegram.abilitybots.api.objects.Privacy.*;
import static org.telegram.abilitybots.api.util.AbilityMessageCodes.*;
import static org.telegram.abilitybots.api.util.AbilityUtils.*;
/**
* The <b>father</b> of all ability bots. Bots that need to utilize abilities need to extend this bot.
* <p>
* It's important to note that this bot strictly extends {@link TelegramLongPollingBot}.
* <p>
* All bots extending the {@link BaseAbilityBot} get implicit abilities:
* <ul>
* <li>/claim - Claims this bot</li>
* <ul>
* <li>Sets the user as the {@link Privacy#CREATOR} of the bot</li>
* <li>Only the user with the ID returned by {@link BaseAbilityBot#creatorId()} can genuinely claim the bot</li>
* </ul>
* <li>/report - reports all user-defined commands (abilities)</li>
* <ul>
* <li>The same format acceptable by BotFather</li>
* </ul>
* <li>/commands - returns a list of all possible bot commands based on the privacy of the requesting user</li>
* <li>/backup - returns a backup of the bot database</li>
* <li>/recover - recovers the database</li>
* <li>/promote <code>@username</code> - promotes user to bot admin</li>
* <li>/demote <code>@username</code> - demotes bot admin to user</li>
* <li>/ban <code>@username</code> - bans the user from accessing your bot commands and features</li>
* <li>/unban <code>@username</code> - lifts the ban from the user</li>
* </ul>
* <p>
* Additional information of the implicit abilities are present in the methods that declare them.
* <p>
* The two most important handles in the BaseAbilityBot are the {@link DBContext} <b><code>db</code></b> and the {@link MessageSender} <b><code>sender</code></b>.
* All bots extending BaseAbilityBot can use both handles in their update consumers.
*
* @author Abbas Abou Daya
*/
@SuppressWarnings({"ConfusingArgumentToVarargsMethod", "UnusedReturnValue", "WeakerAccess", "unused", "ConstantConditions"})
public abstract class BaseAbilityBot extends DefaultAbsSender {
private static final String TAG = BaseAbilityBot.class.getSimpleName();
// DB objects
public static final String ADMINS = "ADMINS";
public static final String USERS = "USERS";
public static final String USER_ID = "USER_ID";
public static final String BLACKLIST = "BLACKLIST";
// Factory commands
protected static final String DEFAULT = "default";
protected static final String CLAIM = "claim";
protected static final String BAN = "ban";
protected static final String PROMOTE = "promote";
protected static final String DEMOTE = "demote";
protected static final String UNBAN = "unban";
protected static final String BACKUP = "backup";
protected static final String RECOVER = "recover";
protected static final String COMMANDS = "commands";
protected static final String REPORT = "report";
// DB and sender
protected final DBContext db;
protected MessageSender sender;
protected SilentSender silent;
// Bot token and username
private final String botToken;
private final String botUsername;
// Ability registry
private Map<String, Ability> abilities;
// Reply registry
private List<Reply> replies;
public abstract int creatorId();
protected BaseAbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions botOptions) {
super(botOptions);
this.botToken = botToken;
this.botUsername = botUsername;
this.db = db;
this.sender = new DefaultSender(this);
silent = new SilentSender(sender);
registerAbilities();
}
/**
* @return the map of ID -> User
*/
protected Map<Integer, User> users() {
return db.getMap(USERS);
}
/**
* @return the map of Username -> ID
*/
protected Map<String, Integer> userIds() {
return db.getMap(USER_ID);
}
/**
* @return a blacklist containing all the IDs of the banned users
*/
protected Set<Integer> blacklist() {
return db.getSet(BLACKLIST);
}
/**
* @return an admin set of all the IDs of bot administrators
*/
protected Set<Integer> admins() {
return db.getSet(ADMINS);
}
/**
* @return the immutable map of String -> Ability
*/
public Map<String, Ability> abilities() {
return abilities;
}
/**
* @return the immutable list carrying the embedded replies
*/
public List<Reply> replies() {
return replies;
}
/**
* This method contains the stream of actions that are applied on any update.
* <p>
* It will correctly handle addition of users into the DB and the execution of abilities and replies.
*
* @param update the update received by Telegram's API
*/
public void onUpdateReceived(Update update) {
BotLogger.info(format("New update [%s] received at %s", update.getUpdateId(), now()), format("%s - %s", TAG, botUsername));
BotLogger.info(update.toString(), TAG);
long millisStarted = System.currentTimeMillis();
Stream.of(update)
.filter(this::checkGlobalFlags)
.filter(this::checkBlacklist)
.map(this::addUser)
.filter(this::filterReply)
.map(this::getAbility)
.filter(this::validateAbility)
.filter(this::checkPrivacy)
.filter(this::checkLocality)
.filter(this::checkInput)
.filter(this::checkMessageFlags)
.map(this::getContext)
.map(this::consumeUpdate)
.forEach(this::postConsumption);
long processingTime = System.currentTimeMillis() - millisStarted;
BotLogger.info(format("Processing of update [%s] ended at %s%n---> Processing time: [%d ms] <---%n", update.getUpdateId(), now(), processingTime), format("%s - %s", TAG, botUsername));
}
public String getBotToken() {
return botToken;
}
public String getBotUsername() {
return botUsername;
}
/**
* Test the update against the provided global flags. The default implementation is a passthrough to all updates.
* <p>
* This method should be <b>overridden</b> if the user wants to restrict bot usage to only certain updates.
*
* @param update a Telegram {@link Update}
* @return <tt>true</tt> if the update satisfies the global flags
*/
protected boolean checkGlobalFlags(Update update) {
return true;
}
/**
* Gets the user with the specified username.
*
* @param username the username of the required user
* @return the user
*/
protected User getUser(String username) {
Integer id = userIds().get(username.toLowerCase());
if (id == null) {
throw new IllegalStateException(format("Could not find ID corresponding to username [%s]", username));
}
return getUser(id);
}
/**
* Gets the user with the specified ID.
*
* @param id the id of the required user
* @return the user
*/
protected User getUser(int id) {
User user = users().get(id);
if (user == null) {
throw new IllegalStateException(format("Could not find user corresponding to id [%d]", id));
}
return user;
}
/**
* Gets the user with the specified username. If user was not found, the bot will send a message on Telegram.
*
* @param username the username of the required user
* @param ctx the message context with the originating user
* @return the id of the user
*/
protected int getUserIdSendError(String username, MessageContext ctx) {
try {
return getUser(username).getId();
} catch (IllegalStateException ex) {
silent.send(getLocalizedMessage(USER_NOT_FOUND, ctx.user().getLanguageCode(), username), ctx.chatId());
throw propagate(ex);
}
}
/**
* <p>
* Format of the report:
* <p>
* [command1] - [description1]
* <p>
* [command2] - [description2]
* <p>
* ...
* <p>
* Once you invoke it, the bot will send the available commands to the chat. This is a public ability so anyone can invoke it.
* <p>
* Usage: <code>/commands</code>
*
* @return the ability to report commands defined by the child bot.
*/
public Ability reportCommands() {
return builder()
.name(REPORT)
.locality(ALL)
.privacy(CREATOR)
.input(0)
.action(ctx -> {
String commands = abilities.entrySet().stream()
.filter(entry -> nonNull(entry.getValue().info()))
.map(entry -> {
String name = entry.getValue().name();
String info = entry.getValue().info();
return format("%s - %s", name, info);
})
.sorted()
.reduce((a, b) -> format("%s%n%s", a, b))
.orElse(getLocalizedMessage(ABILITY_COMMANDS_NOT_FOUND, ctx.user().getLanguageCode()));
silent.send(commands, ctx.chatId());
})
.build();
}
/**
* Default format:
* <p>
* PUBLIC
* <p>
* [command1] - [description1]
* <p>
* [command2] - [description2]
* <p>
* GROUP_ADMIN
* <p>
* [command1] - [description1]
* <p>
* ...
*
* @return the ability to print commands based on the privacy of the requesting user
*/
public Ability commands() {
return builder()
.name(COMMANDS)
.locality(USER)
.privacy(PUBLIC)
.input(0)
.action(ctx -> {
Privacy privacy = getPrivacy(ctx.update(), ctx.user().getId());
ListMultimap<Privacy, String> abilitiesPerPrivacy = abilities.entrySet().stream()
.map(entry -> {
String name = entry.getValue().name();
String info = entry.getValue().info();
if (!isEmpty(info))
return Pair.of(entry.getValue().privacy(), format("/%s - %s", name, info));
return Pair.of(entry.getValue().privacy(), format("/%s", name));
})
.sorted(comparing(Pair::b))
.collect(() -> hashKeys().arrayListValues().build(),
(map, pair) -> map.put(pair.a(), pair.b()),
Multimap::putAll);
String commands = abilitiesPerPrivacy.asMap().entrySet().stream()
.filter(entry -> privacy.compareTo(entry.getKey()) >= 0)
.sorted(comparing(Entry::getKey))
.map(entry ->
entry.getValue().stream()
.reduce(entry.getKey().toString(), (a, b) -> format("%s\n%s", a, b))
)
.collect(joining("\n"));
if (commands.isEmpty())
commands = getLocalizedMessage(ABILITY_COMMANDS_NOT_FOUND, ctx.user().getLanguageCode());
silent.send(commands, ctx.chatId());
})
.build();
}
/**
* This backup ability returns the object defined by {@link DBContext#backup()} as a message document.
* <p>
* This is a high-profile ability and is restricted to the CREATOR only.
* <p>
* Usage: <code>/backup</code>
*
* @return the ability to back-up the database of the bot
*/
public Ability backupDB() {
return builder()
.name(BACKUP)
.locality(USER)
.privacy(CREATOR)
.input(0)
.action(ctx -> {
File backup = new File("backup.json");
try (PrintStream printStream = new PrintStream(backup)) {
printStream.print(db.backup());
sender.sendDocument(new SendDocument()
.setDocument(backup)
.setChatId(ctx.chatId())
);
} catch (FileNotFoundException e) {
BotLogger.error("Error while fetching backup", TAG, e);
} catch (TelegramApiException e) {
BotLogger.error("Error while sending document/backup file", TAG, e);
}
})
.build();
}
/**
* Recovers the bot database using {@link DBContext#recover(Object)}.
* <p>
* The bot recovery process hugely depends on the implementation of the recovery method of {@link DBContext}.
* <p>
* Usage: <code>/recover</code>
*
* @return the ability to recover the database of the bot
*/
public Ability recoverDB() {
return builder()
.name(RECOVER)
.locality(USER)
.privacy(CREATOR)
.input(0)
.action(ctx -> silent.forceReply(
getLocalizedMessage(ABILITY_RECOVER_MESSAGE, ctx.user().getLanguageCode()), ctx.chatId()))
.reply(update -> {
String replyToMsg = update.getMessage().getReplyToMessage().getText();
String recoverMessage = getLocalizedMessage(ABILITY_RECOVER_MESSAGE, AbilityUtils.getUser(update).getLanguageCode());
if (!replyToMsg.equals(recoverMessage))
return;
String fileId = update.getMessage().getDocument().getFileId();
try (FileReader reader = new FileReader(downloadFileWithId(fileId))) {
String backupData = IOUtils.toString(reader);
if (db.recover(backupData)) {
send(ABILITY_RECOVER_SUCCESS, update);
} else {
send(ABILITY_RECOVER_FAIL, update);
}
} catch (Exception e) {
BotLogger.error("Could not recover DB from backup", TAG, e);
send(ABILITY_RECOVER_ERROR, update);
}
}, MESSAGE, DOCUMENT, REPLY)
.build();
}
/**
* Banned users are accumulated in the blacklist. Use {@link DBContext#getSet(String)} with name specified by {@link BaseAbilityBot#BLACKLIST}.
* <p>
* Usage: <code>/ban @username</code>
* <p>
* <u>Note that admins who try to ban the creator, get banned.</u>
*
* @return the ability to ban the user from any kind of <b>bot interaction</b>
*/
public Ability banUser() {
return builder()
.name(BAN)
.locality(ALL)
.privacy(ADMIN)
.input(1)
.action(ctx -> {
String username = stripTag(ctx.firstArg());
int userId = getUserIdSendError(username, ctx);
String bannedUser;
// Protection from abuse
if (userId == creatorId()) {
userId = ctx.user().getId();
bannedUser = isNullOrEmpty(ctx.user().getUserName()) ? addTag(ctx.user().getUserName()) : shortName(ctx.user());
} else {
bannedUser = addTag(username);
}
Set<Integer> blacklist = blacklist();
if (blacklist.contains(userId))
sendMd(ABILITY_BAN_FAIL, ctx, escape(bannedUser));
else {
blacklist.add(userId);
sendMd(ABILITY_BAN_SUCCESS, ctx, escape(bannedUser));
}
})
.post(commitTo(db))
.build();
}
/**
* Usage: <code>/unban @username</code>
*
* @return the ability to unban a user
*/
public Ability unbanUser() {
return builder()
.name(UNBAN)
.locality(ALL)
.privacy(ADMIN)
.input(1)
.action(ctx -> {
String username = stripTag(ctx.firstArg());
Integer userId = getUserIdSendError(username, ctx);
Set<Integer> blacklist = blacklist();
if (!blacklist.remove(userId))
silent.sendMd(getLocalizedMessage(ABILITY_UNBAN_FAIL, ctx.user().getLanguageCode(), escape(username)), ctx.chatId());
else {
silent.sendMd(getLocalizedMessage(ABILITY_UNBAN_SUCCESS, ctx.user().getLanguageCode(), escape(username)), ctx.chatId());
}
})
.post(commitTo(db))
.build();
}
/**
* @return the ability to promote a user to a bot admin
*/
public Ability promoteAdmin() {
return builder()
.name(PROMOTE)
.locality(ALL)
.privacy(ADMIN)
.input(1)
.action(ctx -> {
String username = stripTag(ctx.firstArg());
Integer userId = getUserIdSendError(username, ctx);
Set<Integer> admins = admins();
if (admins.contains(userId))
sendMd(ABILITY_PROMOTE_FAIL, ctx, escape(username));
else {
admins.add(userId);
sendMd(ABILITY_PROMOTE_SUCCESS, ctx, escape(username));
}
}).post(commitTo(db))
.build();
}
/**
* @return the ability to demote an admin to a user
*/
public Ability demoteAdmin() {
return builder()
.name(DEMOTE)
.locality(ALL)
.privacy(ADMIN)
.input(1)
.action(ctx -> {
String username = stripTag(ctx.firstArg());
Integer userId = getUserIdSendError(username, ctx);
Set<Integer> admins = admins();
if (admins.remove(userId)) {
sendMd(ABILITY_DEMOTE_SUCCESS, ctx, escape(username));
} else {
sendMd(ABILITY_DEMOTE_FAIL, ctx, escape(username));
}
})
.post(commitTo(db))
.build();
}
/**
* Regular users and admins who try to claim the bot will get <b>banned</b>.
*
* @return the ability to claim yourself as the master and creator of the bot
*/
public Ability claimCreator() {
return builder()
.name(CLAIM)
.locality(ALL)
.privacy(CREATOR)
.input(0)
.action(ctx -> {
Set<Integer> admins = admins();
int id = creatorId();
if (admins.contains(id))
send(ABILITY_CLAIM_FAIL, ctx);
else {
admins.add(id);
send(ABILITY_CLAIM_SUCCESS, ctx);
}
})
.post(commitTo(db))
.build();
}
private Optional<Message> send(String message, MessageContext ctx, String... args) {
return silent.send(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId());
}
private Optional<Message> sendMd(String message, MessageContext ctx, String... args) {
return silent.sendMd(getLocalizedMessage(message, ctx.user().getLanguageCode(), args), ctx.chatId());
}
private Optional<Message> send(String message, Update upd) {
Long chatId = upd.getMessage().getChatId();
return silent.send(getLocalizedMessage(message, AbilityUtils.getUser(upd).getLanguageCode()), chatId);
}
/**
* Registers the declared abilities using method reflection. Also, replies are accumulated using the built abilities and standalone methods that return a Reply.
* <p>
* <b>Only abilities and replies with the <u>public</u> accessor are registered!</b>
*/
private void registerAbilities() {
try {
abilities = stream(this.getClass().getMethods())
.filter(method -> method.getReturnType().equals(Ability.class))
.map(this::returnAbility)
.collect(ImmutableMap::<String, Ability>builder,
(b, a) -> b.put(a.name(), a),
(b1, b2) -> b1.putAll(b2.build()))
.build();
Stream<Reply> methodReplies = stream(this.getClass().getMethods())
.filter(method -> method.getReturnType().equals(Reply.class))
.map(this::returnReply);
Stream<Reply> abilityReplies = abilities.values().stream()
.flatMap(ability -> ability.replies().stream());
replies = Stream.concat(methodReplies, abilityReplies).collect(
ImmutableList::<Reply>builder,
Builder::add,
(b1, b2) -> b1.addAll(b2.build()))
.build();
} catch (IllegalStateException e) {
BotLogger.error(TAG, "Duplicate names found while registering abilities. Make sure that the abilities declared don't clash with the reserved ones.", e);
throw propagate(e);
}
}
/**
* Invokes the method and retrieves its return {@link Ability}.
*
* @param method a method that returns an ability
* @return the ability returned by the method
*/
private Ability returnAbility(Method method) {
try {
return (Ability) method.invoke(this);
} catch (IllegalAccessException | InvocationTargetException e) {
BotLogger.error("Could not add ability", TAG, e);
throw propagate(e);
}
}
/**
* Invokes the method and retrieves its returned Reply.
*
* @param method a method that returns a reply
* @return the reply returned by the method
*/
private Reply returnReply(Method method) {
try {
return (Reply) method.invoke(this);
} catch (IllegalAccessException | InvocationTargetException e) {
BotLogger.error("Could not add reply", TAG, e);
throw propagate(e);
}
}
private void postConsumption(Pair<MessageContext, Ability> pair) {
ofNullable(pair.b().postAction())
.ifPresent(consumer -> consumer.accept(pair.a()));
}
Pair<MessageContext, Ability> consumeUpdate(Pair<MessageContext, Ability> pair) {
pair.b().action().accept(pair.a());
return pair;
}
Pair<MessageContext, Ability> getContext(Trio<Update, Ability, String[]> trio) {
Update update = trio.a();
User user = AbilityUtils.getUser(update);
return Pair.of(newContext(update, user, getChatId(update), trio.c()), trio.b());
}
boolean checkBlacklist(Update update) {
Integer id = AbilityUtils.getUser(update).getId();
return id == creatorId() || !blacklist().contains(id);
}
boolean checkInput(Trio<Update, Ability, String[]> trio) {
String[] tokens = trio.c();
int abilityTokens = trio.b().tokens();
boolean isOk = abilityTokens == 0 || (tokens.length > 0 && tokens.length == abilityTokens);
if (!isOk)
silent.send(
getLocalizedMessage(
CHECK_INPUT_FAIL,
AbilityUtils.getUser(trio.a()).getLanguageCode(),
abilityTokens, abilityTokens == 1 ? "input" : "inputs"),
getChatId(trio.a()));
return isOk;
}
boolean checkLocality(Trio<Update, Ability, String[]> trio) {
Update update = trio.a();
Locality locality = isUserMessage(update) ? USER : GROUP;
Locality abilityLocality = trio.b().locality();
boolean isOk = abilityLocality == ALL || locality == abilityLocality;
if (!isOk)
silent.send(
getLocalizedMessage(
CHECK_LOCALITY_FAIL,
AbilityUtils.getUser(trio.a()).getLanguageCode(),
abilityLocality.toString().toLowerCase()),
getChatId(trio.a()));
return isOk;
}
boolean checkPrivacy(Trio<Update, Ability, String[]> trio) {
Update update = trio.a();
User user = AbilityUtils.getUser(update);
Privacy privacy;
int id = user.getId();
privacy = getPrivacy(update, id);
boolean isOk = privacy.compareTo(trio.b().privacy()) >= 0;
if (!isOk)
silent.send(
getLocalizedMessage(
CHECK_PRIVACY_FAIL,
AbilityUtils.getUser(trio.a()).getLanguageCode()),
getChatId(trio.a()));
return isOk;
}
@NotNull
private Privacy getPrivacy(Update update, int id) {
return isCreator(id) ?
CREATOR : isAdmin(id) ?
ADMIN : (isGroupUpdate(update) || isSuperGroupUpdate(update)) && isGroupAdmin(update, id) ?
GROUP_ADMIN : PUBLIC;
}
private boolean isGroupAdmin(Update update, int id) {
GetChatAdministrators admins = new GetChatAdministrators().setChatId(getChatId(update));
return silent.execute(admins)
.orElse(new ArrayList<>()).stream()
.anyMatch(member -> member.getUser().getId() == id);
}
private boolean isCreator(int id) {
return id == creatorId();
}
private boolean isAdmin(Integer id) {
return admins().contains(id);
}
boolean validateAbility(Trio<Update, Ability, String[]> trio) {
return trio.b() != null;
}
Trio<Update, Ability, String[]> getAbility(Update update) {
// Handle updates without messages
// Passing through this function means that the global flags have passed
Message msg = update.getMessage();
if (!update.hasMessage() || !msg.hasText())
return Trio.of(update, abilities.get(DEFAULT), new String[]{});
String[] tokens = msg.getText().split(" ");
if (tokens[0].startsWith("/")) {
String abilityToken = stripBotUsername(tokens[0].substring(1)).toLowerCase();
Ability ability = abilities.get(abilityToken);
tokens = Arrays.copyOfRange(tokens, 1, tokens.length);
return Trio.of(update, ability, tokens);
} else {
Ability ability = abilities.get(DEFAULT);
return Trio.of(update, ability, tokens);
}
}
private String stripBotUsername(String token) {
return compile(format("@%s", botUsername), CASE_INSENSITIVE)
.matcher(token)
.replaceAll("");
}
Update addUser(Update update) {
User endUser = AbilityUtils.getUser(update);
users().compute(endUser.getId(), (id, user) -> {
if (user == null) {
updateUserId(user, endUser);
return endUser;
}
if (!user.equals(endUser)) {
updateUserId(user, endUser);
return endUser;
}
return user;
});
db.commit();
return update;
}
private void updateUserId(User oldUser, User newUser) {
if (oldUser != null && oldUser.getUserName() != null) {
// Remove old username -> ID
userIds().remove(oldUser.getUserName());
}
if (newUser.getUserName() != null) {
// Add new mapping with the new username
userIds().put(newUser.getUserName().toLowerCase(), newUser.getId());
}
}
boolean filterReply(Update update) {
return replies.stream()
.filter(reply -> reply.isOkFor(update))
.map(reply -> {
reply.actOn(update);
return false;
})
.reduce(true, Boolean::logicalAnd);
}
boolean checkMessageFlags(Trio<Update, Ability, String[]> trio) {
Ability ability = trio.b();
Update update = trio.a();
// The following variable is required to avoid bug #JDK-8044546
BiFunction<Boolean, Predicate<Update>, Boolean> flagAnd = (flag, nextFlag) -> flag && nextFlag.test(update);
return ability.flags().stream()
.reduce(true, flagAnd, Boolean::logicalAnd);
}
private File downloadFileWithId(String fileId) throws TelegramApiException {
return sender.downloadFile(sender.execute(new GetFile().setFileId(fileId)));
}
private String escape(String username) {
return username.replace("_", "\\_");
}
}

View File

@ -1,7 +1,7 @@
package org.telegram.abilitybots.api.db;
import org.telegram.abilitybots.api.bot.AbilityBot;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.io.Closeable;
import java.util.List;
@ -12,7 +12,7 @@ import java.util.Set;
* This interface represents the high-level methods exposed to the user when handling an {@link Update}.
* Example usage:
* <p><code>Ability.builder().action(ctx -> {db.getSet(USERS); doSomething();})* </code></p>
* {@link AbilityBot} contains a handle on the <code>db</code> that the user can use inside his declared abilities.
* {@link BaseAbilityBot} contains a handle on the <code>db</code> that the user can use inside his declared abilities.
*
* @author Abbas Abou Daya
*/
@ -39,6 +39,13 @@ public interface DBContext extends Closeable {
*/
<T> Set<T> getSet(String name);
/**
* @param name the unique name of the {@link Var}
* @param <T> the type that the variable holds
* @return the variable with the specified name
*/
<T> Var<T> getVar(String name);
/**
* @return a high-level summary of the database structures (Sets, Lists, Maps, ...) present.
*/

View File

@ -3,11 +3,12 @@ package org.telegram.abilitybots.api.db;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.mapdb.Atomic;
import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.mapdb.Serializer;
import org.telegram.abilitybots.api.util.Pair;
import org.telegram.telegrambots.logging.BotLogger;
import org.telegram.telegrambots.meta.logging.BotLogger;
import java.io.IOException;
import java.util.*;
@ -20,7 +21,7 @@ import static java.util.Objects.isNull;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.StreamSupport.stream;
import static org.mapdb.Serializer.JAVA;
import static org.telegram.abilitybots.api.bot.AbilityBot.USERS;
import static org.telegram.abilitybots.api.bot.BaseAbilityBot.USERS;
/**
* An implementation of {@link DBContext} that relies on a {@link DB}.
@ -28,7 +29,7 @@ import static org.telegram.abilitybots.api.bot.AbilityBot.USERS;
* @author Abbas Abou Daya
* @see <a href="https://github.com/jankotek/mapdb">MapDB project</a>
*/
@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "WeakerAccess"})
public class MapDBContext implements DBContext {
private static final String TAG = DBContext.class.getSimpleName();
@ -93,6 +94,11 @@ public class MapDBContext implements DBContext {
return (Set<T>) db.<T>hashSet(name, JAVA).createOrOpen();
}
@Override
public <T> Var<T> getVar(String name) {
return new MapDBVar<>((Atomic.Var<T>) db.atomicVar(name).createOrOpen());
}
@Override
public String summary() {
return stream(db.getAllNames().spliterator(), false)
@ -163,7 +169,7 @@ public class MapDBContext implements DBContext {
}
@Override
public void close() throws IOException {
public void close() {
db.close();
}

View File

@ -0,0 +1,49 @@
package org.telegram.abilitybots.api.db;
import com.google.common.base.MoreObjects;
import org.mapdb.Atomic;
import java.util.Objects;
/**
* The MapDB variant for {@link DBContext#getVar(String)}.
*
* @param <T> the type of the inner variable
*/
public final class MapDBVar<T> implements Var<T> {
private Atomic.Var<T> var;
public MapDBVar(Atomic.Var<T> var) {
this.var = var;
}
@Override
public T get() {
return var.get();
}
@Override
public void set(T var) {
this.var.set(var);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MapDBVar<?> mapDBVar = (MapDBVar<?>) o;
return Objects.equals(var, mapDBVar.var);
}
@Override
public int hashCode() {
return Objects.hash(var);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("var", var)
.toString();
}
}

View File

@ -0,0 +1,19 @@
package org.telegram.abilitybots.api.db;
/**
* The interface governing a variable for abstract getters and setters.
* @param <T> the type of the variable
*
* @author Abbas Abou Daya
*/
public interface Var<T> {
/**
* @return the variable contained
*/
T get();
/**
* @param var the new variable value
*/
void set(T var);
}

View File

@ -2,8 +2,8 @@ package org.telegram.abilitybots.api.objects;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.logging.BotLogger;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.logging.BotLogger;
import java.util.Arrays;
import java.util.List;

View File

@ -1,138 +0,0 @@
package org.telegram.abilitybots.api.objects;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.MoreObjects;
import org.telegram.telegrambots.api.objects.User;
import java.io.Serializable;
import java.util.Objects;
import java.util.StringJoiner;
import static org.apache.commons.lang3.StringUtils.isEmpty;
/**
* This class serves the purpose of separating the basic Telegram {@link User} and the augmented {@link EndUser}.
* <p>
* It adds proper hashCode, equals, toString as well as useful utility methods such as {@link EndUser#shortName} and {@link EndUser#fullName}.
*
* @author Abbas Abou Daya
*/
public final class EndUser implements Serializable {
@JsonProperty("id")
private final Integer id;
@JsonProperty("firstName")
private final String firstName;
@JsonProperty("lastName")
private final String lastName;
@JsonProperty("username")
private final String username;
private EndUser(Integer id, String firstName, String lastName, String username) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.username = username;
}
@JsonCreator
public static EndUser endUser(@JsonProperty("id") Integer id,
@JsonProperty("firstName") String firstName,
@JsonProperty("lastName") String lastName,
@JsonProperty("username") String username) {
return new EndUser(id, firstName, lastName, username);
}
/**
* Constructs an {@link EndUser} from a {@link User}.
*
* @param user the Telegram user
* @return an augmented end-user
*/
public static EndUser fromUser(User user) {
return new EndUser(user.getId(), user.getFirstName(), user.getLastName(), user.getUserName());
}
public int id() {
return id;
}
public String firstName() {
return firstName;
}
public String lastName() {
return lastName;
}
public String username() {
return username;
}
/**
* The full name is identified as the concatenation of the first and last name, separated by a space.
* This method can return an empty name if both first and last name are empty.
*
* @return the full name of the user
*/
public String fullName() {
StringJoiner name = new StringJoiner(" ");
if (!isEmpty(firstName))
name.add(firstName);
if (!isEmpty(lastName))
name.add(lastName);
return name.toString();
}
/**
* The short name is one of the following:
* <ol>
* <li>First name</li>
* <li>Last name</li>
* <li>Username</li>
* </ol>
* The method will try to return the first valid name in the specified order.
*
* @return the short name of the user
*/
public String shortName() {
if (!isEmpty(firstName))
return firstName;
if (!isEmpty(lastName))
return lastName;
return username;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
EndUser endUser = (EndUser) o;
return Objects.equals(id, endUser.id) &&
Objects.equals(firstName, endUser.firstName) &&
Objects.equals(lastName, endUser.lastName) &&
Objects.equals(username, endUser.username);
}
@Override
public int hashCode() {
return Objects.hash(id, firstName, lastName, username);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("id", id)
.add("firstName", firstName)
.add("lastName", lastName)
.add("username", username)
.toString();
}
}

View File

@ -1,7 +1,7 @@
package org.telegram.abilitybots.api.objects;
import org.telegram.abilitybots.api.objects.Ability.AbilityBuilder;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.function.Consumer;
import java.util.function.Predicate;
@ -11,7 +11,7 @@ import static java.util.Objects.nonNull;
/**
* Flags are an conditions that are applied on an {@link Update}.
* <p>
* They can be used on {@link AbilityBuilder#flag(Flag...)} and on the post conditions in {@link AbilityBuilder#reply(Consumer, Predicate[])}.
* They can be used on {@link AbilityBuilder#flag(Predicate[])} and on the post conditions in {@link AbilityBuilder#reply(Consumer, Predicate[])}.
*
* @author Abbas Abou Daya
*/

View File

@ -2,7 +2,8 @@ package org.telegram.abilitybots.api.objects;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.User;
import java.util.Arrays;
@ -14,26 +15,26 @@ import java.util.Arrays;
* @author Abbas Abou Daya
*/
public class MessageContext {
private final EndUser user;
private final User user;
private final Long chatId;
private final String[] arguments;
private final Update update;
private MessageContext(Update update, EndUser user, Long chatId, String[] arguments) {
private MessageContext(Update update, User user, Long chatId, String[] arguments) {
this.user = user;
this.chatId = chatId;
this.update = update;
this.arguments = arguments;
}
public static MessageContext newContext(Update update, EndUser user, Long chatId, String... arguments) {
public static MessageContext newContext(Update update, User user, Long chatId, String... arguments) {
return new MessageContext(update, user, chatId, arguments);
}
/**
* @return the originating Telegram user of this update
*/
public EndUser user() {
public User user() {
return user;
}

View File

@ -1,7 +1,7 @@
package org.telegram.abilitybots.api.objects;
import com.google.common.base.MoreObjects;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.List;
import java.util.Objects;
@ -14,7 +14,7 @@ import static java.util.Arrays.asList;
/**
* A reply consists of update conditionals and an action to be applied on the update.
* <p>
* If an update satisfies the {@link Reply#conditions}set by the reply, then it's safe to {@link Reply#actOn(Update)}.
* If an update satisfies the {@link Reply#conditions} set by the reply, then it's safe to {@link Reply#actOn(Update)}.
*
* @author Abbas Abou Daya
*/

View File

@ -1,19 +1,19 @@
package org.telegram.abilitybots.api.sender;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.methods.groupadministration.SetChatPhoto;
import org.telegram.telegrambots.api.methods.send.*;
import org.telegram.telegrambots.api.methods.stickers.AddStickerToSet;
import org.telegram.telegrambots.api.methods.stickers.CreateNewStickerSet;
import org.telegram.telegrambots.api.methods.stickers.UploadStickerFile;
import org.telegram.telegrambots.api.objects.File;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.User;
import org.telegram.telegrambots.api.objects.WebhookInfo;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.groupadministration.SetChatPhoto;
import org.telegram.telegrambots.meta.api.methods.send.*;
import org.telegram.telegrambots.meta.api.methods.stickers.AddStickerToSet;
import org.telegram.telegrambots.meta.api.methods.stickers.CreateNewStickerSet;
import org.telegram.telegrambots.meta.api.methods.stickers.UploadStickerFile;
import org.telegram.telegrambots.meta.api.objects.File;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.api.objects.WebhookInfo;
import org.telegram.telegrambots.bots.DefaultAbsSender;
import org.telegram.telegrambots.exceptions.TelegramApiException;
import org.telegram.telegrambots.updateshandlers.DownloadFileCallback;
import org.telegram.telegrambots.updateshandlers.SentCallback;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback;
import org.telegram.telegrambots.meta.updateshandlers.SentCallback;
import java.io.Serializable;
@ -43,22 +43,22 @@ public class DefaultSender implements MessageSender {
@Override
public Boolean addStickerToSet(AddStickerToSet addStickerToSet) throws TelegramApiException {
return bot.addStickerToSet(addStickerToSet);
return bot.execute(addStickerToSet);
}
@Override
public Boolean createNewStickerSet(CreateNewStickerSet createNewStickerSet) throws TelegramApiException {
return bot.createNewStickerSet(createNewStickerSet);
return bot.execute(createNewStickerSet);
}
@Override
public File uploadStickerFile(UploadStickerFile uploadStickerFile) throws TelegramApiException {
return bot.uploadStickerFile(uploadStickerFile);
return bot.execute(uploadStickerFile);
}
@Override
public Boolean setChatPhoto(SetChatPhoto setChatPhoto) throws TelegramApiException {
return bot.setChatPhoto(setChatPhoto);
return bot.execute(setChatPhoto);
}
@Override
@ -104,36 +104,36 @@ public class DefaultSender implements MessageSender {
@Override
public Message sendDocument(SendDocument sendDocument) throws TelegramApiException {
return bot.sendDocument(sendDocument);
return bot.execute(sendDocument);
}
@Override
public Message sendPhoto(SendPhoto sendPhoto) throws TelegramApiException {
return bot.sendPhoto(sendPhoto);
return bot.execute(sendPhoto);
}
@Override
public Message sendVideo(SendVideo sendVideo) throws TelegramApiException {
return bot.sendVideo(sendVideo);
return bot.execute(sendVideo);
}
@Override
public Message sendSticker(SendSticker sendSticker) throws TelegramApiException {
return bot.sendSticker(sendSticker);
return bot.execute(sendSticker);
}
@Override
public Message sendAudio(SendAudio sendAudio) throws TelegramApiException {
return bot.sendAudio(sendAudio);
return bot.execute(sendAudio);
}
@Override
public Message sendVoice(SendVoice sendVoice) throws TelegramApiException {
return bot.sendVoice(sendVoice);
return bot.execute(sendVoice);
}
@Override
public Message sendVideoNote(SendVideoNote sendVideoNote) throws TelegramApiException {
public Message sendVideoNote(SendVideoNote sendVideoNote) {
return null;
}
}

View File

@ -1,19 +1,19 @@
package org.telegram.abilitybots.api.sender;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.methods.groupadministration.SetChatPhoto;
import org.telegram.telegrambots.api.methods.send.*;
import org.telegram.telegrambots.api.methods.stickers.AddStickerToSet;
import org.telegram.telegrambots.api.methods.stickers.CreateNewStickerSet;
import org.telegram.telegrambots.api.methods.stickers.UploadStickerFile;
import org.telegram.telegrambots.api.objects.File;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.User;
import org.telegram.telegrambots.api.objects.WebhookInfo;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.groupadministration.SetChatPhoto;
import org.telegram.telegrambots.meta.api.methods.send.*;
import org.telegram.telegrambots.meta.api.methods.stickers.AddStickerToSet;
import org.telegram.telegrambots.meta.api.methods.stickers.CreateNewStickerSet;
import org.telegram.telegrambots.meta.api.methods.stickers.UploadStickerFile;
import org.telegram.telegrambots.meta.api.objects.File;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.api.objects.WebhookInfo;
import org.telegram.telegrambots.bots.DefaultAbsSender;
import org.telegram.telegrambots.exceptions.TelegramApiException;
import org.telegram.telegrambots.updateshandlers.DownloadFileCallback;
import org.telegram.telegrambots.updateshandlers.SentCallback;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback;
import org.telegram.telegrambots.meta.updateshandlers.SentCallback;
import java.io.Serializable;

View File

@ -1,11 +1,11 @@
package org.telegram.abilitybots.api.sender;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.methods.send.SendMessage;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.replykeyboard.ForceReplyKeyboard;
import org.telegram.telegrambots.exceptions.TelegramApiException;
import org.telegram.telegrambots.logging.BotLogger;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ForceReplyKeyboard;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.logging.BotLogger;
import java.io.Serializable;
import java.util.Optional;

View File

@ -0,0 +1,31 @@
package org.telegram.abilitybots.api.util;
public final class AbilityMessageCodes {
public static String USER_NOT_FOUND = "userNotFound";
public static String CHECK_INPUT_FAIL = "checkInput.fail";
public static String CHECK_LOCALITY_FAIL = "checkLocality.fail";
public static String CHECK_PRIVACY_FAIL = "checkPrivacy.fail";
public static String ABILITY_COMMANDS_NOT_FOUND = "ability.commands.notFound";
public static String ABILITY_RECOVER_SUCCESS = "ability.recover.success";
public static String ABILITY_RECOVER_FAIL = "ability.recover.fail";
public static String ABILITY_RECOVER_MESSAGE = "ability.recover.message";
public static String ABILITY_RECOVER_ERROR = "ability.recover.error";
public static String ABILITY_BAN_SUCCESS = "ability.ban.success";
public static String ABILITY_BAN_FAIL = "ability.ban.fail";
public static String ABILITY_UNBAN_SUCCESS = "ability.unban.success";
public static String ABILITY_UNBAN_FAIL = "ability.unban.fail";
public static String ABILITY_PROMOTE_SUCCESS = "ability.promote.success";
public static String ABILITY_PROMOTE_FAIL = "ability.promote.fail";
public static String ABILITY_DEMOTE_SUCCESS = "ability.demote.success";
public static String ABILITY_DEMOTE_FAIL = "ability.demote.fail";
public static String ABILITY_CLAIM_SUCCESS = "ability.claim.success";
public static String ABILITY_CLAIM_FAIL = "ability.claim.fail";
}

View File

@ -1,13 +1,23 @@
package org.telegram.abilitybots.api.util;
import com.google.common.base.Strings;
import org.telegram.abilitybots.api.db.DBContext;
import org.telegram.abilitybots.api.objects.MessageContext;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.api.objects.User;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.User;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.StringJoiner;
import java.util.function.Consumer;
import java.util.function.Predicate;
import static java.util.ResourceBundle.Control.FORMAT_PROPERTIES;
import static java.util.ResourceBundle.Control.getNoFallbackControl;
import static java.util.ResourceBundle.getBundle;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.telegram.abilitybots.api.objects.Flag.*;
/**
@ -86,6 +96,28 @@ public final class AbilityUtils {
}
}
/**
* A "best-effort" boolean stating whether the update is a super-group message or not.
*
* @param update a Telegram {@link Update}
* @return whether the update is linked to a group
*/
public static boolean isSuperGroupUpdate(Update update) {
if (MESSAGE.test(update)) {
return update.getMessage().isSuperGroupMessage();
} else if (CALLBACK_QUERY.test(update)) {
return update.getCallbackQuery().getMessage().isSuperGroupMessage();
} else if (CHANNEL_POST.test(update)) {
return update.getChannelPost().isSuperGroupMessage();
} else if (EDITED_CHANNEL_POST.test(update)) {
return update.getEditedChannelPost().isSuperGroupMessage();
} else if (EDITED_MESSAGE.test(update)) {
return update.getEditedMessage().isSuperGroupMessage();
} else {
return false;
}
}
/**
* Fetches the direct chat ID of the specified update.
*
@ -150,4 +182,66 @@ public final class AbilityUtils {
public static Predicate<Update> isReplyTo(String msg) {
return update -> update.getMessage().getReplyToMessage().getText().equals(msg);
}
}
public static String getLocalizedMessage(String messageCode, Locale locale, Object...arguments) {
ResourceBundle bundle;
if (locale == null) {
bundle = getBundle("messages", Locale.ROOT);
} else {
try {
bundle = getBundle(
"messages",
locale,
getNoFallbackControl(FORMAT_PROPERTIES));
} catch (MissingResourceException e) {
bundle = getBundle("messages", Locale.ROOT);
}
}
String message = bundle.getString(messageCode);
return MessageFormat.format(message, arguments);
}
public static String getLocalizedMessage(String messageCode, String languageCode, Object...arguments){
Locale locale = Strings.isNullOrEmpty(languageCode) ? null : Locale.forLanguageTag(languageCode);
return getLocalizedMessage(messageCode, locale, arguments);
}
/**
* The short name is one of the following:
* <ol>
* <li>First name</li>
* <li>Last name</li>
* <li>Username</li>
* </ol>
* The method will try to return the first valid name in the specified order.
*
* @return the short name of the user
*/
public static String shortName(User user) {
if (!isEmpty(user.getFirstName()))
return user.getFirstName();
if (!isEmpty(user.getLastName()))
return user.getLastName();
return user.getUserName();
}
/**
* The full name is identified as the concatenation of the first and last name, separated by a space.
* This method can return an empty name if both first and last name are empty.
*
* @return the full name of the user
* @param user
*/
public static String fullName(User user) {
StringJoiner name = new StringJoiner(" ");
if (!isEmpty(user.getFirstName()))
name.add(user.getFirstName());
if (!isEmpty(user.getLastName()))
name.add(user.getLastName());
return name.toString();
}
}

View File

@ -0,0 +1,27 @@
ability.commands.notFound=No available commands found.
ability.recover.success=I have successfully recovered.
ability.recover.fail=Oops, something went wrong during recovery.
ability.recover.message=I am ready to receive the backup file. Please reply to this message with the backup file attached.
ability.recover.error=I have failed to recover.
ability.ban.success={0} is now *banned*.
ability.ban.fail={0} is already *banned*.
ability.unban.success=@{0}, your ban has been *lifted*.
ability.unban.fail=@{0} is *not* on the *blacklist*.
ability.promote.success=@{0} has been *promoted*.
ability.promote.fail=@{0} is already an *admin*.
ability.demote.success=@{0} has been *demoted*.
ability.demote.fail=@{0} is *not* an *admin*.
ability.claim.success=You''re now my master.
ability.claim.fail=You''re already my master.
checkInput.fail=Sorry, this feature requires {0,number,integer} additional {1}.
checkLocality.fail=Sorry, {0}-only feature.
checkPrivacy.fail=Sorry, you don''t have the required access level to do that.
userNotFound=Sorry, I could not find the user [{0}].

View File

@ -0,0 +1,81 @@
package org.telegram.abilitybots.api.bot;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.telegram.abilitybots.api.db.DBContext;
import org.telegram.abilitybots.api.objects.MessageContext;
import org.telegram.abilitybots.api.sender.MessageSender;
import org.telegram.abilitybots.api.sender.SilentSender;
import org.telegram.telegrambots.meta.api.objects.User;
import java.io.IOException;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import static org.telegram.abilitybots.api.bot.AbilityBotTest.mockContext;
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
public class AbilityBotI18nTest {
private static final User NO_LANGUAGE_USER = new User(1, "first", false, "last", "username", null);
private static final User ITALIAN_USER = new User(2, "first", false, "last", "username", "it-IT");
private DBContext db;
private NoPublicCommandsBot bot;
private MessageSender sender;
private SilentSender silent;
@Before
public void setUp() {
db = offlineInstance("db");
bot = new NoPublicCommandsBot(EMPTY, EMPTY, db);
sender = mock(MessageSender.class);
silent = mock(SilentSender.class);
bot.sender = sender;
bot.silent = silent;
}
@Test
public void missingPublicCommandsLocalizedInEnglishByDefault() {
MessageContext context = mockContext(NO_LANGUAGE_USER);
bot.reportCommands().action().accept(context);
verify(silent, times(1))
.send("No available commands found.", NO_LANGUAGE_USER.getId());
}
@Test
public void missingPublicCommandsLocalizedInItalian() {
MessageContext context = mockContext(ITALIAN_USER);
bot.reportCommands().action().accept(context);
verify(silent, times(1))
.send("Non sono presenti comandi disponibile.", ITALIAN_USER.getId());
}
@After
public void tearDown() throws IOException {
db.clear();
db.close();
}
public static class NoPublicCommandsBot extends AbilityBot {
protected NoPublicCommandsBot(String botToken, String botUsername, DBContext db) {
super(botToken, botUsername, db);
}
@Override
public int creatorId() {
return 1;
}
}
}

View File

@ -12,9 +12,9 @@ import org.telegram.abilitybots.api.sender.MessageSender;
import org.telegram.abilitybots.api.sender.SilentSender;
import org.telegram.abilitybots.api.util.Pair;
import org.telegram.abilitybots.api.util.Trio;
import org.telegram.telegrambots.api.methods.groupadministration.GetChatAdministrators;
import org.telegram.telegrambots.api.objects.*;
import org.telegram.telegrambots.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators;
import org.telegram.telegrambots.meta.api.objects.*;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.io.BufferedWriter;
import java.io.IOException;
@ -36,11 +36,8 @@ import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import static org.telegram.abilitybots.api.bot.AbilityBot.RECOVERY_MESSAGE;
import static org.telegram.abilitybots.api.bot.AbilityBot.RECOVER_SUCCESS;
import static org.telegram.abilitybots.api.bot.DefaultBot.getDefaultBuilder;
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
import static org.telegram.abilitybots.api.objects.EndUser.endUser;
import static org.telegram.abilitybots.api.objects.Flag.DOCUMENT;
import static org.telegram.abilitybots.api.objects.Flag.MESSAGE;
import static org.telegram.abilitybots.api.objects.Locality.ALL;
@ -49,12 +46,16 @@ import static org.telegram.abilitybots.api.objects.MessageContext.newContext;
import static org.telegram.abilitybots.api.objects.Privacy.*;
public class AbilityBotTest {
// Messages
private static final String RECOVERY_MESSAGE = "I am ready to receive the backup file. Please reply to this message with the backup file attached.";
private static final String RECOVER_SUCCESS = "I have successfully recovered.";
private static final String[] EMPTY_ARRAY = {};
private static final long GROUP_ID = 10L;
private static final String TEST = "test";
private static final String[] TEXT = {TEST};
public static final EndUser MUSER = endUser(1, "first", "last", "username");
public static final EndUser CREATOR = endUser(1337, "creatorFirst", "creatorLast", "creatorUsername");
public static final User USER = new User(1, "first", false, "last", "username", null);
public static final User CREATOR = new User(1337, "creatorFirst", false, "creatorLast", "creatorUsername", null);
private DefaultBot bot;
private DBContext db;
@ -75,39 +76,39 @@ public class AbilityBotTest {
@Test
public void sendsPrivacyViolation() {
Update update = mockFullUpdate(MUSER, "/admin");
Update update = mockFullUpdate(USER, "/admin");
bot.onUpdateReceived(update);
verify(silent, times(1)).send("Sorry, you don't have the required access level to do that.", MUSER.id());
verify(silent, times(1)).send("Sorry, you don't have the required access level to do that.", USER.getId());
}
@Test
public void sendsLocalityViolation() {
Update update = mockFullUpdate(MUSER, "/group");
Update update = mockFullUpdate(USER, "/group");
bot.onUpdateReceived(update);
verify(silent, times(1)).send(format("Sorry, %s-only feature.", "group"), MUSER.id());
verify(silent, times(1)).send(format("Sorry, %s-only feature.", "group"), USER.getId());
}
@Test
public void sendsInputArgsViolation() {
Update update = mockFullUpdate(MUSER, "/count 1 2 3");
Update update = mockFullUpdate(USER, "/count 1 2 3");
bot.onUpdateReceived(update);
verify(silent, times(1)).send(format("Sorry, this feature requires %d additional inputs.", 4), MUSER.id());
verify(silent, times(1)).send(format("Sorry, this feature requires %d additional inputs.", 4), USER.getId());
}
@Test
public void canProcessRepliesIfSatisfyRequirements() {
Update update = mockFullUpdate(MUSER, "must reply");
Update update = mockFullUpdate(USER, "must reply");
// False means the update was not pushed down the stream since it has been consumed by the reply
assertFalse(bot.filterReply(update));
verify(silent, times(1)).send("reply", MUSER.id());
verify(silent, times(1)).send("reply", USER.getId());
}
@Test
@ -144,8 +145,8 @@ public class AbilityBotTest {
@Test
public void canDemote() {
addUsers(MUSER);
bot.admins().add(MUSER.id());
addUsers(USER);
bot.admins().add(USER.getId());
MessageContext context = defaultContext();
@ -158,33 +159,33 @@ public class AbilityBotTest {
@Test
public void canPromote() {
addUsers(MUSER);
addUsers(USER);
MessageContext context = defaultContext();
bot.promoteAdmin().action().accept(context);
Set<Integer> actual = bot.admins();
Set<Integer> expected = newHashSet(MUSER.id());
Set<Integer> expected = newHashSet(USER.getId());
assertEquals("Could not sudo user", expected, actual);
}
@Test
public void canBanUser() {
addUsers(MUSER);
addUsers(USER);
MessageContext context = defaultContext();
bot.banUser().action().accept(context);
Set<Integer> actual = bot.blacklist();
Set<Integer> expected = newHashSet(MUSER.id());
Set<Integer> expected = newHashSet(USER.getId());
assertEquals("The ban was not emplaced", expected, actual);
}
@Test
public void canUnbanUser() {
addUsers(MUSER);
bot.blacklist().add(MUSER.id());
addUsers(USER);
bot.blacklist().add(USER.getId());
MessageContext context = defaultContext();
@ -197,65 +198,42 @@ public class AbilityBotTest {
@NotNull
private MessageContext defaultContext() {
MessageContext context = mock(MessageContext.class);
when(context.user()).thenReturn(CREATOR);
when(context.firstArg()).thenReturn(MUSER.username());
return context;
return mockContext(CREATOR, GROUP_ID, USER.getUserName());
}
@Test
public void cannotBanCreator() {
addUsers(MUSER, CREATOR);
MessageContext context = mock(MessageContext.class);
when(context.user()).thenReturn(MUSER);
when(context.firstArg()).thenReturn(CREATOR.username());
addUsers(USER, CREATOR);
MessageContext context = mockContext(USER, GROUP_ID, CREATOR.getUserName());
bot.banUser().action().accept(context);
Set<Integer> actual = bot.blacklist();
Set<Integer> expected = newHashSet(MUSER.id());
Set<Integer> expected = newHashSet(USER.getId());
assertEquals("Impostor was not added to the blacklist", expected, actual);
}
private void addUsers(EndUser... users) {
private void addUsers(User... users) {
Arrays.stream(users).forEach(user -> {
bot.users().put(user.id(), user);
bot.userIds().put(user.username().toLowerCase(), user.id());
bot.users().put(user.getId(), user);
bot.userIds().put(user.getUserName().toLowerCase(), user.getId());
});
}
@Test
public void creatorCanClaimBot() {
MessageContext context = mock(MessageContext.class);
when(context.user()).thenReturn(CREATOR);
MessageContext context = mockContext(CREATOR, GROUP_ID);
bot.claimCreator().action().accept(context);
Set<Integer> actual = bot.admins();
Set<Integer> expected = newHashSet(CREATOR.id());
Set<Integer> expected = newHashSet(CREATOR.getId());
assertEquals("Creator was not properly added to the super admins set", expected, actual);
}
@Test
public void userGetsBannedIfClaimsBot() {
addUsers(MUSER);
MessageContext context = mock(MessageContext.class);
when(context.user()).thenReturn(MUSER);
bot.claimCreator().action().accept(context);
Set<Integer> actual = bot.blacklist();
Set<Integer> expected = newHashSet(MUSER.id());
assertEquals("Could not find user on the blacklist", expected, actual);
actual = bot.admins();
expected = emptySet();
assertEquals("Admins set is not empty", expected, actual);
}
@Test
public void bannedCreatorPassesBlacklistCheck() {
bot.blacklist().add(CREATOR.id());
bot.blacklist().add(CREATOR.getId());
Update update = mock(Update.class);
Message message = mock(Message.class);
User user = mock(User.class);
@ -270,37 +248,35 @@ public class AbilityBotTest {
public void canAddUser() {
Update update = mock(Update.class);
Message message = mock(Message.class);
User user = mock(User.class);
mockAlternateUser(update, message, user, MUSER);
mockAlternateUser(update, message, USER);
bot.addUser(update);
Map<String, Integer> expectedUserIds = ImmutableMap.of(MUSER.username(), MUSER.id());
Map<Integer, EndUser> expectedUsers = ImmutableMap.of(MUSER.id(), MUSER);
Map<String, Integer> expectedUserIds = ImmutableMap.of(USER.getUserName(), USER.getId());
Map<Integer, User> expectedUsers = ImmutableMap.of(USER.getId(), USER);
assertEquals("User was not added", expectedUserIds, bot.userIds());
assertEquals("User was not added", expectedUsers, bot.users());
}
@Test
public void canEditUser() {
addUsers(MUSER);
addUsers(USER);
Update update = mock(Update.class);
Message message = mock(Message.class);
User user = mock(User.class);
String newUsername = MUSER.username() + "-test";
String newFirstName = MUSER.firstName() + "-test";
String newLastName = MUSER.lastName() + "-test";
int sameId = MUSER.id();
EndUser changedUser = endUser(sameId, newFirstName, newLastName, newUsername);
String newUsername = USER.getUserName() + "-test";
String newFirstName = USER.getFirstName() + "-test";
String newLastName = USER.getLastName() + "-test";
int sameId = USER.getId();
User changedUser = new User(sameId, newFirstName, false, newLastName, newUsername, null);
mockAlternateUser(update, message, user, changedUser);
mockAlternateUser(update, message, changedUser);
bot.addUser(update);
Map<String, Integer> expectedUserIds = ImmutableMap.of(changedUser.username(), changedUser.id());
Map<Integer, EndUser> expectedUsers = ImmutableMap.of(changedUser.id(), changedUser);
Map<String, Integer> expectedUserIds = ImmutableMap.of(changedUser.getUserName(), changedUser.getId());
Map<Integer, User> expectedUsers = ImmutableMap.of(changedUser.getId(), changedUser);
assertEquals("User was not properly edited", bot.userIds(), expectedUserIds);
assertEquals("User was not properly edited", expectedUsers, expectedUsers);
}
@ -311,13 +287,13 @@ public class AbilityBotTest {
Ability validAbility = getDefaultBuilder().build();
Trio<Update, Ability, String[]> validPair = Trio.of(null, validAbility, null);
assertEquals("Bot can't validate ability properly", false, bot.validateAbility(invalidPair));
assertEquals("Bot can't validate ability properly", true, bot.validateAbility(validPair));
assertFalse("Bot can't validate ability properly", bot.validateAbility(invalidPair));
assertTrue("Bot can't validate ability properly", bot.validateAbility(validPair));
}
@Test
public void canCheckInput() {
Update update = mockFullUpdate(MUSER, "/something");
Update update = mockFullUpdate(USER, "/something");
Ability abilityWithOneInput = getDefaultBuilder()
.build();
Ability abilityWithZeroInput = getDefaultBuilder()
@ -327,22 +303,22 @@ public class AbilityBotTest {
Trio<Update, Ability, String[]> trioOneArg = Trio.of(update, abilityWithOneInput, TEXT);
Trio<Update, Ability, String[]> trioZeroArg = Trio.of(update, abilityWithZeroInput, TEXT);
assertEquals("Unexpected result when applying token filter", true, bot.checkInput(trioOneArg));
assertTrue("Unexpected result when applying token filter", bot.checkInput(trioOneArg));
trioOneArg = Trio.of(update, abilityWithOneInput, addAll(TEXT, TEXT));
assertEquals("Unexpected result when applying token filter", false, bot.checkInput(trioOneArg));
assertFalse("Unexpected result when applying token filter", bot.checkInput(trioOneArg));
assertEquals("Unexpected result when applying token filter", true, bot.checkInput(trioZeroArg));
assertTrue("Unexpected result when applying token filter", bot.checkInput(trioZeroArg));
trioZeroArg = Trio.of(update, abilityWithZeroInput, EMPTY_ARRAY);
assertEquals("Unexpected result when applying token filter", true, bot.checkInput(trioZeroArg));
assertTrue("Unexpected result when applying token filter", bot.checkInput(trioZeroArg));
}
@Test
public void canCheckPrivacy() {
Update update = mock(Update.class);
Message message = mock(Message.class);
org.telegram.telegrambots.api.objects.User user = mock(User.class);
User user = mock(User.class);
Ability publicAbility = getDefaultBuilder().privacy(PUBLIC).build();
Ability groupAdminAbility = getDefaultBuilder().privacy(GROUP_ADMIN).build();
Ability adminAbility = getDefaultBuilder().privacy(ADMIN).build();
@ -355,17 +331,17 @@ public class AbilityBotTest {
mockUser(update, message, user);
assertEquals("Unexpected result when checking for privacy", true, bot.checkPrivacy(publicTrio));
assertEquals("Unexpected result when checking for privacy", false, bot.checkPrivacy(groupAdminTrio));
assertEquals("Unexpected result when checking for privacy", false, bot.checkPrivacy(adminTrio));
assertEquals("Unexpected result when checking for privacy", false, bot.checkPrivacy(creatorTrio));
assertTrue("Unexpected result when checking for privacy", bot.checkPrivacy(publicTrio));
assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(groupAdminTrio));
assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(adminTrio));
assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(creatorTrio));
}
@Test
public void canValidateGroupAdminPrivacy() throws TelegramApiException {
public void canValidateGroupAdminPrivacy() {
Update update = mock(Update.class);
Message message = mock(Message.class);
org.telegram.telegrambots.api.objects.User user = mock(User.class);
User user = mock(User.class);
Ability groupAdminAbility = getDefaultBuilder().privacy(GROUP_ADMIN).build();
Trio<Update, Ability, String[]> groupAdminTrio = Trio.of(update, groupAdminAbility, TEXT);
@ -379,14 +355,14 @@ public class AbilityBotTest {
when(silent.execute(any(GetChatAdministrators.class))).thenReturn(Optional.of(newArrayList(member)));
assertEquals("Unexpected result when checking for privacy", true, bot.checkPrivacy(groupAdminTrio));
assertTrue("Unexpected result when checking for privacy", bot.checkPrivacy(groupAdminTrio));
}
@Test
public void canRestrictNormalUsersFromGroupAdminAbilities() throws TelegramApiException {
public void canRestrictNormalUsersFromGroupAdminAbilities() {
Update update = mock(Update.class);
Message message = mock(Message.class);
org.telegram.telegrambots.api.objects.User user = mock(User.class);
User user = mock(User.class);
Ability groupAdminAbility = getDefaultBuilder().privacy(GROUP_ADMIN).build();
Trio<Update, Ability, String[]> groupAdminTrio = Trio.of(update, groupAdminAbility, TEXT);
@ -396,22 +372,22 @@ public class AbilityBotTest {
when(silent.execute(any(GetChatAdministrators.class))).thenReturn(empty());
assertEquals("Unexpected result when checking for privacy", false, bot.checkPrivacy(groupAdminTrio));
assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(groupAdminTrio));
}
@Test
public void canBlockAdminsFromCreatorAbilities() {
Update update = mock(Update.class);
Message message = mock(Message.class);
org.telegram.telegrambots.api.objects.User user = mock(User.class);
User user = mock(User.class);
Ability creatorAbility = getDefaultBuilder().privacy(Privacy.CREATOR).build();
Trio<Update, Ability, String[]> creatorTrio = Trio.of(update, creatorAbility, TEXT);
bot.admins().add(MUSER.id());
bot.admins().add(USER.getId());
mockUser(update, message, user);
assertEquals("Unexpected result when checking for privacy", false, bot.checkPrivacy(creatorTrio));
assertFalse("Unexpected result when checking for privacy", bot.checkPrivacy(creatorTrio));
}
@Test
@ -430,24 +406,23 @@ public class AbilityBotTest {
mockUser(update, message, user);
when(message.isUserMessage()).thenReturn(true);
assertEquals("Unexpected result when checking for locality", true, bot.checkLocality(publicTrio));
assertEquals("Unexpected result when checking for locality", true, bot.checkLocality(userTrio));
assertEquals("Unexpected result when checking for locality", false, bot.checkLocality(groupTrio));
assertTrue("Unexpected result when checking for locality", bot.checkLocality(publicTrio));
assertTrue("Unexpected result when checking for locality", bot.checkLocality(userTrio));
assertFalse("Unexpected result when checking for locality", bot.checkLocality(groupTrio));
}
@Test
public void canRetrieveContext() {
Update update = mock(Update.class);
Message message = mock(Message.class);
User user = mock(User.class);
Ability ability = getDefaultBuilder().build();
Trio<Update, Ability, String[]> trio = Trio.of(update, ability, TEXT);
when(message.getChatId()).thenReturn(GROUP_ID);
mockUser(update, message, user);
mockUser(update, message, USER);
Pair<MessageContext, Ability> actualPair = bot.getContext(trio);
Pair<MessageContext, Ability> expectedPair = Pair.of(newContext(update, MUSER, GROUP_ID, TEXT), ability);
Pair<MessageContext, Ability> expectedPair = Pair.of(newContext(update, USER, GROUP_ID, TEXT), ability);
assertEquals("Unexpected result when fetching for context", expectedPair, actualPair);
}
@ -455,7 +430,7 @@ public class AbilityBotTest {
@Test
public void defaultGlobalFlagIsTrue() {
Update update = mock(Update.class);
assertEquals("Unexpected result when checking for the default global flags", true, bot.checkGlobalFlags(update));
assertTrue("Unexpected result when checking for the default global flags", bot.checkGlobalFlags(update));
}
@Test(expected = ArithmeticException.class)
@ -542,24 +517,69 @@ public class AbilityBotTest {
Trio<Update, Ability, String[]> docTrio = Trio.of(update, documentAbility, TEXT);
Trio<Update, Ability, String[]> textTrio = Trio.of(update, textAbility, TEXT);
assertEquals("Unexpected result when checking for message flags", false, bot.checkMessageFlags(docTrio));
assertEquals("Unexpected result when checking for message flags", true, bot.checkMessageFlags(textTrio));
assertFalse("Unexpected result when checking for message flags", bot.checkMessageFlags(docTrio));
assertTrue("Unexpected result when checking for message flags", bot.checkMessageFlags(textTrio));
}
@Test
public void canReportCommands() {
MessageContext context = mockContext(USER, GROUP_ID);
bot.reportCommands().action().accept(context);
verify(silent, times(1)).send("default - dis iz default command", GROUP_ID);
}
@NotNull
public static MessageContext mockContext(User user) {
return mockContext(user, user.getId());
}
@NotNull
public static MessageContext mockContext(User user, long groupId, String... args) {
Update update = mock(Update.class);
Message message = mock(Message.class);
when(update.hasMessage()).thenReturn(true);
when(update.getMessage()).thenReturn(message);
when(message.getFrom()).thenReturn(user);
when(message.hasText()).thenReturn(true);
return newContext(update, user, groupId, args);
}
@Test
public void canPrintCommandsBasedOnPrivacy() {
Update update = mock(Update.class);
Message message = mock(Message.class);
when(update.hasMessage()).thenReturn(true);
when(update.getMessage()).thenReturn(message);
when(message.hasText()).thenReturn(true);
MessageContext context = mock(MessageContext.class);
when(context.chatId()).thenReturn(GROUP_ID);
MessageContext creatorCtx = newContext(update, CREATOR, GROUP_ID);
bot.reportCommands().action().accept(context);
bot.commands().action().accept(creatorCtx);
verify(silent, times(1)).send("default - dis iz default command", GROUP_ID);
String expected = "PUBLIC\n/commands\n/count\n/default - dis iz default command\n/group\n/test\nADMIN\n/admin\n/ban\n/demote\n/promote\n/unban\nCREATOR\n/backup\n/claim\n/recover\n/report";
verify(silent, times(1)).send(expected, GROUP_ID);
}
@Test
public void printsOnlyPublicCommandsForNormalUser() {
Update update = mock(Update.class);
Message message = mock(Message.class);
when(update.hasMessage()).thenReturn(true);
when(update.getMessage()).thenReturn(message);
when(message.hasText()).thenReturn(true);
MessageContext userCtx = newContext(update, USER, GROUP_ID);
bot.commands().action().accept(userCtx);
String expected = "PUBLIC\n/commands\n/count\n/default - dis iz default command\n/group\n/test";
verify(silent, times(1)).send(expected, GROUP_ID);
}
@After
@ -568,26 +588,14 @@ public class AbilityBotTest {
db.close();
}
private User mockUser(EndUser fromUser) {
User user = mock(User.class);
when(user.getId()).thenReturn(fromUser.id());
when(user.getUserName()).thenReturn(fromUser.username());
when(user.getFirstName()).thenReturn(fromUser.firstName());
when(user.getLastName()).thenReturn(fromUser.lastName());
return user;
}
@NotNull
private Update mockFullUpdate(EndUser fromUser, String args) {
bot.users().put(MUSER.id(), MUSER);
bot.users().put(CREATOR.id(), CREATOR);
bot.userIds().put(CREATOR.username(), CREATOR.id());
bot.userIds().put(MUSER.username(), MUSER.id());
private Update mockFullUpdate(User user, String args) {
bot.users().put(USER.getId(), USER);
bot.users().put(CREATOR.getId(), CREATOR);
bot.userIds().put(CREATOR.getUserName(), CREATOR.getId());
bot.userIds().put(USER.getUserName(), USER.getId());
bot.admins().add(CREATOR.id());
User user = mockUser(fromUser);
bot.admins().add(CREATOR.getId());
Update update = mock(Update.class);
when(update.hasMessage()).thenReturn(true);
@ -596,7 +604,7 @@ public class AbilityBotTest {
when(message.getText()).thenReturn(args);
when(message.hasText()).thenReturn(true);
when(message.isUserMessage()).thenReturn(true);
when(message.getChatId()).thenReturn((long) fromUser.id());
when(message.getChatId()).thenReturn((long) user.getId());
when(update.getMessage()).thenReturn(message);
return update;
}
@ -605,17 +613,9 @@ public class AbilityBotTest {
when(update.hasMessage()).thenReturn(true);
when(update.getMessage()).thenReturn(message);
when(message.getFrom()).thenReturn(user);
when(user.getFirstName()).thenReturn(MUSER.firstName());
when(user.getLastName()).thenReturn(MUSER.lastName());
when(user.getId()).thenReturn(MUSER.id());
when(user.getUserName()).thenReturn(MUSER.username());
}
private void mockAlternateUser(Update update, Message message, User user, EndUser changedUser) {
when(user.getId()).thenReturn(changedUser.id());
when(user.getFirstName()).thenReturn(changedUser.firstName());
when(user.getLastName()).thenReturn(changedUser.lastName());
when(user.getUserName()).thenReturn(changedUser.username());
private void mockAlternateUser(Update update, Message message, User user) {
when(message.getFrom()).thenReturn(user);
when(update.hasMessage()).thenReturn(true);
when(update.getMessage()).thenReturn(message);
@ -627,10 +627,12 @@ public class AbilityBotTest {
Message botMessage = mock(Message.class);
Document document = mock(Document.class);
when(message.getFrom()).thenReturn(CREATOR);
when(update.getMessage()).thenReturn(message);
when(message.getDocument()).thenReturn(document);
when(botMessage.getText()).thenReturn(RECOVERY_MESSAGE);
when(message.isReply()).thenReturn(true);
when(update.hasMessage()).thenReturn(true);
when(message.hasDocument()).thenReturn(true);
when(message.getReplyToMessage()).thenReturn(botMessage);
when(message.getChatId()).thenReturn(GROUP_ID);

View File

@ -3,7 +3,7 @@ package org.telegram.abilitybots.api.db;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.telegram.abilitybots.api.objects.EndUser;
import org.telegram.telegrambots.meta.api.objects.User;
import java.io.IOException;
import java.util.Map;
@ -12,17 +12,16 @@ import java.util.Set;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Sets.newHashSet;
import static java.lang.String.format;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.telegram.abilitybots.api.bot.AbilityBot.USERS;
import static org.telegram.abilitybots.api.bot.AbilityBot.USER_ID;
import static org.junit.Assert.*;
import static org.telegram.abilitybots.api.bot.AbilityBotTest.CREATOR;
import static org.telegram.abilitybots.api.bot.AbilityBotTest.MUSER;
import static org.telegram.abilitybots.api.bot.AbilityBotTest.USER;
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
public class MapDBContextTest {
private static final String USERS = "USERS";
private static final String USER_ID = "USER_ID";
private static final String TEST = "TEST";
private DBContext db;
@Before
@ -32,22 +31,22 @@ public class MapDBContextTest {
@Test
public void canRecoverDB() {
Map<Integer, EndUser> users = db.getMap(USERS);
Map<Integer, User> users = db.getMap(USERS);
Map<String, Integer> userIds = db.getMap(USER_ID);
users.put(CREATOR.id(), CREATOR);
users.put(MUSER.id(), MUSER);
userIds.put(CREATOR.username(), CREATOR.id());
userIds.put(MUSER.username(), MUSER.id());
users.put(CREATOR.getId(), CREATOR);
users.put(USER.getId(), USER);
userIds.put(CREATOR.getUserName(), CREATOR.getId());
userIds.put(USER.getUserName(), USER.getId());
db.getSet("AYRE").add(123123);
Map<Integer, EndUser> originalUsers = newHashMap(users);
Map<Integer, User> originalUsers = newHashMap(users);
String beforeBackupInfo = db.info(USERS);
Object jsonBackup = db.backup();
db.clear();
boolean recovered = db.recover(jsonBackup);
Map<Integer, EndUser> recoveredUsers = db.getMap(USERS);
Map<Integer, User> recoveredUsers = db.getMap(USERS);
String afterRecoveryInfo = db.info(USERS);
assertTrue("Could not recover database successfully", recovered);
@ -56,24 +55,24 @@ public class MapDBContextTest {
}
@Test
public void canFallbackDBIfRecoveryFails() throws IOException {
Set<EndUser> users = db.getSet(USERS);
public void canFallbackDBIfRecoveryFails() {
Set<User> users = db.getSet(USERS);
users.add(CREATOR);
users.add(MUSER);
users.add(USER);
Set<EndUser> originalSet = newHashSet(users);
Set<User> originalSet = newHashSet(users);
Object jsonBackup = db.backup();
String corruptBackup = "!@#$" + String.valueOf(jsonBackup);
boolean recovered = db.recover(corruptBackup);
Set<EndUser> recoveredSet = db.getSet(USERS);
Set<User> recoveredSet = db.getSet(USERS);
assertEquals("Recovery was successful from a CORRUPT backup", false, recovered);
assertFalse("Recovery was successful from a CORRUPT backup", recovered);
assertEquals("Set before and after corrupt recovery are not equal", originalSet, recoveredSet);
}
@Test
public void canGetSummary() throws IOException {
public void canGetSummary() {
String anotherTest = TEST + 1;
db.getSet(TEST).add(TEST);
db.getSet(anotherTest).add(anotherTest);
@ -86,7 +85,7 @@ public class MapDBContextTest {
}
@Test
public void canGetInfo() throws IOException {
public void canGetInfo() {
db.getSet(TEST).add(TEST);
String actualInfo = db.info(TEST);
@ -97,10 +96,27 @@ public class MapDBContextTest {
}
@Test(expected = IllegalStateException.class)
public void cantGetInfoFromNonexistentDBStructureName() throws IOException {
public void cantGetInfoFromNonexistentDBStructureName() {
db.info(TEST);
}
@Test
public void canGetAndSetVariables() {
String varName = "somevar";
Var<User> var = db.getVar(varName);
var.set(CREATOR);
db.commit();
var = db.getVar(varName);
assertEquals(var.get(), CREATOR);
var.set(USER);
db.commit();
Var<User> changedVar = db.getVar(varName);
assertEquals(changedVar.get(), USER);
}
@After
public void tearDown() throws IOException {
db.clear();

View File

@ -2,7 +2,7 @@ package org.telegram.abilitybots.api.sender;
import org.junit.Before;
import org.junit.Test;
import org.telegram.telegrambots.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.util.Optional;

View File

@ -0,0 +1 @@
ability.commands.notFound=Non sono presenti comandi disponibile.

View File

@ -0,0 +1,55 @@
<div align="center">
[![Build Status](https://travis-ci.org/rubenlagus/TelegramBots.svg?branch=master)](https://travis-ci.org/rubenlagus/TelegramBots)
[![Jitpack](https://jitpack.io/v/rubenlagus/TelegramBots.svg)](https://jitpack.io/#rubenlagus/TelegramBots)
[![Telegram](http://trellobot.doomdns.org/telegrambadge.svg)](https://telegram.me/JavaBotsApi)
</div>
Usage
-----
**Maven**
```xml
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-chat-session-bot</artifactId>
<version>4.0.0</version>
</dependency>
```
Motivation
----------
Implementation of bot dialogs require saving some data about current state of conversation.
That brings us to idea of chat session management.
How to use
----------
`Chat session bot` was implemented by using [`Shiro Apache`](https://shiro.apache.org/) session manager.
That allow to manage and store sessions.
To create default Long Polling Session Bot with in-memory store,
you need simply implement `TelegramLongPollingSessionBot`
```java
public class ExampleBotWithSession extends TelegramLongPollingSessionBot {
@Override
public void onUpdateReceived(Update update, Optional<Session> optionalSession) {
//Do some action with update and session
}
@Override
public String getBotUsername() {
return "ExampleBotWithSessionBot";
}
@Override
public String getBotToken() {
return "1234";
}
}
```
Where session is implementation of `org.apache.shiro.session.Session`

View File

@ -0,0 +1,254 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-chat-session-bot</artifactId>
<version>4.0.0</version>
<packaging>jar</packaging>
<name>Telegram Bots Chat Session Bot</name>
<url>https://github.com/rubenlagus/TelegramBots</url>
<description>Telegram bot with chat session support</description>
<issueManagement>
<url>https://github.com/rubenlagus/TelegramBots/issues</url>
<system>GitHub Issues</system>
</issueManagement>
<scm>
<url>https://github.com/rubenlagus/TelegramBots</url>
<connection>scm:git:git://github.com/rubenlagus/TelegramBots.git</connection>
<developerConnection>scm:git:git@github.com:rubenlagus/TelegramBots.git</developerConnection>
</scm>
<ciManagement>
<url>https://travis-ci.org/rubenlagus/TelegramBots</url>
<system>Travis</system>
</ciManagement>
<developers>
<developer>
<email>rberlopez@gmail.com</email>
<name>Ruben Bermudez</name>
<url>https://github.com/rubenlagus</url>
<id>rubenlagus</id>
</developer>
<developer>
<email>bochkarevei@gmail.com</email>
<name>Egor Bochkarev</name>
<url>https://github.com/EgorBochkarev</url>
<id>EgorBochkarev</id>
</developer>
</developers>
<licenses>
<license>
<name>MIT License</name>
<url>http://www.opensource.org/licenses/mit-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<bots.version>4.0.0</bots.version>
<shiro.version>1.4.0</shiro.version>
</properties>
<dependencies>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>${bots.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>2.0.2-beta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<directory>${project.basedir}/target</directory>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<finalName>${project.artifactId}-${project.version}</finalName>
<testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.3</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>clean-project</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.7.201606060606</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.1</version>
<executions>
<execution>
<id>enforce-versions</id>
<goals>
<goal>enforce</goal>
</goals>
</execution>
</executions>
<configuration>
<rules>
<DependencyConvergence />
</rules>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -0,0 +1,10 @@
package org.telegram.telegrambots.session;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import java.io.Serializable;
public interface ChatIdConverter extends SessionKey, SessionIdGenerator {
void setSessionId(Serializable sessionId);
}

View File

@ -0,0 +1,34 @@
package org.telegram.telegrambots.session;
import org.apache.shiro.session.Session;
import java.io.Serializable;
@SuppressWarnings({"unused", "WeakerAccess"})
public class DefaultChatIdConverter implements ChatIdConverter {
private long sessionId;
public DefaultChatIdConverter() {
super();
}
public DefaultChatIdConverter(long sessionId) {
this();
this.sessionId = sessionId;
}
@Override
public void setSessionId(Serializable sessionId){
this.sessionId = (long) sessionId;
};
@Override
public Serializable getSessionId() {
return sessionId;
}
@Override
public Serializable generateId(Session session) {
return getSessionId();
}
}

View File

@ -0,0 +1,37 @@
package org.telegram.telegrambots.session;
import org.apache.shiro.session.mgt.SessionContext;
import java.io.Serializable;
import java.util.HashMap;
@SuppressWarnings("WeakerAccess")
public class DefaultChatSessionContext extends HashMap<String, Object> implements SessionContext {
private long sessionId;
private String host;
public DefaultChatSessionContext(long sessionId, String host) {
this.sessionId = sessionId;
this.host = host;
}
@Override
public String getHost() {
return host;
}
@Override
public void setHost(String host) {
this.host = host;
}
@Override
public Serializable getSessionId() {
return sessionId;
}
@Override
public void setSessionId(Serializable serializable) {
this.sessionId = (long) serializable;
}
}

View File

@ -0,0 +1,67 @@
package org.telegram.telegrambots.session;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.session.mgt.SessionContext;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import java.util.Optional;
@SuppressWarnings({"WeakerAccess", "OptionalUsedAsFieldOrParameterType", "unused"})
public abstract class TelegramLongPollingSessionBot extends TelegramLongPollingBot {
DefaultSessionManager sessionManager;
ChatIdConverter chatIdConverter;
public TelegramLongPollingSessionBot(){
this(new DefaultChatIdConverter());
}
public TelegramLongPollingSessionBot(ChatIdConverter chatIdConverter){
this.setSessionManager(new DefaultSessionManager());
this.setChatIdConverter(chatIdConverter);
AbstractSessionDAO sessionDAO = (AbstractSessionDAO) sessionManager.getSessionDAO();
sessionDAO.setSessionIdGenerator(chatIdConverter);
}
public void setSessionManager(DefaultSessionManager sessionManager) {
this.sessionManager = sessionManager;
}
public void setChatIdConverter(ChatIdConverter chatIdConverter) {
this.chatIdConverter = chatIdConverter;
}
@Override
public void onUpdateReceived(Update update) {
Optional<Session> chatSession;
Message message;
if (update.hasMessage()) {
message = update.getMessage();
} else if (update.hasCallbackQuery()) {
message = update.getCallbackQuery().getMessage();
} else {
chatSession = Optional.empty();
onUpdateReceived(update, chatSession);
return;
}
chatIdConverter.setSessionId(message.getChatId());
chatSession = this.getSession(message);
onUpdateReceived(update, chatSession);
}
public Optional<Session> getSession(Message message){
try {
return Optional.of(sessionManager.getSession(chatIdConverter));
} catch (UnknownSessionException e) {
SessionContext botSession = new DefaultChatSessionContext(message.getChatId(), message.getFrom().getUserName());
return Optional.of(sessionManager.start(botSession));
}
}
public abstract void onUpdateReceived(Update update, Optional<Session> botSession);
}

View File

@ -16,7 +16,7 @@ Just import add the library to your project with one of these options:
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambotsextensions</artifactId>
<version>3.6.1</version>
<version>4.0.0</version>
</dependency>
```

View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.telegram</groupId>
<artifactId>telegrambotsextensions</artifactId>
<version>3.6.1</version>
<version>4.0.0</version>
<packaging>jar</packaging>
<name>Telegram Bots Extensions</name>
@ -59,7 +59,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<bots.version>3.6.1</bots.version>
<bots.version>4.0.0</bots.version>
</properties>
<dependencies>

View File

@ -1,16 +1,15 @@
package org.telegram.telegrambots.bots.commandbot;
package org.telegram.telegrambots.extensions.bots.commandbot;
import org.telegram.telegrambots.ApiContext;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.bots.AbsSender;
import org.telegram.telegrambots.meta.ApiContext;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.bots.AbsSender;
import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.bots.commandbot.commands.BotCommand;
import org.telegram.telegrambots.bots.commandbot.commands.CommandRegistry;
import org.telegram.telegrambots.bots.commandbot.commands.IBotCommand;
import org.telegram.telegrambots.bots.commandbot.commands.ICommandRegistry;
import org.telegram.telegrambots.extensions.bots.commandbot.commands.CommandRegistry;
import org.telegram.telegrambots.extensions.bots.commandbot.commands.IBotCommand;
import org.telegram.telegrambots.extensions.bots.commandbot.commands.ICommandRegistry;
import java.util.Collection;
import java.util.Map;

View File

@ -1,9 +1,9 @@
package org.telegram.telegrambots.bots.commandbot.commands;
package org.telegram.telegrambots.extensions.bots.commandbot.commands;
import org.telegram.telegrambots.api.objects.Chat;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.User;
import org.telegram.telegrambots.bots.AbsSender;
import org.telegram.telegrambots.meta.api.objects.Chat;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.bots.AbsSender;
/**
* Representation of a command, which can be executed

View File

@ -1,7 +1,7 @@
package org.telegram.telegrambots.bots.commandbot.commands;
package org.telegram.telegrambots.extensions.bots.commandbot.commands;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.bots.AbsSender;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.bots.AbsSender;
import java.util.Arrays;
import java.util.Collection;

View File

@ -1,9 +1,9 @@
package org.telegram.telegrambots.bots.commandbot.commands;
package org.telegram.telegrambots.extensions.bots.commandbot.commands;
import org.telegram.telegrambots.api.objects.Chat;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.User;
import org.telegram.telegrambots.bots.AbsSender;
import org.telegram.telegrambots.meta.api.objects.Chat;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.bots.AbsSender;
/**
* Bot command with message ID in execute method

View File

@ -1,11 +1,7 @@
package org.telegram.telegrambots.bots.commandbot.commands;
package org.telegram.telegrambots.extensions.bots.commandbot.commands;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.bots.AbsSender;
import java.util.Collection;
import java.util.Map;
import java.util.function.BiConsumer;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.bots.AbsSender;
/**
* This Interface represents the a Command that can be executed

View File

@ -1,7 +1,7 @@
package org.telegram.telegrambots.bots.commandbot.commands;
package org.telegram.telegrambots.extensions.bots.commandbot.commands;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.bots.AbsSender;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.bots.AbsSender;
import java.util.Collection;
import java.util.Map;

View File

@ -1,116 +1,116 @@
package org.telegram.telegrambots.bots.commandbot.commands.helpCommand;
import org.telegram.telegrambots.api.methods.send.SendMessage;
import org.telegram.telegrambots.api.objects.Chat;
import org.telegram.telegrambots.api.objects.User;
import org.telegram.telegrambots.bots.AbsSender;
import org.telegram.telegrambots.bots.commandbot.commands.IBotCommand;
import org.telegram.telegrambots.bots.commandbot.commands.ICommandRegistry;
import org.telegram.telegrambots.exceptions.TelegramApiException;
import java.util.Collection;
/**
* A special bot command used for printing help messages similiar to the Linux man command.
* The commands printed by this command should implement the {@link IManCommand} interface to provide an extended description.
* @author Lukas Prediger(Chase)
* @version 1.0.0
*
*/
public class HelpCommand extends ManCommand {
private static final String COMMAND_IDENTIFIER = "help";
private static final String COMMAND_DESCRIPTION = "shows all commands. Use /help [command] for more info";
private static final String EXTENDED_DESCRIPTION = "This command displays all commands the bot has to offer.\n /help [command] can display deeper information";
/**
* Returns the command and description of all supplied commands as a formatted String
* @param botCommands the Commands that should be included in the String
* @return a formatted String containing command and description for all supplied commands
*/
public static String getHelpText(IBotCommand...botCommands) {
StringBuilder reply = new StringBuilder();
for (IBotCommand com : botCommands) {
reply.append(com.toString()).append(System.lineSeparator()).append(System.lineSeparator());
}
return reply.toString();
}
/**
* Returns the command and description of all supplied commands as a formatted String
* @param botCommands a collection of commands that should be included in the String
* @return a formatted String containing command and description for all supplied commands
*/
public static String getHelpText(Collection<IBotCommand> botCommands) {
return getHelpText(botCommands.toArray(new IBotCommand[botCommands.size()]));
}
/**
* Returns the command and description of all supplied commands as a formatted String
* @param registry a commandRegistry which commands are formatted into the String
* @return a formatted String containing command and description for all supplied commands
*/
public static String getHelpText(ICommandRegistry registry) {
return getHelpText(registry.getRegisteredCommands());
}
/**
* Reads the extended Description from a BotCommand. If the Command is not of Type {@link IManCommand}, it calls toString();
* @param command a command the extended Descriptions is read from
* @return the extended Description or the toString() if IManCommand is not implemented
*/
public static String getManText(IBotCommand command) {
return IManCommand.class.isInstance(command) ? getManText((IManCommand) command) : command.toString();
}
/**
* Reads the extended Description from a BotCommand;
* @param command a command the extended Descriptions is read from
* @return the extended Description
*/
public static String getManText(IManCommand command) {
return command.toMan();
}
/**
* Create a Help command with the standard Arguments.
*/
public HelpCommand() {
super(COMMAND_IDENTIFIER, COMMAND_DESCRIPTION, EXTENDED_DESCRIPTION);
}
/**
* Creates a Help Command with custom identifier, description and extended Description
* @param commandIdentifier the unique identifier of this command (e.g. the command string to enter into chat)
* @param description the description of this command
* @param extendedDescription The extended Description for the Command, should provide detailed information about arguments and possible options
*/
public HelpCommand(String commandIdentifier, String description, String extendedDescription) {
super(commandIdentifier, description, extendedDescription);
}
@Override
public void execute(AbsSender absSender, User user, Chat chat, String[] arguments) {
if (ICommandRegistry.class.isInstance(absSender)) {
ICommandRegistry registry = (ICommandRegistry) absSender;
if (arguments.length > 0) {
IBotCommand command = registry.getRegisteredCommand(arguments[0]);
String reply = getManText(command);
try {
absSender.execute(new SendMessage(chat.getId(), reply).setParseMode("HTML"));
} catch (TelegramApiException e) {
e.printStackTrace();
}
} else {
String reply = getHelpText(registry);
try {
absSender.execute(new SendMessage(chat.getId(), reply).setParseMode("HTML"));
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
}
}
}
package org.telegram.telegrambots.extensions.bots.commandbot.commands.helpCommand;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Chat;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.bots.AbsSender;
import org.telegram.telegrambots.extensions.bots.commandbot.commands.IBotCommand;
import org.telegram.telegrambots.extensions.bots.commandbot.commands.ICommandRegistry;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.util.Collection;
/**
* A special bot command used for printing help messages similiar to the Linux man command.
* The commands printed by this command should implement the {@link IManCommand} interface to provide an extended description.
* @author Lukas Prediger(Chase)
* @version 1.0.0
*
*/
public class HelpCommand extends ManCommand {
private static final String COMMAND_IDENTIFIER = "help";
private static final String COMMAND_DESCRIPTION = "shows all commands. Use /help [command] for more info";
private static final String EXTENDED_DESCRIPTION = "This command displays all commands the bot has to offer.\n /help [command] can display deeper information";
/**
* Returns the command and description of all supplied commands as a formatted String
* @param botCommands the Commands that should be included in the String
* @return a formatted String containing command and description for all supplied commands
*/
public static String getHelpText(IBotCommand...botCommands) {
StringBuilder reply = new StringBuilder();
for (IBotCommand com : botCommands) {
reply.append(com.toString()).append(System.lineSeparator()).append(System.lineSeparator());
}
return reply.toString();
}
/**
* Returns the command and description of all supplied commands as a formatted String
* @param botCommands a collection of commands that should be included in the String
* @return a formatted String containing command and description for all supplied commands
*/
public static String getHelpText(Collection<IBotCommand> botCommands) {
return getHelpText(botCommands.toArray(new IBotCommand[botCommands.size()]));
}
/**
* Returns the command and description of all supplied commands as a formatted String
* @param registry a commandRegistry which commands are formatted into the String
* @return a formatted String containing command and description for all supplied commands
*/
public static String getHelpText(ICommandRegistry registry) {
return getHelpText(registry.getRegisteredCommands());
}
/**
* Reads the extended Description from a BotCommand. If the Command is not of Type {@link IManCommand}, it calls toString();
* @param command a command the extended Descriptions is read from
* @return the extended Description or the toString() if IManCommand is not implemented
*/
public static String getManText(IBotCommand command) {
return IManCommand.class.isInstance(command) ? getManText((IManCommand) command) : command.toString();
}
/**
* Reads the extended Description from a BotCommand;
* @param command a command the extended Descriptions is read from
* @return the extended Description
*/
public static String getManText(IManCommand command) {
return command.toMan();
}
/**
* Create a Help command with the standard Arguments.
*/
public HelpCommand() {
super(COMMAND_IDENTIFIER, COMMAND_DESCRIPTION, EXTENDED_DESCRIPTION);
}
/**
* Creates a Help Command with custom identifier, description and extended Description
* @param commandIdentifier the unique identifier of this command (e.g. the command string to enter into chat)
* @param description the description of this command
* @param extendedDescription The extended Description for the Command, should provide detailed information about arguments and possible options
*/
public HelpCommand(String commandIdentifier, String description, String extendedDescription) {
super(commandIdentifier, description, extendedDescription);
}
@Override
public void execute(AbsSender absSender, User user, Chat chat, String[] arguments) {
if (ICommandRegistry.class.isInstance(absSender)) {
ICommandRegistry registry = (ICommandRegistry) absSender;
if (arguments.length > 0) {
IBotCommand command = registry.getRegisteredCommand(arguments[0]);
String reply = getManText(command);
try {
absSender.execute(new SendMessage(chat.getId(), reply).setParseMode("HTML"));
} catch (TelegramApiException e) {
e.printStackTrace();
}
} else {
String reply = getHelpText(registry);
try {
absSender.execute(new SendMessage(chat.getId(), reply).setParseMode("HTML"));
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -1,21 +1,21 @@
package org.telegram.telegrambots.bots.commandbot.commands.helpCommand;
/**
* Represents a Command that, aside the normal command description provides an extended Description similar to the output of the Linux <i>man</i> command
* @author Lukas Prediger(Chase)
* @version 1.0.0
*/
public interface IManCommand {
/**
* Returns the extended Description of this command
* @return the extendedDescription
*/
String getExtendedDescription();
/**
* Returns a String Representations of the Command and it's extended Description.
* @return a String representing the Command and it's extended Description
*/
String toMan();
package org.telegram.telegrambots.extensions.bots.commandbot.commands.helpCommand;
/**
* Represents a Command that, aside the normal command description provides an extended Description similar to the output of the Linux <i>man</i> command
* @author Lukas Prediger(Chase)
* @version 1.0.0
*/
public interface IManCommand {
/**
* Returns the extended Description of this command
* @return the extendedDescription
*/
String getExtendedDescription();
/**
* Returns a String Representations of the Command and it's extended Description.
* @return a String representing the Command and it's extended Description
*/
String toMan();
}

View File

@ -1,41 +1,41 @@
package org.telegram.telegrambots.bots.commandbot.commands.helpCommand;
import org.telegram.telegrambots.bots.commandbot.commands.BotCommand;
public abstract class ManCommand extends BotCommand implements IManCommand {
private final String extendedDescription;
/**
* Create a new ManCommand providing a commandIdentifier, a short description and the extended description
* @param commandIdentifier the unique identifier of this command (e.g. the command string to enter into chat)
* @param description the description of this command
* @param extendedDescription The extended Description for the Command, should provide detailed information about arguments and possible options
*/
public ManCommand(String commandIdentifier, String description, String extendedDescription) {
super(commandIdentifier, description);
this.extendedDescription = extendedDescription;
}
/* (non-Javadoc)
* @see org.telegram.telegrambots.bots.commandbot.commands.helpCommand.IManCommand#getExtendedDescription()
*/
@Override
public String getExtendedDescription() {
return extendedDescription;
}
/* (non-Javadoc)
* @see org.telegram.telegrambots.bots.commandbot.commands.helpCommand.IManCommand#toMan()
*/
@Override
public String toMan() {
StringBuilder sb = new StringBuilder(toString());
sb.append(System.lineSeparator())
.append("-----------------")
.append(System.lineSeparator());
if (getExtendedDescription() != null) sb.append(getExtendedDescription());
return sb.toString();
}
}
package org.telegram.telegrambots.extensions.bots.commandbot.commands.helpCommand;
import org.telegram.telegrambots.extensions.bots.commandbot.commands.BotCommand;
public abstract class ManCommand extends BotCommand implements IManCommand {
private final String extendedDescription;
/**
* Create a new ManCommand providing a commandIdentifier, a short description and the extended description
* @param commandIdentifier the unique identifier of this command (e.g. the command string to enter into chat)
* @param description the description of this command
* @param extendedDescription The extended Description for the Command, should provide detailed information about arguments and possible options
*/
public ManCommand(String commandIdentifier, String description, String extendedDescription) {
super(commandIdentifier, description);
this.extendedDescription = extendedDescription;
}
/* (non-Javadoc)
* @see org.telegram.telegrambots.extensions.bots.commandbot.commands.helpCommand.IManCommand#getExtendedDescription()
*/
@Override
public String getExtendedDescription() {
return extendedDescription;
}
/* (non-Javadoc)
* @see org.telegram.telegrambots.extensions.bots.commandbot.commands.helpCommand.IManCommand#toMan()
*/
@Override
public String toMan() {
StringBuilder sb = new StringBuilder(toString());
sb.append(System.lineSeparator())
.append("-----------------")
.append(System.lineSeparator());
if (getExtendedDescription() != null) sb.append(getExtendedDescription());
return sb.toString();
}
}

View File

@ -1,4 +1,4 @@
package org.telegram.telegrambots.bots.timedbot;
package org.telegram.telegrambots.extensions.bots.timedbot;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;

View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-meta</artifactId>
<version>3.6.1</version>
<version>4.0.0</version>
<packaging>jar</packaging>
<name>Telegram Bots Meta</name>

View File

@ -1,74 +0,0 @@
package org.telegram.telegrambots.api.objects.media;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
/**
* @author Ruben Bermudez
* @version 3.5
*
* Represents a video.
*/
@SuppressWarnings("unused")
public class InputMediaVideo extends InputMedia<InputMediaVideo> {
private static final String TYPE = "video";
private static final String WIDTH_FIELD = "width";
private static final String HEIGHT_FIELD = "height";
private static final String DURATION_FIELD = "duration";
private static final String SUPPORTSSTREAMING_FIELD = "supports_streaming";
@JsonProperty(WIDTH_FIELD)
private int width; ///< Optional. Video width
@JsonProperty(HEIGHT_FIELD)
private int height; ///< Optional. Video height
@JsonProperty(DURATION_FIELD)
private int duration; ///< Optional. Video duration
@JsonProperty(SUPPORTSSTREAMING_FIELD)
private Boolean supportsStreaming; ///< Optional. Pass True, if the uploaded video is suitable for streaming
public InputMediaVideo() {
super();
}
public InputMediaVideo(String media, String caption) {
super(media, caption);
}
public int getWidth() {
return width;
}
public InputMediaVideo setWidth(int width) {
this.width = width;
return this;
}
public int getHeight() {
return height;
}
public InputMediaVideo setHeight(int height) {
this.height = height;
return this;
}
public int getDuration() {
return duration;
}
public InputMediaVideo setDuration(int duration) {
this.duration = duration;
return this;
}
@Override
public String getType() {
return TYPE;
}
@Override
public void validate() throws TelegramApiValidationException {
super.validate();
}
}

View File

@ -1,13 +0,0 @@
package org.telegram.telegrambots.api.objects.replykeyboard;
import org.telegram.telegrambots.api.interfaces.InputBotApiObject;
import org.telegram.telegrambots.api.interfaces.Validable;
/**
* @author Ruben Bermudez
* @version 1.0
* @brief Reply keyboard abstract type
* @date 20 of June of 2015
*/
public interface ReplyKeyboard extends InputBotApiObject, Validable {
}

View File

@ -1,872 +0,0 @@
package org.telegram.telegrambots.bots;
import org.telegram.telegrambots.api.methods.*;
import org.telegram.telegrambots.api.methods.games.GetGameHighScores;
import org.telegram.telegrambots.api.methods.games.SetGameScore;
import org.telegram.telegrambots.api.methods.groupadministration.*;
import org.telegram.telegrambots.api.methods.pinnedmessages.PinChatMessage;
import org.telegram.telegrambots.api.methods.pinnedmessages.UnpinChatMessage;
import org.telegram.telegrambots.api.methods.send.*;
import org.telegram.telegrambots.api.methods.stickers.AddStickerToSet;
import org.telegram.telegrambots.api.methods.stickers.CreateNewStickerSet;
import org.telegram.telegrambots.api.methods.stickers.UploadStickerFile;
import org.telegram.telegrambots.api.methods.updates.DeleteWebhook;
import org.telegram.telegrambots.api.methods.updates.GetWebhookInfo;
import org.telegram.telegrambots.api.methods.updatingmessages.DeleteMessage;
import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageCaption;
import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageReplyMarkup;
import org.telegram.telegrambots.api.methods.updatingmessages.EditMessageText;
import org.telegram.telegrambots.api.objects.*;
import org.telegram.telegrambots.api.objects.games.GameHighScore;
import org.telegram.telegrambots.exceptions.TelegramApiException;
import org.telegram.telegrambots.updateshandlers.SentCallback;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* @author Ruben Bermudez
* @version 1.0
*/
@SuppressWarnings("unused")
public abstract class AbsSender {
protected AbsSender() {
}
// General methods to execute BotApiMethods
public <T extends Serializable, Method extends BotApiMethod<T>, Callback extends SentCallback<T>> void executeAsync(Method method, Callback callback) throws TelegramApiException {
if (method == null) {
throw new TelegramApiException("Parameter method can not be null");
}
if (callback == null) {
throw new TelegramApiException("Parameter callback can not be null");
}
sendApiMethodAsync(method, callback);
}
public <T extends Serializable, Method extends BotApiMethod<T>> T execute(Method method) throws TelegramApiException {
if (method == null) {
throw new TelegramApiException("Parameter method can not be null");
}
return sendApiMethod(method);
}
// Send Requests
@Deprecated
public final Message sendMessage(SendMessage sendMessage) throws TelegramApiException {
if (sendMessage == null) {
throw new TelegramApiException("Parameter sendMessage can not be null");
}
return sendApiMethod(sendMessage);
}
@Deprecated
public final Boolean answerInlineQuery(AnswerInlineQuery answerInlineQuery) throws TelegramApiException {
if (answerInlineQuery == null) {
throw new TelegramApiException("Parameter answerInlineQuery can not be null");
}
return sendApiMethod(answerInlineQuery);
}
@Deprecated
public final Boolean sendChatAction(SendChatAction sendChatAction) throws TelegramApiException {
if (sendChatAction == null) {
throw new TelegramApiException("Parameter sendChatAction can not be null");
}
return sendApiMethod(sendChatAction);
}
@Deprecated
public final Message forwardMessage(ForwardMessage forwardMessage) throws TelegramApiException {
if (forwardMessage == null) {
throw new TelegramApiException("Parameter forwardMessage can not be null");
}
return sendApiMethod(forwardMessage);
}
@Deprecated
public final Message sendLocation(SendLocation sendLocation) throws TelegramApiException {
if (sendLocation == null) {
throw new TelegramApiException("Parameter sendLocation can not be null");
}
return sendApiMethod(sendLocation);
}
@Deprecated
public final Message sendVenue(SendVenue sendVenue) throws TelegramApiException {
if (sendVenue == null) {
throw new TelegramApiException("Parameter sendVenue can not be null");
}
return sendApiMethod(sendVenue);
}
@Deprecated
public final Message sendContact(SendContact sendContact) throws TelegramApiException {
if (sendContact == null) {
throw new TelegramApiException("Parameter sendContact can not be null");
}
return sendApiMethod(sendContact);
}
@Deprecated
public final Boolean kickMember(KickChatMember kickChatMember) throws TelegramApiException {
if (kickChatMember == null) {
throw new TelegramApiException("Parameter kickChatMember can not be null");
}
return sendApiMethod(kickChatMember);
}
@Deprecated
public final Boolean unbanMember(UnbanChatMember unbanChatMember) throws TelegramApiException {
if (unbanChatMember == null) {
throw new TelegramApiException("Parameter unbanChatMember can not be null");
}
return sendApiMethod(unbanChatMember);
}
@Deprecated
public final Boolean leaveChat(LeaveChat leaveChat) throws TelegramApiException {
if (leaveChat == null) {
throw new TelegramApiException("Parameter leaveChat can not be null");
}
return sendApiMethod(leaveChat);
}
@Deprecated
public final Chat getChat(GetChat getChat) throws TelegramApiException {
if (getChat == null) {
throw new TelegramApiException("Parameter getChat can not be null");
}
return sendApiMethod(getChat);
}
@Deprecated
public final String exportChatInviteLink(ExportChatInviteLink exportChatInviteLink) throws TelegramApiException {
if (exportChatInviteLink == null) {
throw new TelegramApiException("Parameter exportChatInviteLink can not be null");
}
return sendApiMethod(exportChatInviteLink);
}
@Deprecated
public final List<ChatMember> getChatAdministrators(GetChatAdministrators getChatAdministrators) throws TelegramApiException {
if (getChatAdministrators == null) {
throw new TelegramApiException("Parameter getChatAdministrators can not be null");
}
return sendApiMethod(getChatAdministrators);
}
@Deprecated
public final ChatMember getChatMember(GetChatMember getChatMember) throws TelegramApiException {
if (getChatMember == null) {
throw new TelegramApiException("Parameter getChatMember can not be null");
}
return sendApiMethod(getChatMember);
}
@Deprecated
public final Integer getChatMemberCount(GetChatMemberCount getChatMemberCount) throws TelegramApiException {
if (getChatMemberCount == null) {
throw new TelegramApiException("Parameter getChatMemberCount can not be null");
}
return sendApiMethod(getChatMemberCount);
}
@Deprecated
public final Serializable editMessageText(EditMessageText editMessageText) throws TelegramApiException {
if (editMessageText == null) {
throw new TelegramApiException("Parameter editMessageText can not be null");
}
return sendApiMethod(editMessageText);
}
@Deprecated
public final Serializable editMessageCaption(EditMessageCaption editMessageCaption) throws TelegramApiException {
if (editMessageCaption == null) {
throw new TelegramApiException("Parameter editMessageCaption can not be null");
}
return sendApiMethod(editMessageCaption);
}
@Deprecated
public final Serializable editMessageReplyMarkup(EditMessageReplyMarkup editMessageReplyMarkup) throws TelegramApiException {
if (editMessageReplyMarkup == null) {
throw new TelegramApiException("Parameter editMessageReplyMarkup can not be null");
}
return sendApiMethod(editMessageReplyMarkup);
}
@Deprecated
public final Boolean answerCallbackQuery(AnswerCallbackQuery answerCallbackQuery) throws TelegramApiException {
if (answerCallbackQuery == null) {
throw new TelegramApiException("Parameter answerCallbackQuery can not be null");
}
return sendApiMethod(answerCallbackQuery);
}
@Deprecated
public final UserProfilePhotos getUserProfilePhotos(GetUserProfilePhotos getUserProfilePhotos) throws TelegramApiException {
if (getUserProfilePhotos == null) {
throw new TelegramApiException("Parameter getUserProfilePhotos can not be null");
}
return sendApiMethod(getUserProfilePhotos);
}
@Deprecated
public final File getFile(GetFile getFile) throws TelegramApiException {
if(getFile == null){
throw new TelegramApiException("Parameter getFile can not be null");
}
else if(getFile.getFileId() == null){
throw new TelegramApiException("Attribute file_id in parameter getFile can not be null");
}
return sendApiMethod(getFile);
}
public final User getMe() throws TelegramApiException {
return sendApiMethod(new GetMe());
}
public final WebhookInfo getWebhookInfo() throws TelegramApiException {
GetWebhookInfo getWebhookInfo = new GetWebhookInfo();
return sendApiMethod(getWebhookInfo);
}
@Deprecated
public final Serializable setGameScore(SetGameScore setGameScore) throws TelegramApiException {
if(setGameScore == null){
throw new TelegramApiException("Parameter setGameScore can not be null");
}
return sendApiMethod(setGameScore);
}
@Deprecated
public final Serializable getGameHighScores(GetGameHighScores getGameHighScores) throws TelegramApiException {
if(getGameHighScores == null){
throw new TelegramApiException("Parameter getGameHighScores can not be null");
}
return sendApiMethod(getGameHighScores);
}
@Deprecated
public final Message sendGame(SendGame sendGame) throws TelegramApiException {
if(sendGame == null){
throw new TelegramApiException("Parameter sendGame can not be null");
}
return sendApiMethod(sendGame);
}
@Deprecated
public final Boolean deleteWebhook(DeleteWebhook deleteWebhook) throws TelegramApiException {
if(deleteWebhook == null){
throw new TelegramApiException("Parameter deleteWebhook can not be null");
}
return sendApiMethod(deleteWebhook);
}
@Deprecated
public final Message sendInvoice(SendInvoice sendInvoice) throws TelegramApiException {
if(sendInvoice == null){
throw new TelegramApiException("Parameter sendInvoice can not be null");
}
return sendApiMethod(sendInvoice);
}
@Deprecated
public final Boolean answerShippingQuery(AnswerShippingQuery answerShippingQuery) throws TelegramApiException {
if(answerShippingQuery == null){
throw new TelegramApiException("Parameter answerShippingQuery can not be null");
}
return sendApiMethod(answerShippingQuery);
}
@Deprecated
public final Boolean answerPreCheckoutQuery(AnswerPreCheckoutQuery answerPreCheckoutQuery) throws TelegramApiException {
if(answerPreCheckoutQuery == null){
throw new TelegramApiException("Parameter answerPreCheckoutQuery can not be null");
}
return sendApiMethod(answerPreCheckoutQuery);
}
@Deprecated
public final Boolean deleteMessage(DeleteMessage deleteMessage) throws TelegramApiException {
if(deleteMessage == null){
throw new TelegramApiException("Parameter deleteMessage can not be null");
}
return sendApiMethod(deleteMessage);
}
@Deprecated
public final Boolean deleteChatPhoto(DeleteChatPhoto deleteChatPhoto) throws TelegramApiException {
if(deleteChatPhoto == null){
throw new TelegramApiException("Parameter deleteChatPhoto can not be null");
}
return sendApiMethod(deleteChatPhoto);
}
@Deprecated
public final Boolean pinChatMessage(PinChatMessage pinChatMessage) throws TelegramApiException {
if(pinChatMessage == null){
throw new TelegramApiException("Parameter pinChatMessage can not be null");
}
return sendApiMethod(pinChatMessage);
}
@Deprecated
public final Boolean unpinChatMessage(UnpinChatMessage unpinChatMessage) throws TelegramApiException {
if(unpinChatMessage == null){
throw new TelegramApiException("Parameter unpinChatMessage can not be null");
}
return sendApiMethod(unpinChatMessage);
}
@Deprecated
public final Boolean promoteChatMember(PromoteChatMember promoteChatMember) throws TelegramApiException {
if(promoteChatMember == null){
throw new TelegramApiException("Parameter promoteChatMember can not be null");
}
return sendApiMethod(promoteChatMember);
}
@Deprecated
public final Boolean restrictChatMember(RestrictChatMember restrictChatMember) throws TelegramApiException {
if(restrictChatMember == null){
throw new TelegramApiException("Parameter restrictChatMember can not be null");
}
return sendApiMethod(restrictChatMember);
}
@Deprecated
public final Boolean setChatDescription(SetChatDescription setChatDescription) throws TelegramApiException {
if(setChatDescription == null){
throw new TelegramApiException("Parameter setChatDescription can not be null");
}
return sendApiMethod(setChatDescription);
}
@Deprecated
public final Boolean setChatTitle(SetChatTitle setChatTitle) throws TelegramApiException {
if(setChatTitle == null){
throw new TelegramApiException("Parameter setChatTitle can not be null");
}
return sendApiMethod(setChatTitle);
}
// Send Requests Async
@Deprecated
public final void sendMessageAsync(SendMessage sendMessage, SentCallback<Message> sentCallback) throws TelegramApiException {
if (sendMessage == null) {
throw new TelegramApiException("Parameter sendMessage can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(sendMessage, sentCallback);
}
@Deprecated
public final void answerInlineQueryAsync(AnswerInlineQuery answerInlineQuery, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (answerInlineQuery == null) {
throw new TelegramApiException("Parameter answerInlineQuery can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(answerInlineQuery, sentCallback);
}
@Deprecated
public final void sendChatActionAsync(SendChatAction sendChatAction, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (sendChatAction == null) {
throw new TelegramApiException("Parameter sendChatAction can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(sendChatAction, sentCallback);
}
@Deprecated
public final void forwardMessageAsync(ForwardMessage forwardMessage, SentCallback<Message> sentCallback) throws TelegramApiException {
if (forwardMessage == null) {
throw new TelegramApiException("Parameter forwardMessage can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(forwardMessage, sentCallback);
}
@Deprecated
public final void sendLocationAsync(SendLocation sendLocation, SentCallback<Message> sentCallback) throws TelegramApiException {
if (sendLocation == null) {
throw new TelegramApiException("Parameter sendLocation can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(sendLocation, sentCallback);
}
@Deprecated
public final void sendVenueAsync(SendVenue sendVenue, SentCallback<Message> sentCallback) throws TelegramApiException {
if (sendVenue == null) {
throw new TelegramApiException("Parameter sendVenue can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(sendVenue, sentCallback);
}
@Deprecated
public final void sendContactAsync(SendContact sendContact, SentCallback<Message> sentCallback) throws TelegramApiException {
if (sendContact == null) {
throw new TelegramApiException("Parameter sendContact can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(sendContact, sentCallback);
}
@Deprecated
public final void kickMemberAsync(KickChatMember kickChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (kickChatMember == null) {
throw new TelegramApiException("Parameter kickChatMember can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(kickChatMember, sentCallback);
}
@Deprecated
public final void unbanMemberAsync(UnbanChatMember unbanChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (unbanChatMember == null) {
throw new TelegramApiException("Parameter unbanChatMember can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(unbanChatMember, sentCallback);
}
@Deprecated
public final void leaveChatAsync(LeaveChat leaveChat, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (leaveChat == null) {
throw new TelegramApiException("Parameter leaveChat can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(leaveChat, sentCallback);
}
@Deprecated
public final void getChatAsync(GetChat getChat, SentCallback<Chat> sentCallback) throws TelegramApiException {
if (getChat == null) {
throw new TelegramApiException("Parameter getChat can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(getChat, sentCallback);
}
@Deprecated
public final void exportChatInviteLinkAsync(ExportChatInviteLink exportChatInviteLink, SentCallback<String> sentCallback) throws TelegramApiException {
if (exportChatInviteLink == null) {
throw new TelegramApiException("Parameter exportChatInviteLink can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(exportChatInviteLink, sentCallback);
}
@Deprecated
public final void getChatAdministratorsAsync(GetChatAdministrators getChatAdministrators, SentCallback<ArrayList<ChatMember>> sentCallback) throws TelegramApiException {
if (getChatAdministrators == null) {
throw new TelegramApiException("Parameter getChatAdministrators can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(getChatAdministrators, sentCallback);
}
@Deprecated
public final void getChatMemberAsync(GetChatMember getChatMember, SentCallback<ChatMember> sentCallback) throws TelegramApiException {
if (getChatMember == null) {
throw new TelegramApiException("Parameter getChatMember can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(getChatMember, sentCallback);
}
@Deprecated
public final void getChatMemberCountAsync(GetChatMemberCount getChatMemberCount, SentCallback<Integer> sentCallback) throws TelegramApiException {
if (getChatMemberCount == null) {
throw new TelegramApiException("Parameter getChatMemberCount can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(getChatMemberCount, sentCallback);
}
@Deprecated
public final void editMessageTextAsync(EditMessageText editMessageText, SentCallback<Serializable> sentCallback) throws TelegramApiException {
if (editMessageText == null) {
throw new TelegramApiException("Parameter editMessageText can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(editMessageText, sentCallback);
}
@Deprecated
public final void editMessageCaptionAsync(EditMessageCaption editMessageCaption, SentCallback<Serializable> sentCallback) throws TelegramApiException {
if (editMessageCaption == null) {
throw new TelegramApiException("Parameter editMessageCaption can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(editMessageCaption, sentCallback);
}
@Deprecated
public final void editMessageReplyMarkup(EditMessageReplyMarkup editMessageReplyMarkup, SentCallback<Serializable> sentCallback) throws TelegramApiException {
if (editMessageReplyMarkup == null) {
throw new TelegramApiException("Parameter editMessageReplyMarkup can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(editMessageReplyMarkup, sentCallback);
}
@Deprecated
public final void answerCallbackQueryAsync(AnswerCallbackQuery answerCallbackQuery, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (answerCallbackQuery == null) {
throw new TelegramApiException("Parameter answerCallbackQuery can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(answerCallbackQuery, sentCallback);
}
@Deprecated
public final void getUserProfilePhotosAsync(GetUserProfilePhotos getUserProfilePhotos, SentCallback<UserProfilePhotos> sentCallback) throws TelegramApiException {
if (getUserProfilePhotos == null) {
throw new TelegramApiException("Parameter getUserProfilePhotos can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(getUserProfilePhotos, sentCallback);
}
@Deprecated
public final void getFileAsync(GetFile getFile, SentCallback<File> sentCallback) throws TelegramApiException {
if (getFile == null) {
throw new TelegramApiException("Parameter getFile can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(getFile, sentCallback);
}
public final void getMeAsync(SentCallback<User> sentCallback) throws TelegramApiException {
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(new GetMe(), sentCallback);
}
public final void getWebhookInfoAsync(SentCallback<WebhookInfo> sentCallback) throws TelegramApiException {
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(new GetWebhookInfo(), sentCallback);
}
@Deprecated
public final void setGameScoreAsync(SetGameScore setGameScore, SentCallback<Serializable> sentCallback) throws TelegramApiException {
if (setGameScore == null) {
throw new TelegramApiException("Parameter setGameScore can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(setGameScore, sentCallback);
}
@Deprecated
public final void getGameHighScoresAsync(GetGameHighScores getGameHighScores, SentCallback<ArrayList<GameHighScore>> sentCallback) throws TelegramApiException {
if (getGameHighScores == null) {
throw new TelegramApiException("Parameter getGameHighScores can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(getGameHighScores, sentCallback);
}
@Deprecated
public final void sendGameAsync(SendGame sendGame, SentCallback<Message> sentCallback) throws TelegramApiException {
if (sendGame == null) {
throw new TelegramApiException("Parameter sendGame can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(sendGame, sentCallback);
}
@Deprecated
public final void deleteWebhook(DeleteWebhook deleteWebhook, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (deleteWebhook == null) {
throw new TelegramApiException("Parameter deleteWebhook can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(deleteWebhook, sentCallback);
}
@Deprecated
public final void sendInvoice(SendInvoice sendInvoice, SentCallback<Message> sentCallback) throws TelegramApiException {
if (sendInvoice == null) {
throw new TelegramApiException("Parameter sendInvoice can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(sendInvoice, sentCallback);
}
@Deprecated
public final void answerShippingQuery(AnswerShippingQuery answerShippingQuery, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (answerShippingQuery == null) {
throw new TelegramApiException("Parameter answerShippingQuery can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(answerShippingQuery, sentCallback);
}
@Deprecated
public final void answerPreCheckoutQuery(AnswerPreCheckoutQuery answerPreCheckoutQuery, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (answerPreCheckoutQuery == null) {
throw new TelegramApiException("Parameter answerPreCheckoutQuery can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(answerPreCheckoutQuery, sentCallback);
}
@Deprecated
public final void deleteMessage(DeleteMessage deleteMessage, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (deleteMessage == null) {
throw new TelegramApiException("Parameter deleteMessage can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(deleteMessage, sentCallback);
}
@Deprecated
public final void deleteChatPhoto(DeleteChatPhoto deleteChatPhoto, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (deleteChatPhoto == null) {
throw new TelegramApiException("Parameter deleteChatPhoto can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(deleteChatPhoto, sentCallback);
}
@Deprecated
public final void pinChatMessage(PinChatMessage pinChatMessage, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (pinChatMessage == null) {
throw new TelegramApiException("Parameter pinChatMessage can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(pinChatMessage, sentCallback);
}
@Deprecated
public final void unpinChatMessage(UnpinChatMessage unpinChatMessage, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (unpinChatMessage == null) {
throw new TelegramApiException("Parameter unpinChatMessage can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(unpinChatMessage, sentCallback);
}
@Deprecated
public final void promoteChatMember(PromoteChatMember promoteChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (promoteChatMember == null) {
throw new TelegramApiException("Parameter promoteChatMember can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(promoteChatMember, sentCallback);
}
@Deprecated
public final void restrictChatMember(RestrictChatMember restrictChatMember, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (restrictChatMember == null) {
throw new TelegramApiException("Parameter restrictChatMember can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(restrictChatMember, sentCallback);
}
@Deprecated
public final void setChatDescription(SetChatDescription setChatDescription, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (setChatDescription == null) {
throw new TelegramApiException("Parameter setChatDescription can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(setChatDescription, sentCallback);
}
@Deprecated
public final void setChatTitle(SetChatTitle setChatTitle, SentCallback<Boolean> sentCallback) throws TelegramApiException {
if (setChatTitle == null) {
throw new TelegramApiException("Parameter setChatTitle can not be null");
}
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
}
sendApiMethodAsync(setChatTitle, sentCallback);
}
// Specific Send Requests
public abstract Message sendDocument(SendDocument sendDocument) throws TelegramApiException;
public abstract Message sendPhoto(SendPhoto sendPhoto) throws TelegramApiException;
public abstract Message sendVideo(SendVideo sendVideo) throws TelegramApiException;
public abstract Message sendVideoNote(SendVideoNote sendVideoNote) throws TelegramApiException;
public abstract Message sendSticker(SendSticker sendSticker) throws TelegramApiException;
/**
* Sends a file using Send Audio method (https://core.telegram.org/bots/api#sendaudio)
* @param sendAudio Information to send
* @return If success, the sent Message is returned
* @throws TelegramApiException If there is any error sending the audio
*/
public abstract Message sendAudio(SendAudio sendAudio) throws TelegramApiException;
/**
* Sends a voice note using Send Voice method (https://core.telegram.org/bots/api#sendvoice)
* For this to work, your audio must be in an .ogg file encoded with OPUS
* @param sendVoice Information to send
* @return If success, the sent Message is returned
* @throws TelegramApiException If there is any error sending the audio
*/
public abstract Message sendVoice(SendVoice sendVoice) throws TelegramApiException;
/**
* Send a media group (https://core.telegram.org/bots/api#sendMediaGroup)
* @return If success, list of generated messages
* @throws TelegramApiException If there is any error sending the media group
*/
public abstract List<Message> sendMediaGroup(SendMediaGroup sendMediaGroup) throws TelegramApiException;
/**
* Set chat profile photo (https://core.telegram.org/bots/api#setChatPhoto)
* @param setChatPhoto Information to set the photo
* @return If success, true is returned
* @throws TelegramApiException If there is any error setting the photo.
*/
public abstract Boolean setChatPhoto(SetChatPhoto setChatPhoto) throws TelegramApiException;
/**
* Adds a new sticker to a set (https://core.telegram.org/bots/api#addStickerToSet)
* @param addStickerToSet Information of the sticker to set
* @return If success, true is returned
* @throws TelegramApiException If there is any error adding the sticker to the set
*/
public abstract Boolean addStickerToSet(AddStickerToSet addStickerToSet) throws TelegramApiException;
/**
* Creates a new sticker set (https://core.telegram.org/bots/api#createNewStickerSet)
* @param createNewStickerSet Information of the sticker set to create
* @return If success, true is returned
* @throws TelegramApiException If there is any error creating the new sticker set
*/
public abstract Boolean createNewStickerSet(CreateNewStickerSet createNewStickerSet) throws TelegramApiException;
/**
* Upload a new file as sticker (https://core.telegram.org/bots/api#uploadStickerFile)
* @param uploadStickerFile Information of the file to upload as sticker
* @return If success, true is returned
* @throws TelegramApiException If there is any error uploading the new file
*/
public abstract File uploadStickerFile(UploadStickerFile uploadStickerFile) throws TelegramApiException;
// Simplified methods
protected abstract <T extends Serializable, Method extends BotApiMethod<T>, Callback extends SentCallback<T>> void sendApiMethodAsync(Method method, Callback callback);
protected abstract <T extends Serializable, Method extends BotApiMethod<T>> T sendApiMethod(Method method) throws TelegramApiException;
}

View File

@ -1,4 +1,4 @@
package org.telegram.telegrambots;
package org.telegram.telegrambots.meta;
/**
* @author Ruben Bermudez

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots;
package org.telegram.telegrambots.meta;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import org.telegram.telegrambots.logging.BotLogger;
import org.telegram.telegrambots.meta.logging.BotLogger;
import java.text.MessageFormat;
import java.util.HashMap;

View File

@ -1,10 +1,10 @@
package org.telegram.telegrambots;
package org.telegram.telegrambots.meta;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.generics.BotSession;
import org.telegram.telegrambots.generics.LongPollingBot;
import org.telegram.telegrambots.generics.Webhook;
import org.telegram.telegrambots.generics.WebhookBot;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.generics.BotSession;
import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.meta.generics.Webhook;
import org.telegram.telegrambots.meta.generics.WebhookBot;
import java.text.MessageFormat;

View File

@ -1,4 +1,4 @@
package org.telegram.telegrambots.api.interfaces;
package org.telegram.telegrambots.meta.api.interfaces;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

View File

@ -1,4 +1,4 @@
package org.telegram.telegrambots.api.interfaces;
package org.telegram.telegrambots.meta.api.interfaces;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

View File

@ -15,9 +15,9 @@
* along with TelegramBots. If not, see <http://www.gnu.org/licenses/>.
*/
package org.telegram.telegrambots.api.interfaces;
package org.telegram.telegrambots.meta.api.interfaces;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
/**
* @author Ruben Bermudez

View File

@ -1,4 +1,4 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
/**
* @author Ruben Bermudez

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;

View File

@ -1,13 +1,13 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.objects.inlinequery.result.InlineQueryResult;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.objects.inlinequery.result.InlineQueryResult;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Arrays;

View File

@ -1,10 +1,10 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.objects.payments.ShippingOption;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.objects.payments.ShippingOption;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.List;

View File

@ -1,4 +1,4 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

View File

@ -1,12 +1,12 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,12 +1,12 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.objects.File;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.objects.File;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.objects.User;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;

View File

@ -1,12 +1,12 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.objects.UserProfilePhotos;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.objects.UserProfilePhotos;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;

View File

@ -1,4 +1,4 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
/**
* @author Ruben Bermudez

View File

@ -1,10 +1,10 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.telegram.telegrambots.api.interfaces.Validable;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.api.interfaces.Validable;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import java.io.Serializable;

View File

@ -0,0 +1,100 @@
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.meta.api.objects.passport.dataerror.PassportElementError;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* @author Ruben Bermudez
* @version 4.0.0
*
* Informs a user that some Telegram Passport data contains errors.
* The user will not be able to resend data, until the errors are fixed
*/
public class SetPassportDataErrors extends BotApiMethod<Boolean> {
public static final String PATH = "setPassportDataErrors";
private static final String USERID_FIELD = "user_id";
private static final String ERRORS_FIELD = "errors";
@JsonProperty(USERID_FIELD)
private Integer userId; ///< User identifier
@JsonProperty(ERRORS_FIELD)
private List<PassportElementError> errors; ///< A JSON-serialized array describing the errors
public SetPassportDataErrors(Integer userId, List<PassportElementError> errors) {
super();
this.userId = checkNotNull(userId);
this.errors = checkNotNull(errors);
}
public SetPassportDataErrors() {
super();
}
public Integer getUserId() {
return userId;
}
public SetPassportDataErrors setUserId(Integer userId) {
this.userId = userId;
return this;
}
public List<PassportElementError> getErrors() {
return errors;
}
public SetPassportDataErrors setErrors(List<PassportElementError> errors) {
this.errors = errors;
return this;
}
public SetPassportDataErrors addError(PassportElementError error) {
error = checkNotNull(error);
if (this.errors == null) {
this.errors = new ArrayList<>();
}
this.errors.add(error);
return this;
}
@Override
public String getMethod() {
return PATH;
}
@Override
public Boolean deserializeResponse(String answer) throws TelegramApiRequestException {
try {
ApiResponse<Boolean> result = OBJECT_MAPPER.readValue(answer,
new TypeReference<ApiResponse<Boolean>>(){});
if (result.getOk()) {
return result.getResult();
} else {
throw new TelegramApiRequestException("Error setting passport data errors", result);
}
} catch (IOException e) {
throw new TelegramApiRequestException("Unable to deserialize response", e);
}
}
@Override
public void validate() throws TelegramApiValidationException {
if (userId == null) {
throw new TelegramApiValidationException("User ID can't be empty", this);
}
if (errors == null || errors.isEmpty()) {
throw new TelegramApiValidationException("Errors can't be empty", this);
}
}
}

View File

@ -1,16 +1,15 @@
package org.telegram.telegrambots.api.methods;
package org.telegram.telegrambots.meta.api.methods;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.io.Serializable;
import java.util.Objects;
/**
* @author Ruben Bermudez

View File

@ -14,20 +14,19 @@
* You should have received a copy of the GNU General Public License
* along with TelegramBots. If not, see <http://www.gnu.org/licenses/>.
*/
package org.telegram.telegrambots.api.methods.games;
package org.telegram.telegrambots.meta.api.methods.games;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.games.GameHighScore;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.games.GameHighScore;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Objects;
/**
* @author Ruben Bermudez

View File

@ -15,20 +15,19 @@
* along with TelegramBots. If not, see <http://www.gnu.org/licenses/>.
*/
package org.telegram.telegrambots.api.methods.games;
package org.telegram.telegrambots.meta.api.methods.games;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.io.Serializable;
import java.util.Objects;
/**
* @author Ruben Bermudez

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,13 +1,13 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.Chat;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.Chat;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,13 +1,13 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.ChatMember;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.ChatMember;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.ArrayList;

View File

@ -1,13 +1,13 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.ChatMember;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.ChatMember;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,12 +1,12 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,12 +1,12 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,12 +1,12 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,10 +1,10 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.File;
import java.io.IOException;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,12 +1,12 @@
package org.telegram.telegrambots.api.methods.groupadministration;
package org.telegram.telegrambots.meta.api.methods.groupadministration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.pinnedmessages;
package org.telegram.telegrambots.meta.api.methods.pinnedmessages;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -1,11 +1,11 @@
package org.telegram.telegrambots.api.methods.pinnedmessages;
package org.telegram.telegrambots.meta.api.methods.pinnedmessages;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;

View File

@ -0,0 +1,247 @@
package org.telegram.telegrambots.meta.api.methods.send;
import com.fasterxml.jackson.core.type.TypeReference;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.objects.InputFile;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ApiResponse;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
/**
* @author Ruben Bermudez
* @version 4.0.0
* Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
* On success, the sent Message is returned.
*
* Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
*/
public class SendAnimation extends PartialBotApiMethod<Message> {
public static final String PATH = "sendAnimation";
public static final String CHATID_FIELD = "chat_id";
public static final String ANIMATION_FIELD = "animation";
public static final String DURATION_FIELD = "duration";
public static final String WIDTH_FIELD = "width";
public static final String HEIGHT_FIELD = "height";
public static final String CAPTION_FIELD = "caption";
public static final String PARSEMODE_FIELD = "parse_mode";
public static final String DISABLENOTIFICATION_FIELD = "disable_notification";
public static final String REPLYTOMESSAGEID_FIELD = "reply_to_message_id";
public static final String REPLYMARKUP_FIELD = "reply_markup";
public static final String THUMB_FIELD = "thumb";
private String chatId; ///< Unique identifier for the chat to send the message to (Or username for channels)
/**
* Animation to send. Pass a file_id as String to send an animation that exists on the
* Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an animation
* from the Internet, or upload a new animation using multipart/form-data.
*/
private InputFile animation;
private Integer duration; ///< Optional. Duration of sent animation in seconds
private String caption; ///< OptionaL. Animation caption (may also be used when resending videos by file_id).
private Integer width; ///< Optional. Animation width
private Integer height; ///< OptionaL. Animation height
private Boolean disableNotification; ///< Optional. Sends the message silently. Users will receive a notification with no sound.
private Integer replyToMessageId; ///< Optional. If the message is a reply, ID of the original message
private ReplyKeyboard replyMarkup; ///< Optional. JSON-serialized object for a custom reply keyboard
private String parseMode; ///< Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.
/**
* Thumbnail of the file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
* A thumbnails width and height should not exceed 90.
* Ignored if the file is not uploaded using multipart/form-data.
* Thumbnails cant be reused and can be only uploaded as a new file, so you can pass attach://<file_attach_name>
* if the thumbnail was uploaded using multipart/form-data under <file_attach_name>.
*/
private InputFile thumb;
public SendAnimation() {
super();
}
public String getChatId() {
return chatId;
}
public SendAnimation setChatId(String chatId) {
this.chatId = chatId;
return this;
}
public InputFile getAnimation() {
return animation;
}
public SendAnimation setAnimation(String animation) {
this.animation = new InputFile(animation);
return this;
}
public SendAnimation setChatId(Long chatId) {
Objects.requireNonNull(chatId);
this.chatId = chatId.toString();
return this;
}
public Integer getDuration() {
return duration;
}
public SendAnimation setDuration(Integer duration) {
this.duration = duration;
return this;
}
public String getCaption() {
return caption;
}
public SendAnimation setCaption(String caption) {
this.caption = caption;
return this;
}
public Integer getReplyToMessageId() {
return replyToMessageId;
}
public SendAnimation setReplyToMessageId(Integer replyToMessageId) {
this.replyToMessageId = replyToMessageId;
return this;
}
public ReplyKeyboard getReplyMarkup() {
return replyMarkup;
}
public SendAnimation setReplyMarkup(ReplyKeyboard replyMarkup) {
this.replyMarkup = replyMarkup;
return this;
}
public Boolean getDisableNotification() {
return disableNotification;
}
public SendAnimation enableNotification() {
this.disableNotification = false;
return this;
}
public SendAnimation disableNotification() {
this.disableNotification = true;
return this;
}
public Integer getWidth() {
return width;
}
public SendAnimation setWidth(Integer width) {
this.width = width;
return this;
}
public Integer getHeight() {
return height;
}
public SendAnimation setHeight(Integer height) {
this.height = height;
return this;
}
public SendAnimation setAnimation(File file) {
this.animation = new InputFile(file, file.getName());
return this;
}
public SendAnimation setAnimation(String animationName, InputStream inputStream) {
Objects.requireNonNull(animationName, "animationName cannot be null!");
Objects.requireNonNull(inputStream, "inputStream cannot be null!");
this.animation = new InputFile(inputStream, animationName);
return this;
}
public SendAnimation setAnimation(InputFile animation) {
Objects.requireNonNull(animation, "animation cannot be null!");
this.animation = animation;
return this;
}
public String getParseMode() {
return parseMode;
}
public SendAnimation setParseMode(String parseMode) {
this.parseMode = parseMode;
return this;
}
public InputFile getThumb() {
return thumb;
}
public SendAnimation setThumb(InputFile thumb) {
this.thumb = thumb;
return this;
}
@Override
public Message deserializeResponse(String answer) throws TelegramApiRequestException {
try {
ApiResponse<Message> result = OBJECT_MAPPER.readValue(answer,
new TypeReference<ApiResponse<Message>>(){});
if (result.getOk()) {
return result.getResult();
} else {
throw new TelegramApiRequestException("Error sending animation", result);
}
} catch (IOException e) {
throw new TelegramApiRequestException("Unable to deserialize response", e);
}
}
@Override
public void validate() throws TelegramApiValidationException {
if (chatId == null) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
}
if (animation == null) {
throw new TelegramApiValidationException("Animation parameter can't be empty", this);
}
animation.validate();
if (replyMarkup != null) {
replyMarkup.validate();
}
if (thumb != null) {
thumb.validate();
}
}
@Override
public String toString() {
return "SendAnimation{" + "chatId='" + chatId + '\'' +
", animation=" + animation +
", duration=" + duration +
", caption='" + caption + '\'' +
", width=" + width +
", height=" + height +
", disableNotification=" + disableNotification +
", replyToMessageId=" + replyToMessageId +
", replyMarkup=" + replyMarkup +
", parseMode='" + parseMode + '\'' +
", thumb=" + thumb +
'}';
}
}

Some files were not shown because too many files have changed in this diff Show More