merge
This commit is contained in:
commit
5c57a06c51
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,6 +5,7 @@ gogs
|
||||||
*.db
|
*.db
|
||||||
*.log
|
*.log
|
||||||
custom/
|
custom/
|
||||||
|
data/
|
||||||
.vendor/
|
.vendor/
|
||||||
.idea/
|
.idea/
|
||||||
*.iml
|
*.iml
|
|
@ -4,7 +4,6 @@ path=github.com/gogits/gogs
|
||||||
[deps]
|
[deps]
|
||||||
github.com/codegangsta/cli=
|
github.com/codegangsta/cli=
|
||||||
github.com/codegangsta/martini=
|
github.com/codegangsta/martini=
|
||||||
github.com/martini-contrib/sessions=
|
|
||||||
github.com/Unknwon/com=
|
github.com/Unknwon/com=
|
||||||
github.com/Unknwon/cae=
|
github.com/Unknwon/cae=
|
||||||
github.com/Unknwon/goconfig=
|
github.com/Unknwon/goconfig=
|
||||||
|
|
19
README.md
19
README.md
|
@ -1,15 +1,19 @@
|
||||||
Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0bc450ac6f09bc56b9640a50aa/s/ "wercker status")](https://app.wercker.com/project/bykey/ad0bdb0bc450ac6f09bc56b9640a50aa) [![Go Walker](http://gowalker.org/api/v1/badge)](https://gowalker.org/github.com/gogits/gogs)
|
Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0bc450ac6f09bc56b9640a50aa/s/ "wercker status")](https://app.wercker.com/project/bykey/ad0bdb0bc450ac6f09bc56b9640a50aa) [![Build Status](https://drone.io/github.com/gogits/gogs/status.png)](https://drone.io/github.com/gogits/gogs/latest)
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language.
|
Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language.
|
||||||
|
|
||||||
Since we choose to use pure Go implementation of Git manipulation, Gogs certainly supports **ALL platforms** that Go supports, including Linux, Max OS X, and Windows with **ZERO** dependency.
|
![Demo](http://gowalker.org/public/gogs_demo.gif)
|
||||||
|
|
||||||
##### Current version: 0.1.5 Alpha
|
##### Current version: 0.1.6 Alpha
|
||||||
|
|
||||||
|
[简体中文](README_ZH.md)
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
There are some very good products in this category such as [gitlab](http://gitlab.com), but the environment setup steps often make us crazy. So our goal of Gogs is to build a GitHub-like clone with very easy setup steps, which take advantages of the Go Programming Language.
|
Since we choose to use pure Go implementation of Git manipulation, Gogs certainly supports **ALL platforms** that Go supports, including Linux, Mac OS X, and Windows with **ZERO** dependency.
|
||||||
|
|
||||||
|
More importantly, Gogs only needs one binary to setup your own project hosting on the fly!
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
@ -23,7 +27,7 @@ There are some very good products in this category such as [gitlab](http://gitla
|
||||||
- Activity timeline
|
- Activity timeline
|
||||||
- SSH protocol support.
|
- SSH protocol support.
|
||||||
- Register/delete account.
|
- Register/delete account.
|
||||||
- Create/delete public repository.
|
- Create/delete/watch public repository.
|
||||||
- User profile page.
|
- User profile page.
|
||||||
- Repository viewer.
|
- Repository viewer.
|
||||||
- Gravatar support.
|
- Gravatar support.
|
||||||
|
@ -42,8 +46,9 @@ There are two ways to install Gogs:
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|
||||||
- Mail service is based on [WeTalk](https://github.com/beego/wetalk).
|
|
||||||
- Logo is inspired by [martini](https://github.com/martini-contrib).
|
- Logo is inspired by [martini](https://github.com/martini-contrib).
|
||||||
|
- Mail Service, modules design is inspired by [WeTalk](https://github.com/beego/wetalk).
|
||||||
|
- System Monitor Status is inspired by [GoBlog](https://github.com/fuxiaohei/goblog).
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
|
|
53
README_ZH.md
Normal file
53
README_ZH.md
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0bc450ac6f09bc56b9640a50aa/s/ "wercker status")](https://app.wercker.com/project/bykey/ad0bdb0bc450ac6f09bc56b9640a50aa) [![Build Status](https://drone.io/github.com/gogits/gogs/status.png)](https://drone.io/github.com/gogits/gogs/latest)
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。
|
||||||
|
|
||||||
|
![Demo](http://gowalker.org/public/gogs_demo.gif)
|
||||||
|
|
||||||
|
##### 当前版本:0.1.6 Alpha
|
||||||
|
|
||||||
|
## 开发目的
|
||||||
|
|
||||||
|
Gogs 完全使用 Go 语言来实现对 Git 数据的操作,实现 **零** 依赖,并且支持 Go 语言所支持的 **所有平台**,包括 Linux、Mac OS X 以及 Windows。
|
||||||
|
|
||||||
|
更重要的是,您只需要一个可执行文件就能借助 Gogs 快速搭建属于您自己的代码托管服务!
|
||||||
|
|
||||||
|
## 项目概览
|
||||||
|
|
||||||
|
- 有关项目设计、开发说明、变更日志和路线图,请通过 [Wiki](https://github.com/gogits/gogs/wiki) 查看。
|
||||||
|
- 您可以到 [Trello Broad](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。
|
||||||
|
- 想要先睹为快?通过 [在线体验](http://try.gogits.org/Unknown/gogs) 或查看 **安装部署 -> 二进制安装** 小节。
|
||||||
|
- 使用过程中遇到问题?尝试从 [故障排查](https://github.com/gogits/gogs/wiki/Troubleshooting) 页面获取帮助。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- 活动时间线
|
||||||
|
- SSH 协议支持
|
||||||
|
- 注册/删除用户
|
||||||
|
- 创建/删除/关注公开仓库
|
||||||
|
- 用户个人信息页面
|
||||||
|
- 仓库浏览器
|
||||||
|
- Gravatar 支持
|
||||||
|
- 邮件服务(注册)
|
||||||
|
- 管理员面板
|
||||||
|
- 支持 MySQL、PostgreSQL 以及 SQLite3(仅限二进制版本)
|
||||||
|
|
||||||
|
## 安装部署
|
||||||
|
|
||||||
|
在安装 Gogs 之前,您需要先安装 [基本环境](https://github.com/gogits/gogs/wiki/Prerequirements)。
|
||||||
|
|
||||||
|
然后,您可以通过以下两种方式来安装 Gogs:
|
||||||
|
|
||||||
|
- [二进制安装](https://github.com/gogits/gogs/wiki/Install-from-binary): **强烈推荐** 适合体验者和实际部署
|
||||||
|
- [源码安装](https://github.com/gogits/gogs/wiki/Install-from-source)
|
||||||
|
|
||||||
|
## 特别鸣谢
|
||||||
|
|
||||||
|
- Logo 基于 [martini](https://github.com/martini-contrib) 修改而来。
|
||||||
|
- 邮件服务、模块设计基于 [WeTalk](https://github.com/beego/wetalk) 修改而来。
|
||||||
|
- 系统监视状态基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改而来。
|
||||||
|
|
||||||
|
## 贡献成员
|
||||||
|
|
||||||
|
本项目最初由 [Unknown](https://github.com/Unknwon) 和 [lunny](https://github.com/lunny) 发起,随后 [fuxiaohei](https://github.com/fuxiaohei) 与 [slene](https://github.com/slene) 加入到开发团队。您可以通过查看 [贡献者页面](https://github.com/gogits/gogs/graphs/contributors) 获取完整的贡献者列表。
|
44
conf/app.ini
44
conf/app.ini
|
@ -34,6 +34,10 @@ PATH = data/gogs.db
|
||||||
[security]
|
[security]
|
||||||
; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
|
; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
|
||||||
SECRET_KEY = !#@FDEWREWR&*(
|
SECRET_KEY = !#@FDEWREWR&*(
|
||||||
|
; Auto-login remember days
|
||||||
|
LOGIN_REMEMBER_DAYS = 7
|
||||||
|
COOKIE_USERNAME = gogs_awesome
|
||||||
|
COOKIE_REMEMBER_NAME = gogs_incredible
|
||||||
|
|
||||||
[service]
|
[service]
|
||||||
ACTIVE_CODE_LIVE_MINUTES = 180
|
ACTIVE_CODE_LIVE_MINUTES = 180
|
||||||
|
@ -44,6 +48,8 @@ REGISTER_EMAIL_CONFIRM = false
|
||||||
DISENABLE_REGISTERATION = false
|
DISENABLE_REGISTERATION = false
|
||||||
; User must sign in to view anything.
|
; User must sign in to view anything.
|
||||||
REQUIRE_SIGNIN_VIEW = false
|
REQUIRE_SIGNIN_VIEW = false
|
||||||
|
; Cache avatar as picture
|
||||||
|
ENABLE_CACHE_AVATAR = false
|
||||||
|
|
||||||
[mailer]
|
[mailer]
|
||||||
ENABLED = false
|
ENABLED = false
|
||||||
|
@ -70,8 +76,38 @@ INTERVAL = 60
|
||||||
; memcache: "127.0.0.1:11211"
|
; memcache: "127.0.0.1:11211"
|
||||||
HOST =
|
HOST =
|
||||||
|
|
||||||
|
[session]
|
||||||
|
; Either "memory", "file", "redis" or "mysql", default is "memory"
|
||||||
|
PROVIDER = file
|
||||||
|
; Provider config options
|
||||||
|
; memory: not have any config yet
|
||||||
|
; file: session file path, e.g. data/sessions
|
||||||
|
; redis: config like redis server addr, poolSize, password, e.g. 127.0.0.1:6379,100,astaxie
|
||||||
|
; mysql: go-sql-driver/mysql dsn config string, e.g. root:password@/session_table
|
||||||
|
PROVIDER_CONFIG = data/sessions
|
||||||
|
; Session cookie name
|
||||||
|
COOKIE_NAME = i_like_gogits
|
||||||
|
; If you use session in https only, default is false
|
||||||
|
COOKIE_SECURE = false
|
||||||
|
; Enable set cookie, default is true
|
||||||
|
ENABLE_SET_COOKIE = true
|
||||||
|
; Session GC time interval, default is 86400
|
||||||
|
GC_INTERVAL_TIME = 86400
|
||||||
|
; Session life time, default is 86400
|
||||||
|
SESSION_LIFE_TIME = 86400
|
||||||
|
; session id hash func, Either "sha1", "sha256" or "md5" default is sha1
|
||||||
|
SESSION_ID_HASHFUNC = sha1
|
||||||
|
; Session hash key, default is use random string
|
||||||
|
SESSION_ID_HASHKEY =
|
||||||
|
|
||||||
|
[picture]
|
||||||
|
; The place to picture data, either "server" or "qiniu", default is "server"
|
||||||
|
SERVICE = server
|
||||||
|
; For "server" only, root path of picture data, default is "data/pictures"
|
||||||
|
PATH = data/pictures
|
||||||
|
|
||||||
[log]
|
[log]
|
||||||
; Either "console", "file", "conn" or "smtp", default is "console"
|
; Either "console", "file", "conn", "smtp" or "database", default is "console"
|
||||||
MODE = console
|
MODE = console
|
||||||
; Buffer length of channel, keep it as it is if you don't know what it is.
|
; Buffer length of channel, keep it as it is if you don't know what it is.
|
||||||
BUFFER_LEN = 10000
|
BUFFER_LEN = 10000
|
||||||
|
@ -121,3 +157,9 @@ USER =
|
||||||
PASSWD =
|
PASSWD =
|
||||||
; Receivers, can be one or more, e.g. ["1@example.com","2@example.com"]
|
; Receivers, can be one or more, e.g. ["1@example.com","2@example.com"]
|
||||||
RECEIVERS =
|
RECEIVERS =
|
||||||
|
|
||||||
|
; For "database" mode only
|
||||||
|
[log.database]
|
||||||
|
LEVEL =
|
||||||
|
Driver =
|
||||||
|
CONN =
|
4
gogs.go
4
gogs.go
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// gogs(Go Git Service) is a Go clone of Github.
|
// Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -20,7 +20,7 @@ import (
|
||||||
// Test that go1.2 tag above is included in builds. main.go refers to this definition.
|
// Test that go1.2 tag above is included in builds. main.go refers to this definition.
|
||||||
const go12tag = true
|
const go12tag = true
|
||||||
|
|
||||||
const APP_VER = "0.1.5.0321"
|
const APP_VER = "0.1.6.0323.1"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
base.AppVer = APP_VER
|
base.AppVer = APP_VER
|
||||||
|
|
|
@ -7,6 +7,8 @@ package models
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Operation types of user action.
|
// Operation types of user action.
|
||||||
|
@ -28,7 +30,7 @@ type Action struct {
|
||||||
ActUserName string // Action user name.
|
ActUserName string // Action user name.
|
||||||
RepoId int64
|
RepoId int64
|
||||||
RepoName string
|
RepoName string
|
||||||
Content string `xorm:"varchar(1000)"`
|
Content string `xorm:"TEXT"`
|
||||||
Created time.Time `xorm:"created"`
|
Created time.Time `xorm:"created"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +81,18 @@ func CommitRepoAction(userId int64, userName string,
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update repository last update time.
|
||||||
|
repo, err := GetRepositoryByName(userId, repoName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
repo.IsBare = false
|
||||||
|
if err = UpdateRepository(repo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace("action.CommitRepoAction: %d/%s", userId, repo.LowerName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +106,8 @@ func NewRepoAction(user *User, repo *Repository) error {
|
||||||
RepoId: repo.Id,
|
RepoId: repo.Id,
|
||||||
RepoName: repo.Name,
|
RepoName: repo.Name,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
log.Trace("action.NewRepoAction: %s/%s", user.LowerName, repo.LowerName)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
141
models/issue.go
141
models/issue.go
|
@ -4,16 +4,155 @@
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrIssueNotExist = errors.New("Issue does not exist")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Issue represents an issue or pull request of repository.
|
||||||
type Issue struct {
|
type Issue struct {
|
||||||
Id int64
|
Id int64
|
||||||
|
Index int64 // Index in one repository.
|
||||||
|
Name string
|
||||||
RepoId int64 `xorm:"index"`
|
RepoId int64 `xorm:"index"`
|
||||||
PosterId int64
|
PosterId int64
|
||||||
|
MilestoneId int64
|
||||||
|
AssigneeId int64
|
||||||
|
IsPull bool // Indicates whether is a pull request or not.
|
||||||
|
IsClosed bool
|
||||||
|
Labels string `xorm:"TEXT"`
|
||||||
|
Mentions string `xorm:"TEXT"`
|
||||||
|
Content string `xorm:"TEXT"`
|
||||||
|
NumComments int
|
||||||
|
Created time.Time `xorm:"created"`
|
||||||
|
Updated time.Time `xorm:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PullRequest struct {
|
// CreateIssue creates new issue for repository.
|
||||||
|
func CreateIssue(userId, repoId, milestoneId, assigneeId int64, name, labels, content string, isPull bool) (*Issue, error) {
|
||||||
|
count, err := GetIssueCount(repoId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: find out mentions
|
||||||
|
mentions := ""
|
||||||
|
|
||||||
|
issue := &Issue{
|
||||||
|
Index: count + 1,
|
||||||
|
Name: name,
|
||||||
|
RepoId: repoId,
|
||||||
|
PosterId: userId,
|
||||||
|
MilestoneId: milestoneId,
|
||||||
|
AssigneeId: assigneeId,
|
||||||
|
IsPull: isPull,
|
||||||
|
Labels: labels,
|
||||||
|
Mentions: mentions,
|
||||||
|
Content: content,
|
||||||
|
}
|
||||||
|
_, err = orm.Insert(issue)
|
||||||
|
return issue, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssueCount returns count of issues in the repository.
|
||||||
|
func GetIssueCount(repoId int64) (int64, error) {
|
||||||
|
return orm.Count(&Issue{RepoId: repoId})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssueById returns issue object by given id.
|
||||||
|
func GetIssueById(id int64) (*Issue, error) {
|
||||||
|
issue := new(Issue)
|
||||||
|
has, err := orm.Id(id).Get(issue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, ErrIssueNotExist
|
||||||
|
}
|
||||||
|
return issue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssues returns a list of issues by given conditions.
|
||||||
|
func GetIssues(userId, repoId, posterId, milestoneId int64, page int, isClosed, isMention bool, labels, sortType string) ([]Issue, error) {
|
||||||
|
sess := orm.Limit(20, (page-1)*20)
|
||||||
|
|
||||||
|
if repoId > 0 {
|
||||||
|
sess = sess.Where("repo_id=?", repoId).And("is_closed=?", isClosed)
|
||||||
|
} else {
|
||||||
|
sess = sess.Where("is_closed=?", isClosed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if userId > 0 {
|
||||||
|
sess = sess.And("assignee_id=?", userId)
|
||||||
|
} else if posterId > 0 {
|
||||||
|
sess = sess.And("poster_id=?", posterId)
|
||||||
|
} else if isMention {
|
||||||
|
sess = sess.And("mentions like '%$" + base.ToStr(userId) + "|%'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if milestoneId > 0 {
|
||||||
|
sess = sess.And("milestone_id=?", milestoneId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(labels) > 0 {
|
||||||
|
for _, label := range strings.Split(labels, ",") {
|
||||||
|
sess = sess.And("mentions like '%$" + label + "|%'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sortType {
|
||||||
|
case "oldest":
|
||||||
|
sess = sess.Asc("created")
|
||||||
|
case "recentupdate":
|
||||||
|
sess = sess.Desc("updated")
|
||||||
|
case "leastupdate":
|
||||||
|
sess = sess.Asc("updated")
|
||||||
|
case "mostcomment":
|
||||||
|
sess = sess.Desc("num_comments")
|
||||||
|
case "leastcomment":
|
||||||
|
sess = sess.Asc("num_comments")
|
||||||
|
default:
|
||||||
|
sess = sess.Desc("created")
|
||||||
|
}
|
||||||
|
|
||||||
|
var issues []Issue
|
||||||
|
err := sess.Find(&issues)
|
||||||
|
return issues, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Label represents a list of labels of repository for issues.
|
||||||
|
type Label struct {
|
||||||
Id int64
|
Id int64
|
||||||
|
RepoId int64 `xorm:"index"`
|
||||||
|
Names string
|
||||||
|
Colors string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Milestone represents a milestone of repository.
|
||||||
|
type Milestone struct {
|
||||||
|
Id int64
|
||||||
|
Name string
|
||||||
|
RepoId int64 `xorm:"index"`
|
||||||
|
IsClosed bool
|
||||||
|
Content string
|
||||||
|
NumIssues int
|
||||||
|
DueDate time.Time
|
||||||
|
Created time.Time `xorm:"created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comment represents a comment in commit and issue page.
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
Id int64
|
Id int64
|
||||||
|
PosterId int64
|
||||||
|
IssueId int64
|
||||||
|
CommitId int64
|
||||||
|
Line int
|
||||||
|
Content string
|
||||||
|
Created time.Time `xorm:"created"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ func setEngine() {
|
||||||
func NewEngine() {
|
func NewEngine() {
|
||||||
setEngine()
|
setEngine()
|
||||||
if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
|
if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
|
||||||
new(Action), new(Access)); err != nil {
|
new(Action), new(Access), new(Issue)); err != nil {
|
||||||
fmt.Printf("sync database struct error: %v\n", err)
|
fmt.Printf("sync database struct error: %v\n", err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -78,7 +80,7 @@ type PublicKey struct {
|
||||||
OwnerId int64 `xorm:"index"`
|
OwnerId int64 `xorm:"index"`
|
||||||
Name string `xorm:"unique not null"`
|
Name string `xorm:"unique not null"`
|
||||||
Fingerprint string
|
Fingerprint string
|
||||||
Content string `xorm:"text not null"`
|
Content string `xorm:"TEXT not null"`
|
||||||
Created time.Time `xorm:"created"`
|
Created time.Time `xorm:"created"`
|
||||||
Updated time.Time `xorm:"updated"`
|
Updated time.Time `xorm:"updated"`
|
||||||
}
|
}
|
||||||
|
@ -99,8 +101,8 @@ func AddPublicKey(key *PublicKey) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate fingerprint.
|
// Calculate fingerprint.
|
||||||
tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()),
|
tmpPath := strings.Replace(filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()),
|
||||||
"id_rsa.pub")
|
"id_rsa.pub"), "\\", "/", -1)
|
||||||
os.MkdirAll(path.Dir(tmpPath), os.ModePerm)
|
os.MkdirAll(path.Dir(tmpPath), os.ModePerm)
|
||||||
if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil {
|
if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -127,25 +129,11 @@ func AddPublicKey(key *PublicKey) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
|
func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
|
||||||
func DeletePublicKey(key *PublicKey) (err error) {
|
|
||||||
// Delete SSH key in database.
|
|
||||||
has, err := orm.Id(key.Id).Get(key)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if !has {
|
|
||||||
return errors.New("Public key does not exist")
|
|
||||||
}
|
|
||||||
if _, err = orm.Delete(key); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete SSH key in SSH key file.
|
// Delete SSH key in SSH key file.
|
||||||
sshOpLocker.Lock()
|
sshOpLocker.Lock()
|
||||||
defer sshOpLocker.Unlock()
|
defer sshOpLocker.Unlock()
|
||||||
|
|
||||||
p := filepath.Join(sshPath, "authorized_keys")
|
|
||||||
tmpP := filepath.Join(sshPath, "authorized_keys.tmp")
|
|
||||||
fr, err := os.Open(p)
|
fr, err := os.Open(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -188,8 +176,29 @@ func DeletePublicKey(key *PublicKey) (err error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if err = os.Remove(p); err != nil {
|
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
|
||||||
|
func DeletePublicKey(key *PublicKey) (err error) {
|
||||||
|
// Delete SSH key in database.
|
||||||
|
has, err := orm.Id(key.Id).Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !has {
|
||||||
|
return errors.New("Public key does not exist")
|
||||||
|
}
|
||||||
|
if _, err = orm.Delete(key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p := filepath.Join(sshPath, "authorized_keys")
|
||||||
|
tmpP := filepath.Join(sshPath, "authorized_keys.tmp")
|
||||||
|
log.Trace("ssh.DeletePublicKey(authorized_keys): %s", p)
|
||||||
|
|
||||||
|
if err = rewriteAuthorizedKeys(key, p, tmpP); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err = os.Remove(p); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.Rename(tmpP, p)
|
return os.Rename(tmpP, p)
|
||||||
|
|
|
@ -83,10 +83,11 @@ type Repository struct {
|
||||||
Name string `xorm:"index not null"`
|
Name string `xorm:"index not null"`
|
||||||
Description string
|
Description string
|
||||||
Website string
|
Website string
|
||||||
Private bool
|
|
||||||
NumWatches int
|
NumWatches int
|
||||||
NumStars int
|
NumStars int
|
||||||
NumForks int
|
NumForks int
|
||||||
|
IsPrivate bool
|
||||||
|
IsBare bool
|
||||||
Created time.Time `xorm:"created"`
|
Created time.Time `xorm:"created"`
|
||||||
Updated time.Time `xorm:"updated"`
|
Updated time.Time `xorm:"updated"`
|
||||||
}
|
}
|
||||||
|
@ -139,7 +140,8 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv
|
||||||
Name: repoName,
|
Name: repoName,
|
||||||
LowerName: strings.ToLower(repoName),
|
LowerName: strings.ToLower(repoName),
|
||||||
Description: desc,
|
Description: desc,
|
||||||
Private: private,
|
IsPrivate: private,
|
||||||
|
IsBare: repoLang == "" && license == "" && !initReadme,
|
||||||
}
|
}
|
||||||
|
|
||||||
repoPath := RepoPath(user.Name, repoName)
|
repoPath := RepoPath(user.Name, repoName)
|
||||||
|
@ -369,6 +371,18 @@ func RepoPath(userName, repoName string) string {
|
||||||
return filepath.Join(UserPath(userName), repoName+".git")
|
return filepath.Join(UserPath(userName), repoName+".git")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateRepository(repo *Repository) error {
|
||||||
|
if len(repo.Description) > 255 {
|
||||||
|
repo.Description = repo.Description[:255]
|
||||||
|
}
|
||||||
|
if len(repo.Website) > 255 {
|
||||||
|
repo.Website = repo.Website[:255]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := orm.Id(repo.Id).UseBool().Cols("description", "website").Update(repo)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteRepository deletes a repository for a user or orgnaztion.
|
// DeleteRepository deletes a repository for a user or orgnaztion.
|
||||||
func DeleteRepository(userId, repoId int64, userName string) (err error) {
|
func DeleteRepository(userId, repoId int64, userName string) (err error) {
|
||||||
repo := &Repository{Id: repoId, OwnerId: userId}
|
repo := &Repository{Id: repoId, OwnerId: userId}
|
||||||
|
@ -413,9 +427,9 @@ func DeleteRepository(userId, repoId int64, userName string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepositoryByName returns the repository by given name under user if exists.
|
// GetRepositoryByName returns the repository by given name under user if exists.
|
||||||
func GetRepositoryByName(user *User, repoName string) (*Repository, error) {
|
func GetRepositoryByName(userId int64, repoName string) (*Repository, error) {
|
||||||
repo := &Repository{
|
repo := &Repository{
|
||||||
OwnerId: user.Id,
|
OwnerId: userId,
|
||||||
LowerName: strings.ToLower(repoName),
|
LowerName: strings.ToLower(repoName),
|
||||||
}
|
}
|
||||||
has, err := orm.Get(repo)
|
has, err := orm.Get(repo)
|
||||||
|
|
|
@ -201,7 +201,14 @@ func VerifyUserActiveCode(code string) (user *User) {
|
||||||
|
|
||||||
// UpdateUser updates user's information.
|
// UpdateUser updates user's information.
|
||||||
func UpdateUser(user *User) (err error) {
|
func UpdateUser(user *User) (err error) {
|
||||||
_, err = orm.Id(user.Id).UseBool().Update(user)
|
if len(user.Location) > 255 {
|
||||||
|
user.Location = user.Location[:255]
|
||||||
|
}
|
||||||
|
if len(user.Website) > 255 {
|
||||||
|
user.Website = user.Website[:255]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = orm.Id(user.Id).UseBool().Cols("website", "location").Update(user)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,9 +286,7 @@ func GetUserByName(name string) (*User, error) {
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
return nil, ErrUserNotExist
|
return nil, ErrUserNotExist
|
||||||
}
|
}
|
||||||
user := &User{
|
user := &User{LowerName: strings.ToLower(name)}
|
||||||
LowerName: strings.ToLower(name),
|
|
||||||
}
|
|
||||||
has, err := orm.Get(user)
|
has, err := orm.Get(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -61,6 +61,7 @@ func (f *RegisterForm) Validate(errors *binding.Errors, req *http.Request, conte
|
||||||
type LogInForm struct {
|
type LogInForm struct {
|
||||||
UserName string `form:"username" binding:"Required;AlphaDash;MaxSize(30)"`
|
UserName string `form:"username" binding:"Required;AlphaDash;MaxSize(30)"`
|
||||||
Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"`
|
Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"`
|
||||||
|
Remember string `form:"remember"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *LogInForm) Name(field string) string {
|
func (f *LogInForm) Name(field string) string {
|
||||||
|
|
54
modules/auth/issue.go
Normal file
54
modules/auth/issue.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/codegangsta/martini"
|
||||||
|
|
||||||
|
"github.com/gogits/binding"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
"github.com/gogits/gogs/modules/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateIssueForm struct {
|
||||||
|
IssueName string `form:"name" binding:"Required;MaxSize(50)"`
|
||||||
|
RepoId int64 `form:"repoid" binding:"Required"`
|
||||||
|
MilestoneId int64 `form:"milestoneid" binding:"Required"`
|
||||||
|
AssigneeId int64 `form:"assigneeid"`
|
||||||
|
Labels string `form:"labels"`
|
||||||
|
Content string `form:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CreateIssueForm) Name(field string) string {
|
||||||
|
names := map[string]string{
|
||||||
|
"IssueName": "Issue name",
|
||||||
|
"RepoId": "Repository ID",
|
||||||
|
"MilestoneId": "Milestone ID",
|
||||||
|
}
|
||||||
|
return names[field]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CreateIssueForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) {
|
||||||
|
if req.Method == "GET" || errors.Count() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
|
||||||
|
data["HasError"] = true
|
||||||
|
AssignForm(f, data)
|
||||||
|
|
||||||
|
if len(errors.Overall) > 0 {
|
||||||
|
for _, err := range errors.Overall {
|
||||||
|
log.Error("CreateIssueForm.Validate: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(errors, data, f)
|
||||||
|
}
|
|
@ -9,7 +9,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/codegangsta/martini"
|
||||||
"github.com/martini-contrib/sessions"
|
|
||||||
|
"github.com/gogits/session"
|
||||||
|
|
||||||
"github.com/gogits/binding"
|
"github.com/gogits/binding"
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignedInId returns the id of signed in user.
|
// SignedInId returns the id of signed in user.
|
||||||
func SignedInId(session sessions.Session) int64 {
|
func SignedInId(session session.SessionStore) int64 {
|
||||||
userId := session.Get("userId")
|
userId := session.Get("userId")
|
||||||
if userId == nil {
|
if userId == nil {
|
||||||
return 0
|
return 0
|
||||||
|
@ -34,7 +35,7 @@ func SignedInId(session sessions.Session) int64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedInName returns the name of signed in user.
|
// SignedInName returns the name of signed in user.
|
||||||
func SignedInName(session sessions.Session) string {
|
func SignedInName(session session.SessionStore) string {
|
||||||
userName := session.Get("userName")
|
userName := session.Get("userName")
|
||||||
if userName == nil {
|
if userName == nil {
|
||||||
return ""
|
return ""
|
||||||
|
@ -46,7 +47,7 @@ func SignedInName(session sessions.Session) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedInUser returns the user object of signed user.
|
// SignedInUser returns the user object of signed user.
|
||||||
func SignedInUser(session sessions.Session) *models.User {
|
func SignedInUser(session session.SessionStore) *models.User {
|
||||||
id := SignedInId(session)
|
id := SignedInId(session)
|
||||||
if id <= 0 {
|
if id <= 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -61,7 +62,7 @@ func SignedInUser(session sessions.Session) *models.User {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSignedIn check if any user has signed in.
|
// IsSignedIn check if any user has signed in.
|
||||||
func IsSignedIn(session sessions.Session) bool {
|
func IsSignedIn(session session.SessionStore) bool {
|
||||||
return SignedInId(session) > 0
|
return SignedInId(session) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/Unknwon/goconfig"
|
"github.com/Unknwon/goconfig"
|
||||||
|
|
||||||
"github.com/gogits/cache"
|
"github.com/gogits/cache"
|
||||||
|
"github.com/gogits/session"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
)
|
)
|
||||||
|
@ -37,21 +38,33 @@ var (
|
||||||
RunUser string
|
RunUser string
|
||||||
RepoRootPath string
|
RepoRootPath string
|
||||||
|
|
||||||
|
LogInRememberDays int
|
||||||
|
CookieUserName string
|
||||||
|
CookieRememberName string
|
||||||
|
|
||||||
Cfg *goconfig.ConfigFile
|
Cfg *goconfig.ConfigFile
|
||||||
MailService *Mailer
|
MailService *Mailer
|
||||||
|
|
||||||
|
LogMode string
|
||||||
|
LogConfig string
|
||||||
|
|
||||||
Cache cache.Cache
|
Cache cache.Cache
|
||||||
CacheAdapter string
|
CacheAdapter string
|
||||||
CacheConfig string
|
CacheConfig string
|
||||||
|
|
||||||
LogMode string
|
SessionProvider string
|
||||||
LogConfig string
|
SessionConfig *session.Config
|
||||||
|
SessionManager *session.Manager
|
||||||
|
|
||||||
|
PictureService string
|
||||||
|
PictureRootPath string
|
||||||
)
|
)
|
||||||
|
|
||||||
var Service struct {
|
var Service struct {
|
||||||
RegisterEmailConfirm bool
|
RegisterEmailConfirm bool
|
||||||
DisenableRegisteration bool
|
DisenableRegisteration bool
|
||||||
RequireSignInView bool
|
RequireSignInView bool
|
||||||
|
EnableCacheAvatar bool
|
||||||
ActiveCodeLives int
|
ActiveCodeLives int
|
||||||
ResetPwdCodeLives int
|
ResetPwdCodeLives int
|
||||||
}
|
}
|
||||||
|
@ -82,6 +95,7 @@ func newService() {
|
||||||
Service.ResetPwdCodeLives = Cfg.MustInt("service", "RESET_PASSWD_CODE_LIVE_MINUTES", 180)
|
Service.ResetPwdCodeLives = Cfg.MustInt("service", "RESET_PASSWD_CODE_LIVE_MINUTES", 180)
|
||||||
Service.DisenableRegisteration = Cfg.MustBool("service", "DISENABLE_REGISTERATION", false)
|
Service.DisenableRegisteration = Cfg.MustBool("service", "DISENABLE_REGISTERATION", false)
|
||||||
Service.RequireSignInView = Cfg.MustBool("service", "REQUIRE_SIGNIN_VIEW", false)
|
Service.RequireSignInView = Cfg.MustBool("service", "REQUIRE_SIGNIN_VIEW", false)
|
||||||
|
Service.EnableCacheAvatar = Cfg.MustBool("service", "ENABLE_CACHE_AVATAR", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLogService() {
|
func newLogService() {
|
||||||
|
@ -129,6 +143,10 @@ func newLogService() {
|
||||||
Cfg.MustValue(modeSec, "HOST", "127.0.0.1:25"),
|
Cfg.MustValue(modeSec, "HOST", "127.0.0.1:25"),
|
||||||
Cfg.MustValue(modeSec, "RECEIVERS", "[]"),
|
Cfg.MustValue(modeSec, "RECEIVERS", "[]"),
|
||||||
Cfg.MustValue(modeSec, "SUBJECT", "Diagnostic message from serve"))
|
Cfg.MustValue(modeSec, "SUBJECT", "Diagnostic message from serve"))
|
||||||
|
case "database":
|
||||||
|
LogConfig = fmt.Sprintf(`{"level":%s,"driver":%s,"conn":%s}`, level,
|
||||||
|
Cfg.MustValue(modeSec, "Driver"),
|
||||||
|
Cfg.MustValue(modeSec, "CONN"))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.NewLogger(Cfg.MustInt64("log", "BUFFER_LEN", 10000), LogMode, LogConfig)
|
log.NewLogger(Cfg.MustInt64("log", "BUFFER_LEN", 10000), LogMode, LogConfig)
|
||||||
|
@ -159,6 +177,34 @@ func newCacheService() {
|
||||||
log.Info("Cache Service Enabled")
|
log.Info("Cache Service Enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newSessionService() {
|
||||||
|
SessionProvider = Cfg.MustValue("session", "PROVIDER", "memory")
|
||||||
|
|
||||||
|
SessionConfig = new(session.Config)
|
||||||
|
SessionConfig.ProviderConfig = Cfg.MustValue("session", "PROVIDER_CONFIG")
|
||||||
|
SessionConfig.CookieName = Cfg.MustValue("session", "COOKIE_NAME", "i_like_gogits")
|
||||||
|
SessionConfig.CookieSecure = Cfg.MustBool("session", "COOKIE_SECURE")
|
||||||
|
SessionConfig.EnableSetCookie = Cfg.MustBool("session", "ENABLE_SET_COOKIE", true)
|
||||||
|
SessionConfig.GcIntervalTime = Cfg.MustInt64("session", "GC_INTERVAL_TIME", 86400)
|
||||||
|
SessionConfig.SessionLifeTime = Cfg.MustInt64("session", "SESSION_LIFE_TIME", 86400)
|
||||||
|
SessionConfig.SessionIDHashFunc = Cfg.MustValue("session", "SESSION_ID_HASHFUNC", "sha1")
|
||||||
|
SessionConfig.SessionIDHashKey = Cfg.MustValue("session", "SESSION_ID_HASHKEY")
|
||||||
|
|
||||||
|
if SessionProvider == "file" {
|
||||||
|
os.MkdirAll(path.Dir(SessionConfig.ProviderConfig), os.ModePerm)
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
SessionManager, err = session.NewManager(SessionProvider, *SessionConfig)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Init session system failed, provider: %s, %v\n",
|
||||||
|
SessionProvider, err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Session Service Enabled")
|
||||||
|
}
|
||||||
|
|
||||||
func newMailService() {
|
func newMailService() {
|
||||||
// Check mailer setting.
|
// Check mailer setting.
|
||||||
if Cfg.MustBool("mailer", "ENABLED") {
|
if Cfg.MustBool("mailer", "ENABLED") {
|
||||||
|
@ -214,6 +260,13 @@ func NewConfigContext() {
|
||||||
SecretKey = Cfg.MustValue("security", "SECRET_KEY")
|
SecretKey = Cfg.MustValue("security", "SECRET_KEY")
|
||||||
RunUser = Cfg.MustValue("", "RUN_USER")
|
RunUser = Cfg.MustValue("", "RUN_USER")
|
||||||
|
|
||||||
|
LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
|
||||||
|
CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
|
||||||
|
CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
|
||||||
|
|
||||||
|
PictureService = Cfg.MustValue("picture", "SERVICE")
|
||||||
|
PictureRootPath = Cfg.MustValue("picture", "PATH")
|
||||||
|
|
||||||
// Determine and create root git reposiroty path.
|
// Determine and create root git reposiroty path.
|
||||||
RepoRootPath = Cfg.MustValue("repository", "ROOT")
|
RepoRootPath = Cfg.MustValue("repository", "ROOT")
|
||||||
if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil {
|
if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil {
|
||||||
|
@ -226,6 +279,7 @@ func NewServices() {
|
||||||
newService()
|
newService()
|
||||||
newLogService()
|
newLogService()
|
||||||
newCacheService()
|
newCacheService()
|
||||||
|
newSessionService()
|
||||||
newMailService()
|
newMailService()
|
||||||
newRegisterMailService()
|
newRegisterMailService()
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,17 @@ func EncodeMd5(str string) string {
|
||||||
return hex.EncodeToString(m.Sum(nil))
|
return hex.EncodeToString(m.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Random generate string
|
// GetRandomString generate random string by specify chars.
|
||||||
func GetRandomString(n int) string {
|
func GetRandomString(n int, alphabets ...byte) string {
|
||||||
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||||
var bytes = make([]byte, n)
|
var bytes = make([]byte, n)
|
||||||
rand.Read(bytes)
|
rand.Read(bytes)
|
||||||
for i, b := range bytes {
|
for i, b := range bytes {
|
||||||
|
if len(alphabets) == 0 {
|
||||||
bytes[i] = alphanum[b%byte(len(alphanum))]
|
bytes[i] = alphanum[b%byte(len(alphanum))]
|
||||||
|
} else {
|
||||||
|
bytes[i] = alphabets[b%byte(len(alphabets))]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return string(bytes)
|
return string(bytes)
|
||||||
}
|
}
|
||||||
|
@ -111,6 +115,85 @@ const (
|
||||||
Year = 12 * Month
|
Year = 12 * Month
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func computeTimeDiff(diff int64) (int64, string) {
|
||||||
|
diffStr := ""
|
||||||
|
switch {
|
||||||
|
case diff <= 0:
|
||||||
|
diff = 0
|
||||||
|
diffStr = "now"
|
||||||
|
case diff < 2:
|
||||||
|
diff = 0
|
||||||
|
diffStr = "1 second"
|
||||||
|
case diff < 1*Minute:
|
||||||
|
diffStr = fmt.Sprintf("%d seconds", diff)
|
||||||
|
diff = 0
|
||||||
|
|
||||||
|
case diff < 2*Minute:
|
||||||
|
diff -= 1 * Minute
|
||||||
|
diffStr = "1 minute"
|
||||||
|
case diff < 1*Hour:
|
||||||
|
diffStr = fmt.Sprintf("%d minutes", diff/Minute)
|
||||||
|
diff -= diff / Minute * Minute
|
||||||
|
|
||||||
|
case diff < 2*Hour:
|
||||||
|
diff -= 1 * Hour
|
||||||
|
diffStr = "1 hour"
|
||||||
|
case diff < 1*Day:
|
||||||
|
diffStr = fmt.Sprintf("%d hours", diff/Hour)
|
||||||
|
diff -= diff / Hour * Hour
|
||||||
|
|
||||||
|
case diff < 2*Day:
|
||||||
|
diff -= 1 * Day
|
||||||
|
diffStr = "1 day"
|
||||||
|
case diff < 1*Week:
|
||||||
|
diffStr = fmt.Sprintf("%d days", diff/Day)
|
||||||
|
diff -= diff / Day * Day
|
||||||
|
|
||||||
|
case diff < 2*Week:
|
||||||
|
diff -= 1 * Week
|
||||||
|
diffStr = "1 week"
|
||||||
|
case diff < 1*Month:
|
||||||
|
diffStr = fmt.Sprintf("%d weeks", diff/Week)
|
||||||
|
diff -= diff / Week * Week
|
||||||
|
|
||||||
|
case diff < 2*Month:
|
||||||
|
diff -= 1 * Month
|
||||||
|
diffStr = "1 month"
|
||||||
|
case diff < 1*Year:
|
||||||
|
diffStr = fmt.Sprintf("%d months", diff/Month)
|
||||||
|
diff -= diff / Month * Month
|
||||||
|
|
||||||
|
case diff < 2*Year:
|
||||||
|
diff -= 1 * Year
|
||||||
|
diffStr = "1 year"
|
||||||
|
default:
|
||||||
|
diffStr = fmt.Sprintf("%d years", diff/Year)
|
||||||
|
diff = 0
|
||||||
|
}
|
||||||
|
return diff, diffStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeSincePro calculates the time interval and generate full user-friendly string.
|
||||||
|
func TimeSincePro(then time.Time) string {
|
||||||
|
now := time.Now()
|
||||||
|
diff := now.Unix() - then.Unix()
|
||||||
|
|
||||||
|
if then.After(now) {
|
||||||
|
return "future"
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeStr, diffStr string
|
||||||
|
for {
|
||||||
|
if diff == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
diff, diffStr = computeTimeDiff(diff)
|
||||||
|
timeStr += ", " + diffStr
|
||||||
|
}
|
||||||
|
return strings.TrimPrefix(timeStr, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
// TimeSince calculates the time interval and generate user-friendly string.
|
// TimeSince calculates the time interval and generate user-friendly string.
|
||||||
func TimeSince(then time.Time) string {
|
func TimeSince(then time.Time) string {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
@ -123,7 +206,6 @@ func TimeSince(then time.Time) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
case diff <= 0:
|
case diff <= 0:
|
||||||
return "now"
|
return "now"
|
||||||
case diff <= 2:
|
case diff <= 2:
|
||||||
|
@ -156,8 +238,10 @@ func TimeSince(then time.Time) string {
|
||||||
case diff < 1*Year:
|
case diff < 1*Year:
|
||||||
return fmt.Sprintf("%d months %s", diff/Month, lbl)
|
return fmt.Sprintf("%d months %s", diff/Month, lbl)
|
||||||
|
|
||||||
case diff < 18*Month:
|
case diff < 2*Year:
|
||||||
return fmt.Sprintf("1 year %s", lbl)
|
return fmt.Sprintf("1 year %s", lbl)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%d years %s", diff/Year, lbl)
|
||||||
}
|
}
|
||||||
return then.String()
|
return then.String()
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,18 +5,40 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/codegangsta/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignInRequire requires user to sign in.
|
type ToggleOptions struct {
|
||||||
func SignInRequire(redirect bool) martini.Handler {
|
SignInRequire bool
|
||||||
return func(ctx *Context) {
|
SignOutRequire bool
|
||||||
if !ctx.IsSigned {
|
AdminRequire bool
|
||||||
if redirect {
|
DisableCsrf bool
|
||||||
ctx.Redirect("/user/login")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Toggle(options *ToggleOptions) martini.Handler {
|
||||||
|
return func(ctx *Context) {
|
||||||
|
if options.SignOutRequire && ctx.IsSigned {
|
||||||
|
ctx.Redirect("/")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !options.DisableCsrf {
|
||||||
|
if ctx.Req.Method == "POST" {
|
||||||
|
if !ctx.CsrfTokenValid() {
|
||||||
|
ctx.Error(403, "CSRF token does not match")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.SignInRequire {
|
||||||
|
if !ctx.IsSigned {
|
||||||
|
ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI))
|
||||||
|
ctx.Redirect("/user/login")
|
||||||
return
|
return
|
||||||
} else if !ctx.User.IsActive && base.Service.RegisterEmailConfirm {
|
} else if !ctx.User.IsActive && base.Service.RegisterEmailConfirm {
|
||||||
ctx.Data["Title"] = "Activate Your Account"
|
ctx.Data["Title"] = "Activate Your Account"
|
||||||
|
@ -24,21 +46,8 @@ func SignInRequire(redirect bool) martini.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// SignOutRequire requires user to sign out.
|
if options.AdminRequire {
|
||||||
func SignOutRequire() martini.Handler {
|
|
||||||
return func(ctx *Context) {
|
|
||||||
if ctx.IsSigned {
|
|
||||||
ctx.Redirect("/")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdminRequire requires user signed in as administor.
|
|
||||||
func AdminRequire() martini.Handler {
|
|
||||||
return func(ctx *Context) {
|
|
||||||
if !ctx.User.IsAdmin {
|
if !ctx.User.IsAdmin {
|
||||||
ctx.Error(403)
|
ctx.Error(403)
|
||||||
return
|
return
|
||||||
|
@ -46,3 +55,4 @@ func AdminRequire() martini.Handler {
|
||||||
ctx.Data["PageIsAdmin"] = true
|
ctx.Data["PageIsAdmin"] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,14 +5,20 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/codegangsta/martini"
|
||||||
"github.com/martini-contrib/sessions"
|
|
||||||
|
|
||||||
"github.com/gogits/cache"
|
"github.com/gogits/cache"
|
||||||
|
"github.com/gogits/session"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/auth"
|
"github.com/gogits/gogs/modules/auth"
|
||||||
|
@ -27,11 +33,13 @@ type Context struct {
|
||||||
p martini.Params
|
p martini.Params
|
||||||
Req *http.Request
|
Req *http.Request
|
||||||
Res http.ResponseWriter
|
Res http.ResponseWriter
|
||||||
Session sessions.Session
|
Session session.SessionStore
|
||||||
Cache cache.Cache
|
Cache cache.Cache
|
||||||
User *models.User
|
User *models.User
|
||||||
IsSigned bool
|
IsSigned bool
|
||||||
|
|
||||||
|
csrfToken string
|
||||||
|
|
||||||
Repo struct {
|
Repo struct {
|
||||||
IsValid bool
|
IsValid bool
|
||||||
IsOwner bool
|
IsOwner bool
|
||||||
|
@ -90,23 +98,157 @@ func (ctx *Context) Handle(status int, title string, err error) {
|
||||||
ctx.HTML(status, fmt.Sprintf("status/%d", status))
|
ctx.HTML(status, fmt.Sprintf("status/%d", status))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) GetCookie(name string) string {
|
||||||
|
cookie, err := ctx.Req.Cookie(name)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return cookie.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
|
||||||
|
cookie := http.Cookie{}
|
||||||
|
cookie.Name = name
|
||||||
|
cookie.Value = value
|
||||||
|
|
||||||
|
if len(others) > 0 {
|
||||||
|
switch v := others[0].(type) {
|
||||||
|
case int:
|
||||||
|
cookie.MaxAge = v
|
||||||
|
case int64:
|
||||||
|
cookie.MaxAge = int(v)
|
||||||
|
case int32:
|
||||||
|
cookie.MaxAge = int(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default "/"
|
||||||
|
if len(others) > 1 {
|
||||||
|
if v, ok := others[1].(string); ok && len(v) > 0 {
|
||||||
|
cookie.Path = v
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cookie.Path = "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
// default empty
|
||||||
|
if len(others) > 2 {
|
||||||
|
if v, ok := others[2].(string); ok && len(v) > 0 {
|
||||||
|
cookie.Domain = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default empty
|
||||||
|
if len(others) > 3 {
|
||||||
|
switch v := others[3].(type) {
|
||||||
|
case bool:
|
||||||
|
cookie.Secure = v
|
||||||
|
default:
|
||||||
|
if others[3] != nil {
|
||||||
|
cookie.Secure = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default false. for session cookie default true
|
||||||
|
if len(others) > 4 {
|
||||||
|
if v, ok := others[4].(bool); ok && v {
|
||||||
|
cookie.HttpOnly = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Res.Header().Add("Set-Cookie", cookie.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get secure cookie from request by a given key.
|
||||||
|
func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) {
|
||||||
|
val := ctx.GetCookie(key)
|
||||||
|
if val == "" {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.SplitN(val, "|", 3)
|
||||||
|
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
vs := parts[0]
|
||||||
|
timestamp := parts[1]
|
||||||
|
sig := parts[2]
|
||||||
|
|
||||||
|
h := hmac.New(sha1.New, []byte(Secret))
|
||||||
|
fmt.Fprintf(h, "%s%s", vs, timestamp)
|
||||||
|
|
||||||
|
if fmt.Sprintf("%02x", h.Sum(nil)) != sig {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
res, _ := base64.URLEncoding.DecodeString(vs)
|
||||||
|
return string(res), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Secure cookie for response.
|
||||||
|
func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) {
|
||||||
|
vs := base64.URLEncoding.EncodeToString([]byte(value))
|
||||||
|
timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||||
|
h := hmac.New(sha1.New, []byte(Secret))
|
||||||
|
fmt.Fprintf(h, "%s%s", vs, timestamp)
|
||||||
|
sig := fmt.Sprintf("%02x", h.Sum(nil))
|
||||||
|
cookie := strings.Join([]string{vs, timestamp, sig}, "|")
|
||||||
|
ctx.SetCookie(name, cookie, others...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) CsrfToken() string {
|
||||||
|
if len(ctx.csrfToken) > 0 {
|
||||||
|
return ctx.csrfToken
|
||||||
|
}
|
||||||
|
|
||||||
|
token := ctx.GetCookie("_csrf")
|
||||||
|
if len(token) == 0 {
|
||||||
|
token = base.GetRandomString(30)
|
||||||
|
ctx.SetCookie("_csrf", token)
|
||||||
|
}
|
||||||
|
ctx.csrfToken = token
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) CsrfTokenValid() bool {
|
||||||
|
token := ctx.Query("_csrf")
|
||||||
|
if token == "" {
|
||||||
|
token = ctx.Req.Header.Get("X-Csrf-Token")
|
||||||
|
}
|
||||||
|
if token == "" {
|
||||||
|
return false
|
||||||
|
} else if ctx.csrfToken != token {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// InitContext initializes a classic context for a request.
|
// InitContext initializes a classic context for a request.
|
||||||
func InitContext() martini.Handler {
|
func InitContext() martini.Handler {
|
||||||
return func(res http.ResponseWriter, r *http.Request, c martini.Context,
|
return func(res http.ResponseWriter, r *http.Request, c martini.Context, rd *Render) {
|
||||||
session sessions.Session, rd *Render) {
|
|
||||||
|
|
||||||
ctx := &Context{
|
ctx := &Context{
|
||||||
c: c,
|
c: c,
|
||||||
// p: p,
|
// p: p,
|
||||||
Req: r,
|
Req: r,
|
||||||
Res: res,
|
Res: res,
|
||||||
Session: session,
|
|
||||||
Cache: base.Cache,
|
Cache: base.Cache,
|
||||||
Render: rd,
|
Render: rd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.Data["PageStartTime"] = time.Now()
|
||||||
|
|
||||||
|
// start session
|
||||||
|
ctx.Session = base.SessionManager.SessionStart(res, r)
|
||||||
|
rw := res.(martini.ResponseWriter)
|
||||||
|
rw.Before(func(martini.ResponseWriter) {
|
||||||
|
ctx.Session.SessionRelease(res)
|
||||||
|
})
|
||||||
|
|
||||||
// Get user from session if logined.
|
// Get user from session if logined.
|
||||||
user := auth.SignedInUser(session)
|
user := auth.SignedInUser(ctx.Session)
|
||||||
ctx.User = user
|
ctx.User = user
|
||||||
ctx.IsSigned = user != nil
|
ctx.IsSigned = user != nil
|
||||||
|
|
||||||
|
@ -119,7 +261,9 @@ func InitContext() martini.Handler {
|
||||||
ctx.Data["IsAdmin"] = ctx.User.IsAdmin
|
ctx.Data["IsAdmin"] = ctx.User.IsAdmin
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["PageStartTime"] = time.Now()
|
// get or create csrf token
|
||||||
|
ctx.Data["CsrfToken"] = ctx.CsrfToken()
|
||||||
|
ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + ctx.csrfToken + `">`)
|
||||||
|
|
||||||
c.Map(ctx)
|
c.Map(ctx)
|
||||||
|
|
||||||
|
|
|
@ -242,8 +242,11 @@ func (r *Render) HTMLString(name string, binding interface{}, htmlOpt ...HTMLOpt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Render) Error(status int) {
|
func (r *Render) Error(status int, message ...string) {
|
||||||
r.WriteHeader(status)
|
r.WriteHeader(status)
|
||||||
|
if len(message) > 0 {
|
||||||
|
r.Write([]byte(message[0]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Render) Redirect(location string, status ...int) {
|
func (r *Render) Redirect(location string, status ...int) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ func RepoAssignment(redirect bool) martini.Handler {
|
||||||
ctx.Repo.Owner = user
|
ctx.Repo.Owner = user
|
||||||
|
|
||||||
// get repository
|
// get repository
|
||||||
repo, err := models.GetRepositoryByName(user, params["reponame"])
|
repo, err := models.GetRepositoryByName(user.Id, params["reponame"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if redirect {
|
if redirect {
|
||||||
ctx.Redirect("/")
|
ctx.Redirect("/")
|
||||||
|
|
|
@ -346,6 +346,10 @@ html, body {
|
||||||
border-left: 4px solid #DD4B39;
|
border-left: 4px solid #DD4B39;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#gogs-repo-setting-container .form-horizontal label {
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
/* gogits user ssh keys */
|
/* gogits user ssh keys */
|
||||||
|
|
||||||
#gogs-ssh-keys .list-group-item {
|
#gogs-ssh-keys .list-group-item {
|
||||||
|
|
|
@ -2,6 +2,39 @@ var Gogits = {
|
||||||
"PageIsSignup": false
|
"PageIsSignup": false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(function($){
|
||||||
|
// extend jQuery ajax, set csrf token value
|
||||||
|
var ajax = $.ajax;
|
||||||
|
$.extend({
|
||||||
|
ajax: function(url, options) {
|
||||||
|
if (typeof url === 'object') {
|
||||||
|
options = url;
|
||||||
|
url = undefined;
|
||||||
|
}
|
||||||
|
options = options || {};
|
||||||
|
url = options.url;
|
||||||
|
var csrftoken = $('meta[name=_csrf]').attr('content');
|
||||||
|
var headers = options.headers || {};
|
||||||
|
var domain = document.domain.replace(/\./ig, '\\.');
|
||||||
|
if (!/^(http:|https:).*/.test(url) || eval('/^(http:|https:)\\/\\/(.+\\.)*' + domain + '.*/').test(url)) {
|
||||||
|
headers = $.extend(headers, {'X-Csrf-Token':csrftoken});
|
||||||
|
}
|
||||||
|
options.headers = headers;
|
||||||
|
var callback = options.success;
|
||||||
|
options.success = function(data){
|
||||||
|
if(data.once){
|
||||||
|
// change all _once value if ajax data.once exist
|
||||||
|
$('[name=_once]').val(data.once);
|
||||||
|
}
|
||||||
|
if(callback){
|
||||||
|
callback.apply(this, arguments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return ajax(url, options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}(jQuery));
|
||||||
|
|
||||||
(function ($) {
|
(function ($) {
|
||||||
|
|
||||||
Gogits.showTab = function (selector, index) {
|
Gogits.showTab = function (selector, index) {
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/codegangsta/martini"
|
||||||
|
|
||||||
|
@ -14,10 +17,93 @@ import (
|
||||||
"github.com/gogits/gogs/modules/middleware"
|
"github.com/gogits/gogs/modules/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var startTime = time.Now()
|
||||||
|
|
||||||
|
var sysStatus struct {
|
||||||
|
Uptime string
|
||||||
|
NumGoroutine int
|
||||||
|
|
||||||
|
// General statistics.
|
||||||
|
MemAllocated string // bytes allocated and still in use
|
||||||
|
MemTotal string // bytes allocated (even if freed)
|
||||||
|
MemSys string // bytes obtained from system (sum of XxxSys below)
|
||||||
|
Lookups uint64 // number of pointer lookups
|
||||||
|
MemMallocs uint64 // number of mallocs
|
||||||
|
MemFrees uint64 // number of frees
|
||||||
|
|
||||||
|
// Main allocation heap statistics.
|
||||||
|
HeapAlloc string // bytes allocated and still in use
|
||||||
|
HeapSys string // bytes obtained from system
|
||||||
|
HeapIdle string // bytes in idle spans
|
||||||
|
HeapInuse string // bytes in non-idle span
|
||||||
|
HeapReleased string // bytes released to the OS
|
||||||
|
HeapObjects uint64 // total number of allocated objects
|
||||||
|
|
||||||
|
// Low-level fixed-size structure allocator statistics.
|
||||||
|
// Inuse is bytes used now.
|
||||||
|
// Sys is bytes obtained from system.
|
||||||
|
StackInuse string // bootstrap stacks
|
||||||
|
StackSys string
|
||||||
|
MSpanInuse string // mspan structures
|
||||||
|
MSpanSys string
|
||||||
|
MCacheInuse string // mcache structures
|
||||||
|
MCacheSys string
|
||||||
|
BuckHashSys string // profiling bucket hash table
|
||||||
|
GCSys string // GC metadata
|
||||||
|
OtherSys string // other system allocations
|
||||||
|
|
||||||
|
// Garbage collector statistics.
|
||||||
|
NextGC string // next run in HeapAlloc time (bytes)
|
||||||
|
LastGC string // last run in absolute time (ns)
|
||||||
|
PauseTotalNs string
|
||||||
|
PauseNs string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
|
||||||
|
NumGC uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateSystemStatus() {
|
||||||
|
sysStatus.Uptime = base.TimeSincePro(startTime)
|
||||||
|
|
||||||
|
m := new(runtime.MemStats)
|
||||||
|
runtime.ReadMemStats(m)
|
||||||
|
sysStatus.NumGoroutine = runtime.NumGoroutine()
|
||||||
|
|
||||||
|
sysStatus.MemAllocated = base.FileSize(int64(m.Alloc))
|
||||||
|
sysStatus.MemTotal = base.FileSize(int64(m.TotalAlloc))
|
||||||
|
sysStatus.MemSys = base.FileSize(int64(m.Sys))
|
||||||
|
sysStatus.Lookups = m.Lookups
|
||||||
|
sysStatus.MemMallocs = m.Mallocs
|
||||||
|
sysStatus.MemFrees = m.Frees
|
||||||
|
|
||||||
|
sysStatus.HeapAlloc = base.FileSize(int64(m.HeapAlloc))
|
||||||
|
sysStatus.HeapSys = base.FileSize(int64(m.HeapSys))
|
||||||
|
sysStatus.HeapIdle = base.FileSize(int64(m.HeapIdle))
|
||||||
|
sysStatus.HeapInuse = base.FileSize(int64(m.HeapInuse))
|
||||||
|
sysStatus.HeapReleased = base.FileSize(int64(m.HeapReleased))
|
||||||
|
sysStatus.HeapObjects = m.HeapObjects
|
||||||
|
|
||||||
|
sysStatus.StackInuse = base.FileSize(int64(m.StackInuse))
|
||||||
|
sysStatus.StackSys = base.FileSize(int64(m.StackSys))
|
||||||
|
sysStatus.MSpanInuse = base.FileSize(int64(m.MSpanInuse))
|
||||||
|
sysStatus.MSpanSys = base.FileSize(int64(m.MSpanSys))
|
||||||
|
sysStatus.MCacheInuse = base.FileSize(int64(m.MCacheInuse))
|
||||||
|
sysStatus.MCacheSys = base.FileSize(int64(m.MCacheSys))
|
||||||
|
sysStatus.BuckHashSys = base.FileSize(int64(m.BuckHashSys))
|
||||||
|
sysStatus.GCSys = base.FileSize(int64(m.GCSys))
|
||||||
|
sysStatus.OtherSys = base.FileSize(int64(m.OtherSys))
|
||||||
|
|
||||||
|
sysStatus.NextGC = base.FileSize(int64(m.NextGC))
|
||||||
|
sysStatus.LastGC = fmt.Sprintf("%.1fs", float64(time.Now().UnixNano()-int64(m.LastGC))/1000/1000/1000)
|
||||||
|
sysStatus.PauseTotalNs = fmt.Sprintf("%.1fs", float64(m.PauseTotalNs)/1000/1000/1000)
|
||||||
|
sysStatus.PauseNs = fmt.Sprintf("%.3fs", float64(m.PauseNs[(m.NumGC+255)%256])/1000/1000/1000)
|
||||||
|
sysStatus.NumGC = m.NumGC
|
||||||
|
}
|
||||||
|
|
||||||
func Dashboard(ctx *middleware.Context) {
|
func Dashboard(ctx *middleware.Context) {
|
||||||
ctx.Data["Title"] = "Admin Dashboard"
|
ctx.Data["Title"] = "Admin Dashboard"
|
||||||
ctx.Data["PageIsDashboard"] = true
|
ctx.Data["PageIsDashboard"] = true
|
||||||
ctx.Data["Stats"] = models.GetStatistic()
|
ctx.Data["Stats"] = models.GetStatistic()
|
||||||
|
updateSystemStatus()
|
||||||
|
ctx.Data["SysStatus"] = sysStatus
|
||||||
ctx.HTML(200, "admin/dashboard")
|
ctx.HTML(200, "admin/dashboard")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +156,12 @@ func Config(ctx *middleware.Context) {
|
||||||
ctx.Data["CacheAdapter"] = base.CacheAdapter
|
ctx.Data["CacheAdapter"] = base.CacheAdapter
|
||||||
ctx.Data["CacheConfig"] = base.CacheConfig
|
ctx.Data["CacheConfig"] = base.CacheConfig
|
||||||
|
|
||||||
|
ctx.Data["SessionProvider"] = base.SessionProvider
|
||||||
|
ctx.Data["SessionConfig"] = base.SessionConfig
|
||||||
|
|
||||||
|
ctx.Data["PictureService"] = base.PictureService
|
||||||
|
ctx.Data["PictureRootPath"] = base.PictureRootPath
|
||||||
|
|
||||||
ctx.Data["LogMode"] = base.LogMode
|
ctx.Data["LogMode"] = base.LogMode
|
||||||
ctx.Data["LogConfig"] = base.LogConfig
|
ctx.Data["LogConfig"] = base.LogConfig
|
||||||
|
|
||||||
|
|
|
@ -107,3 +107,38 @@ func EditUser(ctx *middleware.Context, params martini.Params, form auth.AdminEdi
|
||||||
log.Trace("%s User profile updated by admin(%s): %s", ctx.Req.RequestURI,
|
log.Trace("%s User profile updated by admin(%s): %s", ctx.Req.RequestURI,
|
||||||
ctx.User.LowerName, ctx.User.LowerName)
|
ctx.User.LowerName, ctx.User.LowerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteUser(ctx *middleware.Context, params martini.Params) {
|
||||||
|
ctx.Data["Title"] = "Edit Account"
|
||||||
|
ctx.Data["PageIsUsers"] = true
|
||||||
|
|
||||||
|
uid, err := base.StrTo(params["userid"]).Int()
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(200, "admin.user.EditUser", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := models.GetUserById(int64(uid))
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(200, "admin.user.EditUser", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = models.DeleteUser(u); err != nil {
|
||||||
|
ctx.Data["HasError"] = true
|
||||||
|
switch err {
|
||||||
|
case models.ErrUserOwnRepos:
|
||||||
|
ctx.Data["ErrorMsg"] = "This account still has ownership of repository, owner has to delete or transfer them first."
|
||||||
|
ctx.Data["User"] = u
|
||||||
|
ctx.HTML(200, "admin/users/edit")
|
||||||
|
default:
|
||||||
|
ctx.Handle(200, "admin.user.DeleteUser", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace("%s User deleted by admin(%s): %s", ctx.Req.RequestURI,
|
||||||
|
ctx.User.LowerName, ctx.User.LowerName)
|
||||||
|
|
||||||
|
ctx.Redirect("/admin/users")
|
||||||
|
}
|
||||||
|
|
|
@ -20,5 +20,12 @@ func Home(ctx *middleware.Context) {
|
||||||
|
|
||||||
func Help(ctx *middleware.Context) {
|
func Help(ctx *middleware.Context) {
|
||||||
ctx.Data["PageIsHelp"] = true
|
ctx.Data["PageIsHelp"] = true
|
||||||
|
ctx.Data["Title"] = "Help"
|
||||||
ctx.HTML(200, "help")
|
ctx.HTML(200, "help")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NotFound(ctx *middleware.Context) {
|
||||||
|
ctx.Data["PageIsNotFound"] = true
|
||||||
|
ctx.Data["Title"] = 404
|
||||||
|
ctx.Handle(404, "home.NotFound", nil)
|
||||||
|
}
|
||||||
|
|
85
routers/repo/issue.go
Normal file
85
routers/repo/issue.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/codegangsta/martini"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/models"
|
||||||
|
"github.com/gogits/gogs/modules/auth"
|
||||||
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
"github.com/gogits/gogs/modules/log"
|
||||||
|
"github.com/gogits/gogs/modules/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Issues(ctx *middleware.Context, params martini.Params) {
|
||||||
|
ctx.Data["Title"] = "Issues"
|
||||||
|
ctx.Data["IsRepoToolbarIssues"] = true
|
||||||
|
|
||||||
|
milestoneId, _ := base.StrTo(params["milestone"]).Int()
|
||||||
|
page, _ := base.StrTo(params["page"]).Int()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
ctx.Data["Issues"], err = models.GetIssues(0, ctx.Repo.Repository.Id, 0,
|
||||||
|
int64(milestoneId), page, params["state"] == "closed", false, params["labels"], params["sortType"])
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(200, "issue.Issues: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.HTML(200, "repo/issues")
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
|
||||||
|
if !ctx.Repo.IsOwner {
|
||||||
|
ctx.Handle(404, "issue.CreateIssue", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["Title"] = "Create issue"
|
||||||
|
|
||||||
|
if ctx.Req.Method == "GET" {
|
||||||
|
ctx.HTML(200, "issue/create")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.HasError() {
|
||||||
|
ctx.HTML(200, "issue/create")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
issue, err := models.CreateIssue(ctx.User.Id, form.RepoId, form.MilestoneId, form.AssigneeId,
|
||||||
|
form.IssueName, form.Labels, form.Content, false)
|
||||||
|
if err == nil {
|
||||||
|
log.Trace("%s Issue created: %d", form.RepoId, issue.Id)
|
||||||
|
ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", params["username"], params["reponame"], issue.Index))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Handle(200, "issue.CreateIssue", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ViewIssue(ctx *middleware.Context, params martini.Params) {
|
||||||
|
issueid, err := base.StrTo(params["issueid"]).Int()
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(404, "issue.ViewIssue", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
issue, err := models.GetIssueById(int64(issueid))
|
||||||
|
if err != nil {
|
||||||
|
if err == models.ErrIssueNotExist {
|
||||||
|
ctx.Handle(404, "issue.ViewIssue", err)
|
||||||
|
} else {
|
||||||
|
ctx.Handle(200, "issue.ViewIssue", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["Title"] = issue.Name
|
||||||
|
ctx.Data["Issue"] = issue
|
||||||
|
ctx.HTML(200, "issue/view")
|
||||||
|
}
|
|
@ -5,8 +5,17 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/codegangsta/martini"
|
||||||
|
|
||||||
|
"github.com/gogits/git"
|
||||||
|
"github.com/gogits/webdav"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/auth"
|
"github.com/gogits/gogs/modules/auth"
|
||||||
|
"github.com/gogits/gogs/modules/base"
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
"github.com/gogits/gogs/modules/middleware"
|
"github.com/gogits/gogs/modules/middleware"
|
||||||
)
|
)
|
||||||
|
@ -22,11 +31,16 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctx.HasError() {
|
||||||
|
ctx.HTML(200, "repo/create")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
_, err := models.CreateRepository(ctx.User, form.RepoName, form.Description,
|
_, err := models.CreateRepository(ctx.User, form.RepoName, form.Description,
|
||||||
form.Language, form.License, form.Visibility == "private", form.InitReadme == "on")
|
form.Language, form.License, form.Visibility == "private", form.InitReadme == "on")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName)
|
log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName)
|
||||||
ctx.Redirect("/"+ctx.User.Name+"/"+form.RepoName, 302)
|
ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName)
|
||||||
return
|
return
|
||||||
} else if err == models.ErrRepoAlreadyExist {
|
} else if err == models.ErrRepoAlreadyExist {
|
||||||
ctx.RenderWithErr("Repository name has already been used", "repo/create", &form)
|
ctx.RenderWithErr("Repository name has already been used", "repo/create", &form)
|
||||||
|
@ -59,5 +73,290 @@ func SettingPost(ctx *middleware.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName)
|
log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName)
|
||||||
ctx.Redirect("/", 302)
|
ctx.Redirect("/")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Branches(ctx *middleware.Context, params martini.Params) {
|
||||||
|
if !ctx.Repo.IsValid {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
brs, err := models.GetBranches(params["username"], params["reponame"])
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(200, "repo.Branches", err)
|
||||||
|
return
|
||||||
|
} else if len(brs) == 0 {
|
||||||
|
ctx.Handle(404, "repo.Branches", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["Username"] = params["username"]
|
||||||
|
ctx.Data["Reponame"] = params["reponame"]
|
||||||
|
|
||||||
|
ctx.Data["Branchname"] = brs[0]
|
||||||
|
ctx.Data["Branches"] = brs
|
||||||
|
ctx.Data["IsRepoToolbarBranches"] = true
|
||||||
|
|
||||||
|
ctx.HTML(200, "repo/branches")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Single(ctx *middleware.Context, params martini.Params) {
|
||||||
|
if !ctx.Repo.IsValid {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params["branchname"]) == 0 {
|
||||||
|
params["branchname"] = "master"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get tree path
|
||||||
|
treename := params["_1"]
|
||||||
|
|
||||||
|
if len(treename) > 0 && treename[len(treename)-1] == '/' {
|
||||||
|
ctx.Redirect("/" + ctx.Repo.Owner.LowerName + "/" +
|
||||||
|
ctx.Repo.Repository.Name + "/src/" + params["branchname"] + "/" + treename[:len(treename)-1])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["IsRepoToolbarSource"] = true
|
||||||
|
|
||||||
|
// Branches.
|
||||||
|
brs, err := models.GetBranches(params["username"], params["reponame"])
|
||||||
|
if err != nil {
|
||||||
|
//log.Error("repo.Single(GetBranches): %v", err)
|
||||||
|
ctx.Handle(404, "repo.Single(GetBranches)", err)
|
||||||
|
return
|
||||||
|
} else if ctx.Repo.Repository.IsBare {
|
||||||
|
ctx.Data["IsBareRepo"] = true
|
||||||
|
ctx.HTML(200, "repo/single")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["Branches"] = brs
|
||||||
|
|
||||||
|
repoFile, err := models.GetTargetFile(params["username"], params["reponame"],
|
||||||
|
params["branchname"], params["commitid"], treename)
|
||||||
|
|
||||||
|
if err != nil && err != models.ErrRepoFileNotExist {
|
||||||
|
//log.Error("repo.Single(GetTargetFile): %v", err)
|
||||||
|
ctx.Handle(404, "repo.Single(GetTargetFile)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
branchLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/src/" + params["branchname"]
|
||||||
|
|
||||||
|
if len(treename) != 0 && repoFile == nil {
|
||||||
|
ctx.Handle(404, "repo.Single", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if repoFile != nil && repoFile.IsFile() {
|
||||||
|
if repoFile.Size > 1024*1024 || repoFile.Filemode != git.FileModeBlob {
|
||||||
|
ctx.Data["FileIsLarge"] = true
|
||||||
|
} else if blob, err := repoFile.LookupBlob(); err != nil {
|
||||||
|
//log.Error("repo.Single(repoFile.LookupBlob): %v", err)
|
||||||
|
ctx.Handle(404, "repo.Single(repoFile.LookupBlob)", err)
|
||||||
|
} else {
|
||||||
|
ctx.Data["IsFile"] = true
|
||||||
|
ctx.Data["FileName"] = repoFile.Name
|
||||||
|
ext := path.Ext(repoFile.Name)
|
||||||
|
if len(ext) > 0 {
|
||||||
|
ext = ext[1:]
|
||||||
|
}
|
||||||
|
ctx.Data["FileExt"] = ext
|
||||||
|
|
||||||
|
readmeExist := base.IsMarkdownFile(repoFile.Name) || base.IsReadmeFile(repoFile.Name)
|
||||||
|
ctx.Data["ReadmeExist"] = readmeExist
|
||||||
|
if readmeExist {
|
||||||
|
ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), ""))
|
||||||
|
} else {
|
||||||
|
ctx.Data["FileContent"] = string(blob.Contents())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Directory and file list.
|
||||||
|
files, err := models.GetReposFiles(params["username"], params["reponame"],
|
||||||
|
params["branchname"], params["commitid"], treename)
|
||||||
|
if err != nil {
|
||||||
|
//log.Error("repo.Single(GetReposFiles): %v", err)
|
||||||
|
ctx.Handle(404, "repo.Single(GetReposFiles)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["Files"] = files
|
||||||
|
|
||||||
|
var readmeFile *models.RepoFile
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
if !f.IsFile() || !base.IsReadmeFile(f.Name) {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
readmeFile = f
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if readmeFile != nil {
|
||||||
|
ctx.Data["ReadmeExist"] = true
|
||||||
|
// if file large than 1M not show it
|
||||||
|
if readmeFile.Size > 1024*1024 || readmeFile.Filemode != git.FileModeBlob {
|
||||||
|
ctx.Data["FileIsLarge"] = true
|
||||||
|
} else if blob, err := readmeFile.LookupBlob(); err != nil {
|
||||||
|
//log.Error("repo.Single(readmeFile.LookupBlob): %v", err)
|
||||||
|
ctx.Handle(404, "repo.Single(readmeFile.LookupBlob)", err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// current repo branch link
|
||||||
|
|
||||||
|
ctx.Data["FileName"] = readmeFile.Name
|
||||||
|
ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), branchLink))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["Username"] = params["username"]
|
||||||
|
ctx.Data["Reponame"] = params["reponame"]
|
||||||
|
ctx.Data["Branchname"] = params["branchname"]
|
||||||
|
|
||||||
|
var treenames []string
|
||||||
|
Paths := make([]string, 0)
|
||||||
|
|
||||||
|
if len(treename) > 0 {
|
||||||
|
treenames = strings.Split(treename, "/")
|
||||||
|
for i, _ := range treenames {
|
||||||
|
Paths = append(Paths, strings.Join(treenames[0:i+1], "/"))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["HasParentPath"] = true
|
||||||
|
if len(Paths)-2 >= 0 {
|
||||||
|
ctx.Data["ParentPath"] = "/" + Paths[len(Paths)-2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get latest commit according username and repo name
|
||||||
|
commit, err := models.GetCommit(params["username"], params["reponame"],
|
||||||
|
params["branchname"], params["commitid"])
|
||||||
|
if err != nil {
|
||||||
|
log.Error("repo.Single(GetCommit): %v", err)
|
||||||
|
ctx.Handle(404, "repo.Single(GetCommit)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Data["LastCommit"] = commit
|
||||||
|
|
||||||
|
ctx.Data["Paths"] = Paths
|
||||||
|
ctx.Data["Treenames"] = treenames
|
||||||
|
ctx.Data["BranchLink"] = branchLink
|
||||||
|
ctx.HTML(200, "repo/single")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Http(ctx *middleware.Context, params martini.Params) {
|
||||||
|
/*if !ctx.Repo.IsValid {
|
||||||
|
return
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// TODO: access check
|
||||||
|
|
||||||
|
username := params["username"]
|
||||||
|
reponame := params["reponame"]
|
||||||
|
if strings.HasSuffix(reponame, ".git") {
|
||||||
|
reponame = reponame[:len(reponame)-4]
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix := path.Join("/", username, params["reponame"])
|
||||||
|
server := &webdav.Server{
|
||||||
|
Fs: webdav.Dir(models.RepoPath(username, reponame)),
|
||||||
|
TrimPrefix: prefix,
|
||||||
|
Listings: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
server.ServeHTTP(ctx.ResponseWriter, ctx.Req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setting(ctx *middleware.Context, params martini.Params) {
|
||||||
|
if !ctx.Repo.IsOwner {
|
||||||
|
ctx.Handle(404, "repo.Setting", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["IsRepoToolbarSetting"] = true
|
||||||
|
|
||||||
|
if ctx.Repo.Repository.IsBare {
|
||||||
|
ctx.Data["IsBareRepo"] = true
|
||||||
|
ctx.HTML(200, "repo/setting")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var title string
|
||||||
|
if t, ok := ctx.Data["Title"].(string); ok {
|
||||||
|
title = t
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params["branchname"]) == 0 {
|
||||||
|
params["branchname"] = "master"
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["Branchname"] = params["branchname"]
|
||||||
|
ctx.Data["Title"] = title + " - settings"
|
||||||
|
ctx.HTML(200, "repo/setting")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Commits(ctx *middleware.Context, params martini.Params) {
|
||||||
|
brs, err := models.GetBranches(params["username"], params["reponame"])
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(200, "repo.Commits", err)
|
||||||
|
return
|
||||||
|
} else if len(brs) == 0 {
|
||||||
|
ctx.Handle(404, "repo.Commits", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["IsRepoToolbarCommits"] = true
|
||||||
|
commits, err := models.GetCommits(params["username"],
|
||||||
|
params["reponame"], params["branchname"])
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(404, "repo.Commits", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Data["Username"] = params["username"]
|
||||||
|
ctx.Data["Reponame"] = params["reponame"]
|
||||||
|
ctx.Data["CommitCount"] = commits.Len()
|
||||||
|
ctx.Data["Commits"] = commits
|
||||||
|
ctx.HTML(200, "repo/commits")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Pulls(ctx *middleware.Context) {
|
||||||
|
ctx.Data["IsRepoToolbarPulls"] = true
|
||||||
|
ctx.HTML(200, "repo/pulls")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Action(ctx *middleware.Context, params martini.Params) {
|
||||||
|
var err error
|
||||||
|
switch params["action"] {
|
||||||
|
case "watch":
|
||||||
|
err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
|
||||||
|
case "unwatch":
|
||||||
|
err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
|
||||||
|
case "desc":
|
||||||
|
if !ctx.Repo.IsOwner {
|
||||||
|
ctx.Error(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Repo.Repository.Description = ctx.Query("desc")
|
||||||
|
ctx.Repo.Repository.Website = ctx.Query("site")
|
||||||
|
err = models.UpdateRepository(ctx.Repo.Repository)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("repo.Action(%s): %v", params["action"], err)
|
||||||
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
"ok": false,
|
||||||
|
"err": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
"ok": true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,307 +0,0 @@
|
||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package repo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
|
||||||
|
|
||||||
"github.com/gogits/git"
|
|
||||||
"github.com/gogits/webdav"
|
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
|
||||||
"github.com/gogits/gogs/modules/base"
|
|
||||||
"github.com/gogits/gogs/modules/log"
|
|
||||||
"github.com/gogits/gogs/modules/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Branches(ctx *middleware.Context, params martini.Params) {
|
|
||||||
if !ctx.Repo.IsValid {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
brs, err := models.GetBranches(params["username"], params["reponame"])
|
|
||||||
if err != nil {
|
|
||||||
ctx.Handle(200, "repo.Branches", err)
|
|
||||||
return
|
|
||||||
} else if len(brs) == 0 {
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Username"] = params["username"]
|
|
||||||
ctx.Data["Reponame"] = params["reponame"]
|
|
||||||
|
|
||||||
ctx.Data["Branchname"] = brs[0]
|
|
||||||
ctx.Data["Branches"] = brs
|
|
||||||
ctx.Data["IsRepoToolbarBranches"] = true
|
|
||||||
|
|
||||||
ctx.HTML(200, "repo/branches")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Single(ctx *middleware.Context, params martini.Params) {
|
|
||||||
if !ctx.Repo.IsValid {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(params["branchname"]) == 0 {
|
|
||||||
params["branchname"] = "master"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get tree path
|
|
||||||
treename := params["_1"]
|
|
||||||
|
|
||||||
if len(treename) > 0 && treename[len(treename)-1] == '/' {
|
|
||||||
ctx.Redirect("/"+ctx.Repo.Owner.LowerName+"/"+
|
|
||||||
ctx.Repo.Repository.Name+"/src/"+params["branchname"]+"/"+treename[:len(treename)-1], 302)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["IsRepoToolbarSource"] = true
|
|
||||||
|
|
||||||
// Branches.
|
|
||||||
brs, err := models.GetBranches(params["username"], params["reponame"])
|
|
||||||
if err != nil {
|
|
||||||
log.Error("repo.Single(GetBranches): %v", err)
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
} else if len(brs) == 0 {
|
|
||||||
ctx.Data["IsBareRepo"] = true
|
|
||||||
ctx.HTML(200, "repo/single")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Branches"] = brs
|
|
||||||
|
|
||||||
repoFile, err := models.GetTargetFile(params["username"], params["reponame"],
|
|
||||||
params["branchname"], params["commitid"], treename)
|
|
||||||
|
|
||||||
if err != nil && err != models.ErrRepoFileNotExist {
|
|
||||||
log.Error("repo.Single(GetTargetFile): %v", err)
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
branchLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/src/" + params["branchname"]
|
|
||||||
|
|
||||||
if len(treename) != 0 && repoFile == nil {
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if repoFile != nil && repoFile.IsFile() {
|
|
||||||
if repoFile.Size > 1024*1024 || repoFile.Filemode != git.FileModeBlob {
|
|
||||||
ctx.Data["FileIsLarge"] = true
|
|
||||||
} else if blob, err := repoFile.LookupBlob(); err != nil {
|
|
||||||
log.Error("repo.Single(repoFile.LookupBlob): %v", err)
|
|
||||||
ctx.Error(404)
|
|
||||||
} else {
|
|
||||||
ctx.Data["IsFile"] = true
|
|
||||||
ctx.Data["FileName"] = repoFile.Name
|
|
||||||
ext := path.Ext(repoFile.Name)
|
|
||||||
if len(ext) > 0 {
|
|
||||||
ext = ext[1:]
|
|
||||||
}
|
|
||||||
ctx.Data["FileExt"] = ext
|
|
||||||
|
|
||||||
readmeExist := base.IsMarkdownFile(repoFile.Name) || base.IsReadmeFile(repoFile.Name)
|
|
||||||
ctx.Data["ReadmeExist"] = readmeExist
|
|
||||||
if readmeExist {
|
|
||||||
ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), ""))
|
|
||||||
} else {
|
|
||||||
ctx.Data["FileContent"] = string(blob.Contents())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Directory and file list.
|
|
||||||
files, err := models.GetReposFiles(params["username"], params["reponame"],
|
|
||||||
params["branchname"], params["commitid"], treename)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("repo.Single(GetReposFiles): %v", err)
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Files"] = files
|
|
||||||
|
|
||||||
var readmeFile *models.RepoFile
|
|
||||||
|
|
||||||
for _, f := range files {
|
|
||||||
if !f.IsFile() || !base.IsReadmeFile(f.Name) {
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
readmeFile = f
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if readmeFile != nil {
|
|
||||||
ctx.Data["ReadmeExist"] = true
|
|
||||||
// if file large than 1M not show it
|
|
||||||
if readmeFile.Size > 1024*1024 || readmeFile.Filemode != git.FileModeBlob {
|
|
||||||
ctx.Data["FileIsLarge"] = true
|
|
||||||
} else if blob, err := readmeFile.LookupBlob(); err != nil {
|
|
||||||
log.Error("repo.Single(readmeFile.LookupBlob): %v", err)
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
// current repo branch link
|
|
||||||
|
|
||||||
ctx.Data["FileName"] = readmeFile.Name
|
|
||||||
ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), branchLink))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Username"] = params["username"]
|
|
||||||
ctx.Data["Reponame"] = params["reponame"]
|
|
||||||
ctx.Data["Branchname"] = params["branchname"]
|
|
||||||
|
|
||||||
var treenames []string
|
|
||||||
Paths := make([]string, 0)
|
|
||||||
|
|
||||||
if len(treename) > 0 {
|
|
||||||
treenames = strings.Split(treename, "/")
|
|
||||||
for i, _ := range treenames {
|
|
||||||
Paths = append(Paths, strings.Join(treenames[0:i+1], "/"))
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["HasParentPath"] = true
|
|
||||||
if len(Paths)-2 >= 0 {
|
|
||||||
ctx.Data["ParentPath"] = "/" + Paths[len(Paths)-2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get latest commit according username and repo name
|
|
||||||
commit, err := models.GetCommit(params["username"], params["reponame"],
|
|
||||||
params["branchname"], params["commitid"])
|
|
||||||
if err != nil {
|
|
||||||
log.Error("repo.Single(GetCommit): %v", err)
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Data["LastCommit"] = commit
|
|
||||||
|
|
||||||
ctx.Data["Paths"] = Paths
|
|
||||||
ctx.Data["Treenames"] = treenames
|
|
||||||
ctx.Data["BranchLink"] = branchLink
|
|
||||||
ctx.HTML(200, "repo/single")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Http(ctx *middleware.Context, params martini.Params) {
|
|
||||||
/*if !ctx.Repo.IsValid {
|
|
||||||
return
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// TODO: access check
|
|
||||||
|
|
||||||
username := params["username"]
|
|
||||||
reponame := params["reponame"]
|
|
||||||
if strings.HasSuffix(reponame, ".git") {
|
|
||||||
reponame = reponame[:len(reponame)-4]
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix := path.Join("/", username, params["reponame"])
|
|
||||||
server := &webdav.Server{
|
|
||||||
Fs: webdav.Dir(models.RepoPath(username, reponame)),
|
|
||||||
TrimPrefix: prefix,
|
|
||||||
Listings: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
server.ServeHTTP(ctx.ResponseWriter, ctx.Req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Setting(ctx *middleware.Context, params martini.Params) {
|
|
||||||
if !ctx.Repo.IsOwner {
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["IsRepoToolbarSetting"] = true
|
|
||||||
|
|
||||||
// Branches.
|
|
||||||
brs, err := models.GetBranches(params["username"], params["reponame"])
|
|
||||||
if err != nil {
|
|
||||||
log.Error("repo.Setting(GetBranches): %v", err)
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
} else if len(brs) == 0 {
|
|
||||||
ctx.Data["IsBareRepo"] = true
|
|
||||||
ctx.HTML(200, "repo/setting")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var title string
|
|
||||||
if t, ok := ctx.Data["Title"].(string); ok {
|
|
||||||
title = t
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(params["branchname"]) == 0 {
|
|
||||||
params["branchname"] = "master"
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Branchname"] = params["branchname"]
|
|
||||||
ctx.Data["Title"] = title + " - settings"
|
|
||||||
ctx.HTML(200, "repo/setting")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Commits(ctx *middleware.Context, params martini.Params) {
|
|
||||||
brs, err := models.GetBranches(params["username"], params["reponame"])
|
|
||||||
if err != nil {
|
|
||||||
ctx.Handle(200, "repo.Commits", err)
|
|
||||||
return
|
|
||||||
} else if len(brs) == 0 {
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["IsRepoToolbarCommits"] = true
|
|
||||||
commits, err := models.GetCommits(params["username"],
|
|
||||||
params["reponame"], params["branchname"])
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Data["Username"] = params["username"]
|
|
||||||
ctx.Data["Reponame"] = params["reponame"]
|
|
||||||
ctx.Data["CommitCount"] = commits.Len()
|
|
||||||
ctx.Data["Commits"] = commits
|
|
||||||
ctx.HTML(200, "repo/commits")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Issues(ctx *middleware.Context) {
|
|
||||||
ctx.Data["IsRepoToolbarIssues"] = true
|
|
||||||
ctx.HTML(200, "repo/issues")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Pulls(ctx *middleware.Context) {
|
|
||||||
ctx.Data["IsRepoToolbarPulls"] = true
|
|
||||||
ctx.HTML(200, "repo/pulls")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Action(ctx *middleware.Context, params martini.Params) {
|
|
||||||
var err error
|
|
||||||
switch params["action"] {
|
|
||||||
case "watch":
|
|
||||||
err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
|
|
||||||
case "unwatch":
|
|
||||||
err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Error("repo.Action(%s): %v", params["action"], err)
|
|
||||||
ctx.JSON(200, map[string]interface{}{
|
|
||||||
"ok": false,
|
|
||||||
"err": err.Error(),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.JSON(200, map[string]interface{}{
|
|
||||||
"ok": true,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@ package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/codegangsta/martini"
|
||||||
|
@ -77,10 +78,48 @@ func SignIn(ctx *middleware.Context, form auth.LogInForm) {
|
||||||
ctx.Data["Title"] = "Log In"
|
ctx.Data["Title"] = "Log In"
|
||||||
|
|
||||||
if ctx.Req.Method == "GET" {
|
if ctx.Req.Method == "GET" {
|
||||||
|
// Check auto-login.
|
||||||
|
userName := ctx.GetCookie(base.CookieUserName)
|
||||||
|
if len(userName) == 0 {
|
||||||
ctx.HTML(200, "user/signin")
|
ctx.HTML(200, "user/signin")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSucceed := false
|
||||||
|
defer func() {
|
||||||
|
if !isSucceed {
|
||||||
|
log.Trace("%s auto-login cookie cleared: %s", ctx.Req.RequestURI, userName)
|
||||||
|
ctx.SetCookie(base.CookieUserName, "", -1)
|
||||||
|
ctx.SetCookie(base.CookieRememberName, "", -1)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
user, err := models.GetUserByName(userName)
|
||||||
|
if err != nil {
|
||||||
|
ctx.HTML(200, "user/signin")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
secret := base.EncodeMd5(user.Rands + user.Passwd)
|
||||||
|
value, _ := ctx.GetSecureCookie(secret, base.CookieRememberName)
|
||||||
|
if value != user.Name {
|
||||||
|
ctx.HTML(200, "user/signin")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isSucceed = true
|
||||||
|
ctx.Session.Set("userId", user.Id)
|
||||||
|
ctx.Session.Set("userName", user.Name)
|
||||||
|
redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to"))
|
||||||
|
if len(redirectTo) > 0 {
|
||||||
|
ctx.SetCookie("redirect_to", "", -1)
|
||||||
|
ctx.Redirect(redirectTo)
|
||||||
|
} else {
|
||||||
|
ctx.Redirect("/")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
|
if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
|
||||||
ctx.HTML(200, "user/signin")
|
ctx.HTML(200, "user/signin")
|
||||||
return
|
return
|
||||||
|
@ -88,7 +127,8 @@ func SignIn(ctx *middleware.Context, form auth.LogInForm) {
|
||||||
|
|
||||||
user, err := models.LoginUserPlain(form.UserName, form.Password)
|
user, err := models.LoginUserPlain(form.UserName, form.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == models.ErrUserNotExist.Error() {
|
if err == models.ErrUserNotExist {
|
||||||
|
log.Trace("%s Log in failed: %s/%s", ctx.Req.RequestURI, form.UserName, form.Password)
|
||||||
ctx.RenderWithErr("Username or password is not correct", "user/signin", &form)
|
ctx.RenderWithErr("Username or password is not correct", "user/signin", &form)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -97,14 +137,29 @@ func SignIn(ctx *middleware.Context, form auth.LogInForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if form.Remember == "on" {
|
||||||
|
secret := base.EncodeMd5(user.Rands + user.Passwd)
|
||||||
|
days := 86400 * base.LogInRememberDays
|
||||||
|
ctx.SetCookie(base.CookieUserName, user.Name, days)
|
||||||
|
ctx.SetSecureCookie(secret, base.CookieRememberName, user.Name, days)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Session.Set("userId", user.Id)
|
ctx.Session.Set("userId", user.Id)
|
||||||
ctx.Session.Set("userName", user.Name)
|
ctx.Session.Set("userName", user.Name)
|
||||||
|
redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to"))
|
||||||
|
if len(redirectTo) > 0 {
|
||||||
|
ctx.SetCookie("redirect_to", "", -1)
|
||||||
|
ctx.Redirect(redirectTo)
|
||||||
|
} else {
|
||||||
ctx.Redirect("/")
|
ctx.Redirect("/")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func SignOut(ctx *middleware.Context) {
|
func SignOut(ctx *middleware.Context) {
|
||||||
ctx.Session.Delete("userId")
|
ctx.Session.Delete("userId")
|
||||||
ctx.Session.Delete("userName")
|
ctx.Session.Delete("userName")
|
||||||
|
ctx.SetCookie(base.CookieUserName, "", -1)
|
||||||
|
ctx.SetCookie(base.CookieRememberName, "", -1)
|
||||||
ctx.Redirect("/")
|
ctx.Redirect("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +301,7 @@ func Activate(ctx *middleware.Context) {
|
||||||
if len(code) == 0 {
|
if len(code) == 0 {
|
||||||
ctx.Data["IsActivatePage"] = true
|
ctx.Data["IsActivatePage"] = true
|
||||||
if ctx.User.IsActive {
|
if ctx.User.IsActive {
|
||||||
ctx.Error(404)
|
ctx.Handle(404, "user.Activate", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Resend confirmation e-mail.
|
// Resend confirmation e-mail.
|
||||||
|
@ -274,7 +329,7 @@ func Activate(ctx *middleware.Context) {
|
||||||
|
|
||||||
ctx.Session.Set("userId", user.Id)
|
ctx.Session.Set("userId", user.Id)
|
||||||
ctx.Session.Set("userName", user.Name)
|
ctx.Session.Set("userName", user.Name)
|
||||||
ctx.Redirect("/", 302)
|
ctx.Redirect("/")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
serve.go
2
serve.go
|
@ -106,7 +106,7 @@ func runServ(k *cli.Context) {
|
||||||
|
|
||||||
//os.Setenv("userName", user.Name)
|
//os.Setenv("userName", user.Name)
|
||||||
//os.Setenv("userId", strconv.Itoa(int(user.Id)))
|
//os.Setenv("userId", strconv.Itoa(int(user.Id)))
|
||||||
repo, err := models.GetRepositoryByName(user, repoName)
|
repo, err := models.GetRepositoryByName(user.Id, repoName)
|
||||||
var isExist bool = true
|
var isExist bool = true
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == models.ErrRepoNotExist {
|
if err == models.ErrRepoNotExist {
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
<div><b>Register Email Confirmation:</b> <i class="fa fa{{if .Service.RegisterEmailConfirm}}-check{{end}}-square-o"></i></div>
|
<div><b>Register Email Confirmation:</b> <i class="fa fa{{if .Service.RegisterEmailConfirm}}-check{{end}}-square-o"></i></div>
|
||||||
<div><b>Disenable Registeration:</b> <i class="fa fa{{if .Service.DisenableRegisteration}}-check{{end}}-square-o"></i></div>
|
<div><b>Disenable Registeration:</b> <i class="fa fa{{if .Service.DisenableRegisteration}}-check{{end}}-square-o"></i></div>
|
||||||
<div><b>Require Sign In View:</b> <i class="fa fa{{if .Service.RequireSignInView}}-check{{end}}-square-o"></i></div>
|
<div><b>Require Sign In View:</b> <i class="fa fa{{if .Service.RequireSignInView}}-check{{end}}-square-o"></i></div>
|
||||||
|
<div><b>Enable Cache Avatar:</b> <i class="fa fa{{if .Service.EnableCacheAvatar}}-check{{end}}-square-o"></i></div>
|
||||||
<hr/>
|
<hr/>
|
||||||
<div><b>Active Code Lives:</b> {{.Service.ActiveCodeLives}} minutes</div>
|
<div><b>Active Code Lives:</b> {{.Service.ActiveCodeLives}} minutes</div>
|
||||||
<div><b>Reset Password Code Lives:</b> {{.Service.ResetPwdCodeLives}} minutes</div>
|
<div><b>Reset Password Code Lives:</b> {{.Service.ResetPwdCodeLives}} minutes</div>
|
||||||
|
@ -76,6 +77,36 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
Session Configuration
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
<div><b>Session Provider:</b> {{.SessionProvider}}</div>
|
||||||
|
<div><b>Cookie Name:</b> {{.SessionConfig.CookieName}}</div>
|
||||||
|
<div><b>Enable Set Cookie:</b> <i class="fa fa{{if .SessionConfig.EnableSetCookie}}-check{{end}}-square-o"></i></div>
|
||||||
|
<div><b>GC Interval Time:</b> {{.SessionConfig.GcIntervalTime}} seconds</div>
|
||||||
|
<div><b>Session Life Time:</b> {{.SessionConfig.SessionLifeTime}} seconds</div>
|
||||||
|
<div><b>HTTPS Only:</b> <i class="fa fa{{if .SessionConfig.CookieSecure}}-check{{end}}-square-o"></i></div>
|
||||||
|
<div><b>Cookie Life Time:</b> {{.SessionConfig.CookieLifeTime}} seconds</div>
|
||||||
|
<div><b>Session ID Hash Function:</b> {{.SessionConfig.SessionIDHashFunc}}</div>
|
||||||
|
<div><b>Session ID Hash Key:</b> {{.SessionConfig.SessionIDHashKey}}</div>
|
||||||
|
<div><b>Provider Config:</b> {{.SessionConfig.ProviderConfig}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
Picture Configuration
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
<div><b>Picture Service:</b> {{.PictureService}}</div>
|
||||||
|
<div><b>Picture Root Path:</b> {{.PictureRootPath}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
Log Configuration
|
Log Configuration
|
||||||
|
|
|
@ -15,10 +15,42 @@
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
System Status
|
System Monitor Status
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
<div>Server Uptime: <b>{{.SysStatus.Uptime}}</b></div>
|
||||||
|
<div>Current Goroutines: <b>{{.SysStatus.NumGoroutine}}</b></div>
|
||||||
|
<hr/>
|
||||||
|
<div>Current Memory Usage: <b>{{.SysStatus.MemAllocated}}</b></div>
|
||||||
|
<div>Total Memory Allocated: <b>{{.SysStatus.MemTotal}}</b></div>
|
||||||
|
<div>Memory Obtained: <b>{{.SysStatus.MemSys}}</b></div>
|
||||||
|
<div>Pointer Lookup Times: <b>{{.SysStatus.Lookups}}</b></div>
|
||||||
|
<div>Memory Allocate Times: <b>{{.SysStatus.MemMallocs}}</b></div>
|
||||||
|
<div>Memory Free Times: <b>{{.SysStatus.MemFrees}}</b></div>
|
||||||
|
<hr/>
|
||||||
|
<div>Current Heap Usage: <b>{{.SysStatus.HeapAlloc}}</b></div>
|
||||||
|
<div>Heap Memory Obtained: <b>{{.SysStatus.HeapSys}}</b></div>
|
||||||
|
<div>Heap Memory Idle: <b>{{.SysStatus.HeapIdle}}</b></div>
|
||||||
|
<div>Heap Memory In Use: <b>{{.SysStatus.HeapInuse}}</b></div>
|
||||||
|
<div>Heap Memory Released: <b>{{.SysStatus.HeapReleased}}</b></div>
|
||||||
|
<div>Heap Objects: <b>{{.SysStatus.HeapObjects}}</b></div>
|
||||||
|
<hr/>
|
||||||
|
<div>Bootstrap Stack Usage: <b>{{.SysStatus.StackInuse}}</b></div>
|
||||||
|
<div>Stack Memory Obtained: <b>{{.SysStatus.StackSys}}</b></div>
|
||||||
|
<div>MSpan Structures Usage: <b>{{.SysStatus.MSpanInuse}}</b></div>
|
||||||
|
<div>MSpan Structures Obtained: <b>{{.SysStatus.HeapSys}}</b></div>
|
||||||
|
<div>MCache Structures Usage: <b>{{.SysStatus.MCacheInuse}}</b></div>
|
||||||
|
<div>MCache Structures Obtained: <b>{{.SysStatus.MCacheSys}}</b></div>
|
||||||
|
<div>Profiling Bucket Hash Table Obtained: <b>{{.SysStatus.BuckHashSys}}</b></div>
|
||||||
|
<div>GC Metadada Obtained: <b>{{.SysStatus.GCSys}}</b></div>
|
||||||
|
<div>Other System Allocation Obtained: <b>{{.SysStatus.OtherSys}}</b></div>
|
||||||
|
<hr/>
|
||||||
|
<div>Next GC Recycle: <b>{{.SysStatus.NextGC}}</b></div>
|
||||||
|
<div>Last GC Time: <b>{{.SysStatus.LastGC}} ago</b></div>
|
||||||
|
<div>Total GC Pause: <b>{{.SysStatus.PauseTotalNs}}</b></div>
|
||||||
|
<div>Last GC Pause: <b>{{.SysStatus.PauseNs}}</b></div>
|
||||||
|
<div>GC Times: <b>{{.SysStatus.NumGC}}</b></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<td>{{.Id}}</td>
|
<td>{{.Id}}</td>
|
||||||
<th>{{.UserName}}</th>
|
<th>{{.UserName}}</th>
|
||||||
<td><a href="/{{.UserName}}/{{.Name}}">{{.Name}}</a></td>
|
<td><a href="/{{.UserName}}/{{.Name}}">{{.Name}}</a></td>
|
||||||
<td><i class="fa fa{{if .Private}}-check{{end}}-square-o"></i></td>
|
<td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td>
|
||||||
<td>{{.NumWatches}}</td>
|
<td>{{.NumWatches}}</td>
|
||||||
<td>{{.NumForks}}</td>
|
<td>{{.NumForks}}</td>
|
||||||
<td>{{DateFormat .Created "M d, Y"}}</td>
|
<td>{{DateFormat .Created "M d, Y"}}</td>
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
<br/>
|
<br/>
|
||||||
<form action="/admin/users/{{.User.Id}}" method="post" class="form-horizontal">
|
<form action="/admin/users/{{.User.Id}}" method="post" class="form-horizontal">
|
||||||
{{if .IsSuccess}}<p class="alert alert-success">Account profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
|
{{if .IsSuccess}}<p class="alert alert-success">Account profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
<input type="hidden" value="{{.User.Id}}" name="userId"/>
|
<input type="hidden" value="{{.User.Id}}" name="userId"/>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Username: </label>
|
<label class="col-md-3 control-label">Username: </label>
|
||||||
|
@ -71,7 +72,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-offset-3 col-md-6">
|
<div class="col-md-offset-3 col-md-6">
|
||||||
<button type="submit" class="btn btn-lg btn-primary btn-block">Update account profile</button>
|
<button type="submit" class="btn btn-lg btn-primary btn-block">Update account profile</button>
|
||||||
<!-- <a type="button" href="/admin/users/{{.User.Id}}/delete" class="btn btn-lg btn-danger btn-block">Delete this account</a> -->
|
<a type="button" href="/admin/users/{{.User.Id}}/delete" class="btn btn-lg btn-danger btn-block">Delete this account</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<br/>
|
<br/>
|
||||||
<form action="/admin/users/new" method="post" class="form-horizontal">
|
<form action="/admin/users/new" method="post" class="form-horizontal">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
<div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
|
<div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
|
||||||
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
|
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
|
||||||
<label class="col-md-3 control-label">Username: </label>
|
<label class="col-md-3 control-label">Username: </label>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
<meta name="author" content="Gogs - Go Git Service" />
|
<meta name="author" content="Gogs - Go Git Service" />
|
||||||
<meta name="description" content="Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language" />
|
<meta name="description" content="Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language" />
|
||||||
<meta name="keywords" content="go, git">
|
<meta name="keywords" content="go, git">
|
||||||
|
<meta name="_csrf" content="{{.CsrfToken}}" />
|
||||||
|
|
||||||
<!-- Stylesheets -->
|
<!-- Stylesheets -->
|
||||||
<link href="/css/bootstrap.min.css" rel="stylesheet" />
|
<link href="/css/bootstrap.min.css" rel="stylesheet" />
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
{{template "base/navbar" .}}
|
{{template "base/navbar" .}}
|
||||||
<div class="container" id="gogs-body">
|
<div class="container" id="gogs-body">
|
||||||
<form action="/repo/create" method="post" class="form-horizontal gogs-card" id="gogs-repo-create">
|
<form action="/repo/create" method="post" class="form-horizontal gogs-card" id="gogs-repo-create">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
<h3>Create New Repository</h3>
|
<h3>Create New Repository</h3>
|
||||||
<div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
|
<div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<div id="gogs-body-nav" class="gogs-repo-nav">
|
<div id="gogs-body-nav" class="gogs-repo-nav">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-7">
|
||||||
<h3 class="name"><i class="fa fa-book fa-lg"></i><a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> / {{.Repository.Name}}</h3>
|
<h3 class="name"><i class="fa fa-book fa-lg"></i><a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> / {{.Repository.Name}}</h3>
|
||||||
<p class="desc">{{.Repository.Description}}{{if .Repository.Website}}<a href="{{.Repository.Website}}">{{.Repository.Website}}</a>{{end}}</p>
|
<p class="desc">{{.Repository.Description}}{{if .Repository.Website}}<a href="{{.Repository.Website}}">{{.Repository.Website}}</a>{{end}}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 actions text-right clone-group-btn">
|
<div class="col-md-5 actions text-right clone-group-btn">
|
||||||
{{if not .IsBareRepo}}
|
{{if not .IsBareRepo}}
|
||||||
<!--<div class="btn-group" id="gogs-repo-clone">
|
<!--<div class="btn-group" id="gogs-repo-clone">
|
||||||
<button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button>
|
<button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button>
|
||||||
|
|
|
@ -19,7 +19,41 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
<form action="/{{.Owner.Name}}/{{.Repository.Name}}/settings" method="post" class="form-horizontal">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
|
<input type="hidden" name="action" value="update">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-3 text-right">Repository Name <strong class="text-danger">*</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" name="repo-name" required="required" value="{{.Repository.Name}}"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-3 text-right">Description</label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<textarea class="form-control" name="desc" id="repo-desc" rows="6"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-3 text-right">Official Site</label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="url" class="form-control" name="repo-site"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-3 text-right">Default Branch</label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<select name="branch" id="repo-default-branch" class="form-control">
|
||||||
|
<option value="">Branch</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-9 col-md-offset-3">
|
||||||
|
<button class="btn btn-primary" type="submit">Save Options</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -40,6 +74,7 @@
|
||||||
<div class="modal fade" id="delete-repository-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
<div class="modal fade" id="delete-repository-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<form action="/{{.Owner.Name}}/{{.Repository.Name}}/settings" method="post" class="modal-content">
|
<form action="/{{.Owner.Name}}/{{.Repository.Name}}/settings" method="post" class="modal-content">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
<input type="hidden" name="action" value="delete">
|
<input type="hidden" name="action" value="delete">
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
7
templates/status/404.tmpl
Normal file
7
templates/status/404.tmpl
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{{template "base/head" .}}
|
||||||
|
{{template "base/navbar" .}}
|
||||||
|
<div id="gogs-body" class="container">
|
||||||
|
<h4>This page is not found !</h4>
|
||||||
|
<p>Application Version: {{AppVer}}</p>
|
||||||
|
</div>
|
||||||
|
{{template "base/footer" .}}
|
7
templates/status/500.tmpl
Normal file
7
templates/status/500.tmpl
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{{template "base/head" .}}
|
||||||
|
{{template "base/navbar" .}}
|
||||||
|
<div id="gogs-body" class="container">
|
||||||
|
<p>An error is occurred : {{.ErrorMsg}}</p>
|
||||||
|
<p>Application Version: {{AppVer}}</p>
|
||||||
|
</div>
|
||||||
|
{{template "base/footer" .}}
|
|
@ -1,7 +1,8 @@
|
||||||
{{template "base/head" .}}
|
{{template "base/head" .}}
|
||||||
{{template "base/navbar" .}}
|
{{template "base/navbar" .}}
|
||||||
<div id="gogs-body" class="container">
|
<div id="gogs-body" class="container">
|
||||||
<form action="/user/activate" method="get" class="form-horizontal gogs-card" id="gogs-login-card">
|
<form action="/user/activate" method="post" class="form-horizontal gogs-card" id="gogs-login-card">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
<h3>Activate Your Account</h3>
|
<h3>Activate Your Account</h3>
|
||||||
{{if .IsActivatePage}}
|
{{if .IsActivatePage}}
|
||||||
{{if .ServiceNotEnabled}}
|
{{if .ServiceNotEnabled}}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<div class="modal fade" id="delete-account-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
<div class="modal fade" id="delete-account-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<form action="/user/delete" method="post" class="modal-content" id="gogs-user-delete">
|
<form action="/user/delete" method="post" class="modal-content" id="gogs-user-delete">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
<h4 class="modal-title" id="myModalLabel">Delete Account</h4>
|
<h4 class="modal-title" id="myModalLabel">Delete Account</h4>
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
<div id="gogs-user-setting-container" class="col-md-9">
|
<div id="gogs-user-setting-container" class="col-md-9">
|
||||||
<div id="gogs-setting-pwd">
|
<div id="gogs-setting-pwd">
|
||||||
<h4>Password</h4>
|
<h4>Password</h4>
|
||||||
<form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting/password">{{if .IsSuccess}}
|
<form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting/password">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
|
{{if .IsSuccess}}
|
||||||
<p class="alert alert-success">Password is changed successfully. You can now sign in via new password.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
|
<p class="alert alert-success">Password is changed successfully. You can now sign in via new password.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Old Password<strong class="text-danger">*</strong></label>
|
<label class="col-md-3 control-label">Old Password<strong class="text-danger">*</strong></label>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<div class="modal fade" id="ssh-add-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
<div class="modal fade" id="ssh-add-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<form class="modal-content form-horizontal" id="gogs-ssh-form" method="post" action="/user/setting/ssh/">
|
<form class="modal-content form-horizontal" id="gogs-ssh-form" method="post" action="/user/setting/ssh/">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
<h4 class="modal-title" id="myModalLabel">Add SSH Key</h4>
|
<h4 class="modal-title" id="myModalLabel">Add SSH Key</h4>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<div id="gogs-setting-pwd">
|
<div id="gogs-setting-pwd">
|
||||||
<h4>Account Profile</h4>
|
<h4>Account Profile</h4>
|
||||||
<form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting">
|
<form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
{{if .IsSuccess}}<p class="alert alert-success">Your profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
|
{{if .IsSuccess}}<p class="alert alert-success">Your profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
|
||||||
<p>Your Email will be public and used for Account related notifications and any web based operations made via the web.</p>
|
<p>Your Email will be public and used for Account related notifications and any web based operations made via the web.</p>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
{{template "base/navbar" .}}
|
{{template "base/navbar" .}}
|
||||||
<div class="container" id="gogs-body" data-page="user-signin">
|
<div class="container" id="gogs-body" data-page="user-signin">
|
||||||
<form action="/user/login" method="post" class="form-horizontal gogs-card" id="gogs-login-card">
|
<form action="/user/login" method="post" class="form-horizontal gogs-card" id="gogs-login-card">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
<h3>Log in</h3>
|
<h3>Log in</h3>
|
||||||
<div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
|
<div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
|
||||||
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
|
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
|
||||||
|
@ -18,6 +19,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-6 col-md-offset-4">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="remember" {{if .remember}}checked{{end}}>
|
||||||
|
<strong>Remember me</strong>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-offset-4 col-md-6">
|
<div class="col-md-offset-4 col-md-6">
|
||||||
<button type="submit" class="btn btn-lg btn-primary">Log In</button>
|
<button type="submit" class="btn btn-lg btn-primary">Log In</button>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
{{template "base/navbar" .}}
|
{{template "base/navbar" .}}
|
||||||
<div class="container" id="gogs-body" data-page="user-signup">
|
<div class="container" id="gogs-body" data-page="user-signup">
|
||||||
<form action="/user/sign_up" method="post" class="form-horizontal gogs-card" id="gogs-login-card">
|
<form action="/user/sign_up" method="post" class="form-horizontal gogs-card" id="gogs-login-card">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
{{if .DisenableRegisteration}}
|
{{if .DisenableRegisteration}}
|
||||||
Sorry, registeration has been disenabled, you can only get account from administrator.
|
Sorry, registeration has been disenabled, you can only get account from administrator.
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
107
web.go
107
web.go
|
@ -12,7 +12,6 @@ import (
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/codegangsta/martini"
|
"github.com/codegangsta/martini"
|
||||||
"github.com/martini-contrib/sessions"
|
|
||||||
|
|
||||||
"github.com/gogits/binding"
|
"github.com/gogits/binding"
|
||||||
|
|
||||||
|
@ -81,70 +80,92 @@ func runWeb(*cli.Context) {
|
||||||
// Middlewares.
|
// Middlewares.
|
||||||
m.Use(middleware.Renderer(middleware.RenderOptions{Funcs: []template.FuncMap{base.TemplateFuncs}}))
|
m.Use(middleware.Renderer(middleware.RenderOptions{Funcs: []template.FuncMap{base.TemplateFuncs}}))
|
||||||
|
|
||||||
// TODO: should use other store because cookie store is not secure.
|
|
||||||
store := sessions.NewCookieStore([]byte("secret123"))
|
|
||||||
m.Use(sessions.Sessions("my_session", store))
|
|
||||||
|
|
||||||
m.Use(middleware.InitContext())
|
m.Use(middleware.InitContext())
|
||||||
|
|
||||||
reqSignIn := middleware.SignInRequire(true)
|
reqSignIn := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true})
|
||||||
ignSignIn := middleware.SignInRequire(base.Service.RequireSignInView)
|
ignSignIn := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: base.Service.RequireSignInView})
|
||||||
reqSignOut := middleware.SignOutRequire()
|
reqSignOut := middleware.Toggle(&middleware.ToggleOptions{SignOutRequire: true})
|
||||||
|
|
||||||
// Routers.
|
// Routers.
|
||||||
m.Get("/", ignSignIn, routers.Home)
|
m.Get("/", ignSignIn, routers.Home)
|
||||||
m.Get("/issues", reqSignIn, user.Issues)
|
m.Get("/issues", reqSignIn, user.Issues)
|
||||||
m.Get("/pulls", reqSignIn, user.Pulls)
|
m.Get("/pulls", reqSignIn, user.Pulls)
|
||||||
m.Get("/stars", reqSignIn, user.Stars)
|
m.Get("/stars", reqSignIn, user.Stars)
|
||||||
m.Any("/user/login", reqSignOut, binding.BindIgnErr(auth.LogInForm{}), user.SignIn)
|
m.Get("/help", routers.Help)
|
||||||
m.Any("/user/logout", reqSignIn, user.SignOut)
|
|
||||||
m.Any("/user/sign_up", reqSignOut, binding.BindIgnErr(auth.RegisterForm{}), user.SignUp)
|
|
||||||
m.Any("/user/delete", reqSignIn, user.Delete)
|
|
||||||
m.Get("/user/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
|
|
||||||
m.Get("/user/activate", user.Activate)
|
|
||||||
|
|
||||||
m.Any("/user/setting", reqSignIn, binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting)
|
m.Group("/user", func(r martini.Router) {
|
||||||
m.Any("/user/setting/password", reqSignIn, binding.BindIgnErr(auth.UpdatePasswdForm{}), user.SettingPassword)
|
r.Any("/login", binding.BindIgnErr(auth.LogInForm{}), user.SignIn)
|
||||||
m.Any("/user/setting/ssh", reqSignIn, binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys)
|
r.Any("/sign_up", binding.BindIgnErr(auth.RegisterForm{}), user.SignUp)
|
||||||
m.Any("/user/setting/notification", reqSignIn, user.SettingNotification)
|
}, reqSignOut)
|
||||||
m.Any("/user/setting/security", reqSignIn, user.SettingSecurity)
|
m.Group("/user", func(r martini.Router) {
|
||||||
|
r.Any("/logout", user.SignOut)
|
||||||
|
r.Any("/delete", user.Delete)
|
||||||
|
r.Any("/setting", binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting)
|
||||||
|
}, reqSignIn)
|
||||||
|
m.Group("/user", func(r martini.Router) {
|
||||||
|
r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
|
||||||
|
r.Get("/activate", user.Activate)
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Group("/user/setting", func(r martini.Router) {
|
||||||
|
r.Any("/password", binding.BindIgnErr(auth.UpdatePasswdForm{}), user.SettingPassword)
|
||||||
|
r.Any("/ssh", binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys)
|
||||||
|
r.Any("/notification", user.SettingNotification)
|
||||||
|
r.Any("/security", user.SettingSecurity)
|
||||||
|
}, reqSignIn)
|
||||||
|
|
||||||
m.Get("/user/:username", ignSignIn, user.Profile)
|
m.Get("/user/:username", ignSignIn, user.Profile)
|
||||||
|
|
||||||
m.Any("/repo/create", reqSignIn, binding.BindIgnErr(auth.CreateRepoForm{}), repo.Create)
|
m.Any("/repo/create", reqSignIn, binding.BindIgnErr(auth.CreateRepoForm{}), repo.Create)
|
||||||
|
|
||||||
m.Get("/help", routers.Help)
|
adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})
|
||||||
|
|
||||||
adminReq := middleware.AdminRequire()
|
m.Get("/admin", adminReq, admin.Dashboard)
|
||||||
m.Get("/admin", reqSignIn, adminReq, admin.Dashboard)
|
m.Group("/admin", func(r martini.Router) {
|
||||||
m.Get("/admin/users", reqSignIn, adminReq, admin.Users)
|
r.Get("/users", admin.Users)
|
||||||
m.Any("/admin/users/new", reqSignIn, adminReq, binding.BindIgnErr(auth.RegisterForm{}), admin.NewUser)
|
r.Get("/repos", admin.Repositories)
|
||||||
m.Any("/admin/users/:userid", reqSignIn, adminReq, binding.BindIgnErr(auth.AdminEditUserForm{}), admin.EditUser)
|
r.Get("/config", admin.Config)
|
||||||
m.Get("/admin/repos", reqSignIn, adminReq, admin.Repositories)
|
}, adminReq)
|
||||||
m.Get("/admin/config", reqSignIn, adminReq, admin.Config)
|
m.Group("/admin/users", func(r martini.Router) {
|
||||||
|
r.Any("/new", binding.BindIgnErr(auth.RegisterForm{}), admin.NewUser)
|
||||||
|
r.Any("/:userid", binding.BindIgnErr(auth.AdminEditUserForm{}), admin.EditUser)
|
||||||
|
r.Any("/:userid/delete", admin.DeleteUser)
|
||||||
|
}, adminReq)
|
||||||
|
|
||||||
m.Post("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.SettingPost)
|
m.Group("/:username/:reponame", func(r martini.Router) {
|
||||||
m.Get("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.Setting)
|
r.Post("/settings", repo.SettingPost)
|
||||||
|
r.Get("/settings", repo.Setting)
|
||||||
|
r.Get("/action/:action", repo.Action)
|
||||||
|
}, reqSignIn, middleware.RepoAssignment(true))
|
||||||
|
m.Group("/:username/:reponame", func(r martini.Router) {
|
||||||
|
r.Get("/commits/:branchname", repo.Commits)
|
||||||
|
r.Get("/issues", repo.Issues)
|
||||||
|
r.Any("/issues/new", binding.BindIgnErr(auth.CreateIssueForm{}), repo.CreateIssue)
|
||||||
|
r.Get("/issues/:issueid", repo.ViewIssue)
|
||||||
|
r.Get("/pulls", repo.Pulls)
|
||||||
|
r.Get("/branches", repo.Branches)
|
||||||
|
r.Get("/src/:branchname", repo.Single)
|
||||||
|
r.Get("/src/:branchname/**", repo.Single)
|
||||||
|
r.Get("/commits/:branchname", repo.Commits)
|
||||||
|
r.Get("/commits/:branchname", repo.Commits)
|
||||||
|
}, ignSignIn, middleware.RepoAssignment(true))
|
||||||
|
|
||||||
m.Get("/:username/:reponame/commits/:branchname", ignSignIn, middleware.RepoAssignment(true), repo.Commits)
|
// TODO: implement single commit page
|
||||||
m.Get("/:username/:reponame/issues", ignSignIn, middleware.RepoAssignment(true), repo.Issues)
|
// m.Get("/:username/:reponame/commit/:commitid/**", ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
||||||
m.Get("/:username/:reponame/pulls", ignSignIn, middleware.RepoAssignment(true), repo.Pulls)
|
// m.Get("/:username/:reponame/commit/:commitid", ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
||||||
m.Get("/:username/:reponame/branches", ignSignIn, middleware.RepoAssignment(true), repo.Branches)
|
|
||||||
m.Get("/:username/:reponame/action/:action", reqSignIn, middleware.RepoAssignment(true), repo.Action)
|
|
||||||
m.Get("/:username/:reponame/src/:branchname/**",
|
|
||||||
ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
|
||||||
m.Get("/:username/:reponame/src/:branchname",
|
|
||||||
ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
|
||||||
m.Get("/:username/:reponame/commit/:commitid/**", ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
|
||||||
m.Get("/:username/:reponame/commit/:commitid", ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
|
||||||
|
|
||||||
m.Get("/:username/:reponame", ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
m.Group("/:username", func(r martini.Router) {
|
||||||
|
r.Get("/:reponame", middleware.RepoAssignment(true), repo.Single)
|
||||||
m.Any("/:username/:reponame/**", ignSignIn, repo.Http)
|
r.Any("/:reponame/**", repo.Http)
|
||||||
|
}, ignSignIn)
|
||||||
|
|
||||||
if martini.Env == martini.Dev {
|
if martini.Env == martini.Dev {
|
||||||
m.Get("/template/**", dev.TemplatePreview)
|
m.Get("/template/**", dev.TemplatePreview)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// not found handler
|
||||||
|
m.NotFound(routers.NotFound)
|
||||||
|
|
||||||
listenAddr := fmt.Sprintf("%s:%s",
|
listenAddr := fmt.Sprintf("%s:%s",
|
||||||
base.Cfg.MustValue("server", "HTTP_ADDR"),
|
base.Cfg.MustValue("server", "HTTP_ADDR"),
|
||||||
base.Cfg.MustValue("server", "HTTP_PORT", "3000"))
|
base.Cfg.MustValue("server", "HTTP_PORT", "3000"))
|
||||||
|
|
Loading…
Reference in a new issue