Fix org contact email not clearable once set (#36975)
When the email field was submitted as empty in org settings (web and API), the previous guard `if form.Email != ""` silently skipped the update, making it impossible to remove a contact email after it was set. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -137,34 +137,45 @@ func TestAPIOrgGeneral(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("OrgEdit", func(t *testing.T) {
|
||||
org := api.EditOrgOption{
|
||||
FullName: "Org3 organization new full name",
|
||||
Description: "A new description",
|
||||
Website: "https://try.gitea.io/new",
|
||||
Location: "Beijing",
|
||||
Visibility: "private",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org).AddTokenAuth(user1Token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"})
|
||||
assert.NotEqual(t, api.VisibleTypeLimited, org3.Visibility)
|
||||
|
||||
var apiOrg api.Organization
|
||||
DecodeJSON(t, resp, &apiOrg)
|
||||
org3Edit := api.EditOrgOption{
|
||||
FullName: new("new full name"),
|
||||
Description: new("new description"),
|
||||
Website: new("https://org3-new-website.example.com"),
|
||||
Location: new("new location"),
|
||||
Visibility: new("limited"),
|
||||
Email: new("org3-new-email@example.com"),
|
||||
}
|
||||
req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org3Edit).AddTokenAuth(user1Token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
apiOrg := DecodeJSON(t, resp, &api.Organization{})
|
||||
|
||||
assert.Equal(t, "org3", apiOrg.Name)
|
||||
assert.Equal(t, org.FullName, apiOrg.FullName)
|
||||
assert.Equal(t, org.Description, apiOrg.Description)
|
||||
assert.Equal(t, org.Website, apiOrg.Website)
|
||||
assert.Equal(t, org.Location, apiOrg.Location)
|
||||
assert.Equal(t, org.Visibility, apiOrg.Visibility)
|
||||
assert.Equal(t, *org3Edit.FullName, apiOrg.FullName)
|
||||
assert.Equal(t, *org3Edit.Description, apiOrg.Description)
|
||||
assert.Equal(t, *org3Edit.Website, apiOrg.Website)
|
||||
assert.Equal(t, *org3Edit.Location, apiOrg.Location)
|
||||
assert.Equal(t, *org3Edit.Visibility, apiOrg.Visibility)
|
||||
assert.Equal(t, *org3Edit.Email, apiOrg.Email)
|
||||
org3 = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"})
|
||||
assert.Equal(t, api.VisibleTypeLimited, org3.Visibility)
|
||||
|
||||
// empty email can clear the email, nil fields won't change the settings
|
||||
req = NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &api.EditOrgOption{
|
||||
Email: new(""),
|
||||
}).AddTokenAuth(user1Token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
apiOrg = DecodeJSON(t, resp, &api.Organization{})
|
||||
assert.Equal(t, *org3Edit.FullName, apiOrg.FullName)
|
||||
assert.Equal(t, *org3Edit.Visibility, apiOrg.Visibility)
|
||||
assert.Empty(t, apiOrg.Email)
|
||||
})
|
||||
|
||||
t.Run("OrgEditBadVisibility", func(t *testing.T) {
|
||||
t.Run("OrgEditInvalidVisibility", func(t *testing.T) {
|
||||
org := api.EditOrgOption{
|
||||
FullName: "Org3 organization new full name",
|
||||
Description: "A new description",
|
||||
Website: "https://try.gitea.io/new",
|
||||
Location: "Beijing",
|
||||
Visibility: "badvisibility",
|
||||
Visibility: new("invalid-visibility"),
|
||||
}
|
||||
req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org).AddTokenAuth(user1Token)
|
||||
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
@@ -410,12 +410,13 @@ func logUnexpectedResponse(t testing.TB, recorder *httptest.ResponseRecorder) {
|
||||
}
|
||||
}
|
||||
|
||||
func DecodeJSON(t testing.TB, resp *httptest.ResponseRecorder, v any) {
|
||||
func DecodeJSON[T any](t testing.TB, resp *httptest.ResponseRecorder, v T) (ret T) {
|
||||
t.Helper()
|
||||
|
||||
// FIXME: JSON-KEY-CASE: for testing purpose only, because many structs don't provide `json` tags, they just use capitalized field names
|
||||
decoder := json.NewDecoderCaseInsensitive(resp.Body)
|
||||
require.NoError(t, decoder.Decode(v))
|
||||
return v
|
||||
}
|
||||
|
||||
func VerifyJSONSchema(t testing.TB, resp *httptest.ResponseRecorder, schemaFile string) {
|
||||
|
||||
@@ -23,9 +23,18 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestOrgRepos(t *testing.T) {
|
||||
func TestOrg(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
t.Run("OrgRepos", testOrgRepos)
|
||||
t.Run("PrivateOrg", testPrivateOrg)
|
||||
t.Run("LimitedOrg", testLimitedOrg)
|
||||
t.Run("OrgMembers", testOrgMembers)
|
||||
t.Run("OrgRestrictedUser", testOrgRestrictedUser)
|
||||
t.Run("TeamSearch", testTeamSearch)
|
||||
t.Run("OrgSettings", testOrgSettings)
|
||||
}
|
||||
|
||||
func testOrgRepos(t *testing.T) {
|
||||
var (
|
||||
users = []string{"user1", "user2"}
|
||||
cases = map[string][]string{
|
||||
@@ -53,10 +62,8 @@ func TestOrgRepos(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLimitedOrg(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// not logged in user
|
||||
func testLimitedOrg(t *testing.T) {
|
||||
// not logged-in user
|
||||
req := NewRequest(t, "GET", "/limited_org")
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequest(t, "GET", "/limited_org/public_repo_on_limited_org")
|
||||
@@ -83,10 +90,8 @@ func TestLimitedOrg(t *testing.T) {
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestPrivateOrg(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// not logged in user
|
||||
func testPrivateOrg(t *testing.T) {
|
||||
// not logged-in user
|
||||
req := NewRequest(t, "GET", "/privated_org")
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequest(t, "GET", "/privated_org/public_repo_on_private_org")
|
||||
@@ -122,10 +127,8 @@ func TestPrivateOrg(t *testing.T) {
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestOrgMembers(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// not logged in user
|
||||
func testOrgMembers(t *testing.T) {
|
||||
// not logged-in user
|
||||
req := NewRequest(t, "GET", "/org/org25/members")
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
@@ -140,9 +143,7 @@ func TestOrgMembers(t *testing.T) {
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestOrgRestrictedUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
func testOrgRestrictedUser(t *testing.T) {
|
||||
// privated_org is a private org who has id 23
|
||||
orgName := "privated_org"
|
||||
|
||||
@@ -200,9 +201,7 @@ func TestOrgRestrictedUser(t *testing.T) {
|
||||
restrictedSession.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestTeamSearch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
func testTeamSearch(t *testing.T) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17})
|
||||
|
||||
@@ -251,3 +250,24 @@ func TestTeamSearch(t *testing.T) {
|
||||
assert.Len(t, teams, 1) // team permission is "write", so can write "code"
|
||||
})
|
||||
}
|
||||
|
||||
func testOrgSettings(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
req := NewRequestWithValues(t, "POST", "/org/org3/settings", map[string]string{
|
||||
"full_name": "org3 new full name",
|
||||
"email": "org3-new-email@example.com",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
|
||||
assert.Equal(t, "org3 new full name", org.FullName)
|
||||
assert.Equal(t, "org3-new-email@example.com", org.Email)
|
||||
|
||||
req = NewRequestWithValues(t, "POST", "/org/org3/settings", map[string]string{
|
||||
"email": "", // empty email means "clear email"
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
|
||||
assert.Equal(t, "org3 new full name", org.FullName)
|
||||
assert.Empty(t, org.Email)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user