feat(sync): unify Google auth under :Pending auth
Problem: users had to run `:Pending gtasks auth` and `:Pending gcal auth` separately, producing two token files and two browser consents for the same Google account. Solution: introduce `oauth.google_client` with combined tasks + calendar scopes and a single `google_tokens.json`. Remove per-backend `auth`/`setup` from `gcal` and `gtasks`; add top-level `:Pending auth` that prompts with `vim.ui.select` and delegates to the shared client's `setup()` or `auth()` based on credential availability.
This commit is contained in:
parent
87d8bf0896
commit
67aa8d71e6
6 changed files with 45 additions and 54 deletions
|
|
@ -828,6 +828,24 @@ function M.edit(id_str, rest)
|
|||
log.info('Task #' .. id .. ' updated: ' .. table.concat(feedback, ', '))
|
||||
end
|
||||
|
||||
---@return nil
|
||||
function M.auth()
|
||||
local oauth = require('pending.sync.oauth')
|
||||
vim.ui.select({ 'gtasks', 'gcal', 'both' }, {
|
||||
prompt = 'Authenticate:',
|
||||
}, function(choice)
|
||||
if not choice then
|
||||
return
|
||||
end
|
||||
local creds = oauth.google_client:resolve_credentials()
|
||||
if creds.client_id == oauth.BUNDLED_CLIENT_ID then
|
||||
oauth.google_client:setup()
|
||||
else
|
||||
oauth.google_client:auth()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
---@param args string
|
||||
---@return nil
|
||||
function M.command(args)
|
||||
|
|
@ -841,6 +859,8 @@ function M.command(args)
|
|||
elseif cmd == 'edit' then
|
||||
local id_str, edit_rest = rest:match('^(%S+)%s*(.*)')
|
||||
M.edit(id_str, edit_rest)
|
||||
elseif cmd == 'auth' then
|
||||
M.auth()
|
||||
elseif SYNC_BACKEND_SET[cmd] then
|
||||
local action = rest:match('^(%S+)')
|
||||
run_sync(cmd, action)
|
||||
|
|
|
|||
|
|
@ -7,14 +7,6 @@ local M = {}
|
|||
M.name = 'gcal'
|
||||
|
||||
local BASE_URL = 'https://www.googleapis.com/calendar/v3'
|
||||
local SCOPE = 'https://www.googleapis.com/auth/calendar'
|
||||
|
||||
local client = oauth.new({
|
||||
name = 'gcal',
|
||||
scope = SCOPE,
|
||||
port = 18392,
|
||||
config_key = 'gcal',
|
||||
})
|
||||
|
||||
---@param access_token string
|
||||
---@return table<string, string>? name_to_id
|
||||
|
|
@ -139,15 +131,15 @@ end
|
|||
---@param callback fun(access_token: string): nil
|
||||
local function with_token(callback)
|
||||
oauth.async(function()
|
||||
local token = client:get_access_token()
|
||||
local token = oauth.google_client:get_access_token()
|
||||
if not token then
|
||||
client:auth(function()
|
||||
oauth.google_client:auth(function()
|
||||
oauth.async(function()
|
||||
local fresh = client:get_access_token()
|
||||
local fresh = oauth.google_client:get_access_token()
|
||||
if fresh then
|
||||
callback(fresh)
|
||||
else
|
||||
log.error(client.name .. ': authorization failed or was cancelled')
|
||||
log.error(oauth.google_client.name .. ': authorization failed or was cancelled')
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
|
@ -157,14 +149,6 @@ local function with_token(callback)
|
|||
end)
|
||||
end
|
||||
|
||||
function M.setup()
|
||||
client:setup()
|
||||
end
|
||||
|
||||
function M.auth()
|
||||
client:auth()
|
||||
end
|
||||
|
||||
function M.push()
|
||||
with_token(function(access_token)
|
||||
local calendars, cal_err = get_all_calendars(access_token)
|
||||
|
|
|
|||
|
|
@ -7,14 +7,6 @@ local M = {}
|
|||
M.name = 'gtasks'
|
||||
|
||||
local BASE_URL = 'https://tasks.googleapis.com/tasks/v1'
|
||||
local SCOPE = 'https://www.googleapis.com/auth/tasks'
|
||||
|
||||
local client = oauth.new({
|
||||
name = 'gtasks',
|
||||
scope = SCOPE,
|
||||
port = 18393,
|
||||
config_key = 'gtasks',
|
||||
})
|
||||
|
||||
---@param access_token string
|
||||
---@return table<string, string>? name_to_id
|
||||
|
|
@ -355,15 +347,15 @@ end
|
|||
---@param callback fun(access_token: string): nil
|
||||
local function with_token(callback)
|
||||
oauth.async(function()
|
||||
local token = client:get_access_token()
|
||||
local token = oauth.google_client:get_access_token()
|
||||
if not token then
|
||||
client:auth(function()
|
||||
oauth.google_client:auth(function()
|
||||
oauth.async(function()
|
||||
local fresh = client:get_access_token()
|
||||
local fresh = oauth.google_client:get_access_token()
|
||||
if fresh then
|
||||
callback(fresh)
|
||||
else
|
||||
log.error(client.name .. ': authorization failed or was cancelled')
|
||||
log.error(oauth.google_client.name .. ': authorization failed or was cancelled')
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
|
@ -373,14 +365,6 @@ local function with_token(callback)
|
|||
end)
|
||||
end
|
||||
|
||||
function M.setup()
|
||||
client:setup()
|
||||
end
|
||||
|
||||
function M.auth()
|
||||
client:auth()
|
||||
end
|
||||
|
||||
function M.push()
|
||||
with_token(function(access_token)
|
||||
local tasklists, s, now_ts = sync_setup(access_token)
|
||||
|
|
@ -462,11 +446,11 @@ M._gtask_to_fields = gtask_to_fields
|
|||
---@return nil
|
||||
function M.health()
|
||||
oauth.health(M.name)
|
||||
local tokens = client:load_tokens()
|
||||
local tokens = oauth.google_client:load_tokens()
|
||||
if tokens and tokens.refresh_token then
|
||||
vim.health.ok('gtasks tokens found')
|
||||
else
|
||||
vim.health.info('no gtasks tokens — run :Pending gtasks auth')
|
||||
vim.health.info('no gtasks tokens — run :Pending auth')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -501,5 +501,14 @@ end
|
|||
|
||||
M._BUNDLED_CLIENT_ID = BUNDLED_CLIENT_ID
|
||||
M._BUNDLED_CLIENT_SECRET = BUNDLED_CLIENT_SECRET
|
||||
M.BUNDLED_CLIENT_ID = BUNDLED_CLIENT_ID
|
||||
|
||||
M.google_client = M.new({
|
||||
name = 'google',
|
||||
scope = 'https://www.googleapis.com/auth/tasks'
|
||||
.. ' https://www.googleapis.com/auth/calendar',
|
||||
port = 18392,
|
||||
config_key = 'google',
|
||||
})
|
||||
|
||||
return M
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ end, {
|
|||
nargs = '*',
|
||||
complete = function(arg_lead, cmd_line)
|
||||
local pending = require('pending')
|
||||
local subcmds = { 'add', 'archive', 'due', 'edit', 'filter', 'undo' }
|
||||
local subcmds = { 'add', 'archive', 'auth', 'due', 'edit', 'filter', 'undo' }
|
||||
for _, b in ipairs(pending.sync_backends()) do
|
||||
table.insert(subcmds, b)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -73,15 +73,14 @@ describe('sync', function()
|
|||
assert.is_true(called)
|
||||
end)
|
||||
|
||||
it('routes auth action', function()
|
||||
it('routes auth command', function()
|
||||
local called = false
|
||||
local gcal = require('pending.sync.gcal')
|
||||
local orig_auth = gcal.auth
|
||||
gcal.auth = function()
|
||||
local orig_auth = pending.auth
|
||||
pending.auth = function()
|
||||
called = true
|
||||
end
|
||||
pending.command('gcal auth')
|
||||
gcal.auth = orig_auth
|
||||
pending.command('auth')
|
||||
pending.auth = orig_auth
|
||||
assert.is_true(called)
|
||||
end)
|
||||
end)
|
||||
|
|
@ -102,11 +101,6 @@ describe('sync', function()
|
|||
assert.are.equal('gcal', gcal.name)
|
||||
end)
|
||||
|
||||
it('has auth function', function()
|
||||
local gcal = require('pending.sync.gcal')
|
||||
assert.are.equal('function', type(gcal.auth))
|
||||
end)
|
||||
|
||||
it('has push function', function()
|
||||
local gcal = require('pending.sync.gcal')
|
||||
assert.are.equal('function', type(gcal.push))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue