Package: jupyterhub-announcement
jupyterhub-announcementThis is an announcement service for JupyterHub that you can manage through a JupyterHub-styled UI.
You can use it to communicate with your hub's users about status, upcoming outages, or share news.
It allows you to post a current announcement, and show previous announcements in reverse chronological order.
It provides a REST API hook that you can use to post the latest announcement on JupyterHub itself (with custom templates).
Announcements are visible even to users who are logged out.Requirementsjupyterhubhtml-sanitizeraiofilesInstallationpip install jupyterhub-announcementHow to Configure ItYou can run this service either as a hub-managed service or as an external service.
Here's an example configuration for a hub-managed service you can place in a JupyterHub config file:c.JupyterHub.services = [
    {
        'name': 'announcement',
        'url': 'http://127.0.0.1:8888',
        'command': ["python", "-m", "jupyterhub_announcement"]
    }
]Here's the config if you set it up as an external service, say, in another Docker container calledannouncement:import os
c.JupyterHub.services = [
    {
        'name': 'announcement',
        'url': 'http://announcement:8888',
        'api_token': os.environ["ANNOUNCEMENT_JUPYTERHUB_API_TOKEN"]
    }
]You have to specify the API token for the hub and the announcement service to share here.
Starting with JupyterHub 2.0, you will need to set user access through appropriate definition ofc.JupyterHub.load_roles.
See thehub-managed service exampleto see how.The service also has its own configuration file, by defaultannouncement_config.pyis what it is called.
The configuration text can be generated with a--generate-configoption.If you're running a hub with internal SSL turned on, you'll want to take advantage of the SSL option settings.How to Use ItWhat does it actually look like when it runs?
Start up the hub.
Log in as an admin user, then go tohttp://localhost:8000/services/announcement/You should see:You'll now see the same page as before but with a text box.
Enter a message. Please note that your input will be sanitized.
For security reasons, a few HTML tags such as "<iframe>" or "<script>" will be automatically removed.That becomes the Latest Announcement.On the hub, a user will see the announcement posted.If you enter an empty message, it clears that message and demotes it to a Previous Announcement.Go on.  Add a few more.  Then log out.
Now log in using a test user who is not an admin.
Point back at the announcement page and there you see all these wonderful communications your friendly admin sent to you.Log out again and have a look.
You can see them even if you're logged out.REST EndpointUse the/services/announcement/latestendpoint to get the latest announcement in JSON form.
You can make a call out to the service to get the announcement from the hub, if you customize the page template.
Users may like that.
If the latest announcement has been cleared or there are no announcements yet, an empty announcement will be returned.Here are more details on how you can use the REST endpoint in a custom template.
This example extends the JupyterHubpage.htmltemplate to make a little AJAX call to the announcement service.
To make it work you mustCreate a directory somewhere the hub can reach, let's use/opt/templatesfor instance.Add the template to/opt/templates/page.htmlFinally, setc.JupyterHub.template_paths = ["/opt/templates"]in your JupyterHub configuration file.Note the first line that says we areextending a template.{% extends "templates/page.html" %}
{% block announcement %}
<div class="container announcement"></div>
{% endblock %}

{% block script %}
{{ super() }}
<script>
$.get("/services/announcement/latest", function(data) {
  var announcement = data["announcement"];
  if(announcement) {
    $(".announcement").html(`<div class="panel panel-warning">
      <div class="panel-heading">
        <h3 class="panel-title">Announcement</h3>
      </div>
      <div class="panel-body text-center announcement">
        ${announcement}
      </div>       
    </div>`);
  }
});
</script>
{% endblock %}BE CAREFULIt should be pretty clear at this point that you want to ensure your admins can be trusted!Fixed MessageThere's a hook in the configuration that lets you add a custom message above all the annoucements.
A good use for this message would be to include a link to a more general system status or message of the day (MOTD) page.Announcement LifetimeAnnouncements are retained in the queue for up to some configurable lifetime in days.
After that they are purged automatically.
By default announcements stay in the queue for a week.Persisted AnnouncementsBy default the service does nothing to persist announcements.
You can change this behavior by specifyingpersist_pathfor theAnnouncementQueueobject.
If this is set, then at start up the service will read this file and try to initialize the queue with its contents.
If it is set but the file doesn't exist, that's OK, the queue just starts off empty.
On update, the file is over-written to reflect the current state of the queue.
This way if the service is restarted, those old announcements aren't lost.
The persistence file is just JSON.BE CERTAINaccess to this file is protected!