Inspired by the novelty Twitter account @isitchristmas, a few of us here at Dropbox put together the website Is it Christmas?, which answers the question by adding a cute photo to your Dropbox each day. Not only is this app adorable, but it demonstrates how a service can periodically update a user’s Dropbox using
How it works
The app is built in Python and uses a handful of Core API methods:
/oauth2/tokento log in a user.
/mediato generate a URL for the image on the home page (which changes each day).
/fileops/copyto copy a file from my Dropbox account (where the images are stored) to each user’s account.
The app stores state in Redis, including the access tokens for users of the app, users’ time zones, and the last photo that was added to their Dropbox. This information is all that’s needed to update every user’s Dropbox every day at midnight (in their time zone). This work is done periodically via a cron job:
def update_if_needed(uid, redis_client, my_token): '''For a given user, copy a new photo into their Dropbox if needed.''' # Get the user's access token from Redis. access_token = redis_client.hget('tokens', uid) # Get the time zone, or use Pacific time by default. tz = redis_client.hget('timezones', uid) or '-8' date = (datetime.utcnow() + timedelta(hours=int(tz))).strftime('%Y-%m-%d') # If the user hasn't been updated yet today, copy in a new photo. if redis_client.hget('last_update', uid) != date: # Get a copy ref from the master account copy_ref = get_copy_ref(my_token, date) client = DropboxClient(access_token) try: # Add the photo client.add_copy_ref(copy_ref, 'Is %s Christmas.jpg' % date) except: # Ignore all errors! Probably a bad idea, but the most common # error is that there's a conflict because the user actually # already has this file. TODO: Catch that specifically. :-) pass # Track the last update so we don't revisit this user until tomorrow. redis_client.hset('last_update', uid, date) @app.route('/cron') def cron(): '''Cron job, triggered remotely on a regular basis by hitting this URL.''' # Update any users that need it. for uid in redis_client.hkeys('tokens'): update_if_needed(uid, redis_client, my_token) return 'Okay.'