Upsert user record from Tailscale identity headers
Sequel/SQLite wired up with auto-migrating DB connection. Tests use in-memory DB.

Assisted-by: Claude Opus 4.6 via pi
change rykopszokzwturztymmwpkzpuxvvlwnq
commit 9b895606604110023bb7485ca9c49a372c5fbf31
author Alpha Chen <alpha@kejadlen.dev>
date
parent xrtwqkvm
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2e274d9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+db/*.db
diff --git a/db/migrate/001_create_users.rb b/db/migrate/001_create_users.rb
new file mode 100644
index 0000000..6bfa8b0
--- /dev/null
+++ b/db/migrate/001_create_users.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+Sequel.migration do
+  change do
+    create_table(:users) do
+      primary_key :id
+      String :login, null: false, unique: true
+      String :name
+      DateTime :created_at, null: false
+      DateTime :updated_at, null: false
+    end
+  end
+end
diff --git a/lib/db.rb b/lib/db.rb
new file mode 100644
index 0000000..df86307
--- /dev/null
+++ b/lib/db.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require "sequel"
+
+DB = Sequel.sqlite(ENV.fetch("DATABASE_URL") { "db/ketchup.db" })
+Sequel.extension :migration
+Sequel::Migrator.run(DB, File.expand_path("../db/migrate", __dir__))
diff --git a/lib/web.rb b/lib/web.rb
index 7f5aca2..b0f85f2 100644
--- a/lib/web.rb
+++ b/lib/web.rb
@@ -2,6 +2,7 @@
 
 require "roda"
 
+require_relative "db"
 require_relative "views/series/new"
 
 class Web < Roda
@@ -12,10 +13,14 @@ class Web < Roda
     login = env["HTTP_TAILSCALE_USER_LOGIN"]
     return unless login
 
-    {
-      login: login,
-      name: env["HTTP_TAILSCALE_USER_NAME"],
-    }
+    name = env["HTTP_TAILSCALE_USER_NAME"]
+    now = Time.now
+
+    DB[:users]
+      .insert_conflict(target: :login, update: { name: name, updated_at: now })
+      .insert(login: login, name: name, created_at: now, updated_at: now)
+
+    DB[:users].first(login: login)
   end
 
   route do |r|
diff --git a/test/test_web.rb b/test/test_web.rb
index a0eb8cd..0fade8b 100644
--- a/test/test_web.rb
+++ b/test/test_web.rb
@@ -1,5 +1,7 @@
 # frozen_string_literal: true
 
+ENV["DATABASE_URL"] = ":memory:"
+
 require "minitest/autorun"
 require "rack/test"
 
@@ -22,6 +24,19 @@ class TestWeb < Minitest::Test
     assert_includes last_response.body, "Alice"
   end
 
+  def test_root_creates_user_record
+    get "/", {}, tailscale_headers(login: "bob@example.com", name: "Bob")
+    user = DB[:users].first(login: "bob@example.com")
+    assert_equal "Bob", user[:name]
+  end
+
+  def test_root_updates_user_name
+    get "/", {}, tailscale_headers(login: "carol@example.com", name: "Carol")
+    get "/", {}, tailscale_headers(login: "carol@example.com", name: "Carol C.")
+    user = DB[:users].first(login: "carol@example.com")
+    assert_equal "Carol C.", user[:name]
+  end
+
   def test_root_requires_tailscale_user
     get "/"
     assert_equal 403, last_response.status