Right now, if we want to update Telegram webhook url, we have to send a GET request manually. We can create a settings page for managing webhook URL easier.

We also need to implement user authentication to ensure that only administrators can access the page. It’s a simple task with Google Sign-In.

For this post, we will focus on creating settings page with admin authentication.

main.py

Add new extended routes for settings page. (Read More)

  • login: show sign in form
  • logout: log user out to home page
  • 403: show forbidden message
app = webapp2.WSGIApplication([
    webapp2.Route('/login', base.LoginHandler, name='login'),
    webapp2.Route('/logout', base.LogoutHandler, name='logout'),
    webapp2.Route('/403', base.Page403, name='403'),
    ('/', base.MainPage),
    ('/about', base.AboutPage),
    ('/settings', base.SettingsPage),
    ('/set_webhook', bot.SetWebhookHandler),
    ('/get_webhook', bot.GetWebhookHandler),
    ('/webhook', bot.WebhookHandler),
], debug=True)

base.py

Add settings, login, logout and 403 page handler classes.

We create __admin_required decorator to check for admin user when accessing settings page. It will compare login user email with a predefined list of admin emails.

[...]
from google.appengine.api import users

[...]
class SettingsPage(Handler):
    def __admin_required(func):
        def func_wrapper(self, *args, **kwargs):
            user = users.get_current_user()
            if user:
                email = user.email()
                admins = [
                    "admin1@gmail.com",
                    "admin2@gmail.com"
                ]
                if email in admins:
                    return func(self, *args, **kwargs)
                else:
                    return webapp2.redirect_to("403")
            else:
                return webapp2.redirect_to("login")
        return func_wrapper

    @__admin_required
    def get(self):
        kwargs = {
            'title': 'Settings',
        }
        self.render_template('settings.html', **kwargs)


class LoginHandler(Handler):
    def get(self):
        self.redirect(users.create_login_url('/'))


class LogoutHandler(Handler):
    def get(self):
        self.redirect(users.create_logout_url('/'))


class Page403(Handler):
    def get(self):
        kwargs = {
            'title': '403 Forbidden',
        }
        self.render_template('403.html', **kwargs)

home.html

Add settings menu item to home navigation bar.

{% set navbar_menus = [
    ('/', 'home', 'Home'),
    ('/about', 'about', 'About'),
    ('/settings', 'settings', 'Settings'),
] -%}

settings.html

{% extends "base.html" %}
{% set active_page = "settings" %}

{% block main_content %}
<h1 class="mt-5">Settings page for Admin only!</h1>
<a href="/logout">Logout</a>
{% endblock main_content %}

403.html

<!DOCTYPE html>
<html lang="en">
<head>
    <title></title>
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <!-- Custom styles for this template -->
    <link href="/static/css/style.css" rel="stylesheet">
</head>
<body>
	<div class="container">
		<img class="img-fluid rounded mx-auto d-block" src="https://i.imgur.com/p4kY38n.gif"/>
	</div>
</body>
</html>

Result

Settings Page