├── README.md ├── src ├── static │ ├── img │ │ ├── bg2.png │ │ ├── close.png │ │ ├── head.png │ │ ├── tx1.png │ │ ├── tx2.png │ │ ├── close2.png │ │ ├── search.png │ │ ├── gitee-icon.png │ │ ├── list-star.png │ │ ├── projectbg.png │ │ ├── github-icon.png │ │ ├── list-rocket.png │ │ ├── login-index.png │ │ ├── kcoin-log-big.png │ │ ├── kcoin-logo-blue.png │ │ └── kcoin-project-list-half-icon.png │ ├── js │ │ ├── capitalInjection.js │ │ ├── paging.js │ │ ├── EasePack.min.js │ │ ├── import.js │ │ └── helloweb.js │ └── css │ │ ├── homepage.css │ │ ├── loginJoin.css │ │ ├── platformAdmin.css │ │ ├── project.css │ │ └── personal.css ├── main.go ├── conf │ └── app.conf ├── controllers │ ├── platforminformation.go │ ├── projectFunding.go │ ├── logout.go │ ├── default.go │ ├── projectNotice.go │ ├── projectMemberWork.go │ ├── projectInfo.go │ ├── capitalInjection.go │ ├── projectMemberList.go │ ├── projectSetting.go │ ├── personalPage.go │ ├── homepage.go │ ├── authorize.go │ ├── import.go │ ├── ccSearchPage.go │ ├── personalProjects.go │ └── importHelper.go ├── views │ ├── footer.html │ ├── platformAdminTopNav.html │ ├── projectSetting.html │ ├── projectTopNav.html │ ├── projectNotice.html │ ├── projectMemberList.html │ ├── leftNav.html │ ├── platformInformation.html │ ├── projectInfo.html │ ├── ccSearchPage.html │ ├── import.tpl │ ├── homePage.tpl │ ├── projectMemberWork.html │ ├── capitalInjection.html │ ├── join.html │ ├── login.html │ ├── projectFunding.html │ ├── personalProjects.html │ └── personalPage.html ├── models │ ├── ccInject.go │ ├── getCsNum.go │ ├── getCommiters.go │ ├── searchCcAndCs.go │ ├── getGithubRepos.go │ ├── getAllJoinedProjects.go │ ├── models.go │ ├── k_project.go │ ├── sendEmailToPotentialUsers.go │ └── k_user.go ├── service │ ├── URLUtil.go │ ├── get_issue_info.go │ └── github_helper.go ├── routers │ └── router.go └── tests │ └── models_test.go ├── user-story ├── 1901210384.md ├── 1900022750.md ├── 1901210560.md ├── 1901210678.md ├── 1901210581.md ├── 1901210466.md ├── 1901210749.md ├── 1901210645.md ├── 1901210408.md └── 1901210377.md ├── .gitignore ├── go.mod ├── user-story.md ├── database └── create.sql └── go.sum /README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/static/img/bg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/bg2.png -------------------------------------------------------------------------------- /src/static/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/close.png -------------------------------------------------------------------------------- /src/static/img/head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/head.png -------------------------------------------------------------------------------- /src/static/img/tx1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/tx1.png -------------------------------------------------------------------------------- /src/static/img/tx2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/tx2.png -------------------------------------------------------------------------------- /src/static/img/close2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/close2.png -------------------------------------------------------------------------------- /src/static/img/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/search.png -------------------------------------------------------------------------------- /src/static/img/gitee-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/gitee-icon.png -------------------------------------------------------------------------------- /src/static/img/list-star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/list-star.png -------------------------------------------------------------------------------- /src/static/img/projectbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/projectbg.png -------------------------------------------------------------------------------- /src/static/img/github-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/github-icon.png -------------------------------------------------------------------------------- /src/static/img/list-rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/list-rocket.png -------------------------------------------------------------------------------- /src/static/img/login-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/login-index.png -------------------------------------------------------------------------------- /src/static/img/kcoin-log-big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/kcoin-log-big.png -------------------------------------------------------------------------------- /src/static/img/kcoin-logo-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/kcoin-logo-blue.png -------------------------------------------------------------------------------- /src/static/img/kcoin-project-list-half-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OS-ABC/Kcoin-Golang/HEAD/src/static/img/kcoin-project-list-half-icon.png -------------------------------------------------------------------------------- /user-story/1901210384.md: -------------------------------------------------------------------------------- 1 | #用户故事 2 | 3 | 作为一个Kcoin社区使用者,我希望获得更多的收益,但是我个人精力有限,因此我希望能够通过推广社区来获得更多收益 4 | 5 | 作为一个平台用户(无论什么身份),我希望我在平台中的虚拟财产更加安全,因此我希望可以拥有自己独立的支付密码 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #add ignore files 2 | src/src 3 | *.exe 4 | *.exe~ 5 | src/.idea/ 6 | src/.vscode/ 7 | .idea/ 8 | src/__debug_bin 9 | 10 | # Mac OS 11 | **/.DS_Store -------------------------------------------------------------------------------- /user-story/1900022750.md: -------------------------------------------------------------------------------- 1 | # User Story 2 | 3 | 1. 作为一名想为开源项目做贡献的人,我希望使用项目搜索功能,以便快速定位到自己感兴趣的项目。 4 | 5 | 2. 作为一名开源项目的管理者,我希望使用网站通知功能,以便我在登录时就可以收到项目的信息动态,更好地管理项目。 6 | 7 | -------------------------------------------------------------------------------- /user-story/1901210560.md: -------------------------------------------------------------------------------- 1 | ## 用户故事 2 | 3 | 作为一名投资者,我希望看到项目被哪些公司或机构使用,这样可以让我更好地决策,到底要不要给这个项目投资、要投资多少。 4 | 5 | 6 | 7 | 作为一名开发者,我希望可以推广我的项目,比如把它们分享到社交媒体,这样可以使更多同行看到、加入它们,提高它们的活跃度。 -------------------------------------------------------------------------------- /src/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "Kcoin-Golang/src/routers" 5 | 6 | "github.com/astaxie/beego" 7 | ) 8 | 9 | func main() { 10 | 11 | beego.Run() 12 | } 13 | -------------------------------------------------------------------------------- /user-story/1901210678.md: -------------------------------------------------------------------------------- 1 | # User Story 2 | 3 | 1. 作为一名想为开源项目做贡献的人,我希望能够被智能推荐,避开人数过多做贡献得到CS收益过低的项目,找到符合自己技术背景并且CS收益高的项目。 4 | 5 | 2. 作为一名开源项目的管理者,我希望使用使用项目主页的图标及超链接,更好地观察项目成员的在不同项目中的CS贡献情况。 6 | -------------------------------------------------------------------------------- /user-story/1901210581.md: -------------------------------------------------------------------------------- 1 | # 用户故事 2 | 3 | 1. 作为一名做出卓越贡献的贡献者,贾组长希望能有项目贡献与总体贡献排行榜,以便于扩大用户的社区影响力。 4 | 5 | 2. 作为一名新贡献者,我想要根据新用户问卷推荐最佳匹配项目,以便我快速上手熟悉最合适项目。 6 | 7 | 3. 作为一名项目管理者,我想要高度贡献者列表与具体工作列表,以便于增强对项目掌控。 8 | 9 | -------------------------------------------------------------------------------- /user-story/1901210466.md: -------------------------------------------------------------------------------- 1 | # User Story 2 | 1. 作为一个游客,我想在没有登录的情况下,可以以游客的身份浏览该平台,看看平台里都哪些项目,再决定要不要注册一个账号或通过第三方授权登录该平台。 3 | 2. 作为一个想结交优秀朋友的普通用户,我希望有渠道能获得全站范围内cs数量排名前100的项目贡献者,并能够对他们添加关注。 4 | 3. 对于第一次登陆该平台的新用户,可以考虑布置几个“新手任务”给他们完成,便于快速熟悉该平台。完成“新手任务”后,即可奖励一些cs给新用户作为鼓励。 -------------------------------------------------------------------------------- /user-story/1901210749.md: -------------------------------------------------------------------------------- 1 | # 用户故事 2 | 3 | 1. 我是一名开源项目的管理者,我希望Kcoin能把我的开源项目智能推荐给参与了相似项目的人,这样能吸引更多人来我的项目中贡献代码。 4 | 2. 我是一名想在开源项目中做贡献的用户,我希望Kcoin能展示项目在Github上的star和committer数量等信息,以便我判断一个项目是否活跃且值得加入。 5 | 3. 我是一名小白用户,我希望Kcoin网站中能有一份介绍Kcoin的名词和操作的入门文档,这样我就可以快速上手了。 6 | 7 | -------------------------------------------------------------------------------- /user-story/1901210645.md: -------------------------------------------------------------------------------- 1 | # 用户故事 2 | 1. 作为一个开源项目贡献者, 我不一定知道这个项目被托管到KCoin上, 因此当这个项目被托管到KCoin时, 我想要被正确通知. 当一个新的Contributor参与到项目时, 也需要被正确通知这个项目的托管情况. 3 | 2. 我需要知道个人所有CC的情况, 以及CC究竟能兑换什么物品, 即需要一个兑换商店. 4 | 3. 作为KCoin小白, 我需要知道KCoin有什么优势, 为什么要使用KCoin, 如何使用KCoin, 即需要一个指导文档. -------------------------------------------------------------------------------- /user-story/1901210408.md: -------------------------------------------------------------------------------- 1 | # 用户故事 2 | 1. 我是一名项目管理者,我希望通过项目url能将我的项目导入到平台 3 | 2. 我是一名项目管理者,我希望能够通过设置规则,制定我的项目工作量和CS的兑换规则 4 | 3. 我是一名普通用户,我希望能够通过设置规则,在基金会投资CC时,按照工作量公平分配 5 | 4. 我是一名普通用户,我希望通过向开源社区提交代码,获得相应的CS 6 | 5. 我是一名普通用户,我希望通过oAuth邮箱登陆到个人中心。 7 | 6. 我是一名项目管理者,我希望查看项目总体CC和项目贡献量动态 -------------------------------------------------------------------------------- /user-story/1901210377.md: -------------------------------------------------------------------------------- 1 | # User story 2 | 3 | 1. 作为一个项目管理者,我想要在登录系统后收到项目参与者的活动消息,以便于我了解项目走向和项目参与者的动态。 4 | 2. 作为一个普通用户,我想要在网站上看到如何使用这个系统的向导信息,以便于我能够快速学会使用这个系统。 5 | 3. 作为一个项目投资人,我想要看到某个项目根据时间线展示的活跃图,以便于我能够找到有潜力的可以进行投资的项目。 6 | 4. 作为一个项目参与者,我想要在网站上了解到关于CS或CC的具体描述信息,以便于我明确对项目做出贡献后可以获取什么回报。 7 | 8 | -------------------------------------------------------------------------------- /src/conf/app.conf: -------------------------------------------------------------------------------- 1 | appname = Kcoin-Golang 2 | httpport = 8080 3 | runmode = dev 4 | sessionon = true 5 | #这里设置oauth app的client id和client secret 6 | client_id = "c698bd09d35414343da4" 7 | client_secret ="e680c1f3ae01fab2175efa4b3366cc43d7ca36ac" 8 | secret_token="0123456789" 9 | #允許接收post請求的request body 10 | copyrequestbody = true -------------------------------------------------------------------------------- /src/controllers/platforminformation.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | _ "Kcoin-Golang/src/models" 5 | 6 | "github.com/astaxie/beego" 7 | ) 8 | 9 | type PlatformInformationController struct { 10 | beego.Controller 11 | } 12 | 13 | func (c *PlatformInformationController) Get() { 14 | c.TplName = "platformInformation.html" //该controller对应的页面 15 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module Kcoin-Golang 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/PuerkitoBio/goquery v1.5.1 7 | github.com/astaxie/beego v1.12.0 8 | github.com/lib/pq v1.2.0 9 | github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect 10 | github.com/smartystreets/goconvey v1.6.4 // indirect 11 | google.golang.org/appengine v1.6.5 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /src/controllers/projectFunding.go: -------------------------------------------------------------------------------- 1 | // TODO Project相关的controller可以全部放到这个文件下, 即这个文件有若干Controller. 2 | package controllers 3 | 4 | import ( 5 | _ "Kcoin-Golang/src/models" 6 | 7 | "github.com/astaxie/beego" 8 | ) 9 | 10 | type ProjectFundingController struct { 11 | beego.Controller 12 | } 13 | 14 | func (c *ProjectFundingController) Get() { 15 | c.TplName = "projectFunding.html" //该controller对应的页面 16 | } 17 | -------------------------------------------------------------------------------- /src/controllers/logout.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | _ "Kcoin-Golang/src/models" 5 | "fmt" 6 | "github.com/astaxie/beego" 7 | ) 8 | 9 | type LogOutController struct { 10 | beego.Controller 11 | } 12 | 13 | func (c *LogOutController) Get() { 14 | 15 | c.Ctx.SetCookie("userName", "", 100) 16 | c.Ctx.SetCookie("headShotUrl", "", 100) 17 | c.Ctx.SetCookie("status", string('0'), 100) 18 | fmt.Println("congrat,his is log out ") 19 | c.Redirect("/homepage", 302) 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/views/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/controllers/default.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | ) 6 | 7 | type MainController struct { 8 | beego.Controller 9 | } 10 | 11 | type LoginController struct { 12 | beego.Controller 13 | } 14 | 15 | type JoinController struct { 16 | beego.Controller 17 | } 18 | 19 | func (c *MainController) Get() { 20 | c.Data["Website"] = "beego.me" 21 | c.Data["Email"] = "astaxie@gmail.com" 22 | c.TplName = "index.tpl" 23 | } 24 | 25 | func (c *LoginController) Get() { 26 | c.TplName = "login.html" 27 | } 28 | 29 | func (c *JoinController) Get() { 30 | c.TplName = "join.html" 31 | } 32 | -------------------------------------------------------------------------------- /src/static/js/capitalInjection.js: -------------------------------------------------------------------------------- 1 | function showPopup(){ 2 | // var page = document.getElementById("injection"); 3 | // page.style.display="block"; 4 | // var button = document.getElementById("commit"); 5 | // button.innerHTML="确认"; 6 | var popUp = document.getElementById("injection"); 7 | popUp.style.position= "absolute"; 8 | popUp.style.zIndex="100"; 9 | popUp.style.width = "100%"; 10 | popUp.style.height = "100%"; 11 | popUp.style.visibility = "visible"; 12 | 13 | } 14 | 15 | function hidePopup(){ 16 | var popUp = document.getElementById("injection"); 17 | popUp.style.visibility = "hidden"; 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/models/ccInject.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "fmt" 5 | "github.com/astaxie/beego/orm" 6 | ) 7 | 8 | func CCInject(donatorId int, projId int, cc float64, dtype int) error { 9 | o := orm.NewOrm() 10 | err := o.Using("default") 11 | if err != nil { 12 | return fmt.Errorf("database connection error:"+err.Error()) 13 | } 14 | SQLQuery := `INSERT INTO "k_cc_donate_record" (donate_from, donate_into, donate_cc, donate_type, donate_time) 15 | VALUES (?, ?, ?, ?, "CURRENT_TIMESTAMP(0)")` 16 | _, err = o.Raw(SQLQuery, donatorId, projId, cc, dtype).Exec() 17 | if err != nil { 18 | return fmt.Errorf("database insert error: "+err.Error()) 19 | } 20 | err = nil 21 | return err 22 | } 23 | -------------------------------------------------------------------------------- /src/models/getCsNum.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/astaxie/beego/orm" 7 | ) 8 | 9 | func GetCsNum(github_id string) int { 10 | 11 | //db, err := sql.Open("postgres", "user=sspkukcoin password=kcoin2019 dbname=postgres host=114.115.133.140 port=5432 sslmode=disable") 12 | 13 | o := orm.NewOrm() 14 | _ = o.Using("default") 15 | 16 | querySql := `select user_cs from "k_user_in_project" where user_id in (select k_user_id from "k_user" where github_id = ?)` 17 | var maps []orm.Params 18 | _, err := o.Raw(querySql, github_id).Values(&maps) 19 | checkErr(err) 20 | var user_cs string 21 | for _, term := range maps { 22 | user_cs = term["user_cs"].(string) 23 | } 24 | res, _ := strconv.Atoi(user_cs) 25 | return res 26 | } 27 | 28 | func checkErr(err error) { 29 | if err != nil { 30 | panic(err) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/models/getCommiters.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | //api:https://api.github.com/repos/OS-ABC/Kcoin-Golang/commits 4 | 5 | import ( 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | ) 10 | 11 | // TODO 该函数尚未完全完成, 需要完成获取某个项目的所有commiter信息 12 | //验证是否是项目commiter的接口,参数为项目名称和用户名称 13 | func checkAutho(userName string, programName string) string { 14 | //请求:获取此项目的commiter信息 15 | var url_1 string = "https://api.github.com/repos/" + userName + "/" + programName + "/" + "commits" 16 | client := &http.Client{} 17 | response, _ := client.Get(url_1) 18 | defer response.Body.Close() 19 | body, err_1 := ioutil.ReadAll(response.Body) 20 | if err_1 != nil { 21 | panic(err_1) 22 | } 23 | 24 | fmt.Println(string(body)) 25 | return string(body) 26 | } 27 | 28 | //使用实例: 29 | //func main() string{ 30 | // var info string=checkAutho("PHP-is-Best","Kcoin-Golang") 31 | // fmt.Println(info) 32 | // return info 33 | //} 34 | -------------------------------------------------------------------------------- /src/views/platformAdminTopNav.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kcoin 6 | 7 | 8 | 9 |
10 | 11 | 12 |
KCOIN
13 |
14 |
15 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /src/views/projectSetting.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | projectsetting 6 | 7 | 8 | 9 | 10 | {{template "./projectTopNav.html" .}} 11 | 14 |
15 |
16 | 1.填写项目名称 17 | 18 | 2. 填写项目描述 19 | 20 | 3.上传项目封面(选填,但只能添加不大于2M的图片) 21 | 22 | 23 |
24 |
25 | 26 | 27 | {{template "./footer.html" .}} 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/views/projectTopNav.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kcoin 6 | 7 | 8 | 9 |
10 | 11 | 12 |
KCOIN
13 |
14 |
15 | 25 | 26 | -------------------------------------------------------------------------------- /src/controllers/projectNotice.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | _ "Kcoin-Golang/src/models" 5 | "Kcoin-Golang/src/service" 6 | 7 | "github.com/astaxie/beego" 8 | ) 9 | 10 | type ProjectNoticeController struct { 11 | beego.Controller 12 | } 13 | 14 | func (c *ProjectNoticeController) Get() { 15 | id := c.Ctx.Input.Param(":id") 16 | 17 | c.Data["id"] = id 18 | 19 | fakeURL := "https://github.com/Darkone0/weatherForcast" 20 | 21 | // starNum := models.GetStarNum(fakeURL) 22 | // contributorsNum := models.GetContributorNum(fakeURL) 23 | starNum := c.GetSession(id + "starNum") 24 | if starNum == nil { 25 | starNum = service.GetStarNum(fakeURL) 26 | c.SetSession(id+"starNum", starNum) 27 | } 28 | 29 | contributorsNum := c.GetSession(id + "contributorsNum") 30 | if contributorsNum == nil { 31 | contributorsNum = service.GetContributorNum(fakeURL) 32 | c.SetSession(id+"contributorsNum", contributorsNum) 33 | } 34 | 35 | c.Data["starNum"] = starNum 36 | c.Data["contributorsNum"] = contributorsNum 37 | c.TplName = "projectNotice.html" //该controller对应的页面 38 | } 39 | -------------------------------------------------------------------------------- /src/views/projectNotice.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 项目信息 5 | 6 | 7 | 8 | 9 | 10 | {{template "./projectTopNav.html" .}} 11 | 12 | 15 | 16 |
17 | 28 |
29 | 30 | {{template "./footer.html" .}} 31 | -------------------------------------------------------------------------------- /src/controllers/projectMemberWork.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | _ "Kcoin-Golang/src/models" 5 | "Kcoin-Golang/src/service" 6 | 7 | "github.com/astaxie/beego" 8 | ) 9 | 10 | type ProjectMemberWorkController struct { 11 | beego.Controller 12 | } 13 | 14 | func (c *ProjectMemberWorkController) Get() { 15 | id := c.Ctx.Input.Param(":id") 16 | c.Data["id"] = id 17 | 18 | fakeURL := "https://github.com/Darkone0/weatherForcast" 19 | 20 | // starNum := models.GetStarNum(fakeURL) 21 | // contributorsNum := models.GetContributorNum(fakeURL) 22 | starNum := c.GetSession(id + "starNum") 23 | if starNum == nil { 24 | starNum = service.GetStarNum(fakeURL) 25 | c.SetSession(id+"starNum", starNum) 26 | c.Ctx.SetCookie(id+"starNum", starNum.(string)) 27 | } 28 | 29 | contributorsNum := c.GetSession(id + "contributorsNum") 30 | if contributorsNum == nil { 31 | contributorsNum = service.GetContributorNum(fakeURL) 32 | c.SetSession(id+"contributorsNum", contributorsNum) 33 | } 34 | 35 | c.Data["starNum"] = starNum 36 | c.Data["contributorsNum"] = contributorsNum 37 | c.TplName = "projectMemberWork.html" //该controller对应的页面 38 | } 39 | -------------------------------------------------------------------------------- /src/views/projectMemberList.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 项目信息 5 | 6 | 7 | 8 | 9 | {{template "./projectTopNav.html" .}} 10 | 11 | 14 | 15 |
16 |
17 |
18 | 查看更多 19 |
20 |
21 |
22 | {{range.membersInfo}} 23 |
24 | 25 |
26 |
27 |

用户名:{{.UserName}}

28 |

贡献度:1 收益:1

29 |
30 | {{end}} 31 |
32 |
33 | {{template "./footer.html" .}} 34 | -------------------------------------------------------------------------------- /src/controllers/projectInfo.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | "Kcoin-Golang/src/service" 6 | 7 | "github.com/astaxie/beego" 8 | ) 9 | 10 | type ProjectInfoController struct { 11 | beego.Controller 12 | } 13 | 14 | func (c *ProjectInfoController) Get() { 15 | //session获取id 16 | 17 | id := c.Ctx.Input.Param(":id") 18 | c.Data["id"] = id 19 | fakeURL := "https://github.com/Darkone0/weatherForcast" 20 | 21 | // starNum := models.GetStarNum(fakeURL) 22 | // contributorsNum := models.GetContributorNum(fakeURL) 23 | //这里的session都没有对不同项目进行区分,后续应当还需要更改 24 | starNum := c.GetSession(id + "starNum") 25 | if starNum == nil { 26 | starNum = service.GetStarNum(fakeURL) 27 | c.SetSession(id+"starNum", starNum) 28 | } 29 | 30 | contributorsNum := c.GetSession(id + "contributorsNum") 31 | if contributorsNum == nil { 32 | contributorsNum = service.GetContributorNum(fakeURL) 33 | c.SetSession(id+"contributorsNum", contributorsNum) 34 | } 35 | projectCC, _ := models.GetProjectsCC(id) 36 | c.Data["projectCC"] = projectCC 37 | c.Data["starNum"] = starNum 38 | c.Data["contributorsNum"] = contributorsNum 39 | c.TplName = "projectInfo.html" 40 | } 41 | -------------------------------------------------------------------------------- /src/service/URLUtil.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strings" 7 | ) 8 | 9 | func ParseGithubHTTPSUrl(url string) (userName string, userRepo string, err error) { 10 | splitedUrl := strings.Split(url, "/") 11 | if len(splitedUrl) != 5 { 12 | return "", "", fmt.Errorf("invalid url") 13 | } 14 | userName = splitedUrl[3] 15 | userRepo = strings.Split(splitedUrl[4], ".")[0] //处理url最后可能出现的.git 16 | return userName, userRepo, nil 17 | } 18 | 19 | //查询项目url是否合法,且判断用户是否有权限导入 20 | func CheckGithubRepoUrl(githubName, url string) error { 21 | _, repoName, err := ParseGithubHTTPSUrl(url) 22 | //TODO:err处理等待解析函数pr合并后更新 23 | if err != nil { 24 | return err 25 | } 26 | //info := GithubUser[userId] 27 | //userName := info.GithubName 28 | apiUrl := "https://api.github.com/repos/" + githubName + "/" + repoName 29 | resp, err := http.Get(apiUrl) 30 | if err != nil { 31 | return err 32 | } 33 | if resp.StatusCode != 200 { 34 | if resp.StatusCode == 404 { 35 | //fmr.Errorf()可直接返回error类型,参数为error.Error()返回值 36 | return fmt.Errorf("this repo Url is not valid") 37 | } else { 38 | return fmt.Errorf("err %d", resp.StatusCode) 39 | } 40 | } 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /src/controllers/capitalInjection.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/astaxie/beego" 8 | ) 9 | 10 | type CapitalInjectionController struct { 11 | beego.Controller 12 | } 13 | func (c *CapitalInjectionController) Get(){ 14 | //从cookie中取出状态 15 | isLogin :=c.Ctx.GetCookie("status") 16 | 17 | //把Json字符串中的数据解析到结构体中 18 | var proj models.ProjectInfo 19 | projectBuf , _ := models.GetAllProjectsInfo() 20 | err := json.Unmarshal([]byte(projectBuf),&proj) 21 | if err != nil { 22 | fmt.Println("err=", err) 23 | //return 24 | } 25 | 26 | //把结构体传到模板当中 27 | c.Data["Projects"] = proj 28 | 29 | //判断当前登录状态 30 | if isLogin == "1"{ 31 | c.Data["isLogin"] = true 32 | user := models.UserInfo{Data:&models.UserData{}}//user中存放着json解析后获得的数据。 33 | user.Data.UserName = c.Ctx.GetCookie("userName") 34 | user.Data.HeadShotUrl = c.Ctx.GetCookie("headShotUrl") 35 | c.Data["user"] = user 36 | } else { 37 | c.Data["isLogin"] = false 38 | c.Ctx.SetCookie("userName","",100) 39 | c.Ctx.SetCookie("headShotUrl","",100) 40 | c.Ctx.SetCookie("status", string('0'),100) 41 | c.Ctx.SetCookie("lastUri",c.Ctx.Request.RequestURI) 42 | } 43 | 44 | //设置Get方法对应展示的模板 45 | c.TplName = "capitalInjection.html" 46 | } -------------------------------------------------------------------------------- /src/controllers/projectMemberList.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | _ "Kcoin-Golang/src/models" 6 | "Kcoin-Golang/src/service" 7 | 8 | "github.com/astaxie/beego" 9 | ) 10 | 11 | type ProjectMemberListController struct { 12 | beego.Controller 13 | } 14 | 15 | func (c *ProjectMemberListController) Get() { 16 | id := c.Ctx.Input.Param(":id") 17 | c.Data["id"] = id 18 | //解决了session造成的bug后,通过读取项目id返回所有项目的信息 19 | membersInfo, _ := models.GetMembersInfoByProjectName(id) 20 | c.Data["membersInfo"] = membersInfo 21 | 22 | fakeURL := "https://github.com/Darkone0/weatherForcast" 23 | 24 | // starNum := models.GetStarNum(fakeURL) 25 | // contributorsNum := models.GetContributorNum(fakeURL) 26 | starNum := c.GetSession(id + "starNum") 27 | if starNum == nil { 28 | starNum = service.GetStarNum(fakeURL) 29 | c.SetSession(id+"starNum", starNum) 30 | } 31 | 32 | contributorsNum := c.GetSession(id + "contributorsNum") 33 | if contributorsNum == nil { 34 | contributorsNum = service.GetContributorNum(fakeURL) 35 | c.SetSession(id+"contributorsNum", contributorsNum) 36 | } 37 | 38 | c.Data["starNum"] = starNum 39 | c.Data["contributorsNum"] = contributorsNum 40 | 41 | c.TplName = "projectMemberList.html" //该controller对应的页面 42 | } 43 | -------------------------------------------------------------------------------- /src/controllers/projectSetting.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | _ "Kcoin-Golang/src/models" 5 | "Kcoin-Golang/src/service" 6 | 7 | "github.com/astaxie/beego" 8 | ) 9 | 10 | type ProjectSettingController struct { 11 | beego.Controller 12 | } 13 | 14 | func (c *ProjectSettingController) Get() { 15 | id := c.Ctx.Input.Param(":id") 16 | 17 | c.Data["id"] = id 18 | 19 | fakeURL := "https://github.com/Darkone0/weatherForcast" 20 | 21 | // starNum := models.GetStarNum(fakeURL) 22 | // contributorsNum := models.GetContributorNum(fakeURL) 23 | starNum := c.GetSession(id + "starNum") 24 | if starNum == nil { 25 | starNum = service.GetStarNum(fakeURL) 26 | c.SetSession(id+"starNum", starNum) 27 | } 28 | 29 | contributorsNum := c.GetSession(id + "contributorsNum") 30 | if contributorsNum == nil { 31 | contributorsNum = service.GetContributorNum(fakeURL) 32 | c.SetSession(id+"contributorsNum", contributorsNum) 33 | } 34 | 35 | c.Data["starNum"] = starNum 36 | c.Data["contributorsNum"] = contributorsNum 37 | c.TplName = "projectSetting.html" //该controller对应的页面 38 | 39 | //session获取textfiled 40 | textfield := c.GetSession("TextField") 41 | if textfield != nil { 42 | c.Data["TextField"] = textfield 43 | } else { 44 | c.Data["TextField"] = "不超过200字符" 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/views/leftNav.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 个人中心 5 | 6 | 7 | 8 | 14 |
15 | 16 |
17 | {{.user.Data.UserName}} 18 |
19 |
20 | 29 |
30 | 31 | -------------------------------------------------------------------------------- /src/views/platformInformation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 平台信息 6 | 7 | 8 | 9 | 10 | {{template "./platformAdminTopNav.html" .}} 11 | 14 | 15 |
16 |
17 |
18 |
平台拥有的CC数
19 |
CC记录
20 |
21 |

日期

变化

总数

22 |

11.23

+1000

1000

23 |

11.25

+2000

3000

24 |
25 |
26 |
27 |
28 |
托管在平台的项目总数
29 |
30 |
项目记录
31 |
32 |

日期

变化

总数

33 |

11.23

+2

2

34 |

11.25

+1

3

35 |
36 |
37 | {{template "./footer.html" .}} 38 | 39 | -------------------------------------------------------------------------------- /src/models/searchCcAndCs.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | // "encoding/json" 5 | _ "encoding/json" 6 | "fmt" 7 | 8 | "github.com/astaxie/beego/orm" 9 | ) 10 | 11 | func GetCcAndCsQuery(userId int, projectId int) ([]orm.Params, error) { 12 | o := orm.NewOrm() 13 | _ = o.Using("default") 14 | SQLQuery := getQuery() 15 | var maps []orm.Params 16 | if _, err := o.Raw(SQLQuery, userId, projectId).Values(&maps); err != nil { 17 | fmt.Println(err.Error()) 18 | return nil, err 19 | } 20 | 21 | if len(maps) == 0 { 22 | return nil, new(noResultErr) 23 | } 24 | return maps, nil 25 | } 26 | 27 | func getQuery() string { 28 | return `select user_cs, b.user_cc from "k_user_in_project" a, "k_user" b where a.user_id=? and a.project_id=? and a.user_id = b.user_id` 29 | } 30 | 31 | // 实现personalPage控制器中的查询CC余额 32 | func GetPersonalRemainingCc(userName string) (float64, error) { 33 | o := orm.NewOrm() 34 | _ = o.Using("default") 35 | 36 | type UsrCC struct { 37 | User_name string 38 | User_cc float64 39 | } 40 | var userCc UsrCC 41 | 42 | /**将取回的用户名和CC余额赋值给结构体userCc; 如有错误,则赋值给err1 43 | ***结构体中属性名需要与数据库中对应字段相同,且首字母大写*/ 44 | ccQuery := `SELECT user_name, user_cc FROM "k_user" WHERE user_name=?` 45 | err1 := o.Raw(ccQuery, userName).QueryRow(&userCc) 46 | if err1 != nil { 47 | fmt.Println(err1.Error()) 48 | return -1.0, err1 49 | } 50 | 51 | return userCc.User_cc, nil 52 | 53 | } -------------------------------------------------------------------------------- /src/views/projectInfo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 项目信息 6 | 7 | 8 | 9 | 10 | 11 | {{template "./projectTopNav.html" .}} 12 | 15 | 16 |
17 |
18 |
19 |
KCoin 总值
20 |
{{.projectCC}}
21 |
22 |
发放记录
23 |
24 |
25 |
26 |
Token 总值
27 |
0
28 |
29 |
发放记录
30 |
31 |
32 |
33 |
项目贡献度评定规则
34 |
35 |
36 |
37 | 38 | {{template "./footer.html" .}} 39 | 40 | -------------------------------------------------------------------------------- /src/models/getGithubRepos.go: -------------------------------------------------------------------------------- 1 | // TODO 该文件并入service层的github_helper.go中, 并删除main函数, 改为测试覆盖. 2 | package models 3 | 4 | import ( 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | ) 10 | 11 | type GithubRepos []struct { 12 | Name string `json:"name"` 13 | Url string `json:"html_url"` 14 | } 15 | 16 | //type ReposInfo struct { 17 | // ErrorCode string `json:"error_code"` 18 | // Data GithubRepos `json:"data"` 19 | //} 20 | //获取一个用户在github上所有公开的repository,返回json 21 | func GetGithubRepos(user string) (string, error) { 22 | //var reposInfo ReposInfo 23 | //reposInfo.ErrorCode = "default Error" 24 | var url string = "https://api.github.com/users/" + user + "/repos" 25 | 26 | client := &http.Client{} 27 | response, _ := client.Get(url) 28 | defer response.Body.Close() 29 | body, err := ioutil.ReadAll(response.Body) 30 | if err != nil { 31 | panic(err) 32 | } 33 | var repos GithubRepos 34 | var projects ProjectInfo 35 | err1 := json.Unmarshal([]byte(body), &repos) 36 | if err1 != nil { 37 | panic(err1) 38 | } 39 | for i := range repos { 40 | p := &Project{} 41 | p.ProjectUrl = repos[i].Url 42 | p.ProjectName = repos[i].Name 43 | projects.Data = append(projects.Data, p) 44 | } 45 | //reposInfo.ErrorCode = "0" 46 | //reposInfo.Data = repos 47 | //res,err2 := json.Marshal(&reposInfo) 48 | res, err2 := json.Marshal(&projects) 49 | if err2 != nil { 50 | panic(err2) 51 | } 52 | return string(res), nil 53 | } 54 | 55 | //测试输出 56 | func main() { 57 | fmt.Println(GetGithubRepos("Darkone0")) 58 | } 59 | -------------------------------------------------------------------------------- /src/routers/router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "Kcoin-Golang/src/controllers" 5 | 6 | "github.com/astaxie/beego" 7 | ) 8 | 9 | func init() { 10 | beego.Router("/", &controllers.MainController{}) 11 | beego.Router("/homepage", &controllers.HomePageController{}) 12 | beego.Router("/logout", &controllers.LogOutController{}) 13 | beego.Router("/personalpage", &controllers.PersonalPageController{}) 14 | beego.Router("/login", &controllers.LoginController{}) 15 | beego.Router("/join", &controllers.JoinController{}) 16 | beego.Router("/autho", &controllers.AuthoController{}) 17 | beego.Router("/import", &controllers.ImportController{}) 18 | beego.Router("/personalprojects", &controllers.PersonalProjectsController{}) 19 | beego.Router("/project/?:id/info", &controllers.ProjectInfoController{}) 20 | beego.Router("/project/?:id/memberList", &controllers.ProjectMemberListController{}) 21 | beego.Router("/project/?:id/memberWork", &controllers.ProjectMemberWorkController{}) 22 | beego.Router("/project/?:id/notice", &controllers.ProjectNoticeController{}) 23 | beego.Router("/project/?:id/setting", &controllers.ProjectSettingController{}) 24 | beego.Router("/ccsearchpage", &controllers.CcSearchPageController{}) 25 | beego.Router("/capitalInjection", &controllers.CapitalInjectionController{}) 26 | beego.Router("/projectfunding", &controllers.ProjectFundingController{}) 27 | beego.Router("/platformInformation", &controllers.PlatformInformationController{}) 28 | beego.Router("/webhooks",&controllers.WebhooksController{}) 29 | } 30 | -------------------------------------------------------------------------------- /src/models/getAllJoinedProjects.go: -------------------------------------------------------------------------------- 1 | // TODO 该文件并入k_user.go中 2 | package models 3 | 4 | import ( 5 | "fmt" 6 | 7 | "github.com/astaxie/beego/orm" 8 | ) 9 | 10 | func GetAllJoinedProjects(userId string) (joinedProjects []*Project, err error) { 11 | var jp []*Project 12 | //var maps []orm.Params 13 | o := orm.NewOrm() 14 | _ = o.Using("default") 15 | SQLQuery := getAllJoinedProjectsQuery() 16 | if _, err := o.Raw(SQLQuery, userId).QueryRows(&jp); err != nil { 17 | fmt.Print(err.Error()) 18 | return nil, err 19 | } 20 | 21 | SQLQuery = getMemberListQuery() 22 | for _, proj := range jp { 23 | var memberlist []*UserData 24 | if _, err = o.Raw(SQLQuery, proj.ProjectId).QueryRows(&memberlist); err != nil { 25 | fmt.Print(err.Error()) 26 | return nil, err 27 | } 28 | 29 | proj.MemberList = memberlist 30 | fmt.Println(proj.MemberList) 31 | } 32 | return jp, nil 33 | } 34 | 35 | func getAllJoinedProjectsQuery() string { 36 | return "select * from \"k_project\" where project_id in " + 37 | "(select project_id from \"k_user_in_project\" where user_id = ?)" 38 | } 39 | 40 | func getMemberListQuery() string { 41 | return `SELECT u.k_user_id, u.user_name, u.head_shot_url 42 | FROM "k_user" u LEFT JOIN "k_user_in_project" up on u.k_user_id = up.user_id 43 | WHERE up.project_id = ?` 44 | //return "SELECT user_id, user_name, head_shot_url FROM \"k_user\" WHERE user_id in " + 45 | // "(SELECT user_id FROM \"k_user_in_Project\" WHERE project_id = ?)" 46 | 47 | } 48 | 49 | //测试 50 | //func main() { 51 | // fmt.Print(GetAllJoinedProjects("1" )) 52 | //} 53 | -------------------------------------------------------------------------------- /src/controllers/personalPage.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | _ "Kcoin-Golang/src/models" 6 | // "encoding/json" 7 | "fmt" 8 | 9 | "github.com/astaxie/beego" 10 | ) 11 | 12 | type PersonalPageController struct { 13 | beego.Controller 14 | } 15 | 16 | func (c *PersonalPageController) Get() { 17 | //jsonBuf是一个用于调试的静态json,之后会调用webserver的接口,动态获取。 18 | //jsonBuf := 19 | // `{ 20 | // "errorCode": "0", 21 | // "data":{ 22 | // "userName": "DoubleJ", 23 | // "headShotUrl": "../static/img/tx2.png" 24 | // } 25 | //}` 26 | status := c.Ctx.GetCookie("status") 27 | c.Ctx.SetCookie("lastUri", c.Ctx.Request.RequestURI) 28 | if status == "0" || status == "" { 29 | defer c.Redirect("/login.html", 302) 30 | } 31 | 32 | //获取GitHubId 33 | //gitId := c.GetSession("GitHubId").(string) 34 | githubId := c.Ctx.GetCookie("githubId") 35 | //通过gitHubId查询cs数 36 | csNum := models.GetCsNum(githubId) 37 | 38 | user := models.UserInfo{Data: &models.UserData{}} //user中存放着json解析后获得的数据。 39 | user.Data.UserName = c.Ctx.GetCookie("userName") 40 | user.Data.HeadShotUrl = c.Ctx.GetCookie("headShotUrl") 41 | user.Data.CsNum = csNum 42 | 43 | c.Data["user"] = user 44 | c.TplName = "personalPage.html" //该controller对应的页面 45 | 46 | // 函数定义在models目录下的searchCcAndCs.go中,根据用户名查询CC余额 47 | remainingCc, err := models.GetPersonalRemainingCc(user.Data.UserName) 48 | if err != nil { 49 | fmt.Println("you r in personalPage controller, something got wrong "+ 50 | "while querying the database: ", err.Error()) 51 | } 52 | 53 | c.Data["remainingCc"] = remainingCc 54 | } 55 | -------------------------------------------------------------------------------- /src/controllers/homepage.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/astaxie/beego" 8 | ) 9 | 10 | type HomePageController struct { 11 | beego.Controller 12 | } 13 | 14 | func (c *HomePageController) Get() { 15 | //从cookie中取出状态 16 | isLogin :=c.Ctx.GetCookie("status") 17 | 18 | 19 | //把Json字符串中的数据解析到结构体中 20 | var proj models.ProjectInfo 21 | projectBuf , _ := models.GetAllProjectsInfo() 22 | err := json.Unmarshal([]byte(projectBuf),&proj) 23 | if err != nil { 24 | fmt.Println("err=", err) 25 | //return 26 | } 27 | 28 | //把结构体传到模板当中 29 | c.Data["Projects"] = proj 30 | 31 | 32 | isPlatformAdmin := false 33 | //判断当前登录状态 34 | if isLogin == "1"{ 35 | c.Data["isLogin"] = true 36 | user := models.UserInfo{Data:&models.UserData{}}//user中存放着json解析后获得的数据。 37 | user.Data.UserName = c.Ctx.GetCookie("userName") 38 | user.Data.UserId = c.Ctx.GetCookie("userId") 39 | user.Data.HeadShotUrl = c.Ctx.GetCookie("headShotUrl") 40 | c.Data["user"] = user 41 | //判断当前用户是不是平台管理员 42 | isPlatformAdmin = models.IsSupervisor(user.Data.UserId) 43 | } else { 44 | c.Data["isLogin"] = false 45 | c.Ctx.SetCookie("userName","",100) 46 | c.Ctx.SetCookie("headShotUrl","",100) 47 | c.Ctx.SetCookie("status", string('0'),100) 48 | c.Ctx.SetCookie("lastUri",c.Ctx.Request.RequestURI) 49 | 50 | } 51 | c.Data["isPlatformAdmin"] = isPlatformAdmin 52 | 53 | //设置Get方法对应展示的模板 54 | c.TplName = "homePage.tpl" 55 | } 56 | -------------------------------------------------------------------------------- /src/models/models.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "fmt" 5 | "github.com/astaxie/beego/orm" 6 | _ "github.com/lib/pq" 7 | ) 8 | 9 | //定义结构体,用来对接前后端json 10 | //homepage 11 | type Project struct { 12 | ProjectId string `json:"projectId"` 13 | ProjectName string `json:"projectName"` 14 | ProjectCoverUrl string `json:"projectCoverUrl"` 15 | ProjectUrl string `json:"projectUrl"` 16 | MemberList []*UserData `json:"memberList"` 17 | } 18 | 19 | type ProjectInfo struct { 20 | ErrorCode string `json:"errorCode"` 21 | Data []*Project `json:"data"` 22 | } 23 | 24 | //ccSearchPage 25 | /*UserCcData:为ccSearchPage的主要结构体,包括kcoin记录中的cc操作日期,操作类型和cc的数量 26 | */ 27 | type UserCcOpe struct{ 28 | OpeCcDate string `json:"opeCcDate"` 29 | OpeCcType string `json:"opeCcType"` 30 | OpeCcNumber string `json:"opeCcNumber"` 31 | } 32 | 33 | //homepage import 34 | /*UserData:为personalpage和projectpage的主要结构体,定义了用户姓名、用户头像url、项目列表 35 | */ 36 | type UserData struct { 37 | UserId string `json:"userId"` 38 | UserName string `json:"userName"` 39 | HeadShotUrl string `json:"headshotUrl"` 40 | ProjectList []*Project `json:"projectList"` 41 | UserCcOpeList []*UserCcOpe `json:"userCcOpeList"` 42 | CsNum int `json:"csNum"` 43 | } 44 | 45 | //import personPage 46 | /*UserInfo:包括UserData和另外一个errorCode,errorCode主要用于调试 47 | */ 48 | type UserInfo struct { 49 | ErrorCode string `json:"errorCode"` 50 | Data *UserData `json:"data"` 51 | } 52 | 53 | func init() { 54 | _ = orm.RegisterDriver("postgres", orm.DRPostgres) 55 | err := orm.RegisterDataBase("default", "postgres", "user=sspkukcoin password=kcoin2019 dbname=postgres host=114.115.133.140 port=5432") 56 | if err != nil { 57 | fmt.Println(err.Error()) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/views/ccSearchPage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 个人中心 5 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | {{template "./leftNav.html" .}} 17 |
18 | 21 | 22 |
23 |
24 | Kcoin记录 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {{with .user.Data}} 34 | {{range .UserCcOpeList}} 35 | 36 | 37 | 38 | 39 | {{end}} 40 | {{end}} 41 |
日期操作类型cc数量
{{.OpeCcDate}}{{.OpeCcType}}{{.OpeCcNumber}}
42 | 43 |
    44 |
  • «
  • 45 |
  • 1
  • 46 |
  • »
  • 47 |
48 | 49 |
50 |
51 |
52 | -------------------------------------------------------------------------------- /src/controllers/authorize.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | "Kcoin-Golang/src/service" 6 | "fmt" 7 | "github.com/astaxie/beego" 8 | "github.com/astaxie/beego/orm" 9 | "time" 10 | ) 11 | 12 | type AuthoController struct { 13 | beego.Controller 14 | } 15 | 16 | func (c *AuthoController) Get() { 17 | var code string = c.GetString("code") 18 | accessToken, _ := service.GetAccessToken(code) 19 | text := service.GetUserJson(accessToken) 20 | 21 | name := text.Data.Name 22 | id := text.Data.Id 23 | // 修改参数 24 | //service.GithubUser.SetGithubUserAccessToken(id, name, accessToken) 25 | uri := text.Data.Uri 26 | 27 | o := orm.NewOrm() 28 | o.Using("default") 29 | // 移到model 改成GitID查询 30 | res, _ := models.FinduserByGitId(id) 31 | 32 | if res.UserId == "" { 33 | err := models.InsertUser(name, uri, id) 34 | if err != nil { 35 | panic(err) 36 | } 37 | } else { 38 | time := time.Now().Format("2006-01-02 15:04:05.000000") 39 | updateSql := `update "k_user" set register_time = ? where github_id = ?` 40 | _, err := o.Raw(updateSql, time, id).Exec() 41 | if err != nil { 42 | panic(err) 43 | } 44 | } 45 | 46 | //存储用户名到cooike中,获取语法:c.Ctx.GetCookie("userName") 47 | c.Ctx.SetCookie("userName", text.Data.Name, 3600) 48 | //存储用户名到cooike中,获取语法:c.Ctx.GetCookie("userId") 49 | c.Ctx.SetCookie("userId", res.UserId, 3600) 50 | //存储用户头像url到cooike中,获取语法:c.Ctx.GetCookie("headShotUrl") 51 | c.Ctx.SetCookie("headShotUrl", text.Data.Uri, 3600) 52 | //存储用户登录状态到cooike中,其中1表示已登录,获取语法:c.Ctx.GetCookie("status") 53 | c.Ctx.SetCookie("status", string('1'), 3600) 54 | 55 | c.Ctx.SetCookie("githubId", id, 3600) 56 | c.Ctx.SetCookie("githubName", name, 3600) 57 | c.Ctx.SetCookie("githubToken", accessToken, 3600) 58 | 59 | if redirectUrl := c.Ctx.GetCookie("lastUri"); redirectUrl != "" { 60 | fmt.Printf(redirectUrl) 61 | c.Redirect(c.Ctx.GetCookie("lastUri"), 302) 62 | } else { 63 | c.Redirect("homepage", 302) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/controllers/import.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | "encoding/json" 6 | "fmt" 7 | "strconv" 8 | 9 | "github.com/astaxie/beego" 10 | ) 11 | 12 | type ImportController struct { 13 | beego.Controller 14 | } 15 | 16 | func (c *ImportController) Get() { 17 | jsonBuf := 18 | `{ 19 | "errorCode": "0", 20 | "data": { 21 | "userName": "anaana", 22 | "headshotUrl": "../static/img/tx2.png", 23 | "projectList": 24 | [ 25 | { 26 | "projectName": "天气预报1", 27 | "projectCoverUrl": "../static/img/projectbg.png", 28 | "projectUrl": "", 29 | "memberList": [ 30 | { 31 | "userName": "Tony", 32 | "headshotUrl": "../static/img/tx2.png" 33 | }, 34 | { 35 | "userName": "Tony", 36 | "headshotUrl": "../static/img/tx1.png" 37 | } 38 | ] 39 | }, 40 | { 41 | "projectName": "天气预报2", 42 | "projectCoverUrl": "../static/img/projectbg.png", 43 | "projectUrl": "", 44 | "memberList": [ 45 | { 46 | "userName": "Joy", 47 | "headshotUrl": "../static/img/tx1.png" 48 | }, 49 | { 50 | "userName": "Tony", 51 | "headshotUrl": "../static/img/tx2.png" 52 | } 53 | ] 54 | } 55 | ] 56 | } 57 | }` 58 | var user models.UserInfo 59 | errorCode := json.Unmarshal([]byte(jsonBuf), &user) 60 | if errorCode != nil { 61 | fmt.Println("there is an error ,sorry ,please continue debug,haha", errorCode.Error()) 62 | } 63 | c.Data["user"] = user //json数据解包 64 | c.Data["memberList_len"] = strconv.Itoa(len(user.Data.ProjectList)) //个人项目数量 65 | c.TplName = "import.tpl" 66 | } 67 | -------------------------------------------------------------------------------- /src/views/import.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 我的项目 8 | 9 | 10 |
11 |

导入项目

12 | 17 |
18 |
19 |
20 | 21 | 22 |
23 |
24 |

25 | profile  26 | {{.user.Data.UserName}}  27 | ({{.memberList_len}}个项目) 28 |

29 | 30 |
    31 | {{with .user.Data}} 32 | {{range .ProjectList}} 33 |
  • {{.ProjectName}}
  • 34 | {{end}} 35 | {{end}} 36 |
37 |
38 |
39 |
40 |

初始信息页面

41 |
42 |
43 |

 

44 |

1. 填写项目名称

45 |
46 | 47 |
48 |

2. 上传项目封面(选填,但只能添加不大于2M的图片)

49 | 选择文件 50 | 51 | 52 |
53 |
54 |
55 |
56 | 57 | 58 |
59 |
60 |
61 | 62 | -------------------------------------------------------------------------------- /src/views/homePage.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HomePage 6 | 7 | 8 | 9 | 10 |
11 |
12 | {{if .isLogin}} 13 | 14 | {{else}} 15 | 16 | {{end}} 17 | 项目列表 18 | 19 | 20 | {{if .isPlatformAdmin}} 21 | 平台管理 22 | {{else}} 23 | 24 | {{end}} 25 | 26 | 首页 27 |
28 |
29 |
KCOIN
30 |

基于区块链的项目激励平台

31 |

您可以在下面的搜索框里

32 |

搜索您感兴趣的项目

33 |
34 | 35 | 36 |
37 |
38 |
39 |
40 |
41 |
42 | {{with .Projects}} 43 | {{range .Data}} 44 | 45 |
46 | project 47 |
{{.ProjectName}}
48 |
introduction
49 |
CC:12138
50 |
51 | {{range .MemberList}} 52 | 53 | 54 | {{end}} 55 |
56 |
57 | {{end}} 58 | {{end}} 59 |
60 |
61 |
62 | {{template "./footer.html" .}} 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/views/projectMemberWork.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 工作列表 5 | 6 | 7 | 8 | 9 | 10 | {{template "./projectTopNav.html" .}} 11 | 12 | 15 | 16 |
17 |
18 | DoubleJ的工作信息 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
日期贡献类型获得cs数量
10.23提交pr500
10.23提交issue200
10.24提交pr500
10.24提交issue200
10.25提交pr500
10.27提交pr500
57 |
58 |
59 | 60 |
< 返回
61 |
62 |
63 |
64 | {{template "./footer.html" .}} 65 | -------------------------------------------------------------------------------- /src/controllers/ccSearchPage.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | _ "Kcoin-Golang/src/models" 6 | "encoding/json" 7 | "fmt" 8 | 9 | "github.com/astaxie/beego" 10 | ) 11 | 12 | type CcSearchPageController struct { 13 | beego.Controller 14 | } 15 | 16 | func (c *CcSearchPageController) Get() { 17 | //jsonBuf是一个用于调试的静态json,之后从数据库中读取数据 18 | jsonBuf := 19 | `{ 20 | "errorCode": "0", 21 | "data": { 22 | "userName": "Sonorous ", 23 | "headshotUrl": "../static/img/tx2.png", 24 | "userCcOpeList": 25 | [ 26 | { 27 | "opeCcDate":"11.18", 28 | "opeCcType":"sell", 29 | "opeCcNumber":"-2000" 30 | }, 31 | { 32 | "opeCcDate":"11.18", 33 | "opeCcType":"buy", 34 | "opeCcNumber":"5000" 35 | }, 36 | { 37 | "opeCcDate":"11.19", 38 | "opeCcType":"sell", 39 | "opeCcNumber":"-1000" 40 | }, 41 | { 42 | "opeCcDate":"11.18", 43 | "opeCcType":"sell", 44 | "opeCcNumber":"-1000" 45 | }, 46 | { 47 | "opeCcDate":"11.18", 48 | "opeCcType":"buy", 49 | "opeCcNumber":"1000" 50 | }, 51 | { 52 | "opeCcDate":"11.19", 53 | "opeCcType":"sell", 54 | "opeCcNumber":"-500" 55 | }, 56 | { 57 | "opeCcDate":"11.18", 58 | "opeCcType":"sell", 59 | "opeCcNumber":"-3000" 60 | }, 61 | { 62 | "opeCcDate":"11.18", 63 | "opeCcType":"buy", 64 | "opeCcNumber":"2000" 65 | }, 66 | { 67 | "opeCcDate":"11.19", 68 | "opeCcType":"sell", 69 | "opeCcNumber":"-800" 70 | }, 71 | { 72 | "opeCcDate":"11.18", 73 | "opeCcType":"sell", 74 | "opeCcNumber":"-1000" 75 | } 76 | ] 77 | } 78 | }` 79 | 80 | status:=c.Ctx.GetCookie("status") 81 | { 82 | c.Ctx.SetCookie("lastUri",c.Ctx.Request.RequestURI) 83 | if status =="0"||status ==""{ 84 | defer c.Redirect("/login.html",302) 85 | } 86 | } 87 | var user models.UserInfo 88 | errorCode := json.Unmarshal([]byte(jsonBuf), &user) 89 | user.Data.UserName = c.Ctx.GetCookie("userName") 90 | user.Data.HeadShotUrl = c.Ctx.GetCookie("headShotUrl") 91 | if errorCode != nil { 92 | fmt.Println("Oops, there is an error:( please keep debugging.", errorCode.Error()) 93 | } 94 | 95 | c.Data["user"] = user 96 | c.TplName = "ccSearchPage.html"//该controller对应的页面 97 | } 98 | -------------------------------------------------------------------------------- /src/models/k_project.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "database/sql" 5 | "encoding/json" 6 | _ "encoding/json" 7 | "fmt" 8 | "log" 9 | 10 | "github.com/astaxie/beego/orm" 11 | ) 12 | 13 | //查询并以json形式返回所有的项目信息 14 | func GetAllProjectsInfo() (string, error) { 15 | o := orm.NewOrm() 16 | o.Using("default") 17 | 18 | var projectsInfo ProjectInfo 19 | projectsInfo.ErrorCode = "default Error" 20 | 21 | /******************************************query all projects************************************************/ 22 | queryProjectSql := `SELECT project_id , project_name , project_url , project_cover_url FROM "k_project" ` 23 | /***********************************************************************************************************/ 24 | 25 | _, err := o.Raw(queryProjectSql).QueryRows(&projectsInfo.Data) 26 | 27 | /******************************************query menberList in one project**********************************/ 28 | queryUsersInProjectSql := `select u.k_user_id,u.user_name,u.head_shot_url 29 | from "k_user" u left join "k_user_in_project" up on u.k_user_id=up.user_id 30 | where up.project_id=?` 31 | /**********************************************************************************************************/ 32 | for _, v := range projectsInfo.Data { 33 | var memberList []*UserData 34 | _, err := o.Raw(queryUsersInProjectSql, v.ProjectId).QueryRows(&memberList) 35 | if err != nil { 36 | fmt.Println(err.Error()) 37 | return fmt.Sprint(projectsInfo), err 38 | } 39 | v.MemberList = memberList 40 | } 41 | projectsInfo.ErrorCode = "0" 42 | res, err := json.Marshal(&projectsInfo) 43 | if err != nil { 44 | fmt.Println(err.Error()) 45 | return fmt.Sprint(projectsInfo), err 46 | } 47 | return string(res), nil 48 | } 49 | 50 | func GetProjectsCC(projectName string) (float64, error) { 51 | o := orm.NewOrm() 52 | o.Using("default") 53 | 54 | queryProjectSql := `SELECT project_cc FROM "k_project" WHERE project_name=? ` 55 | var num float64 56 | err := o.Raw(queryProjectSql, projectName).QueryRow(&num) 57 | if err != nil { 58 | fmt.Println(err.Error()) 59 | } 60 | return num, nil 61 | } 62 | 63 | func GetProjectidByRepoName(reponame string) (int, error) { 64 | o := orm.NewOrm() 65 | _ = o.Using("default") 66 | var project_id int 67 | querySql := `select project_id from "k_project" where project_name=?` 68 | err := o.Raw(querySql, reponame).QueryRow(&project_id) 69 | return project_id, err 70 | 71 | } 72 | 73 | func InsertProject(reponame string, url string, project_cover_url string) (sql.Result, error) { 74 | o := orm.NewOrm() 75 | _ = o.Using("default") 76 | 77 | querySql := `insert into "k_project"(project_name,project_url,project_cover_url)values(?,?,?)` 78 | 79 | res, err := o.Raw(querySql, reponame, url, project_cover_url).Exec() 80 | if err != nil { 81 | log.Fatal("error when insert project,", err) 82 | } 83 | return res, err 84 | } 85 | -------------------------------------------------------------------------------- /src/controllers/personalProjects.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | "Kcoin-Golang/src/service" 6 | "encoding/json" 7 | "fmt" 8 | "log" 9 | "strconv" 10 | 11 | "github.com/astaxie/beego" 12 | ) 13 | 14 | type PersonalProjectsController struct { 15 | beego.Controller 16 | } 17 | 18 | func (c *PersonalProjectsController) GetPersonalInfo() { 19 | name := c.Ctx.GetCookie("userName") 20 | userBuf, _ := models.GetUserInfo(name) 21 | projectBuf, _ := models.GetGithubRepos(name) 22 | 23 | status := c.Ctx.GetCookie("status") 24 | //判断是否登录,如果未登录,登录后跳转到原页面 25 | c.Ctx.SetCookie("lastUri", c.Ctx.Request.RequestURI) 26 | if status == "0" || status == "" { 27 | defer c.Redirect("/login.html", 302) 28 | } 29 | 30 | user := models.UserInfo{Data: &models.UserData{}} 31 | user.Data.UserName = name 32 | user.Data.HeadShotUrl = c.Ctx.GetCookie("headShotUrl") 33 | var projects models.ProjectInfo 34 | errorCode := json.Unmarshal([]byte(userBuf), &user) 35 | errorCode2 := json.Unmarshal([]byte(projectBuf), &projects) 36 | 37 | if errorCode != nil { 38 | fmt.Println("Oops, there is an error:( please keep debugging.", errorCode.Error()) 39 | } 40 | if errorCode2 != nil { 41 | fmt.Println("Oops, there is an error:( please keep debugging.", errorCode2.Error()) 42 | } 43 | 44 | c.Data["user"] = user 45 | c.Data["repos"] = projects 46 | c.Data["memberList_len"] = strconv.Itoa(len(projects.Data)) //个人项目数量 47 | 48 | //获取已加入项目 49 | //使用testid=95 50 | testid := c.Ctx.GetCookie("userId") 51 | joinedprojects, _ := models.GetAllJoinedProjects(testid) 52 | fmt.Print(models.GetAllJoinedProjects("95")) 53 | c.Data["joinedProjects"] = joinedprojects 54 | c.Data["joinedprojects_len"] = strconv.Itoa(len(joinedprojects)) 55 | } 56 | 57 | func (c *PersonalProjectsController) Post() { 58 | //var U models.Project 59 | pUrl := c.GetString("ProjectUrl") //项目地址 60 | pName := c.GetString("ProjectName") //项目名称 61 | pIntro := c.GetString("ProjectIntro") //项目介绍 62 | //uploadname := c.GetString("uploadname") //项目封面 63 | fmt.Println(pUrl, pName, pIntro) 64 | 65 | //提交图片 66 | f, h, err := c.GetFile("uploadname") 67 | if err != nil { 68 | log.Fatal("getfile err ", err) 69 | } 70 | defer f.Close() 71 | fmt.Println(f, h, err) 72 | githubId := c.Ctx.GetCookie("githubId") 73 | githubName := c.Ctx.GetCookie("githubName") 74 | githubToken := c.Ctx.GetCookie("githubToken") 75 | githubInfo := service.GithubInfo{ 76 | GithubId: githubId, 77 | GithubName: githubName, 78 | AccessToken: githubToken, 79 | } 80 | 81 | if err = ImportProject(pUrl, "../static/img/projectbg.png", githubInfo); err != nil { 82 | fmt.Println("Oops, there is an error:( please keep debugging.", err.Error()) 83 | // 需要返回错误页面 84 | return 85 | } 86 | 87 | c.TplName = "personalProjects.html" 88 | c.Redirect("personalprojects", 302) 89 | } 90 | 91 | func (c *PersonalProjectsController) Get() { 92 | c.GetPersonalInfo() 93 | 94 | c.TplName = "personalProjects.html" 95 | } 96 | -------------------------------------------------------------------------------- /src/views/capitalInjection.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 资金注入页面 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | {{template "./platformAdminTopNav.html" .}} 16 |
17 | 20 |
21 | {{with .Projects}} 22 | {{range .Data}} 23 |
24 | project 25 |
{{.ProjectName}}
26 |
introduction
27 |
CC:12138
28 |
29 | {{range .MemberList}} 30 | 31 |
32 | 33 |
34 | {{end}} 35 |
36 | 37 |
38 |
39 | {{end}} 40 | {{end}} 41 |
42 |
43 | 44 |
45 |
46 |

注资信息 47 | 49 |

50 |
51 | 金额 52 | 53 |
54 | 期限 55 | 56 |
57 | 58 | 59 | 60 | 61 |
62 | 63 | 64 |
65 |
66 | 67 |
68 | 69 | 70 | -------------------------------------------------------------------------------- /src/tests/models_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "Kcoin-Golang/src/models" 5 | "Kcoin-Golang/src/service" 6 | "testing" 7 | ) 8 | 9 | func Test_getContributors(t *testing.T) { 10 | type args struct { 11 | userName string 12 | programName string 13 | } 14 | tests := []struct { 15 | name string 16 | args args 17 | want string 18 | }{ 19 | //测试用例 20 | {args: args{userName: "rjkris", programName: "fluffy-robot"}, want: "rjkris "}, //PASS 21 | } 22 | for _, tt := range tests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | if got := service.GetContributors(tt.args.userName, tt.args.programName); got != tt.want { 25 | t.Errorf("getContributors() = %v, want %v", got, tt.want) 26 | } 27 | }) 28 | } 29 | } 30 | 31 | func TestGetContributorNum(t *testing.T) { 32 | type args struct { 33 | url string 34 | } 35 | tests := []struct { 36 | name string 37 | args args 38 | want int 39 | }{ 40 | //测试用例 41 | {args: args{url: "https://github.com/OS-ABC/HelloWorld"}, want: 115}, //FAIL 通过该API获得的contributors可能不全 42 | {args: args{url: "https://github.com/OS-ABC/Kcoin-Golang"}, want: 17}, //PASS 43 | } 44 | for _, tt := range tests { 45 | t.Run(tt.name, func(t *testing.T) { 46 | if got := service.GetContributorNum(tt.args.url); got != tt.want { 47 | t.Errorf("GetContributorNum() = %v, want %v", got, tt.want) 48 | } 49 | }) 50 | } 51 | } 52 | 53 | func TestGetStarNum(t *testing.T) { 54 | type args struct { 55 | url string 56 | } 57 | tests := []struct { 58 | name string 59 | args args 60 | want int 61 | }{ 62 | //测试用例 63 | {args: args{url: "https://github.com/OS-ABC/Kcoin-Golang"}, want: 16}, //PASS 64 | {args: args{url: "https://github.com/OS-ABC/HelloWorld"}, want: 86}, //PASS 65 | } 66 | for _, tt := range tests { 67 | t.Run(tt.name, func(t *testing.T) { 68 | if got := service.GetStarNum(tt.args.url); got != tt.want { 69 | t.Errorf("GetStarNum() = %v, want %v", got, tt.want) 70 | } 71 | }) 72 | } 73 | } 74 | 75 | func TestParseGithubHTTPSUrl(t *testing.T) { 76 | type args struct { 77 | url string 78 | } 79 | tests := []struct { 80 | name string 81 | args args 82 | wantUserName string 83 | wantUserRepo string 84 | }{ 85 | //测试用例 86 | {args: args{url: "https://github.com/OS-ABC/Kcoin-Golang"}, wantUserName: "OS-ABC", wantUserRepo: "Kcoin-Golang"}, //PASS 87 | {args: args{url: "https://github.com/zhang2j/HelloWorld.git"}, wantUserName: "zhang2j", wantUserRepo: "HelloWorld"}, //PASS 88 | } 89 | for _, tt := range tests { 90 | t.Run(tt.name, func(t *testing.T) { 91 | if gotName, gotRepo, _ := service.ParseGithubHTTPSUrl(tt.args.url); gotName != tt.wantUserName || gotRepo != tt.wantUserRepo { 92 | t.Errorf("userName = %v, want %v; userRepo = %v; want %v", gotName, tt.wantUserName, gotRepo, tt.wantUserRepo) 93 | } 94 | }) 95 | } 96 | } 97 | 98 | func TestGetProjectsCC(t *testing.T) { 99 | type args struct { 100 | projectName string 101 | } 102 | tests := []struct { 103 | name string 104 | args args 105 | want float64 106 | }{ 107 | //测试用例 108 | {args: args{projectName: "baidu"}, want: 1}, //PASS 109 | {args: args{projectName: "i_love_Kcoin"}, want: 3}, //PASS 110 | } 111 | for _, tt := range tests { 112 | t.Run(tt.name, func(t *testing.T) { 113 | if got, _ := models.GetProjectsCC(tt.args.projectName); got != tt.want { 114 | t.Errorf("CCNum = %v, want %v", got, tt.want) 115 | } 116 | }) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/static/js/paging.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 分页函数 4 | * pno--页数 5 | * psize--每页显示记录数 6 | * 分页部分是从真实数据行开始,因而存在加减某个常数,以确定真正的记录数 7 | * 纯js分页实质是数据行全部加载,通过是否显示属性完成分页功能 8 | **/ 9 | function goPage1(pno,psize){ 10 | 11 | var itable = document.getElementById("idData1"); 12 | var num = itable.rows.length;//表格所有行数(所有记录数) 13 | console.log(num); 14 | var totalPage = 0;//总页数 15 | var pageSize = psize;//每页显示行数 16 | //总共分几页 17 | if(num/pageSize > parseInt(num/pageSize)){ //判断是否为小数 18 | totalPage=parseInt(num/pageSize)+1; } 19 | else{ 20 | totalPage=parseInt(num/pageSize); 21 | } 22 | var currentPage = pno;//当前页数 23 | var startRow = (currentPage - 1) * pageSize+1;//开始显示的行 31 24 | var endRow = currentPage * pageSize;//结束显示的行 40 25 | endRow = (endRow > num)? num : endRow; //40 26 | console.log(endRow); 27 | //遍历显示数据实现分页 28 | for(var i=1;i<(num+1);i++){ 29 | var irow = itable.rows[i-1]; 30 | if(i>=startRow && i<=endRow){ 31 | irow.style.display = "block"; 32 | }else{ 33 | irow.style.display = "none"; 34 | } 35 | } 36 | var tempStr = "共"+num+"条记录 分"+totalPage+"页 当前第"+currentPage+"页"; 37 | if(currentPage>1){ 38 | tempStr += "首页"; 39 | tempStr += "<上一页" 40 | }else{ 41 | tempStr += "首页"; 42 | tempStr += "<上一页"; 43 | } 44 | if(currentPage下一页>"; 46 | tempStr += "尾页"; 47 | }else{ 48 | tempStr += "下一页>"; 49 | tempStr += "尾页"; 50 | } 51 | document.getElementById("barcon1").innerHTML = tempStr; 52 | 53 | 54 | } 55 | 56 | 57 | 58 | function goPage2(pno,psize){ 59 | 60 | var itable = document.getElementById("idData2"); 61 | var num = itable.rows.length;//表格所有行数(所有记录数) 62 | console.log(num); 63 | var totalPage = 0;//总页数 64 | var pageSize = psize;//每页显示行数 65 | //总共分几页 66 | if(num/pageSize > parseInt(num/pageSize)){ //判断是否为小数 67 | totalPage=parseInt(num/pageSize)+1; 68 | }else{ 69 | totalPage=parseInt(num/pageSize); 70 | } 71 | var currentPage = pno;//当前页数 72 | var startRow = (currentPage - 1) * pageSize+1;//开始显示的行 31 73 | var endRow = currentPage * pageSize;//结束显示的行 40 74 | endRow = (endRow > num)? num : endRow; //40 75 | console.log(endRow); 76 | //遍历显示数据实现分页 77 | for(var i=1;i<(num+1);i++){ 78 | var irow = itable.rows[i-1]; 79 | if(i>=startRow && i<=endRow){ 80 | irow.style.display = "block"; 81 | }else{ 82 | irow.style.display = "none"; 83 | } 84 | } 85 | var tempStr = "共"+num+"条记录 分"+totalPage+"页 当前第"+currentPage+"页"; 86 | if(currentPage>1){ 87 | tempStr += "首页"; 88 | tempStr += "<上一页" 89 | }else{ 90 | tempStr += "首页"; 91 | tempStr += "<上一页"; 92 | } 93 | if(currentPage下一页>"; 95 | tempStr += "尾页"; 96 | }else{ 97 | tempStr += "下一页>"; 98 | tempStr += "尾页"; 99 | } 100 | document.getElementById("barcon2").innerHTML = tempStr; 101 | } 102 | -------------------------------------------------------------------------------- /src/static/css/homepage.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* CSS Document */ 3 | 4 | body { 5 | margin: 0; 6 | } 7 | 8 | a:link,a:visited,a:active 9 | { 10 | color: #1B1B1B; 11 | text-decoration:none; 12 | } 13 | 14 | a:hover{ 15 | color: #1B1B1B; 16 | text-decoration:none; 17 | border: 2px; 18 | border-color: blue; 19 | } 20 | 21 | .header { 22 | background-size: cover; 23 | background-image: url("../img/bg2.png"); 24 | background-repeat: no-repeat; 25 | padding-bottom: 16vw; 26 | } 27 | 28 | .title > .kcoin{ 29 | color: aliceblue; 30 | font-size: 5vw; 31 | font-weight: 500; 32 | padding-top: 17vw; 33 | margin-left: 10vw; 34 | } 35 | .title h2{ 36 | color: aliceblue; 37 | font-size: 2vw; 38 | font-weight: 500; 39 | margin-left: 10vw; 40 | } 41 | .title p{ 42 | color:#B1B1B1; 43 | font-size: 15px; 44 | margin-left: 10vw; 45 | } 46 | 47 | .search { 48 | width: 25vw; 49 | height: 40px; 50 | border-radius: 18px; 51 | margin-left: 9.5vw; 52 | outline: none; 53 | border: 1px solid #ccc; 54 | padding-left: 20px; 55 | position: absolute; 56 | } 57 | 58 | .search-btn { 59 | height: 35px; 60 | width: 35px; 61 | position: absolute; 62 | background: url("../img/search.png") no-repeat; 63 | margin-top: 5px; 64 | margin-left: 32.5vw; 65 | border: none; 66 | outline: none; 67 | cursor: pointer; 68 | } 69 | .head { 70 | padding-top: 20px; 71 | padding-bottom: 20px; 72 | position: fixed; 73 | height: 40px; 74 | width: 100%; 75 | background-image: url("../img/head.png"); 76 | background-size: cover; 77 | } 78 | .head > .head-bt { 79 | position: relative; 80 | float: right; 81 | color: aliceblue; 82 | height: 40px; 83 | width: 120px; 84 | font-size: 28px; 85 | text-decoration: none; 86 | text-align: right; 87 | padding-right: 20px; 88 | } 89 | .head > .login-bt { 90 | position: relative; 91 | float: right; 92 | color: aliceblue; 93 | font-size: 28px; 94 | display:block; 95 | margin-left: 15px; 96 | margin-right: 15px; 97 | width:100px; 98 | height:40px; 99 | border-radius: 20px 20px 20px 20px; 100 | background: #00CCFF; 101 | text-decoration: none; 102 | text-align: center; 103 | } 104 | .head > .login-bt:hover { 105 | background: #04e7ff; 106 | } 107 | .head > a > .login-headshot { 108 | position: relative; 109 | float: right; 110 | margin-right: 15px; 111 | margin-left: 15px; 112 | width: 50px; 113 | } 114 | .container { 115 | width: 100%; 116 | font-size: 0; 117 | } 118 | .container-child { 119 | margin: auto; 120 | width: 1250px; 121 | } 122 | .project { 123 | display: inline-block; 124 | margin-top: 40px; 125 | margin-left: 15px; 126 | margin-right: 15px; 127 | width: 220px; 128 | background: #F8F8FD; 129 | } 130 | .project > .project-cover { 131 | width: 100%; 132 | height: auto; 133 | } 134 | .project > .project-name { 135 | text-align: left; 136 | font-weight: 1000; 137 | font-size: 30px; 138 | padding-left: 10px; 139 | } 140 | .project > .introduction { 141 | text-align: left; 142 | font-size: 20px; 143 | padding-left: 20px; 144 | } 145 | .project > .CC { 146 | color: #FFCC33; 147 | font-size: 20px; 148 | text-align: left; 149 | padding-left: 20px; 150 | } 151 | .head_shot { 152 | padding-left: 15px; 153 | height: 50px; 154 | float: left; 155 | } 156 | .footer { 157 | position: relative; 158 | background: #1B1B1B; 159 | height: 100px; 160 | margin-top: 2vw; 161 | } 162 | .footer p { 163 | color: aliceblue; 164 | text-align: center; 165 | padding-top: 40px; 166 | font-family: "华文行楷"; 167 | } -------------------------------------------------------------------------------- /src/service/get_issue_info.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strconv" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | //解析api获取到的信息,需要的是labels中的name 14 | type IssueData struct { 15 | URL string `json:"url"` 16 | RepositoryURL string `json:"repository_url"` 17 | LabelsURL string `json:"labels_url"` 18 | CommentsURL string `json:"comments_url"` 19 | EventsURL string `json:"events_url"` 20 | HTMLURL string `json:"html_url"` 21 | ID int `json:"id"` 22 | NodeID string `json:"node_id"` 23 | Number int `json:"number"` 24 | Title string `json:"title"` 25 | User struct { 26 | Login string `json:"login"` 27 | ID int `json:"id"` 28 | NodeID string `json:"node_id"` 29 | AvatarURL string `json:"avatar_url"` 30 | GravatarID string `json:"gravatar_id"` 31 | URL string `json:"url"` 32 | HTMLURL string `json:"html_url"` 33 | FollowersURL string `json:"followers_url"` 34 | FollowingURL string `json:"following_url"` 35 | GistsURL string `json:"gists_url"` 36 | StarredURL string `json:"starred_url"` 37 | SubscriptionsURL string `json:"subscriptions_url"` 38 | OrganizationsURL string `json:"organizations_url"` 39 | ReposURL string `json:"repos_url"` 40 | EventsURL string `json:"events_url"` 41 | ReceivedEventsURL string `json:"received_events_url"` 42 | Type string `json:"type"` 43 | SiteAdmin bool `json:"site_admin"` 44 | } `json:"user"` 45 | Labels []struct { 46 | ID int `json:"id"` 47 | NodeID string `json:"node_id"` 48 | URL string `json:"url"` 49 | Name string `json:"name"` 50 | Color string `json:"color"` 51 | Default bool `json:"default"` 52 | Description string `json:"description"` 53 | } `json:"labels"` 54 | State string `json:"state"` 55 | Locked bool `json:"locked"` 56 | Assignee interface{} `json:"assignee"` 57 | Assignees []interface{} `json:"assignees"` 58 | Milestone interface{} `json:"milestone"` 59 | Comments int `json:"comments"` 60 | CreatedAt time.Time `json:"created_at"` 61 | UpdatedAt time.Time `json:"updated_at"` 62 | ClosedAt interface{} `json:"closed_at"` 63 | AuthorAssociation string `json:"author_association"` 64 | Body string `json:"body"` 65 | ClosedBy interface{} `json:"closed_by"` 66 | } 67 | 68 | //获取项目贡献者信息的接口 69 | // 函数名:Get_issue_info 70 | // 函数参数:userName string, programName string,issueName int 71 | // 返回值:string 包含所有的labels信息 72 | 73 | func Get_issue_info(userName string, programName string, issueNum int) int { 74 | Num := strconv.Itoa(issueNum) 75 | var url_1 string = "https://api.github.com/repos/" + userName + "/" + programName + "/" + "issues" + "/" + Num 76 | fmt.Println(url_1) 77 | client := &http.Client{} 78 | response, _ := client.Get(url_1) 79 | defer response.Body.Close() 80 | body, err_1 := ioutil.ReadAll(response.Body) 81 | if err_1 != nil { 82 | panic(err_1) 83 | } 84 | 85 | var ib IssueData 86 | json.Unmarshal(body, &ib) 87 | issues := []string{} 88 | for i := 0; i < len(ib.Labels); i++ { 89 | var labelsName string = ib.Labels[i].Name 90 | kcoin := "Kcoin" 91 | if strings.HasPrefix(labelsName, kcoin) == true { 92 | issues = append(issues, strings.Split(labelsName, "Kcoin#")[1]) 93 | } 94 | } 95 | res, _ := strconv.Atoi(issues[0]) 96 | return res 97 | } 98 | 99 | //使用实例: 100 | //func main() { 101 | // var info int= Get_issue_info("OS-ABC", "Kcoin-Golang", 288) 102 | // fmt.Println(info) 103 | //} 104 | -------------------------------------------------------------------------------- /src/views/join.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | KCoin-join 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 | 注册新帐号 22 |
23 |
24 |
25 | 26 | 28 |
29 |
30 | 31 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 | 47 | 52 |
53 | 54 |
55 | 60 |
61 | 62 | 63 |
64 |
65 |
66 |
67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/controllers/importHelper.go: -------------------------------------------------------------------------------- 1 | // TODO 把该文件与github_helper.go移动到service文件夹下, 并保证可以运行 2 | package controllers 3 | 4 | import ( 5 | "Kcoin-Golang/src/models" 6 | "Kcoin-Golang/src/service" 7 | "fmt" 8 | "log" 9 | "strings" 10 | ) 11 | 12 | func ImportProject(url, cover_url string, githubInfo service.GithubInfo) error { 13 | fmt.Println("进入ImportProject") 14 | //首先将string类型的currentUserId转成Int型 15 | //currentUserId_int,err:=strconv.Atoi(currentUserId) 16 | //检查地址是否合法 17 | err := service.CheckGithubRepoUrl(githubInfo.GithubName, url) 18 | if err != nil { 19 | log.Fatal("url is illegal", err) 20 | return err 21 | } else { 22 | fmt.Println("url合法") 23 | } 24 | //解析已经合法的地址中的用户名和仓库名 25 | userName, repoName, _ := service.ParseGithubHTTPSUrl(url) 26 | //使用用户名和仓库名获取项目全部contributor 27 | userslist_string := service.GetContributors(userName, repoName) 28 | users := strings.Split(userslist_string, " ") 29 | //将当前登录用户注册到webhook中 30 | service.RegisterGithubWebhooks(githubInfo.GithubName, repoName, githubInfo.AccessToken) 31 | host_id, _ := models.GetUseridByUsername(userName) 32 | fmt.Println("当前登陆用户id为", host_id, "当前username为", userName) 33 | fmt.Println("项目中的全部contributors", users) 34 | //查询数据库,看看所有的contributor哪个已经加入到数据库了,如果已经加入数据库,就把这些人放到k_user_in_project这个表里 35 | var alreadyIn []string //已经加入kcoin的contributor 36 | var notIn []string //还没加入kcoin的contributor 37 | var project_id int 38 | 39 | //插入项目到数据库 40 | _, _ = models.InsertProject(repoName, url, cover_url) 41 | //根据根据项目名查k_project表获取project_id 42 | project_id, err = models.GetProjectidByRepoName(repoName) 43 | if err != nil { 44 | log.Fatal("when query project_id in k_project ,error occured:", err) 45 | } 46 | //基金会注入原始cc100.00,捐献种类dtype设为0. 47 | err = models.CCInject(0, project_id, 100.00, 0) 48 | if err != nil { 49 | log.Fatal("when initialize cc injection, error occured: ", err) 50 | } 51 | 52 | for _, singleUser := range users { 53 | fmt.Println("开始for循环") 54 | if singleUser == "" { 55 | break 56 | } 57 | //遍历全部contributor列表 58 | var k_user_id int 59 | 60 | fmt.Println("正在找当前contributor:", singleUser) 61 | res, err := models.FindUserByUsername(singleUser) 62 | if err != nil { 63 | log.Fatal("when query a single user in k_user table,an error occured,", err) 64 | } else { 65 | num, _ := res.RowsAffected() 66 | if num == 0 { //如果没查到 67 | notIn = append(notIn, singleUser) 68 | //通过github API获取这个用户的git id 69 | singleUser_git_id := service.GetGithubId(singleUser) 70 | //插入到临时用户表 71 | res, err := models.InsertIntoKTemporaryUser(host_id, singleUser_git_id, singleUser, project_id) 72 | if err == nil { 73 | num, _ := res.RowsAffected() 74 | fmt.Println(num) 75 | } else { 76 | log.Fatal("when insert into k_temporary_user,error occured,", err) 77 | } 78 | } else { //查到了,这个用户已经在项目了 79 | alreadyIn = append(alreadyIn, singleUser) 80 | //然后把这个用户加到k_user_in_project中 81 | //首先根据user_name获取k_user_id 82 | k_user_id, err = models.GetUseridByUsername(singleUser) 83 | if err != nil { 84 | log.Fatal("when query k_user_id in k_user,error occured:", err) 85 | } 86 | //然后根据根据项目名查k_project表获取project_id 87 | project_id, err = models.GetProjectidByRepoName(repoName) 88 | if err != nil { 89 | log.Fatal("when query project_id in k_project ,error occured:", err) 90 | } 91 | //最后两个id都有了,插入k_user_in_project 92 | res, err = models.InsertIntoKUserInProject(project_id, k_user_id) 93 | if err == nil { 94 | nums, _ := res.RowsAffected() 95 | fmt.Println("affected rows has", nums) 96 | id, _ := res.LastInsertId() 97 | fmt.Println("last insert id is ", id) 98 | } else { 99 | log.Fatal("when insert to k_user_in_project,error occured,", err) 100 | } 101 | } 102 | } 103 | } 104 | //最后判断一下项目拥有者在不在k_user_in_Projet里,不在就插入 105 | var IfOwnerIn int 106 | IfOwnerIn, err = models.FindUserInKUserInProject(host_id) 107 | if IfOwnerIn == 0 { 108 | fmt.Println("拥有者还不在数据库,插入") 109 | 110 | _, err = models.InsertIntoKUserInProject(project_id, host_id) 111 | } 112 | //对所有没有加入的人给他们发个邮件 113 | _, err = models.SendEMailToPotentialUsers(notIn, githubInfo.AccessToken) 114 | return err 115 | } 116 | -------------------------------------------------------------------------------- /user-story.md: -------------------------------------------------------------------------------- 1 | # 用户故事集 2 | ## V1.0 Milestone 3 | ### 1. 作为一个平台管理者,我希望登陆时能够识别我的管理员身份,以便于进行相应的管理操作 4 | 5 | - [ ] 平台管理者登录后能在个人中心看到他是管理者身份。 6 | - [ ] 平台管理员登录后能看到外部发起的捐赠、注资信息。 7 | - [ ] 平台管理员能够参与有关向项目注资的讨论和决策。 8 | ### 2. 作为一个普通用户,我希望直接通过github、gitee登陆,以便于将账号与我的github相关联,进行导入项目、参与项目等操作 9 | - [ ] 用户可以通过github账号登录平台 10 | - [ ] 用户可以通过gitee账号登录平台 11 | - [ ] 一个用github或gitee登录过的用户再用另一种方式登录平台时,平台能关联这名用户的两种账号 12 | 13 | ### 3. 作为一个项目管理者,我希望通过项目url导入项目 14 | 15 | - [ ] 平台能通过URL获取git仓库的管理员、contributor等信息 16 | - [ ] 项目管理者可以通过项目URL导入项目 17 | 18 | ### 4. 作为一个项目管理者,我希望通过点击获取到的github仓库列表item,导入项目 19 | 20 | - [ ] 个人页面中可查看个人github仓库列表 21 | - [ ] 点击仓库列表项可导入github项目 22 | - [ ] 导入后提示是否成功,失败说明原因 23 | 24 | ### 5. 作为一个项目管理者,我希望我在导入项目时,可以制定自己的初始贡献量评定规则 25 | 26 | - [ ] 导入项目时以填表的方式设置简单的分配规则 27 | - [ ] 导入项目时可以上传自己定制的较为复杂的智能合约,并给出描述 28 | 29 | ### 6. 作为一个独裁制项目管理者,我希望我在导入项目后,可以更改贡献量评定规则 30 | - [ ] 项目在被导入后,管理者可以访问项目设置页面,更改项目规则。 31 | - [ ] 更改项目规则,可以查看到当前所有规则列表,管理者可以增加新的规则,或者改变某一规则赋予用户的CS,也可以删除一种规则。 32 | - [ ] 规则更改完成后,管理者可以点击确定保存。 33 | - [ ] 保存后应当判断规则制定合法性,如果合法提示更改成功;否则标红列表中不合法的规则,并注明原因。 34 | - [ ] 用户可以取消更改,当用户点击取消时,应当提示是否确定取消,以防止误操作。 35 | ### 7. 作为一个项目管理者,我希望可以设置项目封面,以便更好的展示给其他用户 36 | - [ ] 项目被导入后,在项目栏目中有设置封面按钮,点击后允许上传图片作为封面 37 | ### 8. 我是一名想在开源项目中做贡献的用户,我希望Kcoin能展示项目在Github上的star和committer数量等信息,以便我判断一个项目是否活跃且值得加入。 38 | - [ ] 项目详情页面会显示github中的star数量 39 | - [ ] 项目详情页面会显示github中的committer数量 40 | - [ ] kcoin的首页会展示按star数和committer数加权得到的排行榜 41 | ### 9. 作为一名投资者,我希望看到项目被哪些公司或机构使用,这样可以让我更好地决策,到底要不要给这个项目投资、要投资多少。 42 | - [ ] 项目详情页底部会展示所有使用该项目的公司/机构的图标 43 | - [ ] 项目管理者可以通过手动添加系统中预设的公司/机构 44 | - [ ] 项目管理者应该在添加公司/机构时提供相应的凭证,以供后台审核。 45 | - [ ] 系统中没有预设所选公司/机构的时候,可以通过向github中kcoin项目提交pr的方式来增加。 46 | ### 10. 我是一名项目管理者,我希望查看项目总体CC(市值cs*股价)和项目公共CC 47 | 48 | + [ ] 用户有项目管理页面 49 | + [ ] 项目管理者在项目管理页面中可看到项目总cs数, 项目cs与cc兑换比。 50 | + [ ] 项目管理者在项目管理页面中可看到项目总体CC和项目公共CC 51 | 52 | ### 11. 作为一个普通用户,我希望快速查看我参与的项目中我的CS和分配得到的CC 53 | - [ ] 普通用户可在我的项目列表中的每个项目名片上看到我的CS和CC 54 | - [ ] 若无法获取数据,则默认初始值为“--” 55 | ### 12. 作为一名项目管理者,我想要关注贡献者列表与具体工作列表,以便于增强对项目掌控。 56 | - [ ] 当用户选择访问一个项目详情时,应当判断他是否是管理员,若是则展示全体成员的贡献度列表,包括工作内容、贡献度、贡献时间。 57 | - [ ] 当信息读取失败时,要给出明确的提示。 58 | - [ ] 当列表内容过多时应当可以分页展示。 59 | ### 13. 作为一个普通用户,我想要查看目前项目所有成员的CS排行榜 60 | - [ ] 普通用户在我的项目列表中的每个项目名片上点击查看该项目的CS排行榜 61 | - [ ] 普通用户能正确读取所参与的各个项目的所有成员的CS排行榜 62 | - [ ] 信息读取失败时,应给出明确的提示信息 63 | - [ ] 普通用户通过点击刷新按钮获取最新的CS排名信息 64 | ### 14. 作为一个普通用户,我想要查看目前项目所有动态,包括项目规则的变化和公共CC变化 65 | - [ ] 普通用户在我的项目列表中,可以点击查看该项目的历史动态 66 | - [ ] 项目的历史动态中包含项目规则的变化和公共CC变化 67 | - [ ] 每次项目规则的变化都以“时间:项目规则的变化”的形式展示出来,最终形成项目规则变化的时间轴 68 | - [ ] 每次公共CC变化都以“时间:公共CC变化”的形式展示出来,最终形成公共CC变化的时间轴 69 | ### 15. 作为一个普通用户,我想要查看目前项目的贡献度评定规则,以便了解游戏规则 70 | - [ ] 普通用户在我的项目列表中的每个项目名片上点击查看该项目的贡献度评定规则 71 | - [ ] 当项目贡献度评定规则发生变化时,普通用户应收到变更通知 72 | - [ ] 贡献度评定规则变更后会保存历史版本,普通用户可以查阅 73 | ### 16. 作为一个普通用户,我希望我所在的项目在被管理员导入后,接收到邮件通知,提醒我加入kcoin平台,以便获取CS 74 | - [ ] 普通用户能通过项目所在平台的个人主要邮箱接收项目已被导入kcoin的邮件通知 75 | - [ ] 普通用户能在接收到通知后方便地跳转至kcoin网站,进行注册活动 76 | - [ ] 普通用户接收的邮件通知应包含:项目已被导入kcoin的通知、kcoin简介、kcoin主页链接、kcoin注册链接 77 | ### 17. 作为一个普通用户,我在给一个已托管的项目贡献成为一个新contributor时,希望收到邮件通知提醒我加入kcoin平台,以便获取CS 78 | 79 | - [ ] 普通用户在GitHub上做出贡献时,如果此项目已经在Kcoin平台上托管,则用户会收到该项目在Kcoin上的通知 80 | - [ ] 普通用户能在邮件中跳转到Kcoin网站 81 | - [ ] 普通用户能在Kcoin网站注册,并关联自己的GitHub账户,以便获取CS 82 | 83 | ### 18. 作为一个普通用户,我希望收到我参与的项目动态消息,包括项目规则的变化、决议投票和公共CC变化等,以便及时了解情况。 84 | 85 | - [ ] 普通用户可以在Kcoin平台看到他参与项目的动态信息 86 | - [ ] 普通用户可以选择是否通过邮件接收项目动态信息 87 | 88 | ### 19. 我是一名普通用户,我希望通过向开源社区提交代码,按照该项目贡献度规则获得相应的贡献度和CS 89 | 90 | - [ ] 普通用户能在GitHub上提交了PR或者作出其他贡献时,在Kcoin平台获取CS 91 | - [ ] 普通用户能在Kcoin平台上查看贡献度规则 92 | 93 | ### 20. 我是kcoin基金会,我希望用CC按股价比例收购某个项目的CS,以便支持项目发展 94 | 95 | - [ ] 有一个网页专门显示当前每个项目CS和CC的市场兑换比例 96 | 97 | ### 21. 我是一名投资者,我希望用法币向基金会购买CC,以便于收购某个项目的股权、投资项目。 98 | 99 | - [ ] CC购买页面有法币CC互换比例,微信/支付宝/银行卡支付功能。 100 | - [ ] 由项目页面点击购买,则CC购买页面有法币与项目CS互换比例 101 | - [ ] 未登录时,也可进行项目搜索,查看信息,购买选项 102 | - [ ] 点击购买时若未登录跳转至登录/注册页面,登录环节完毕检查CC是否足够,分别跳转 103 | 104 | ### 22. 我是一名投资者,我希望用CC按股价比例收购某个项目的CS,这些CS由全体成员按比例缴出,以便获得该项目的CS,进而控制投票权 105 | - [ ] 投资者能够在项目名片中看到cc与cs的股价比例 106 | - [ ] 投资者能够在投资时看到投资后自己的cs在项目中的占比以及投票权情况 107 | - [ ] 投资者能够收到活跃项目的推荐信息 108 | 109 | ### 23. 我是一名投资者,我希望用CC按股价比例向某个项目成员购买他手中的CS,从而拥有项目的投票权 110 | - [ ] 项目详情页面显示“买入cs”按钮 111 | - [ ] 点击“买入cs”按钮,会让用户在文本框输入买入多少cc的cs,文本框中的内容只能是实数 112 | - [ ] 有确定买入和取消按钮,供用户选择 113 | - [ ] 当用户点击确定买入,会跳转到输入密码页面 114 | - [ ] 当用户输入正确的密码,买入成功,个人持有的该项目cs增加相应数量,个人cc减少相应数量 115 | 116 | -------------------------------------------------------------------------------- /src/views/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | KCoin 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 |
17 |
18 | 19 |
20 | 59 |
60 |
61 |
62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/static/css/loginJoin.css: -------------------------------------------------------------------------------- 1 | /*以下是login和join页面的css*/ 2 | .logo-join { 3 | display:block; 4 | margin-top:50px; 5 | position: relative; 6 | width:100%; 7 | height: auto; 8 | text-align: center; 9 | } 10 | 11 | .title-join { 12 | display: block; 13 | font-family: PingFangHK-Semibold; 14 | font-size: 20px; 15 | color: #ffffff; 16 | position: relative; 17 | margin-top: 20px; 18 | width:100%; 19 | height:auto; 20 | text-align:center; 21 | } 22 | 23 | .join-label { 24 | padding-left: 32px; 25 | text-align: left; 26 | color:#ffffff; 27 | } 28 | 29 | .grid-join { 30 | display: block; 31 | position: relative; 32 | width: 376px; 33 | left:35%; 34 | height: 700px; 35 | z-index: 1001; 36 | } 37 | 38 | .father-div { 39 | display: block; 40 | width: 100%; 41 | position: relative; 42 | text-align: center; 43 | } 44 | 45 | .form-submit { 46 | display: block; 47 | position: relative; 48 | width: 376px; 49 | height: 95px; 50 | } 51 | 52 | .content { 53 | position: relative; 54 | width: 100%; 55 | top: 10%; 56 | } 57 | 58 | .left-subcontent { 59 | position: relative; 60 | width:40%; 61 | left:150px; 62 | margin-top: 35px; 63 | margin-bottom: 50px; 64 | left:150px; 65 | } 66 | 67 | .right-subcontent { 68 | width:40%; 69 | margin-top: 120px; 70 | margin-left: 20px; 71 | margin-bottom: 50px; 72 | float:right 73 | } 74 | 75 | .login-subtitle { 76 | text-align:center; 77 | margin-top: 20px; 78 | margin-bottom: 10px; 79 | font-family: PingFangHK-Semibold; 80 | font-size: 28px; 81 | color: #323a45; 82 | } 83 | 84 | .grid { 85 | position: absolute; 86 | background: #ffffff; 87 | border-radius: 5px; 88 | width: 310px; 89 | height: 420px; 90 | padding-left: 20px; 91 | padding-right: 20px; 92 | } 93 | 94 | .row { 95 | position: relative; 96 | display: flex; 97 | flex-wrap: wrap; 98 | } 99 | 100 | .cell { 101 | -webkit-box-flex: 1; 102 | flex: 1 0 0; 103 | max-width: 100%; 104 | padding: 0 12px 105 | } 106 | 107 | .form-group { 108 | display: block; 109 | position: relative 110 | } 111 | 112 | .form-group > label { 113 | margin-top: 20px; 114 | display: block; 115 | font-family: PingFangHK-Semibold; 116 | font-size: 13px; 117 | margin-bottom: 5px; 118 | } 119 | 120 | .required { 121 | border: 1px #1ba1e2 dashed !important; 122 | width: 310px !important; 123 | height: 40px; 124 | } 125 | 126 | .link { 127 | color: #60a8f0 !important; 128 | font-family: PingFangHK-Semibold; 129 | font-size: 13px; 130 | float: right; 131 | bottom:20px; 132 | position:relative; 133 | text-decoration: none; 134 | } 135 | 136 | .bottom-login { 137 | background: #60A8F0; 138 | border-radius: 5px; 139 | font-size: 16px; 140 | margin-bottom: 5px; 141 | text-align: center; 142 | width: 320px; 143 | height: 40px; 144 | box-shadow: none; 145 | text-decoration: none; 146 | max-width: 400px; 147 | height: 40px; 148 | font-weight: 400; 149 | text-align: center; 150 | white-space: nowrap; 151 | vertical-align: middle; 152 | } 153 | 154 | .link-underBotton { 155 | display: block; 156 | outline-color: #9d9d9d; 157 | font-family: PingFangHK-Semibold; 158 | font-size: 13px; 159 | float: right; 160 | position: relative; 161 | float: right; 162 | width: 25%; 163 | } 164 | 165 | .cell { 166 | display: block; 167 | background-color: lime; 168 | } 169 | 170 | .block-dark { 171 | display: block; 172 | position: relative; 173 | border-radius: 5px; 174 | font-size: 16px; 175 | margin-bottom: 5px; 176 | text-align: center; 177 | width: 320px; 178 | height: 40px; 179 | box-shadow: none; 180 | background-color: #666666; 181 | } 182 | 183 | .buttom-dark { 184 | color: #ffffff; 185 | width: 100% !important; 186 | text-decoration: none; 187 | text-align: center; 188 | margin-top: 10px; 189 | } 190 | 191 | .github-icon { 192 | width: 25px !important; 193 | height: 25px !important; 194 | position: relative; 195 | } 196 | 197 | .gitee-icon { 198 | width: 36px !important; 199 | height: 36px !important; 200 | position: relative; 201 | } 202 | 203 | .form-login { 204 | width: 100%; 205 | } 206 | 207 | .form-login-buttom { 208 | display: block; 209 | position: relative; 210 | height:65px; 211 | } 212 | -------------------------------------------------------------------------------- /database/create.sql: -------------------------------------------------------------------------------- 1 | --创建用户表 2 | CREATE TABLE "public"."K_User" ( 3 | "user_id" int4 DEFAULT nextval('test_c_id_seq'::regclass) NOT NULL, 4 | "user_name" varchar(255) COLLATE "default" NOT NULL, 5 | "user_cc" float8 DEFAULT 0, 6 | "register_time" timestamp(6) NOT NULL, 7 | "head_shot_url" varchar(255) COLLATE "default" NOT NULL, 8 | "is_delete" bool DEFAULT false, 9 | CONSTRAINT "K_User_pkey" PRIMARY KEY ("user_id") 10 | ) 11 | WITH (OIDS=FALSE) 12 | 13 | 14 | --创建项目表 15 | CREATE TABLE "public"."K_Project" ( 16 | "project_id" int4 DEFAULT nextval('"K_Project1_project_id_seq"'::regclass) NOT NULL, 17 | "project_name" varchar(255) COLLATE "default" NOT NULL, 18 | "project_url" varchar(255) COLLATE "default" NOT NULL, 19 | "project_cover_url" varchar(255) COLLATE "default" NOT NULL, 20 | "project_institution" int4, 21 | "project_description" text COLLATE "default", 22 | CONSTRAINT "k_project_pkey" PRIMARY KEY ("project_id") 23 | ) 24 | WITH (OIDS=FALSE) 25 | ; 26 | 27 | ALTER TABLE "public"."K_Project" OWNER TO "sspkukcoin"; 28 | 29 | COMMENT ON TABLE "public"."K_Project" IS '项目表'; 30 | 31 | COMMENT ON COLUMN "public"."K_Project"."project_id" IS '项目id(主键)'; 32 | 33 | COMMENT ON COLUMN "public"."K_Project"."project_name" IS '项目名称'; 34 | 35 | COMMENT ON COLUMN "public"."K_Project"."project_url" IS '项目url'; 36 | 37 | COMMENT ON COLUMN "public"."K_Project"."project_cover_url" IS '项目封面urll'; 38 | 39 | COMMENT ON COLUMN "public"."K_Project"."project_institution" IS '项目制度(1是独裁制,2是委员会占比制,3是委员会单票制,4是全体占比制,5是全体单票制)'; 40 | 41 | --创建用户 in项目表 42 | CREATE TABLE "public"."K_User_in_Project" ( 43 | "item_id" int4 DEFAULT nextval('"K_User_in_Project1_item_id_seq"'::regclass) NOT NULL, 44 | "project_id" int4 NOT NULL, 45 | "user_id" int4 NOT NULL, 46 | "user_cs" float8 DEFAULT 0 NOT NULL, 47 | "user_cc" float8 DEFAULT 0 NOT NULL, 48 | CONSTRAINT "k_user_in_project_pkey" PRIMARY KEY ("user_id", "project_id"), 49 | CONSTRAINT "K_User_in_Project_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "public"."K_User" ("user_id") ON DELETE NO ACTION ON UPDATE NO ACTION, 50 | CONSTRAINT "K_User_in_Project_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "public"."K_Project" ("project_id") ON DELETE NO ACTION ON UPDATE NO ACTION 51 | ) 52 | WITH (OIDS=FALSE) 53 | ; 54 | 55 | --创建触发器 56 | CREATE TRIGGER "cc_trigger" AFTER UPDATE ON "public"."K_User_in_Project" 57 | FOR EACH ROW 58 | EXECUTE PROCEDURE "sumcc"(); 59 | 60 | 61 | --创建权限表 62 | CREATE TABLE "public"."K_Permission" ( 63 | "id" int4 DEFAULT nextval('"K_Permission_id_seq"'::regclass) NOT NULL, 64 | "Permission_id" int4 NOT NULL, 65 | "Permission" varchar(100) COLLATE "default" NOT NULL, 66 | CONSTRAINT "K_Permission_pkey" PRIMARY KEY ("id") 67 | ) 68 | WITH (OIDS=FALSE) 69 | ; 70 | 71 | ALTER TABLE "public"."K_Permission" OWNER TO "sspkukcoin"; 72 | 73 | COMMENT ON TABLE "public"."K_Permission" IS '权限表'; 74 | 75 | COMMENT ON COLUMN "public"."K_Permission"."id" IS '主键ID'; 76 | 77 | COMMENT ON COLUMN "public"."K_Permission"."Permission_id" IS '权限ID'; 78 | 79 | COMMENT ON COLUMN "public"."K_Permission"."Permission" IS '权限名'; 80 | 81 | --创建角色表 82 | CREATE TABLE "public"."k_role" ( 83 | "id" int4 DEFAULT nextval('k_role_id_seq'::regclass) NOT NULL, 84 | "role_id" int4 NOT NULL, 85 | "role_name" varchar(100) COLLATE "default" NOT NULL, 86 | "role_permissions" int4 NOT NULL, 87 | "is_able" bool DEFAULT false NOT NULL, 88 | CONSTRAINT "k_role_pkey" PRIMARY KEY ("id"), 89 | CONSTRAINT "k_role_role_permissions_fkey" FOREIGN KEY ("role_permissions") REFERENCES "public"."K_Permission" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION 90 | ) 91 | WITH (OIDS=FALSE) 92 | ; 93 | 94 | ALTER TABLE "public"."k_role" OWNER TO "sspkukcoin"; 95 | 96 | COMMENT ON TABLE "public"."k_role" IS '角色表'; 97 | 98 | COMMENT ON COLUMN "public"."k_role"."id" IS '主键ID'; 99 | 100 | COMMENT ON COLUMN "public"."k_role"."role_id" IS '用户ID'; 101 | 102 | COMMENT ON COLUMN "public"."k_role"."role_name" IS '用户名'; 103 | 104 | COMMENT ON COLUMN "public"."k_role"."role_permissions" IS '用户权限'; 105 | 106 | COMMENT ON COLUMN "public"."k_role"."is_able" IS '用户是否使用'; 107 | 108 | --创建项目中,用户的角色表 109 | CREATE TABLE "public"."k_user_role_in_project" ( 110 | "id" int4 DEFAULT nextval('k_user_role_in_project_id_seq'::regclass) NOT NULL, 111 | "project_id" int4 NOT NULL, 112 | "user_id" int4 NOT NULL, 113 | "role_id" int4 NOT NULL, 114 | CONSTRAINT "k_user_role_in_project_pkey" PRIMARY KEY ("id"), 115 | CONSTRAINT "k_user_role_in_project_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "public"."K_Project" ("project_id") ON DELETE NO ACTION ON UPDATE NO ACTION, 116 | CONSTRAINT "k_user_role_in_project_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "public"."K_User" ("user_id") ON DELETE NO ACTION ON UPDATE NO ACTION 117 | ) 118 | WITH (OIDS=FALSE) 119 | ; 120 | 121 | -------------------------------------------------------------------------------- /src/static/js/EasePack.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * VERSION: beta 1.9.4 3 | * DATE: 2014-07-17 4 | * UPDATES AND DOCS AT: http://www.greensock.com 5 | * 6 | * @license Copyright (c) 2008-2014, GreenSock. All rights reserved. 7 | * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for 8 | * Club GreenSock members, the software agreement that was issued with your membership. 9 | * 10 | * @author: Jack Doyle, jack@greensock.com 11 | **/ 12 | var _gsScope="undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window;(_gsScope._gsQueue||(_gsScope._gsQueue=[])).push(function(){"use strict";_gsScope._gsDefine("easing.Back",["easing.Ease"],function(t){var e,i,s,r=_gsScope.GreenSockGlobals||_gsScope,n=r.com.greensock,a=2*Math.PI,o=Math.PI/2,h=n._class,l=function(e,i){var s=h("easing."+e,function(){},!0),r=s.prototype=new t;return r.constructor=s,r.getRatio=i,s},_=t.register||function(){},u=function(t,e,i,s){var r=h("easing."+t,{easeOut:new e,easeIn:new i,easeInOut:new s},!0);return _(r,t),r},c=function(t,e,i){this.t=t,this.v=e,i&&(this.next=i,i.prev=this,this.c=i.v-e,this.gap=i.t-t)},p=function(e,i){var s=h("easing."+e,function(t){this._p1=t||0===t?t:1.70158,this._p2=1.525*this._p1},!0),r=s.prototype=new t;return r.constructor=s,r.getRatio=i,r.config=function(t){return new s(t)},s},f=u("Back",p("BackOut",function(t){return(t-=1)*t*((this._p1+1)*t+this._p1)+1}),p("BackIn",function(t){return t*t*((this._p1+1)*t-this._p1)}),p("BackInOut",function(t){return 1>(t*=2)?.5*t*t*((this._p2+1)*t-this._p2):.5*((t-=2)*t*((this._p2+1)*t+this._p2)+2)})),m=h("easing.SlowMo",function(t,e,i){e=e||0===e?e:.7,null==t?t=.7:t>1&&(t=1),this._p=1!==t?e:0,this._p1=(1-t)/2,this._p2=t,this._p3=this._p1+this._p2,this._calcEnd=i===!0},!0),d=m.prototype=new t;return d.constructor=m,d.getRatio=function(t){var e=t+(.5-t)*this._p;return this._p1>t?this._calcEnd?1-(t=1-t/this._p1)*t:e-(t=1-t/this._p1)*t*t*t*e:t>this._p3?this._calcEnd?1-(t=(t-this._p3)/this._p1)*t:e+(t-e)*(t=(t-this._p3)/this._p1)*t*t*t:this._calcEnd?1:e},m.ease=new m(.7,.7),d.config=m.config=function(t,e,i){return new m(t,e,i)},e=h("easing.SteppedEase",function(t){t=t||1,this._p1=1/t,this._p2=t+1},!0),d=e.prototype=new t,d.constructor=e,d.getRatio=function(t){return 0>t?t=0:t>=1&&(t=.999999999),(this._p2*t>>0)*this._p1},d.config=e.config=function(t){return new e(t)},i=h("easing.RoughEase",function(e){e=e||{};for(var i,s,r,n,a,o,h=e.taper||"none",l=[],_=0,u=0|(e.points||20),p=u,f=e.randomize!==!1,m=e.clamp===!0,d=e.template instanceof t?e.template:null,g="number"==typeof e.strength?.4*e.strength:.4;--p>-1;)i=f?Math.random():1/u*p,s=d?d.getRatio(i):i,"none"===h?r=g:"out"===h?(n=1-i,r=n*n*g):"in"===h?r=i*i*g:.5>i?(n=2*i,r=.5*n*n*g):(n=2*(1-i),r=.5*n*n*g),f?s+=Math.random()*r-.5*r:p%2?s+=.5*r:s-=.5*r,m&&(s>1?s=1:0>s&&(s=0)),l[_++]={x:i,y:s};for(l.sort(function(t,e){return t.x-e.x}),o=new c(1,1,null),p=u;--p>-1;)a=l[p],o=new c(a.x,a.y,o);this._prev=new c(0,0,0!==o.t?o:o.next)},!0),d=i.prototype=new t,d.constructor=i,d.getRatio=function(t){var e=this._prev;if(t>e.t){for(;e.next&&t>=e.t;)e=e.next;e=e.prev}else for(;e.prev&&e.t>=t;)e=e.prev;return this._prev=e,e.v+(t-e.t)/e.gap*e.c},d.config=function(t){return new i(t)},i.ease=new i,u("Bounce",l("BounceOut",function(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}),l("BounceIn",function(t){return 1/2.75>(t=1-t)?1-7.5625*t*t:2/2.75>t?1-(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1-(7.5625*(t-=2.25/2.75)*t+.9375):1-(7.5625*(t-=2.625/2.75)*t+.984375)}),l("BounceInOut",function(t){var e=.5>t;return t=e?1-2*t:2*t-1,t=1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375,e?.5*(1-t):.5*t+.5})),u("Circ",l("CircOut",function(t){return Math.sqrt(1-(t-=1)*t)}),l("CircIn",function(t){return-(Math.sqrt(1-t*t)-1)}),l("CircInOut",function(t){return 1>(t*=2)?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)})),s=function(e,i,s){var r=h("easing."+e,function(t,e){this._p1=t||1,this._p2=e||s,this._p3=this._p2/a*(Math.asin(1/this._p1)||0)},!0),n=r.prototype=new t;return n.constructor=r,n.getRatio=i,n.config=function(t,e){return new r(t,e)},r},u("Elastic",s("ElasticOut",function(t){return this._p1*Math.pow(2,-10*t)*Math.sin((t-this._p3)*a/this._p2)+1},.3),s("ElasticIn",function(t){return-(this._p1*Math.pow(2,10*(t-=1))*Math.sin((t-this._p3)*a/this._p2))},.3),s("ElasticInOut",function(t){return 1>(t*=2)?-.5*this._p1*Math.pow(2,10*(t-=1))*Math.sin((t-this._p3)*a/this._p2):.5*this._p1*Math.pow(2,-10*(t-=1))*Math.sin((t-this._p3)*a/this._p2)+1},.45)),u("Expo",l("ExpoOut",function(t){return 1-Math.pow(2,-10*t)}),l("ExpoIn",function(t){return Math.pow(2,10*(t-1))-.001}),l("ExpoInOut",function(t){return 1>(t*=2)?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*(t-1)))})),u("Sine",l("SineOut",function(t){return Math.sin(t*o)}),l("SineIn",function(t){return-Math.cos(t*o)+1}),l("SineInOut",function(t){return-.5*(Math.cos(Math.PI*t)-1)})),h("easing.EaseLookup",{find:function(e){return t.map[e]}},!0),_(r.SlowMo,"SlowMo","ease,"),_(i,"RoughEase","ease,"),_(e,"SteppedEase","ease,"),f},!0)}),_gsScope._gsDefine&&_gsScope._gsQueue.pop()(); -------------------------------------------------------------------------------- /src/views/projectFunding.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 项目信息 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{template "./platformAdminTopNav.html" .}} 12 | 13 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 |
日期注资项目cc数量
11.22Sonorous77/Robot2000
11.22Sonorous77/Weather forecast3000
11.23OS-ABC/HelloWorld5000
11.24Sonorous77/Robot5000
11.24OS-ABC/HelloWorld2000
11.25OS-ABC/HelloWorld6000
11.25Sonorous77/Robot2000
11.26Sonorous77/Weather forecast3000
日期注资项目cc数量
11.27OS-ABC/HelloWorld1000
11.27Sonorous77/Weather forecast3000
11.28Sonorous77/Robot3000
11.28OS-ABC/HelloWorld5000
11.29Sonorous77/Robot4000
11.29OS-ABC/HelloWorld6000
11.30Sonorous77/Weather forecast2000
11.30Sonorous77/Robot3000
日期注资项目cc数量
12.01Sonorous77/Weather forecast2000
12.01Sonorous77/Robot3000
12.02Sonorous77/Robot5000
12.02OS-ABC/HelloWorld5000
12.03OS-ABC/HelloWorld2000
12.03OS-ABC/HelloWorld6000
12.04Sonorous77/Robot2000
12.04Sonorous77/Weather forecast3000
157 | 158 | 159 | 160 | 161 |
162 |
163 | 164 | 165 | 166 | {{template "./footer.html" .}} 167 | -------------------------------------------------------------------------------- /src/views/personalProjects.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 我的项目 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | {{template "./leftNav.html" .}} 13 |
14 | 17 | 18 | 19 | 22 | 23 |
24 | 31 | 32 | 33 | 51 | 52 |
53 |

test

54 |

{{.test_projectUrl}}

55 |

{{.test_projectName}}

56 |

{{.test_filename}}

57 |

{{.test_ProjectIntro}}

58 |
59 |
60 |
61 | 62 |
63 | 64 |
65 |

导入项目 66 | 68 |

69 |
    70 |
  • 选择项目
  • 71 |
  • 初始信息
  • 72 |
  • 初始分配
  • 73 |
74 |
75 |
76 |
77 | 78 |
79 |

80 | profile  81 | {{.user.Data.UserName}}  82 | ({{.memberList_len}}个项目) 83 |

84 | 85 |
    86 | {{range .repos.Data}} 87 |
  • {{.ProjectName}}
  • 88 | {{end}} 89 | 90 |
91 |
92 |
93 |
94 |

test

95 |
96 |
97 |

 

98 |

1. 填写项目名称

99 | 100 |

2. 填写项目描述

101 | 102 |

3. 上传项目封面(选填,但只能添加不大于2M的图片)

103 | 选择文件 104 | 105 | 106 |
107 |
108 | 109 | 110 | 111 |
112 |
113 |
114 |
115 |
116 | -------------------------------------------------------------------------------- /src/static/js/import.js: -------------------------------------------------------------------------------- 1 | var step_num = 1; 2 | 3 | function showPopup(){ 4 | step_num = 1; 5 | var step = document.getElementById("step2"); 6 | step.className = ""; 7 | step = document.getElementById("step3"); 8 | step.className = ""; 9 | var page = document.getElementById("myprojects"); 10 | page.style.display="block"; 11 | page = document.getElementById("init_message"); 12 | page.style.display="none"; 13 | page = document.getElementById("config_project"); 14 | page.style.display="none"; 15 | var button = document.getElementById("btnNextStep"); 16 | button.style.display="block"; 17 | button = document.getElementById("btnconfirm"); 18 | button.style.display="none"; 19 | 20 | var popUp = document.getElementById("import"); 21 | popUp.style.position= "absolute"; 22 | popUp.style.zIndex="100"; 23 | popUp.style.width = "100%"; 24 | popUp.style.height = "100%"; 25 | popUp.style.visibility = "visible"; 26 | } 27 | 28 | function hidePopup(){ 29 | var popUp = document.getElementById("import"); 30 | popUp.style.visibility = "hidden"; 31 | } 32 | 33 | function next_step(){ 34 | if(step_num === 1) { //在第一步输入url后,点击下一步时,进行判断,验证其权限 35 | var isProjOwner = false; //表示仓库是否属于此用户,默认为false 36 | var orgMember = false; //表示仓库是否属于用户所在的组织,暂且默认为false,待后端写好再实现 37 | var projUrl = document.getElementById("projectUrl").value; //获取用户输入的URL 38 | var temp = projUrl.split('/'); 39 | 40 | //用cookie获取用户的用户名 41 | var userName = getCookie("userName"); 42 | if (userName==null) { 43 | //此时浏览器中cookie已经到期,需要重新登录 44 | } 45 | //用斜杠‘/’分割项目url,则倒数第二项为用户名。两个用户名相等,则项目属于该用户 46 | if(userName === temp[temp.length-2] || 47 | userName === temp[temp.length-2].replace("git@github.com:", "")) //使用SSH 48 | isProjOwner = true; 49 | //如果两个条件都不满足,则提示错误并返回 50 | if(!isProjOwner && !orgMember) { 51 | alert('请检查输入的URL:您不是此项目的所有者,且不属于此项目的组织。(当前仅支持https)'); 52 | return; 53 | } 54 | } 55 | 56 | if(step_num >= 1 && step_num < 3) 57 | step_num += 1; 58 | switch(step_num){ 59 | case 2: 60 | var step = document.getElementById("step2"); 61 | step.className = "active"; 62 | var page = document.getElementById("myprojects"); 63 | page.style.display="none"; 64 | page = document.getElementById("init_message"); 65 | page.style.display="block"; 66 | break; 67 | case 3: 68 | var step = document.getElementById("step3"); 69 | step.className = "active"; 70 | var page = document.getElementById("init_message"); 71 | page.style.display="none"; 72 | page = document.getElementById("config_project"); 73 | page.style.display="block"; 74 | var button = document.getElementById("btnNextStep"); 75 | button.style.display="none"; 76 | button = document.getElementById("btnconfirm"); 77 | button.style.display="block"; 78 | break; 79 | default: 80 | break; 81 | } 82 | } 83 | 84 | function back_step(){ 85 | if(step_num >1 && step_num <= 3) 86 | step_num -= 1; 87 | switch(step_num){ 88 | case 1: 89 | var step = document.getElementById("step2"); 90 | step.className = ""; 91 | var page = document.getElementById("myprojects"); 92 | page.style.display="block"; 93 | page = document.getElementById("init_message"); 94 | page.style.display="none"; 95 | break; 96 | case 2: 97 | var step = document.getElementById("step3"); 98 | step.className = ""; 99 | var page = document.getElementById("init_message"); 100 | page.style.display="block"; 101 | page = document.getElementById("config_project"); 102 | page.style.display="none"; 103 | var button = document.getElementById("btnNextStep"); 104 | button.style.display="block"; 105 | button = document.getElementById("btnconfirm"); 106 | button.style.display="none"; 107 | 108 | break; 109 | default: 110 | break; 111 | } 112 | } 113 | 114 | function showImg(input) { 115 | var file = input.files[0]; 116 | var url = window.URL.createObjectURL(file); 117 | document.getElemtById('upload_image').src=url; 118 | } 119 | 120 | function show_joined(){ 121 | var popUp = document.getElementById("joined_projects"); 122 | popUp.style.display = "block"; 123 | popUp = document.getElementById("managed_projects"); 124 | popUp.style.display = "none"; 125 | document.getElementById("join").style.backgroundColor = 'white'; 126 | document.getElementById("manage").style.backgroundColor = '#bfbfbf'; 127 | } 128 | 129 | function show_managed(){ 130 | var popUp = document.getElementById("managed_projects"); 131 | popUp.style.display = "block"; 132 | popUp = document.getElementById("joined_projects"); 133 | popUp.style.display = "none"; 134 | document.getElementById("join").style.backgroundColor = '#bfbfbf'; 135 | document.getElementById("manage").style.backgroundColor = 'white'; 136 | } 137 | 138 | function setUrl(url) { 139 | var projectUrl = document.getElementById("projectUrl"); 140 | projectUrl.value = url; 141 | next_step(); 142 | } 143 | 144 | function getCookie(cookieKey){ 145 | var arrcookie = document.cookie.split("; "); 146 | //遍历匹配 147 | for ( var i = 0; i < arrcookie.length; i++) { 148 | var arr = arrcookie[i].split("="); 149 | if (arr[0] == cookieKey){ 150 | return arr[1]; 151 | } 152 | } 153 | return null; 154 | } 155 | 156 | //JS获取url中项目名称 157 | function getProjectNameByUrl(){ 158 | var projUrl = document.getElementById("projectUrl").value; //获取用户输入的URL 159 | var index = projUrl.lastIndexOf("\/"); 160 | projUrl = projUrl.substring(index + 1, projUrl.length); 161 | document.getElementById("projUrl").value = projUrl; 162 | } -------------------------------------------------------------------------------- /src/static/js/helloweb.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | var width, height, largeHeader, canvas, ctx, points, target, animateHeader = true; 4 | 5 | // Main 6 | initHeader(); 7 | initAnimation(); 8 | addListeners(); 9 | 10 | function initHeader() { 11 | width = window.innerWidth; 12 | height = window.innerHeight; 13 | target = {x: width/2, y: height/2}; 14 | 15 | largeHeader = document.getElementById('large-header'); 16 | largeHeader.style.height = height+'px'; 17 | 18 | canvas = document.getElementById('demo-canvas'); 19 | canvas.width = width; 20 | canvas.height = height; 21 | ctx = canvas.getContext('2d'); 22 | 23 | // create points 24 | points = []; 25 | for(var x = 0; x < width; x = x + width/20) { 26 | for(var y = 0; y < height; y = y + height/20) { 27 | var px = x + Math.random()*width/20; 28 | var py = y + Math.random()*height/20; 29 | var p = {x: px, originX: px, y: py, originY: py }; 30 | points.push(p); 31 | } 32 | } 33 | 34 | // for each point find the 5 closest points 35 | for(var i = 0; i < points.length; i++) { 36 | var closest = []; 37 | var p1 = points[i]; 38 | for(var j = 0; j < points.length; j++) { 39 | var p2 = points[j] 40 | if(!(p1 == p2)) { 41 | var placed = false; 42 | for(var k = 0; k < 5; k++) { 43 | if(!placed) { 44 | if(closest[k] == undefined) { 45 | closest[k] = p2; 46 | placed = true; 47 | } 48 | } 49 | } 50 | 51 | for(var k = 0; k < 5; k++) { 52 | if(!placed) { 53 | if(getDistance(p1, p2) < getDistance(p1, closest[k])) { 54 | closest[k] = p2; 55 | placed = true; 56 | } 57 | } 58 | } 59 | } 60 | } 61 | p1.closest = closest; 62 | } 63 | 64 | // assign a circle to each point 65 | for(var i in points) { 66 | var c = new Circle(points[i], 2+Math.random()*2, 'rgba(255,255,255,0.3)'); 67 | points[i].circle = c; 68 | } 69 | } 70 | 71 | // Event handling 72 | function addListeners() { 73 | if(!('ontouchstart' in window)) { 74 | window.addEventListener('mousemove', mouseMove); 75 | } 76 | window.addEventListener('scroll', scrollCheck); 77 | window.addEventListener('resize', resize); 78 | } 79 | 80 | function mouseMove(e) { 81 | var posx = posy = 0; 82 | if (e.pageX || e.pageY) { 83 | posx = e.pageX; 84 | posy = e.pageY; 85 | } 86 | else if (e.clientX || e.clientY) { 87 | posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 88 | posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 89 | } 90 | target.x = posx; 91 | target.y = posy; 92 | } 93 | 94 | function scrollCheck() { 95 | if(document.body.scrollTop > height) animateHeader = false; 96 | else animateHeader = true; 97 | } 98 | 99 | function resize() { 100 | width = window.innerWidth; 101 | height = window.innerHeight; 102 | largeHeader.style.height = height+'px'; 103 | canvas.width = width; 104 | canvas.height = height; 105 | } 106 | 107 | // animation 108 | function initAnimation() { 109 | animate(); 110 | for(var i in points) { 111 | shiftPoint(points[i]); 112 | } 113 | } 114 | 115 | function animate() { 116 | if(animateHeader) { 117 | ctx.clearRect(0,0,width,height); 118 | for(var i in points) { 119 | // detect points in range 120 | if(Math.abs(getDistance(target, points[i])) < 4000) { 121 | points[i].active = 0.3; 122 | points[i].circle.active = 0.6; 123 | } else if(Math.abs(getDistance(target, points[i])) < 20000) { 124 | points[i].active = 0.1; 125 | points[i].circle.active = 0.3; 126 | } else if(Math.abs(getDistance(target, points[i])) < 40000) { 127 | points[i].active = 0.02; 128 | points[i].circle.active = 0.1; 129 | } else { 130 | points[i].active = 0; 131 | points[i].circle.active = 0; 132 | } 133 | 134 | drawLines(points[i]); 135 | points[i].circle.draw(); 136 | } 137 | } 138 | requestAnimationFrame(animate); 139 | } 140 | 141 | function shiftPoint(p) { 142 | TweenLite.to(p, 1+1*Math.random(), {x:p.originX-50+Math.random()*100, 143 | y: p.originY-50+Math.random()*100, ease:Circ.easeInOut, 144 | onComplete: function() { 145 | shiftPoint(p); 146 | }}); 147 | } 148 | 149 | // Canvas manipulation 150 | function drawLines(p) { 151 | if(!p.active) return; 152 | for(var i in p.closest) { 153 | ctx.beginPath(); 154 | ctx.moveTo(p.x, p.y); 155 | ctx.lineTo(p.closest[i].x, p.closest[i].y); 156 | ctx.strokeStyle = 'rgba(156,217,249,'+ p.active+')'; 157 | ctx.stroke(); 158 | } 159 | } 160 | 161 | function Circle(pos,rad,color) { 162 | var _this = this; 163 | 164 | // constructor 165 | (function() { 166 | _this.pos = pos || null; 167 | _this.radius = rad || null; 168 | _this.color = color || null; 169 | })(); 170 | 171 | this.draw = function() { 172 | if(!_this.active) return; 173 | ctx.beginPath(); 174 | ctx.arc(_this.pos.x, _this.pos.y, _this.radius, 0, 2 * Math.PI, false); 175 | ctx.fillStyle = 'rgba(156,217,249,'+ _this.active+')'; 176 | ctx.fill(); 177 | }; 178 | } 179 | 180 | // Util 181 | function getDistance(p1, p2) { 182 | return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2); 183 | } 184 | 185 | })(); -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 2 | github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM= 3 | github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= 4 | github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= 5 | github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= 6 | github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= 7 | github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y= 8 | github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= 9 | github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= 10 | github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= 11 | github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= 12 | github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= 13 | github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= 14 | github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= 15 | github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= 16 | github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= 17 | github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= 18 | github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 19 | github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= 20 | github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= 21 | github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= 22 | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 23 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 24 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 25 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 26 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 27 | github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= 28 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 29 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 30 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 31 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 32 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 33 | github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= 34 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 35 | github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= 36 | github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 37 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 38 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 39 | github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= 40 | github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= 41 | github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= 42 | github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= 43 | github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= 44 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= 45 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 46 | github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 47 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 48 | github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= 49 | github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= 50 | github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= 51 | golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 52 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= 53 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 54 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 55 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 56 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 57 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 58 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= 59 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 60 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 61 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 62 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 63 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 64 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 65 | google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= 66 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 67 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 68 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 69 | gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= 70 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 71 | -------------------------------------------------------------------------------- /src/static/css/platformAdmin.css: -------------------------------------------------------------------------------- 1 | /*以下页面共有的css*/ 2 | body{ 3 | margin: 0; 4 | 5 | } 6 | 7 | /*以下是platformAdminTopNav页面的css*/ 8 | 9 | a:link,a:visited,a:hover,a:active 10 | { 11 | color: #1B1B1B; 12 | text-decoration:none; 13 | } 14 | 15 | .head { 16 | position: relative; 17 | height: 70px; 18 | background-color: #333333; 19 | } 20 | 21 | .topNavLogo{ 22 | float: left; 23 | width: 60px; 24 | height: 60px; 25 | margin-top: 5px; 26 | margin-left: 5px; 27 | margin-right: 10px; 28 | } 29 | 30 | .topNavName{ 31 | float: left; 32 | line-height: 70px; 33 | font-size: 28px; 34 | color: aliceblue; 35 | } 36 | 37 | .navigation { 38 | position: relative; 39 | height: 160px; 40 | padding-left: 100px; 41 | background-color: #bfbfbf; 42 | } 43 | 44 | .navigation > img { 45 | position: absolute; 46 | width: 150px; 47 | height: 100%; 48 | border-style: solid; 49 | border-width: 6px; 50 | border-color: #FFFFFF; 51 | border-radius: 5px; 52 | margin-left: 50px; 53 | margin-top: 20px; 54 | } 55 | 56 | .navigation > .platform-admin { 57 | position: absolute; 58 | font-size: 60px; 59 | margin-left: 250px; 60 | margin-top: 30px; 61 | color: #323a45; 62 | } 63 | 64 | .navigation > .first { 65 | margin-left: 250px; 66 | 67 | } 68 | 69 | .navigation > a { 70 | float: left; 71 | margin-top: 110px; 72 | margin-left: 40px; 73 | padding-left: 10px; 74 | padding-right: 10px; 75 | padding-top: 5px; 76 | border-radius: 10px; 77 | font-size: 30px; 78 | height: 60px; 79 | } 80 | 81 | 82 | /*以下是platformInformation.html页面的css*/ 83 | .pltinfo-container { 84 | margin: auto; 85 | width: 1200px; 86 | font-size: 0; 87 | } 88 | .pltinfo-card { 89 | display: inline-block; 90 | vertical-align: top; 91 | border: 2px solid #52B1EC; 92 | border-radius: 10px; 93 | width: 500px; 94 | height: 500px; 95 | margin-top: 70px; 96 | margin-left: 46px; 97 | margin-right: 46px; 98 | } 99 | .card-head { 100 | height: 70px; 101 | background-color: #ACDCFA; 102 | } 103 | .card-title { 104 | display: inline-block; 105 | vertical-align: bottom; 106 | font-size: 25px; 107 | color: #3B43F4; 108 | height: 70px; 109 | line-height: 70px; 110 | text-align: center; 111 | margin-left: 20px; 112 | } 113 | .pltinfo-card-value { 114 | display: inline-block; 115 | vertical-align: bottom; 116 | font-size: 25px; 117 | font-weight: bold; 118 | color: #5DCBED; 119 | height: 370px; 120 | width: 500px; 121 | line-height: 70px; 122 | text-align: center; 123 | 124 | } 125 | .pltinfo-card-value p{ 126 | display: inline-block; 127 | vertical-align: bottom; 128 | font-size: 25px; 129 | font-weight: bold; 130 | color: #5DCBED; 131 | height: 70px; 132 | width: 100px; 133 | line-height: 70px; 134 | text-align: center; 135 | margin-left: 30px; 136 | } 137 | .record-label { 138 | font-size: 15px; 139 | text-align: center; 140 | color: #1B82EB; 141 | width: 100px; 142 | height: 30px; 143 | line-height: 30px; 144 | margin: -15px auto; 145 | background-color: #41F2FD; 146 | border-radius: 15px; 147 | } 148 | 149 | /*以下是projectFunding页面的css*/ 150 | .record{ 151 | position: relative; 152 | margin: 50px; 153 | width: 900px; 154 | height: 350px; 155 | padding-left: 50px; 156 | padding-bottom: 30px; 157 | margin-bottom: 120px; 158 | } 159 | 160 | .customers{ 161 | font-family:"Trebuchet MS", Arial, Helvetica, sans-serif; 162 | border-collapse:collapse; 163 | position: relative; 164 | width: 900px; 165 | margin-top: 40px; 166 | font-size: 19px; 167 | } 168 | 169 | .customers th 170 | { display: inline-block; 171 | font-size:1em; 172 | border:1px solid #ffffff; 173 | margin:5px 10px 15px 10px; 174 | text-align: left; 175 | width: 270px; 176 | } 177 | 178 | .customers td 179 | { display: inline-block; 180 | width: 270px; 181 | white-space: nowrap; 182 | text-overflow: ellipsis; 183 | overflow: hidden; 184 | font-size:1em; 185 | border:1px solid #ffffff; 186 | margin:5px 10px 15px 10px; 187 | } 188 | 189 | /*以下是capitalInjection页面的css*/ 190 | .topNavLogo{ 191 | float: left; 192 | width: 60px; 193 | height: 60px; 194 | margin-top: 5px; 195 | margin-left: 5px; 196 | margin-right: 10px; 197 | } 198 | .topNavName{ 199 | float: left; 200 | line-height: 70px; 201 | font-size: 28px; 202 | color: aliceblue; 203 | } 204 | .container { 205 | width: 100%; 206 | font-size: 0; 207 | } 208 | .container-child { 209 | margin: auto; 210 | width: 1250px; 211 | } 212 | .project { 213 | display: inline-block; 214 | margin-top: 40px; 215 | margin-left: 15px; 216 | margin-right: 15px; 217 | width: 220px; 218 | background: #F8F8FD; 219 | } 220 | .project > .project-cover { 221 | width: 100%; 222 | height: auto; 223 | } 224 | .project > .project-name { 225 | text-align: left; 226 | font-weight: 1000; 227 | font-size: 30px; 228 | padding-left: 10px; 229 | } 230 | .project > .introduction { 231 | text-align: left; 232 | font-size: 20px; 233 | padding-left: 20px; 234 | } 235 | .project > .CC { 236 | color: #FFCC33; 237 | font-size: 20px; 238 | text-align: left; 239 | padding-left: 20px; 240 | } 241 | .head_shot { 242 | padding-left: 15px; 243 | height: 50px; 244 | float: left; 245 | } 246 | 247 | .main{ 248 | width:500px; 249 | margin: auto; 250 | position: relative; 251 | top: 50%; 252 | transform: translateY(-50%); 253 | } 254 | .content{ 255 | padding-left: 20px; 256 | padding-right: 20px; 257 | } 258 | 259 | #injection{ 260 | position:absolute; 261 | left:0px; 262 | top:0px; 263 | /*width:300px; */ 264 | min-height:700px; 265 | } 266 | input[type="text"]{ 267 | border: 2px solid #ccc; 268 | padding: 6px 0px; 269 | border-radius: 10px; 270 | padding-left:20px; 271 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075); 272 | box-shadow: inset 0 1px 1px rgba(0,0,0,.075); 273 | -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s; 274 | -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; 275 | transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s 276 | } 277 | input:focus{ 278 | border-color: #3052e9; 279 | outline: 0; 280 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6); 281 | box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6) 282 | } 283 | 284 | input[type="button"] { 285 | position: relative; 286 | display: inline-block; 287 | background: #D0EEFF; 288 | border: 1px solid #99D3F5; 289 | border-radius: 4px; 290 | padding: 4px 12px; 291 | overflow: hidden; 292 | color: #3052e9; 293 | text-decoration: none; 294 | text-indent: 0; 295 | line-height: 20px; 296 | } 297 | #commit{ 298 | border-style: ridge; 299 | border-radius: 5px; 300 | font-size: 110%; 301 | padding-top: 2px; 302 | padding-bottom: 2px; 303 | margin-left: 15px; 304 | background-color: #ff5b5d; 305 | color: white; 306 | 307 | } 308 | #cancel{ 309 | border-style: ridge; 310 | border-radius: 5px; 311 | font-size: 110%; 312 | padding-top: 2px; 313 | padding-bottom: 2px; 314 | margin-left: 15px; 315 | background-color: white; 316 | color:#ff5b5d; 317 | 318 | } 319 | 320 | 321 | 322 | -------------------------------------------------------------------------------- /src/models/sendEmailToPotentialUsers.go: -------------------------------------------------------------------------------- 1 | // TODO 该文件不应该放在model层, 应该放在service层 2 | package models 3 | 4 | import ( 5 | "encoding/json" 6 | "fmt" 7 | "github.com/PuerkitoBio/goquery" 8 | "github.com/astaxie/beego/utils" 9 | "io/ioutil" 10 | "log" 11 | "net/http" 12 | "net/http/cookiejar" 13 | "net/url" 14 | "time" 15 | ) 16 | 17 | //用于登录时验证 18 | type AuthenticityToken struct { 19 | Token string 20 | } 21 | 22 | //同样用于登录时验证 23 | type TimeStamp struct { 24 | Time string 25 | Secret string 26 | } 27 | 28 | //http请求 29 | type App struct { 30 | Client *http.Client 31 | } 32 | 33 | const ( 34 | baseURL = "https://github.com" 35 | githubUserApi = "https://api.github.com/users/" 36 | ) 37 | 38 | var ( //用于模拟登录,个人账号,请勿登录 39 | username = "kcoinTest" 40 | password = "Kcoin123456." 41 | ) 42 | 43 | //用于接收爬取到的邮箱 44 | type Email struct { 45 | Email string 46 | } 47 | 48 | type UsersApiJson struct { 49 | Login string `json:"login"` 50 | ID int `json:"id"` 51 | NodeID string `json:"node_id"` 52 | AvatarURL string `json:"avatar_url"` 53 | GravatarID string `json:"gravatar_id"` 54 | URL string `json:"url"` 55 | HTMLURL string `json:"html_url"` 56 | FollowersURL string `json:"followers_url"` 57 | FollowingURL string `json:"following_url"` 58 | GistsURL string `json:"gists_url"` 59 | StarredURL string `json:"starred_url"` 60 | SubscriptionsURL string `json:"subscriptions_url"` 61 | OrganizationsURL string `json:"organizations_url"` 62 | ReposURL string `json:"repos_url"` 63 | EventsURL string `json:"events_url"` 64 | ReceivedEventsURL string `json:"received_events_url"` 65 | Type string `json:"type"` 66 | SiteAdmin bool `json:"site_admin"` 67 | Name string `json:"name"` 68 | Company interface{} `json:"company"` 69 | Blog string `json:"blog"` 70 | Location string `json:"location"` 71 | Email string `json:"email"` 72 | Hireable interface{} `json:"hireable"` 73 | Bio interface{} `json:"bio"` 74 | PublicRepos int `json:"public_repos"` 75 | PublicGists int `json:"public_gists"` 76 | Followers int `json:"followers"` 77 | Following int `json:"following"` 78 | CreatedAt time.Time `json:"created_at"` 79 | UpdatedAt time.Time `json:"updated_at"` 80 | } 81 | 82 | /* 83 | func (app *App) GetToken() AuthenticityToken 84 | 该函数用于获取github的登录时的authenticity_token,是一个隐藏的值,相当于验证码 85 | */ 86 | func (app *App) GetToken() (AuthenticityToken, TimeStamp) { 87 | var authenticityToken AuthenticityToken 88 | var timeAndsecret TimeStamp 89 | loginURL := baseURL + "/login" 90 | client := app.Client 91 | response, err := client.Get(loginURL) 92 | if err != nil { 93 | log.Fatalln("Error fetching response. ", err) 94 | return authenticityToken, timeAndsecret 95 | } 96 | defer response.Body.Close() 97 | 98 | document, err := goquery.NewDocumentFromReader(response.Body) 99 | if err != nil { 100 | log.Fatal("Error loading HTTP response body. ", err) 101 | } 102 | 103 | token, exist := document.Find("input[name='authenticity_token']").Attr("value") 104 | if exist != true { 105 | log.Fatal("Error finding authenticity_token,does not exist", exist) 106 | exist = true 107 | } 108 | 109 | fmt.Println("token is", token) 110 | authenticityToken.Token = token 111 | time, exist := document.Find("input[name='timestamp']").Attr("value") 112 | if exist != true { 113 | log.Fatal("Error finding timestamp,does not exist", exist) 114 | exist = true 115 | } 116 | secret, exist := document.Find("input[name='timestamp_secret']").Attr("value") 117 | if exist != true { 118 | log.Fatal("Error finding timestamp,does not exist", exist) 119 | exist = true 120 | } 121 | fmt.Println("timestamp is ", time) 122 | fmt.Println("timestamp_secret is ", secret) 123 | timeAndsecret.Secret = secret 124 | timeAndsecret.Time = time 125 | return authenticityToken, timeAndsecret 126 | } 127 | 128 | /* 129 | func (app *App) Login() 130 | 该函数用于模拟登录,如果不登录,爬取到的内容是“sign up to view email” 131 | */ 132 | func (app *App) Login() { 133 | client := app.Client 134 | //通过GetToken()获得登录所需的动态信息 135 | authenticityToken, timeAndsecret := app.GetToken() 136 | loginURL := baseURL + "/session" 137 | //模拟登录的文件header中的Form data,详情请看github登录时候的发包 138 | data := url.Values{ 139 | "utf8": {"✓"}, 140 | "commit": {"Sign in"}, 141 | "ga_id": {"76806099.1573434977"}, 142 | "login": {username}, 143 | "password": {password}, 144 | "webauthn-support": {"supported"}, 145 | "webauthn-iuvpaa-support": {"unsupported"}, 146 | 147 | "required_field_440e": {}, 148 | "timestamp": {timeAndsecret.Time}, 149 | "timestamp_secret": {timeAndsecret.Secret}, 150 | "authenticity_token": {authenticityToken.Token}, 151 | } 152 | //模拟post请求,发送header 153 | response, err := client.PostForm(loginURL, data) 154 | if err != nil { 155 | fmt.Println(err) 156 | log.Fatalln(err) 157 | } 158 | defer response.Body.Close() 159 | _, err = ioutil.ReadAll(response.Body) 160 | if err != nil { 161 | log.Fatalln(err) 162 | } 163 | fmt.Println("status code is ", response.StatusCode) 164 | fmt.Println("login done") 165 | } 166 | 167 | /* 168 | func (app *App) getEmail(user,githubToken string) Email 169 | 功能:获得用户user的邮箱 170 | 参数:user github用户名 171 | githubToken 此时登录系统的github账号的githubToken 172 | 返回:user对应的邮箱(用户未公布邮箱,未测试) 173 | */ 174 | func (app *App) getEmail(user, githubToken string) Email { 175 | //个人主页,如果邮箱公开,那么会显示在主页 176 | personalURL := githubUserApi + user + "?access_token=" + githubToken 177 | 178 | client := &http.Client{} 179 | response, _ := client.Get(personalURL) 180 | defer response.Body.Close() 181 | body, err := ioutil.ReadAll(response.Body) 182 | if err != nil { 183 | panic(err) 184 | } 185 | var userApiJson UsersApiJson 186 | err = json.Unmarshal(body, &userApiJson) 187 | if err != nil { 188 | log.Fatal("Error Unmarshaling json response body from githubUserApi. ", err) 189 | panic(err) 190 | } 191 | return Email{Email: userApiJson.Email} 192 | } 193 | 194 | /* 195 | func SendEMailToPotentialUsers(users []string)([]string ,error) 196 | 功能:将邮件发送给users中的每一个人 197 | 参数:users 用户列表,github用户名的切片,待发送邮件的名单 198 | githubToken 此时登录系统的github账号的githubToken 199 | 返回:邮箱不对外显示,因此无法发送邮件的成员用户名集合 200 | */ 201 | func SendEMailToPotentialUsers(users []string, githubToken string) ([]string, error) { 202 | jar, _ := cookiejar.New(nil) 203 | app := App{ 204 | Client: &http.Client{Jar: jar}, 205 | } 206 | app.Login() 207 | 208 | //未能成功发送邮件的用户名单 209 | var UsersNotSend []string 210 | for i := 0; i < len(users); i++ { 211 | email := app.getEmail(users[i], githubToken) 212 | if email.Email == "" { 213 | //如果得到邮箱,给他加到列表里,最后返回 214 | UsersNotSend = append(UsersNotSend, users[i]) 215 | } else { 216 | //如果得到了邮箱 217 | config := 218 | `{"username":"kcoin_golang@163.com","password":"kcoin163","host":"smtp.163.com","port":25}` 219 | // 通过存放配置信息的字符串,创建Email对象 220 | temail := utils.NewEMail(config) 221 | // 指定邮件的基本信息 222 | temail.To = []string{email.Email} //指定收件人邮箱地址 223 | temail.From = "kcoin_golang@163.com" //指定发件人的邮箱地址,这是我注册的kcoin项目邮箱,账号kcoin_golang@163.com 密码kcoingolang 224 | temail.Subject = "Kcoin:Welcome to join us" //指定邮件的标题 225 | //这是邮件的内容 226 | temail.HTML = ` 227 | 228 | 229 | 230 |
你好,我们是开原激励社区Kcoin,现在你所在的github项目已经加入Kcoin,我们同样欢迎您的加入
231 | 232 | ` 233 | // 发送邮件 234 | err := temail.Send() 235 | if err != nil { 236 | return UsersNotSend, err 237 | } 238 | } 239 | } 240 | return UsersNotSend, nil 241 | } 242 | -------------------------------------------------------------------------------- /src/models/k_user.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "database/sql" 5 | "encoding/json" 6 | "fmt" 7 | "time" 8 | 9 | "github.com/astaxie/beego/orm" 10 | ) 11 | 12 | type noResultErr int 13 | 14 | func (err noResultErr) Error() string { 15 | return "There is no result." 16 | } 17 | 18 | func GetUserInfo(userName string) (string, error) { 19 | userInfo := UserInfo{} 20 | userInfo.ErrorCode = "default Error" 21 | 22 | maps, err := getSQLQueryResult(userName) 23 | if err != nil { 24 | return fmt.Sprint(userInfo), err 25 | } 26 | 27 | userData := buildProjectsDataFrom(maps) 28 | 29 | // complete userInfo building 30 | userInfo.ErrorCode = "0" 31 | userData.UserName = userName 32 | for i := range maps { 33 | if name := maps[i]["user_name"].(string); name == userName { 34 | userData.HeadShotUrl = maps[i]["head_shot_url"].(string) 35 | } 36 | } 37 | userInfo.Data = userData 38 | 39 | return jsonize(userInfo) 40 | } 41 | 42 | func getSQLQueryResult(userName string) ([]orm.Params, error) { 43 | o := orm.NewOrm() 44 | _ = o.Using("default") 45 | SQLQuery := getUserInfoSQLQuery() 46 | var maps []orm.Params 47 | 48 | if _, err := o.Raw(SQLQuery, userName).Values(&maps); err != nil { 49 | fmt.Println(err.Error()) 50 | return nil, err 51 | } 52 | 53 | if len(maps) == 0 { 54 | return nil, new(noResultErr) 55 | } 56 | return maps, nil 57 | } 58 | 59 | func getUserInfoSQLQuery() string { 60 | return `WITH attend_project AS 61 | ( 62 | SELECT DISTINCT(project_id) AS attended_pro_id from "k_user_in_project" 63 | where user_id in( 64 | SELECT user_id from "k_user" 65 | where user_name=? 66 | ) 67 | ) 68 | 69 | SELECT a.project_name,a.project_url,a.project_cover_url,b.user_name,b.head_shot_url FROM 70 | 71 | (SELECT project_id, project_name,project_url,project_cover_url FROM "k_project" kpro 72 | where kpro.project_id in 73 | (SELECT attended_pro_id FROM attend_project) 74 | ) a 75 | 76 | LEFT JOIN 77 | 78 | (SELECT kuip.project_id,ku.user_name,ku.head_shot_url FROM "k_user_in_project" kuip INNER JOIN "k_user" ku ON kuip.user_id=ku.user_id 79 | where kuip.project_id in 80 | (SELECT attended_pro_id FROM attend_project) 81 | ) b 82 | 83 | ON a.project_id=b.project_id` 84 | } 85 | 86 | func buildProjectsDataFrom(maps []orm.Params) *UserData { 87 | userData := &UserData{} 88 | projectToIndex := make(map[string]int) 89 | index := 0 90 | for i := range maps { 91 | projectName := maps[i]["project_name"].(string) 92 | if _, ok := projectToIndex[projectName]; !ok { 93 | // 如果project name不存在, 那么添加这个projectName, 并且新建这个Project的信息 94 | projectToIndex[projectName] = index 95 | index++ 96 | projectInfo := &Project{} 97 | projectInfo.ProjectName = projectName 98 | projectInfo.ProjectUrl = maps[i]["project_url"].(string) 99 | projectInfo.ProjectCoverUrl = maps[i]["project_cover_url"].(string) 100 | userData.ProjectList = append(userData.ProjectList, projectInfo) 101 | } 102 | member := &UserData{} 103 | member.UserName = maps[i]["user_name"].(string) 104 | member.HeadShotUrl = maps[i]["head_shot_url"].(string) 105 | projectIndex := projectToIndex[projectName] 106 | userData.ProjectList[projectIndex].MemberList = append(userData.ProjectList[projectIndex].MemberList, member) 107 | } 108 | return userData 109 | } 110 | 111 | func jsonize(info UserInfo) (string, error) { 112 | if res, err := json.Marshal(&info); err != nil { 113 | fmt.Println(err.Error()) 114 | return fmt.Sprint(info), err 115 | } else { 116 | return string(res), nil 117 | } 118 | } 119 | 120 | func FinduserByGitId(id string) (UserData, error) { 121 | o := orm.NewOrm() 122 | _ = o.Using("default") 123 | querySql := `select * from "k_user" where github_id = ?` 124 | var maps []orm.Params 125 | var u = UserData{} 126 | _, err := o.Raw(querySql, id).Values(&maps) 127 | if err != nil { 128 | fmt.Println(err.Error()) 129 | } 130 | for i := range maps { 131 | u.UserId = maps[i]["k_user_id"].(string) 132 | u.UserName = maps[i]["user_name"].(string) 133 | } 134 | return u, err 135 | } 136 | func FindUserByUsername(username string) (sql.Result, error) { 137 | o := orm.NewOrm() 138 | _ = o.Using("default") 139 | querySql := `select k_user_id from "k_user" where user_name = ?` 140 | res, err := o.Raw(querySql, username).Exec() 141 | return res, err 142 | } 143 | func GetUseridByUsername(username string) (int, error) { 144 | var k_user_id int 145 | o := orm.NewOrm() 146 | _ = o.Using("default") 147 | querySql := `select k_user_id from "k_user" where user_name = ?` 148 | err := o.Raw(querySql, username).QueryRow(&k_user_id) 149 | return k_user_id, err 150 | } 151 | func InsertIntoKUserInProject(projectId int, userId int) (sql.Result, error) { 152 | o := orm.NewOrm() 153 | _ = o.Using("default") 154 | insertSql := `insert into "k_user_in_project" (project_id,user_id)values(?,?)` 155 | res, err := o.Raw(insertSql, projectId, userId).Exec() 156 | return res, err 157 | } 158 | func InsertIntoKTemporaryUser(inviterId, gitId int, gitName string, projectId int) (sql.Result, error) { 159 | o := orm.NewOrm() 160 | _ = o.Using("default") 161 | insertSql := `insert into "k_temporary_user" (inviter_id,git_id,git_name,project_id,invite_time)values(?,?,?,?,?)` 162 | currentTime := time.Now() 163 | currentTime.Format("2006-01-02 15:04:05:000000") 164 | res, err := o.Raw(insertSql, inviterId, gitId, gitName, projectId, currentTime).Exec() 165 | return res, err 166 | } 167 | func InsertUser(name string, uri string, id string) error { 168 | o := orm.NewOrm() 169 | _ = o.Using("default") 170 | time := time.Now().Format("2006-01-02 15:04:05.000000") 171 | 172 | insertSql := `INSERT INTO "k_user" (USER_NAME,REGISTER_TIME,HEAD_SHOT_URL,GITHUB_ID) VALUES (?,?,?,?);` 173 | _, err := o.Raw(insertSql, name, time, uri, id).Exec() 174 | 175 | return err 176 | } 177 | func IsSupervisor(id string) bool { 178 | o := orm.NewOrm() 179 | _ = o.Using("default") 180 | findSql := `select * from "k_supervisor" where k_user_id= ?` 181 | res, _ := o.Raw(findSql, id).Exec() 182 | if res == nil { 183 | return false 184 | } else if n, _ := res.RowsAffected(); n == 0 { 185 | return false 186 | } 187 | return true 188 | } 189 | func FindUserInKUserInProject(userid int) (int, error) { 190 | o := orm.NewOrm() 191 | _ = o.Using("default") 192 | querySql := `select project_id from "k_user_in_project" where user_id = ?` 193 | res, err := o.Raw(querySql, userid).Exec() 194 | num, err := res.RowsAffected() 195 | return int(num), err 196 | } 197 | 198 | func InsertKCsChangeRecord(projectId int, projectName string, acceptUserId int, acceptUserName string, csAmount int) (sql.Result, error) { 199 | o := orm.NewOrm() 200 | insertSql := `insert into "k_cs_change_record"(distribute_project_id,distribute_project_name,accept_user_id,accept_user_name,cs_amount,distribute_time)values(?,?,?,?,?,?)` 201 | currentTime := time.Now() 202 | currentTime.Format("2006-01-02 15:04:05:000000") 203 | res, err := o.Raw(insertSql, projectId, projectName, acceptUserId, acceptUserName, csAmount, currentTime).Exec() 204 | return res, err 205 | 206 | } 207 | 208 | //该函数通过项目id获取该项目的所有成员信息 209 | func GetMembersInfoByProjectName(projectName string) (membersInfo []*UserData, err error) { 210 | var memberlist []*UserData 211 | var projectid int 212 | o := orm.NewOrm() 213 | o.Using("default") 214 | queryProjectIDSql := getProjectIDQuery() 215 | if err = o.Raw(queryProjectIDSql, projectName).QueryRow(&projectid); err != nil { 216 | fmt.Print(err.Error()) 217 | return nil, err 218 | } 219 | 220 | queryMembersInProjectSql := getAllMemberQuery() 221 | if _, err = o.Raw(queryMembersInProjectSql, projectid).QueryRows(&memberlist); err != nil { 222 | fmt.Print(err.Error()) 223 | return nil, err 224 | } 225 | 226 | return memberlist, nil 227 | } 228 | 229 | //通过连接k_user表和k_user_in_project表查询用户信息 230 | func getAllMemberQuery() string { 231 | return `SELECT u.k_user_id, u.user_name, u.head_shot_url 232 | FROM "k_user" u LEFT JOIN "k_user_in_project" up on u.k_user_id = up.user_id 233 | WHERE up.project_id = ?` 234 | } 235 | 236 | //ProjectId只能通过查询K_project表获取,所以getProjectId函数通过函数名查询ProjectId后返回 237 | func getProjectIDQuery() string { 238 | return `SELECT project_id FROM "k_project" WHERE project_name = ?` 239 | } 240 | -------------------------------------------------------------------------------- /src/static/css/project.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* CSS Document */ 3 | 4 | /*以下是projectTopNav页面用到的css*/ 5 | body { 6 | margin: 0; 7 | } 8 | 9 | a:link,a:visited,a:hover,a:active 10 | { 11 | color: #1B1B1B; 12 | text-decoration:none; 13 | } 14 | 15 | .head { 16 | position: relative; 17 | height: 70px; 18 | background-color: #333333; 19 | } 20 | .navigation { 21 | position: relative; 22 | height: 160px; 23 | padding-left: 100px; 24 | background-color: #bfbfbf; 25 | } 26 | .navigation > img { 27 | position: absolute; 28 | width: 150px; 29 | height: 100%; 30 | border-style: solid; 31 | border-width: 6px; 32 | border-color: #FFFFFF; 33 | border-radius: 5px; 34 | margin-left: 50px; 35 | margin-top: 20px; 36 | } 37 | .navigation > .prj-name { 38 | position: absolute; 39 | font-size: 60px; 40 | margin-left: 250px; 41 | margin-top: 30px; 42 | color: #323a45; 43 | } 44 | 45 | .navigation > .invest{ 46 | position: absolute; 47 | right: 150px; 48 | top: 50px; 49 | width: 100px; 50 | height: 50px; 51 | text-align: center; 52 | background-color: rgb(56, 212, 69); 53 | border-radius: 20px; 54 | font-size: 25px; 55 | cursor: pointer; 56 | border: none; 57 | outline: none; 58 | } 59 | 60 | 61 | .navigation > .starNum{ 62 | position:absolute; 63 | right: 300px; 64 | top: 60px; 65 | font-size: 20px; 66 | 67 | } 68 | 69 | 70 | .navigation > .first { 71 | margin-left: 250px; 72 | 73 | } 74 | .navigation > a { 75 | float: left; 76 | margin-top: 110px; 77 | margin-left: 40px; 78 | padding-left: 10px; 79 | padding-right: 10px; 80 | padding-top: 5px; 81 | border-radius: 10px; 82 | font-size: 30px; 83 | height: 60px; 84 | } 85 | 86 | .topNavLogo{ 87 | float: left; 88 | width: 60px; 89 | height: 60px; 90 | margin-top: 5px; 91 | margin-left: 5px; 92 | margin-right: 10px; 93 | } 94 | 95 | .topNavName{ 96 | float: left; 97 | line-height: 70px; 98 | font-size: 28px; 99 | color: aliceblue; 100 | } 101 | 102 | /*以下是projectInfo页面的css*/ 103 | .projectInfo-container { 104 | margin: auto; 105 | width: 1200px; 106 | font-size: 0; 107 | } 108 | .projectInfo-card { 109 | display: inline-block; 110 | vertical-align: top; 111 | border-style: solid; 112 | border-width: 4px; 113 | border-radius: 10px; 114 | border-color: #bfbfbf; 115 | width: 500px; 116 | height: 500px; 117 | margin-top: 70px; 118 | margin-left: 46px; 119 | margin-right: 46px; 120 | } 121 | .projectInfo-card-head { 122 | height: 70px; 123 | background-color: #bfbfbf; 124 | } 125 | .projectInfo-card-title { 126 | display: inline-block; 127 | vertical-align: bottom; 128 | font-size: 25px; 129 | height: 70px; 130 | line-height: 70px; 131 | text-align: center; 132 | margin-left: 20px; 133 | } 134 | .projectInfo-card-value { 135 | display: inline-block; 136 | vertical-align: bottom; 137 | font-size: 35px; 138 | font-weight: bold; 139 | color: #ff3600; 140 | height: 70px; 141 | line-height: 70px; 142 | text-align: center; 143 | margin-left: 300px; 144 | } 145 | .projectInfo-record-label { 146 | font-size: 15px; 147 | text-align: center; 148 | width: 100px; 149 | height: 30px; 150 | line-height: 30px; 151 | margin: -15px auto; 152 | background-color: #FFFFFF; 153 | border-radius: 15px; 154 | } 155 | 156 | .projectInfo-card-rule { 157 | display: inline-block; 158 | vertical-align: top; 159 | border-style: solid; 160 | border-width: 4px; 161 | border-radius: 10px; 162 | border-color: #bfbfbf; 163 | width: 1100px; 164 | height: 350px; 165 | margin-top: 70px; 166 | margin-left: 46px; 167 | margin-right: 46px; 168 | } 169 | 170 | /*以下是projectNotice页面的css*/ 171 | .container { 172 | width: 1200px; 173 | padding-left: 150px; 174 | padding-top: 150px; 175 | font-size: 20px; 176 | 177 | } 178 | 179 | .yearNode { /*表示年份的结点*/ 180 | width: 80px; 181 | height: 30px; 182 | border-radius: 15px; /*给矩形增加圆角*/ 183 | background-color: #ff7070; 184 | position: relative; 185 | left: -45px; 186 | top: 30px; 187 | text-align: center; 188 | margin-bottom: 100px; 189 | } 190 | 191 | 192 | .time-vertical { 193 | list-style-type: none; 194 | border-left: 10px solid #ff7070;/*左侧边界,显示效果为纵向的时间线*/ 195 | margin-left: 10px; 196 | padding: 0px; 197 | } 198 | 199 | .time-vertical div { 200 | height: 100px; 201 | position: relative; 202 | } 203 | 204 | .time-vertical div a { 205 | display: inline-block; 206 | margin-left: 20px; 207 | margin-top: 15px; 208 | text-decoration: none; 209 | color: #000; 210 | } 211 | 212 | .time-vertical div b:before { 213 | content: ''; 214 | position: absolute; 215 | top: 15px; 216 | left: -16px; 217 | width: 18px; 218 | height: 18px; 219 | border: 2px solid #ff7070; 220 | border-radius: 10px; 221 | background: #fff; 222 | vertical-align: middle; 223 | } 224 | 225 | .time-vertical div span { 226 | position: absolute; 227 | color: #ff5050; 228 | top: 18px; 229 | left: -65px; 230 | } 231 | 232 | /*以下是projectMemberList页面的css*/ 233 | .memberListContainer{ 234 | background-color: white; 235 | margin: auto; 236 | margin-top: 80px; 237 | width: 1200px; 238 | height: 300px; 239 | } 240 | .memberItem{ 241 | float:left; 242 | width: 600px; 243 | height: 125px; 244 | background-color: white; 245 | display: flex; 246 | } 247 | .pageList{ 248 | position: relative; 249 | width: 100%; 250 | height: 50px; 251 | background-color: white; 252 | } 253 | .lookMore{ 254 | line-height: 50px; 255 | } 256 | .lookMore > a{ 257 | position: relative; 258 | left: 92%; 259 | color:cadetblue; 260 | } 261 | .memberItem > .headShot{ 262 | float:left; 263 | width: 125px; 264 | height: 125px; 265 | } 266 | .memberItem > .memberInfo{ 267 | float: left; 268 | width: 175px; 269 | height: 125px; 270 | } 271 | 272 | /*以下是projectSetting.html页面的css*/ 273 | .projectsetting{ 274 | margin-top: 60px; 275 | height: 282px; 276 | } 277 | .projectsetting p1{ 278 | display:block; 279 | color: #A9AFB5; 280 | margin-top: 110px; 281 | margin-left: 20px; 282 | font-size: 16px; 283 | } 284 | .projectsetting p2{ 285 | display:block; 286 | margin-left: 20px; 287 | color: #A9AFB5; 288 | font-size: 16px; 289 | } 290 | .projectsetting p3{ 291 | display:block; 292 | margin-left: 20px; 293 | color: #A9AFB5; 294 | font-size: 16px; 295 | } 296 | .upload-pjname { 297 | display:block; 298 | font-size: 16px; 299 | width: 1150px; 300 | height: 35px; 301 | border-radius: 5px; 302 | outline: none; 303 | border: 1px solid #B5B3B3; 304 | margin-top: 10px; 305 | margin-left: 20px; 306 | } 307 | .upload-button { 308 | display:block; 309 | width: 70px; 310 | margin-top: 10px; 311 | margin-left:20px; 312 | border:2px solid #27D5F5; 313 | padding:10px; 314 | border-radius: 10px; 315 | color: #27D5F5; 316 | } 317 | 318 | textarea.projectintro{ 319 | border-style: ridge; 320 | border-radius: 5px; 321 | padding: 5px; 322 | color:gray; 323 | font-size: 110%; 324 | margin-left: 20px; 325 | width: 1140px; 326 | height:100px; 327 | } 328 | 329 | /*以下是projectMemberWork.html页面的css*/ 330 | .work-mainInterface{ 331 | background-color: #FFFFFF; 332 | position: relative; 333 | min-height: 70vh; 334 | width: 100%; 335 | font-size: 20px; 336 | } 337 | 338 | .work-record{ 339 | position: relative; 340 | margin: 50px; 341 | width: 900px; 342 | height: 150px; 343 | top:60px 344 | } 345 | 346 | .work-customers{ 347 | font-family:"Trebuchet MS", Arial, Helvetica, sans-serif; 348 | width:100%; 349 | border-collapse:collapse; 350 | margin-top: 20px; 351 | } 352 | 353 | .work-customers th { 354 | font-size:1em; 355 | border:0px solid #ffffff; 356 | padding:3px 7px 15px 7px; 357 | 358 | } 359 | 360 | .work-customers td{ 361 | font-size:1em; 362 | border:0px solid #ffffff; 363 | padding:3px 7px 2px 7px; 364 | text-align: center; 365 | } 366 | 367 | .work-back{ 368 | position: absolute; 369 | font-size: 15px; 370 | left: 25px; 371 | top: 15px; 372 | color: rgb(75, 192, 238); 373 | } 374 | -------------------------------------------------------------------------------- /src/static/css/personal.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | 4 | /*以下是personalPage页面的css*/ 5 | *{ 6 | border: 0; 7 | margin: 0; 8 | } 9 | 10 | body{ 11 | font:19px/1.5 Microsoft YaHei; 12 | position:relative; 13 | margin:0 auto; 14 | background-color:#ece9ecfd; 15 | } 16 | a:link,a:visited,a:hover,a:active 17 | { 18 | color: #1B1B1B; 19 | text-decoration:none; 20 | } 21 | ul { 22 | list-style-type:none; 23 | margin:0; 24 | padding:0; 25 | } 26 | 27 | #container{ 28 | position: relative; 29 | width: 100%; 30 | height: 1200px; 31 | } 32 | 33 | .left-nav{ 34 | background-color: #ece9ecfd; 35 | position: relative; 36 | float: left; 37 | width: 20%; 38 | } 39 | 40 | .mainInterface{ 41 | background-color: #FFFFFF; 42 | position: relative; 43 | min-height: 100vh; 44 | float: left; 45 | width: 80%; 46 | height: 100%; 47 | } 48 | 49 | .banner{ 50 | background-color: #8a818afd; 51 | position:relative; 52 | padding-top: 10px; 53 | padding-left: 10px; 54 | vertical-align: middle; 55 | width: 100%; 56 | height: 40px; 57 | } 58 | 59 | .information{ 60 | position: relative; 61 | width: 100%; 62 | height: 250px; 63 | text-align: center; 64 | padding-top: 30px; 65 | padding-top: 50px; 66 | } 67 | 68 | .list{ 69 | position: relative; 70 | padding-top: 30px; 71 | width: 100%; 72 | height: 100%; 73 | text-align: center; 74 | } 75 | 76 | .money{ 77 | position: relative; 78 | box-shadow: 0px 3px 7px #000000; 79 | margin: 50px; 80 | width: 900px; 81 | height: 150px; 82 | border: 0px; 83 | border-radius: 15px; 84 | border-style: solid; 85 | border-color:#4da5b4fd; 86 | padding: 2px; 87 | } 88 | 89 | .record{ 90 | position: relative; 91 | margin: 50px; 92 | width: 900px; 93 | height: 150px; 94 | } 95 | 96 | .token{ 97 | position: absolute; 98 | margin-top: 200px; 99 | width: 900px; 100 | height: 150px; 101 | } 102 | 103 | .list a{ 104 | display:block; 105 | font-weight:bold; 106 | width:100%; 107 | height: 60px; 108 | text-align: center; 109 | } 110 | 111 | .sermore{ 112 | margin-left: 550px; 113 | font-weight: 500; 114 | font-size: 18px; 115 | color: #c00; 116 | } 117 | 118 | .customers 119 | { 120 | font-family:"Trebuchet MS", Arial, Helvetica, sans-serif; 121 | width:120%; 122 | border-collapse:collapse; 123 | margin-top: 20px; 124 | } 125 | .customers th 126 | { display: inline-block; 127 | border:0px solid #ffffff; 128 | font-size:1em; 129 | text-align:left; 130 | margin-top:30px; 131 | margin-right:80px; 132 | background-color:#FFFFFF; 133 | width: 200px; 134 | } 135 | .customers td 136 | { display: inline-block; 137 | border:0px solid #ffffff; 138 | font-size:1em; 139 | text-align:left; 140 | margin-top:30px; 141 | margin-right:80px; 142 | background-color:#FFFFFF; 143 | width: 200px; 144 | } 145 | .customers tr.alt td 146 | { 147 | color:#000000; 148 | background-color:#e2e0e0; 149 | } 150 | 151 | ul.pagination { 152 | position: absolute; 153 | display: inline-block; 154 | padding: 0; 155 | margin: 10px; 156 | margin-top: 80px; 157 | 158 | } 159 | 160 | ul.pagination li {display: inline;} 161 | 162 | ul.pagination li a { 163 | color: black; 164 | float: left; 165 | padding: 3px 6px; 166 | text-decoration: none; 167 | transition: background-color .3s; 168 | border: 1px solid #ddd; 169 | margin: 0 4px; 170 | } 171 | 172 | ul.pagination li a.active { 173 | background-color: rgb(176, 225, 248); 174 | color: white; 175 | border: 1px solid rgb(176, 225, 248); 176 | } 177 | 178 | ul.pagination li a:hover:not(.active) {background-color: #ddd;} 179 | 180 | 181 | 182 | /*以下是personalProjects页面的css*/ 183 | .container { 184 | width: 100%; 185 | text-align: center; 186 | float: left; 187 | } 188 | 189 | .addprojbar { 190 | width: 100%; 191 | height: 60px; 192 | float: left; 193 | font-size: 25px; 194 | border: 1px; 195 | } 196 | 197 | .project { 198 | display: inline-block; 199 | margin-top: 40px; 200 | margin-left: 10px; 201 | margin-right: 10px; 202 | width: 300px; 203 | background: #F8F8FD; 204 | } 205 | .project > .project-cover { 206 | width: 100%; 207 | height: auto; 208 | } 209 | .project > .project-name { 210 | text-align: left; 211 | font-weight: 1000; 212 | font-size: 30px; 213 | padding-left: 10px; 214 | } 215 | .project > .introduction { 216 | text-align: left; 217 | padding-left: 20px; 218 | } 219 | .project > .CC { 220 | color: #FFCC33; 221 | font-size: 20px; 222 | text-align: left; 223 | padding-left: 20px; 224 | } 225 | .head_shot { 226 | padding-left: 15px; 227 | height: 50px; 228 | float: left; 229 | } 230 | 231 | 232 | 233 | /*表示点击按钮后,其他区域阴影*/ 234 | .black_overlay{ 235 | display: none; 236 | position: absolute; 237 | top: 0%; 238 | left: 0%; 239 | width: 100%; 240 | height: 100%; 241 | background-color: black; 242 | z-index:1001; 243 | -moz-opacity: 0.8; 244 | opacity:.80; 245 | filter: alpha(opacity=88); 246 | } 247 | 248 | /*以下为点击按钮后高亮的图层*/ 249 | 250 | .main{ 251 | width:800px; 252 | margin: auto; 253 | position: relative; 254 | top: 50%; 255 | transform: translateY(-50%); 256 | } 257 | .content{ 258 | padding-left: 20px; 259 | padding-right: 20px; 260 | } 261 | 262 | .steps { 263 | position: relative; 264 | counter-reset: step; /*创建步骤数字计数器*/ 265 | margin:0; 266 | padding:0; 267 | } 268 | 269 | /*步骤描述*/ 270 | .steps li { 271 | list-style-type: none; 272 | font-size: 12px; 273 | color:black; 274 | text-align: center; 275 | width: 33.3%; 276 | position: relative; 277 | float: left; 278 | padding-bottom: 5px; 279 | } 280 | /*步骤数字*/ 281 | .steps li:before { 282 | display: block; 283 | content: counter(step); /*设定计数器内容*/ 284 | counter-increment: step; /*计数器值递增*/ 285 | width: 32px; 286 | height: 32px; 287 | background-color: #ffd7d8; 288 | line-height: 32px; 289 | border-radius: 32px; 290 | font-size: 16px; 291 | color: white; 292 | text-align: center; 293 | font-weight: 700; 294 | margin: 0 auto 8px auto; 295 | } 296 | 297 | /*连接线*/ 298 | .steps li ~ li:after { 299 | content: ''; 300 | width: 100%; 301 | height: 2px; 302 | background-color: #ffd7d8; 303 | position: absolute; 304 | left: -50%; 305 | top: 15px; 306 | z-index: -1; /*放置在数字后面*/ 307 | } 308 | 309 | .steps li.active:before, 310 | .steps li.active:after { 311 | background-color: #ff5b5d; 312 | } 313 | 314 | img.profile{ 315 | height: 25px; 316 | } 317 | #username{ 318 | font-weight:bold; 319 | } 320 | #userprojects{ 321 | color:gray; 322 | } 323 | ul.projects{ 324 | list-style-position: outside; 325 | font-size:130%; 326 | padding: 0px; 327 | } 328 | .projects li{ 329 | margin-top:5px; 330 | list-style-type: none; 331 | border-radius: 5px; 332 | background-color:#edf0f5; 333 | padding: 5px; 334 | } 335 | 336 | #managed_projects{ 337 | display: none; 338 | } 339 | 340 | /* 参加项目和管理项目头部 */ 341 | a:link,a:visited,a:hover,a:active 342 | { 343 | color: #1B1B1B; 344 | text-decoration:none; 345 | } 346 | 347 | .navigation > .first { 348 | margin-left: 40px; 349 | background-color:#bfbfbf; 350 | } 351 | .navigation > a { 352 | float: left; 353 | margin-top: 20px; 354 | margin-left: 40px; 355 | padding-left: 10px; 356 | padding-right: 10px; 357 | padding-top: 5px; 358 | border-radius: 10px; 359 | font-size: 30px; 360 | height: 60px; 361 | } 362 | 363 | textarea.projectintro{ 364 | border-style: ridge; 365 | border-radius: 5px; 366 | padding: 5px; 367 | color:gray; 368 | font-size: 110%; 369 | width:98%; 370 | height:100px; 371 | } 372 | 373 | /*以下是import.tpl页面用到的css*/ 374 | html, body { 375 | width: 100%; 376 | height: 100%; 377 | margin: 0; 378 | padding: 0; 379 | } 380 | 381 | .main{ 382 | width:800px; 383 | margin: auto; 384 | position: relative; 385 | top: 50%; 386 | transform: translateY(-50%); 387 | } 388 | .content{ 389 | padding-left: 20px; 390 | padding-right: 20px; 391 | } 392 | 393 | .steps { 394 | position: relative; 395 | counter-reset: step; /*创建步骤数字计数器*/ 396 | margin:0; 397 | padding:0; 398 | } 399 | 400 | /*步骤描述*/ 401 | .steps li { 402 | list-style-type: none; 403 | font-size: 12px; 404 | color:black; 405 | text-align: center; 406 | width: 33.3%; 407 | position: relative; 408 | float: left; 409 | padding-bottom: 5px; 410 | } 411 | /*步骤数字*/ 412 | .steps li:before { 413 | display: block; 414 | content: counter(step); /*设定计数器内容*/ 415 | counter-increment: step; /*计数器值递增*/ 416 | width: 32px; 417 | height: 32px; 418 | background-color: #ffd7d8; 419 | line-height: 32px; 420 | border-radius: 32px; 421 | font-size: 16px; 422 | color: white; 423 | text-align: center; 424 | font-weight: 700; 425 | margin: 0 auto 8px auto; 426 | } 427 | 428 | /*连接线*/ 429 | .steps li ~ li:after { 430 | content: ''; 431 | width: 100%; 432 | height: 2px; 433 | background-color: #ffd7d8; 434 | position: absolute; 435 | left: -50%; 436 | top: 15px; 437 | z-index: -1; /*放置在数字后面*/ 438 | } 439 | 440 | .steps li.active:before, 441 | .steps li.active:after { 442 | background-color: #ff5b5d; 443 | } 444 | 445 | /*主体*/ 446 | input.url_input{ 447 | border-style: ridge; 448 | border-radius: 5px; 449 | margin-top: 5px; 450 | padding-left: 5px; 451 | padding-top: 5px; 452 | padding-bottom: 5px; 453 | color:gray; 454 | font-size: 110%; 455 | width:90%; 456 | } 457 | 458 | input.submit{ 459 | border-style: ridge; 460 | border-radius: 5px; 461 | background-color:white; 462 | color:#ff5b5d; 463 | font-size: 110%; 464 | padding-top: 2px; 465 | padding-bottom: 2px; 466 | margin-left: 5px; 467 | } 468 | 469 | h1 { 470 | background-color: #434343; 471 | padding-top: 5px; 472 | padding-bottom: 5px; 473 | padding-left: 20px; 474 | color:white; 475 | font-weight:normal; 476 | font-size: 160%; 477 | } 478 | 479 | img.profile{ 480 | height: 25px; 481 | } 482 | 483 | #username{ 484 | font-weight:bold; 485 | } 486 | 487 | #userprojects{ 488 | color:gray; 489 | } 490 | 491 | ul.projects{ 492 | list-style-position: outside; 493 | font-size:130%; 494 | padding: 0px; 495 | } 496 | 497 | .projects li{ 498 | margin-top:5px; 499 | list-style-type: none; 500 | border-radius: 5px; 501 | background-color:#edf0f5; 502 | padding: 5px; 503 | } 504 | 505 | #next_back{ 506 | margin-top: 20px; 507 | } 508 | 509 | button.back{ 510 | border-style: ridge; 511 | border-radius: 5px; 512 | color:#ff5b5d; 513 | background-color: white; 514 | font-size: 110%; 515 | padding-top: 2px; 516 | padding-bottom: 2px; 517 | /* float:right; */ 518 | margin-left: 590px; 519 | margin-bottom: 20px; 520 | } 521 | 522 | button.next{ 523 | border-style: ridge; 524 | border-radius: 5px; 525 | font-size: 110%; 526 | padding-top: 2px; 527 | padding-bottom: 2px; 528 | margin-left: 15px; 529 | background-color: #ff5b5d; 530 | color:white; 531 | float:right; 532 | } 533 | button.confirm{ 534 | border-style: ridge; 535 | border-radius: 5px; 536 | font-size: 110%; 537 | padding-top: 2px; 538 | padding-bottom: 2px; 539 | margin-left: 15px; 540 | background-color: #ff5b5d; 541 | color:white; 542 | float:right; 543 | display: none; 544 | } 545 | 546 | #myprojects{ 547 | display: block; 548 | } 549 | 550 | #init_message{ 551 | display: none; 552 | } 553 | #config_project{ 554 | display: none; 555 | } 556 | 557 | #config_project p{ 558 | color:gray; 559 | } 560 | 561 | input.projectname{ 562 | border-style: ridge; 563 | border-radius: 5px; 564 | padding: 5px; 565 | color:gray; 566 | font-size: 110%; 567 | width:98%; 568 | } 569 | 570 | .upload{ 571 | padding: 4px 10px; 572 | border-style: ridge; 573 | border-radius: 5px; 574 | border: 1px solid #999; 575 | text-decoration: none; 576 | color: #ff5b5d; 577 | } 578 | 579 | .change{ 580 | border-style: ridge; 581 | border-radius: 5px; 582 | color:#ff5b5d; 583 | font-size: 25px; 584 | overflow: hidden; 585 | position: absolute; 586 | left:20px; 587 | bottom: 65px; 588 | opacity:0; 589 | width:90px; 590 | } 591 | 592 | -------------------------------------------------------------------------------- /src/views/personalPage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 个人中心 5 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | {{template "./leftNav.html" .}} 17 |
18 | 21 | 22 |
23 |
24 | 25 | Kcoin
26 | {{.remainingCc}} 27 |
28 |
29 | Kcoin记录 30 | 查看更多 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 |
日期操作类型cc数量
11.19sell-1000
11.20buy+5000
11.21sell-1500
11.22sell-1000
日期操作类型cc数量
11.23sell-1500
11.24sell-2000
11.25buy+3000
11.26sell-2500
日期操作类型cc数量
11.27buy+1000
11.28sell-1500
11.29sell-1000
11.30sell-2000
日期操作类型cc数量
12.01buy+4000
12.02sell-1000
12.03buy+6000
12.04sell-1500
日期操作类型cc数量
12.05sell-1000
12.06sell-1500
12.07sell-1000
12.08buy+1000
161 | 171 |
172 | 173 | 174 | 175 | 176 |
177 |
178 | 179 |
180 | 项目token记录 181 |

cs数

182 |

{{.user.Data.CsNum}}

183 |
184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 |
日期操作类型cc数量
11.19sell-1000
11.20buy+5000
11.21sell-1500
11.22sell-1000
日期操作类型cc数量
11.23sell-1500
11.24sell-2000
11.25buy+3000
11.26sell-2500
日期操作类型cc数量
11.27buy+1000
11.28sell-1500
11.29sell-1000
11.30sell-2000
日期操作类型cc数量
12.01buy+4000
12.02sell-1000
12.03buy+6000
12.04sell-1500
日期操作类型cc数量
12.05sell-1000
12.06sell-1500
12.07sell-1000
12.08buy+1000
315 | 325 | 326 | 327 | 328 | 329 |
330 |
331 |
332 |
333 | 334 | -------------------------------------------------------------------------------- /src/service/github_helper.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "fmt" 8 | "github.com/astaxie/beego" 9 | "io/ioutil" 10 | "net/http" 11 | "strings" 12 | "time" 13 | ) 14 | 15 | /** 16 | * 这是一个全局数据结构,目前只有三个字段,用来保存GithubID, Github Name和对应access_token 17 | */ 18 | type GithubInfo struct { 19 | GithubId string 20 | GithubName string 21 | AccessToken string 22 | } 23 | 24 | // TODO 妥善使用该数据结构, 用户信息应该用session保存, 可以建立一个sessionID->session的映射, 但是不太清楚session如何使用, 这里需要会的人来修改这个丑陋的数据结构 25 | //Github UserID -> GithubInfo 26 | //type GithubUserMap map[string]*GithubInfo 27 | 28 | //var GithubUser GithubUserMap 29 | 30 | // struct for github api: "https://api.github.com/repos/"+userName+"/"+programName发送请求后的返回值 31 | type JsonData struct { 32 | ID int `json:"id"` 33 | NodeID string `json:"node_id"` 34 | Name string `json:"name"` 35 | FullName string `json:"full_name"` 36 | Private bool `json:"private"` 37 | Owner struct { 38 | Login string `json:"login"` 39 | ID int `json:"id"` 40 | NodeID string `json:"node_id"` 41 | AvatarURL string `json:"avatar_url"` 42 | GravatarID string `json:"gravatar_id"` 43 | URL string `json:"url"` 44 | HTMLURL string `json:"html_url"` 45 | FollowersURL string `json:"followers_url"` 46 | FollowingURL string `json:"following_url"` 47 | GistsURL string `json:"gists_url"` 48 | StarredURL string `json:"starred_url"` 49 | SubscriptionsURL string `json:"subscriptions_url"` 50 | OrganizationsURL string `json:"organizations_url"` 51 | ReposURL string `json:"repos_url"` 52 | EventsURL string `json:"events_url"` 53 | ReceivedEventsURL string `json:"received_events_url"` 54 | Type string `json:"type"` 55 | SiteAdmin bool `json:"site_admin"` 56 | } `json:"owner"` 57 | HTMLURL string `json:"html_url"` 58 | Description interface{} `json:"description"` 59 | Fork bool `json:"fork"` 60 | URL string `json:"url"` 61 | ForksURL string `json:"forks_url"` 62 | KeysURL string `json:"keys_url"` 63 | CollaboratorsURL string `json:"collaborators_url"` 64 | TeamsURL string `json:"teams_url"` 65 | HooksURL string `json:"hooks_url"` 66 | IssueEventsURL string `json:"issue_events_url"` 67 | EventsURL string `json:"events_url"` 68 | AssigneesURL string `json:"assignees_url"` 69 | BranchesURL string `json:"branches_url"` 70 | TagsURL string `json:"tags_url"` 71 | BlobsURL string `json:"blobs_url"` 72 | GitTagsURL string `json:"git_tags_url"` 73 | GitRefsURL string `json:"git_refs_url"` 74 | TreesURL string `json:"trees_url"` 75 | StatusesURL string `json:"statuses_url"` 76 | LanguagesURL string `json:"languages_url"` 77 | StargazersURL string `json:"stargazers_url"` 78 | ContributorsURL string `json:"contributors_url"` 79 | SubscribersURL string `json:"subscribers_url"` 80 | SubscriptionURL string `json:"subscription_url"` 81 | CommitsURL string `json:"commits_url"` 82 | GitCommitsURL string `json:"git_commits_url"` 83 | CommentsURL string `json:"comments_url"` 84 | IssueCommentURL string `json:"issue_comment_url"` 85 | ContentsURL string `json:"contents_url"` 86 | CompareURL string `json:"compare_url"` 87 | MergesURL string `json:"merges_url"` 88 | ArchiveURL string `json:"archive_url"` 89 | DownloadsURL string `json:"downloads_url"` 90 | IssuesURL string `json:"issues_url"` 91 | PullsURL string `json:"pulls_url"` 92 | MilestonesURL string `json:"milestones_url"` 93 | NotificationsURL string `json:"notifications_url"` 94 | LabelsURL string `json:"labels_url"` 95 | ReleasesURL string `json:"releases_url"` 96 | DeploymentsURL string `json:"deployments_url"` 97 | CreatedAt time.Time `json:"created_at"` 98 | UpdatedAt time.Time `json:"updated_at"` 99 | PushedAt time.Time `json:"pushed_at"` 100 | GitURL string `json:"git_url"` 101 | SSHURL string `json:"ssh_url"` 102 | CloneURL string `json:"clone_url"` 103 | SvnURL string `json:"svn_url"` 104 | Homepage interface{} `json:"homepage"` 105 | Size int `json:"size"` 106 | StargazersCount int `json:"stargazers_count"` 107 | WatchersCount int `json:"watchers_count"` 108 | Language string `json:"language"` 109 | HasIssues bool `json:"has_issues"` 110 | HasProjects bool `json:"has_projects"` 111 | HasDownloads bool `json:"has_downloads"` 112 | HasWiki bool `json:"has_wiki"` 113 | HasPages bool `json:"has_pages"` 114 | ForksCount int `json:"forks_count"` 115 | MirrorURL interface{} `json:"mirror_url"` 116 | Archived bool `json:"archived"` 117 | Disabled bool `json:"disabled"` 118 | OpenIssuesCount int `json:"open_issues_count"` 119 | License interface{} `json:"license"` 120 | Forks int `json:"forks"` 121 | OpenIssues int `json:"open_issues"` 122 | Watchers int `json:"watchers"` 123 | DefaultBranch string `json:"default_branch"` 124 | Organization struct { 125 | Login string `json:"login"` 126 | ID int `json:"id"` 127 | NodeID string `json:"node_id"` 128 | AvatarURL string `json:"avatar_url"` 129 | GravatarID string `json:"gravatar_id"` 130 | URL string `json:"url"` 131 | HTMLURL string `json:"html_url"` 132 | FollowersURL string `json:"followers_url"` 133 | FollowingURL string `json:"following_url"` 134 | GistsURL string `json:"gists_url"` 135 | StarredURL string `json:"starred_url"` 136 | SubscriptionsURL string `json:"subscriptions_url"` 137 | OrganizationsURL string `json:"organizations_url"` 138 | ReposURL string `json:"repos_url"` 139 | EventsURL string `json:"events_url"` 140 | ReceivedEventsURL string `json:"received_events_url"` 141 | Type string `json:"type"` 142 | SiteAdmin bool `json:"site_admin"` 143 | } `json:"organization"` 144 | NetworkCount int `json:"network_count"` 145 | SubscribersCount int `json:"subscribers_count"` 146 | } 147 | 148 | // struct for github api: "https://api.github.com/repos/" + userName + "/" + programName + "/" + "contributors" 149 | type ContributorData []struct { 150 | Login string `json:"login"` 151 | ID int `json:"id"` 152 | NodeID string `json:"node_id"` 153 | AvatarURL string `json:"avatar_url"` 154 | GravatarID string `json:"gravatar_id"` 155 | URL string `json:"url"` 156 | HTMLURL string `json:"html_url"` 157 | FollowersURL string `json:"followers_url"` 158 | FollowingURL string `json:"following_url"` 159 | GistsURL string `json:"gists_url"` 160 | StarredURL string `json:"starred_url"` 161 | SubscriptionsURL string `json:"subscriptions_url"` 162 | OrganizationsURL string `json:"organizations_url"` 163 | ReposURL string `json:"repos_url"` 164 | EventsURL string `json:"events_url"` 165 | ReceivedEventsURL string `json:"received_events_url"` 166 | Type string `json:"type"` 167 | SiteAdmin bool `json:"site_admin"` 168 | Contributions int `json:"contributions"` 169 | } 170 | 171 | // struct for github api: "https://api.github.com/users/" + username 172 | type API_User struct { 173 | Login string `json:"login"` 174 | Id int `json:"id"` 175 | Node_id string `json:"node_id"` 176 | Avatar_url string `json:"avatar_url"` 177 | Gravatar_id string `json:"gravatar_id"` 178 | Url string `json:"url"` 179 | Html_url string `json:"html_url"` 180 | Followers_url string `json:"followers_url"` 181 | Following_url string `json:"following_url"` 182 | Gists_url string `json:"gists_url"` 183 | Starred_url string `json:"starred_url"` 184 | Subscriptions_url string `json:"subscriptions_url"` 185 | Organizations_url string `json:"organizations_url"` 186 | Repos_url string `json:"repos_url"` 187 | Events_url string `json:"events_url"` 188 | Received_events_url string `json:"received_events_url"` 189 | Type string `json:"type"` 190 | Site_admin bool `json:"site_admin"` 191 | Name string `json:"name"` 192 | Company string `json:"company"` 193 | Blog string `json:"blog"` 194 | Location string `json:"location"` 195 | Email string `json:"email"` 196 | Hireable bool `json:"hireable"` 197 | Bio string `json:"bio"` 198 | Public_repos int `json:"public_repos"` 199 | Public_gists int `json:"public_gists"` 200 | Followers int `json:"followers"` 201 | Following int `json:"following"` 202 | Created_at string `json:"created_at"` 203 | Updated_at string `json:"updated_at"` 204 | } 205 | 206 | func init() { 207 | fmt.Println("Controller initialized!") 208 | //GithubUser = make(GithubUserMap) 209 | } 210 | 211 | /** 212 | * 获取项目star数量的接口 213 | * 函数名:GetStarNum 214 | * 函数参数:url string 215 | * 返回值:starNum int 返回url对应项目的star数目 216 | */ 217 | func GetStarNum(url string) int { 218 | var starNum = 0 219 | //从url中获取到用户名和项目名 220 | userName, programName, _ := ParseGithubHTTPSUrl(url) 221 | 222 | var Api = "https://api.github.com/repos/" + userName + "/" + programName 223 | client := &http.Client{} 224 | response, _ := client.Get(Api) 225 | defer response.Body.Close() 226 | body, err := ioutil.ReadAll(response.Body) 227 | if err != nil { 228 | panic(err) 229 | } 230 | 231 | var jd JsonData 232 | json.Unmarshal(body, &jd) 233 | starNum = jd.StargazersCount 234 | return starNum 235 | } 236 | 237 | //获取项目贡献者信息的接口 238 | // 函数名:getContributors 239 | // 函数参数:userName string programName string 240 | // 返回值:string 包含所有的contributor信息,不同的contributor用" "分割 241 | 242 | func GetContributors(userName string, programName string) string { 243 | var url_1 string = "https://api.github.com/repos/" + userName + "/" + programName + "/" + "contributors" 244 | 245 | client := &http.Client{} 246 | response, _ := client.Get(url_1) 247 | defer response.Body.Close() 248 | body, err_1 := ioutil.ReadAll(response.Body) 249 | if err_1 != nil { 250 | panic(err_1) 251 | } 252 | 253 | var cb ContributorData 254 | json.Unmarshal(body, &cb) 255 | var cl string = "" 256 | for i := 0; i < len(cb); i++ { 257 | var Name = cb[i].Login 258 | cl = cl + Name + " " 259 | } 260 | fmt.Println(cl) 261 | return cl 262 | } 263 | 264 | //获取贡献者的人数 265 | // 函数名:GetContributorNum 266 | // 函数参数:url string 267 | // 返回值:int 返回对应项目的贡献者人数 268 | func GetContributorNum(url string) int { 269 | 270 | user_Name, program_Name, _ := ParseGithubHTTPSUrl(url) 271 | 272 | info := GetContributors(user_Name, program_Name) 273 | res := strings.TrimSpace(info) 274 | str_arr := strings.Split(res, " ") 275 | count := len(str_arr) 276 | return count 277 | } 278 | 279 | type Data struct { 280 | Id string `json:userId` 281 | Name string `json:"userName"` 282 | Uri string `json:"headShotUrl"` 283 | } 284 | 285 | type UserJson struct { 286 | ErrorCode int 287 | Data Data 288 | } 289 | 290 | func GetUserJson(access_token string) UserJson { 291 | var url_2 = "https://api.github.com/user?" + "access_token=" + access_token 292 | 293 | client_2 := &http.Client{} 294 | response_2, _ := client_2.Get(url_2) 295 | defer response_2.Body.Close() 296 | body_2, err_2 := ioutil.ReadAll(response_2.Body) 297 | if err_2 != nil { 298 | panic(err_2) 299 | } 300 | 301 | // 获取ID 302 | var name = strings.Split(strings.Split(string(body_2), ",")[0], "\"")[3] 303 | var uri = strings.Split(strings.Split(string(body_2), ",")[3], "\"")[3] 304 | var id = strings.Split(strings.Split(string(body_2), ",")[1], ":")[1] 305 | 306 | //select id according to name 307 | data := Data{ 308 | Name: name, 309 | Uri: uri, 310 | Id: id, 311 | } 312 | userJson := UserJson{ 313 | ErrorCode: 0, 314 | Data: data, 315 | } 316 | 317 | return userJson 318 | } 319 | 320 | func GetAccessToken(code string) (accessToken string, err error) { 321 | client_id := beego.AppConfig.String("client_id") 322 | client_secret := beego.AppConfig.String("client_secret") 323 | url_1 := "https://github.com/login/oauth/access_token?code=" + code + "&client_id=" + client_id + "&client_secret=" + client_secret 324 | 325 | client := &http.Client{} 326 | response, err := client.Get(url_1) 327 | if err != nil { 328 | return "", err 329 | } else { 330 | defer response.Body.Close() 331 | } 332 | body, err1 := ioutil.ReadAll(response.Body) 333 | if err1 != nil { 334 | panic(err1) 335 | } 336 | accessToken = strings.Split(strings.Split(string(body), "&")[0], "=")[1] 337 | return accessToken, err 338 | } 339 | 340 | /** 341 | * 设置Github User这个map的Access Token字段. 342 | */ 343 | /*func (this GithubUserMap) SetGithubUserAccessToken(id string, name string, accessToken string) { 344 | if _, ok := this[id]; !ok { 345 | this[id] = new(GithubInfo) 346 | } 347 | this[id].AccessToken = accessToken 348 | this[id].GithubId = id 349 | this[id].GithubName = name 350 | }*/ 351 | 352 | /*func (this GithubUserMap) GetGithubUserAccessToken(userId string) (string, error) { 353 | if userInfo, ok := this[userId]; ok { 354 | return userInfo.AccessToken, nil 355 | } else { 356 | return "", fmt.Errorf("user id %s is not valid", userId) 357 | } 358 | }*/ 359 | 360 | //getWebhooksUrl 可以通过 361 | func RegisterGithubWebhooks(githubName, repoName, accessToken string) { 362 | //accessToken, _ := GithubUser.GetGithubUserAccessToken(userId) 363 | postPayload := getPayloadOfRegisterGithubWebhooks() 364 | //userName := c.Ctx.GetCookie("gethubName") 365 | api_url := getWebhooksUrlBy(githubName, repoName) 366 | bytePostPayload := []byte(postPayload) 367 | buffer := bytes.NewBuffer(bytePostPayload) 368 | request, err := http.NewRequest("POST", api_url, buffer) 369 | if err != nil { 370 | fmt.Printf("http.NewRequest%v", err) 371 | } 372 | request.Header.Set("Content-Type", "application/json") 373 | request.Header.Set("Authorization", "token "+accessToken) 374 | client := &http.Client{} 375 | resp, err := client.Do(request.WithContext(context.TODO())) 376 | if err != nil { 377 | fmt.Printf("client.Do%v", err) 378 | } 379 | respBytes, err := ioutil.ReadAll(resp.Body) 380 | defer resp.Body.Close() 381 | if err != nil { 382 | fmt.Printf("ioutil.ReadAll%v", err) 383 | } 384 | 385 | fmt.Println(string(respBytes)) 386 | } 387 | 388 | /** 389 | * TODO 在config中设置secret, 与github_webhooks中的Post函数一起完成 390 | */ 391 | func getPayloadOfRegisterGithubWebhooks() string { 392 | return `{ 393 | "name": "web", 394 | "active": true, 395 | "events": [ 396 | "push", 397 | "pull_request" 398 | ], 399 | "config": { 400 | "url": "http://114.115.206.8:8080/webhooks", 401 | "content_type": "json", 402 | "insecure_ssl": "0" 403 | } 404 | }` 405 | } 406 | 407 | func getWebhooksUrlBy(userName string, repoName string) string { 408 | return "https://api.github.com/repos/" + userName + "/" + repoName + "/hooks" 409 | } 410 | 411 | func GetGithubId(username string) int { 412 | api := "https://api.github.com/users/" + username 413 | client := &http.Client{} 414 | response, _ := client.Get(api) 415 | defer response.Body.Close() 416 | body, err_1 := ioutil.ReadAll(response.Body) 417 | if err_1 != nil { 418 | panic(err_1) 419 | } 420 | var res API_User 421 | json.Unmarshal(body, &res) 422 | fmt.Println(res.Id) 423 | return res.Id 424 | } 425 | --------------------------------------------------------------------------------