From 7728ffb9a47c34182ed313763f9f7e375bb463b4 Mon Sep 17 00:00:00 2001 From: jayden Date: Tue, 25 Jul 2017 18:15:23 +0800 Subject: [PATCH 1/8] admin panel layout --- cmd/web.go | 9 ++++ core/userService/user_service.go | 38 ++++++++++++++ model/dto/dto_user.go | 17 ++++++ model/user.go | 62 +++++++++++++++++----- module/context/auth.go | 13 +++++ public/css/goby.css | 5 +- public/js/admin.js | 77 ++++++++++++++++++++++++++++ router/web/admin.go | 32 ++++++++++++ template/admin/users.html | 75 +++++++++++++++++++++++++++ template/app/detail/deployments.html | 11 ++-- template/base/footer.html | 23 +++------ template/base/header.html | 41 +++++++++------ 12 files changed, 352 insertions(+), 51 deletions(-) create mode 100644 public/js/admin.js create mode 100644 router/web/admin.go create mode 100644 template/admin/users.html diff --git a/cmd/web.go b/cmd/web.go index 18c32a8..1c63c5d 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -142,6 +142,7 @@ func runWeb(cliCtx *cli.Context) { reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequire: true}) ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequire: setting.Service.RequireSignInView}) reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequire: true}) + reqAdmin := context.Toggle(&context.ToggleOptions{SignInRequire: true, AdminRequire: true}) bindIgnErr := binding.BindIgnErr apiBind := binding.Bind @@ -168,6 +169,14 @@ func runWeb(cliCtx *cli.Context) { m.Combo("/list").Get(web.AccessKeysGet) }, reqSignIn) + m.Group("/admin/api", func() { + m.Get("/users/:pageIndex/:pageCount", web.UsersQuery) + }) + + m.Group("/admin", func() { + m.Get("/users", web.UsersGet) + }, reqAdmin) + }) m.Group("/auth", func() { diff --git a/core/userService/user_service.go b/core/userService/user_service.go index c67c05d..554a536 100644 --- a/core/userService/user_service.go +++ b/core/userService/user_service.go @@ -7,9 +7,11 @@ import ( "unicode/utf8" "github.com/Unknwon/com" + . "gopkg.in/ahmetb/go-linq.v3" . "github.com/MessageDream/goby/core" "github.com/MessageDream/goby/model" + "github.com/MessageDream/goby/model/dto" "github.com/MessageDream/goby/module/infrastructure" "github.com/MessageDream/goby/module/setting" ) @@ -192,3 +194,39 @@ func Signin(emailOrName, pwd string) (*model.User, error) { } return user, nil } + +func QueryUsers(uid uint64, pageIndex, pageCount int, email string) (*dto.Pager, error) { + if pageCount > 100 { + pageCount = 100 + } + pager, err := model.QueryUsers(uid, pageIndex, pageCount, email) + if err != nil { + return nil, err + } + + var results []*dto.UserDetail + + From(pager.Data).Select(func(item interface{}) interface{} { + u := item.(*model.User) + var role = 0 + if u.IsAdmin { + role = 1 + } + return &dto.UserDetail{ + Email: u.Email, + UserName: u.UserName, + Role: role, + IsActive: u.IsActive, + IsForbidden: u.IsForbidden, + JoinedAt: u.CreatedAt, + } + }).ToSlice(&results) + + return &dto.Pager{ + TotalCount: pager.TotalCount, + TotalPageCount: pager.TotalPageCount, + PageIndex: pager.PageIndex, + PageCount: pager.PageCount, + Data: results, + }, nil +} diff --git a/model/dto/dto_user.go b/model/dto/dto_user.go index 025aec2..cc702ef 100644 --- a/model/dto/dto_user.go +++ b/model/dto/dto_user.go @@ -24,3 +24,20 @@ type Collaborator struct { IsCurrentAccount bool `json:"isCurrentAccount"` Permission string `json:"permission"` } + +type Pager struct { + PageIndex int `json:"pageIndex"` + PageCount int `json:"pageCount"` + TotalCount int64 `json:"totalCount"` + TotalPageCount int64 `json:"totalPageCount"` + Data interface{} `json:"data"` +} + +type UserDetail struct { + Email string `json:"email"` + UserName string `json:"userName"` + Role int `json:"role"` + IsActive bool `json:"isActive"` + IsForbidden bool `json:"isForbidden"` + JoinedAt time.Time `json:"joinedTime"` +} diff --git a/model/user.go b/model/user.go index a645bc5..83336b3 100644 --- a/model/user.go +++ b/model/user.go @@ -11,24 +11,28 @@ import ( "github.com/Unknwon/com" "golang.org/x/crypto/pbkdf2" + "math" + "github.com/MessageDream/goby/model/dto" "github.com/MessageDream/goby/module/infrastructure" "github.com/MessageDream/goby/module/mailer" + "github.com/go-xorm/xorm" ) type User struct { - ID uint64 `xorm:"pk autoincr"` - Email string `xorm:"unique notnull"` - Password string `xorm:"notnull"` - Rands string `xorm:"index"` - UserName string - LowerName string `xorm:"unique notnull"` - IsAdmin bool `xorm:"notnull default(0)"` - IsActive bool `xorm:"notnull default(0)"` - Salt string - CreatedAt time.Time `xorm:"created"` - UpdatedAt time.Time `xorm:"updated"` - DeletedAt time.Time `xorm:"deleted"` + ID uint64 `xorm:"pk autoincr"` + Email string `xorm:"unique notnull"` + Password string `xorm:"notnull"` + Rands string `xorm:"index"` + UserName string + LowerName string `xorm:"unique notnull"` + IsAdmin bool `xorm:"notnull default(0)"` + IsActive bool `xorm:"notnull default(0)"` + IsForbidden bool `xorm:"notnull default(0)"` + Salt string + CreatedAt time.Time `xorm:"created"` + UpdatedAt time.Time `xorm:"updated"` + DeletedAt time.Time `xorm:"deleted"` } func (self *User) EncodePasswd() { @@ -124,6 +128,40 @@ func FindUserByIDs(ids []uint64) ([]*User, error) { return users, x.In("id", ids).Find(&users) } +func QueryUsers(currentUserID uint64, pageIndex, pageCount int, email string) (*dto.Pager, error) { + users := make([]*User, 0, 50) + var sess *xorm.Session + if len(email) != 0 { + sess = x.Where("id > ? and id != ? and email like ?", 1, currentUserID, "%"+email+"%") + } else { + sess = x.Where("id > ? and id != ?", 1, currentUserID) + } + total, err := sess.Count(new(User)) + if err != nil { + return nil, err + } + + if len(email) != 0 { + sess = x.Where("id > ? and id != ? and email like ?", 1, currentUserID, "%"+email+"%") + } else { + sess = x.Where("id > ? and id != ?", 1, currentUserID) + } + + err = sess.Desc("created_at").Limit(pageCount, pageIndex*pageCount).Find(&users) + if err != nil { + return nil, err + } + + return &dto.Pager{ + TotalCount: total, + TotalPageCount: int64(math.Ceil(float64(total) / float64(pageCount))), + PageIndex: pageIndex, + PageCount: pageCount, + Data: users, + }, nil + +} + type mailerUser struct { user *User activeCodeLives int diff --git a/module/context/auth.go b/module/context/auth.go index e0ef3d5..3f9abd8 100644 --- a/module/context/auth.go +++ b/module/context/auth.go @@ -61,6 +61,13 @@ func APIToggle(options *ToggleOptions) macaron.Handler { return } } + + if options.AdminRequire { + if !ctx.User.IsAdmin { + ctx.Status(403) + return + } + } } } @@ -90,6 +97,7 @@ func Toggle(options *ToggleOptions) macaron.Handler { ctx.HTML(200, "auth/activate") return } + } if options.AdminRequire { @@ -99,5 +107,10 @@ func Toggle(options *ToggleOptions) macaron.Handler { } ctx.Data["PageIsAdmin"] = true } + + if ctx.User != nil && ctx.User.IsAdmin { + ctx.Data["IsAdmin"] = true + } + } } diff --git a/public/css/goby.css b/public/css/goby.css index bfdca02..a4798da 100644 --- a/public/css/goby.css +++ b/public/css/goby.css @@ -852,7 +852,7 @@ ul { clear: both; padding-top: 0.755em; } -.dataTables_filter input { + /* .dataTables_filter input { background: #fff none repeat scroll 0 0; border: 1px solid rgba(34, 36, 38, 0.15); border-radius: 0.285714rem; @@ -871,7 +871,8 @@ ul { -o-transition: background-color 0.1s ease 0s, box-shadow 0.1s ease 0s, border-color 0.1s ease 0s; -webkit-transition: background-color 0.1s ease 0s, box-shadow 0.1s ease 0s, border-color 0.1s ease 0s; transition: background-color 0.1s ease 0s, box-shadow 0.1s ease 0s, border-color 0.1s ease 0s; -} +} */ + /* =============Datatable Page Css============= */ /* MOBIL PAGE SETTINGS*/ /* Desktops and laptops ----------- */ diff --git a/public/js/admin.js b/public/js/admin.js new file mode 100644 index 0000000..5cf5e44 --- /dev/null +++ b/public/js/admin.js @@ -0,0 +1,77 @@ +function active(element) { + +} + +function changeRole(element) { + +} + +function forbid(element) { + +} + +function fetchAllUsers(params, callback, settings) { + var start = params.start ? params.start : 0 + var length = params.length ? params.length : 20 + var search = params.search ? params.search.value : "" + var pageIndex = start / length; + var returnData = {}; + $.ajax({ + url: '/web/admin/api/users/' + pageIndex + '/' + length + '?email=' + search, + type: 'GET', + success: function (data, textStatus) { + var result = data.users; + returnData.start = start; + returnData.recordsTotal = result.totalCount; + returnData.recordsFiltered = result.totalCount; + returnData.data = result.data; + if (callback) { + callback(returnData); + } + }, + error: function (XMLHttpRequest, textStatus, errorThrown) { + returnData.error = XMLHttpRequest.responseJSON.message; + if (callback) { + callback(returnData); + } + } + }); +} + +var admin_users_table = $('#table_users').dataTable({ + "ordering": false, + "paginate": true, + "lengthMenu": [20, 50, 100], + "processing": true, + "serverSide": true, + "ajax": fetchAllUsers, + "columns": [ + { data: 'userName' }, + { data: 'email' }, + { data: 'isActive' }, + { + data: 'role', + render: function (data, type, row, meta) { + return data == 1 ? 'admin' : 'member'; + } + }, + { + data: 'joinedTime', + render: function (data, type, row, meta) { + return moment(new Date(data)).format("YYYY-MM-DD hh:mm:ss"); + } + }, + { + data: 'email', + render: function (data, type, row, meta) { + if (!row.isActive) { + return ''; + } else { + var roleButton = ''; + var forbiddenButton = ''; + return '
' + roleButton + forbiddenButton + '
'; + } + } + } + ] +}).api(); \ No newline at end of file diff --git a/router/web/admin.go b/router/web/admin.go new file mode 100644 index 0000000..b36fb8d --- /dev/null +++ b/router/web/admin.go @@ -0,0 +1,32 @@ +package web + +import ( + "github.com/MessageDream/goby/core/userService" + "github.com/MessageDream/goby/module/context" + "github.com/MessageDream/goby/module/infrastructure" +) + +const ( + ADMIN_USERS infrastructure.TplName = "admin/users" +) + +func UsersGet(ctx *context.HTMLContext) { + ctx.Data["PageIsAdminUsers"] = true + ctx.HTML(200, ADMIN_USERS) +} + +func UsersQuery(ctx *context.APIContext) { + pageIndex := ctx.ParamsInt("pageIndex") + pageCount := ctx.ParamsInt("pageCount") + email := ctx.Query("email") + + result, err := userService.QueryUsers(ctx.User.ID, pageIndex, pageCount, email) + if err != nil { + ctx.Error(err) + return + } + + ctx.JSON(200, map[string]interface{}{ + "users": result, + }) +} diff --git a/template/admin/users.html b/template/admin/users.html new file mode 100644 index 0000000..bdd4ea6 --- /dev/null +++ b/template/admin/users.html @@ -0,0 +1,75 @@ +{{template "base/header" .}} +
+
+
+
+
+ Users + +
+ +
+ + + + + + + + + + + +
User NameEmailIs ActiveRoleJoined Time Operation
+
+
+
+
+ + +
+{{template "base/footer" .}} + \ No newline at end of file diff --git a/template/app/detail/deployments.html b/template/app/detail/deployments.html index 91520f1..b806a9d 100644 --- a/template/app/detail/deployments.html +++ b/template/app/detail/deployments.html @@ -4,7 +4,7 @@ {{template "app/detail/header" .}}
{{$user := .SignedUser}} {{$owner := .Owner}} {{$condition := ne $user.Email $owner}} -
+
Summary @@ -12,6 +12,7 @@ Add +
@@ -109,7 +110,10 @@
-
+ +
+
+
History @@ -174,7 +178,6 @@ -
Platform
{{template "base/footer" .}} - - \ No newline at end of file diff --git a/template/base/footer.html b/template/base/footer.html index 034f28d..6c79d9b 100644 --- a/template/base/footer.html +++ b/template/base/footer.html @@ -5,29 +5,18 @@
*/}}
- - + - + + + diff --git a/template/base/header.html b/template/base/header.html index 000cfe3..68d4a39 100644 --- a/template/base/header.html +++ b/template/base/header.html @@ -1,4 +1,4 @@ - + @@ -24,13 +24,13 @@ - - - - - - - + + + + + + + {{if .Title}}{{.Title}} - {{end}}{{AppName}} @@ -44,16 +44,29 @@