diff --git a/models/models.go b/models/models.go index 854cb33b147fe..26af805286ad3 100644 --- a/models/models.go +++ b/models/models.go @@ -113,6 +113,8 @@ func init() { new(OAuth2AuthorizationCode), new(OAuth2Grant), new(Task), + new(Transfer), + new(Fund), ) gonicNames := []string{"SSL", "UID"} diff --git a/models/pull.go b/models/pull.go index c6da63ec55795..44112740d320d 100644 --- a/models/pull.go +++ b/models/pull.go @@ -467,6 +467,18 @@ func (pr *PullRequest) SetMerged() (err error) { return err } + if err = pr.GetHeadRepo(); err != nil { + return err + } + + if err = pr.GetBaseRepo(); err != nil { + return err + } + + if err = pr.HeadRepo.GetOwner(); err != nil { + return err + } + if err = pr.Issue.changeStatus(sess, pr.Merger, true); err != nil { return fmt.Errorf("Issue.changeStatus: %v", err) } @@ -474,6 +486,34 @@ func (pr *PullRequest) SetMerged() (err error) { return fmt.Errorf("update pull request: %v", err) } + var FromID = pr.BaseRepo.OwnerName + var Why = "奖励"+pr.BaseRepo.Name+ "项目的贡献" + var ToID = pr.HeadRepo.Owner.Name + var Qty = int(pr.BaseRepo.NextPoint) + + if FromID != ToID { + + if _, err = sess.Insert(&Transfer{FromID: FromID, ToID: ToID, Why: Why, Qty: Qty}); err != nil { + return fmt.Errorf("Transfer", err) + } + + if _, err = sess.Exec("UPDATE `user` SET point = point + ? WHERE name = ?", Qty, ToID); err != nil { + return fmt.Errorf("Add Point", err) + } + + if _, err = sess.Exec("UPDATE `user` SET point = point - ? WHERE name = ?", Qty, FromID); err != nil { + return fmt.Errorf("Subtract Point", err) + } + + if _, err = sess.Exec("UPDATE `repository` SET point = point - ? WHERE id = ?", Qty, pr.BaseRepo.ID); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `repository` SET next_point = point * percent * 0.01 WHERE id = ?", pr.BaseRepo.ID); err != nil { + return err + } + } + if err = sess.Commit(); err != nil { return fmt.Errorf("Commit: %v", err) } @@ -507,10 +547,10 @@ func (pr *PullRequest) manuallyMerged() bool { pr.Merger = merger pr.MergerID = merger.ID - if err = pr.SetMerged(); err != nil { - log.Error("PullRequest[%d].setMerged : %v", pr.ID, err) - return false - } +// if err = pr.SetMerged(); err != nil { +// log.Error("PullRequest[%d].setMerged : %v", pr.ID, err) +// return false +// } log.Info("manuallyMerged[%d]: Marked as manually merged into %s/%s by commit id: %s", pr.ID, pr.BaseRepo.Name, pr.BaseBranch, commit.ID.String()) return true } diff --git a/models/repo.go b/models/repo.go index ac3443f8953b4..fee766a5c8196 100644 --- a/models/repo.go +++ b/models/repo.go @@ -147,6 +147,9 @@ type Repository struct { Name string `xorm:"INDEX NOT NULL"` Description string `xorm:"TEXT"` Website string `xorm:"VARCHAR(2048)"` + Percent int64 + Point int64 + NextPoint int64 OriginalServiceType structs.GitServiceType `xorm:"index"` OriginalURL string `xorm:"VARCHAR(2048)"` DefaultBranch string diff --git a/models/repo_list.go b/models/repo_list.go index c823647eba098..3621275720a54 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -163,6 +163,7 @@ const ( SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" SearchOrderByForks SearchOrderBy = "num_forks ASC" SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" + SearchOrderByPoint SearchOrderBy = "Point DESC" ) // SearchRepository returns repositories based on search options, diff --git a/models/transfer_point.go b/models/transfer_point.go new file mode 100644 index 0000000000000..ea1b89494ec0e --- /dev/null +++ b/models/transfer_point.go @@ -0,0 +1,129 @@ +// Copyright 2017 The Gitea 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 ( + "fmt" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + "xorm.io/builder" +) + +type Transfer struct { + ID int64 `xorm:"pk autoincr"` + FromID string + ToID string + Why string + Qty int + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` +} + +// SearchTransOptions contains the options for searching +type SearchTransOptions struct { + Keyword string + OrderBy SearchOrderBy + Page int + PageSize int // Can be smaller than or equal to setting.UI.ExplorePagingNum +} + +func (opts *SearchTransOptions) toConds() builder.Cond { + var cond builder.Cond = builder.Gt{"ID": 0} + return cond +} + +func SearchTrans(opts *SearchTransOptions) (trans []*Transfer, _ int64, _ error) { + cond := opts.toConds() + count, err := x.Where(cond).Count(new(Transfer)) + if err != nil { + return nil, 0, fmt.Errorf("Count: %v", err) + } + + if opts.PageSize == 0 || opts.PageSize > setting.UI.ExplorePagingNum { + opts.PageSize = setting.UI.ExplorePagingNum + } + if opts.Page <= 0 { + opts.Page = 1 + } + if len(opts.OrderBy) == 0 { + opts.OrderBy = SearchOrderByIDReverse + } + + sess := x.Where(cond) + if opts.PageSize > 0 { + sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) + } + if opts.PageSize == -1 { + opts.PageSize = int(count) + } + + trans = make([]*Transfer, 0, opts.PageSize) + return trans, count, sess.OrderBy(opts.OrderBy.String()).Find(&trans) +} + +func TransferPoint(FromID string, Why string, ToID string, Qty int) (err error) { + + sess := x.NewSession() + + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + if _, err = sess.Insert(&Transfer{FromID: FromID, ToID: ToID, Why: Why, Qty: Qty}); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `user` SET point = point + ? WHERE name = ?", Qty, ToID); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `user` SET point = point - ? WHERE name = ?", Qty, FromID); err != nil { + return err + } + return sess.Commit() +} + +// Fund contains the fund information +type Fund struct { + ID int64 `xorm:"pk autoincr"` + Name string + RepoID int64 `xorm:"INDEX"` + Qty int64 +} + +type FundList []*Fund + +// GetFunds returns a list of Funds of given repository. +func GetFunds(repoID int64, page int) (FundList, error) { + funds := make([]*Fund, 0, setting.UI.IssuePagingNum) + sess := x.Where("repo_id = ? ", repoID) + if page > 0 { + sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum) + } + + return funds, sess.Find(&funds) +} + +func NewFund(name string, repoID int64, qty int64)(err error){ + sess := x.NewSession() + + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + if _, err = sess.Insert(&Fund{Name: name, RepoID: repoID, Qty: qty}); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `repository` SET point = point + ? WHERE id = ?", qty, repoID); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `repository` SET next_point = point * percent * 0.01 WHERE id = ?", repoID); err != nil { + return err + } + return sess.Commit() +} diff --git a/models/user.go b/models/user.go index 7aa1e143e835b..4811d1f368c56 100644 --- a/models/user.go +++ b/models/user.go @@ -118,6 +118,7 @@ type User struct { Salt string `xorm:"VARCHAR(10)"` Language string `xorm:"VARCHAR(5)"` Description string + Point int `xorm:"NOT NULL DEFAULT 0"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 2280666114d52..7cecf6f19d047 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -102,6 +102,8 @@ type RepoSettingForm struct { RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"` Description string `binding:"MaxSize(255)"` Website string `binding:"ValidUrl;MaxSize(255)"` + Percent int64 + Point int64 Interval string MirrorAddress string MirrorUsername string diff --git a/routers/home.go b/routers/home.go index eddff28ee9965..650721a4f2c17 100644 --- a/routers/home.go +++ b/routers/home.go @@ -28,6 +28,8 @@ const ( tplExploreUsers base.TplName = "explore/users" // tplExploreOrganizations explore organizations page template tplExploreOrganizations base.TplName = "explore/organizations" + + tplExploreTrans base.TplName = "explore/trans" // tplExploreCode explore code page template tplExploreCode base.TplName = "explore/code" ) @@ -210,7 +212,7 @@ func RenderUserSearch(ctx *context.Context, opts *models.SearchUserOptions, tplN orderBy = models.SearchOrderByAlphabetically default: ctx.Data["SortType"] = "alphabetically" - orderBy = models.SearchOrderByAlphabetically + orderBy = models.SearchOrderByPoint } opts.Keyword = strings.Trim(ctx.Query("q"), " ") @@ -270,6 +272,63 @@ func ExploreOrganizations(ctx *context.Context) { }, tplExploreOrganizations) } +// RenderUserSearch render user search page +func RenderTransSearch(ctx *context.Context, opts *models.SearchTransOptions, tplName base.TplName) { + opts.Page = ctx.QueryInt("page") + if opts.Page <= 1 { + opts.Page = 1 + } + + var ( + trans []*models.Transfer + count int64 + err error + orderBy models.SearchOrderBy + ) + + ctx.Data["SortType"] = ctx.Query("sort") + switch ctx.Query("sort") { + case "newest": + orderBy = models.SearchOrderByIDReverse + case "oldest": + orderBy = models.SearchOrderByID + default: + ctx.Data["SortType"] = "alphabetically" + orderBy = models.SearchOrderByIDReverse + } + + opts.Keyword = strings.Trim(ctx.Query("q"), " ") + opts.OrderBy = orderBy + if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) { + trans, count, err = models.SearchTrans(opts) + if err != nil { + ctx.ServerError("SearchTrans", err) + return + } + } + ctx.Data["Keyword"] = opts.Keyword + ctx.Data["Total"] = count + ctx.Data["Trans"] = trans + ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled + + pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5) + pager.SetDefaultParams(ctx) + ctx.Data["Page"] = pager + + ctx.HTML(200, tplName) +} + +func ExploreTrans(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("explore") + ctx.Data["PageIsExplore"] = true + ctx.Data["PageIsExploreTrans"] = true + ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled + + RenderTransSearch(ctx, &models.SearchTransOptions{ + PageSize: setting.UI.ExplorePagingNum, + }, tplExploreTrans) +} + // ExploreCode render explore code page func ExploreCode(ctx *context.Context) { if !setting.Indexer.RepoIndexerEnabled { diff --git a/routers/repo/fund.go b/routers/repo/fund.go new file mode 100644 index 0000000000000..f73d1d8012069 --- /dev/null +++ b/routers/repo/fund.go @@ -0,0 +1,67 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2018 The Gitea 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 repo + +import ( + "strconv" + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" +) + +const ( + tplFunds base.TplName = "repo/fund/list" +) + +// Funds render repository branch page +func Funds(ctx *context.Context) { + ctx.Data["Title"] = "Funds" + ctx.Data["PageIsFund"] = true + page := ctx.QueryInt("page") + funds, err := models.GetFunds(ctx.Repo.Repository.ID, page) + if err != nil { + ctx.ServerError("GetFunds", err) + return + } + ctx.Data["Funds"] = funds + ctx.HTML(200, tplFunds) +} + +func Funding(ctx *context.Context) { + //减少发送者点数 + //增加接收者点数 + //创建transfer记录 + var err error + Qty, err := strconv.Atoi(ctx.Query("qty")) + if err != nil { + ctx.Flash.Error("请输入数字") + return + } + var repoid int + repoid, err = strconv.Atoi(ctx.Query("repoid")) + if ctx.User.Point < Qty { + ctx.Flash.Error("余额不足!") + return + } + err = models.TransferPoint(ctx.User.Name, + ctx.Query("why"), + ctx.Query("toid"), + Qty) + if err != nil { + ctx.ServerError("Transfer", err) + return + } + err = models.NewFund(ctx.User.Name, + int64(repoid), + int64(Qty)) + if err != nil { + ctx.ServerError("Transfer", err) + return + } + + ctx.RedirectToFirst(ctx.Query("redirect_to"), ctx.Repo.RepoLink + "/funds") +} + diff --git a/routers/repo/repo.go b/routers/repo/repo.go index cf1845a727bb4..2ea4f94802de0 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -473,3 +473,4 @@ func Status(ctx *context.Context) { "err": task.Errors, }) } + diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 663394fe3db6d..d73f4d33d8608 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -100,6 +100,9 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { repo.LowerName = strings.ToLower(newRepoName) repo.Description = form.Description repo.Website = form.Website + repo.Percent = form.Percent + repo.Point = form.Point + repo.NextPoint = int64(float64(repo.Point) * float64(repo.Percent) * 0.01) // Visibility of forked repository is forced sync with base repository. if repo.IsFork { diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 13a5bb27084d0..1d9d5af4ce1e7 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -268,6 +268,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("", func(ctx *context.Context) { ctx.Redirect(setting.AppSubURL + "/explore/repos") }) + m.Get("/trans", routers.ExploreTrans) m.Get("/repos", routers.ExploreRepos) m.Get("/users", routers.ExploreUsers) m.Get("/organizations", routers.ExploreOrganizations) @@ -520,6 +521,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/:username", func() { m.Get("/action/:action", user.Action) + m.Post("/action/transfer_point", user.TransferP) }, reqSignIn) if macaron.Env == macaron.DEV { @@ -846,6 +848,11 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/raw/*", repo.WikiRaw) }, repo.MustEnableWiki) + m.Group("/funds", func(){ + m.Get("", repo.Funds) + m.Post("/action/funding",repo.Funding) + },context.RepoRef()) + m.Group("/activity", func() { m.Get("", repo.Activity) m.Get("/:period", repo.Activity) diff --git a/routers/user/profile.go b/routers/user/profile.go index 8a62ddeac026c..63e5bd4ab49ed 100644 --- a/routers/user/profile.go +++ b/routers/user/profile.go @@ -9,6 +9,7 @@ import ( "fmt" "path" "strings" + "strconv" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" @@ -270,3 +271,30 @@ func Action(ctx *context.Context) { ctx.RedirectToFirst(ctx.Query("redirect_to"), u.HomeLink()) } + +func TransferP(ctx *context.Context) { + //减少发送者点数 + //增加接收者点数 + //创建transfer记录 + u := GetUserByParams(ctx) + var err error + Qty, err := strconv.Atoi(ctx.Query("qty")) + if err != nil { + ctx.Flash.Error("请输入数字") + return + } + if ctx.User.Point < Qty { + ctx.Flash.Error("余额不足!") + ctx.RedirectToFirst(ctx.Query("redirect_to"), u.HomeLink()) + return + } + err = models.TransferPoint(ctx.User.Name, + ctx.Query("why"), + u.Name, + Qty) + if err != nil { + ctx.ServerError("Transfer", err) + return + } + ctx.RedirectToFirst(ctx.Query("redirect_to"), u.HomeLink()) +} diff --git a/templates/explore/navbar.tmpl b/templates/explore/navbar.tmpl index 3bd52645e2165..8343b7aa9c8c2 100644 --- a/templates/explore/navbar.tmpl +++ b/templates/explore/navbar.tmpl @@ -1,4 +1,7 @@