From 3e49fba5781f80b91fbd2496e99586efdc3b0be4 Mon Sep 17 00:00:00 2001 From: Tobias Balle-Petersen Date: Thu, 1 May 2025 20:42:17 +0200 Subject: [PATCH] feat: return time of last usage for public keys and access tokens in the api (#34323) In the Gitea GUI, the user can see the time that _AccessTokens_ and _PublicKeys_ were last used. This information is not returned by the _/users/{username}/tokens_ and _/user/keys_ endpoints in the API. This PR adds the missing data. The time of last usage for for _tokens_ & _keys_ seem to be stored in the _Updated_ field of the structs internally. For consistency, I have used the name _updated_at_ for the new field returned by the _API_. However, for the _API_ user, I don't think that name reflects the data returned, as I believe it is the time of last usage. I propose that we use the name _last_used_at_ instead. Let's hear reviewers opinion on that. * PublicKey 1. _last_used_at_: string($date-time) * AccessToken 1. _created_at_: string($date-time) (for parity with public keys) 2. _last_used_at_: string($date-time) Fix #34313 --- modules/structs/user_app.go | 12 +++++++----- modules/structs/user_key.go | 1 + routers/api/v1/user/app.go | 2 ++ services/convert/convert.go | 1 + templates/swagger/v1_json.tmpl | 15 +++++++++++++++ 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/modules/structs/user_app.go b/modules/structs/user_app.go index 8401252bd6..15811ceb66 100644 --- a/modules/structs/user_app.go +++ b/modules/structs/user_app.go @@ -11,11 +11,13 @@ import ( // AccessToken represents an API access token. // swagger:response AccessToken type AccessToken struct { - ID int64 `json:"id"` - Name string `json:"name"` - Token string `json:"sha1"` - TokenLastEight string `json:"token_last_eight"` - Scopes []string `json:"scopes"` + ID int64 `json:"id"` + Name string `json:"name"` + Token string `json:"sha1"` + TokenLastEight string `json:"token_last_eight"` + Scopes []string `json:"scopes"` + Created time.Time `json:"created_at"` + Updated time.Time `json:"last_used_at"` } // AccessTokenList represents a list of API access token. diff --git a/modules/structs/user_key.go b/modules/structs/user_key.go index 08eed59a89..c4c41207e1 100644 --- a/modules/structs/user_key.go +++ b/modules/structs/user_key.go @@ -16,6 +16,7 @@ type PublicKey struct { Fingerprint string `json:"fingerprint,omitempty"` // swagger:strfmt date-time Created time.Time `json:"created_at,omitempty"` + Updated time.Time `json:"last_used_at,omitempty"` Owner *User `json:"user,omitempty"` ReadOnly bool `json:"read_only,omitempty"` KeyType string `json:"key_type,omitempty"` diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go index 4ca06ca923..7201010161 100644 --- a/routers/api/v1/user/app.go +++ b/routers/api/v1/user/app.go @@ -62,6 +62,8 @@ func ListAccessTokens(ctx *context.APIContext) { Name: tokens[i].Name, TokenLastEight: tokens[i].TokenLastEight, Scopes: tokens[i].Scope.StringSlice(), + Created: tokens[i].CreatedUnix.AsTime(), + Updated: tokens[i].UpdatedUnix.AsTime(), } } diff --git a/services/convert/convert.go b/services/convert/convert.go index 17bc83653f..b93365bbb9 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -316,6 +316,7 @@ func ToPublicKey(apiLink string, key *asymkey_model.PublicKey) *api.PublicKey { Title: key.Name, Fingerprint: key.Fingerprint, Created: key.CreatedUnix.AsTime(), + Updated: key.UpdatedUnix.AsTime(), } } diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 8758b5c0a1..223a2e8410 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -19978,11 +19978,21 @@ "type": "object", "title": "AccessToken represents an API access token.", "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "x-go-name": "Created" + }, "id": { "type": "integer", "format": "int64", "x-go-name": "ID" }, + "last_used_at": { + "type": "string", + "format": "date-time", + "x-go-name": "Updated" + }, "name": { "type": "string", "x-go-name": "Name" @@ -25477,6 +25487,11 @@ "type": "string", "x-go-name": "KeyType" }, + "last_used_at": { + "type": "string", + "format": "date-time", + "x-go-name": "Updated" + }, "read_only": { "type": "boolean", "x-go-name": "ReadOnly"