Uh oh!
There was an error while loading. Please reload this page.
forked from jsmnbom/githubbotrevised
- Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmain.py
More file actions
Latest commit
198 lines (157 loc) · 9.28 KB
/
Copy pathmain.py
File metadata and controls
198 lines (157 loc) · 9.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
importhttp.client
importlogging
fromrequestsimportHTTPError
fromtelegramimportUpdate, ParseMode, InlineKeyboardMarkup, InlineKeyboardButton, Chat
fromtelegram.extimportTypeHandler, CallbackContext, CommandHandler, MessageHandler, Filters
frombotimportsettings
frombot.constimportTELEGRAM_BOT_TOKEN, DATABASE_FILE, DEBUG
frombot.githubimportGithubHandler
frombot.githubapiimportgithub_api
frombot.githubupdatesimportGithubUpdate, GithubAuthUpdate
frombot.menuimportreply_menu
frombot.persistenceimportPersistence
frombot.utilsimportdecode_first_data_entity, deep_link, reply_data_link_filter
frombot.webhookupdaterimportWebhookUpdater
ifDEBUG:
http.client.HTTPConnection.debuglevel=5
logging.basicConfig(level=logging.DEBUGifDEBUGelselogging.INFO,
# [%(filename)s:%(lineno)d]
format='%(asctime)s %(levelname)-8s %(name)s - %(message)s')
deferror_handler(update, context: CallbackContext):
logging.warning('Update "%s" caused error "%s"'% (update, context.error))
defstart_handler(update: Update, context: CallbackContext):
msg=update.effective_message
# For deep linking
ifcontext.args:
# Get the deep link argument and treat it as a command
args=context.args[0].split('__')
update.effective_message.text='/'+' '.join(args)
update.effective_message.entities[0].length=len(args[0]) +1
context.update_queue.put(update)
return
msg.reply_text(f'👋 Hello, I am {context.bot.name}.\n'
f'I can notify you about events in your public GitHub repositories. '
f'You can also reply to my messages to post comments to GitHub right from Telegram. '
f'I am an improved version of the Telegram GitHub Bot.\n\n'
f'Use /settings to get started.',
disable_notification=True)
defhelp_handler(update: Update, context: CallbackContext):
msg=update.effective_message
private=update.effective_chat.type==Chat.PRIVATE
steps= [
f'First you must allow me access to the repositories in question. To do this, <a href="https://github.com/apps/ptb-github-bridge/installations/new">install</a> my <a href="https://github.com/apps/ptb-github-bridge">GitHub App</a> on your account or organisation, and make sure that it has access to the desired repositories.',
f'Use the command /settings to open my settings interface and press the login button. This way I will know who you are.',
f'Add me ({context.bot.name}) to the chat/group in which you would like to receive notifications.',
f'In that chat use /settings to add the repositories you would like to receive notifications for.'
]
ifnotprivate:
steps.insert(1, f'Go to a private chat with me, by clicking here: {context.bot.name}.')
text='\n\n'.join(f'{i+1}️⃣ {step}'fori, stepinenumerate(steps))
msg.reply_text(f'<b>Github notification guide.</b>\n\n{text}\n\n'
f'Note that GitHub Help has more in depth guides on how to install GitHub Apps <a href="https://help.github.com/articles/installing-an-app-in-your-personal-account/#installing-a-github-app-in-your-personal-account">in your personal account</a> or <a href="https://help.github.com/articles/installing-an-app-in-your-organization/#installing-a-github-app-in-your-organization">in your organisation</a> if you are having trouble with step 1.',
reply_markup=InlineKeyboardMarkup([
[InlineKeyboardButton('Add me to a group',
url=f'https://telegram.me/{context.bot.username}?startgroup=start')]
]),
parse_mode=ParseMode.HTML,
disable_web_page_preview=True,
disable_notification=True)
defprivacy_handler(update: Update, context: CallbackContext):
msg=update.effective_message
msg.reply_text(
f'🔏 Privacy policy for {context.bot.name}\n\n'
f'GithubBot Revised is an open source bot built by <a href="https://telegram.me/jsmnbom">Jasmin Bom</a>.\n\n'
f'GithubBot revised stores GitHub login tokens - if you logout they will be deleted from the server.\n'
f'To prevent overloading GitHub servers, data received from GitHub is also cached according to GitHub server headers.\n\n'
f'THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT '
f'LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. '
f'IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, '
f'WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE '
f'OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'
f'The MIT-licensed source code for GithubBot revised can be found at <a href="https://github.com/jsmnbom/githubbotrevised">GitHub</a>.',
parse_mode=ParseMode.HTML,
disable_web_page_preview=True,
disable_notification=True
)
deflogin_handler(update: Update, context):
context.menu_stack= ['settings']
reply_menu(update, context, settings.login_menu)
defdelete_job(context: CallbackContext):
context.job.context.delete()
defreply_handler(update: Update, context: CallbackContext):
msg=update.effective_message
ifmsg.text[0] =='!':
return
data=decode_first_data_entity(msg.reply_to_message.entities)
ifnotdata:
return
comment_type, *data=data
access_token=context.user_data.get('access_token')
ifnotaccess_token:
sent_msg=msg.reply_text(f'Cannot reply to {comment_type}, since you are not logged in. '
f'Press button below to go to a private chat with me and login.\n\n'
f'<i>This message will self destruct in 30 sec.</i>',
reply_markup=InlineKeyboardMarkup([[
InlineKeyboardButton('Login', url=deep_link(context.bot, 'login'))
]]),
parse_mode=ParseMode.HTML,
disable_notification=True)
context.job_queue.run_once(delete_job, 30, sent_msg)
return
ifcomment_type=='discussion':
sent_msg=msg.reply_text(f'Cannot reply discussions.\n\n'
f'<i>This message will self destruct in 30 sec.</i>',
parse_mode=ParseMode.HTML,
disable_notification=True)
context.job_queue.run_once(delete_job, 30, sent_msg)
return
try:
ifcomment_typein ('issue', 'pull request'):
repo, number, author=data
text=f'@{author}{msg.text_html}'
github_api.add_issue_comment(repo, number, text, access_token=access_token)
elifcomment_type=='pull request review comment':
repo, number, comment_id, author=data
text=f'@{author}{msg.text_html}'
github_api.add_review_comment(repo, number, comment_id, text, access_token=access_token)
exceptHTTPErrorasexc:
if"Unauthorized for url"notinstr(exc):
raiseexc
context.user_data.pop('access_token', None)
msg.reply_text(
f'Cannot reply to {comment_type}, since your login token is no longer valid. '
f'Press button below to go to a private chat with me and login again.\n\n'
f'<i>This message will self destruct in 30 sec.</i>',
reply_markup=InlineKeyboardMarkup([[
InlineKeyboardButton('Login', url=deep_link(context.bot, 'login'))
]]),
parse_mode=ParseMode.HTML,
disable_notification=True
)
if__name__=='__main__':
# Not strictly needed anymore since we no longer have custom persistent data
# But since we likely will want it in the future, we keep our custom persistence
persistence=Persistence(DATABASE_FILE)
# Init our very custom webhook handler
updater=WebhookUpdater(TELEGRAM_BOT_TOKEN,
updater_kwargs={'use_context': True,
'persistence': persistence})
dp=updater.dispatcher
# See persistence note above
CallbackContext.github_data=property(lambdaself: persistence.github_data)
# Save data every five (5) min
dp.job_queue.run_repeating(lambda*_: persistence.flush(), 5*60)
# Telegram updates
dp.add_handler(CommandHandler('start', start_handler))
dp.add_handler(CommandHandler('help', help_handler))
dp.add_handler(CommandHandler('privacy', privacy_handler))
dp.add_handler(CommandHandler('login', login_handler))
settings.add_handlers(dp)
# For commenting on issues/PR/reviews
dp.add_handler(MessageHandler(Filters.reply&reply_data_link_filter, reply_handler))
# Non-telegram updates
github_handler=GithubHandler(dp)
dp.add_handler(TypeHandler(GithubUpdate, github_handler.handle_update))
dp.add_handler(TypeHandler(GithubAuthUpdate, github_handler.handle_auth_update))
dp.add_error_handler(error_handler)
updater.start()