Merge branch 'master' of github.com:gogits/gogs

This commit is contained in:
Lunny Xiao 2014-03-16 22:32:50 +08:00
commit f824d6a4b1
27 changed files with 732 additions and 191 deletions

View File

@ -17,6 +17,7 @@ Please see [Wiki](https://github.com/gogits/gogs/wiki) for project design, devel
## Features ## Features
- Activity timeline
- SSH protocal support. - SSH protocal support.
- Register/delete account. - Register/delete account.
- Create/delete public repository. - Create/delete public repository.

View File

@ -3,8 +3,8 @@ RUN_USER = lunny
[repository] [repository]
ROOT = /Users/%(RUN_USER)s/git/gogs-repositories ROOT = /Users/%(RUN_USER)s/git/gogs-repositories
LANG_IGNS=Google Go|C|Python LANG_IGNS=Google Go|C|Python|Ruby
LICENSES=Apache v2 License|GPL v2|BSD (3-Clause) License LICENSES=Apache v2 License|GPL v2|MIT License|BSD (3-Clause) License
[server] [server]
HTTP_ADDR = HTTP_ADDR =

18
conf/gitignore/Ruby Normal file
View File

@ -0,0 +1,18 @@
*.gem
*.rbc
.bundle
.config
coverage
InstalledFiles
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
# YARD artifacts
.yardoc
_yardoc
doc/

21
conf/license/MIT License Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

24
gogs.go
View File

@ -7,7 +7,7 @@ package main
import ( import (
"os" "os"
"os/user" // "os/user"
"runtime" "runtime"
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
@ -20,21 +20,21 @@ import (
// Test that go1.1 tag above is included in builds. main.go refers to this definition. // Test that go1.1 tag above is included in builds. main.go refers to this definition.
const go11tag = true const go11tag = true
const APP_VER = "0.0.8.0315" const APP_VER = "0.0.8.0316.1"
func init() { func init() {
base.AppVer = APP_VER base.AppVer = APP_VER
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
} }
func checkRunUser() bool { // func checkRunUser() bool {
u, err := user.Current() // u, err := user.Current()
if err != nil { // if err != nil {
// TODO: log // // TODO: log
return false // return false
} // }
return u.Username == base.Cfg.MustValue("", "RUN_USER") // return u.Username == base.Cfg.MustValue("", "RUN_USER")
} // }
func main() { func main() {
/*if !checkRunUser() { /*if !checkRunUser() {
@ -51,8 +51,6 @@ func main() {
CmdServ, CmdServ,
CmdUpdate, CmdUpdate,
} }
app.Flags = append(app.Flags, []cli.Flag{ app.Flags = append(app.Flags, []cli.Flag{}...)
cli.BoolFlag{"noterm", "disable color output"},
}...)
app.Run(os.Args) app.Run(os.Args)
} }

View File

@ -43,6 +43,7 @@ func (a Action) GetRepoName() string {
return a.RepoName return a.RepoName
} }
// CommitRepoAction records action for commit repository.
func CommitRepoAction(userId int64, userName string, func CommitRepoAction(userId int64, userName string,
repoId int64, repoName string, msg string) error { repoId int64, repoName string, msg string) error {
_, err := orm.InsertOne(&Action{ _, err := orm.InsertOne(&Action{
@ -57,8 +58,7 @@ func CommitRepoAction(userId int64, userName string,
return err return err
} }
// NewRepoAction inserts action for create repository. // NewRepoAction records action for create repository.
func NewRepoAction(user *User, repo *Repository) error { func NewRepoAction(user *User, repo *Repository) error {
_, err := orm.InsertOne(&Action{ _, err := orm.InsertOne(&Action{
UserId: user.Id, UserId: user.Id,

View File

@ -1,21 +1,32 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models package models
import ( import (
"bufio"
"errors"
"fmt" "fmt"
"io"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"strings"
"sync"
"time" "time"
"github.com/Unknwon/com" "github.com/Unknwon/com"
) )
var ( var (
sshOpLocker = sync.Mutex{}
//publicKeyRootPath string //publicKeyRootPath string
sshPath string sshPath string
appPath string appPath string
tmplPublicKey = "### autogenerated by gitgos, DO NOT EDIT\n" + // "### autogenerated by gitgos, DO NOT EDIT\n"
"command=\"%s serv key-%d\",no-port-forwarding," + tmplPublicKey = "command=\"%s serv key-%d\",no-port-forwarding," +
"no-X11-forwarding,no-agent-forwarding,no-pty %s\n" "no-X11-forwarding,no-agent-forwarding,no-pty %s\n"
) )
@ -47,29 +58,60 @@ func init() {
} }
type PublicKey struct { type PublicKey struct {
Id int64 Id int64
OwnerId int64 `xorm:"index"` OwnerId int64 `xorm:"index"`
Name string `xorm:"unique not null"` Name string `xorm:"unique not null"`
Content string `xorm:"text not null"` Fingerprint string
Created time.Time `xorm:"created"` Content string `xorm:"text not null"`
Updated time.Time `xorm:"updated"` Created time.Time `xorm:"created"`
Updated time.Time `xorm:"updated"`
} }
var (
ErrKeyAlreadyExist = errors.New("Public key already exist")
)
func GenAuthorizedKey(keyId int64, key string) string { func GenAuthorizedKey(keyId int64, key string) string {
return fmt.Sprintf(tmplPublicKey, appPath, keyId, key) return fmt.Sprintf(tmplPublicKey, appPath, keyId, key)
} }
func AddPublicKey(key *PublicKey) error { func AddPublicKey(key *PublicKey) (err error) {
_, err := orm.Insert(key) // Check if public key name has been used.
has, err := orm.Get(key)
if err != nil { if err != nil {
return err return err
} else if has {
return ErrKeyAlreadyExist
}
// Calculate fingerprint.
tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()),
"id_rsa.pub")
os.MkdirAll(path.Dir(tmpPath), os.ModePerm)
f, err := os.Create(tmpPath)
if err != nil {
return
}
if _, err = f.WriteString(key.Content); err != nil {
return err
}
f.Close()
stdout, _, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath)
if err != nil {
return err
} else if len(stdout) < 2 {
return errors.New("Not enough output for calculating fingerprint")
}
key.Fingerprint = strings.Split(stdout, " ")[1]
// Save SSH key.
if _, err = orm.Insert(key); err != nil {
return err
} }
err = SaveAuthorizedKeyFile(key) if err = SaveAuthorizedKeyFile(key); err != nil {
if err != nil { if _, err2 := orm.Delete(key); err2 != nil {
_, err2 := orm.Delete(key) return err2
if err2 != nil {
// TODO: log the error
} }
return err return err
} }
@ -77,9 +119,71 @@ func AddPublicKey(key *PublicKey) error {
return nil return nil
} }
func DeletePublicKey(key *PublicKey) error { // DeletePublicKey deletes SSH key information both in database and authorized_keys file.
_, err := orm.Delete(key) func DeletePublicKey(key *PublicKey) (err error) {
return err 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
}
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
p := filepath.Join(sshPath, "authorized_keys")
tmpP := filepath.Join(sshPath, "authorized_keys.tmp")
fr, err := os.Open(p)
if err != nil {
return err
}
defer fr.Close()
fw, err := os.Create(tmpP)
if err != nil {
return err
}
defer fw.Close()
buf := bufio.NewReader(fr)
for {
line, errRead := buf.ReadString('\n')
line = strings.TrimSpace(line)
if errRead != nil {
if errRead != io.EOF {
return errRead
}
// Reached end of file, if nothing to read then break,
// otherwise handle the last line.
if len(line) == 0 {
break
}
}
// Found the line and copy rest of file.
if strings.Contains(line, fmt.Sprintf("key-%d", key.Id)) && strings.Contains(line, key.Content) {
continue
}
// Still finding the line, copy the line that currently read.
if _, err = fw.WriteString(line + "\n"); err != nil {
return err
}
if errRead == io.EOF {
break
}
}
if err = os.Remove(p); err != nil {
return err
}
return os.Rename(tmpP, p)
} }
func ListPublicKey(userId int64) ([]PublicKey, error) { func ListPublicKey(userId int64) ([]PublicKey, error) {
@ -89,11 +193,16 @@ func ListPublicKey(userId int64) ([]PublicKey, error) {
} }
func SaveAuthorizedKeyFile(key *PublicKey) error { func SaveAuthorizedKeyFile(key *PublicKey) error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
p := filepath.Join(sshPath, "authorized_keys") p := filepath.Join(sshPath, "authorized_keys")
f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil { if err != nil {
return err return err
} }
defer f.Close()
//os.Chmod(p, 0600) //os.Chmod(p, 0600)
_, err = f.WriteString(GenAuthorizedKey(key.Id, key.Content)) _, err = f.WriteString(GenAuthorizedKey(key.Id, key.Content))
return err return err

View File

@ -264,7 +264,7 @@ func GetRepositoryById(id int64) (repo *Repository, err error) {
// GetRepositories returns the list of repositories of given user. // GetRepositories returns the list of repositories of given user.
func GetRepositories(user *User) ([]Repository, error) { func GetRepositories(user *User) ([]Repository, error) {
repos := make([]Repository, 0, 10) repos := make([]Repository, 0, 10)
err := orm.Find(&repos, &Repository{OwnerId: user.Id}) err := orm.Desc("updated").Find(&repos, &Repository{OwnerId: user.Id})
return repos, err return repos, err
} }

View File

@ -142,6 +142,7 @@ func UpdateUser(user *User) (err error) {
// DeleteUser completely deletes everything of the user. // DeleteUser completely deletes everything of the user.
func DeleteUser(user *User) error { func DeleteUser(user *User) error {
// Check ownership of repository.
count, err := GetRepositoryCount(user) count, err := GetRepositoryCount(user)
if err != nil { if err != nil {
return errors.New("modesl.GetRepositories: " + err.Error()) return errors.New("modesl.GetRepositories: " + err.Error())
@ -151,6 +152,22 @@ func DeleteUser(user *User) error {
// TODO: check issues, other repos' commits // TODO: check issues, other repos' commits
// Delete all feeds.
if _, err = orm.Delete(&Action{UserId: user.Id}); err != nil {
return err
}
// Delete all SSH keys.
keys := make([]PublicKey, 0, 10)
if err = orm.Find(&keys, &PublicKey{OwnerId: user.Id}); err != nil {
return err
}
for _, key := range keys {
if err = DeletePublicKey(&key); err != nil {
return err
}
}
_, err = orm.Delete(user) _, err = orm.Delete(user)
// TODO: delete and update follower information. // TODO: delete and update follower information.
return err return err
@ -158,8 +175,8 @@ func DeleteUser(user *User) error {
// EncodePasswd encodes password to safe format. // EncodePasswd encodes password to safe format.
func (user *User) EncodePasswd() error { func (user *User) EncodePasswd() error {
newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(UserPasswdSalt), 16384, 8, 1, 64) var err error
user.Passwd = fmt.Sprintf("%x", newPasswd) user.Passwd, err = EncodePasswd(user.Passwd)
return err return err
} }
@ -167,6 +184,14 @@ func UserPath(userName string) string {
return filepath.Join(RepoRootPath, userName) return filepath.Join(RepoRootPath, userName)
} }
func EncodePasswd(rawPasswd string) (string, error) {
newPasswd, err := scrypt.Key([]byte(rawPasswd), []byte(UserPasswdSalt), 16384, 8, 1, 64)
if err != nil {
return "", err
}
return fmt.Sprintf("%x", newPasswd), nil
}
func GetUserByKeyId(keyId int64) (*User, error) { func GetUserByKeyId(keyId int64) (*User, error) {
user := new(User) user := new(User)
has, err := orm.Sql("select a.* from user as a, public_key as b where a.id = b.owner_id and b.id=?", keyId).Get(user) has, err := orm.Sql("select a.* from user as a, public_key as b where a.id = b.owner_id and b.id=?", keyId).Get(user)

View File

@ -5,6 +5,8 @@
package middleware package middleware
import ( import (
"errors"
"github.com/codegangsta/martini" "github.com/codegangsta/martini"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
@ -31,9 +33,7 @@ func RepoAssignment(redirect bool) martini.Handler {
ctx.Render.Redirect("/") ctx.Render.Redirect("/")
return return
} }
//data["ErrorMsg"] = err ctx.Handle(200, "RepoAssignment", err)
//log.Error("repo.Single: %v", err)
//r.HTML(200, "base/error", data)
return return
} }
} else { } else {
@ -45,9 +45,7 @@ func RepoAssignment(redirect bool) martini.Handler {
ctx.Render.Redirect("/") ctx.Render.Redirect("/")
return return
} }
//data["ErrorMsg"] = "invliad user account for single repository" ctx.Handle(200, "RepoAssignment", errors.New("invliad user account for single repository"))
//log.Error("repo.Single: %v", err)
//r.HTML(200, "base/error", data)
return return
} }
@ -60,9 +58,7 @@ func RepoAssignment(redirect bool) martini.Handler {
ctx.Render.Redirect("/") ctx.Render.Redirect("/")
return return
} }
//data["ErrorMsg"] = err ctx.Handle(200, "RepoAssignment", err)
//log.Error("repo.Single: %v", err)
//r.HTML(200, "base/error", data)
return return
} }

File diff suppressed because one or more lines are too long

View File

@ -302,32 +302,23 @@ html, body {
/* gogits user ssh keys */ /* gogits user ssh keys */
#gogs-ssh-keys .list-group-item { #gogs-ssh-keys .list-group-item {
line-height: 48px; padding: 15px 0;
border-bottom: 1px solid #DDD; border-bottom: 1px solid #DDD;
} }
#gogs-ssh-keys .list-group-item .delete {
margin: -5px 50px 0;
}
#gogs-ssh-keys .list-group-item:after { #gogs-ssh-keys .list-group-item:after {
clear: both; clear: both;
} }
#gogs-ssh-keys .list-group-item:hover a.delete {
display: block;
}
#gogs-ssh-keys .name { #gogs-ssh-keys .name {
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
} }
#gogs-ssh-keys .list-group-item a.delete {
float: right;
color: white;
cursor: pointer;
margin-top: 10px;
border-radius: 3px;
display: none;
}
#gogs-ssh-keys .print { #gogs-ssh-keys .print {
padding-left: 1em; padding-left: 1em;
color: #888; color: #888;
@ -472,56 +463,6 @@ html, body {
padding: 0; padding: 0;
} }
/* #gogs-source */
#gogs-source-toolbar:after {
clear: both;
}
#gogs-source-toolbar .branch-switch {
display: inline-block;
}
#gogs-source-toolbar .breadcrumb {
margin: 0 .5em;
font-size: 16px;
vertical-align: middle;
display: inline-block;
background-color: transparent;
}
#gogs-source-table {
margin-top: 1.5em;
font-size: 14px;
}
#gogs-source-table .fa{
font-size: 15px;
width: 16px;
text-align: center;
color: #666;
}
#gogs-source-table .name{
width: 160px;
}
#gogs-source-table .size{
width: 80px;
}
#gogs-source-table .date{
width: 120px;
}
#gogs-source-table .is-dir .name {
font-weight: bold;
}
#gogs-source-table.table-hover > tbody > tr:hover > td {
background-color: #FEFEFE;
}
.activity-list { .activity-list {
font-size: 14px; font-size: 14px;
} }
@ -583,6 +524,70 @@ html, body {
color: #999; color: #999;
} }
/* #gogs-source */
#gogs-source .source-toolbar:after {
clear: both;
}
#gogs-source .source-toolbar .branch-switch {
display: inline-block;
}
#gogs-source .source-toolbar .breadcrumb {
margin: 0 .5em;
padding: 6px 15px;
font-size: 16px;
vertical-align: middle;
display: inline-block;
background-color: transparent;
}
#gogs-source .source-toolbar,
#gogs-source .info-box,
#gogs-source .file-content {
margin: 0 0 10px;
}
.info-box .info-head,
.info-box .info-content {
padding: 9px 20px;
}
.file-list {
background-color: #fafafa;
}
.file-list .icon {
font-size: 17px;
padding: 5px 0 4px 10px;
width: 40px;
}
.file-list .wrap {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: top;
white-space: nowrap;
}
.file-list .name .wrap {
max-width: 180px;
}
.file-list .text .wrap {
max-width: 450px;
}
.file-list .date .wrap {
max-width: 100px;
padding: 0 20px 0 0;
}
.file-list .date {
text-align: right;
}
#wrapper { #wrapper {
min-height: 100%; min-height: 100%;
height: auto !important; height: auto !important;

View File

@ -99,15 +99,16 @@ function initRegister() {
} }
function initUserSetting(){ function initUserSetting(){
$('#gogs-ssh-keys').on("click",".delete",function(){ $('#gogs-ssh-keys .delete').confirmation({
var $this = $(this); singleton: true,
Gogits.ajaxDelete("",{"id":$this.data("del")},function(json){ onConfirm: function(e, $this){
if(json.ok){ Gogits.ajaxDelete("",{"id":$this.data("del")},function(json){
window.location.reload(); if(json.ok){
}else{ window.location.reload();
alert(json.err); }else{
} alert(json.err);
}); }
return false; });
}
}); });
} }

File diff suppressed because one or more lines are too long

View File

@ -17,3 +17,7 @@ func Home(ctx *middleware.Context) {
ctx.Data["PageIsHome"] = true ctx.Data["PageIsHome"] = true
ctx.Render.HTML(200, "home", ctx.Data) ctx.Render.HTML(200, "home", ctx.Data)
} }
func Help(ctx *middleware.Context) string {
return "This is help page"
}

View File

@ -1,3 +1,7 @@
// 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 package repo
import ( import (
@ -60,3 +64,15 @@ func Setting(ctx *middleware.Context) {
ctx.Data["IsRepoToolbarSetting"] = true ctx.Data["IsRepoToolbarSetting"] = true
ctx.Render.HTML(200, "repo/setting", ctx.Data) ctx.Render.HTML(200, "repo/setting", ctx.Data)
} }
func Commits(ctx *middleware.Context) string {
return "This is commits page"
}
func Issues(ctx *middleware.Context) string {
return "This is issues page"
}
func Pulls(ctx *middleware.Context) string {
return "This is pulls page"
}

View File

@ -128,6 +128,10 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) {
} }
if err := models.AddPublicKey(k); err != nil { if err := models.AddPublicKey(k); err != nil {
if err.Error() == models.ErrKeyAlreadyExist.Error() {
ctx.RenderWithErr("Public key name has been used", "user/publickey", &form)
return
}
ctx.Handle(200, "ssh.AddPublicKey", err) ctx.Handle(200, "ssh.AddPublicKey", err)
return return
} else { } else {

View File

@ -157,13 +157,23 @@ func Delete(ctx *middleware.Context) {
return return
} }
if err := models.DeleteUser(ctx.User); err != nil { rawPasswd := ctx.Query("password")
encodedPwd, _ := models.EncodePasswd(rawPasswd)
if len(encodedPwd) == 0 || encodedPwd != ctx.User.Passwd {
ctx.Data["HasError"] = true ctx.Data["HasError"] = true
switch err.Error() { ctx.Data["ErrorMsg"] = "Your password error. Make sure you are owner of this account."
case models.ErrUserOwnRepos.Error(): } else {
ctx.Data["ErrorMsg"] = "Your account still have ownership of repository, you have to delete or transfer them first." if err := models.DeleteUser(ctx.User); err != nil {
default: ctx.Data["HasError"] = true
ctx.Handle(200, "user.Delete", err) switch err {
case models.ErrUserOwnRepos:
ctx.Data["ErrorMsg"] = "Your account still have ownership of repository, you have to delete or transfer them first."
default:
ctx.Handle(200, "user.Delete", err)
return
}
} else {
ctx.Render.Redirect("/")
return return
} }
} }
@ -189,3 +199,15 @@ func Feeds(ctx *middleware.Context, form auth.FeedsForm) {
} }
ctx.Render.JSON(200, &feeds) ctx.Render.JSON(200, &feeds)
} }
func Issues(ctx *middleware.Context) string {
return "This is issues page"
}
func Pulls(ctx *middleware.Context) string {
return "This is pulls page"
}
func Stars(ctx *middleware.Context) string {
return "This is stars page"
}

View File

@ -58,7 +58,7 @@ func runServ(*cli.Context) {
cmd := os.Getenv("SSH_ORIGINAL_COMMAND") cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
if cmd == "" { if cmd == "" {
println("Hi ", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.") println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.")
return return
} }

View File

@ -3,8 +3,7 @@
<nav class="gogs-nav"> <nav class="gogs-nav">
<a id="gogs-nav-logo" class="gogs-nav-item{{if .PageIsHome}} active{{end}}" href="/"><img src="/img/favicon.png" alt="Gogs Logo" id="gogs-logo"></a> <a id="gogs-nav-logo" class="gogs-nav-item{{if .PageIsHome}} active{{end}}" href="/"><img src="/img/favicon.png" alt="Gogs Logo" id="gogs-logo"></a>
<a class="gogs-nav-item{{if .PageIsUserDashboard}} active{{end}}" href="/">Dashboard</a> <a class="gogs-nav-item{{if .PageIsUserDashboard}} active{{end}}" href="/">Dashboard</a>
<a class="gogs-nav-item" href="#">Explore</a> <a class="gogs-nav-item" href="/help">Help</a>{{if .IsSigned}}
<a class="gogs-nav-item" href="#">Help</a>{{if .IsSigned}}
<a id="gogs-nav-out" class="gogs-nav-item navbar-right navbar-btn btn btn-danger" href="/user/logout/"><i class="fa fa-power-off fa-lg"></i></a> <a id="gogs-nav-out" class="gogs-nav-item navbar-right navbar-btn btn btn-danger" href="/user/logout/"><i class="fa fa-power-off fa-lg"></i></a>
<a id="gogs-nav-avatar" class="gogs-nav-item navbar-right" href="{{.SignedUser.HomeLink}}" data-toggle="tooltip" data-placement="bottom" title="{{.SignedUserName}}"> <a id="gogs-nav-avatar" class="gogs-nav-item navbar-right" href="{{.SignedUser.HomeLink}}" data-toggle="tooltip" data-placement="bottom" title="{{.SignedUserName}}">
<img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username"/> <img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username"/>

View File

@ -59,7 +59,7 @@
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="initReadme"> <input type="checkbox" name="initReadme" {{if .initReadme}}checked{{end}}>
<strong>Initialize this repository with a README</strong> <strong>Initialize this repository with a README</strong>
</label> </label>
</div> </div>

View File

@ -14,7 +14,7 @@
</div> </div>
<div id="gogs-repo-setting-container" class="col-md-9 tab-content"> <div id="gogs-repo-setting-container" class="col-md-9 tab-content">
<div id="options" class="tab-pane"> <div id="options" class="tab-pane">
repo-options <h4>Repository Options</h4>
</div> </div>
<div id="delete" class="tab-pane"> <div id="delete" class="tab-pane">
<h4>Delete Repository</h4> <h4>Delete Repository</h4>

View File

@ -4,14 +4,14 @@
{{template "repo/toolbar" .}} {{template "repo/toolbar" .}}
<div id="gogs-body" class="container"> <div id="gogs-body" class="container">
<div id="gogs-source"> <div id="gogs-source">
<div id="gogs-source-toolbar"> <div class="source-toolbar">
<button class="btn btn-default pull-right"><i class="fa fa-plus-square"></i>Add File</button> <button class="btn btn-default pull-right"><i class="fa fa-plus-square"></i>Add File</button>
<div class="dropdown branch-switch"> <div class="dropdown branch-switch">
<a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>master&nbsp;&nbsp; <a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>master&nbsp;&nbsp;
<b class="caret"></b></a> <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a class="current" href="/{{.RepositoryLink}}/branch/master">master</a></li> <li><a class="current" href="/{{.RepositoryLink}}/tree/master">master</a></li>
<li><a href="//{{.RepositoryLink}}/branch/develop">develop</a></li> <li><a href="/{{.RepositoryLink}}/tree/develop">develop</a></li>
</ul> </ul>
</div> </div>
{{$paths := .Paths}} {{$paths := .Paths}}
@ -32,29 +32,60 @@
{{end}} {{end}}
</ol> </ol>
</div> </div>
<table id="gogs-source-table" class="table table-hover"> <div class="panel panel-default info-box">
<thead class="hidden"> <div class="panel-heading info-head">
<tr> Merge branch 'release/1.1.1'
<th class="name">Filename</th> </div>
<th class="date">Date modified</th> <div class="panel-body info-content">
<th class="text">Message</th> slene authored 4 days ago
</tr> </div>
</thead> <table class="panel-footer table file-list">
<tbody> <thead class="hidden">
{{range .Files}} <tr>
<tr {{if .IsDir}}class="is-dir"{{end}}> <th class="icon"></th>
<td class="name"><i class="fa {{if .IsDir}}fa-folder{{else}}fa-file{{end}}"></i> <th class="name">Filename</th>
{{if .IsDir}} <th class="text">Message</th>
<a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}/{{.Path}}">{{.Name}}</a> <th class="date">Date modified</th>
{{else}} </tr>
<a href="#">{{.Name}} - {{FileSize .Size}}</a> </thead>
{{end}}</td> <tbody>
<td class="date"><time datetime="{{.Created}}" data-title="true" title="{{.Created}}">{{TimeSince .Created}}</time></td> {{range .Files}}
<td class="text">{{.Message}}</td> <tr {{if .IsDir}}class="is-dir"{{end}}>
</tr> <td class="icon">
{{end}} <i class="fa {{if .IsDir}}fa-folder{{else}}fa-file-text-o{{end}}"></i>
</tbody> </td>
</table> <td class="name">
<span class="wrap">
{{if .IsDir}}
<a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}/{{.Path}}">{{.Name}}</a>
{{else}}
<a href="/{{$username}}/{{$reponame}}/blob/{{$branchname}}/{{.Name}}">{{.Name}}</a>
{{end}}
</span>
</td>
<td class="text">
<span class="wrap">
{{.Message}}
</span>
</td>
<td class="date">
<span class="wrap">
{{TimeSince .Created}}
</span>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<div class="panel panel-default file-content">
<div class="panel-heading">
README.md
</div>
<div class="panel-body markdown">
httplib
</div>
</div>
</div> </div>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

View File

@ -13,22 +13,33 @@
</ul> </ul>
</div> </div>
<div id="gogs-user-setting-container" class="col-md-9"> <div id="gogs-user-setting-container" class="col-md-9">
<form action="/user/delete" method="post" class="form-horizontal" id="gogs-user-delete"> <h4>Delete Account</h4>
<h4>Delete Account</h4> <p class="alert alert-danger">{{if not .HasError}}The operation will delete your account permanently. Sorry to see you go, but we know you'll back soon.{{else}}{{.ErrorMsg}}{{end}}</p>
<p class="alert alert-danger">{{if not .HasError}}The operation will delete your account permanently. Sorry to see you go, but we know you'll back soon.{{else}}{{.ErrorMsg}}{{end}}</p> <div class="form-group">
<div class="form-group"> <button type="submit" class="btn btn-danger btn-lg" href="#delete-account-modal" id="gogs-delete-account" data-toggle="modal">Delete Account</button>
<div class="col-md-3"> </div>
<button type="submit" class="btn btn-danger btn-lg">Delete Account</button> </div>
<div class="modal fade" id="delete-account-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<form action="/user/delete" method="post" class="modal-content" id="gogs-user-delete">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="myModalLabel">Delete Account</h4>
</div> </div>
</div>
</form> <div class="modal-body">
<div class="form-group">
<label>Make sure your are owner of this account. Please enter your password.<strong class="text-danger">*</strong></label>
<input name="password" class="form-control" type="password" placeholder="Type your account password" required="required">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-danger">Delete</button>
</div>
</form>
</div>
</div> </div>
</div> </div>
<script>
$(function(){
$('#gogs-user-delete').on('submit',function(){
return confirm("Are you sure ?");
})
});
</script>
{{template "base/footer" .}} {{template "base/footer" .}}

View File

@ -5,7 +5,7 @@
<h4>Account Setting</h4> <h4>Account Setting</h4>
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"><a href="/user/setting">Account Profile</a></li> <li class="list-group-item"><a href="/user/setting">Account Profile</a></li>
<li class="list-group-item"><a href="/user/setting/Password">Password</a></li> <li class="list-group-item"><a href="/user/setting/password">Password</a></li>
<li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> <li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li>
<li class="list-group-item list-group-item-success"><a href="/user/setting/ssh/">SSH Keys</a></li> <li class="list-group-item list-group-item-success"><a href="/user/setting/ssh/">SSH Keys</a></li>
<li class="list-group-item"><a href="/user/setting/security">Security</a></li> <li class="list-group-item"><a href="/user/setting/security">Security</a></li>
@ -18,12 +18,14 @@
<h4>SSH Keys</h4>{{if .AddSSHKeySuccess}} <h4>SSH Keys</h4>{{if .AddSSHKeySuccess}}
<p class="alert alert-success">New SSH Key has been added !</p>{{else if .HasError}}<p class="alert alert-danger">{{.ErrorMsg}}</p>{{end}} <p class="alert alert-success">New SSH Key has been added !</p>{{else if .HasError}}<p class="alert alert-danger">{{.ErrorMsg}}</p>{{end}}
<ul id="gogs-ssh-keys-list" class="list-group"> <ul id="gogs-ssh-keys-list" class="list-group">
<li class="list-group-item"><span class="name">SSH Key's name</span></li>{{range .Keys}} <li class="list-group-item"><span class="name">SSH Key's name</span></li>
{{range .Keys}}
<li class="list-group-item"> <li class="list-group-item">
<span class="name">{{.Name}}</span> <span class="name">{{.Name}}</span>
<span class="print">(print code)</span> <span class="print">({{.Fingerprint}})</span>
<a href="#" class="btn btn-link btn-danger right delete" rel="{{.Id}}" data-del="{{.Id}}">Delete</a> <button href="#" class="btn btn-danger delete pull-right" rel="{{.Id}}" data-del="{{.Id}}">Delete</button>
</li>{{end}} </li>
{{end}}
<li class="list-group-item"> <li class="list-group-item">
<a class="btn btn-link btn-primary" href="#ssh-add-modal" id="gogs-ssh-add" data-toggle="modal">Add SSH Key</a> <a class="btn btn-link btn-primary" href="#ssh-add-modal" id="gogs-ssh-add" data-toggle="modal">Add SSH Key</a>
</li> </li>

View File

@ -1,13 +1,19 @@
// 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 main package main
import ( import (
"os" "os"
"strconv" "strconv"
"github.com/gogits/gogs/models"
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
git "github.com/gogits/git" git "github.com/gogits/git"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
) )
var CmdUpdate = cli.Command{ var CmdUpdate = cli.Command{
@ -41,11 +47,18 @@ func runUpdate(*cli.Context) {
if err != nil { if err != nil {
return return
} }
sUserId, _ := strconv.Atoi(userId) sUserId, err := strconv.Atoi(userId)
sRepoId, _ := strconv.Atoi(repoId)
err = models.CommitRepoAction(int64(sUserId), userName,
int64(sRepoId), repoName, lastCommit.Message())
if err != nil { if err != nil {
//TODO: log log.Error("runUpdate.Parse userId: %v", err)
return
}
sRepoId, err := strconv.Atoi(repoId)
if err != nil {
log.Error("runUpdate.Parse repoId: %v", err)
return
}
if err = models.CommitRepoAction(int64(sUserId), userName,
int64(sRepoId), repoName, lastCommit.Message()); err != nil {
log.Error("runUpdate.models.CommitRepoAction: %v", err)
} }
} }

10
web.go
View File

@ -50,6 +50,9 @@ func runWeb(*cli.Context) {
// Routers. // Routers.
m.Get("/", middleware.SignInRequire(false), routers.Home) m.Get("/", middleware.SignInRequire(false), routers.Home)
m.Get("/issues", middleware.SignInRequire(true), user.Issues)
m.Get("/pulls", middleware.SignInRequire(true), user.Pulls)
m.Get("/stars", middleware.SignInRequire(true), user.Stars)
m.Any("/user/login", middleware.SignOutRequire(), binding.BindIgnErr(auth.LogInForm{}), user.SignIn) m.Any("/user/login", middleware.SignOutRequire(), binding.BindIgnErr(auth.LogInForm{}), user.SignIn)
m.Any("/user/logout", middleware.SignInRequire(true), user.SignOut) m.Any("/user/logout", middleware.SignInRequire(true), user.SignOut)
m.Any("/user/sign_up", middleware.SignOutRequire(), binding.BindIgnErr(auth.RegisterForm{}), user.SignUp) m.Any("/user/sign_up", middleware.SignOutRequire(), binding.BindIgnErr(auth.RegisterForm{}), user.SignUp)
@ -67,15 +70,18 @@ func runWeb(*cli.Context) {
m.Any("/repo/create", middleware.SignInRequire(true), binding.BindIgnErr(auth.CreateRepoForm{}), repo.Create) m.Any("/repo/create", middleware.SignInRequire(true), binding.BindIgnErr(auth.CreateRepoForm{}), repo.Create)
m.Any("/repo/delete", middleware.SignInRequire(true), binding.Bind(auth.DeleteRepoForm{}), repo.Delete) m.Any("/repo/delete", middleware.SignInRequire(true), binding.Bind(auth.DeleteRepoForm{}), repo.Delete)
m.Get("/help", routers.Help)
m.Get("/:username/:reponame/settings", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Setting) m.Get("/:username/:reponame/settings", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Setting)
m.Get("/:username/:reponame/commits", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Commits)
m.Get("/:username/:reponame/issues", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Issues)
m.Get("/:username/:reponame/pulls", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Pulls)
m.Get("/:username/:reponame/tree/:branchname/**", m.Get("/:username/:reponame/tree/:branchname/**",
middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single) middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single)
m.Get("/:username/:reponame/tree/:branchname", m.Get("/:username/:reponame/tree/:branchname",
middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single) middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single)
m.Get("/:username/:reponame", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single) m.Get("/:username/:reponame", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single)
//m.Get("/:username/:reponame", repo.Repo)
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"))