User details page (#26713)
This PR implements a proposal to clean up the admin users table by
moving some information out to a separate user details page (which also
displays some additional information).
Other changes:
- move edit user page from `/admin/users/{id}` to
`/admin/users/{id}/edit` -> `/admin/users/{id}` now shows the user
details page
- show if user is instance administrator as a label instead of a
separate column
- separate explore users template into a page- and a shared one, to make
it possible to use it on the user details page
- fix issue where there was no margin between alert message and
following content on admin pages
<details>
<summary>Screenshots</summary>


</details>
Partially resolves #25939
---------
Co-authored-by: Giteabot <teabot@gitea.io>
	
	
This commit is contained in:
		
					parent
					
						
							
								3d109861dd
							
						
					
				
			
			
				commit
				
					
						5b5bb8d354
					
				
			
		
					 12 changed files with 242 additions and 43 deletions
				
			
		| 
						 | 
				
			
			@ -2823,6 +2823,7 @@ users.list_status_filter.is_prohibit_login = Prohibit Login
 | 
			
		|||
users.list_status_filter.not_prohibit_login = Allow Login
 | 
			
		||||
users.list_status_filter.is_2fa_enabled = 2FA Enabled
 | 
			
		||||
users.list_status_filter.not_2fa_enabled = 2FA Disabled
 | 
			
		||||
users.details = User Details
 | 
			
		||||
 | 
			
		||||
emails.email_manage_panel = User Email Management
 | 
			
		||||
emails.primary = Primary
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,8 @@ import (
 | 
			
		|||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/models/auth"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	org_model "code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	system_model "code.gitea.io/gitea/models/system"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/auth/password"
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +34,7 @@ import (
 | 
			
		|||
const (
 | 
			
		||||
	tplUsers    base.TplName = "admin/user/list"
 | 
			
		||||
	tplUserNew  base.TplName = "admin/user/new"
 | 
			
		||||
	tplUserView base.TplName = "admin/user/view"
 | 
			
		||||
	tplUserEdit base.TplName = "admin/user/edit"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -249,6 +252,61 @@ func prepareUserInfo(ctx *context.Context) *user_model.User {
 | 
			
		|||
	return u
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ViewUser(ctx *context.Context) {
 | 
			
		||||
	ctx.Data["Title"] = ctx.Tr("admin.users.details")
 | 
			
		||||
	ctx.Data["PageIsAdminUsers"] = true
 | 
			
		||||
	ctx.Data["DisableRegularOrgCreation"] = setting.Admin.DisableRegularOrgCreation
 | 
			
		||||
	ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
 | 
			
		||||
	ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
 | 
			
		||||
 | 
			
		||||
	u := prepareUserInfo(ctx)
 | 
			
		||||
	if ctx.Written() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos, count, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{
 | 
			
		||||
		ListOptions: db.ListOptions{
 | 
			
		||||
			ListAll: true,
 | 
			
		||||
		},
 | 
			
		||||
		OwnerID:     u.ID,
 | 
			
		||||
		OrderBy:     db.SearchOrderByAlphabetically,
 | 
			
		||||
		Private:     true,
 | 
			
		||||
		Collaborate: util.OptionalBoolFalse,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("SearchRepository", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Data["Repos"] = repos
 | 
			
		||||
	ctx.Data["ReposTotal"] = int(count)
 | 
			
		||||
 | 
			
		||||
	emails, err := user_model.GetEmailAddresses(ctx.Doer.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("GetEmailAddresses", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["Emails"] = emails
 | 
			
		||||
	ctx.Data["EmailsTotal"] = len(emails)
 | 
			
		||||
 | 
			
		||||
	orgs, err := org_model.FindOrgs(org_model.FindOrgOptions{
 | 
			
		||||
		ListOptions: db.ListOptions{
 | 
			
		||||
			ListAll: true,
 | 
			
		||||
		},
 | 
			
		||||
		UserID:         u.ID,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("FindOrgs", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Data["Users"] = orgs // needed to be able to use explore/user_list template
 | 
			
		||||
	ctx.Data["OrgsTotal"] = len(orgs)
 | 
			
		||||
 | 
			
		||||
	ctx.HTML(http.StatusOK, tplUserView)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EditUser show editing user page
 | 
			
		||||
func EditUser(ctx *context.Context) {
 | 
			
		||||
	ctx.Data["Title"] = ctx.Tr("admin.users.edit_account")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -573,7 +573,8 @@ func registerRoutes(m *web.Route) {
 | 
			
		|||
		m.Group("/users", func() {
 | 
			
		||||
			m.Get("", admin.Users)
 | 
			
		||||
			m.Combo("/new").Get(admin.NewUser).Post(web.Bind(forms.AdminCreateUserForm{}), admin.NewUserPost)
 | 
			
		||||
			m.Combo("/{userid}").Get(admin.EditUser).Post(web.Bind(forms.AdminEditUserForm{}), admin.EditUserPost)
 | 
			
		||||
			m.Get("/{userid}", admin.ViewUser)
 | 
			
		||||
			m.Combo("/{userid}/edit").Get(admin.EditUser).Post(web.Bind(forms.AdminEditUserForm{}), admin.EditUserPost)
 | 
			
		||||
			m.Post("/{userid}/delete", admin.DeleteUser)
 | 
			
		||||
			m.Post("/{userid}/avatar", web.Bind(forms.AvatarForm{}), admin.AvatarPost)
 | 
			
		||||
			m.Post("/{userid}/avatar/delete", admin.DeleteAvatar)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
{{template "base/head" .ctxData}}
 | 
			
		||||
<div role="main" aria-label="{{.ctxData.Title}}" class="page-content {{.pageClass}}">
 | 
			
		||||
	<div class="ui container">
 | 
			
		||||
	<div class="ui container gt-mb-4">
 | 
			
		||||
		{{template "base/alert" .ctxData}}
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="ui container flex-container">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,36 +68,35 @@
 | 
			
		|||
						</th>
 | 
			
		||||
						<th>{{.locale.Tr "email"}}</th>
 | 
			
		||||
						<th>{{.locale.Tr "admin.users.activated"}}</th>
 | 
			
		||||
						<th>{{.locale.Tr "admin.users.admin"}}</th>
 | 
			
		||||
						<th>{{.locale.Tr "admin.users.restricted"}}</th>
 | 
			
		||||
						<th>{{.locale.Tr "admin.users.2fa"}}</th>
 | 
			
		||||
						<th>{{.locale.Tr "admin.users.repos"}}</th>
 | 
			
		||||
						<th>{{.locale.Tr "admin.users.created"}}</th>
 | 
			
		||||
						<th data-sortt-asc="lastlogin" data-sortt-desc="reverselastlogin">
 | 
			
		||||
							{{.locale.Tr "admin.users.last_login"}}
 | 
			
		||||
							{{SortArrow "lastlogin" "reverselastlogin" $.SortType false}}
 | 
			
		||||
						</th>
 | 
			
		||||
						<th>{{.locale.Tr "admin.users.edit"}}</th>
 | 
			
		||||
					</tr>
 | 
			
		||||
				</thead>
 | 
			
		||||
				<tbody>
 | 
			
		||||
					{{range .Users}}
 | 
			
		||||
						<tr>
 | 
			
		||||
							<td>{{.ID}}</td>
 | 
			
		||||
							<td><a href="{{.HomeLink}}">{{.Name}}</a></td>
 | 
			
		||||
							<td>
 | 
			
		||||
								<a href="{{$.Link}}/{{.ID}}">{{.Name}}</a>
 | 
			
		||||
								{{if .IsAdmin}}
 | 
			
		||||
									<span class="ui basic label">{{$.locale.Tr "admin.users.admin"}}</span>
 | 
			
		||||
								{{end}}
 | 
			
		||||
							</td>
 | 
			
		||||
							<td class="gt-ellipsis gt-max-width-12rem">{{.Email}}</td>
 | 
			
		||||
							<td>{{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
 | 
			
		||||
							<td>{{if .IsAdmin}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
 | 
			
		||||
							<td>{{if .IsRestricted}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
 | 
			
		||||
							<td>{{if index $.UsersTwoFaStatus .ID}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
 | 
			
		||||
							<td>{{.NumRepos}}</td>
 | 
			
		||||
							<td>{{DateTime "short" .CreatedUnix}}</td>
 | 
			
		||||
							{{if .LastLoginUnix}}
 | 
			
		||||
								<td>{{DateTime "short" .LastLoginUnix}}</td>
 | 
			
		||||
							{{else}}
 | 
			
		||||
								<td><span>{{$.locale.Tr "admin.users.never_login"}}</span></td>
 | 
			
		||||
							{{end}}
 | 
			
		||||
							<td><a href="{{$.Link}}/{{.ID}}">{{svg "octicon-pencil"}}</a></td>
 | 
			
		||||
						</tr>
 | 
			
		||||
					{{end}}
 | 
			
		||||
				</tbody>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										48
									
								
								templates/admin/user/view.tmpl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								templates/admin/user/view.tmpl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin view user")}}
 | 
			
		||||
 | 
			
		||||
<div class="admin-setting-content">
 | 
			
		||||
	<div class="admin-responsive-columns">
 | 
			
		||||
		<div class="gt-f1">
 | 
			
		||||
			<h4 class="ui top attached header">
 | 
			
		||||
				{{.Title}}
 | 
			
		||||
				<div class="ui right">
 | 
			
		||||
					<a class="ui primary tiny button" href="{{.Link}}/edit">{{ctx.Locale.Tr "admin.users.edit"}}</a>
 | 
			
		||||
				</div>
 | 
			
		||||
			</h4>
 | 
			
		||||
			<div class="ui attached segment">
 | 
			
		||||
				{{template "admin/user/view_details" .}}
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="gt-f1">
 | 
			
		||||
			<h4 class="ui top attached header">
 | 
			
		||||
				{{ctx.Locale.Tr "admin.emails"}}
 | 
			
		||||
				<div class="ui right">
 | 
			
		||||
					{{.EmailsTotal}}
 | 
			
		||||
				</div>
 | 
			
		||||
			</h4>
 | 
			
		||||
			<div class="ui attached segment">
 | 
			
		||||
				{{template "admin/user/view_emails" .}}
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<h4 class="ui top attached header">
 | 
			
		||||
		{{ctx.Locale.Tr "admin.repositories"}}
 | 
			
		||||
		<div class="ui right">
 | 
			
		||||
			{{.ReposTotal}}
 | 
			
		||||
		</div>
 | 
			
		||||
	</h4>
 | 
			
		||||
	<div class="ui attached segment">
 | 
			
		||||
		{{template "explore/repo_list" .}}
 | 
			
		||||
	</div>
 | 
			
		||||
	<h4 class="ui top attached header">
 | 
			
		||||
		{{ctx.Locale.Tr "settings.organization"}}
 | 
			
		||||
		<div class="ui right">
 | 
			
		||||
			{{.OrgsTotal}}
 | 
			
		||||
		</div>
 | 
			
		||||
	</h4>
 | 
			
		||||
	<div class="ui attached segment">
 | 
			
		||||
		{{template "explore/user_list" .}}
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{{template "admin/layout_footer" .}}
 | 
			
		||||
							
								
								
									
										65
									
								
								templates/admin/user/view_details.tmpl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								templates/admin/user/view_details.tmpl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,65 @@
 | 
			
		|||
<div class="flex-list">
 | 
			
		||||
	<div class="flex-item">
 | 
			
		||||
		<div class="flex-item-leading">
 | 
			
		||||
			{{ctx.AvatarUtils.Avatar .User 48}}
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="flex-item-main">
 | 
			
		||||
			<div class="flex-item-title">
 | 
			
		||||
				{{template "shared/user/name" .User}}
 | 
			
		||||
				{{if .User.IsAdmin}}
 | 
			
		||||
					<span class="ui basic label">{{ctx.Locale.Tr "admin.users.admin"}}</span>
 | 
			
		||||
				{{end}}
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="flex-item-body">
 | 
			
		||||
				<b>{{ctx.Locale.Tr "admin.users.auth_source"}}:</b>
 | 
			
		||||
				{{if eq .LoginSource.ID 0}}
 | 
			
		||||
					{{ctx.Locale.Tr "admin.users.local"}}
 | 
			
		||||
				{{else}}
 | 
			
		||||
					{{.LoginSource.Name}}
 | 
			
		||||
				{{end}}
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="flex-item-body">
 | 
			
		||||
				<b>{{ctx.Locale.Tr "admin.users.activated"}}:</b>
 | 
			
		||||
				{{if .User.IsActive}}
 | 
			
		||||
					{{svg "octicon-check"}}
 | 
			
		||||
				{{else}}
 | 
			
		||||
					{{svg "octicon-x"}}
 | 
			
		||||
				{{end}}
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="flex-item-body">
 | 
			
		||||
				<b>{{ctx.Locale.Tr "admin.users.restricted"}}:</b>
 | 
			
		||||
				{{if .User.IsRestricted}}
 | 
			
		||||
					{{svg "octicon-check"}}
 | 
			
		||||
				{{else}}
 | 
			
		||||
					{{svg "octicon-x"}}
 | 
			
		||||
				{{end}}
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="flex-item-body">
 | 
			
		||||
				<b>{{ctx.Locale.Tr "settings.visibility"}}:</b>
 | 
			
		||||
				{{if .User.Visibility.IsLimited}}{{ctx.Locale.Tr "settings.visibility.limited"}}{{end}}
 | 
			
		||||
				{{if .User.Visibility.IsPrivate}}{{ctx.Locale.Tr "settings.visibility.private"}}{{end}}
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="flex-item-body">
 | 
			
		||||
				<b>{{ctx.Locale.Tr "admin.users.2fa"}}:</b>
 | 
			
		||||
				{{if .TwoFactorEnabled}}
 | 
			
		||||
					<span class="text green">{{svg "octicon-check"}}</span>
 | 
			
		||||
				{{else}}
 | 
			
		||||
					{{svg "octicon-x"}}
 | 
			
		||||
				{{end}}
 | 
			
		||||
			</div>
 | 
			
		||||
			{{if .User.Location}}
 | 
			
		||||
				<div class="flex-item-body">
 | 
			
		||||
					<span class="flex-text-inline">{{svg "octicon-location"}}{{.User.Location}}</span>
 | 
			
		||||
				</div>
 | 
			
		||||
			{{end}}
 | 
			
		||||
			{{if .User.Website}}
 | 
			
		||||
				<div class="flex-item-body">
 | 
			
		||||
					<span class="flex-text-inline">
 | 
			
		||||
						{{svg "octicon-link"}}
 | 
			
		||||
						<a target="_blank" href="{{.User.Website}}">{{.User.Website}}</a>
 | 
			
		||||
					</span>
 | 
			
		||||
				</div>
 | 
			
		||||
			{{end}}
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										19
									
								
								templates/admin/user/view_emails.tmpl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								templates/admin/user/view_emails.tmpl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
<div class="flex-list">
 | 
			
		||||
	{{range .Emails}}
 | 
			
		||||
		<div class="flex-item">
 | 
			
		||||
			<div class="flex-item-main">
 | 
			
		||||
				<div class="flex-text-block">
 | 
			
		||||
					{{.Email}}
 | 
			
		||||
					{{if .IsPrimary}}
 | 
			
		||||
						<div class="ui primary label">{{ctx.Locale.Tr "settings.primary"}}</div>
 | 
			
		||||
					{{end}}
 | 
			
		||||
					{{if .IsActivated}}
 | 
			
		||||
						<div class="ui green label">{{ctx.Locale.Tr "settings.activated"}}</div>
 | 
			
		||||
					{{else}}
 | 
			
		||||
						<div class="ui label">{{ctx.Locale.Tr "settings.requires_activation"}}</div>
 | 
			
		||||
					{{end}}
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	{{end}}
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										31
									
								
								templates/explore/user_list.tmpl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								templates/explore/user_list.tmpl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
<div class="flex-list">
 | 
			
		||||
	{{range .Users}}
 | 
			
		||||
		<div class="flex-item flex-item-center">
 | 
			
		||||
			<div class="flex-item-leading">
 | 
			
		||||
				{{ctx.AvatarUtils.Avatar . 48}}
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="flex-item-main">
 | 
			
		||||
				<div class="flex-item-title">
 | 
			
		||||
					{{template "shared/user/name" .}}
 | 
			
		||||
					{{if .Visibility.IsPrivate}}
 | 
			
		||||
						<span class="ui basic tiny label">{{ctx.Locale.Tr "repo.desc.private"}}</span>
 | 
			
		||||
					{{end}}
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="flex-item-body">
 | 
			
		||||
					{{if .Location}}
 | 
			
		||||
						<span class="flex-text-inline">{{svg "octicon-location"}}{{.Location}}</span>
 | 
			
		||||
					{{end}}
 | 
			
		||||
					{{if and .Email (or (and $.ShowUserEmail $.IsSigned (not .KeepEmailPrivate)) $.PageIsAdminUsers)}}
 | 
			
		||||
						<span class="flex-text-inline">
 | 
			
		||||
							{{svg "octicon-mail"}}
 | 
			
		||||
							<a href="mailto:{{.Email}}">{{.Email}}</a>
 | 
			
		||||
						</span>
 | 
			
		||||
					{{end}}
 | 
			
		||||
					<span class="flex-text-inline">{{svg "octicon-calendar"}}{{ctx.Locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}}</span>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	{{else}}
 | 
			
		||||
		<div class="flex-item">{{ctx.Locale.Tr "explore.user_no_results"}}</div>
 | 
			
		||||
	{{end}}
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -4,37 +4,7 @@
 | 
			
		|||
	<div class="ui container">
 | 
			
		||||
		{{template "explore/search" .}}
 | 
			
		||||
 | 
			
		||||
		<div class="flex-list">
 | 
			
		||||
			{{range .Users}}
 | 
			
		||||
				<div class="flex-item flex-item-center">
 | 
			
		||||
					<div class="flex-item-leading">
 | 
			
		||||
						{{ctx.AvatarUtils.Avatar . 48}}
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="flex-item-main">
 | 
			
		||||
						<div class="flex-item-title">
 | 
			
		||||
							{{template "shared/user/name" .}}
 | 
			
		||||
							{{if .Visibility.IsPrivate}}
 | 
			
		||||
								<span class="ui basic tiny label">{{$.locale.Tr "repo.desc.private"}}</span>
 | 
			
		||||
							{{end}}
 | 
			
		||||
						</div>
 | 
			
		||||
						<div class="flex-item-body">
 | 
			
		||||
							{{if .Location}}
 | 
			
		||||
								<span class="flex-text-inline">{{svg "octicon-location"}}{{.Location}}</span>
 | 
			
		||||
							{{end}}
 | 
			
		||||
							{{if and $.ShowUserEmail .Email $.IsSigned (not .KeepEmailPrivate)}}
 | 
			
		||||
								<span class="flex-text-inline">
 | 
			
		||||
									{{svg "octicon-mail"}}
 | 
			
		||||
									<a href="mailto:{{.Email}}" rel="nofollow">{{.Email}}</a>
 | 
			
		||||
								</span>
 | 
			
		||||
							{{end}}
 | 
			
		||||
							<span class="flex-text-inline">{{svg "octicon-calendar"}}{{$.locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}}</span>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			{{else}}
 | 
			
		||||
				<div class="flex-item">{{$.locale.Tr "explore.user_no_results"}}</div>
 | 
			
		||||
			{{end}}
 | 
			
		||||
		</div>
 | 
			
		||||
		{{template "explore/user_list" .}}
 | 
			
		||||
 | 
			
		||||
		{{template "base/paginate" .}}
 | 
			
		||||
	</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,8 +51,8 @@ func testSuccessfullEdit(t *testing.T, formData user_model.User) {
 | 
			
		|||
 | 
			
		||||
func makeRequest(t *testing.T, formData user_model.User, headerCode int) {
 | 
			
		||||
	session := loginUser(t, "user1")
 | 
			
		||||
	csrf := GetCSRF(t, session, "/admin/users/"+strconv.Itoa(int(formData.ID)))
 | 
			
		||||
	req := NewRequestWithValues(t, "POST", "/admin/users/"+strconv.Itoa(int(formData.ID)), map[string]string{
 | 
			
		||||
	csrf := GetCSRF(t, session, "/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit")
 | 
			
		||||
	req := NewRequestWithValues(t, "POST", "/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit", map[string]string{
 | 
			
		||||
		"_csrf":      csrf,
 | 
			
		||||
		"user_name":  formData.Name,
 | 
			
		||||
		"login_name": formData.LoginName,
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ func TestAdminDeleteUser(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	session := loginUser(t, "user1")
 | 
			
		||||
 | 
			
		||||
	csrf := GetCSRF(t, session, "/admin/users/8")
 | 
			
		||||
	csrf := GetCSRF(t, session, "/admin/users/8/edit")
 | 
			
		||||
	req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{
 | 
			
		||||
		"_csrf": csrf,
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,3 +42,10 @@
 | 
			
		|||
.admin .table th {
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.admin-responsive-columns {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
  gap: 1rem;
 | 
			
		||||
  margin-bottom: 1rem;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue