• Added support for verifying and revoking tokens. One thing I like about API development vs regular page/form development is the inputs and outputs are clearly defined. You don't need to worry about things like layout or looks. It's either valid or it's not.
  • With the basic indie auth login flow working, the next couple of days will be dedicated of fully fleshing out apis to support revoking tokens (e.g. on logout ) and checking token validity.ย  I added basic tests for the authentication -> access token call today, so I can be confident that while I make these changes, I won't break anything.

    I also added Bearer token based authentication today, which I've plugged into my micropub endpoint stub. My goal is to have the full indieauth/micropub api ready for release by Friday, at least on a basic level.

    Importing data from OwnYourSwarm like I want will require a few more models and planning because posts will need to support geo-coordinates and so forth.
  • Woohoo! First successful IndieAuth login with Tanzawa.ย  ๐ŸŽ‰๐Ÿ™Œ๐Ÿป

    Tanzawa logged in to OwnYourSwarm
  • The Week #31


    • As I've been public blogging about ๐Ÿ”Tanzawa I've had more people emailing me, responding to my posts, or DMing me directly about it than any past project. One of the things I still have difficulty talking about succinctly is the IndieWeb, Tanzawa, and how it all fits together. I think I may be getting better at it though.

    This week I was explaining the building blocks of the IndieWeb to my internet buddy Frey. My explanation seemed to click as he's added rss to his blog and joined micro.blog!

  • Each month at BeProud there's a monthly meet-up where employees give presentations and afterwards there's sushi, beer, and chitchatting. It's great fun. When you first join the company, it's tradition for you give a 10-minute self-introduction presentation. The meetup still happens with covid, but remotely over zoom.

    As we've grown we realized that newer employees don't have an opportunity to learn about the longer-tenured employees without asking them directly, which is difficult. This week it was my turn to re-introduce myself to the company. This time I was able to speak for 10 minutes in front of half the company without much effort or really thinking too much. Much different than my first time almost 4 years ago.


  • I discovered you can use VideoLan to play videos off YouTube. You could probably use this to download videos, but I'm not doing that. I'm just enjoying being able to have a native app play music without all of the bloat and trackers running in the background.

  • Kai wrote a post with some tips and tricks in the terminal (Japanese). Improving my fluency in the shell is one of my goals for this year. This week I'm going to try and use some of these.

  • Leo's started to recognize when he's wet his diaper and tells us about it. I think this means the days of changing diapers will be coming to an end soon. ๐Ÿ™Œ๐Ÿป

  • Aggregating Nested Values with JSONFields

    Note: I originally wrote this for the Kwoosh Workshop blog. Since it's no longer around and I'm posting it here.


    Integrating with 3rd party APIs you'll often need to implement a webhook for your application to respond to external events. It's useful to take the event data and store it in your Database for future reference.

    As Kwoosh is run out of Texas, users in Texas need to pay an 8.25% sales tax. To my surprise Stripe's
    dashboard doesn't seem to offer an answer to a simple question: How much did I collect that was taxable
    and how much do I need to remit to the state for last quarter's sales.

    Armed with our event log data and Python we can quickly get that the numbers we're looking for.

    Our data looks something like this. Naturally a real event would have a lot more data, but for our purposes
    today this should suffice.

    {
    "data": {
    "object": {
    "tax": 25
    ...
    }
    }
    }

    This data is sent with each invoice.payment_successful event and it's saved in aa JSONField in our database. Using the KeyTransform we can extract values from our JSONField and annotate them
    to our QuerySet. Even better, as of Django 1.11 we can nest our KeyTransform so we can extract values
    that are multiple levels deep.

    Our plan of attack is to annotate the value, sum them together, and return them with the period.
    Unfortunately we have to sum them in Python until bug #29139
    is fixed. We're not summing millions of rows so it's still quick enough.

    from functools import reduce

    from django.contrib.postgres.fields.jsonb import KeyTransform

    from accounts.models import StripeEvent

    def accumulate_tax(start_date, end_date):
    """
    Can't aggregate KeyTransformed objects directly, so summing manually
    Reference: https://code.djangoproject.com/ticket/29139
    """
    events = StripeEvent.objects.filter(
    created__range=(start_date, end_date),
    type='invoice.payment_succeeded'
    ).annotate(
    tax=KeyTransform('tax', KeyTransform('object', KeyTransform('data', 'data'))),
    ).values('tax')

    if events:
    tax_total = reduce(lambda x, y: dict((k, (v or 0) + (y[k] or 0),)
    for k, v in x.items()), events)
    else:
    tax_total = {'tax': 0}

    for key, value in tax_total.items():
    tax_total[key] = '${:,.2f}'.format(value / 100)

    return {'start': start_date, 'end': end_date, 'totals': tax_total}

    And just like that we can aggregate values from our JSONFields. If you want to sum other fields
    you can simply add another line like this, but replace "tax" with the field you want to sum.

    To make it a bit more useful, I built a second function that uses this function to give me quarterly sums.

    import datetime

    QUARTERS = (
    ((1, 1), (3, 31)),
    ((4, 1), (6, 30)),
    ((7, 1), (9, 30)),
    ((10, 1), (12, 31)),
    )

    def calculate_quarters():
    today = datetime.date.today()
    last_year = today.year - 1

    for start, end in QUARTERS:
    quarter_start = datetime.date(year=today.year, month=start[0], day=start[1])
    year = today.year
    if quarter_start > today:
    year = last_year

    yield accumulate_tax(datetime.datetime(year=year, month=start[0],
    day=start[1], hour=0, minute=0,
    second=0),
    datetime.datetime(year=year, month=end[0],
    day=end[1], hour=23, minute=59,
    second=59))

    We can simply iterate over this function and generate a simple report that shows us a quarterly breakdown
    of our sales and taxes collected.

  • I got the IndieAuth authorization api working. Initially I had built it out using the rest_framework.authtoken. However I realized their models only allow one token per user.ย  This would make integrating with multiple clients impossible, so I'm opting to generate / manage tokens myself.

    I can almost complete a sign in with OwnYourSwarm. I think my token endpoint response is wrong, which is preventing it from completing. Hopefully tomorrow I can get the complete signin working so I can move on to the micropub endpoint.

    I feel like I'm starting to break small bits here and there inadvertently . So perhaps before building out the micropub endpoint and potentially breaking more things, I should take a step back and start adding some unit tests for my apis. It'll cost me a day today, but save me days of headaches over the course of the project.
  • Got the start of the indieauth authorization flow working and the base models setup.

    Indieauth auth screen


  • UX Design Textbook

    As part of of the "team UX" at work we're doing a bookclub to make sure we all have good foundations in UX before making it a company offering. We're starting with two books: The Design of Everyday Things by Don Norman, and UXใƒ‡ใ‚ถใ‚คใƒณใฎๆ•™็ง‘ๆ›ธ (The UX Design Textbook) by Masaya Andou.

    While I work reading and writing Japanese all day (when I'm not slinging code), I haven't read a book in Japanese in ages. This is mostly because what I'm interested in ( technology, the web etc...) is usually written about in English well before Japanese. And since I can read English natively, it's natural for me to pick those books.

    Starting to read UXใƒ‡ใ‚ถใ‚คใƒณใฎๆ•™็ง‘ๆ›ธ yesterday and the first thing that hit me is how much my Japanese has improved in the last 4 years. I used to struggle reading texts written for native-speakers as I had large gaps in my kanji recognition abilities. Gaps still exist. But now they're small enough that reading a single page doesn't take 20 minutes as I look up every 5th word. Only taken me...20 years(!) to come the far.

  • Just a small update today. I shipped the login screen I shared yesterday and planned out what I need to build to support IndieAuth. I think I can use DRF to help handle token generation and authentication using the token.
  • With webmentions working, next up I want to tackle support for check-ins. Currently I'm using OwnYourSwarm to backfeed my checkins to my main site and I'd like to continue doing so with Tanzawa.

    Doing so requires that I add support for IndieAuth (so I can login using just my domain) and Micropub. I'm starting on the IndieAuth implementation, which means I need to actually start with a login page for users to authenticate (thus far I've been using the django admin).

    This is what it's looking like so far. Something feels off in the design of it, but I can't quite place my finger on what it is.

    The base login form
Previous 158 of 359 Next