diff --git a/cmd/web.go b/cmd/web.go index 201eb48f0..9f2ec8b82 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -243,6 +243,11 @@ func runWeb(*cli.Context) { r.Post("/:authid", bindIgnErr(auth.AuthenticationForm{}), admin.EditAuthSourcePost) r.Post("/:authid/delete", admin.DeleteAuthSource) }) + + m.Group("/notices", func(r *macaron.Router) { + r.Get("", admin.Notices) + r.Get("/:id:int/delete", admin.DeleteNotice) + }) }, adminReq) m.Get("/:username", ignSignIn, user.Profile) diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini index 4fc8c359f..15262e630 100644 --- a/conf/locale/locale_en-US.ini +++ b/conf/locale/locale_en-US.ini @@ -416,6 +416,7 @@ organizations = Organizations repositories = Repositories authentication = Authentications config = Configuration +notices = System Notices monitor = Monitoring prev = Prev. next = Next @@ -593,6 +594,13 @@ monitor.desc = Description monitor.start = Start Time monitor.execute_time = Execution Time +notices.system_notice_list = System Notices +notices.type = Type +notices.type_1 = Repository +notices.desc = Description +notices.op = Op. +notices.delete_success = System notice has been successfully deleted. + [action] create_repo = created repository <a href="%s/%s">%s</a> commit_repo = pushed to <a href="%s/%s/src/%s">%s</a> at <a href="%s/%s">%s</a> diff --git a/conf/locale/locale_zh-CN.ini b/conf/locale/locale_zh-CN.ini index dc4548487..8a343d4c8 100644 --- a/conf/locale/locale_zh-CN.ini +++ b/conf/locale/locale_zh-CN.ini @@ -416,6 +416,7 @@ organizations = 组织管理 repositories = 仓库管理 authentication = 授权认证管理 config = 应用配置管理 +notices = 系统提示管理 monitor = 应用监控面板 prev = 上一页 next = 下一页 @@ -593,6 +594,13 @@ monitor.desc = 进程描述 monitor.start = 开始时间 monitor.execute_time = 已执行时间 +notices.system_notice_list = 系统提示管理 +notices.type = 提示类型 +notices.type_1 = 仓库 +notices.desc = 描述 +notices.op = 操作 +notices.delete_success = 系统提示删除成功! + [action] create_repo = 创建了仓库 <a href="%s/%s">%s</a> commit_repo = 推送了 <a href="%s/%s/src/%s">%s</a> 分支的代码到 <a href="%s/%s">%s</a> diff --git a/gogs.go b/gogs.go index b1e46096a..250333f39 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.5.5.1007 Beta" +const APP_VER = "0.5.5.1008 Beta" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/admin.go b/models/admin.go new file mode 100644 index 000000000..493cc7afc --- /dev/null +++ b/models/admin.go @@ -0,0 +1,64 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "time" + + "github.com/Unknwon/com" +) + +type NoticeType int + +const ( + NOTICE_REPOSITORY NoticeType = iota + 1 +) + +// Notice represents a system notice for admin. +type Notice struct { + Id int64 + Type NoticeType + Description string `xorm:"TEXT"` + Created time.Time `xorm:"CREATED"` +} + +// TrStr returns a translation format string. +func (n *Notice) TrStr() string { + return "admin.notices.type_" + com.ToStr(n.Type) +} + +// CreateNotice creates new system notice. +func CreateNotice(tp NoticeType, desc string) error { + n := &Notice{ + Type: tp, + Description: desc, + } + _, err := x.Insert(n) + return err +} + +// CreateRepositoryNotice creates new system notice with type NOTICE_REPOSITORY. +func CreateRepositoryNotice(desc string) error { + return CreateNotice(NOTICE_REPOSITORY, desc) +} + +// CountNotices returns number of notices. +func CountNotices() int64 { + count, _ := x.Count(new(Notice)) + return count +} + +// GetNotices returns given number of notices with offset. +func GetNotices(num, offset int) ([]*Notice, error) { + notices := make([]*Notice, 0, num) + err := x.Limit(num, offset).Desc("id").Find(¬ices) + return notices, err +} + +// DeleteNotice deletes a system notice by given ID. +func DeleteNotice(id int64) error { + _, err := x.Id(id).Delete(new(Notice)) + return err +} diff --git a/models/models.go b/models/models.go index 570df0c11..35eb4c969 100644 --- a/models/models.go +++ b/models/models.go @@ -32,12 +32,12 @@ var ( ) func init() { - tables = append(tables, new(User), new(PublicKey), + tables = append(tables, new(User), new(PublicKey), new(Follow), new(Oauth2), new(Repository), new(Watch), new(Star), new(Action), new(Access), - new(Issue), new(Comment), new(Oauth2), new(Follow), - new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssueUser), - new(Milestone), new(Label), new(HookTask), new(Team), new(OrgUser), new(TeamUser), - new(UpdateTask), new(Attachment)) + new(Issue), new(Comment), new(Attachment), new(IssueUser), new(Label), new(Milestone), + new(Mirror), new(Release), new(LoginSource), new(Webhook), + new(UpdateTask), new(HookTask), new(Team), new(OrgUser), new(TeamUser), + new(Notice)) } func LoadModelsConfig() { diff --git a/models/repo.go b/models/repo.go index 8e29b3357..3a26c88f0 100644 --- a/models/repo.go +++ b/models/repo.go @@ -934,9 +934,14 @@ func DeleteRepository(uid, repoId int64, userName string) error { sess.Rollback() return err } + + // Remove repository files. if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil { - sess.Rollback() - return err + desc := fmt.Sprintf("Fail to delete repository files(%s/%s): %v", userName, repo.Name, err) + log.Warn(desc) + if err = CreateRepositoryNotice(desc); err != nil { + log.Error(4, "Fail to add notice: %v", err) + } } return sess.Commit() } diff --git a/routers/admin/notice.go b/routers/admin/notice.go new file mode 100644 index 000000000..b43194636 --- /dev/null +++ b/routers/admin/notice.go @@ -0,0 +1,46 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package admin + +import ( + "github.com/Unknwon/com" + + "github.com/gogits/gogs/models" + "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/middleware" +) + +const ( + NOTICES base.TplName = "admin/notice" +) + +func Notices(ctx *middleware.Context) { + ctx.Data["Title"] = ctx.Tr("admin.notices") + ctx.Data["PageIsAdmin"] = true + ctx.Data["PageIsAdminNotices"] = true + + pageNum := 50 + p := pagination(ctx, models.CountNotices(), pageNum) + + notices, err := models.GetNotices(pageNum, (p-1)*pageNum) + if err != nil { + ctx.Handle(500, "GetNotices", err) + return + } + ctx.Data["Notices"] = notices + ctx.HTML(200, NOTICES) +} + +func DeleteNotice(ctx *middleware.Context) { + id := com.StrTo(ctx.Params(":id")).MustInt64() + if err := models.DeleteNotice(id); err != nil { + ctx.Handle(500, "DeleteNotice", err) + return + } + log.Trace("System notice deleted by admin(%s): %d", ctx.User.Name, id) + ctx.Flash.Success(ctx.Tr("admin.notices.delete_success")) + ctx.Redirect("/admin/notices") +} diff --git a/routers/admin/users.go b/routers/admin/users.go index fc3b0cbce..e5cd364f3 100644 --- a/routers/admin/users.go +++ b/routers/admin/users.go @@ -48,12 +48,12 @@ func Users(ctx *middleware.Context) { pageNum := 50 p := pagination(ctx, models.CountUsers(), pageNum) - var err error - ctx.Data["Users"], err = models.GetUsers(pageNum, (p-1)*pageNum) + users, err := models.GetUsers(pageNum, (p-1)*pageNum) if err != nil { ctx.Handle(500, "GetUsers", err) return } + ctx.Data["Users"] = users ctx.HTML(200, USERS) } diff --git a/templates/.VERSION b/templates/.VERSION index 999f683bf..194ec5802 100644 --- a/templates/.VERSION +++ b/templates/.VERSION @@ -1 +1 @@ -0.5.5.1007 Beta \ No newline at end of file +0.5.5.1008 Beta \ No newline at end of file diff --git a/templates/admin/nav.tmpl b/templates/admin/nav.tmpl index e294cd921..49c4b72cf 100644 --- a/templates/admin/nav.tmpl +++ b/templates/admin/nav.tmpl @@ -8,6 +8,7 @@ <li {{if .PageIsAdminRepositories}}class="current"{{end}}><a href="{{AppSubUrl}}/admin/repos">{{.i18n.Tr "admin.repositories"}}</a></li> <li {{if .PageIsAdminAuthentications}}class="current"{{end}}><a href="{{AppSubUrl}}/admin/auths">{{.i18n.Tr "admin.authentication"}}</a></li> <li {{if .PageIsAdminConfig}}class="current"{{end}}><a href="{{AppSubUrl}}/admin/config">{{.i18n.Tr "admin.config"}}</a></li> + <li {{if .PageIsAdminNotices}}class="current"{{end}}><a href="{{AppSubUrl}}/admin/notices">{{.i18n.Tr "admin.notices"}}</a></li> <li {{if .PageIsAdminMonitor}}class="current"{{end}}><a href="{{AppSubUrl}}/admin/monitor">{{.i18n.Tr "admin.monitor"}}</a></li> </ul> </div> diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl new file mode 100644 index 000000000..b3abbb6b7 --- /dev/null +++ b/templates/admin/notice.tmpl @@ -0,0 +1,54 @@ +{{template "ng/base/head" .}} +{{template "ng/base/header" .}} +<div id="admin-wrapper"> + <div id="setting-wrapper" class="main-wrapper"> + <div id="admin-setting" class="container clear"> + {{template "admin/nav" .}} + <div class="grid-4-5 left"> + <div class="setting-content"> + {{template "ng/base/alert" .}} + <div id="setting-content"> + <div class="panel panel-radius"> + <div class="panel-header"> + <strong>{{.i18n.Tr "admin.notices.system_notice_list"}}</strong> + </div> + <div class="panel-body admin-panel"> + <div class="admin-table"> + <table class="table table-striped"> + <thead> + <tr> + <th>Id</th> + <th>{{.i18n.Tr "admin.notices.type"}}</th> + <th>{{.i18n.Tr "admin.notices.desc"}}</th> + <th>{{.i18n.Tr "admin.users.created"}}</th> + <th>{{.i18n.Tr "admin.notices.op"}}</th> + </tr> + </thead> + <tbody> + {{range .Notices}} + <tr> + <td>{{.Id}}</td> + <td>{{$.i18n.Tr .TrStr}}</td> + <td class="grid-1-2"><span>{{.Description}}</span></td> + <td>{{.Created}}</td> + <td><a href="{{AppSubUrl}}/admin/notices/{{.Id}}/delete"><i class="fa fa-trash-o text-red"></i></a></td> + </tr> + {{end}} + </tbody> + </table> + {{if or .LastPageNum .NextPageNum}} + <ul class="pagination"> + {{if .LastPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{AppSubUrl}}/admin/users?p={{.LastPageNum}}">« {{.i18n.Tr "admin.prev"}}</a></li>{{end}} + {{if .NextPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{AppSubUrl}}/admin/users?p={{.NextPageNum}}">» {{.i18n.Tr "admin.next"}}</a></li>{{end}} + </ul> + {{end}} + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</div> +{{template "ng/base/footer" .}} \ No newline at end of file