feat: user/service sessions repo
This commit is contained in:
@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApiService struct {
|
type ApiService struct {
|
||||||
@ -25,6 +26,24 @@ type ApiService struct {
|
|||||||
IconUrl *string `json:"icon_url"`
|
IconUrl *string `json:"icon_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServiceSession struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
ServiceID uuid.UUID `json:"service_id"`
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
UserID *uuid.UUID `json:"user_id"`
|
||||||
|
IssuedAt time.Time `json:"issued_at"`
|
||||||
|
ExpiresAt *time.Time `json:"expires_at"`
|
||||||
|
LastActive *time.Time `json:"last_active"`
|
||||||
|
IpAddress pgtype.Text `json:"ip_address"`
|
||||||
|
UserAgent *string `json:"user_agent"`
|
||||||
|
AccessTokenID *uuid.UUID `json:"access_token_id"`
|
||||||
|
RefreshTokenID *uuid.UUID `json:"refresh_token_id"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
RevokedAt *time.Time `json:"revoked_at"`
|
||||||
|
Scope *string `json:"scope"`
|
||||||
|
Claims []byte `json:"claims"`
|
||||||
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
@ -41,3 +60,19 @@ type User struct {
|
|||||||
AvatarVerified bool `json:"avatar_verified"`
|
AvatarVerified bool `json:"avatar_verified"`
|
||||||
Verified bool `json:"verified"`
|
Verified bool `json:"verified"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserSession struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
UserID uuid.UUID `json:"user_id"`
|
||||||
|
SessionType string `json:"session_type"`
|
||||||
|
IssuedAt time.Time `json:"issued_at"`
|
||||||
|
ExpiresAt *time.Time `json:"expires_at"`
|
||||||
|
LastActive *time.Time `json:"last_active"`
|
||||||
|
IpAddress pgtype.Text `json:"ip_address"`
|
||||||
|
UserAgent *string `json:"user_agent"`
|
||||||
|
AccessTokenID *uuid.UUID `json:"access_token_id"`
|
||||||
|
RefreshTokenID *uuid.UUID `json:"refresh_token_id"`
|
||||||
|
DeviceInfo []byte `json:"device_info"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
RevokedAt *time.Time `json:"revoked_at"`
|
||||||
|
}
|
||||||
|
288
internal/repository/service_sessions.sql.go
Normal file
288
internal/repository/service_sessions.sql.go
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.29.0
|
||||||
|
// source: service_sessions.sql
|
||||||
|
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createServiceSession = `-- name: CreateServiceSession :one
|
||||||
|
INSERT INTO service_sessions (
|
||||||
|
service_id, client_id, user_id, issued_at, expires_at, last_active,
|
||||||
|
ip_address, user_agent, access_token_id, refresh_token_id,
|
||||||
|
is_active, scope, claims
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, NOW(), $4, $5,
|
||||||
|
$6, $7, $8, $9,
|
||||||
|
TRUE, $8, $9
|
||||||
|
)
|
||||||
|
RETURNING id, service_id, client_id, user_id, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, is_active, revoked_at, scope, claims
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateServiceSessionParams struct {
|
||||||
|
ServiceID uuid.UUID `json:"service_id"`
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
UserID *uuid.UUID `json:"user_id"`
|
||||||
|
ExpiresAt *time.Time `json:"expires_at"`
|
||||||
|
LastActive *time.Time `json:"last_active"`
|
||||||
|
IpAddress pgtype.Text `json:"ip_address"`
|
||||||
|
UserAgent *string `json:"user_agent"`
|
||||||
|
AccessTokenID *uuid.UUID `json:"access_token_id"`
|
||||||
|
RefreshTokenID *uuid.UUID `json:"refresh_token_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateServiceSession(ctx context.Context, arg CreateServiceSessionParams) (ServiceSession, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createServiceSession,
|
||||||
|
arg.ServiceID,
|
||||||
|
arg.ClientID,
|
||||||
|
arg.UserID,
|
||||||
|
arg.ExpiresAt,
|
||||||
|
arg.LastActive,
|
||||||
|
arg.IpAddress,
|
||||||
|
arg.UserAgent,
|
||||||
|
arg.AccessTokenID,
|
||||||
|
arg.RefreshTokenID,
|
||||||
|
)
|
||||||
|
var i ServiceSession
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ServiceID,
|
||||||
|
&i.ClientID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
&i.Scope,
|
||||||
|
&i.Claims,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getServiceSessionByAccessJTI = `-- name: GetServiceSessionByAccessJTI :one
|
||||||
|
SELECT id, service_id, client_id, user_id, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, is_active, revoked_at, scope, claims FROM service_sessions
|
||||||
|
WHERE access_token_id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetServiceSessionByAccessJTI(ctx context.Context, accessTokenID *uuid.UUID) (ServiceSession, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getServiceSessionByAccessJTI, accessTokenID)
|
||||||
|
var i ServiceSession
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ServiceID,
|
||||||
|
&i.ClientID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
&i.Scope,
|
||||||
|
&i.Claims,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getServiceSessionByRefreshJTI = `-- name: GetServiceSessionByRefreshJTI :one
|
||||||
|
SELECT id, service_id, client_id, user_id, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, is_active, revoked_at, scope, claims FROM service_sessions
|
||||||
|
WHERE refresh_token_id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetServiceSessionByRefreshJTI(ctx context.Context, refreshTokenID *uuid.UUID) (ServiceSession, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getServiceSessionByRefreshJTI, refreshTokenID)
|
||||||
|
var i ServiceSession
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ServiceID,
|
||||||
|
&i.ClientID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
&i.Scope,
|
||||||
|
&i.Claims,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listActiveServiceSessionsByClient = `-- name: ListActiveServiceSessionsByClient :many
|
||||||
|
SELECT id, service_id, client_id, user_id, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, is_active, revoked_at, scope, claims FROM service_sessions
|
||||||
|
WHERE client_id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
ORDER BY issued_at DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListActiveServiceSessionsByClient(ctx context.Context, clientID string) ([]ServiceSession, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listActiveServiceSessionsByClient, clientID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []ServiceSession
|
||||||
|
for rows.Next() {
|
||||||
|
var i ServiceSession
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ServiceID,
|
||||||
|
&i.ClientID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
&i.Scope,
|
||||||
|
&i.Claims,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const listActiveServiceSessionsByUser = `-- name: ListActiveServiceSessionsByUser :many
|
||||||
|
SELECT id, service_id, client_id, user_id, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, is_active, revoked_at, scope, claims FROM service_sessions
|
||||||
|
WHERE user_id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
ORDER BY issued_at DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListActiveServiceSessionsByUser(ctx context.Context, userID *uuid.UUID) ([]ServiceSession, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listActiveServiceSessionsByUser, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []ServiceSession
|
||||||
|
for rows.Next() {
|
||||||
|
var i ServiceSession
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ServiceID,
|
||||||
|
&i.ClientID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
&i.Scope,
|
||||||
|
&i.Claims,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const listAllServiceSessions = `-- name: ListAllServiceSessions :many
|
||||||
|
SELECT id, service_id, client_id, user_id, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, is_active, revoked_at, scope, claims FROM service_sessions
|
||||||
|
ORDER BY issued_at DESC
|
||||||
|
LIMIT $1 OFFSET $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListAllServiceSessionsParams struct {
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListAllServiceSessions(ctx context.Context, arg ListAllServiceSessionsParams) ([]ServiceSession, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listAllServiceSessions, arg.Limit, arg.Offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []ServiceSession
|
||||||
|
for rows.Next() {
|
||||||
|
var i ServiceSession
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ServiceID,
|
||||||
|
&i.ClientID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
&i.Scope,
|
||||||
|
&i.Claims,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const revokeServiceSession = `-- name: RevokeServiceSession :exec
|
||||||
|
UPDATE service_sessions
|
||||||
|
SET is_active = FALSE,
|
||||||
|
revoked_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) RevokeServiceSession(ctx context.Context, id uuid.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, revokeServiceSession, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateServiceSessionLastActive = `-- name: UpdateServiceSessionLastActive :exec
|
||||||
|
UPDATE service_sessions
|
||||||
|
SET last_active = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) UpdateServiceSessionLastActive(ctx context.Context, id uuid.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateServiceSessionLastActive, id)
|
||||||
|
return err
|
||||||
|
}
|
235
internal/repository/user_sessions.sql.go
Normal file
235
internal/repository/user_sessions.sql.go
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.29.0
|
||||||
|
// source: user_sessions.sql
|
||||||
|
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createUserSession = `-- name: CreateUserSession :one
|
||||||
|
INSERT INTO user_sessions (
|
||||||
|
user_id, session_type, issued_at, expires_at, last_active,
|
||||||
|
ip_address, user_agent, access_token_id, refresh_token_id,
|
||||||
|
device_info, is_active
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, NOW(), $3, $4,
|
||||||
|
$5, $6, $7, $8,
|
||||||
|
$9, TRUE
|
||||||
|
)
|
||||||
|
RETURNING id, user_id, session_type, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, device_info, is_active, revoked_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateUserSessionParams struct {
|
||||||
|
UserID uuid.UUID `json:"user_id"`
|
||||||
|
SessionType string `json:"session_type"`
|
||||||
|
ExpiresAt *time.Time `json:"expires_at"`
|
||||||
|
LastActive *time.Time `json:"last_active"`
|
||||||
|
IpAddress pgtype.Text `json:"ip_address"`
|
||||||
|
UserAgent *string `json:"user_agent"`
|
||||||
|
AccessTokenID *uuid.UUID `json:"access_token_id"`
|
||||||
|
RefreshTokenID *uuid.UUID `json:"refresh_token_id"`
|
||||||
|
DeviceInfo []byte `json:"device_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateUserSession(ctx context.Context, arg CreateUserSessionParams) (UserSession, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createUserSession,
|
||||||
|
arg.UserID,
|
||||||
|
arg.SessionType,
|
||||||
|
arg.ExpiresAt,
|
||||||
|
arg.LastActive,
|
||||||
|
arg.IpAddress,
|
||||||
|
arg.UserAgent,
|
||||||
|
arg.AccessTokenID,
|
||||||
|
arg.RefreshTokenID,
|
||||||
|
arg.DeviceInfo,
|
||||||
|
)
|
||||||
|
var i UserSession
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.SessionType,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.DeviceInfo,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUserSessionByAccessJTI = `-- name: GetUserSessionByAccessJTI :one
|
||||||
|
SELECT id, user_id, session_type, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, device_info, is_active, revoked_at FROM user_sessions
|
||||||
|
WHERE access_token_id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetUserSessionByAccessJTI(ctx context.Context, accessTokenID *uuid.UUID) (UserSession, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getUserSessionByAccessJTI, accessTokenID)
|
||||||
|
var i UserSession
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.SessionType,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.DeviceInfo,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUserSessionByRefreshJTI = `-- name: GetUserSessionByRefreshJTI :one
|
||||||
|
SELECT id, user_id, session_type, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, device_info, is_active, revoked_at FROM user_sessions
|
||||||
|
WHERE refresh_token_id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetUserSessionByRefreshJTI(ctx context.Context, refreshTokenID *uuid.UUID) (UserSession, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getUserSessionByRefreshJTI, refreshTokenID)
|
||||||
|
var i UserSession
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.SessionType,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.DeviceInfo,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listActiveUserSessions = `-- name: ListActiveUserSessions :many
|
||||||
|
SELECT id, user_id, session_type, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, device_info, is_active, revoked_at FROM user_sessions
|
||||||
|
WHERE user_id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
ORDER BY issued_at DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListActiveUserSessions(ctx context.Context, userID uuid.UUID) ([]UserSession, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listActiveUserSessions, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []UserSession
|
||||||
|
for rows.Next() {
|
||||||
|
var i UserSession
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.SessionType,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.DeviceInfo,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const listAllSessions = `-- name: ListAllSessions :many
|
||||||
|
SELECT id, user_id, session_type, issued_at, expires_at, last_active, ip_address, user_agent, access_token_id, refresh_token_id, device_info, is_active, revoked_at FROM user_sessions
|
||||||
|
ORDER BY issued_at DESC
|
||||||
|
LIMIT $1 OFFSET $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListAllSessionsParams struct {
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListAllSessions(ctx context.Context, arg ListAllSessionsParams) ([]UserSession, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listAllSessions, arg.Limit, arg.Offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []UserSession
|
||||||
|
for rows.Next() {
|
||||||
|
var i UserSession
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.SessionType,
|
||||||
|
&i.IssuedAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.LastActive,
|
||||||
|
&i.IpAddress,
|
||||||
|
&i.UserAgent,
|
||||||
|
&i.AccessTokenID,
|
||||||
|
&i.RefreshTokenID,
|
||||||
|
&i.DeviceInfo,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.RevokedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const revokeUserSession = `-- name: RevokeUserSession :exec
|
||||||
|
UPDATE user_sessions
|
||||||
|
SET is_active = FALSE,
|
||||||
|
revoked_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) RevokeUserSession(ctx context.Context, id uuid.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, revokeUserSession, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateSessionLastActive = `-- name: UpdateSessionLastActive :exec
|
||||||
|
UPDATE user_sessions
|
||||||
|
SET last_active = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
AND is_active = TRUE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) UpdateSessionLastActive(ctx context.Context, id uuid.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateSessionLastActive, id)
|
||||||
|
return err
|
||||||
|
}
|
@ -15,7 +15,8 @@ CREATE TABLE user_sessions (
|
|||||||
TIME ZONE,
|
TIME ZONE,
|
||||||
ip_address VARCHAR(45), -- supports IPv4/IPv6
|
ip_address VARCHAR(45), -- supports IPv4/IPv6
|
||||||
user_agent TEXT,
|
user_agent TEXT,
|
||||||
refresh_token TEXT,
|
access_token_id UUID,
|
||||||
|
refresh_token_id UUID,
|
||||||
device_info JSONB, -- optional: structured info (browser, OS, etc.)
|
device_info JSONB, -- optional: structured info (browser, OS, etc.)
|
||||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
revoked_at TIMESTAMP
|
revoked_at TIMESTAMP
|
||||||
|
@ -16,7 +16,8 @@ CREATE TABLE service_sessions (
|
|||||||
TIME ZONE,
|
TIME ZONE,
|
||||||
ip_address VARCHAR(45),
|
ip_address VARCHAR(45),
|
||||||
user_agent TEXT,
|
user_agent TEXT,
|
||||||
refresh_token TEXT,
|
access_token_id UUID,
|
||||||
|
refresh_token_id UUID,
|
||||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
revoked_at TIMESTAMP
|
revoked_at TIMESTAMP
|
||||||
WITH
|
WITH
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
-- name: CreateServiceSession :one
|
-- name: CreateServiceSession :one
|
||||||
INSERT INTO service_sessions (
|
INSERT INTO service_sessions (
|
||||||
client_id, user_id, issued_at, expires_at, last_active,
|
service_id, client_id, user_id, issued_at, expires_at, last_active,
|
||||||
ip_address, user_agent, is_active, scope, claims
|
ip_address, user_agent, access_token_id, refresh_token_id,
|
||||||
|
is_active, scope, claims
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, NOW(), $3, $4,
|
$1, $2, $3, NOW(), $4, $5,
|
||||||
$5, $6, $6, TRUE, $7, $8
|
$6, $7, $8, $9,
|
||||||
|
TRUE, $8, $9
|
||||||
)
|
)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
@ -20,9 +22,14 @@ WHERE user_id = $1
|
|||||||
AND is_active = TRUE
|
AND is_active = TRUE
|
||||||
ORDER BY issued_at DESC;
|
ORDER BY issued_at DESC;
|
||||||
|
|
||||||
-- name: GetServiceSessionByToken :one
|
-- name: GetServiceSessionByAccessJTI :one
|
||||||
SELECT * FROM service_sessions
|
SELECT * FROM service_sessions
|
||||||
WHERE refresh_token = $1
|
WHERE access_token_id = $1
|
||||||
|
AND is_active = TRUE;
|
||||||
|
|
||||||
|
-- name: GetServiceSessionByRefreshJTI :one
|
||||||
|
SELECT * FROM service_sessions
|
||||||
|
WHERE refresh_token_id = $1
|
||||||
AND is_active = TRUE;
|
AND is_active = TRUE;
|
||||||
|
|
||||||
-- name: RevokeServiceSession :exec
|
-- name: RevokeServiceSession :exec
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
-- name: CreateUserSession :one
|
-- name: CreateUserSession :one
|
||||||
INSERT INTO user_sessions (
|
INSERT INTO user_sessions (
|
||||||
user_id, session_type, issued_at, expires_at, last_active,
|
user_id, session_type, issued_at, expires_at, last_active,
|
||||||
ip_address, user_agent,
|
ip_address, user_agent, access_token_id, refresh_token_id,
|
||||||
device_info, is_active
|
device_info, is_active
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, NOW(), $3, $4,
|
$1, $2, NOW(), $3, $4,
|
||||||
$5, $6,
|
$5, $6, $7, $8,
|
||||||
$7, TRUE
|
$9, TRUE
|
||||||
)
|
)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
@ -16,9 +16,14 @@ WHERE user_id = $1
|
|||||||
AND is_active = TRUE
|
AND is_active = TRUE
|
||||||
ORDER BY issued_at DESC;
|
ORDER BY issued_at DESC;
|
||||||
|
|
||||||
-- name: GetUserSessionByToken :one
|
-- name: GetUserSessionByAccessJTI :one
|
||||||
SELECT * FROM user_sessions
|
SELECT * FROM user_sessions
|
||||||
WHERE refresh_token = $1
|
WHERE access_token_id = $1
|
||||||
|
AND is_active = TRUE;
|
||||||
|
|
||||||
|
-- name: GetUserSessionByRefreshJTI :one
|
||||||
|
SELECT * FROM user_sessions
|
||||||
|
WHERE refresh_token_id = $1
|
||||||
AND is_active = TRUE;
|
AND is_active = TRUE;
|
||||||
|
|
||||||
-- name: RevokeUserSession :exec
|
-- name: RevokeUserSession :exec
|
||||||
|
Reference in New Issue
Block a user