Day 10 of the Anvil Advent Calendar

Build a web app every day until Christmas, with nothing but Python!

Building a Secret Santa app

You want to exchange Christmas presents at your office, sports club or D&D group, but you don’t want to get presents for everybody. So you set up a Secret Santa - everyone buys a present for someone else, and everyone gets a present. Who bought yours? It’s a secret.

But if you’re the one who picks the match-ups, it’s not a secret any more! What if we could instead get a computer to make the list? For today Advent app, I built a minimal example in Anvil, the platform for building full-stack web apps using nothing but Python.

Check out the example below:

https://secret-santa-assignments.anvil.app

Here’s what it looks like:

And, if you want to use it yourself, all you have to do is clone the app and send your own version to your friends!

How it works

When you open the app, it loads a Form where a visitor can input their name and email address in order to be added to the list of participants. When they click the button, their details are sent to the server and stored in a Data Table, so that the app can keep track of who’s signed up over time.

@anvil.server.callable
def add_participant(name, email):
  if not app_tables.participants.get(name=name) and not app_tables.participants.get(email=email):
    app_tables.participants.add_row(name=name, email=email, giftee="")
    return True
  else:
    return False

Above is the server function that adds participants to the Data Table. It checks that both the name and the email supplied are unique, so that you don’t end up with the same person signing up multiple times, and that when people are assigned giftees, they’ll be given a unique name for that person.

Once everyone has signed up, it’s time to send the emails! The button in the top left that says ‘Send Emails’ will open a new Form, which contains the button to actually send the emails, along with a warning that this will mean that no new users can sign up:

We’re relying on the honour system here; if we really wanted to protect this button from being pressed by anyone but us, we could gate it behind a user login with the Users Service. For this minimal example, we won’t worry about that, and instead trust that none of our friends want to ruin the fun by clicking this button early.

When this button is pressed, it calls the following server function:

@anvil.server.callable
def email_participants():
  if len(app_tables.participants.search()) and not secret_santa_started():
    shuffle_and_assign_participants()
  for person in app_tables.participants.search():
    anvil.email.send(
      from_name="Secret Santa",
      to=person['email'],
      subject=f"Dear {person['name']}, you will be getting a gift for....",
      text=f"{person['giftee']}! Have fun, and have a merry Christmas!"
    )

The secret_santa_started function is very simple: it just checks whether we already have participants, and if so, whether the first participant already has a giftee assigned to them.

def secret_santa_started():
  if len(app_tables.participants.search()) and app_tables.participants.search()[0]['giftee']:
    return True
  return False

By default, the giftee value of a new row in the Data Table will be the empty string "", which is a Falsy value. If the giftee field actually contains a name, that’d be a Truthy value.

If the Secret Santa is determined not to have started yet - that is, participants haven’t been assigned giftees yet - then we call the function to do just that.

def shuffle_and_assign_participants():
  people = list(app_tables.participants.search())
  shuffle(people)
  for i in range(len(people)):
    people[i]['giftee'] = people[i+1]['name'] if i+1 < len(people) else people[0]['name']

All this function does is take the list of participants, shuffle them, then assign giftees by matching each person to the one after them, looping round at the end. This ensures that the shuffling we do won’t end with anyone assigned to themself - there’d be no fun in that!

With the shuffling sorted, the email_participants function goes on to loop over all the participants, emailing them all with the name of the person for whom they will be buying a gift. The ‘Send email to participants’ button can be pressed multiple times, sending multiple emails, just in case someone misses or accidentally deletes one; the shuffling will remain the same, since the function only shuffles the participants if it hasn’t happened already.

(The functionality of this button is disabled in the example app, so don’t worry if you’ve already put in an email address; you won’t be spammed!)

And that’s it! Now you can go forth and arrange a Secret Santa among your friends with no fuss.

Open the example app here, or...


Give the Gift of Python

Share this post: