From b0b68fdcb68984c5d815ea3c22d7305d25e3059d Mon Sep 17 00:00:00 2001 From: yan Date: Tue, 26 May 2020 15:37:46 +0800 Subject: [PATCH] add admin management --- models/dataset.go | 97 ++++++++++++++++++++++++++---- options/locale/locale_zh-CN.ini | 12 ++++ routers/admin/dataset.go | 115 ++++++++++++++++++++++++++++++++++++ routers/routes/routes.go | 5 ++ templates/admin/dataset/list.tmpl | 59 ++++++++++++++++++ templates/admin/dataset/search.tmpl | 29 +++++++++ templates/admin/navbar.tmpl | 3 + 7 files changed, 307 insertions(+), 13 deletions(-) create mode 100644 routers/admin/dataset.go create mode 100644 templates/admin/dataset/list.tmpl create mode 100644 templates/admin/dataset/search.tmpl diff --git a/models/dataset.go b/models/dataset.go index 24652d060..b7cc818a4 100644 --- a/models/dataset.go +++ b/models/dataset.go @@ -9,6 +9,12 @@ import ( "xorm.io/builder" ) +const ( + DatasetStatusPrivate int32 = iota + DatasetStatusPublic + DatasetStatusDeleted +) + type Dataset struct { ID int64 `xorm:"pk autoincr"` Title string `xorm:"INDEX NOT NULL"` @@ -23,6 +29,7 @@ type Dataset struct { CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + User *User `xorm:"-"` Attachments []*Attachment `xorm:"-"` } @@ -41,14 +48,36 @@ func (d *Dataset) IsPrivate() bool { type DatasetList []*Dataset -const ( - DatasetStatusPrivate int32 = iota - DatasetStatusPublic - DatasetStatusDeleted -) +func (datasets DatasetList) loadAttributes(e Engine) error { + if len(datasets) == 0 { + return nil + } + + set := make(map[int64]struct{}) + datasetIDs := make([]int64, len(datasets)) + for i := range datasets { + set[datasets[i].UserID] = struct{}{} + datasetIDs[i] = datasets[i].ID + } + + // Load owners. + users := make(map[int64]*User, len(set)) + if err := e. + Where("id > 0"). + In("id", keysInt64(set)). + Find(&users); err != nil { + return fmt.Errorf("find users: %v", err) + } + for i := range datasets { + datasets[i].User = users[datasets[i].UserID] + } + + return nil +} type SearchDatasetOptions struct { Keyword string + doerID int64 OwnerID int64 IsPublic bool ListOptions @@ -71,20 +100,30 @@ func SearchDataset(opts *SearchDatasetOptions) (DatasetList, int64, error) { func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond { var cond = builder.NewCond() cond = cond.And(builder.Neq{"status": DatasetStatusDeleted}) - if len(opts.Keyword) > 0 { cond = cond.And(builder.Like{"title", opts.Keyword}) } - if opts.IsPublic { - cond = cond.And(builder.Eq{"status": DatasetStatusPublic}) - if opts.OwnerID > 0 { - cond = cond.Or(builder.Eq{"user_id": opts.OwnerID}) + if opts.doerID > 0 { + doer, err := GetUserByID(opts.doerID) + if err != nil { + return nil + } + if doer.IsAdmin { + + } + + } else { + if opts.IsPublic { + cond = cond.And(builder.Eq{"status": DatasetStatusPublic}) + if opts.OwnerID > 0 { + cond = cond.Or(builder.Eq{"user_id": opts.OwnerID}) + } } - } - if opts.OwnerID > 0 { - cond = cond.And(builder.Eq{"user_id": opts.OwnerID}) + if opts.OwnerID > 0 { + cond = cond.And(builder.Eq{"user_id": opts.OwnerID}) + } } return cond @@ -114,6 +153,10 @@ func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (Da return nil, 0, fmt.Errorf("Dataset: %v", err) } + if err = datasets.loadAttributes(sess); err != nil { + return nil, 0, fmt.Errorf("LoadAttributes: %v", err) + } + return datasets, count, nil } @@ -216,6 +259,34 @@ func GetDatasetByID(id int64) (*Dataset, error) { return rel, nil } +func DeleteDataset(datasetID int64, uid int64) error { + var err error + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + dataset := &Dataset{ID: datasetID, UserID: uid} + has, err := sess.Get(dataset) + if err != nil { + return err + } else if !has { + return errors.New("not found") + } + + if cnt, err := sess.ID(datasetID).Delete(new(Dataset)); err != nil { + return err + } else if cnt != 1 { + return errors.New("not found") + } + if err = sess.Commit(); err != nil { + sess.Close() + return fmt.Errorf("Commit: %v", err) + } + return nil +} + func GetOwnerDatasetByID(id int64, user *User) (*Dataset, error) { dataset, err := GetDatasetByID(id) if err != nil { diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 01b7a23fe..22b6ceaa1 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -641,6 +641,12 @@ visibility_description=只有组织所有人或拥有权利的组织成员才能 visibility_helper=将数据集设为私有 visibility_helper_forced=站点管理员强制要求新数据集为私有。 visibility_fork_helper=(修改该值将会影响到所有派生数据集) +settings.delete=删除本据集 +settings.delete_desc=删除据集是永久性的, 无法撤消。 +settings.delete_notices_1=- 此操作 不可以 被回滚。 +settings.delete_notices_2=- 此操作将永久删除据集 %s。 +settings.delete_notices_fork_1=- 在此仓库删除后,它的派生据集将变成独立据集。 +settings.deletion_success=据集已被删除。 [repo] owner=拥有者 @@ -1846,6 +1852,7 @@ teams.all_repositories_admin_permission_desc=该团队拥有 管理Web钩子指南 获取更多内容。 hooks.add_webhook=新增默认Web钩子 hooks.update_webhook=更新默认Web钩子 diff --git a/routers/admin/dataset.go b/routers/admin/dataset.go new file mode 100644 index 000000000..7554bd869 --- /dev/null +++ b/routers/admin/dataset.go @@ -0,0 +1,115 @@ +package admin + +import ( + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" +) + +const ( + tplDatasets base.TplName = "admin/dataset/list" +) + +func Datasets(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("admin.datasets") + ctx.Data["PageIsAdmin"] = true + ctx.Data["PageIsAdminDatasets"] = true + + page := ctx.QueryInt("page") + if page <= 0 { + page = 1 + } + + var ( + datasets []*models.Dataset + count int64 + err error + orderBy models.SearchOrderBy + ) + + ctx.Data["SortType"] = ctx.Query("sort") + switch ctx.Query("sort") { + case "newest": + orderBy = models.SearchOrderByNewest + case "oldest": + orderBy = models.SearchOrderByOldest + case "recentupdate": + orderBy = models.SearchOrderByRecentUpdated + case "leastupdate": + orderBy = models.SearchOrderByLeastUpdated + case "reversealphabetically": + orderBy = models.SearchOrderByAlphabeticallyReverse + case "alphabetically": + orderBy = models.SearchOrderByAlphabetically + case "reversesize": + orderBy = models.SearchOrderBySizeReverse + case "size": + orderBy = models.SearchOrderBySize + case "moststars": + orderBy = models.SearchOrderByStarsReverse + case "feweststars": + orderBy = models.SearchOrderByStars + case "mostforks": + orderBy = models.SearchOrderByForksReverse + case "fewestforks": + orderBy = models.SearchOrderByForks + default: + ctx.Data["SortType"] = "recentupdate" + orderBy = models.SearchOrderByRecentUpdated + } + + keyword := strings.Trim(ctx.Query("q"), " ") + var uid int64 + if ctx.User != nil { + uid = ctx.User.ID + } else { + uid = 0 + } + + datasets, count, err = models.SearchDataset(&models.SearchDatasetOptions{ + ListOptions: models.ListOptions{ + Page: page, + PageSize: setting.UI.ExplorePagingNum, + }, + Keyword: keyword, + OwnerID: uid, + SearchOrderBy: orderBy, + }) + if err != nil { + ctx.ServerError("SearchDataset", err) + return + } + + ctx.Data["Keyword"] = keyword + ctx.Data["Total"] = count + ctx.Data["Datasets"] = datasets + + pager := context.NewPagination(int(count), setting.UI.ExplorePagingNum, page, 5) + pager.SetDefaultParams(ctx) + ctx.Data["Page"] = pager + + ctx.HTML(200, tplDatasets) +} + +func DeleteDataset(ctx *context.Context) { + dataset, err := models.GetDatasetByID(ctx.QueryInt64("id")) + if err != nil { + ctx.ServerError("GetDatasetByID", err) + return + } + + if err := models.DeleteDataset(dataset.ID, ctx.User.ID); err != nil { + ctx.ServerError("DeleteDataset", err) + return + } + log.Trace("DeleteDataset deleted: %s", dataset.ID) + + ctx.Flash.Success(ctx.Tr("dataset.settings.deletion_success")) + ctx.JSON(200, map[string]interface{}{ + "redirect": setting.AppSubURL + "/admin/datasets?page=" + ctx.Query("page") + "&sort=" + ctx.Query("sort"), + }) +} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index df27139e4..51e14f037 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -464,6 +464,11 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", admin.DeleteRepo) }) + m.Group("/datasets", func() { + m.Get("", admin.Datasets) + m.Post("/delete", admin.DeleteDataset) + }) + m.Group("/^:configType(hooks|system-hooks)$", func() { m.Get("", admin.DefaultOrSystemWebhooks) m.Post("/delete", admin.DeleteDefaultOrSystemWebhook) diff --git a/templates/admin/dataset/list.tmpl b/templates/admin/dataset/list.tmpl new file mode 100644 index 000000000..0aa9a2895 --- /dev/null +++ b/templates/admin/dataset/list.tmpl @@ -0,0 +1,59 @@ +{{template "base/head" .}} +
+ {{template "admin/navbar" .}} +
+ {{template "base/alert" .}} +

+ {{.i18n.Tr "admin.datasets.dataset_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}}) +

+
+ {{template "admin/dataset/search" .}} +
+
+ + + + + + + + + + + + + {{range .Datasets}} + + + + + + + + + {{end}} + +
ID{{.i18n.Tr "admin.datasets.owner"}}{{.i18n.Tr "admin.datasets.name"}}{{.i18n.Tr "admin.datasets.private"}}{{.i18n.Tr "admin.users.created"}}{{.i18n.Tr "admin.notices.op"}}
{{.ID}} + {{.User.Name}} + {{if .User.Visibility.IsPrivate}} + {{svg "octicon-lock" 16}} + {{end}} + {{.Title}}{{.CreatedUnix.FormatShort}}
+
+ + {{template "base/paginate" .}} +
+
+ + +{{template "base/footer" .}} diff --git a/templates/admin/dataset/search.tmpl b/templates/admin/dataset/search.tmpl new file mode 100644 index 000000000..586f2c9f3 --- /dev/null +++ b/templates/admin/dataset/search.tmpl @@ -0,0 +1,29 @@ + +
+
+ + +
+
diff --git a/templates/admin/navbar.tmpl b/templates/admin/navbar.tmpl index 6d81d7557..2b9f8b7c4 100644 --- a/templates/admin/navbar.tmpl +++ b/templates/admin/navbar.tmpl @@ -11,6 +11,9 @@ {{.i18n.Tr "admin.repositories"}} + + {{.i18n.Tr "admin.datasets"}} + {{.i18n.Tr "admin.hooks"}}