Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
724f8e89
Commit
724f8e89
authored
Apr 20, 2026
by
IanShaw027
Browse files
feat: resolve auth identity migration reports
parent
452e55a5
Changes
7
Hide whitespace changes
Inline
Side-by-side
backend/internal/handler/admin/admin_basic_handlers_test.go
View file @
724f8e89
...
@@ -7,6 +7,7 @@ import (
...
@@ -7,6 +7,7 @@ import (
"net/http/httptest"
"net/http/httptest"
"testing"
"testing"
servermiddleware
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/require"
)
)
...
@@ -24,6 +25,10 @@ func setupAdminRouter() (*gin.Engine, *stubAdminService) {
...
@@ -24,6 +25,10 @@ func setupAdminRouter() (*gin.Engine, *stubAdminService) {
router
.
GET
(
"/api/v1/admin/users"
,
userHandler
.
List
)
router
.
GET
(
"/api/v1/admin/users"
,
userHandler
.
List
)
router
.
GET
(
"/api/v1/admin/users/auth-identity-migration-reports/summary"
,
userHandler
.
GetAuthIdentityMigrationReportSummary
)
router
.
GET
(
"/api/v1/admin/users/auth-identity-migration-reports/summary"
,
userHandler
.
GetAuthIdentityMigrationReportSummary
)
router
.
GET
(
"/api/v1/admin/users/auth-identity-migration-reports"
,
userHandler
.
ListAuthIdentityMigrationReports
)
router
.
GET
(
"/api/v1/admin/users/auth-identity-migration-reports"
,
userHandler
.
ListAuthIdentityMigrationReports
)
router
.
POST
(
"/api/v1/admin/users/auth-identity-migration-reports/:id/resolve"
,
func
(
c
*
gin
.
Context
)
{
c
.
Set
(
string
(
servermiddleware
.
ContextKeyUser
),
servermiddleware
.
AuthSubject
{
UserID
:
99
})
userHandler
.
ResolveAuthIdentityMigrationReport
(
c
)
})
router
.
GET
(
"/api/v1/admin/users/:id"
,
userHandler
.
GetByID
)
router
.
GET
(
"/api/v1/admin/users/:id"
,
userHandler
.
GetByID
)
router
.
POST
(
"/api/v1/admin/users/:id/auth-identities"
,
userHandler
.
BindAuthIdentity
)
router
.
POST
(
"/api/v1/admin/users/:id/auth-identities"
,
userHandler
.
BindAuthIdentity
)
router
.
POST
(
"/api/v1/admin/users"
,
userHandler
.
Create
)
router
.
POST
(
"/api/v1/admin/users"
,
userHandler
.
Create
)
...
@@ -83,6 +88,13 @@ func TestUserHandlerEndpoints(t *testing.T) {
...
@@ -83,6 +88,13 @@ func TestUserHandlerEndpoints(t *testing.T) {
router
.
ServeHTTP
(
rec
,
req
)
router
.
ServeHTTP
(
rec
,
req
)
require
.
Equal
(
t
,
http
.
StatusOK
,
rec
.
Code
)
require
.
Equal
(
t
,
http
.
StatusOK
,
rec
.
Code
)
body
,
_
:=
json
.
Marshal
(
map
[
string
]
any
{
"resolution_note"
:
"resolved by manual bind"
})
rec
=
httptest
.
NewRecorder
()
req
=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/api/v1/admin/users/auth-identity-migration-reports/1/resolve"
,
bytes
.
NewReader
(
body
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
router
.
ServeHTTP
(
rec
,
req
)
require
.
Equal
(
t
,
http
.
StatusOK
,
rec
.
Code
)
rec
=
httptest
.
NewRecorder
()
rec
=
httptest
.
NewRecorder
()
req
=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/api/v1/admin/users/1"
,
nil
)
req
=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/api/v1/admin/users/1"
,
nil
)
router
.
ServeHTTP
(
rec
,
req
)
router
.
ServeHTTP
(
rec
,
req
)
...
@@ -99,7 +111,7 @@ func TestUserHandlerEndpoints(t *testing.T) {
...
@@ -99,7 +111,7 @@ func TestUserHandlerEndpoints(t *testing.T) {
"channel_subject"
:
"openid-123"
,
"channel_subject"
:
"openid-123"
,
},
},
}
}
body
,
_
:
=
json
.
Marshal
(
bindBody
)
body
,
_
=
json
.
Marshal
(
bindBody
)
rec
=
httptest
.
NewRecorder
()
rec
=
httptest
.
NewRecorder
()
req
=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/api/v1/admin/users/1/auth-identities"
,
bytes
.
NewReader
(
body
))
req
=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/api/v1/admin/users/1/auth-identities"
,
bytes
.
NewReader
(
body
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
...
...
backend/internal/handler/admin/admin_service_stub_test.go
View file @
724f8e89
...
@@ -249,6 +249,20 @@ func (s *stubAdminService) BindUserAuthIdentity(ctx context.Context, userID int6
...
@@ -249,6 +249,20 @@ func (s *stubAdminService) BindUserAuthIdentity(ctx context.Context, userID int6
return
result
,
nil
return
result
,
nil
}
}
func
(
s
*
stubAdminService
)
ResolveAuthIdentityMigrationReport
(
ctx
context
.
Context
,
reportID
,
resolvedByUserID
int64
,
resolutionNote
string
)
(
*
service
.
AuthIdentityMigrationReport
,
error
)
{
now
:=
time
.
Now
()
.
UTC
()
for
i
:=
range
s
.
migrationReports
{
if
s
.
migrationReports
[
i
]
.
ID
!=
reportID
{
continue
}
s
.
migrationReports
[
i
]
.
ResolvedAt
=
&
now
s
.
migrationReports
[
i
]
.
ResolvedByUserID
=
&
resolvedByUserID
s
.
migrationReports
[
i
]
.
ResolutionNote
=
resolutionNote
return
&
s
.
migrationReports
[
i
],
nil
}
return
nil
,
nil
}
func
(
s
*
stubAdminService
)
ListGroups
(
ctx
context
.
Context
,
page
,
pageSize
int
,
platform
,
status
,
search
string
,
isExclusive
*
bool
,
sortBy
,
sortOrder
string
)
([]
service
.
Group
,
int64
,
error
)
{
func
(
s
*
stubAdminService
)
ListGroups
(
ctx
context
.
Context
,
page
,
pageSize
int
,
platform
,
status
,
search
string
,
isExclusive
*
bool
,
sortBy
,
sortOrder
string
)
([]
service
.
Group
,
int64
,
error
)
{
return
s
.
groups
,
int64
(
len
(
s
.
groups
)),
nil
return
s
.
groups
,
int64
(
len
(
s
.
groups
)),
nil
}
}
...
...
backend/internal/handler/admin/user_handler.go
View file @
724f8e89
...
@@ -7,6 +7,7 @@ import (
...
@@ -7,6 +7,7 @@ import (
"github.com/Wei-Shaw/sub2api/internal/handler/dto"
"github.com/Wei-Shaw/sub2api/internal/handler/dto"
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
servermiddleware
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin"
...
@@ -82,6 +83,10 @@ type BindUserAuthIdentityChannelRequest struct {
...
@@ -82,6 +83,10 @@ type BindUserAuthIdentityChannelRequest struct {
Metadata
map
[
string
]
any
`json:"metadata"`
Metadata
map
[
string
]
any
`json:"metadata"`
}
}
type
ResolveAuthIdentityMigrationReportRequest
struct
{
ResolutionNote
string
`json:"resolution_note"`
}
// List handles listing all users with pagination
// List handles listing all users with pagination
// GET /api/v1/admin/users
// GET /api/v1/admin/users
// Query params:
// Query params:
...
@@ -252,6 +257,40 @@ func (h *UserHandler) BindAuthIdentity(c *gin.Context) {
...
@@ -252,6 +257,40 @@ func (h *UserHandler) BindAuthIdentity(c *gin.Context) {
response
.
Success
(
c
,
result
)
response
.
Success
(
c
,
result
)
}
}
// ResolveAuthIdentityMigrationReport marks a migration report as resolved.
// POST /api/v1/admin/users/auth-identity-migration-reports/:id/resolve
func
(
h
*
UserHandler
)
ResolveAuthIdentityMigrationReport
(
c
*
gin
.
Context
)
{
reportID
,
err
:=
strconv
.
ParseInt
(
c
.
Param
(
"id"
),
10
,
64
)
if
err
!=
nil
{
response
.
BadRequest
(
c
,
"Invalid report ID"
)
return
}
subject
,
ok
:=
servermiddleware
.
GetAuthSubjectFromContext
(
c
)
if
!
ok
||
subject
.
UserID
<=
0
{
response
.
Unauthorized
(
c
,
"Authentication required"
)
return
}
var
req
ResolveAuthIdentityMigrationReportRequest
if
err
:=
c
.
ShouldBindJSON
(
&
req
);
err
!=
nil
{
response
.
BadRequest
(
c
,
"Invalid request: "
+
err
.
Error
())
return
}
report
,
err
:=
h
.
adminService
.
ResolveAuthIdentityMigrationReport
(
c
.
Request
.
Context
(),
reportID
,
subject
.
UserID
,
req
.
ResolutionNote
,
)
if
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
return
}
response
.
Success
(
c
,
report
)
}
// Create handles creating a new user
// Create handles creating a new user
// POST /api/v1/admin/users
// POST /api/v1/admin/users
func
(
h
*
UserHandler
)
Create
(
c
*
gin
.
Context
)
{
func
(
h
*
UserHandler
)
Create
(
c
*
gin
.
Context
)
{
...
...
backend/internal/server/routes/admin.go
View file @
724f8e89
...
@@ -212,6 +212,7 @@ func registerUserManagementRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
...
@@ -212,6 +212,7 @@ func registerUserManagementRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
{
{
users
.
GET
(
"/auth-identity-migration-reports/summary"
,
h
.
Admin
.
User
.
GetAuthIdentityMigrationReportSummary
)
users
.
GET
(
"/auth-identity-migration-reports/summary"
,
h
.
Admin
.
User
.
GetAuthIdentityMigrationReportSummary
)
users
.
GET
(
"/auth-identity-migration-reports"
,
h
.
Admin
.
User
.
ListAuthIdentityMigrationReports
)
users
.
GET
(
"/auth-identity-migration-reports"
,
h
.
Admin
.
User
.
ListAuthIdentityMigrationReports
)
users
.
POST
(
"/auth-identity-migration-reports/:id/resolve"
,
h
.
Admin
.
User
.
ResolveAuthIdentityMigrationReport
)
users
.
GET
(
""
,
h
.
Admin
.
User
.
List
)
users
.
GET
(
""
,
h
.
Admin
.
User
.
List
)
users
.
GET
(
"/:id"
,
h
.
Admin
.
User
.
GetByID
)
users
.
GET
(
"/:id"
,
h
.
Admin
.
User
.
GetByID
)
users
.
POST
(
"/:id/auth-identities"
,
h
.
Admin
.
User
.
BindAuthIdentity
)
users
.
POST
(
"/:id/auth-identities"
,
h
.
Admin
.
User
.
BindAuthIdentity
)
...
...
backend/internal/service/admin_service.go
View file @
724f8e89
...
@@ -42,6 +42,7 @@ type AdminService interface {
...
@@ -42,6 +42,7 @@ type AdminService interface {
ListAuthIdentityMigrationReports
(
ctx
context
.
Context
,
reportType
string
,
page
,
pageSize
int
)
([]
AuthIdentityMigrationReport
,
int64
,
error
)
ListAuthIdentityMigrationReports
(
ctx
context
.
Context
,
reportType
string
,
page
,
pageSize
int
)
([]
AuthIdentityMigrationReport
,
int64
,
error
)
GetAuthIdentityMigrationReportSummary
(
ctx
context
.
Context
)
(
*
AuthIdentityMigrationReportSummary
,
error
)
GetAuthIdentityMigrationReportSummary
(
ctx
context
.
Context
)
(
*
AuthIdentityMigrationReportSummary
,
error
)
BindUserAuthIdentity
(
ctx
context
.
Context
,
userID
int64
,
input
AdminBindAuthIdentityInput
)
(
*
AdminBoundAuthIdentity
,
error
)
BindUserAuthIdentity
(
ctx
context
.
Context
,
userID
int64
,
input
AdminBindAuthIdentityInput
)
(
*
AdminBoundAuthIdentity
,
error
)
ResolveAuthIdentityMigrationReport
(
ctx
context
.
Context
,
reportID
,
resolvedByUserID
int64
,
resolutionNote
string
)
(
*
AuthIdentityMigrationReport
,
error
)
// Group management
// Group management
ListGroups
(
ctx
context
.
Context
,
page
,
pageSize
int
,
platform
,
status
,
search
string
,
isExclusive
*
bool
,
sortBy
,
sortOrder
string
)
([]
Group
,
int64
,
error
)
ListGroups
(
ctx
context
.
Context
,
page
,
pageSize
int
,
platform
,
status
,
search
string
,
isExclusive
*
bool
,
sortBy
,
sortOrder
string
)
([]
Group
,
int64
,
error
)
...
@@ -137,16 +138,21 @@ type UpdateUserInput struct {
...
@@ -137,16 +138,21 @@ type UpdateUserInput struct {
}
}
type
AuthIdentityMigrationReport
struct
{
type
AuthIdentityMigrationReport
struct
{
ID
int64
`json:"id"`
ID
int64
`json:"id"`
ReportType
string
`json:"report_type"`
ReportType
string
`json:"report_type"`
ReportKey
string
`json:"report_key"`
ReportKey
string
`json:"report_key"`
Details
map
[
string
]
any
`json:"details"`
Details
map
[
string
]
any
`json:"details"`
CreatedAt
time
.
Time
`json:"created_at"`
CreatedAt
time
.
Time
`json:"created_at"`
ResolvedAt
*
time
.
Time
`json:"resolved_at,omitempty"`
ResolvedByUserID
*
int64
`json:"resolved_by_user_id,omitempty"`
ResolutionNote
string
`json:"resolution_note,omitempty"`
}
}
type
AuthIdentityMigrationReportSummary
struct
{
type
AuthIdentityMigrationReportSummary
struct
{
Total
int64
`json:"total"`
Total
int64
`json:"total"`
ByType
map
[
string
]
int64
`json:"by_type"`
OpenTotal
int64
`json:"open_total"`
ResolvedTotal
int64
`json:"resolved_total"`
ByType
map
[
string
]
int64
`json:"by_type"`
}
}
type
AdminBindAuthIdentityInput
struct
{
type
AdminBindAuthIdentityInput
struct
{
...
@@ -874,7 +880,7 @@ WHERE ($1 = '' OR report_type = $1)`,
...
@@ -874,7 +880,7 @@ WHERE ($1 = '' OR report_type = $1)`,
}
}
rows
,
err
:=
db
.
QueryContext
(
ctx
,
`
rows
,
err
:=
db
.
QueryContext
(
ctx
,
`
SELECT id, report_type, report_key, details, created_at
SELECT id, report_type, report_key, details, created_at
, resolved_at, resolved_by_user_id, resolution_note
FROM auth_identity_migration_reports
FROM auth_identity_migration_reports
WHERE ($1 = '' OR report_type = $1)
WHERE ($1 = '' OR report_type = $1)
ORDER BY created_at DESC, id DESC
ORDER BY created_at DESC, id DESC
...
@@ -909,7 +915,11 @@ func (s *adminServiceImpl) GetAuthIdentityMigrationReportSummary(ctx context.Con
...
@@ -909,7 +915,11 @@ func (s *adminServiceImpl) GetAuthIdentityMigrationReportSummary(ctx context.Con
}
}
rows
,
err
:=
db
.
QueryContext
(
ctx
,
`
rows
,
err
:=
db
.
QueryContext
(
ctx
,
`
SELECT report_type, COUNT(*)
SELECT
report_type,
COUNT(*),
SUM(CASE WHEN resolved_at IS NULL THEN 1 ELSE 0 END),
SUM(CASE WHEN resolved_at IS NOT NULL THEN 1 ELSE 0 END)
FROM auth_identity_migration_reports
FROM auth_identity_migration_reports
GROUP BY report_type
GROUP BY report_type
ORDER BY report_type ASC`
)
ORDER BY report_type ASC`
)
...
@@ -924,11 +934,15 @@ ORDER BY report_type ASC`)
...
@@ -924,11 +934,15 @@ ORDER BY report_type ASC`)
for
rows
.
Next
()
{
for
rows
.
Next
()
{
var
reportType
string
var
reportType
string
var
count
int64
var
count
int64
if
err
:=
rows
.
Scan
(
&
reportType
,
&
count
);
err
!=
nil
{
var
openCount
int64
var
resolvedCount
int64
if
err
:=
rows
.
Scan
(
&
reportType
,
&
count
,
&
openCount
,
&
resolvedCount
);
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
summary
.
ByType
[
reportType
]
=
count
summary
.
ByType
[
reportType
]
=
count
summary
.
Total
+=
count
summary
.
Total
+=
count
summary
.
OpenTotal
+=
openCount
summary
.
ResolvedTotal
+=
resolvedCount
}
}
if
err
:=
rows
.
Err
();
err
!=
nil
{
if
err
:=
rows
.
Err
();
err
!=
nil
{
return
nil
,
err
return
nil
,
err
...
@@ -936,6 +950,56 @@ ORDER BY report_type ASC`)
...
@@ -936,6 +950,56 @@ ORDER BY report_type ASC`)
return
summary
,
nil
return
summary
,
nil
}
}
func
(
s
*
adminServiceImpl
)
ResolveAuthIdentityMigrationReport
(
ctx
context
.
Context
,
reportID
,
resolvedByUserID
int64
,
resolutionNote
string
)
(
*
AuthIdentityMigrationReport
,
error
)
{
if
reportID
<=
0
{
return
nil
,
infraerrors
.
BadRequest
(
"INVALID_INPUT"
,
"report id must be greater than 0"
)
}
if
resolvedByUserID
<=
0
{
return
nil
,
infraerrors
.
BadRequest
(
"INVALID_INPUT"
,
"resolved_by_user_id must be greater than 0"
)
}
db
,
err
:=
s
.
adminSQLDB
()
if
err
!=
nil
{
return
nil
,
err
}
now
:=
time
.
Now
()
.
UTC
()
result
,
err
:=
db
.
ExecContext
(
ctx
,
`
UPDATE auth_identity_migration_reports
SET
resolved_at = COALESCE(resolved_at, $2),
resolved_by_user_id = COALESCE(resolved_by_user_id, $3),
resolution_note = $4
WHERE id = $1`
,
reportID
,
now
,
resolvedByUserID
,
strings
.
TrimSpace
(
resolutionNote
),
)
if
err
!=
nil
{
return
nil
,
err
}
affected
,
err
:=
result
.
RowsAffected
()
if
err
!=
nil
{
return
nil
,
err
}
if
affected
==
0
{
return
nil
,
infraerrors
.
NotFound
(
"AUTH_IDENTITY_MIGRATION_REPORT_NOT_FOUND"
,
"auth identity migration report not found"
)
}
row
:=
db
.
QueryRowContext
(
ctx
,
`
SELECT id, report_type, report_key, details, created_at, resolved_at, resolved_by_user_id, resolution_note
FROM auth_identity_migration_reports
WHERE id = $1`
,
reportID
,
)
report
,
err
:=
scanAuthIdentityMigrationReport
(
row
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
report
,
nil
}
func
(
s
*
adminServiceImpl
)
BindUserAuthIdentity
(
ctx
context
.
Context
,
userID
int64
,
input
AdminBindAuthIdentityInput
)
(
*
AdminBoundAuthIdentity
,
error
)
{
func
(
s
*
adminServiceImpl
)
BindUserAuthIdentity
(
ctx
context
.
Context
,
userID
int64
,
input
AdminBindAuthIdentityInput
)
(
*
AdminBoundAuthIdentity
,
error
)
{
if
userID
<=
0
{
if
userID
<=
0
{
return
nil
,
infraerrors
.
BadRequest
(
"INVALID_INPUT"
,
"user_id must be greater than 0"
)
return
nil
,
infraerrors
.
BadRequest
(
"INVALID_INPUT"
,
"user_id must be greater than 0"
)
...
@@ -1170,10 +1234,22 @@ func cloneAdminAuthIdentityMetadata(input map[string]any) map[string]any {
...
@@ -1170,10 +1234,22 @@ func cloneAdminAuthIdentityMetadata(input map[string]any) map[string]any {
func
scanAuthIdentityMigrationReport
(
scanner
interface
{
Scan
(
dest
...
any
)
error
})
(
AuthIdentityMigrationReport
,
error
)
{
func
scanAuthIdentityMigrationReport
(
scanner
interface
{
Scan
(
dest
...
any
)
error
})
(
AuthIdentityMigrationReport
,
error
)
{
var
(
var
(
report
AuthIdentityMigrationReport
report
AuthIdentityMigrationReport
details
[]
byte
details
[]
byte
resolvedAt
sql
.
NullTime
resolvedByUserID
sql
.
NullInt64
resolutionNote
sql
.
NullString
)
)
if
err
:=
scanner
.
Scan
(
&
report
.
ID
,
&
report
.
ReportType
,
&
report
.
ReportKey
,
&
details
,
&
report
.
CreatedAt
);
err
!=
nil
{
if
err
:=
scanner
.
Scan
(
&
report
.
ID
,
&
report
.
ReportType
,
&
report
.
ReportKey
,
&
details
,
&
report
.
CreatedAt
,
&
resolvedAt
,
&
resolvedByUserID
,
&
resolutionNote
,
);
err
!=
nil
{
return
AuthIdentityMigrationReport
{},
err
return
AuthIdentityMigrationReport
{},
err
}
}
report
.
Details
=
map
[
string
]
any
{}
report
.
Details
=
map
[
string
]
any
{}
...
@@ -1182,6 +1258,15 @@ func scanAuthIdentityMigrationReport(scanner interface{ Scan(dest ...any) error
...
@@ -1182,6 +1258,15 @@ func scanAuthIdentityMigrationReport(scanner interface{ Scan(dest ...any) error
return
AuthIdentityMigrationReport
{},
err
return
AuthIdentityMigrationReport
{},
err
}
}
}
}
if
resolvedAt
.
Valid
{
report
.
ResolvedAt
=
&
resolvedAt
.
Time
}
if
resolvedByUserID
.
Valid
{
report
.
ResolvedByUserID
=
&
resolvedByUserID
.
Int64
}
if
resolutionNote
.
Valid
{
report
.
ResolutionNote
=
resolutionNote
.
String
}
return
report
,
nil
return
report
,
nil
}
}
...
...
backend/internal/service/admin_service_identity_migration_report_test.go
View file @
724f8e89
...
@@ -30,7 +30,10 @@ func newAdminServiceMigrationReportTestClient(t *testing.T) *dbent.Client {
...
@@ -30,7 +30,10 @@ func newAdminServiceMigrationReportTestClient(t *testing.T) *dbent.Client {
report_type TEXT NOT NULL,
report_type TEXT NOT NULL,
report_key TEXT NOT NULL,
report_key TEXT NOT NULL,
details TEXT NOT NULL DEFAULT '{}',
details TEXT NOT NULL DEFAULT '{}',
created_at DATETIME NOT NULL
created_at DATETIME NOT NULL,
resolved_at DATETIME NULL,
resolved_by_user_id INTEGER NULL,
resolution_note TEXT NOT NULL DEFAULT ''
)`
)
)`
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
...
@@ -87,6 +90,35 @@ VALUES
...
@@ -87,6 +90,35 @@ VALUES
summary
,
err
:=
svc
.
GetAuthIdentityMigrationReportSummary
(
context
.
Background
())
summary
,
err
:=
svc
.
GetAuthIdentityMigrationReportSummary
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
int64
(
3
),
summary
.
Total
)
require
.
Equal
(
t
,
int64
(
3
),
summary
.
Total
)
require
.
Equal
(
t
,
int64
(
3
),
summary
.
OpenTotal
)
require
.
Zero
(
t
,
summary
.
ResolvedTotal
)
require
.
Equal
(
t
,
int64
(
1
),
summary
.
ByType
[
"oidc_synthetic_email_requires_manual_recovery"
])
require
.
Equal
(
t
,
int64
(
1
),
summary
.
ByType
[
"oidc_synthetic_email_requires_manual_recovery"
])
require
.
Equal
(
t
,
int64
(
2
),
summary
.
ByType
[
"wechat_provider_key_conflict"
])
require
.
Equal
(
t
,
int64
(
2
),
summary
.
ByType
[
"wechat_provider_key_conflict"
])
}
}
func
TestAdminServiceResolveAuthIdentityMigrationReport
(
t
*
testing
.
T
)
{
client
:=
newAdminServiceMigrationReportTestClient
(
t
)
driver
,
ok
:=
client
.
Driver
()
.
(
*
entsql
.
Driver
)
require
.
True
(
t
,
ok
)
now
:=
time
.
Now
()
.
UTC
()
_
,
err
:=
driver
.
DB
()
.
ExecContext
(
context
.
Background
(),
`
INSERT INTO auth_identity_migration_reports (report_type, report_key, details, created_at)
VALUES ($1, $2, $3, $4)`
,
"oidc_synthetic_email_requires_manual_recovery"
,
"u-1"
,
`{"user_id":1}`
,
now
,
)
require
.
NoError
(
t
,
err
)
svc
:=
&
adminServiceImpl
{
entClient
:
client
}
report
,
err
:=
svc
.
ResolveAuthIdentityMigrationReport
(
context
.
Background
(),
1
,
99
,
"resolved by admin binding"
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
report
.
ResolvedAt
)
require
.
NotNil
(
t
,
report
.
ResolvedByUserID
)
require
.
Equal
(
t
,
int64
(
99
),
*
report
.
ResolvedByUserID
)
require
.
Equal
(
t
,
"resolved by admin binding"
,
report
.
ResolutionNote
)
summary
,
err
:=
svc
.
GetAuthIdentityMigrationReportSummary
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
Zero
(
t
,
summary
.
OpenTotal
)
require
.
Equal
(
t
,
int64
(
1
),
summary
.
ResolvedTotal
)
}
backend/migrations/114_auth_identity_migration_report_resolution.sql
0 → 100644
View file @
724f8e89
ALTER
TABLE
auth_identity_migration_reports
ADD
COLUMN
IF
NOT
EXISTS
resolved_at
TIMESTAMPTZ
NULL
;
ALTER
TABLE
auth_identity_migration_reports
ADD
COLUMN
IF
NOT
EXISTS
resolved_by_user_id
BIGINT
NULL
;
ALTER
TABLE
auth_identity_migration_reports
ADD
COLUMN
IF
NOT
EXISTS
resolution_note
TEXT
NOT
NULL
DEFAULT
''
;
CREATE
INDEX
IF
NOT
EXISTS
idx_auth_identity_migration_reports_resolved_at
ON
auth_identity_migration_reports
(
resolved_at
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment