JoostSijm 5 rokov pred
commit
ca88ef66b8
9 zmenil súbory, kde vykonal 591 pridanie a 0 odobranie
  1. 4 0
      .gitignore
  2. 18 0
      Pipfile
  3. 251 0
      Pipfile.lock
  4. 60 0
      app/__init__.py
  5. 73 0
      app/__main__.py
  6. 94 0
      app/conversations/add_account.py
  7. 27 0
      app/database.py
  8. 59 0
      app/models.py
  9. 5 0
      example.env

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+__pycache__/
+.venv/
+.env
+*.log

+ 18 - 0
Pipfile

@@ -0,0 +1,18 @@
+[[source]]
+name = "pypi"
+url = "https://pypi.org/simple"
+verify_ssl = true
+
+[dev-packages]
+
+[packages]
+requests = "*"
+beautifulsoup4 = "*"
+sqlalchemy = "*"
+psycopg2-binary = "*"
+python-dotenv = "*"
+apscheduler = "*"
+python-telegram-bot = "*"
+
+[requires]
+python_version = "3"

+ 251 - 0
Pipfile.lock

@@ -0,0 +1,251 @@
+{
+    "_meta": {
+        "hash": {
+            "sha256": "4827bab3abdc69cd1319b4ad833d48439e8a040a4fb264ea0abe65ffa41d8dd7"
+        },
+        "pipfile-spec": 6,
+        "requires": {
+            "python_version": "3"
+        },
+        "sources": [
+            {
+                "name": "pypi",
+                "url": "https://pypi.org/simple",
+                "verify_ssl": true
+            }
+        ]
+    },
+    "default": {
+        "apscheduler": {
+            "hashes": [
+                "sha256:3bb5229eed6fbbdafc13ce962712ae66e175aa214c69bed35a06bffcf0c5e244",
+                "sha256:e8b1ecdb4c7cb2818913f766d5898183c7cb8936680710a4d3a966e02262e526"
+            ],
+            "index": "pypi",
+            "version": "==3.6.3"
+        },
+        "beautifulsoup4": {
+            "hashes": [
+                "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a",
+                "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887",
+                "sha256:e1505eeed31b0f4ce2dbb3bc8eb256c04cc2b3b72af7d551a4ab6efd5cbe5dae"
+            ],
+            "index": "pypi",
+            "version": "==4.8.2"
+        },
+        "certifi": {
+            "hashes": [
+                "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3",
+                "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"
+            ],
+            "version": "==2019.11.28"
+        },
+        "cffi": {
+            "hashes": [
+                "sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42",
+                "sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04",
+                "sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5",
+                "sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54",
+                "sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba",
+                "sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57",
+                "sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396",
+                "sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12",
+                "sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97",
+                "sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43",
+                "sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db",
+                "sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3",
+                "sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b",
+                "sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579",
+                "sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346",
+                "sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159",
+                "sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652",
+                "sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e",
+                "sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a",
+                "sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506",
+                "sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f",
+                "sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d",
+                "sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c",
+                "sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20",
+                "sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858",
+                "sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc",
+                "sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a",
+                "sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3",
+                "sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e",
+                "sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410",
+                "sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25",
+                "sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b",
+                "sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d"
+            ],
+            "version": "==1.13.2"
+        },
+        "chardet": {
+            "hashes": [
+                "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
+                "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
+            ],
+            "version": "==3.0.4"
+        },
+        "cryptography": {
+            "hashes": [
+                "sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c",
+                "sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595",
+                "sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad",
+                "sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651",
+                "sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2",
+                "sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff",
+                "sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d",
+                "sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42",
+                "sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d",
+                "sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e",
+                "sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912",
+                "sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793",
+                "sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13",
+                "sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7",
+                "sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0",
+                "sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879",
+                "sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f",
+                "sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9",
+                "sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2",
+                "sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf",
+                "sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8"
+            ],
+            "version": "==2.8"
+        },
+        "future": {
+            "hashes": [
+                "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
+            ],
+            "version": "==0.18.2"
+        },
+        "idna": {
+            "hashes": [
+                "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
+                "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
+            ],
+            "version": "==2.8"
+        },
+        "psycopg2-binary": {
+            "hashes": [
+                "sha256:040234f8a4a8dfd692662a8308d78f63f31a97e1c42d2480e5e6810c48966a29",
+                "sha256:086f7e89ec85a6704db51f68f0dcae432eff9300809723a6e8782c41c2f48e03",
+                "sha256:18ca813fdb17bc1db73fe61b196b05dd1ca2165b884dd5ec5568877cabf9b039",
+                "sha256:19dc39616850342a2a6db70559af55b22955f86667b5f652f40c0e99253d9881",
+                "sha256:2166e770cb98f02ed5ee2b0b569d40db26788e0bf2ec3ae1a0d864ea6f1d8309",
+                "sha256:3a2522b1d9178575acee4adf8fd9f979f9c0449b00b4164bb63c3475ea6528ed",
+                "sha256:3aa773580f85a28ffdf6f862e59cb5a3cc7ef6885121f2de3fca8d6ada4dbf3b",
+                "sha256:3b5deaa3ee7180585a296af33e14c9b18c218d148e735c7accf78130765a47e3",
+                "sha256:407af6d7e46593415f216c7f56ba087a9a42bd6dc2ecb86028760aa45b802bd7",
+                "sha256:4c3c09fb674401f630626310bcaf6cd6285daf0d5e4c26d6e55ca26a2734e39b",
+                "sha256:4c6717962247445b4f9e21c962ea61d2e884fc17df5ddf5e35863b016f8a1f03",
+                "sha256:50446fae5681fc99f87e505d4e77c9407e683ab60c555ec302f9ac9bffa61103",
+                "sha256:5057669b6a66aa9ca118a2a860159f0ee3acf837eda937bdd2a64f3431361a2d",
+                "sha256:5dd90c5438b4f935c9d01fcbad3620253da89d19c1f5fca9158646407ed7df35",
+                "sha256:659c815b5b8e2a55193ede2795c1e2349b8011497310bb936da7d4745652823b",
+                "sha256:69b13fdf12878b10dc6003acc8d0abf3ad93e79813fd5f3812497c1c9fb9be49",
+                "sha256:7a1cb80e35e1ccea3e11a48afe65d38744a0e0bde88795cc56a4d05b6e4f9d70",
+                "sha256:7e6e3c52e6732c219c07bd97fff6c088f8df4dae3b79752ee3a817e6f32e177e",
+                "sha256:7f42a8490c4fe854325504ce7a6e4796b207960dabb2cbafe3c3959cb00d1d7e",
+                "sha256:84156313f258eafff716b2961644a4483a9be44a5d43551d554844d15d4d224e",
+                "sha256:8578d6b8192e4c805e85f187bc530d0f52ba86c39172e61cd51f68fddd648103",
+                "sha256:890167d5091279a27e2505ff0e1fb273f8c48c41d35c5b92adbf4af80e6b2ed6",
+                "sha256:98e10634792ac0e9e7a92a76b4991b44c2325d3e7798270a808407355e7bb0a1",
+                "sha256:9aadff9032e967865f9778485571e93908d27dab21d0fdfdec0ca779bb6f8ad9",
+                "sha256:9f24f383a298a0c0f9b3113b982e21751a8ecde6615494a3f1470eb4a9d70e9e",
+                "sha256:a73021b44813b5c84eda4a3af5826dd72356a900bac9bd9dd1f0f81ee1c22c2f",
+                "sha256:afd96845e12638d2c44d213d4810a08f4dc4a563f9a98204b7428e567014b1cd",
+                "sha256:b73ddf033d8cd4cc9dfed6324b1ad2a89ba52c410ef6877998422fcb9c23e3a8",
+                "sha256:b8f490f5fad1767a1331df1259763b3bad7d7af12a75b950c2843ba319b2415f",
+                "sha256:dbc5cd56fff1a6152ca59445178652756f4e509f672e49ccdf3d79c1043113a4",
+                "sha256:eac8a3499754790187bb00574ab980df13e754777d346f85e0ff6df929bcd964",
+                "sha256:eaed1c65f461a959284649e37b5051224f4db6ebdc84e40b5e65f2986f101a08"
+            ],
+            "index": "pypi",
+            "version": "==2.8.4"
+        },
+        "pycparser": {
+            "hashes": [
+                "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
+            ],
+            "version": "==2.19"
+        },
+        "python-dotenv": {
+            "hashes": [
+                "sha256:440c7c23d53b7d352f9c94d6f70860242c2f071cf5c029dd661ccb22d64ae42b",
+                "sha256:f254bfd0c970d64ccbb6c9ebef3667ab301a71473569c991253a481f1c98dddc"
+            ],
+            "index": "pypi",
+            "version": "==0.10.5"
+        },
+        "python-telegram-bot": {
+            "hashes": [
+                "sha256:41608512a3025a04ff7472efcaae344ad7533a77ae207685bb10fc2fc8282f7b",
+                "sha256:5e2156f829402e41bb5ea7196e450bf7f121c5689c5100ae180507d72f3777f5"
+            ],
+            "index": "pypi",
+            "version": "==12.3.0"
+        },
+        "pytz": {
+            "hashes": [
+                "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
+                "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
+            ],
+            "version": "==2019.3"
+        },
+        "requests": {
+            "hashes": [
+                "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
+                "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
+            ],
+            "index": "pypi",
+            "version": "==2.22.0"
+        },
+        "six": {
+            "hashes": [
+                "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
+                "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
+            ],
+            "version": "==1.14.0"
+        },
+        "soupsieve": {
+            "hashes": [
+                "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5",
+                "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"
+            ],
+            "version": "==1.9.5"
+        },
+        "sqlalchemy": {
+            "hashes": [
+                "sha256:64a7b71846db6423807e96820993fa12a03b89127d278290ca25c0b11ed7b4fb"
+            ],
+            "index": "pypi",
+            "version": "==1.3.13"
+        },
+        "tornado": {
+            "hashes": [
+                "sha256:349884248c36801afa19e342a77cc4458caca694b0eda633f5878e458a44cb2c",
+                "sha256:398e0d35e086ba38a0427c3b37f4337327231942e731edaa6e9fd1865bbd6f60",
+                "sha256:4e73ef678b1a859f0cb29e1d895526a20ea64b5ffd510a2307b5998c7df24281",
+                "sha256:559bce3d31484b665259f50cd94c5c28b961b09315ccd838f284687245f416e5",
+                "sha256:abbe53a39734ef4aba061fca54e30c6b4639d3e1f59653f0da37a0003de148c7",
+                "sha256:c845db36ba616912074c5b1ee897f8e0124df269468f25e4fe21fe72f6edd7a9",
+                "sha256:c9399267c926a4e7c418baa5cbe91c7d1cf362d505a1ef898fde44a07c9dd8a5"
+            ],
+            "version": "==6.0.3"
+        },
+        "tzlocal": {
+            "hashes": [
+                "sha256:11c9f16e0a633b4b60e1eede97d8a46340d042e67b670b290ca526576e039048",
+                "sha256:949b9dd5ba4be17190a80c0268167d7e6c92c62b30026cf9764caf3e308e5590"
+            ],
+            "version": "==2.0.0"
+        },
+        "urllib3": {
+            "hashes": [
+                "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
+                "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"
+            ],
+            "version": "==1.25.8"
+        }
+    },
+    "develop": {}
+}

+ 60 - 0
app/__init__.py

@@ -0,0 +1,60 @@
+"""Initialize application"""
+
+import os
+import logging
+
+from dotenv import load_dotenv
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+from apscheduler.schedulers.background import BackgroundScheduler
+import telegram
+from telegram.ext import Updater
+
+
+load_dotenv()
+
+# get logger
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+TELEGRAM_LOGGER = logging.getLogger('telegram')
+TELEGRAM_LOGGER.setLevel(logging.DEBUG)
+
+# create file handler
+FILE_HANDLER = logging.FileHandler('output.log')
+FILE_HANDLER.setLevel(logging.DEBUG)
+
+# create console handler
+STREAM_HANDLER = logging.StreamHandler()
+STREAM_HANDLER.setLevel(logging.DEBUG)
+
+# create formatter and add it to the handlers
+FORMATTER = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+STREAM_HANDLER.setFormatter(FORMATTER)
+FILE_HANDLER.setFormatter(FORMATTER)
+
+# add the handlers to logger
+LOGGER.addHandler(STREAM_HANDLER)
+LOGGER.addHandler(FILE_HANDLER)
+TELEGRAM_LOGGER.addHandler(STREAM_HANDLER)
+TELEGRAM_LOGGER.addHandler(FILE_HANDLER)
+
+# database
+ENGINE = create_engine(os.environ["DATABASE_URI"])
+SESSION = sessionmaker(bind=ENGINE)
+
+# scheduler
+SCHEDULER = BackgroundScheduler(
+    daemon=True,
+    job_defaults={'misfire_grace_time': 300},
+)
+SCHEDULER.start()
+
+TELEGRAM_KEY = os.environ['TELEGRAM_KEY']
+BOT = telegram.Bot(token=TELEGRAM_KEY)
+UPDATER = Updater(TELEGRAM_KEY, use_context=True)
+
+# api
+BASE_URL = os.environ["API_URL"]
+HEADERS = {
+    'Authorization': os.environ["API_AUTHORIZATION"]
+}

+ 73 - 0
app/__main__.py

@@ -0,0 +1,73 @@
+"""Telegram bot"""
+
+import re
+
+from telegram import ParseMode
+from telegram.ext import MessageHandler, CommandHandler, Filters, ConversationHandler, RegexHandler
+
+from app import LOGGER, BOT, UPDATER
+
+from app import database
+from app.conversations.add_account import ADD_ACCOUNT_CONV
+
+
+def cmd_start(update, context):
+    """Start command"""
+    update.message.reply_text(
+        'Hello {},\ntype /help for a list of commands'.format(update.message.from_user.first_name))
+
+def cmd_help(update, context):
+    """Help command"""
+    message_list = [
+        '**Command list**',
+        '/accounts - list of accounts',
+        '/add\\_account - add account to list',
+    ]
+    message = '\n'.join(message_list)
+    print(message)
+    update.message.reply_text(message, parse_mode=ParseMode.MARKDOWN)
+
+def cmd_accounts(update, context):
+    """Return account list"""
+    accounts = database.get_rr_accounts(update.message.from_user.id)
+    message_list = ['Accounts verified to this Telgeram account:']
+    for account in accounts:
+        # name = re.sub(r'\[.*\]\s', '', account.name)
+        desktop_link = '[desktop](https://rivalregions.com/#slide/profile/{})'.format(account.id)
+        mobile_link = '[mobile](https://m.rivalregions.com/#slide/profile/{})'.format(account.id)
+        message_list.append(
+            '• {} {} - {}'.format(
+                escape_text(account.name),
+                desktop_link,
+                mobile_link,
+            )
+        )
+    message = '\n'.join(message_list)
+    update.message.reply_text(message, parse_mode=ParseMode.MARKDOWN)
+
+def escape_text(text):
+    """Escape text"""
+    return text \
+        .replace("_", "\\_") \
+        .replace("*", "\\*") \
+        .replace("[", "\\[") \
+        .replace("`", "\\`")
+
+def main():
+    """Main function"""
+    dispatcher = UPDATER.dispatcher
+
+    # general commands
+    dispatcher.add_handler(CommandHandler('start', cmd_start))
+    dispatcher.add_handler(CommandHandler('help', cmd_help))
+
+    # account commaonds
+    dispatcher.add_handler(CommandHandler('accounts', cmd_accounts))
+
+    dispatcher.add_handler(ADD_ACCOUNT_CONV)
+
+    UPDATER.start_polling()
+    UPDATER.idle()
+
+if __name__ == '__main__':
+    main()

+ 94 - 0
app/conversations/add_account.py

@@ -0,0 +1,94 @@
+"""Add account conversation"""
+
+from telegram import ParseMode
+from telegram.ext import MessageHandler, CommandHandler, Filters, ConversationHandler, RegexHandler
+
+
+ACCOUNT_ID, CONFIRM, VERIFICATION = range(3)
+
+def conv_ask_account_id(update, context):
+    """Ask account id"""
+    update.message.reply_text('What\'s your Rival Regions acount ID?')
+    return ACCOUNT_ID
+
+def conv_error_ask_account_id(update, context):
+    """Ask max resource"""
+    incorrect_input = update.message.text
+    update.message.reply_text(
+        '{}, I don\'t recognize that. What\'s your Rival Regions account ID?'.format(
+            incorrect_input
+        ),
+    )
+    return ACCOUNT_ID
+
+def conv_account_id_confirm(update, context):
+    """Sending announcement"""
+    account_id = update.message.text
+
+    message_list = [
+        '**Account details**',
+        'ID: {}'.format(account_id),
+        'Name: {}'.format(account_id),
+        'Region: {}'.format(account_id),
+        'Residency: {}'.format(account_id),
+        '\nPlease confirm this is your account by typing \'confirm\'',
+    ]
+
+    update.message.reply_text(
+        '\n'.join(message_list),
+        parse_mode=ParseMode.MARKDOWN
+    )
+    return CONFIRM
+
+def conv_verification(update, context):
+    """Sending announcement"""
+    update.message.reply_text(
+        'Verification code send to your Rival Region account ' + \
+        'Check your personal messages for a verification code and send it here.',
+        parse_mode=ParseMode.MARKDOWN
+    )
+    return VERIFICATION
+
+def conv_finish(update, context):
+    """Sending announcement"""
+    update.message.reply_text(
+        'Verificated your Rival Region account to Telegram',
+        parse_mode=ParseMode.MARKDOWN
+    )
+    return ConversationHandler.END
+
+def conv_error_finish(update, context):
+    """Ask max resource"""
+    incorrect_input = update.message.text
+    update.message.reply_text(
+        '"{}" not recognized. Send me the verification code.\n/cancel to cancel'.format(
+            incorrect_input
+        ),
+    )
+    return VERIFICATION
+    
+def conv_cancel(update, context):
+    """Cancel announcement"""
+    update.message.reply_text('Canceled action.')
+    context.user_data.clear()
+    return ConversationHandler.END
+
+# announcement conversation
+ADD_ACCOUNT_CONV = ConversationHandler(
+    entry_points=[CommandHandler('add_account', conv_ask_account_id)],
+    states={
+        ACCOUNT_ID: [
+            RegexHandler(r'^\d*$', conv_account_id_confirm),
+            MessageHandler(Filters.text, conv_error_ask_account_id),
+        ],
+        CONFIRM: [
+            MessageHandler(Filters.regex('confirm'), conv_verification),
+            MessageHandler(Filters.text, conv_cancel),
+        ],
+        VERIFICATION: [
+            MessageHandler(Filters.regex(r'^([a-z]|\d)+$'), conv_finish),
+            MessageHandler(Filters.text, conv_error_finish),
+        ],
+    },
+    fallbacks=[CommandHandler('cancel', conv_cancel)]
+)

+ 27 - 0
app/database.py

@@ -0,0 +1,27 @@
+"""Database functons"""
+
+from app import SESSION
+from app.models import Player, TelegramAccount, TelegramHandle, PlayerTelegram, TelegramVerification
+
+
+def get_telegram_account(telegram_id):
+    """Get Telegram account"""
+    session = SESSION()
+    telegram_account = _get_telegram_account(session, telegram_id)
+    session.close()
+    return telegram_account
+
+def _get_telegram_account(session, telegram_id):
+    """Return telegram_account"""
+    return session.query(TelegramAccount).get(telegram_id)
+
+def get_rr_accounts(telegram_id):
+    """Get Rival Region accounts associated with Telegram account"""
+    session = SESSION()
+    telegram_account = _get_telegram_account(session, telegram_id)
+    rr_accounts = session.query(Player) \
+        .join(Player.player_telegram) \
+        .filter(PlayerTelegram.telegram_id == telegram_account.id) \
+        .all()
+    session.close()
+    return rr_accounts

+ 59 - 0
app/models.py

@@ -0,0 +1,59 @@
+"""Database models"""
+
+from sqlalchemy import Column, ForeignKey, Integer, String, \
+    DateTime, BigInteger, Date, Boolean
+from sqlalchemy.orm import relationship, backref
+from sqlalchemy.ext.declarative import declarative_base
+
+
+Base = declarative_base()
+
+class Player(Base):
+    """Model for player"""
+    __tablename__ = 'player'
+    id = Column(BigInteger, primary_key=True)
+    name = Column(String)
+    nation = Column(String)
+    registration_date = Column(Date)
+
+class TelegramAccount(Base):
+    """Model for Telegram account"""
+    __tablename__ = 'telegram_account'
+    id = Column(BigInteger, primary_key=True)
+    name = Column(String)
+    registration_date = Column(DateTime)
+
+class TelegramHandle(Base):
+    """Model for Telegram handle"""
+    __tablename__ = 'telegram_handle'
+    id = Column(Integer, primary_key=True)
+    handle = Column(String)
+    registration_date = Column(DateTime)
+
+    telegram_account_id = Column(BigInteger, ForeignKey('telegram_account.id'))
+    telegram_account = relationship(
+        'TelegramAccount',
+        backref=backref('account_handles', lazy='dynamic')
+    )
+
+class PlayerTelegram(Base):
+    """Model for belongs to"""
+    __tablename__ = 'player_telegram'
+    player_id = Column(BigInteger, ForeignKey('player.id'), primary_key=True)
+    telegram_id = Column(BigInteger, ForeignKey('telegram_account.id'), primary_key=True)
+    from_date_time = Column(DateTime, primary_key=True)
+    until_date_time = Column(DateTime)
+
+    player = relationship(
+        'Player',
+        backref=backref('player_telegram', lazy='dynamic')
+    )
+
+class TelegramVerification(Base):
+    """Model for Telegram verification"""
+    __tablename__ = 'telegram_verification'
+    player_id = Column(BigInteger, ForeignKey('player.id'), primary_key=True)
+    telegram_id = Column(BigInteger, ForeignKey('telegram_account.id'), primary_key=True)
+    code = Column(String)
+    date_time = Column(DateTime)
+    confirmed = Column(Boolean, server_default='f', default=False)

+ 5 - 0
example.env

@@ -0,0 +1,5 @@
+# test
+TELEGRAM_KEY=
+DATABASE_URI='postgresql://vboo@localhost/vboo'
+API_AUTHORIZATION=
+API_URL='http://localhost:5000/api/request/'