From 767e9634d3d02acab27f05e1783391c9c7f6292e Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Fri, 23 Feb 2024 15:24:04 +0800
Subject: [PATCH] Allow options to disable user deletion from the interface on
 app.ini (#29275)

Extract from #20549

This PR added a new option on app.ini `[admin]USER_DISABLED_FEATURES` to
allow the site administrator to disable users visiting deletion user
interface or allow.
This options are also potentially allowed to define more features in
future PRs.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit 3ef6252e06a1f3981f8b7d1717bfc581418b1dc5)

Conflicts:
	custom/conf/app.example.ini
	docs/content/administration/config-cheat-sheet.en-us.md
	modules/setting/admin.go
	context
---
 custom/conf/app.example.ini          |  3 +++
 modules/setting/admin.go             | 10 +++++++++-
 routers/web/user/setting/account.go  |  6 ++++++
 templates/user/settings/account.tmpl | 23 ++++++++++++-----------
 4 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index dc1843097f..04714e5502 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -1492,6 +1492,9 @@ LEVEL = Info
 ;DEFAULT_EMAIL_NOTIFICATIONS = enabled
 ;; Send an email to all admins when a new user signs up to inform the admins about this act. Options: true, false
 ;SEND_NOTIFICATION_EMAIL_ON_NEW_USER = false
+;; Disabled features for users, could be "deletion", more features can be disabled in future
+;; - deletion: a user cannot delete their own account
+;USER_DISABLED_FEATURES =
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/modules/setting/admin.go b/modules/setting/admin.go
index d7f0ee827d..502efd0eb9 100644
--- a/modules/setting/admin.go
+++ b/modules/setting/admin.go
@@ -3,15 +3,23 @@
 
 package setting
 
+import "code.gitea.io/gitea/modules/container"
+
 // Admin settings
 var Admin struct {
 	DisableRegularOrgCreation      bool
 	DefaultEmailNotification       string
 	SendNotificationEmailOnNewUser bool
+	UserDisabledFeatures           container.Set[string]
 }
 
 func loadAdminFrom(rootCfg ConfigProvider) {
-	mustMapSetting(rootCfg, "admin", &Admin)
 	sec := rootCfg.Section("admin")
+	Admin.DisableRegularOrgCreation = sec.Key("DISABLE_REGULAR_ORG_CREATION").MustBool(false)
 	Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled")
+	Admin.UserDisabledFeatures = container.SetOf(sec.Key("USER_DISABLED_FEATURES").Strings(",")...)
 }
+
+const (
+	UserFeatureDeletion = "deletion"
+)
diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go
index 371718ba23..6042e0b6cd 100644
--- a/routers/web/user/setting/account.go
+++ b/routers/web/user/setting/account.go
@@ -242,6 +242,11 @@ func DeleteEmail(ctx *context.Context) {
 
 // DeleteAccount render user suicide page and response for delete user himself
 func DeleteAccount(ctx *context.Context) {
+	if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureDeletion) {
+		ctx.Error(http.StatusNotFound)
+		return
+	}
+
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsAccount"] = true
 
@@ -308,6 +313,7 @@ func loadAccountData(ctx *context.Context) {
 	ctx.Data["EmailNotificationsPreference"] = ctx.Doer.EmailNotificationsPreference
 	ctx.Data["ActivationsPending"] = pendingActivation
 	ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm
+	ctx.Data["UserDisabledFeatures"] = &setting.Admin.UserDisabledFeatures
 
 	if setting.Service.UserDeleteWithCommentsMaxTime != 0 {
 		ctx.Data["UserDeleteWithCommentsMaxTime"] = setting.Service.UserDeleteWithCommentsMaxTime.String()
diff --git a/templates/user/settings/account.tmpl b/templates/user/settings/account.tmpl
index 820d48a94b..c7bf3c0a41 100644
--- a/templates/user/settings/account.tmpl
+++ b/templates/user/settings/account.tmpl
@@ -128,6 +128,7 @@
 			{{end}}
 		</div>
 
+		{{if not ($.UserDisabledFeatures.Contains "deletion")}}
 		<h4 class="ui top attached error header">
 			{{ctx.Locale.Tr "settings.delete_account"}}
 		</h4>
@@ -151,7 +152,18 @@
 					</button>
 				</div>
 			</form>
+			<div class="ui g-modal-confirm delete modal" id="delete-account">
+				<div class="header">
+					{{svg "octicon-trash"}}
+					{{ctx.Locale.Tr "settings.delete_account_title"}}
+				</div>
+				<div class="content">
+					<p>{{ctx.Locale.Tr "settings.delete_account_desc"}}</p>
+				</div>
+				{{template "base/modal_actions_confirm" .}}
+			</div>
 		</div>
+		{{end}}
 	</div>
 
 <div class="ui g-modal-confirm delete modal" id="delete-email">
@@ -165,15 +177,4 @@
 	{{template "base/modal_actions_confirm" .}}
 </div>
 
-<div class="ui g-modal-confirm delete modal" id="delete-account">
-	<div class="header">
-		{{svg "octicon-trash"}}
-		{{ctx.Locale.Tr "settings.delete_account_title"}}
-	</div>
-	<div class="content">
-		<p>{{ctx.Locale.Tr "settings.delete_account_desc"}}</p>
-	</div>
-	{{template "base/modal_actions_confirm" .}}
-</div>
-
 {{template "user/settings/layout_footer" .}}