diff --git a/docs/开源社区平台与区块链平台对接方案.docx b/docs/开源社区平台与区块链平台对接方案.docx new file mode 100755 index 000000000..f4223c354 Binary files /dev/null and b/docs/开源社区平台与区块链平台对接方案.docx differ diff --git a/models/block_chain_issue.go b/models/block_chain_issue.go new file mode 100755 index 000000000..971ccf002 --- /dev/null +++ b/models/block_chain_issue.go @@ -0,0 +1,101 @@ +package models + +import ( + "code.gitea.io/gitea/modules/timeutil" + "fmt" + "time" +) + +type BlockChainIssueStatus int +const ( + BlockChainIssueInit BlockChainIssueStatus = iota + BlockChainIssueSuccess + BlockChainIssueFailed +) +type BlockChainIssue struct { + ID int64 `xorm:"pk autoincr"` + IssueID int64 `xorm:"INDEX NOT NULL unique"` + Contributor string `xorm:"INDEX NOT NULL"` + ContractAddress string `xorm:"INDEX NOT NULL"` + Status BlockChainIssueStatus `xorm:"INDEX NOT NULL DEFAULT 0"` + Amount int64 `xorm:"INDEX"` + UserID int64 `xorm:"INDEX"` + RepoID int64 `xorm:"INDEX"` + TransactionHash string `xorm:"INDEX"` + CreatedUnix timeutil.TimeStamp `xorm:"created"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated"` + DeletedAt time.Time `xorm:"deleted"` + + User *User `xorm:"-"` + Repo *Repository `xorm:"-"` +} + +func getBlockChainIssueByID(e Engine, id int64) (*BlockChainIssue, error) { + blockChainIssue := new(BlockChainIssue) + has, err := e.ID(id).Get(blockChainIssue) + if err != nil { + return nil, err + } else if !has { + return nil, fmt.Errorf("get block_chain by id failed(%d)", id) + } + return blockChainIssue, nil +} + +func GetBlockChainIssueByID(id int64) (*BlockChainIssue, error) { + return getBlockChainIssueByID(x, id) +} + +func getBlockChainIssueByPrID(e Engine, prId int64) (*BlockChainIssue, error) { + blockChainIssue := new(BlockChainIssue) + has, err := e.Where("pr_id = ?", prId).Get(blockChainIssue) + if err != nil { + return nil, err + } else if !has { + return nil, fmt.Errorf("get block_chain by pr_id failed(%d)", prId) + } + return blockChainIssue, nil +} + +func GetBlockChainIssueByPrID(prId int64) (*BlockChainIssue, error) { + return getBlockChainIssueByPrID(x, prId) +} + +func getBlockChainIssueByCommitID(e Engine, commitID string) (*BlockChainIssue, error) { + blockChainIssue := new(BlockChainIssue) + has, err := e.Where("commit_id = ?", commitID).Get(blockChainIssue) + if err != nil { + return nil, err + } else if !has { + return nil, fmt.Errorf("get block_chain_issue by commitID failed(%s)", commitID) + } + return blockChainIssue, nil +} + +func GetBlockChainIssueByCommitID(commitID string) (*BlockChainIssue, error) { + return getBlockChainIssueByCommitID(x, commitID) +} + +func updateBlockChainIssueCols(e Engine, blockChainIssue *BlockChainIssue, cols ...string) error { + _, err := e.ID(blockChainIssue.ID).Cols(cols...).Update(blockChainIssue) + return err +} + +func UpdateBlockChainIssueCols(blockChainIssue *BlockChainIssue, cols ...string) error { + return updateBlockChainIssueCols(x, blockChainIssue, cols...) +} + +func GetBlockChainUnSuccessIssues() ([]*BlockChainIssue, error) { + blockChainIssues := make([]*BlockChainIssue, 0, 10) + return blockChainIssues, x. + Where("status != ?", BlockChainIssueSuccess). + Find(&blockChainIssues) +} + +func InsertBlockChainIssue(blockChainIssue *BlockChainIssue) (_ *BlockChainIssue, err error) { + + if _, err := x.Insert(blockChainIssue); err != nil { + return nil, err + } + + return blockChainIssue, nil +} diff --git a/models/blockchain.go b/models/blockchain.go index f5ba8e1b6..ed13908d7 100755 --- a/models/blockchain.go +++ b/models/blockchain.go @@ -15,18 +15,19 @@ const ( ) type BlockChain struct { - ID int64 `xorm:"pk autoincr"` - CommitID string `xorm:"INDEX NOT NULL"` - Contributor string `xorm:"INDEX NOT NULL"` - ContractAddress string `xorm:"INDEX NOT NULL"` - Status BlockChainCommitStatus `xorm:"INDEX NOT NULL DEFAULT 0"` - Amount int64 `xorm:"INDEX"` - UserID int64 `xorm:"INDEX"` - RepoID int64 `xorm:"INDEX"` - TransactionHash string `xorm:"INDEX"` - CreatedUnix timeutil.TimeStamp `xorm:"created"` - UpdatedUnix timeutil.TimeStamp `xorm:"updated"` - DeletedAt time.Time `xorm:"deleted"` + ID int64 `xorm:"pk autoincr"` + PrID int64 `xorm:"INDEX NOT NULL unique"` + CommitID string `xorm:"INDEX NOT NULL unique"` + Contributor string `xorm:"INDEX NOT NULL"` + ContractAddress string `xorm:"INDEX NOT NULL"` + Status BlockChainCommitStatus `xorm:"INDEX NOT NULL DEFAULT 0"` + Amount int64 `xorm:"INDEX"` + UserID int64 `xorm:"INDEX"` + RepoID int64 `xorm:"INDEX"` + TransactionHash string `xorm:"INDEX"` + CreatedUnix timeutil.TimeStamp `xorm:"created"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated"` + DeletedAt time.Time `xorm:"deleted"` User *User `xorm:"-"` Repo *Repository `xorm:"-"` @@ -47,6 +48,21 @@ func GetBlockChainByID(id int64) (*BlockChain, error) { return getBlockChainByID(x, id) } +func getBlockChainByPrID(e Engine, prId int64) (*BlockChain, error) { + blockChain := new(BlockChain) + has, err := e.Where("pr_id = ?", prId).Get(blockChain) + if err != nil { + return nil, err + } else if !has { + return nil, fmt.Errorf("get block_chain by pr_id failed(%d)", prId) + } + return blockChain, nil +} + +func GetBlockChainByPrID(prId int64) (*BlockChain, error) { + return getBlockChainByPrID(x, prId) +} + func getBlockChainByCommitID(e Engine, commitID string) (*BlockChain, error) { blockChain := new(BlockChain) has, err := e.Where("commit_id = ?", commitID).Get(blockChain) diff --git a/models/issue.go b/models/issue.go old mode 100644 new mode 100755 index d9f8e929c..7bed58843 --- a/models/issue.go +++ b/models/issue.go @@ -66,6 +66,10 @@ type Issue struct { // IsLocked limits commenting abilities to users on an issue // with write access IsLocked bool `xorm:"NOT NULL DEFAULT false"` + + //block_chain + Amount int64 + IsTransformed bool `xorm:"INDEX NOT NULL DEFAULT false"` } var ( diff --git a/models/pull.go b/models/pull.go old mode 100644 new mode 100755 index 9f1f48526..a8b86937a --- a/models/pull.go +++ b/models/pull.go @@ -36,6 +36,13 @@ const ( PullRequestStatusError ) +const ( + PullRequestAmountZero int = 0 + PullRequestAmountOne int = 100 + PullRequestAmountTwo int = 200 + PullRequestAmountMax int = 300 +) + // PullRequest represents relation between pull request and repositories. type PullRequest struct { ID int64 `xorm:"pk autoincr"` @@ -65,6 +72,10 @@ type PullRequest struct { MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"` isHeadRepoLoaded bool `xorm:"-"` + + //block_chain + IsTransformed bool `xorm:"INDEX NOT NULL DEFAULT false"` + Amount int `xorm:"INDEX NOT NULL DEFAULT 0"` } // MustHeadUserName returns the HeadRepo's username if failed return blank @@ -396,7 +407,7 @@ func (pr *PullRequest) SetMerged() (bool, error) { return false, fmt.Errorf("Issue.changeStatus: %v", err) } - if _, err := sess.Where("id = ?", pr.ID).Cols("has_merged, status, merged_commit_id, merger_id, merged_unix").Update(pr); err != nil { + if _, err := sess.Where("id = ?", pr.ID).Cols("has_merged, status, merged_commit_id, merger_id, merged_unix, amount").Update(pr); err != nil { return false, fmt.Errorf("Failed to update pr[%d]: %v", pr.ID, err) } diff --git a/models/pull_list.go b/models/pull_list.go old mode 100644 new mode 100755 index 989de4689..ee61f2ab5 --- a/models/pull_list.go +++ b/models/pull_list.go @@ -5,6 +5,7 @@ package models import ( + "code.gitea.io/gitea/modules/setting" "fmt" "code.gitea.io/gitea/modules/base" @@ -170,3 +171,11 @@ func (prs PullRequestList) invalidateCodeComments(e Engine, doer *User, repo *gi func (prs PullRequestList) InvalidateCodeComments(doer *User, repo *git.Repository, branch string) error { return prs.invalidateCodeComments(x, doer, repo, branch) } + +func GetUnTransformedMergedPullRequests() ([]*PullRequest, error) { + prs := make([]*PullRequest, 0, 10) + return prs, x. + Where("has_merged = ? AND pull_request.is_transformed = ? AND to_timestamp(merged_unix) >= ?",true, false, setting.CommitValidDate). + Join("INNER", "issue", "issue.id = pull_request.issue_id"). + Find(&prs) +} diff --git a/models/repo.go b/models/repo.go index 9095bbda8..f99e909ae 100755 --- a/models/repo.go +++ b/models/repo.go @@ -206,9 +206,9 @@ type Repository struct { Avatar string `xorm:"VARCHAR(64)"` //blockchain - ContractAddress string `xorm:"INDEX"` - Balance int64 `xorm:"NOT NULL DEFAULT 0"` - BlockChainStatus RepoBlockChainStatus `xorm:"NOT NULL DEFAULT 0"` + ContractAddress string `xorm:"INDEX"` + Balance string `xorm:"NOT NULL DEFAULT '0'"` + BlockChainStatus RepoBlockChainStatus `xorm:"NOT NULL DEFAULT 0"` // git clone total count CloneCnt int64 `xorm:"NOT NULL DEFAULT 0"` @@ -1105,6 +1105,12 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error Type: tp, Config: &CloudBrainConfig{EnableCloudBrain: true}, }) + } else if tp == UnitTypeBlockChain { + units = append(units, RepoUnit{ + RepoID: repo.ID, + Type: tp, + Config: &BlockChainConfig{EnableBlockChain: true}, + }) } else { units = append(units, RepoUnit{ RepoID: repo.ID, diff --git a/models/repo_unit.go b/models/repo_unit.go old mode 100644 new mode 100755 index a0e7a2f76..518c4b979 --- a/models/repo_unit.go +++ b/models/repo_unit.go @@ -141,6 +141,20 @@ func (cfg *CloudBrainConfig) ToDB() ([]byte, error) { return json.Marshal(cfg) } +type BlockChainConfig struct { + EnableBlockChain bool +} + +// FromDB fills up a CloudBrainConfig from serialized format. +func (cfg *BlockChainConfig) FromDB(bs []byte) error { + return json.Unmarshal(bs, &cfg) +} + +// ToDB exports a CloudBrainConfig to a serialized format. +func (cfg *BlockChainConfig) ToDB() ([]byte, error) { + return json.Marshal(cfg) +} + // BeforeSet is invoked from XORM before setting the value of a field of this object. func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) { switch colName { @@ -160,6 +174,8 @@ func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) { r.Config = new(DatasetConfig) case UnitTypeCloudBrain: r.Config = new(CloudBrainConfig) + case UnitTypeBlockChain: + r.Config = new(BlockChainConfig) default: panic("unrecognized repo unit type: " + com.ToStr(*val)) } diff --git a/models/unit.go b/models/unit.go old mode 100644 new mode 100755 index 41712f238..3d1d03f18 --- a/models/unit.go +++ b/models/unit.go @@ -26,6 +26,7 @@ const ( UnitTypeExternalTracker // 7 ExternalTracker UnitTypeDatasets UnitType = 10 // 10 Dataset UnitTypeCloudBrain UnitType = 11 // 11 CloudBrain + UnitTypeBlockChain UnitType = 12 // 12 BlockChain ) // Value returns integer value for unit type @@ -53,6 +54,8 @@ func (u UnitType) String() string { return "UnitTypeDataset" case UnitTypeCloudBrain: return "UnitTypeCloudBrain" + case UnitTypeBlockChain: + return "UnitTypeBlockChain" } return fmt.Sprintf("Unknown UnitType %d", u) } @@ -76,6 +79,7 @@ var ( UnitTypeExternalTracker, UnitTypeDatasets, UnitTypeCloudBrain, + UnitTypeBlockChain, } // DefaultRepoUnits contains the default unit types @@ -87,6 +91,7 @@ var ( UnitTypeWiki, UnitTypeDatasets, UnitTypeCloudBrain, + UnitTypeBlockChain, } // NotAllowedDefaultRepoUnits contains units that can't be default @@ -268,6 +273,14 @@ var ( 6, } + UnitBlockChain = Unit{ + UnitTypeBlockChain, + "repo.blockchains", + "/blockchains", + "repo.blockchains.desc", + 7, + } + // Units contains all the units Units = map[UnitType]Unit{ UnitTypeCode: UnitCode, @@ -279,6 +292,7 @@ var ( UnitTypeExternalWiki: UnitExternalWiki, UnitTypeDatasets: UnitDataset, UnitTypeCloudBrain: UnitCloudBrain, + UnitTypeBlockChain: UnitBlockChain, } ) diff --git a/models/user.go b/models/user.go index e076949ec..4d282f477 100755 --- a/models/user.go +++ b/models/user.go @@ -174,8 +174,8 @@ type User struct { Token string `xorm:"VARCHAR(1024)"` //BlockChain - PublicKey string `xorm` - PrivateKey string `xorm` + PublicKey string `xorm:"INDEX"` + PrivateKey string `xorm:"INDEX"` } // SearchOrganizationsOptions options to filter organizations diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 5e5638db1..e34da18fa 100755 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -369,6 +369,7 @@ type CreateIssueForm struct { AssigneeID int64 Content string Files []string + Rewards int64 } // Validate validates the fields @@ -489,6 +490,7 @@ type MergePullRequestForm struct { MergeTitleField string MergeMessageField string ForceMerge *bool `json:"force_merge,omitempty"` + BlockChainAmount int } // Validate validates the fields diff --git a/modules/blockchain/resty.go b/modules/blockchain/resty.go index 47fe11ddb..4b5de68f3 100755 --- a/modules/blockchain/resty.go +++ b/modules/blockchain/resty.go @@ -2,6 +2,7 @@ package blockchain import ( "fmt" + "strconv" "code.gitea.io/gitea/modules/setting" "github.com/go-resty/resty/v2" @@ -13,11 +14,10 @@ var ( const ( UrlCreateAccount = "createAccount" - UrlGetBalance = "getBalance" - UrlNewRepo = "newRepo" - UrlContribute = "contribute" - - ActionCommit = "commit" + UrlGetBalance = "getBalance" + UrlNewRepo = "newRepo" + UrlContribute = "contribute" + UrlSetIssue = "setIssue" Success = 0 ) @@ -31,7 +31,7 @@ type CreateAccountResult struct { type GetBalanceResult struct { Code int `json:"code"` Msg string `json:"message"` - Payload map[string]interface{} `json:"data"` + Data string `json:"data"` } type NewRepoResult struct { @@ -41,9 +41,15 @@ type NewRepoResult struct { } type ContributeResult struct { - Code int `json:"code"` - Msg string `json:"message"` - Payload map[string]interface{} `json:"data"` + Code int `json:"code"` + Msg string `json:"message"` + //Payload map[string]interface{} `json:"data"` +} + +type SetIssueResult struct { + Code int `json:"code"` + Msg string `json:"message"` + //Data string `json:"data"` } func getRestyClient() *resty.Client { @@ -122,18 +128,18 @@ func GetBalance(contractAddress, contributor string) (*GetBalanceResult, error) return &result, nil } -func Contribute(contractAddress, contributor, action, commitId string, codeLine int) (*ContributeResult, error) { +func Contribute(contractAddress, contributor, commitId string, amount int64) (*ContributeResult, error) { client := getRestyClient() var result ContributeResult + strAmount := strconv.FormatInt(amount, 10) res, err := client.R(). SetHeader("Accept", "application/json"). SetQueryParams(map[string]string{ - "contractAddress": contractAddress, - "contributor": contributor, - "action": action, - "commitId": commitId, - "amount": string(codeLine), + "contractAddress" : contractAddress, + "contributor" : contributor, + "commitId": commitId, + "amount": strAmount, }). SetResult(&result). Get(setting.BlockChainHost + UrlContribute) @@ -148,3 +154,31 @@ func Contribute(contractAddress, contributor, action, commitId string, codeLine return &result, nil } + +func SetIssue(contractAddress, contributor string, issueId int64, amount int64) (*SetIssueResult, error) { + client := getRestyClient() + var result SetIssueResult + + strAmount := strconv.FormatInt(amount, 10) + strIssue := strconv.FormatInt(issueId, 10) + res, err := client.R(). + SetHeader("Accept", "application/json"). + SetQueryParams(map[string]string{ + "contractAddress" : contractAddress, + "contributor" : contributor, + "issueId": strIssue, + "amount": strAmount, + }). + SetResult(&result). + Get(setting.BlockChainHost + UrlSetIssue) + + if err != nil { + return nil, fmt.Errorf("resty SetIssue: %v", err) + } + + if result.Code != Success { + return &result, fmt.Errorf("SetIssue err: %s", res.String()) + } + + return &result, nil +} diff --git a/modules/context/repo.go b/modules/context/repo.go old mode 100644 new mode 100755 index bdd8cde5d..c6e5e8edd --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -820,5 +820,6 @@ func UnitTypes() macaron.Handler { ctx.Data["UnitTypeWiki"] = models.UnitTypeWiki ctx.Data["UnitTypeExternalWiki"] = models.UnitTypeExternalWiki ctx.Data["UnitTypeExternalTracker"] = models.UnitTypeExternalTracker + ctx.Data["UnitTypeBlockChain"] = models.UnitTypeBlockChain } } diff --git a/modules/timer/timer.go b/modules/timer/timer.go index a501234d1..58cc13084 100755 --- a/modules/timer/timer.go +++ b/modules/timer/timer.go @@ -12,16 +12,16 @@ func init() { spec := "*/10 * * * *" c.AddFunc(spec, repo.HandleUnDecompressAttachment) - //specCheckBlockChainUserSuccess := "*/10 * * * *" - //c.AddFunc(specCheckBlockChainUserSuccess, repo.HandleBlockChainUnSuccessUsers) + specCheckBlockChainUserSuccess := "*/10 * * * *" + c.AddFunc(specCheckBlockChainUserSuccess, repo.HandleBlockChainUnSuccessUsers) - //specCheckRepoBlockChainSuccess := "*/5 * * * *" - //c.AddFunc(specCheckRepoBlockChainSuccess, repo.HandleBlockChainUnSuccessRepos) + specCheckRepoBlockChainSuccess := "*/1 * * * *" + c.AddFunc(specCheckRepoBlockChainSuccess, repo.HandleBlockChainUnSuccessRepos) - //specCheckUnTransformedActions := "*/1 * * * *" - //c.AddFunc(specCheckUnTransformedActions, repo.HandleUnTransformedActions) + specCheckUnTransformedPRs := "*/1 * * * *" + c.AddFunc(specCheckUnTransformedPRs, repo.HandleBlockChainMergedPulls) - //specCheckBlockChainCommitSuccess := "*/3 * * * *" - //c.AddFunc(specCheckBlockChainCommitSuccess, repo.HandleBlockChainUnSuccessCommits) + specCheckBlockChainCommitSuccess := "*/3 * * * *" + c.AddFunc(specCheckBlockChainCommitSuccess, repo.HandleBlockChainUnSuccessCommits) c.Start() } diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index c2f37b976..8df65bd2a 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -268,7 +268,7 @@ twofa_passcode_incorrect=你的验证码不正确。如果你丢失了你的设 twofa_scratch_token_incorrect=你的验证口令不正确。 login_userpass=登录 login_openid=OpenID -login_cloudbrain=云脑用户登录 +login_cloudbrain=用户登录 oauth_signup_tab=注册帐号 oauth_signup_title=添加电子邮件和密码 (用于帐号恢复) oauth_signup_submit=完成账号 @@ -753,7 +753,10 @@ cloudbrain.new=新建任务 cloudbrain.desc=云脑功能 cloudbrain.cancel=取消 cloudbrain.commit_image=提交 -clone_cnt=次下载 +balance=余额 +balance.total_view=余额总览 +balance.available=可用余额: +balance.disable=不可用余额: template.items=模板选项 template.git_content=Git数据(默认分支) @@ -936,6 +939,7 @@ issues.filter_labels=筛选标签 issues.filter_reviewers=筛选审核者 issues.new=创建任务 issues.new.title_empty=标题不能为空 +issues.new.rewards_error=奖励金额错误:不能小于0,且不能大于自身余额 issues.new.labels=标签 issues.new.add_labels_title=添加标签 issues.new.no_label=未选择标签 diff --git a/routers/repo/blockchain.go b/routers/repo/blockchain.go index cb7e5a196..afba3bb98 100755 --- a/routers/repo/blockchain.go +++ b/routers/repo/blockchain.go @@ -1,14 +1,14 @@ package repo import ( - "code.gitea.io/gitea/modules/repository" - "encoding/json" - "strconv" - "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/blockchain" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "encoding/json" + "net/http" + "strconv" ) type BlockChainInitNotify struct { @@ -20,6 +20,29 @@ type BlockChainCommitNotify struct { CommitID string `json:"commitId"` TransactionHash string `json:"txHash"` } +const ( + tplBlockChainIndex base.TplName = "repo/blockchain/index" +) + +func BlockChainIndex(ctx *context.Context) { + repo := ctx.Repo.Repository + if repo.ContractAddress == "" || ctx.User.PublicKey == ""{ + log.Error("the repo(%d) or the user(%d) has not been initialized in block_chain", repo.RepoID, ctx.User.ID) + ctx.HTML(http.StatusInternalServerError, tplBlockChainIndex) + return + } + + res, err := blockchain.GetBalance(repo.ContractAddress, ctx.User.PublicKey) + if err != nil { + log.Error("GetBalance(%s) failed:%v", ctx.User.PublicKey, err) + ctx.HTML(http.StatusInternalServerError, tplBlockChainIndex) + return + } + + ctx.Data["balance"] = res.Data + ctx.Data["PageIsBlockChain"] = true + ctx.HTML(200, tplBlockChainIndex) +} func HandleBlockChainInitNotify(ctx *context.Context) { var req BlockChainInitNotify @@ -130,7 +153,6 @@ func HandleBlockChainUnSuccessRepos() { continue } strRepoID := strconv.FormatInt(repo.ID, 10) - log.Info(strRepoID) _, err = blockchain.NewRepo(strRepoID, repo.Owner.PublicKey, repo.Name) if err != nil { log.Error("blockchain.NewRepo(%s) failed:%v", strRepoID, err) @@ -148,7 +170,7 @@ func HandleBlockChainUnSuccessCommits() { } for _, block_chain := range blockChains { - _, err = blockchain.Contribute(block_chain.ContractAddress, block_chain.Contributor, blockchain.ActionCommit, block_chain.CommitID, int(block_chain.Amount)) + _, err = blockchain.Contribute(block_chain.ContractAddress, block_chain.Contributor, block_chain.CommitID, block_chain.Amount) if err != nil { log.Error("blockchain.Contribute(%s) failed:%v", block_chain.CommitID, err) } @@ -180,71 +202,89 @@ func HandleBlockChainUnSuccessUsers() { return } -func HandleUnTransformedActions() { - actions, err := models.GetUnTransformedActions() +func HandleBlockChainMergedPulls() { + prs, err := models.GetUnTransformedMergedPullRequests() if err != nil { - log.Error("GetUnTransformedActions failed:", err.Error()) + log.Error("GetUnTransformedMergedPullRequests failed:", err.Error()) return } - isTransformed := true + for _, pr := range prs { + _, err = models.GetBlockChainByPrID(pr.ID) + if err == nil { + log.Info("the pr(%s) has been transformed", pr.MergedCommitID) + continue + } - for _, action := range actions { - var content repository.PushCommits - err = json.Unmarshal([]byte(action.Content), &content) + err = pr.LoadIssue() if err != nil { - isTransformed = false - log.Error("json.Unmarshal action.Content(%s) failed:%v", action.Content, err) - break + log.Error("LoadIssue(%s) failed:%v", pr.MergedCommitID, err) + continue } - repo, err := models.GetRepositoryByID(action.RepoID) + poster, err := models.GetUserByID(pr.Issue.PosterID) if err != nil { - isTransformed = false - log.Error("GetRepositoryByID(%d) failed:%v", action.RepoID, err) - break + log.Error("GetUserByID(%s) failed:%v", pr.MergedCommitID, err) + continue + } + + if len(poster.PrivateKey) == 0 || len(poster.PublicKey) == 0 { + log.Error("the user has not been init in block_chain:", poster.Name) + continue } - if repo.ContractAddress == "" { - isTransformed = false + repo, err := models.GetRepositoryByID(pr.HeadRepoID) + if err != nil { + log.Error("GetUserByID(%s) failed:%v", pr.MergedCommitID, err) + continue + } + + if len(repo.ContractAddress) == 0 { log.Error("the repo(%s) has not been initialized in block_chain", repo.Name) - break + continue } - for _, commit := range content.Commits { - _, err = models.GetBlockChainByCommitID(commit.Sha1) - if err == nil { - log.Info("the commit(%s) has been transformed", commit.Sha1) - continue - } - - user, err := models.GetUserByName(commit.CommitterName) - if err != nil { - isTransformed = false - log.Error("GetUserByName(%s) failed:%v", commit.CommitterName, err) - break - } - - blockChain := models.BlockChain{ - CommitID: commit.Sha1, - Contributor: user.PublicKey, - ContractAddress: repo.ContractAddress, - Status: models.BlockChainCommitInit, - Amount: 1, - UserID: action.UserID, - RepoID: action.RepoID, - } - _, err = models.InsertBlockChain(&blockChain) - if err != nil { - isTransformed = false - log.Error("InsertBlockChain(%s) failed:%v", commit.Sha1, err) - break - } + blockChain := models.BlockChain{ + Contributor : poster.PublicKey, + PrID : pr.ID, + CommitID : pr.MergedCommitID, + ContractAddress : repo.ContractAddress, + Status : models.BlockChainCommitInit, + Amount : int64(pr.Amount), + UserID : poster.ID, + RepoID : pr.HeadRepoID, } + _, err = models.InsertBlockChain(&blockChain) + if err != nil { + log.Error("InsertBlockChain(%s) failed:%v", pr.MergedCommitID, err) + continue + } + + pr.IsTransformed = true + pr.UpdateCols("is_transformed") + _, err = blockchain.Contribute(repo.ContractAddress, poster.PublicKey, pr.MergedCommitID, int64(pr.Amount)) + if err != nil { + log.Error("Contribute(%s) failed:%v", pr.MergedCommitID, err) + } } - log.Info("", isTransformed) + return +} + +func HandleBlockChainUnSuccessIssues() { + issues, err := models.GetBlockChainUnSuccessCommits() + if err != nil { + log.Error("GetBlockChainUnSuccessIssues failed:", err.Error()) + return + } + + for _, issue := range issues { + _, err = blockchain.SetIssue(issue.ContractAddress, issue.Contributor, issue.ID, issue.Amount) + if err != nil { + log.Error("SetIssue(%s) failed:%v", issue.CommitID, err) + } + } return } diff --git a/routers/repo/issue.go b/routers/repo/issue.go old mode 100644 new mode 100755 index 1e8f1d81a..555cd065f --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -509,6 +509,21 @@ func NewIssue(ctx *context.Context) { ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(models.UnitTypeIssues) + /*if ctx.Repo.Repository.ContractAddress == "" || ctx.User.PublicKey == ""{ + log.Error("the repo(%d) or the user(%d) has not been initialized in block_chain", ctx.Repo.Repository.ID, ctx.User.ID) + ctx.HTML(http.StatusInternalServerError, tplIssueNew) + return + } + + res, err := blockchain.GetBalance(ctx.Repo.Repository.ContractAddress, ctx.User.PublicKey) + if err != nil { + log.Error("GetBalance(%s) failed:%v", ctx.User.PublicKey, err) + ctx.HTML(http.StatusInternalServerError, tplIssueNew) + return + } + + ctx.Data["balance"] = res.Data*/ + ctx.HTML(200, tplIssueNew) } @@ -637,6 +652,33 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) { Ref: form.Ref, } + /*if repo.ContractAddress == "" || ctx.User.PublicKey == ""{ + log.Error("the repo(%d) or the user(%d) has not been initialized in block_chain", issue.RepoID, ctx.User.ID) + ctx.HTML(http.StatusInternalServerError, tplIssueNew) + return + } + + res, err := blockchain.GetBalance(repo.ContractAddress, ctx.User.PublicKey) + if err != nil { + log.Error("GetBalance(%s) failed:%v", ctx.User.PublicKey, err) + ctx.HTML(http.StatusInternalServerError, tplIssueNew) + return + } + + balance, err := com.StrTo(res.Data).Int64() + if err != nil { + log.Error("balance(%s) convert failed:%v", res.Data, err) + ctx.HTML(http.StatusInternalServerError, tplIssueNew) + return + } + + if form.Rewards < 0 || form.Rewards > balance { + ctx.RenderWithErr(ctx.Tr("repo.issues.new.rewards_error"), tplIssueNew, form) + return + } + + issue.Amount = form.Rewards*/ + if err := issue_service.NewIssue(repo, issue, labelIDs, attachments, assigneeIDs); err != nil { if models.IsErrUserDoesNotHaveAccessToRepo(err) { ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error()) diff --git a/routers/repo/pull.go b/routers/repo/pull.go old mode 100644 new mode 100755 index a7af5bdb3..8841e4755 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -810,6 +810,14 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) { return } + if form.BlockChainAmount < int(models.PullRequestAmountZero) || form.BlockChainAmount > int(models.PullRequestAmountMax) { + log.Error("amount set error(0-300)") + ctx.RenderWithErr("amount set error(0-300)", tplIssueView, form) + return + } + + pr.Amount = form.BlockChainAmount + if err = pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil { if models.IsErrInvalidMergeStyle(err) { ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option")) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index cfb730490..8831e20a5 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -568,6 +568,8 @@ func RegisterRoutes(m *macaron.Macaron) { reqRepoDatasetWriter := context.RequireRepoWriter(models.UnitTypeDatasets) reqRepoCloudBrainReader := context.RequireRepoReader(models.UnitTypeCloudBrain) reqRepoCloudBrainWriter := context.RequireRepoWriter(models.UnitTypeCloudBrain) + //reqRepoBlockChainReader := context.RequireRepoReader(models.UnitTypeBlockChain) + //reqRepoBlockChainWriter := context.RequireRepoWriter(models.UnitTypeBlockChain) // ***** START: Organization ***** m.Group("/org", func() { @@ -911,6 +913,10 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) }, context.RepoRef()) + m.Group("/blockchain", func() { + m.Get("", repo.BlockChainIndex) + }, context.RepoRef()) + m.Group("/wiki", func() { m.Get("/?:page", repo.Wiki) m.Get("/_pages", repo.WikiPages) diff --git a/templates/repo/blockchain/index.tmpl b/templates/repo/blockchain/index.tmpl new file mode 100755 index 000000000..e62981e3f --- /dev/null +++ b/templates/repo/blockchain/index.tmpl @@ -0,0 +1,18 @@ +{{template "base/head" .}} +
+ {{template "repo/header" .}} +
+

+ {{.i18n.Tr "repo.balance.total_view"}} +

+ +
+
+ {{.i18n.Tr "repo.balance.available"}} + {{.balance}} +
+
+ +
+
+{{template "base/footer" .}} \ No newline at end of file diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 9c137d53a..6b6a066a9 100755 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -145,6 +145,11 @@ {{end}} + + {{svg "octicon-law" 16}} + {{.i18n.Tr "repo.balance"}} + + {{template "custom/extra_tabs" .}} {{if .Permission.IsAdmin}} @@ -158,4 +163,4 @@ {{end}}
- + \ No newline at end of file diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl old mode 100644 new mode 100755 index 682469a14..a35dacbce --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -188,7 +188,6 @@ {{end}}
#{{.Index}}
{{.Title | RenderEmoji}} - {{if .IsPull }} {{if (index $.CommitStatus .PullRequest.ID)}} {{template "repo/commit_status" (index $.CommitStatus .PullRequest.ID)}} diff --git a/templates/repo/issue/new_form.tmpl b/templates/repo/issue/new_form.tmpl old mode 100644 new mode 100755 index a42a4d9ad..2466dfdfa --- a/templates/repo/issue/new_form.tmpl +++ b/templates/repo/issue/new_form.tmpl @@ -1,182 +1,224 @@ -
- {{.CsrfTokenHtml}} - {{if .Flash}} -
- {{template "base/alert" .}} -
- {{end}} -
-
-
- - - -
-
- - {{if .PageIsComparePull}} -
{{.i18n.Tr "repo.pulls.title_wip_desc" (index .PullRequestWorkInProgressPrefixes 0| Escape) | Safe}}
- {{end}} -
- {{template "repo/issue/comment_tab" .}} -
- -
-
-
-
-
+ + + {{.CsrfTokenHtml}} + {{if .Flash}} +
+ {{template "base/alert" .}} +
+ {{end}} +
+
+
+ + + +
+
+ + + {{if .PageIsComparePull}} +
{{.i18n.Tr "repo.pulls.title_wip_desc" (index .PullRequestWorkInProgressPrefixes 0| Escape) | Safe}}
+ {{end}} +
-
-
- {{template "repo/issue/branch_selector_field" .}} + + - - -
- {{.i18n.Tr "repo.issues.new.no_label"}} - {{range .Labels}} - {{.Name | RenderEmoji}} - {{end}} - {{range .OrgLabels}} - {{.Name | RenderEmoji}} - {{end}} -
+ {{template "repo/issue/comment_tab" .}} +
+ +
+
+
+
+
-
+
+
+ {{template "repo/issue/branch_selector_field" .}} - - -
- {{.i18n.Tr "repo.issues.new.no_milestone"}} -
- {{if .Milestone}} - {{.Milestone.Name}} - {{end}} -
-
+ + +
+ {{.i18n.Tr "repo.issues.new.no_label"}} + {{range .Labels}} + {{.Name | RenderEmoji}} + {{end}} + {{range .OrgLabels}} + {{.Name | RenderEmoji}} + {{end}} +
-
+
- - -
- - {{.i18n.Tr "repo.issues.new.no_assignees"}} - - {{range .Assignees}} - -  {{.GetDisplayName}} - - {{end}} -
-
-
+ + +
+ {{.i18n.Tr "repo.issues.new.no_milestone"}} +
+ {{if .Milestone}} + {{.Milestone.Name}} + {{end}} +
+
+ +
+ + + +
+ + {{.i18n.Tr "repo.issues.new.no_assignees"}} + + {{range .Assignees}} + +  {{.GetDisplayName}} + + {{end}} +
+
+
+ + {{if .PageIsComparePull}} - + {{end}} - diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl old mode 100644 new mode 100755 index 3aee0773f..6e38a6f75 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -1,3 +1,9 @@ + {{if gt (len .PullReviewers) 0}}
@@ -58,6 +64,8 @@
{{end}} + +
{{end}} + + {{if .AllowMerge}} {{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} {{$approvers := .Issue.PullRequest.GetApprovers}} @@ -197,6 +207,21 @@