mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Add DISABLE_ORGANIZATIONS_PAGE and DISABLE_CODE_PAGE settings for explore pages and fix an issue related to user search (#32288)
				
					
				
			These settings can allow users to only display the repositories explore page. Thanks to yp05327 and wxiaoguang ! --------- Co-authored-by: Giteabot <teabot@gitea.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		| @@ -907,6 +907,24 @@ LEVEL = Info | ||||
| ;; Valid site url schemes for user profiles | ||||
| ;VALID_SITE_URL_SCHEMES=http,https | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;[service.explore] | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; | ||||
| ;; Only allow signed in users to view the explore pages. | ||||
| ;REQUIRE_SIGNIN_VIEW = false | ||||
| ;; | ||||
| ;; Disable the users explore page. | ||||
| ;DISABLE_USERS_PAGE = false | ||||
| ;; | ||||
| ;; Disable the organizations explore page. | ||||
| ;DISABLE_ORGANIZATIONS_PAGE = false | ||||
| ;; | ||||
| ;; Disable the code explore page. | ||||
| ;DISABLE_CODE_PAGE = false | ||||
| ;; | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|   | ||||
| @@ -90,8 +90,10 @@ var Service = struct { | ||||
|  | ||||
| 	// Explore page settings | ||||
| 	Explore struct { | ||||
| 		RequireSigninView bool `ini:"REQUIRE_SIGNIN_VIEW"` | ||||
| 		DisableUsersPage  bool `ini:"DISABLE_USERS_PAGE"` | ||||
| 		RequireSigninView        bool `ini:"REQUIRE_SIGNIN_VIEW"` | ||||
| 		DisableUsersPage         bool `ini:"DISABLE_USERS_PAGE"` | ||||
| 		DisableOrganizationsPage bool `ini:"DISABLE_ORGANIZATIONS_PAGE"` | ||||
| 		DisableCodePage          bool `ini:"DISABLE_CODE_PAGE"` | ||||
| 	} `ini:"service.explore"` | ||||
| }{ | ||||
| 	AllowedUserVisibilityModesSlice: []bool{true, true, true}, | ||||
|   | ||||
| @@ -356,12 +356,20 @@ func reqToken() func(ctx *context.APIContext) { | ||||
|  | ||||
| func reqExploreSignIn() func(ctx *context.APIContext) { | ||||
| 	return func(ctx *context.APIContext) { | ||||
| 		if setting.Service.Explore.RequireSigninView && !ctx.IsSigned { | ||||
| 		if (setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView) && !ctx.IsSigned { | ||||
| 			ctx.Error(http.StatusUnauthorized, "reqExploreSignIn", "you must be signed in to search for users") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func reqUsersExploreEnabled() func(ctx *context.APIContext) { | ||||
| 	return func(ctx *context.APIContext) { | ||||
| 		if setting.Service.Explore.DisableUsersPage { | ||||
| 			ctx.NotFound() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func reqBasicOrRevProxyAuth() func(ctx *context.APIContext) { | ||||
| 	return func(ctx *context.APIContext) { | ||||
| 		if ctx.IsSigned && setting.Service.EnableReverseProxyAuthAPI && ctx.Data["AuthedMethod"].(string) == auth.ReverseProxyMethodName { | ||||
| @@ -955,7 +963,7 @@ func Routes() *web.Router { | ||||
|  | ||||
| 		// Users (requires user scope) | ||||
| 		m.Group("/users", func() { | ||||
| 			m.Get("/search", reqExploreSignIn(), user.Search) | ||||
| 			m.Get("/search", reqExploreSignIn(), reqUsersExploreEnabled(), user.Search) | ||||
|  | ||||
| 			m.Group("/{username}", func() { | ||||
| 				m.Get("", reqExploreSignIn(), user.GetInfo) | ||||
|   | ||||
| @@ -21,12 +21,13 @@ const ( | ||||
|  | ||||
| // Code render explore code page | ||||
| func Code(ctx *context.Context) { | ||||
| 	if !setting.Indexer.RepoIndexerEnabled { | ||||
| 	if !setting.Indexer.RepoIndexerEnabled || setting.Service.Explore.DisableCodePage { | ||||
| 		ctx.Redirect(setting.AppSubURL + "/explore") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage | ||||
| 	ctx.Data["UsersPageIsDisabled"] = setting.Service.Explore.DisableUsersPage | ||||
| 	ctx.Data["OrganizationsPageIsDisabled"] = setting.Service.Explore.DisableOrganizationsPage | ||||
| 	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled | ||||
| 	ctx.Data["Title"] = ctx.Tr("explore") | ||||
| 	ctx.Data["PageIsExplore"] = true | ||||
|   | ||||
| @@ -14,7 +14,13 @@ import ( | ||||
|  | ||||
| // Organizations render explore organizations page | ||||
| func Organizations(ctx *context.Context) { | ||||
| 	ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage | ||||
| 	if setting.Service.Explore.DisableOrganizationsPage { | ||||
| 		ctx.Redirect(setting.AppSubURL + "/explore") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ctx.Data["UsersPageIsDisabled"] = setting.Service.Explore.DisableUsersPage | ||||
| 	ctx.Data["CodePageIsDisabled"] = setting.Service.Explore.DisableCodePage | ||||
| 	ctx.Data["Title"] = ctx.Tr("explore") | ||||
| 	ctx.Data["PageIsExplore"] = true | ||||
| 	ctx.Data["PageIsExploreOrganizations"] = true | ||||
|   | ||||
| @@ -165,7 +165,9 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { | ||||
|  | ||||
| // Repos render explore repositories page | ||||
| func Repos(ctx *context.Context) { | ||||
| 	ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage | ||||
| 	ctx.Data["UsersPageIsDisabled"] = setting.Service.Explore.DisableUsersPage | ||||
| 	ctx.Data["OrganizationsPageIsDisabled"] = setting.Service.Explore.DisableOrganizationsPage | ||||
| 	ctx.Data["CodePageIsDisabled"] = setting.Service.Explore.DisableCodePage | ||||
| 	ctx.Data["Title"] = ctx.Tr("explore") | ||||
| 	ctx.Data["PageIsExplore"] = true | ||||
| 	ctx.Data["PageIsExploreRepositories"] = true | ||||
|   | ||||
| @@ -131,9 +131,11 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, | ||||
| // Users render explore users page | ||||
| func Users(ctx *context.Context) { | ||||
| 	if setting.Service.Explore.DisableUsersPage { | ||||
| 		ctx.Redirect(setting.AppSubURL + "/explore/repos") | ||||
| 		ctx.Redirect(setting.AppSubURL + "/explore") | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.Data["OrganizationsPageIsDisabled"] = setting.Service.Explore.DisableOrganizationsPage | ||||
| 	ctx.Data["CodePageIsDisabled"] = setting.Service.Explore.DisableCodePage | ||||
| 	ctx.Data["Title"] = ctx.Tr("explore") | ||||
| 	ctx.Data["PageIsExplore"] = true | ||||
| 	ctx.Data["PageIsExploreUsers"] = true | ||||
|   | ||||
| @@ -8,37 +8,24 @@ import ( | ||||
|  | ||||
| 	"code.gitea.io/gitea/models/db" | ||||
| 	user_model "code.gitea.io/gitea/models/user" | ||||
| 	"code.gitea.io/gitea/modules/optional" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/services/context" | ||||
| 	"code.gitea.io/gitea/services/convert" | ||||
| ) | ||||
|  | ||||
| // Search search users | ||||
| func Search(ctx *context.Context) { | ||||
| 	listOptions := db.ListOptions{ | ||||
| 		Page:     ctx.FormInt("page"), | ||||
| 		PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), | ||||
| 	} | ||||
|  | ||||
| 	users, maxResults, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ | ||||
| // SearchCandidates searches candidate users for dropdown list | ||||
| func SearchCandidates(ctx *context.Context) { | ||||
| 	users, _, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ | ||||
| 		Actor:       ctx.Doer, | ||||
| 		Keyword:     ctx.FormTrim("q"), | ||||
| 		UID:         ctx.FormInt64("uid"), | ||||
| 		Type:        user_model.UserTypeIndividual, | ||||
| 		IsActive:    ctx.FormOptionalBool("active"), | ||||
| 		ListOptions: listOptions, | ||||
| 		IsActive:    optional.Some(true), | ||||
| 		ListOptions: db.ListOptions{PageSize: setting.UI.MembersPagingNum}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		ctx.JSON(http.StatusInternalServerError, map[string]any{ | ||||
| 			"ok":    false, | ||||
| 			"error": err.Error(), | ||||
| 		}) | ||||
| 		ctx.ServerError("Unable to search users", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ctx.SetTotalCountHeader(maxResults) | ||||
|  | ||||
| 	ctx.JSON(http.StatusOK, map[string]any{ | ||||
| 		"ok":   true, | ||||
| 		"data": convert.ToUsers(ctx, ctx.Doer, users), | ||||
| 	}) | ||||
| 	ctx.JSON(http.StatusOK, map[string]any{"data": convert.ToUsers(ctx, ctx.Doer, users)}) | ||||
| } | ||||
|   | ||||
| @@ -670,7 +670,7 @@ func registerRoutes(m *web.Router) { | ||||
| 		m.Post("/forgot_password", auth.ForgotPasswdPost) | ||||
| 		m.Post("/logout", auth.SignOut) | ||||
| 		m.Get("/stopwatches", reqSignIn, user.GetStopwatches) | ||||
| 		m.Get("/search", ignExploreSignIn, user.Search) | ||||
| 		m.Get("/search_candidates", ignExploreSignIn, user.SearchCandidates) | ||||
| 		m.Group("/oauth2", func() { | ||||
| 			m.Get("/{provider}", auth.SignInOAuth) | ||||
| 			m.Get("/{provider}/callback", auth.SignInOAuthCallback) | ||||
|   | ||||
| @@ -3,15 +3,17 @@ | ||||
| 		<a class="{{if .PageIsExploreRepositories}}active {{end}}item" href="{{AppSubUrl}}/explore/repos"> | ||||
| 			{{svg "octicon-repo"}} {{ctx.Locale.Tr "explore.repos"}} | ||||
| 		</a> | ||||
| 		{{if not .UsersIsDisabled}} | ||||
| 		{{if not .UsersPageIsDisabled}} | ||||
| 			<a class="{{if .PageIsExploreUsers}}active {{end}}item" href="{{AppSubUrl}}/explore/users"> | ||||
| 				{{svg "octicon-person"}} {{ctx.Locale.Tr "explore.users"}} | ||||
| 			</a> | ||||
| 		{{end}} | ||||
| 		{{if not .OrganizationsPageIsDisabled}} | ||||
| 		<a class="{{if .PageIsExploreOrganizations}}active {{end}}item" href="{{AppSubUrl}}/explore/organizations"> | ||||
| 			{{svg "octicon-organization"}} {{ctx.Locale.Tr "explore.organizations"}} | ||||
| 		</a> | ||||
| 		{{if and (not ctx.Consts.RepoUnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}} | ||||
| 		{{end}} | ||||
| 		{{if and (not ctx.Consts.RepoUnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled (not .CodePageIsDisabled)}} | ||||
| 		<a class="{{if .PageIsExploreCode}}active {{end}}item" href="{{AppSubUrl}}/explore/code"> | ||||
| 			{{svg "octicon-code"}} {{ctx.Locale.Tr "explore.code"}} | ||||
| 		</a> | ||||
|   | ||||
| @@ -8,41 +8,38 @@ export function initCompSearchUserBox() { | ||||
|   const searchUserBox = document.querySelector('#search-user-box'); | ||||
|   if (!searchUserBox) return; | ||||
|  | ||||
|   const $searchUserBox = $(searchUserBox); | ||||
|   const allowEmailInput = searchUserBox.getAttribute('data-allow-email') === 'true'; | ||||
|   const allowEmailDescription = searchUserBox.getAttribute('data-allow-email-description') ?? undefined; | ||||
|   $searchUserBox.search({ | ||||
|   $(searchUserBox).search({ | ||||
|     minCharacters: 2, | ||||
|     apiSettings: { | ||||
|       url: `${appSubUrl}/user/search?active=1&q={query}`, | ||||
|       url: `${appSubUrl}/user/search_candidates?q={query}`, | ||||
|       onResponse(response) { | ||||
|         const items = []; | ||||
|         const searchQuery = $searchUserBox.find('input').val(); | ||||
|         const resultItems = []; | ||||
|         const searchQuery = searchUserBox.querySelector('input').value; | ||||
|         const searchQueryUppercase = searchQuery.toUpperCase(); | ||||
|         $.each(response.data, (_i, item) => { | ||||
|         for (const item of response.data) { | ||||
|           const resultItem = { | ||||
|             title: item.login, | ||||
|             image: item.avatar_url, | ||||
|             description: htmlEscape(item.full_name), | ||||
|           }; | ||||
|           if (item.full_name) { | ||||
|             resultItem.description = htmlEscape(item.full_name); | ||||
|           } | ||||
|           if (searchQueryUppercase === item.login.toUpperCase()) { | ||||
|             items.unshift(resultItem); | ||||
|             resultItems.unshift(resultItem); // add the exact match to the top | ||||
|           } else { | ||||
|             items.push(resultItem); | ||||
|             resultItems.push(resultItem); | ||||
|           } | ||||
|         }); | ||||
|         } | ||||
|  | ||||
|         if (allowEmailInput && !items.length && looksLikeEmailAddressCheck.test(searchQuery)) { | ||||
|         if (allowEmailInput && !resultItems.length && looksLikeEmailAddressCheck.test(searchQuery)) { | ||||
|           const resultItem = { | ||||
|             title: searchQuery, | ||||
|             description: allowEmailDescription, | ||||
|           }; | ||||
|           items.push(resultItem); | ||||
|           resultItems.push(resultItem); | ||||
|         } | ||||
|  | ||||
|         return {results: items}; | ||||
|         return {results: resultItems}; | ||||
|       }, | ||||
|     }, | ||||
|     searchFields: ['login', 'full_name'], | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Zettat123
					Zettat123