mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 19:11:25 +01:00
150 lines
7.3 KiB
Go
150 lines
7.3 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestAdminPromptAndFlagsReachEquivalentPayloads(t *testing.T) {
|
|
var payloads []map[string]any
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(t, http.MethodPost, r.Method)
|
|
var payload map[string]any
|
|
require.NoError(t, json.NewDecoder(r.Body).Decode(&payload))
|
|
payloads = append(payloads, payload)
|
|
_, _ = w.Write([]byte(`{"id":1,"login":"account"}`))
|
|
}))
|
|
defer server.Close()
|
|
deps, out, _ := serverDeps(t, server.URL)
|
|
prompt := &scriptedPrompter{input: "account@example.test", secret: " preserved password ", accept: true}
|
|
deps.Prompter = prompt
|
|
deps.Streams.InTTY = true
|
|
deps.Streams.ErrTTY = true
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"admin", "user", "create", "account", "--full-name", "Test Account"}))
|
|
require.Equal(t, []string{"Email address"}, prompt.asked)
|
|
require.Len(t, prompt.secrets, 2)
|
|
require.Empty(t, prompt.confirmations)
|
|
out.Reset()
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"admin", "user", "create", "account", "--full-name", "Test Account", "--email", "account@example.test", "--password", " preserved password ", "--no-input"}))
|
|
require.Equal(t, payloads[0], payloads[1])
|
|
require.Len(t, prompt.asked, 1)
|
|
require.Len(t, prompt.secrets, 2)
|
|
require.NotContains(t, out.String(), "password")
|
|
}
|
|
|
|
func TestAdminUserEditSetsMustChangePasswordOnlyWhenPassed(t *testing.T) {
|
|
var edits []map[string]any
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodPatch {
|
|
var payload map[string]any
|
|
require.NoError(t, json.NewDecoder(r.Body).Decode(&payload))
|
|
edits = append(edits, payload)
|
|
}
|
|
_, _ = w.Write([]byte(`[{"id":2,"login":"bob"}]`))
|
|
}))
|
|
defer server.Close()
|
|
deps, _, _ := serverDeps(t, server.URL)
|
|
for _, flags := range [][]string{{"--password", "new password"}, {"--password", "new password", "--must-change-password"}, {"--must-change-password=false"}} {
|
|
require.NoError(t, Execute(context.Background(), deps, append([]string{"admin", "user", "edit", "bob", "--no-input"}, flags...)))
|
|
}
|
|
require.Len(t, edits, 3)
|
|
require.Equal(t, "new password", edits[0]["password"])
|
|
require.Nil(t, edits[0]["must_change_password"])
|
|
require.Equal(t, true, edits[1]["must_change_password"])
|
|
require.Equal(t, false, edits[2]["must_change_password"])
|
|
}
|
|
|
|
func TestAdminUserListShowsRolesAndStatuses(t *testing.T) {
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(t, "/api/v1/admin/users", r.URL.Path)
|
|
require.Equal(t, "li", r.URL.Query().Get("q"))
|
|
_, _ = w.Write([]byte(`[
|
|
{"id":1,"login":"alice","full_name":"Alice","email":"alice@example.test","is_admin":true,"active":true,"created":"2026-10-01T12:00:00Z"},
|
|
{"id":2,"login":"elisa","email":"elisa@example.test","restricted":true,"active":true,"created":"2026-10-02T12:00:00Z"},
|
|
{"id":3,"login":"lisbeth","email":"lisbeth@example.test","prohibit_login":true,"active":true,"created":"2026-10-03T12:00:00Z"},
|
|
{"id":4,"login":"lin","email":"lin@example.test","active":false,"created":"2026-10-04T12:00:00Z"}]`))
|
|
}))
|
|
defer server.Close()
|
|
deps, out, _ := serverDeps(t, server.URL)
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"admin", "user", "list", "--query", "li"}))
|
|
require.Equal(t, "1\talice\tAlice\talice@example.test\tadmin\tactive\t2026-10-01T12:00:00Z\n"+
|
|
"2\telisa\t\telisa@example.test\trestricted\tactive\t2026-10-02T12:00:00Z\n"+
|
|
"3\tlisbeth\t\tlisbeth@example.test\tuser\tlogin prohibited\t2026-10-03T12:00:00Z\n"+
|
|
"4\tlin\t\tlin@example.test\tuser\tinactive\t2026-10-04T12:00:00Z\n", out.String())
|
|
}
|
|
|
|
func TestAdminUserDeleteOffersPurgeForOwners(t *testing.T) {
|
|
var deletes []string
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
require.Equal(t, "/api/v1/admin/users", r.URL.Path)
|
|
_, _ = w.Write([]byte(`[{"id":2,"login":"bob"}]`))
|
|
case http.MethodDelete:
|
|
deletes = append(deletes, r.URL.RequestURI())
|
|
if r.URL.Query().Get("purge") != "true" {
|
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
_, _ = w.Write([]byte(`{"message":"user still has ownership of repositories [uid: 2]"}`))
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
deps, _, _ := serverDeps(t, server.URL)
|
|
err := Execute(context.Background(), deps, []string{"admin", "user", "delete", "bob", "--yes"})
|
|
require.EqualError(t, err, `user "bob" still owns repositories; transfer or delete them, or pass --purge to delete them with the user`)
|
|
|
|
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
|
const typed = "Delete user bob with their repositories, packages and organization memberships, and the organizations they are the last owner of with those organizations' repositories? This cannot be undone. Type bob to confirm:"
|
|
prompt := &scriptedPrompter{inputs: map[string]string{typed: "bob"}}
|
|
deps.Prompter = prompt
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"admin", "user", "delete", "bob", "--purge"}))
|
|
require.Equal(t, []string{typed}, prompt.asked)
|
|
require.Equal(t, []string{"/api/v1/admin/users/bob", "/api/v1/admin/users/bob?purge=true"}, deletes)
|
|
}
|
|
|
|
func TestAdminUserDeleteOffersPurgeForMembersAndPackageOwners(t *testing.T) {
|
|
message := "user still has membership of organizations [uid: 2]"
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodGet {
|
|
_, _ = w.Write([]byte(`[{"id":2,"login":"bob"}]`))
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
_, _ = w.Write([]byte(`{"message":"` + message + `"}`))
|
|
}))
|
|
defer server.Close()
|
|
deps, _, _ := serverDeps(t, server.URL)
|
|
err := Execute(context.Background(), deps, []string{"admin", "user", "delete", "bob", "--yes"})
|
|
require.EqualError(t, err, `user "bob" is still a member of organizations or owns packages; transfer or delete them, or pass --purge to delete them with the user`)
|
|
message = "user still has ownership of packages [uid: 2]"
|
|
err = Execute(context.Background(), deps, []string{"admin", "user", "delete", "bob", "--yes"})
|
|
require.ErrorContains(t, err, "pass --purge")
|
|
}
|
|
|
|
func TestAdminUserCreateLeavesVisibilityToTheInstanceUnlessPassed(t *testing.T) {
|
|
var payloads []map[string]any
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var payload map[string]any
|
|
require.NoError(t, json.NewDecoder(r.Body).Decode(&payload))
|
|
payloads = append(payloads, payload)
|
|
_, _ = w.Write([]byte(`{"id":1,"login":"account"}`))
|
|
}))
|
|
defer server.Close()
|
|
deps, _, _ := serverDeps(t, server.URL)
|
|
args := []string{"admin", "user", "create", "account", "--email", "account@example.test", "--password", "secret", "--no-input"}
|
|
require.NoError(t, Execute(context.Background(), deps, args))
|
|
require.NoError(t, Execute(context.Background(), deps, append(args, "--visibility", "limited")))
|
|
require.Len(t, payloads, 2)
|
|
require.Nil(t, payloads[0]["visibility"], "an omitted visibility lets DEFAULT_USER_VISIBILITY apply")
|
|
require.Equal(t, "limited", payloads[1]["visibility"])
|
|
}
|