Compare commits
26 Commits
Author | SHA1 | Date |
---|---|---|
AJ ONeal | de85108909 | |
AJ ONeal | dbd197976b | |
AJ ONeal | 0994704e2e | |
AJ ONeal | 685995b1ca | |
AJ ONeal | 279f4b65f8 | |
AJ ONeal | db970dcf06 | |
AJ ONeal | 0b85f74e79 | |
techknowlogick | 31a738b221 | |
AJ ONeal | ef263718b8 | |
AJ ONeal | f432d95ed5 | |
AJ ONeal | 18ee6f3ed7 | |
AJ ONeal | b3d5fec6b2 | |
AJ ONeal | ce9f757a38 | |
AJ ONeal | 9d3690f8df | |
SagePtr | 812c225223 | |
Lauris BH | 33c3cbc968 | |
Iwasa Kazmi | 8f29f61a6b | |
SagePtr | 93dcc6caef | |
crito | 4176e33148 | |
Toni Villena | 177b46fe77 | |
linweijie2012 | 1e51307466 | |
SagePtr | c145cb745b | |
techknowlogick | 1a68b3962f | |
SagePtr | d918e63bc5 | |
Lunny Xiao | 1901f35980 | |
Nicolas Lenz | 745c898561 |
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -4,6 +4,22 @@ This changelog goes through all the changes that have been made in each release
|
|||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.5.2](https://github.com/go-gitea/gitea/releases/tag/v1.5.2) - 2018-10-09
|
||||
* SECURITY
|
||||
* Enforce token on api routes (#4840) (#4905)
|
||||
* BUGFIXES
|
||||
* Remove links from topics in edit mode (#5030)
|
||||
* Detect charset and convert non UTF-8 files for display (#4950) (#4994)
|
||||
* Fix layout of the topics editing form (#4971) (#4993)
|
||||
* Fix null pointer dereference in ParseCommitWithSignature (#4964)
|
||||
* Fix url in discord webhook (#4951)
|
||||
* Fix font-cropping UI bug in diff (#4726) (#4929)
|
||||
* Fix bug forget to remove Stopwatch when remove repository (#4933)
|
||||
* Fix bug when repo remained bare if multiple branches pushed (#4927)
|
||||
* Fix redirect with non-ascii branch names (#4764) (#4887)
|
||||
* Fix issues api allow pulls (#4852) (#4862)
|
||||
* Fix trimming of markup section names (#4864)
|
||||
|
||||
## [1.5.1](https://github.com/go-gitea/gitea/releases/tag/v1.5.1) - 2018-09-03
|
||||
* SECURITY
|
||||
* Don't disclose emails of all users when sending out emails (#4784)
|
||||
|
|
|
@ -339,29 +339,6 @@
|
|||
packages = ["."]
|
||||
revision = "5f1c01d9f64b941dd9582c638279d046eda6ca31"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/context"
|
||||
packages = ["."]
|
||||
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/mux"
|
||||
packages = ["."]
|
||||
revision = "757bef944d0f21880861c2dd9c871ca543023cba"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/securecookie"
|
||||
packages = ["."]
|
||||
revision = "e59506cc896acb7f7bf732d4fdf5e25f7ccd8983"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/sessions"
|
||||
packages = ["."]
|
||||
revision = "ca9ada44574153444b00d3fd9c8559e4cc95f896"
|
||||
version = "v1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/issue9/identicon"
|
||||
packages = ["."]
|
||||
|
|
|
@ -40,14 +40,6 @@ ignored = ["google.golang.org/appengine*"]
|
|||
#version = "0.6.5"
|
||||
revision = "ad69f7d8f0861a29438154bb0a20b60501298480"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/gorilla/mux"
|
||||
revision = "757bef944d0f21880861c2dd9c871ca543023cba"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/context"
|
||||
version = "1.1.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/lafriks/xormstore"
|
||||
version = "1.0.0"
|
||||
|
|
11
cmd/web.go
11
cmd/web.go
|
@ -20,7 +20,6 @@ import (
|
|||
"code.gitea.io/gitea/routers/routes"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
context2 "github.com/gorilla/context"
|
||||
"github.com/urfave/cli"
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
@ -64,7 +63,7 @@ func runHTTPRedirector() {
|
|||
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
|
||||
})
|
||||
|
||||
var err = runHTTP(source, context2.ClearHandler(handler))
|
||||
var err = runHTTP(source, handler)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to start port redirection: %v", err)
|
||||
|
@ -141,19 +140,19 @@ func runWeb(ctx *cli.Context) error {
|
|||
var err error
|
||||
switch setting.Protocol {
|
||||
case setting.HTTP:
|
||||
err = runHTTP(listenAddr, context2.ClearHandler(m))
|
||||
err = runHTTP(listenAddr, m)
|
||||
case setting.HTTPS:
|
||||
if setting.RedirectOtherPort {
|
||||
go runHTTPRedirector()
|
||||
}
|
||||
err = runHTTPS(listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
|
||||
err = runHTTPS(listenAddr, setting.CertFile, setting.KeyFile, m)
|
||||
case setting.FCGI:
|
||||
listener, err := net.Listen("tcp", listenAddr)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to bind %s", listenAddr, err)
|
||||
}
|
||||
defer listener.Close()
|
||||
err = fcgi.Serve(listener, context2.ClearHandler(m))
|
||||
err = fcgi.Serve(listener, m)
|
||||
case setting.UnixSocket:
|
||||
if err := os.Remove(listenAddr); err != nil && !os.IsNotExist(err) {
|
||||
log.Fatal(4, "Failed to remove unix socket directory %s: %v", listenAddr, err)
|
||||
|
@ -169,7 +168,7 @@ func runWeb(ctx *cli.Context) error {
|
|||
if err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)); err != nil {
|
||||
log.Fatal(4, "Failed to set permission of unix socket: %v", err)
|
||||
}
|
||||
err = http.Serve(listener, context2.ClearHandler(m))
|
||||
err = http.Serve(listener, m)
|
||||
default:
|
||||
log.Fatal(4, "Invalid protocol: %s", setting.Protocol)
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
|
|||
session := loginUser(t, "user1")
|
||||
keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", keyOwner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", keyOwner.Name, token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
|
||||
"title": "test-key",
|
||||
|
@ -36,7 +37,7 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
|
|||
OwnerID: keyOwner.ID,
|
||||
})
|
||||
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d",
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
|
||||
keyOwner.Name, newPublicKey.ID)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
models.AssertNotExistsBean(t, &models.PublicKey{ID: newPublicKey.ID})
|
||||
|
@ -46,8 +47,9 @@ func TestAPIAdminDeleteMissingSSHKey(t *testing.T) {
|
|||
prepareTestEnv(t)
|
||||
// user1 is an admin user
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d", models.NonexistentID)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d?token="+token, models.NonexistentID)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
|
@ -57,7 +59,8 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
|
|||
normalUsername := "user2"
|
||||
session := loginUser(t, adminUsername)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", adminUsername, token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
|
||||
"title": "test-key",
|
||||
|
@ -67,7 +70,8 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
|
|||
DecodeJSON(t, resp, &newPublicKey)
|
||||
|
||||
session = loginUser(t, normalUsername)
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d",
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
|
||||
adminUsername, newPublicKey.ID)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ func testAPIGetBranch(t *testing.T, branchName string, exists bool) {
|
|||
prepareTestEnv(t)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branches/%s", branchName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branches/%s?token=%s", branchName, token)
|
||||
resp := session.MakeRequest(t, req, NoExpectedStatus)
|
||||
if !exists {
|
||||
assert.EqualValues(t, http.StatusNotFound, resp.Code)
|
||||
|
|
|
@ -69,8 +69,9 @@ func TestAPICreateComment(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments",
|
||||
repoOwner.Name, repo.Name, issue.Index)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
|
||||
repoOwner.Name, repo.Name, issue.Index, token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"body": commentBody,
|
||||
})
|
||||
|
@ -93,8 +94,9 @@ func TestAPIEditComment(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d",
|
||||
repoOwner.Name, repo.Name, comment.ID)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
||||
repoOwner.Name, repo.Name, comment.ID, token)
|
||||
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
|
||||
"body": newCommentBody,
|
||||
})
|
||||
|
@ -117,8 +119,9 @@ func TestAPIDeleteComment(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d",
|
||||
repoOwner.Name, repo.Name, comment.ID)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
||||
repoOwner.Name, repo.Name, comment.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
models.AssertNotExistsBean(t, &models.Comment{ID: comment.ID})
|
||||
|
|
|
@ -20,16 +20,18 @@ type makeRequestFunc func(testing.TB, *http.Request, int) *httptest.ResponseReco
|
|||
func TestGPGKeys(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
makeRequest makeRequestFunc
|
||||
token string
|
||||
results []int
|
||||
}{
|
||||
{name: "NoLogin", makeRequest: MakeRequest,
|
||||
{name: "NoLogin", makeRequest: MakeRequest, token: "",
|
||||
results: []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized},
|
||||
},
|
||||
{name: "LoggedAsUser2", makeRequest: session.MakeRequest,
|
||||
{name: "LoggedAsUser2", makeRequest: session.MakeRequest, token: token,
|
||||
results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusInternalServerError, http.StatusInternalServerError, http.StatusCreated, http.StatusCreated}},
|
||||
}
|
||||
|
||||
|
@ -38,29 +40,29 @@ func TestGPGKeys(t *testing.T) {
|
|||
//Basic test on result code
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Run("ViewOwnGPGKeys", func(t *testing.T) {
|
||||
testViewOwnGPGKeys(t, tc.makeRequest, tc.results[0])
|
||||
testViewOwnGPGKeys(t, tc.makeRequest, tc.token, tc.results[0])
|
||||
})
|
||||
t.Run("ViewGPGKeys", func(t *testing.T) {
|
||||
testViewGPGKeys(t, tc.makeRequest, tc.results[1])
|
||||
testViewGPGKeys(t, tc.makeRequest, tc.token, tc.results[1])
|
||||
})
|
||||
t.Run("GetGPGKey", func(t *testing.T) {
|
||||
testGetGPGKey(t, tc.makeRequest, tc.results[2])
|
||||
testGetGPGKey(t, tc.makeRequest, tc.token, tc.results[2])
|
||||
})
|
||||
t.Run("DeleteGPGKey", func(t *testing.T) {
|
||||
testDeleteGPGKey(t, tc.makeRequest, tc.results[3])
|
||||
testDeleteGPGKey(t, tc.makeRequest, tc.token, tc.results[3])
|
||||
})
|
||||
|
||||
t.Run("CreateInvalidGPGKey", func(t *testing.T) {
|
||||
testCreateInvalidGPGKey(t, tc.makeRequest, tc.results[4])
|
||||
testCreateInvalidGPGKey(t, tc.makeRequest, tc.token, tc.results[4])
|
||||
})
|
||||
t.Run("CreateNoneRegistredEmailGPGKey", func(t *testing.T) {
|
||||
testCreateNoneRegistredEmailGPGKey(t, tc.makeRequest, tc.results[5])
|
||||
testCreateNoneRegistredEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[5])
|
||||
})
|
||||
t.Run("CreateValidGPGKey", func(t *testing.T) {
|
||||
testCreateValidGPGKey(t, tc.makeRequest, tc.results[6])
|
||||
testCreateValidGPGKey(t, tc.makeRequest, tc.token, tc.results[6])
|
||||
})
|
||||
t.Run("CreateValidSecondaryEmailGPGKey", func(t *testing.T) {
|
||||
testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.results[7])
|
||||
testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[7])
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -70,7 +72,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
|
||||
var keys []*api.GPGKey
|
||||
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys") //GET all keys
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token) //GET all keys
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &keys)
|
||||
|
||||
|
@ -91,7 +93,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
assert.EqualValues(t, false, primaryKey2.Emails[0].Verified)
|
||||
|
||||
var key api.GPGKey
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)) //Primary key 1
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)+"?token="+token) //Primary key 1
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &key)
|
||||
assert.EqualValues(t, "38EA3BCED732982C", key.KeyID)
|
||||
|
@ -99,13 +101,13 @@ func TestGPGKeys(t *testing.T) {
|
|||
assert.EqualValues(t, "user2@example.com", key.Emails[0].Email)
|
||||
assert.EqualValues(t, true, key.Emails[0].Verified)
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)) //Subkey of 38EA3BCED732982C
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)+"?token="+token) //Subkey of 38EA3BCED732982C
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &key)
|
||||
assert.EqualValues(t, "70D7C694D17D03AD", key.KeyID)
|
||||
assert.EqualValues(t, 0, len(key.Emails))
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey2.ID, 10)) //Primary key 2
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey2.ID, 10)+"?token="+token) //Primary key 2
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &key)
|
||||
assert.EqualValues(t, "FABF39739FE1E927", key.KeyID)
|
||||
|
@ -119,7 +121,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
t.Run("CheckCommits", func(t *testing.T) {
|
||||
t.Run("NotSigned", func(t *testing.T) {
|
||||
var branch api.Branch
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/not-signed")
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/not-signed?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.EqualValues(t, false, branch.Commit.Verification.Verified)
|
||||
|
@ -127,7 +129,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
|
||||
t.Run("SignedWithNotValidatedEmail", func(t *testing.T) {
|
||||
var branch api.Branch
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated")
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.EqualValues(t, false, branch.Commit.Verification.Verified)
|
||||
|
@ -135,7 +137,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
|
||||
t.Run("SignedWithValidEmail", func(t *testing.T) {
|
||||
var branch api.Branch
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign")
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.EqualValues(t, true, branch.Commit.Verification.Verified)
|
||||
|
@ -143,39 +145,39 @@ func TestGPGKeys(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func testViewOwnGPGKeys(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys")
|
||||
func testViewOwnGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testViewGPGKeys(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/users/user2/gpg_keys")
|
||||
func testViewGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/users/user2/gpg_keys?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testGetGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys/1")
|
||||
func testGetGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys/1?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testDeleteGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
req := NewRequest(t, "DELETE", "/api/v1/user/gpg_keys/1")
|
||||
func testDeleteGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "DELETE", "/api/v1/user/gpg_keys/1?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testCreateGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int, publicKey string) {
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/gpg_keys", api.CreateGPGKeyOption{
|
||||
func testCreateGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int, publicKey string) {
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/gpg_keys?token="+token, api.CreateGPGKeyOption{
|
||||
ArmoredKey: publicKey,
|
||||
})
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testCreateInvalidGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, expected, "invalid_key")
|
||||
func testCreateInvalidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, token, expected, "invalid_key")
|
||||
}
|
||||
|
||||
func testCreateNoneRegistredEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
func testCreateNoneRegistredEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFmGUygBCACjCNbKvMGgp0fd5vyFW9olE1CLCSyyF9gQN2hSuzmZLuAZF2Kh
|
||||
dCMCG2T1UwzUB/yWUFWJ2BtCwSjuaRv+cGohqEy6bhEBV90peGA33lHfjx7wP25O
|
||||
|
@ -194,9 +196,9 @@ INx/MmBfmtCq05FqNclvU+sj2R3N1JJOtBOjZrJHQbJhzoILou8AkxeX1A+q9OAz
|
|||
-----END PGP PUBLIC KEY BLOCK-----`)
|
||||
}
|
||||
|
||||
func testCreateValidGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
func testCreateValidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
//User2 <user2@example.com> //primary & activated
|
||||
testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFmGVsMBCACuxgZ7W7rI9xN08Y4M7B8yx/6/I4Slm94+wXf8YNRvAyqj30dW
|
||||
VJhyBcnfNRDLKSQp5o/hhfDkCgdqBjLa1PnHlGS3PXJc0hP/FyYPD2BFvNMPpCYS
|
||||
|
@ -228,9 +230,9 @@ uy6MA3VSB99SK9ducGmE1Jv8mcziREroz2TEGr0zPs6h
|
|||
-----END PGP PUBLIC KEY BLOCK-----`)
|
||||
}
|
||||
|
||||
func testCreateValidSecondaryEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
func testCreateValidSecondaryEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
//User2 <user21@example.com> //secondary and not activated
|
||||
testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFmGWN4BCAC18V4tVGO65VLCV7p14FuXJlUtZ5CuYMvgEkcOqrvRaBSW9ao4
|
||||
PGESOhJpfWpnW3QgJniYndLzPpsmdHEclEER6aZjiNgReWPOjHD5tykWocZAJqXD
|
||||
|
|
|
@ -23,12 +23,13 @@ func TestAPIAddIssueLabels(t *testing.T) {
|
|||
label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
|
||||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels",
|
||||
owner.Name, repo.Name, issue.Index)
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
|
||||
owner.Name, repo.Name, issue.Index, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueLabelsOption{
|
||||
Labels: []int64{label.ID},
|
||||
})
|
||||
session := loginUser(t, owner.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiLabels []*api.Label
|
||||
DecodeJSON(t, resp, &apiLabels)
|
||||
|
@ -45,12 +46,13 @@ func TestAPIReplaceIssueLabels(t *testing.T) {
|
|||
label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
|
||||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels",
|
||||
owner.Name, repo.Name, issue.Index)
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
|
||||
owner.Name, repo.Name, issue.Index, token)
|
||||
req := NewRequestWithJSON(t, "PUT", urlStr, &api.IssueLabelsOption{
|
||||
Labels: []int64{label.ID},
|
||||
})
|
||||
session := loginUser(t, owner.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiLabels []*api.Label
|
||||
DecodeJSON(t, resp, &apiLabels)
|
||||
|
|
|
@ -22,8 +22,9 @@ func TestAPIListIssues(t *testing.T) {
|
|||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all",
|
||||
owner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all&token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiIssues []*api.Issue
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
|
@ -41,8 +42,8 @@ func TestAPICreateIssue(t *testing.T) {
|
|||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all", owner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all&token=%s", owner.Name, repo.Name, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
|
||||
Body: body,
|
||||
Title: title,
|
||||
|
|
|
@ -46,8 +46,8 @@ func TestCreateReadOnlyDeployKey(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys", repoOwner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
|
||||
rawKeyBody := api.CreateKeyOption{
|
||||
Title: "read-only",
|
||||
Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
|
||||
|
@ -72,8 +72,8 @@ func TestCreateReadWriteDeployKey(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys", repoOwner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
|
||||
rawKeyBody := api.CreateKeyOption{
|
||||
Title: "read-write",
|
||||
Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsufOCrDDlT8DLkodnnJtbq7uGflcPae7euTfM+Laq4So+v4WeSV362Rg0O/+Sje1UthrhN6lQkfRkdWIlCRQEXg+LMqr6RhvDfZquE2Xwqv/itlz7LjbdAUdYoO1iH7rMSmYvQh4WEnC/DAacKGbhdGIM/ZBz0z6tHm7bPgbI9ykEKekTmPwQFP1Qebvf5NYOFMWqQ2sCEAI9dBMVLoojsIpV+KADf+BotiIi8yNfTG2rzmzpxBpW9fYjd1Sy1yd4NSUpoPbEJJYJ1TrjiSWlYOVq9Ar8xW1O87i6gBjL/3zN7ANeoYhaAXupdOS6YL22YOK/yC0tJtXwwdh/eSrh",
|
||||
|
|
|
@ -20,7 +20,8 @@ func TestAPIViewPulls(t *testing.T) {
|
|||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all", owner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all&token="+token, owner.Name, repo.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var pulls []*api.PullRequest
|
||||
|
|
|
@ -22,7 +22,7 @@ func TestAPICreateRelease(t *testing.T) {
|
|||
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
|
||||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
session := loginUser(t, owner.LowerName)
|
||||
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
@ -32,8 +32,8 @@ func TestAPICreateRelease(t *testing.T) {
|
|||
commitID, err := gitRepo.GetTagCommitID("v0.0.1")
|
||||
assert.NoError(t, err)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases",
|
||||
owner.Name, repo.Name)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
|
||||
TagName: "v0.0.1",
|
||||
Title: "v0.0.1",
|
||||
|
@ -53,8 +53,8 @@ func TestAPICreateRelease(t *testing.T) {
|
|||
Note: newRelease.Note,
|
||||
})
|
||||
|
||||
urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d",
|
||||
owner.Name, repo.Name, newRelease.ID)
|
||||
urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d?token=%s",
|
||||
owner.Name, repo.Name, newRelease.ID, token)
|
||||
req = NewRequest(t, "GET", urlStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
|
|
|
@ -16,16 +16,17 @@ func TestAPIReposRaw(t *testing.T) {
|
|||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
for _, ref := range [...]string{
|
||||
"master", // Branch
|
||||
"v1.1", // Tag
|
||||
"65f1bf27bc3bf70f64657658635e66094edbcb4d", // Commit
|
||||
} {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md", user.Name, ref)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md?token="+token, user.Name, ref)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
// Test default branch
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md", user.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md?token="+token, user.Name)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
|
|
@ -67,16 +67,16 @@ func TestAPISearchRepo(t *testing.T) {
|
|||
expectedResults
|
||||
}{
|
||||
{name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50", expectedResults: expectedResults{
|
||||
nil: {count: 16},
|
||||
user: {count: 16},
|
||||
user2: {count: 16}},
|
||||
nil: {count: 17},
|
||||
user: {count: 17},
|
||||
user2: {count: 17}},
|
||||
},
|
||||
{name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10", expectedResults: expectedResults{
|
||||
nil: {count: 10},
|
||||
user: {count: 10},
|
||||
user2: {count: 10}},
|
||||
},
|
||||
{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search", expectedResults: expectedResults{
|
||||
{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default", expectedResults: expectedResults{
|
||||
nil: {count: 10},
|
||||
user: {count: 10},
|
||||
user2: {count: 10}},
|
||||
|
@ -143,17 +143,19 @@ func TestAPISearchRepo(t *testing.T) {
|
|||
var session *TestSession
|
||||
var testName string
|
||||
var userID int64
|
||||
var token string
|
||||
if userToLogin != nil && userToLogin.ID > 0 {
|
||||
testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
|
||||
session = loginUser(t, userToLogin.Name)
|
||||
userID = userToLogin.ID
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
} else {
|
||||
testName = "AnonymousUser"
|
||||
session = emptyTestSession(t)
|
||||
}
|
||||
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
request := NewRequest(t, "GET", testCase.requestURL)
|
||||
request := NewRequest(t, "GET", testCase.requestURL+"&token="+token)
|
||||
response := session.MakeRequest(t, request, http.StatusOK)
|
||||
|
||||
var body api.SearchResults
|
||||
|
@ -215,7 +217,8 @@ func TestAPIOrgRepos(t *testing.T) {
|
|||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", sourceOrg.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token="+token, sourceOrg.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiRepos []*api.Repository
|
||||
|
@ -231,9 +234,10 @@ func TestAPIOrgRepos(t *testing.T) {
|
|||
func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)
|
||||
sess := loginUser(t, user.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repositories/2")
|
||||
sess.MakeRequest(t, req, http.StatusNotFound)
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repositories/2?token="+token)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func TestAPIRepoMigrate(t *testing.T) {
|
||||
|
@ -253,8 +257,8 @@ func TestAPIRepoMigrate(t *testing.T) {
|
|||
for _, testCase := range testCases {
|
||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
|
||||
session := loginUser(t, user.Name)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate", &api.MigrateRepoOption{
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOption{
|
||||
CloneAddr: testCase.cloneURL,
|
||||
UID: int(testCase.userID),
|
||||
RepoName: testCase.repoName,
|
||||
|
|
|
@ -21,7 +21,8 @@ func TestAPITeam(t *testing.T) {
|
|||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: teamUser.UID}).(*models.User)
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamUser.TeamID)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiTeam api.Team
|
||||
|
|
|
@ -75,7 +75,8 @@ func TestGit(t *testing.T) {
|
|||
|
||||
t.Run("CreateRepo", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
|
||||
AutoInit: true,
|
||||
Description: "Temporary repo",
|
||||
Name: "repo-tmp-17",
|
||||
|
@ -166,7 +167,8 @@ func TestGit(t *testing.T) {
|
|||
t.Run("Standard", func(t *testing.T) {
|
||||
t.Run("CreateRepo", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
|
||||
AutoInit: true,
|
||||
Description: "Temporary repo",
|
||||
Name: "repo-tmp-18",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ref: refs/heads/master
|
|
@ -0,0 +1,4 @@
|
|||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = true
|
|
@ -0,0 +1 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message taken by
|
||||
# applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit. The hook is
|
||||
# allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "applypatch-msg".
|
||||
|
||||
. git-sh-setup
|
||||
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||
:
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message.
|
||||
# Called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero
|
||||
# status after issuing an appropriate message if it wants to stop the
|
||||
# commit. The hook is allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "commit-msg".
|
||||
|
||||
# Uncomment the below to add a Signed-off-by line to the message.
|
||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||
# hook is more suited to it.
|
||||
#
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||
|
||||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||
echo >&2 Duplicate Signed-off-by lines.
|
||||
exit 1
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
ORI_DIR=`pwd`
|
||||
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||
cd "$ORI_DIR"
|
||||
for i in `ls "$SHELL_FOLDER/post-receive.d"`; do
|
||||
sh "$SHELL_FOLDER/post-receive.d/$i"
|
||||
done
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to prepare a packed repository for use over
|
||||
# dumb transports.
|
||||
#
|
||||
# To enable this hook, rename this file to "post-update".
|
||||
|
||||
exec git update-server-info
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed
|
||||
# by applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-applypatch".
|
||||
|
||||
. git-sh-setup
|
||||
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||
:
|
|
@ -0,0 +1,49 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git commit" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message if
|
||||
# it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-commit".
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||
then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
||||
fi
|
||||
|
||||
# If you want to allow non-ASCII filenames set this variable to true.
|
||||
allownonascii=$(git config --bool hooks.allownonascii)
|
||||
|
||||
# Redirect output to stderr.
|
||||
exec 1>&2
|
||||
|
||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||
# them from being added to the repository. We exploit the fact that the
|
||||
# printable range starts at the space character and ends with tilde.
|
||||
if [ "$allownonascii" != "true" ] &&
|
||||
# Note that the use of brackets around a tr range is ok here, (it's
|
||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||
# the square bracket bytes happen to fall in the designated range.
|
||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||
then
|
||||
cat <<\EOF
|
||||
Error: Attempt to add a non-ASCII file name.
|
||||
|
||||
This can cause problems if you want to work with people on other platforms.
|
||||
|
||||
To be portable it is advisable to rename the file.
|
||||
|
||||
If you know what you are doing you can disable this check using:
|
||||
|
||||
git config hooks.allownonascii true
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If there are whitespace errors, print the offending file names and fail.
|
||||
exec git diff-index --check --cached $against --
|
|
@ -0,0 +1,53 @@
|
|||
#!/bin/sh
|
||||
|
||||
# An example hook script to verify what is about to be pushed. Called by "git
|
||||
# push" after it has checked the remote status, but before anything has been
|
||||
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||
#
|
||||
# This hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- Name of the remote to which the push is being done
|
||||
# $2 -- URL to which the push is being done
|
||||
#
|
||||
# If pushing without using a named remote those arguments will be equal.
|
||||
#
|
||||
# Information about the commits which are being pushed is supplied as lines to
|
||||
# the standard input in the form:
|
||||
#
|
||||
# <local ref> <local sha1> <remote ref> <remote sha1>
|
||||
#
|
||||
# This sample shows how to prevent push of commits where the log message starts
|
||||
# with "WIP" (work in progress).
|
||||
|
||||
remote="$1"
|
||||
url="$2"
|
||||
|
||||
z40=0000000000000000000000000000000000000000
|
||||
|
||||
while read local_ref local_sha remote_ref remote_sha
|
||||
do
|
||||
if [ "$local_sha" = $z40 ]
|
||||
then
|
||||
# Handle delete
|
||||
:
|
||||
else
|
||||
if [ "$remote_sha" = $z40 ]
|
||||
then
|
||||
# New branch, examine all commits
|
||||
range="$local_sha"
|
||||
else
|
||||
# Update to existing branch, examine new commits
|
||||
range="$remote_sha..$local_sha"
|
||||
fi
|
||||
|
||||
# Check for WIP commit
|
||||
commit=`git rev-list -n 1 --grep '^WIP' "$range"`
|
||||
if [ -n "$commit" ]
|
||||
then
|
||||
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,169 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||
#
|
||||
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||
# its job, and can prevent the command from running by exiting with
|
||||
# non-zero status.
|
||||
#
|
||||
# The hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- the upstream the series was forked from.
|
||||
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||
#
|
||||
# This sample shows how to prevent topic branches that are already
|
||||
# merged to 'next' branch from getting rebased, because allowing it
|
||||
# would result in rebasing already published history.
|
||||
|
||||
publish=next
|
||||
basebranch="$1"
|
||||
if test "$#" = 2
|
||||
then
|
||||
topic="refs/heads/$2"
|
||||
else
|
||||
topic=`git symbolic-ref HEAD` ||
|
||||
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||
fi
|
||||
|
||||
case "$topic" in
|
||||
refs/heads/??/*)
|
||||
;;
|
||||
*)
|
||||
exit 0 ;# we do not interrupt others.
|
||||
;;
|
||||
esac
|
||||
|
||||
# Now we are dealing with a topic branch being rebased
|
||||
# on top of master. Is it OK to rebase it?
|
||||
|
||||
# Does the topic really exist?
|
||||
git show-ref -q "$topic" || {
|
||||
echo >&2 "No such branch $topic"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Is topic fully merged to master?
|
||||
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||
if test -z "$not_in_master"
|
||||
then
|
||||
echo >&2 "$topic is fully merged to master; better remove it."
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
fi
|
||||
|
||||
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||
if test "$only_next_1" = "$only_next_2"
|
||||
then
|
||||
not_in_topic=`git rev-list "^$topic" master`
|
||||
if test -z "$not_in_topic"
|
||||
then
|
||||
echo >&2 "$topic is already up-to-date with master"
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||
/usr/bin/perl -e '
|
||||
my $topic = $ARGV[0];
|
||||
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||
my (%not_in_next) = map {
|
||||
/^([0-9a-f]+) /;
|
||||
($1 => 1);
|
||||
} split(/\n/, $ARGV[1]);
|
||||
for my $elem (map {
|
||||
/^([0-9a-f]+) (.*)$/;
|
||||
[$1 => $2];
|
||||
} split(/\n/, $ARGV[2])) {
|
||||
if (!exists $not_in_next{$elem->[0]}) {
|
||||
if ($msg) {
|
||||
print STDERR $msg;
|
||||
undef $msg;
|
||||
}
|
||||
print STDERR " $elem->[1]\n";
|
||||
}
|
||||
}
|
||||
' "$topic" "$not_in_next" "$not_in_master"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
<<\DOC_END
|
||||
|
||||
This sample hook safeguards topic branches that have been
|
||||
published from being rewound.
|
||||
|
||||
The workflow assumed here is:
|
||||
|
||||
* Once a topic branch forks from "master", "master" is never
|
||||
merged into it again (either directly or indirectly).
|
||||
|
||||
* Once a topic branch is fully cooked and merged into "master",
|
||||
it is deleted. If you need to build on top of it to correct
|
||||
earlier mistakes, a new topic branch is created by forking at
|
||||
the tip of the "master". This is not strictly necessary, but
|
||||
it makes it easier to keep your history simple.
|
||||
|
||||
* Whenever you need to test or publish your changes to topic
|
||||
branches, merge them into "next" branch.
|
||||
|
||||
The script, being an example, hardcodes the publish branch name
|
||||
to be "next", but it is trivial to make it configurable via
|
||||
$GIT_DIR/config mechanism.
|
||||
|
||||
With this workflow, you would want to know:
|
||||
|
||||
(1) ... if a topic branch has ever been merged to "next". Young
|
||||
topic branches can have stupid mistakes you would rather
|
||||
clean up before publishing, and things that have not been
|
||||
merged into other branches can be easily rebased without
|
||||
affecting other people. But once it is published, you would
|
||||
not want to rewind it.
|
||||
|
||||
(2) ... if a topic branch has been fully merged to "master".
|
||||
Then you can delete it. More importantly, you should not
|
||||
build on top of it -- other people may already want to
|
||||
change things related to the topic as patches against your
|
||||
"master", so if you need further changes, it is better to
|
||||
fork the topic (perhaps with the same name) afresh from the
|
||||
tip of "master".
|
||||
|
||||
Let's look at this example:
|
||||
|
||||
o---o---o---o---o---o---o---o---o---o "next"
|
||||
/ / / /
|
||||
/ a---a---b A / /
|
||||
/ / / /
|
||||
/ / c---c---c---c B /
|
||||
/ / / \ /
|
||||
/ / / b---b C \ /
|
||||
/ / / / \ /
|
||||
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||
|
||||
|
||||
A, B and C are topic branches.
|
||||
|
||||
* A has one fix since it was merged up to "next".
|
||||
|
||||
* B has finished. It has been fully merged up to "master" and "next",
|
||||
and is ready to be deleted.
|
||||
|
||||
* C has not merged to "next" at all.
|
||||
|
||||
We would want to allow C to be rebased, refuse A, and encourage
|
||||
B to be deleted.
|
||||
|
||||
To compute (1):
|
||||
|
||||
git rev-list ^master ^topic next
|
||||
git rev-list ^master next
|
||||
|
||||
if these match, topic has not merged in next at all.
|
||||
|
||||
To compute (2):
|
||||
|
||||
git rev-list master..topic
|
||||
|
||||
if this is empty, it is fully merged to "master".
|
||||
|
||||
DOC_END
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
ORI_DIR=`pwd`
|
||||
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||
cd "$ORI_DIR"
|
||||
for i in `ls "$SHELL_FOLDER/pre-receive.d"`; do
|
||||
sh "$SHELL_FOLDER/pre-receive.d/$i"
|
||||
done
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to prepare the commit log message.
|
||||
# Called by "git commit" with the name of the file that has the
|
||||
# commit message, followed by the description of the commit
|
||||
# message's source. The hook's purpose is to edit the commit
|
||||
# message file. If the hook fails with a non-zero status,
|
||||
# the commit is aborted.
|
||||
#
|
||||
# To enable this hook, rename this file to "prepare-commit-msg".
|
||||
|
||||
# This hook includes three examples. The first comments out the
|
||||
# "Conflicts:" part of a merge commit.
|
||||
#
|
||||
# The second includes the output of "git diff --name-status -r"
|
||||
# into the message, just before the "git status" output. It is
|
||||
# commented because it doesn't cope with --amend or with squashed
|
||||
# commits.
|
||||
#
|
||||
# The third example adds a Signed-off-by line to the message, that can
|
||||
# still be edited. This is rarely a good idea.
|
||||
|
||||
case "$2,$3" in
|
||||
merge,)
|
||||
/usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
|
||||
|
||||
# ,|template,)
|
||||
# /usr/bin/perl -i.bak -pe '
|
||||
# print "\n" . `git diff --cached --name-status -r`
|
||||
# if /^#/ && $first++ == 0' "$1" ;;
|
||||
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
ORI_DIR=`pwd`
|
||||
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||
cd "$ORI_DIR"
|
||||
for i in `ls "$SHELL_FOLDER/update.d"`; do
|
||||
sh "$SHELL_FOLDER/update.d/$i" $1 $2 $3
|
||||
done
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
|
|
@ -0,0 +1,128 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to block unannotated tags from entering.
|
||||
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
||||
#
|
||||
# To enable this hook, rename this file to "update".
|
||||
#
|
||||
# Config
|
||||
# ------
|
||||
# hooks.allowunannotated
|
||||
# This boolean sets whether unannotated tags will be allowed into the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowdeletetag
|
||||
# This boolean sets whether deleting tags will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowmodifytag
|
||||
# This boolean sets whether a tag may be modified after creation. By default
|
||||
# it won't be.
|
||||
# hooks.allowdeletebranch
|
||||
# This boolean sets whether deleting branches will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.denycreatebranch
|
||||
# This boolean sets whether remotely creating branches will be denied
|
||||
# in the repository. By default this is allowed.
|
||||
#
|
||||
|
||||
# --- Command line
|
||||
refname="$1"
|
||||
oldrev="$2"
|
||||
newrev="$3"
|
||||
|
||||
# --- Safety check
|
||||
if [ -z "$GIT_DIR" ]; then
|
||||
echo "Don't run this script from the command line." >&2
|
||||
echo " (if you want, you could supply GIT_DIR then run" >&2
|
||||
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Config
|
||||
allowunannotated=$(git config --bool hooks.allowunannotated)
|
||||
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
|
||||
denycreatebranch=$(git config --bool hooks.denycreatebranch)
|
||||
allowdeletetag=$(git config --bool hooks.allowdeletetag)
|
||||
allowmodifytag=$(git config --bool hooks.allowmodifytag)
|
||||
|
||||
# check for no description
|
||||
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||
case "$projectdesc" in
|
||||
"Unnamed repository"* | "")
|
||||
echo "*** Project description file hasn't been set" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Check types
|
||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||
zero="0000000000000000000000000000000000000000"
|
||||
if [ "$newrev" = "$zero" ]; then
|
||||
newrev_type=delete
|
||||
else
|
||||
newrev_type=$(git cat-file -t $newrev)
|
||||
fi
|
||||
|
||||
case "$refname","$newrev_type" in
|
||||
refs/tags/*,commit)
|
||||
# un-annotated tag
|
||||
short_refname=${refname##refs/tags/}
|
||||
if [ "$allowunannotated" != "true" ]; then
|
||||
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
||||
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,delete)
|
||||
# delete tag
|
||||
if [ "$allowdeletetag" != "true" ]; then
|
||||
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,tag)
|
||||
# annotated tag
|
||||
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
||||
then
|
||||
echo "*** Tag '$refname' already exists." >&2
|
||||
echo "*** Modifying a tag is not allowed in this repository." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,commit)
|
||||
# branch
|
||||
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,delete)
|
||||
# delete branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/remotes/*,commit)
|
||||
# tracking branch
|
||||
;;
|
||||
refs/remotes/*,delete)
|
||||
# delete tracking branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Anything else (is there anything else?)
|
||||
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Finished
|
||||
exit 0
|
|
@ -0,0 +1,6 @@
|
|||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
|
@ -0,0 +1,9 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/heads/Grüßen
|
||||
3a810dbf6b96afaa8c5f69a8b6ec1dabfca7368b refs/heads/Plus+Is+Not+Space
|
||||
3aa73c3499bff049a352b4e265575373e964b89a refs/heads/master
|
||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/heads/ГлавнаяВетка
|
||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/heads/а/б/в
|
||||
28d579e4920fbf4f66e71dab3e779d9fbf41422a refs/heads/ブランチ
|
||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/tags/Ё/人
|
||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/tags/Тэг
|
||||
28d579e4920fbf4f66e71dab3e779d9fbf41422a refs/tags/タグ
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
x•ŽAjÄ0E»ö)´œR(²ci<PJ{Å–˜)ILo_ÓM×]}xü/×u½uDO½©‚/¤ˆ6!É9K’KT¦Hœ
|
||||
—À(EæäviºuÐÙ|dK8YÎsöñìÕЗd‚¦>¢ì…œÜûµ6¸Ú¼ý·>dÝ}Íu}OñÄ)xÁ€èi]ÿ%¹ÏRàKvÙôP°Û¢Ð똛lù
|
||||
u[¾ád£§ëÑÇ£>»²´QÑ
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
x<01><>]jC!<10>ћь*цНPtFЧ+<2B>в.e4#ЎЙС<18>ьОЖ;шг<D188>УљљЪб{<7B><><EFBFBD>_цPеФ<1B>ЋOXйгцrБbк2<D0BA>+ХygЎ2є2<D194>D"ђ)<>ѕI(`і<>BiЭљМ%1r<31>чcР§Іс§O>ѕ!§Кы[9њИ@<40><>-!МZДж,wЁM§WЩ|<7C>NPлЎ№нцЪsД}o.вцёћr<>ЁUQѓ<03>M<EFBFBD>
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
3a810dbf6b96afaa8c5f69a8b6ec1dabfca7368b
|
|
@ -0,0 +1 @@
|
|||
3aa73c3499bff049a352b4e265575373e964b89a
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
28d579e4920fbf4f66e71dab3e779d9fbf41422a
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
28d579e4920fbf4f66e71dab3e779d9fbf41422a
|
|
@ -223,6 +223,22 @@ func loginUserWithPassword(t testing.TB, userName, password string) *TestSession
|
|||
return session
|
||||
}
|
||||
|
||||
func getTokenForLoggedInUser(t testing.TB, session *TestSession) string {
|
||||
req := NewRequest(t, "GET", "/user/settings/applications")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
req = NewRequestWithValues(t, "POST", "/user/settings/applications", map[string]string{
|
||||
"_csrf": doc.GetCSRF(),
|
||||
"name": "api-testing-token",
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusFound)
|
||||
req = NewRequest(t, "GET", "/user/settings/applications")
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
token := htmlDoc.doc.Find(".ui.info p").Text()
|
||||
return token
|
||||
}
|
||||
|
||||
func NewRequest(t testing.TB, method, urlStr string) *http.Request {
|
||||
return NewRequestWithBody(t, method, urlStr, nil)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testSrcRouteRedirect(t *testing.T, session *TestSession, user, repo, route, expectedLocation string, expectedStatus int) {
|
||||
prefix := path.Join("/", user, repo, "src")
|
||||
|
||||
// Make request
|
||||
req := NewRequest(t, "GET", path.Join(prefix, route))
|
||||
resp := session.MakeRequest(t, req, http.StatusFound)
|
||||
|
||||
// Check Location header
|
||||
location := resp.HeaderMap.Get("Location")
|
||||
assert.Equal(t, path.Join(prefix, expectedLocation), location)
|
||||
|
||||
// Perform redirect
|
||||
req = NewRequest(t, "GET", location)
|
||||
resp = session.MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
func setDefaultBranch(t *testing.T, session *TestSession, user, repo, branch string) {
|
||||
location := path.Join("/", user, repo, "settings/branches")
|
||||
csrf := GetCSRF(t, session, location)
|
||||
req := NewRequestWithValues(t, "POST", location, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"action": "default_branch",
|
||||
"branch": branch,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusFound)
|
||||
}
|
||||
|
||||
func TestNonasciiBranches(t *testing.T) {
|
||||
testRedirects := []struct {
|
||||
from string
|
||||
to string
|
||||
status int
|
||||
}{
|
||||
// Branches
|
||||
{
|
||||
from: "master",
|
||||
to: "branch/master",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "master/README.md",
|
||||
to: "branch/master/README.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "master/badfile",
|
||||
to: "branch/master/badfile",
|
||||
status: http.StatusNotFound, // it does not exists
|
||||
},
|
||||
{
|
||||
from: "ГлавнаяВетка",
|
||||
to: "branch/%d0%93%d0%bb%d0%b0%d0%b2%d0%bd%d0%b0%d1%8f%d0%92%d0%b5%d1%82%d0%ba%d0%b0",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "а/б/в",
|
||||
to: "branch/%d0%b0/%d0%b1/%d0%b2",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Grüßen/README.md",
|
||||
to: "branch/Gr%c3%bc%c3%9fen/README.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Plus+Is+Not+Space",
|
||||
to: "branch/Plus+Is+Not+Space",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Plus+Is+Not+Space/Файл.md",
|
||||
to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Plus+Is+Not+Space/and+it+is+valid.md",
|
||||
to: "branch/Plus+Is+Not+Space/and+it+is+valid.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "ブランチ",
|
||||
to: "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
// Tags
|
||||
{
|
||||
from: "Тэг",
|
||||
to: "tag/%d0%a2%d1%8d%d0%b3",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Ё/人",
|
||||
to: "tag/%d0%81/%e4%ba%ba",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "タグ",
|
||||
to: "tag/%e3%82%bf%e3%82%b0",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "タグ/ファイル.md",
|
||||
to: "tag/%e3%82%bf%e3%82%b0/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
// Files
|
||||
{
|
||||
from: "README.md",
|
||||
to: "branch/Plus+Is+Not+Space/README.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Файл.md",
|
||||
to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "ファイル.md",
|
||||
to: "branch/Plus+Is+Not+Space/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
|
||||
status: http.StatusNotFound, // it's not on default branch
|
||||
},
|
||||
// Same but url-encoded (few tests)
|
||||
{
|
||||
from: "%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81",
|
||||
to: "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "%E3%82%BF%E3%82%b0",
|
||||
to: "tag/%e3%82%bf%e3%82%b0",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "%D0%A4%D0%B0%D0%B9%D0%BB.md",
|
||||
to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "%D0%81%2F%E4%BA%BA",
|
||||
to: "tag/%d0%81/%e4%ba%ba",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Ё%2F%E4%BA%BA",
|
||||
to: "tag/%d0%81/%e4%ba%ba",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
prepareTestEnv(t)
|
||||
|
||||
user := "user2"
|
||||
repo := "utf8"
|
||||
session := loginUser(t, user)
|
||||
|
||||
setDefaultBranch(t, session, user, repo, "Plus+Is+Not+Space")
|
||||
|
||||
for _, test := range testRedirects {
|
||||
testSrcRouteRedirect(t, session, user, repo, test.from, test.to, test.status)
|
||||
}
|
||||
|
||||
setDefaultBranch(t, session, user, repo, "master")
|
||||
|
||||
}
|
|
@ -33,6 +33,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
|
|||
prepareTestEnv(t)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Request repository commits page
|
||||
req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
|
||||
|
@ -45,7 +46,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
|
|||
assert.NotEmpty(t, commitURL)
|
||||
|
||||
// Call API to add status for commit
|
||||
req = NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/statuses/"+path.Base(commitURL),
|
||||
req = NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/statuses/"+path.Base(commitURL)+"?token="+token,
|
||||
api.CreateStatusOption{
|
||||
State: api.StatusState(state),
|
||||
TargetURL: "http://test.ci/",
|
||||
|
|
|
@ -524,12 +524,14 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
|||
}
|
||||
|
||||
refName := git.RefEndName(opts.RefFullName)
|
||||
if repo.IsBare && refName != repo.DefaultBranch {
|
||||
|
||||
// Change default branch and bare status only if pushed ref is non-empty branch.
|
||||
if repo.IsBare && opts.NewCommitID != git.EmptySHA && strings.HasPrefix(opts.RefFullName, git.BranchPrefix) {
|
||||
repo.DefaultBranch = refName
|
||||
repo.IsBare = false
|
||||
}
|
||||
|
||||
// Change repository bare status and update last updated time.
|
||||
repo.IsBare = repo.IsBare && opts.Commits.Len <= 0
|
||||
if err = UpdateRepository(repo, false); err != nil {
|
||||
return fmt.Errorf("UpdateRepository: %v", err)
|
||||
}
|
||||
|
|
|
@ -74,3 +74,38 @@
|
|||
type: 1
|
||||
config: "{}"
|
||||
created_unix: 1524304355
|
||||
|
||||
-
|
||||
id: 12
|
||||
repo_id: 33
|
||||
type: 1
|
||||
config: "{}"
|
||||
created_unix: 1535593231
|
||||
|
||||
-
|
||||
id: 13
|
||||
repo_id: 33
|
||||
type: 2
|
||||
config: "{\"EnableTimetracker\":true,\"AllowOnlyContributorsToTrackTime\":true}"
|
||||
created_unix: 1535593231
|
||||
|
||||
-
|
||||
id: 14
|
||||
repo_id: 33
|
||||
type: 3
|
||||
config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowSquash\":true}"
|
||||
created_unix: 1535593231
|
||||
|
||||
-
|
||||
id: 15
|
||||
repo_id: 33
|
||||
type: 4
|
||||
config: "{}"
|
||||
created_unix: 1535593231
|
||||
|
||||
-
|
||||
id: 16
|
||||
repo_id: 33
|
||||
type: 5
|
||||
config: "{}"
|
||||
created_unix: 1535593231
|
|
@ -400,3 +400,10 @@
|
|||
num_forks: 0
|
||||
num_issues: 0
|
||||
is_mirror: false
|
||||
|
||||
-
|
||||
id: 33
|
||||
owner_id: 2
|
||||
lower_name: utf8
|
||||
name: utf8
|
||||
is_private: false
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
is_admin: false
|
||||
avatar: avatar2
|
||||
avatar_email: user2@example.com
|
||||
num_repos: 5
|
||||
num_repos: 6
|
||||
num_stars: 2
|
||||
num_followers: 2
|
||||
num_following: 1
|
||||
|
|
|
@ -360,7 +360,7 @@ func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error {
|
|||
|
||||
// ParseCommitWithSignature check if signature is good against keystore.
|
||||
func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
|
||||
if c.Signature != nil {
|
||||
if c.Signature != nil && c.Committer != nil {
|
||||
//Parsing signature
|
||||
sig, err := extractSignature(c.Signature.Signature)
|
||||
if err != nil { //Skipping failed to extract sign
|
||||
|
|
|
@ -73,7 +73,7 @@ func SendActivateAccountMail(c *macaron.Context, u *User) {
|
|||
|
||||
// SendResetPasswordMail sends a password reset mail to the user
|
||||
func SendResetPasswordMail(c *macaron.Context, u *User) {
|
||||
SendUserMail(c, u, mailAuthResetPassword, u.GenerateActivateCode(), c.Tr("mail.reset_password"), "reset password")
|
||||
SendUserMail(c, u, mailAuthResetPassword, u.GenerateActivateCode(), c.Tr("mail.reset_password"), "recover account")
|
||||
}
|
||||
|
||||
// SendActivateEmailMail sends confirmation email to confirm new email address
|
||||
|
|
|
@ -1852,6 +1852,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
|||
if _, err = sess.In("issue_id", issueIDs).Delete(&IssueWatch{}); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = sess.In("issue_id", issueIDs).Delete(&Stopwatch{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attachments := make([]*Attachment, 0, 5)
|
||||
if err = sess.
|
||||
|
|
|
@ -147,10 +147,10 @@ func TestSearchRepositoryByName(t *testing.T) {
|
|||
count: 14},
|
||||
{name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, AllPublic: true},
|
||||
count: 16},
|
||||
count: 17},
|
||||
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
|
||||
count: 20},
|
||||
count: 21},
|
||||
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
|
||||
opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
|
||||
count: 13},
|
||||
|
@ -159,7 +159,7 @@ func TestSearchRepositoryByName(t *testing.T) {
|
|||
count: 11},
|
||||
{name: "AllPublic/PublicRepositoriesOfOrganization",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 16},
|
||||
count: 17},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
|
|
|
@ -213,6 +213,7 @@ func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPaylo
|
|||
func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPayload, error) {
|
||||
var text, title string
|
||||
var color int
|
||||
url := fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index)
|
||||
switch p.Action {
|
||||
case api.HookIssueOpened:
|
||||
title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
|
||||
|
@ -268,7 +269,7 @@ func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPa
|
|||
{
|
||||
Title: title,
|
||||
Description: text,
|
||||
URL: p.Issue.URL,
|
||||
URL: url,
|
||||
Color: color,
|
||||
Author: DiscordEmbedAuthor{
|
||||
Name: p.Sender.UserName,
|
||||
|
|
|
@ -63,6 +63,7 @@ func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
|
|||
if err = models.UpdateAccessToken(t); err != nil {
|
||||
log.Error(4, "UpdateAccessToken: %v", err)
|
||||
}
|
||||
ctx.Data["IsApiToken"] = true
|
||||
return t.UID
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +137,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
|||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
ctx.Data["IsApiToken"] = true
|
||||
return u, true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,22 @@ func DetectEncoding(content []byte) (string, error) {
|
|||
return "UTF-8", nil
|
||||
}
|
||||
|
||||
result, err := chardet.NewTextDetector().DetectBest(content)
|
||||
textDetector := chardet.NewTextDetector()
|
||||
var detectContent []byte
|
||||
if len(content) < 1024 {
|
||||
// Check if original content is valid
|
||||
if _, err := textDetector.DetectBest(content); err != nil {
|
||||
return "", err
|
||||
}
|
||||
times := 1024 / len(content)
|
||||
detectContent = make([]byte, 0, times*len(content))
|
||||
for i := 0; i < times; i++ {
|
||||
detectContent = append(detectContent, content...)
|
||||
}
|
||||
} else {
|
||||
detectContent = content
|
||||
}
|
||||
result, err := textDetector.DetectBest(detectContent)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -620,7 +620,7 @@ func RepoRefByType(refType RepoRefType) macaron.Handler {
|
|||
// redirect from old URL scheme to new URL scheme
|
||||
ctx.Redirect(path.Join(
|
||||
setting.AppSubURL,
|
||||
strings.TrimSuffix(ctx.Req.URL.String(), ctx.Params("*")),
|
||||
strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*")),
|
||||
ctx.Repo.BranchNameSubURL(),
|
||||
ctx.Repo.TreePath))
|
||||
return
|
||||
|
|
|
@ -1116,7 +1116,7 @@ func NewContext() {
|
|||
|
||||
extensionReg := regexp.MustCompile(`\.\w`)
|
||||
for _, sec := range Cfg.Section("markup").ChildSections() {
|
||||
name := strings.TrimLeft(sec.Name(), "markup.")
|
||||
name := strings.TrimPrefix(sec.Name(), "markup.")
|
||||
if name == "" {
|
||||
log.Warn("name is empty, markup " + sec.Name() + "ignored")
|
||||
continue
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// 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.
|
||||
|
@ -246,7 +247,7 @@ func ToUTF8WithErr(content []byte) (string, error) {
|
|||
}
|
||||
|
||||
// If there is an error, we concatenate the nicely decoded part and the
|
||||
// original left over. This way we won't loose data.
|
||||
// original left over. This way we won't lose data.
|
||||
result, n, err := transform.String(encoding.NewDecoder(), string(content))
|
||||
if err != nil {
|
||||
result = result + string(content[n:])
|
||||
|
@ -255,6 +256,28 @@ func ToUTF8WithErr(content []byte) (string, error) {
|
|||
return result, err
|
||||
}
|
||||
|
||||
// ToUTF8WithFallback detects the encoding of content and coverts to UTF-8 if possible
|
||||
func ToUTF8WithFallback(content []byte) []byte {
|
||||
charsetLabel, err := base.DetectEncoding(content)
|
||||
if err != nil || charsetLabel == "UTF-8" {
|
||||
return content
|
||||
}
|
||||
|
||||
encoding, _ := charset.Lookup(charsetLabel)
|
||||
if encoding == nil {
|
||||
return content
|
||||
}
|
||||
|
||||
// If there is an error, we concatenate the nicely decoded part and the
|
||||
// original left over. This way we won't lose data.
|
||||
result, n, err := transform.Bytes(encoding.NewDecoder(), content)
|
||||
if err != nil {
|
||||
return append(result, content[n:]...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ToUTF8 converts content to UTF8 encoding and ignore error
|
||||
func ToUTF8(content string) string {
|
||||
res, _ := ToUTF8WithErr([]byte(content))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
app_desc = A painless, self-hosted Git service
|
||||
app_desc = All Neo-Luddites and Lv. 99 Code Whisperers Welcome
|
||||
|
||||
home = Home
|
||||
dashboard = Dashboard
|
||||
|
@ -200,18 +200,19 @@ forgot_password_title= Forgot Password
|
|||
forgot_password = Forgot password?
|
||||
sign_up_now = Need an account? Register now.
|
||||
confirmation_mail_sent_prompt = A new confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the registration process.
|
||||
reset_password_mail_sent_prompt = A confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the password reset process.
|
||||
reset_password_mail_sent_prompt = A confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the account recovery process.
|
||||
active_your_account = Activate Your Account
|
||||
prohibit_login = Sign In Prohibited
|
||||
prohibit_login_desc = Your account is prohibited to sign in, please contact your site administrator.
|
||||
resent_limit_prompt = You have already requested an activation email recently. Please wait 3 minutes and try again.
|
||||
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (<b>%s</b>). If you haven't received a confirmation email or need to resend a new one, please click on the button below.
|
||||
resend_mail = Click here to resend your activation email
|
||||
resend_mail = Resend Activation Email
|
||||
email_not_associate = The email address is not associated with any account.
|
||||
send_reset_mail = Click here to resend your password reset email
|
||||
reset_password = Reset Your Password
|
||||
send_reset_mail = Send Account Recovery Email
|
||||
reset_password = Account Recovery
|
||||
invalid_code = Your confirmation code is invalid or has expired.
|
||||
reset_password_helper = Click here to reset your password
|
||||
reset_password_helper = Recover Account
|
||||
reset_password_wrong_user = You are signed in as %s, but the account recovery link is for %s
|
||||
password_too_short = Password length cannot be less than %d characters.
|
||||
non_local_account = Non-local users can not update their password through the Gitea web interface.
|
||||
verify = Verify
|
||||
|
@ -234,12 +235,12 @@ openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new
|
|||
openid_register_title = Create new account
|
||||
openid_register_desc = The chosen OpenID URI is unknown. Associate it with a new account here.
|
||||
openid_signin_desc = Enter your OpenID URI. For example: https://anne.me, bob.openid.org.cn or gnusocial.net/carry.
|
||||
disable_forgot_password_mail = Password reset is disabled. Please contact your site administrator.
|
||||
disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator.
|
||||
|
||||
[mail]
|
||||
activate_account = Please activate your account
|
||||
activate_email = Verify your email address
|
||||
reset_password = Reset your password
|
||||
reset_password = Recover your account
|
||||
register_success = Registration successful
|
||||
register_notify = Welcome to Gitea
|
||||
|
||||
|
@ -1497,7 +1498,7 @@ config.mail_notify = Enable Email Notifications
|
|||
config.disable_key_size_check = Disable Minimum Key Size Check
|
||||
config.enable_captcha = Enable CAPTCHA
|
||||
config.active_code_lives = Active Code Lives
|
||||
config.reset_password_code_lives = Reset Password Code Expiry Time
|
||||
config.reset_password_code_lives = Recover Account Code Expiry Time
|
||||
config.default_keep_email_private = Hide Email Addresses by Default
|
||||
config.default_allow_create_organization = Allow Creation of Organizations by Default
|
||||
config.enable_timetracking = Enable Time Tracking
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2309,7 +2309,7 @@ function initTopicbar() {
|
|||
|
||||
mgrBtn.click(function() {
|
||||
viewDiv.hide();
|
||||
editDiv.show();
|
||||
editDiv.css('display', ''); // show Semantic UI Grid
|
||||
})
|
||||
|
||||
saveBtn.click(function() {
|
||||
|
@ -2334,7 +2334,7 @@ function initTopicbar() {
|
|||
}
|
||||
}
|
||||
}).done(function() {
|
||||
editDiv.hide();
|
||||
editDiv.css('display', 'none'); // hide Semantic UI Grid
|
||||
viewDiv.show();
|
||||
}).fail(function(xhr) {
|
||||
alert(xhr.responseJSON.message)
|
||||
|
|
|
@ -9,6 +9,9 @@ body {
|
|||
img {
|
||||
border-radius: 3px;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.rounded {
|
||||
border-radius: .28571429rem !important;
|
||||
}
|
||||
|
|
|
@ -1743,7 +1743,6 @@ tbody.commit-list {
|
|||
|
||||
#topic_edit {
|
||||
margin-top:5px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#repo-topic {
|
||||
|
|
|
@ -132,7 +132,7 @@ func repoAssignment() macaron.Handler {
|
|||
// Contexter middleware already checks token for user sign in process.
|
||||
func reqToken() macaron.Handler {
|
||||
return func(ctx *context.Context) {
|
||||
if !ctx.IsSigned {
|
||||
if true != ctx.Data["IsApiToken"] {
|
||||
ctx.Error(401)
|
||||
return
|
||||
}
|
||||
|
@ -273,6 +273,14 @@ func mustAllowPulls(ctx *context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
func mustEnableIssuesOrPulls(ctx *context.Context) {
|
||||
if !ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues) &&
|
||||
!ctx.Repo.Repository.AllowsPulls() {
|
||||
ctx.Status(404)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterRoutes registers all v1 APIs routes to web application.
|
||||
// FIXME: custom form error response
|
||||
func RegisterRoutes(m *macaron.Macaron) {
|
||||
|
@ -447,7 +455,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
Post(reqToken(), bind(api.AddTimeOption{}), repo.AddTime)
|
||||
})
|
||||
})
|
||||
}, mustEnableIssues)
|
||||
}, mustEnableIssuesOrPulls)
|
||||
m.Group("/labels", func() {
|
||||
m.Combo("").Get(repo.ListLabels).
|
||||
Post(reqToken(), bind(api.CreateLabelOption{}), repo.CreateLabel)
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
|
||||
"github.com/Unknwon/paginater"
|
||||
)
|
||||
|
||||
|
@ -99,7 +100,8 @@ func renderDirectory(ctx *context.Context, treeLink string) {
|
|||
ctx.Data["FileSize"] = readmeFile.Size()
|
||||
} else {
|
||||
d, _ := ioutil.ReadAll(dataRc)
|
||||
buf = append(buf, d...)
|
||||
buf = templates.ToUTF8WithFallback(append(buf, d...))
|
||||
|
||||
if markup.Type(readmeFile.Name()) != "" {
|
||||
ctx.Data["IsMarkup"] = true
|
||||
ctx.Data["FileContent"] = string(markup.Render(readmeFile.Name(), buf, treeLink, ctx.Repo.Repository.ComposeMetas()))
|
||||
|
@ -201,7 +203,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
|||
}
|
||||
|
||||
d, _ := ioutil.ReadAll(dataRc)
|
||||
buf = append(buf, d...)
|
||||
buf = templates.ToUTF8WithFallback(append(buf, d...))
|
||||
|
||||
readmeExist := markup.IsReadmeFile(blob.Name())
|
||||
ctx.Data["ReadmeExist"] = readmeExist
|
||||
|
|
|
@ -184,10 +184,6 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues)
|
||||
|
||||
// ***** START: User *****
|
||||
m.Group("/user", func() {
|
||||
m.Get("/reset_password", user.ResetPasswd)
|
||||
m.Post("/reset_password", user.ResetPasswdPost)
|
||||
})
|
||||
m.Group("/user", func() {
|
||||
m.Get("/login", user.SignIn)
|
||||
m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost)
|
||||
|
@ -295,6 +291,8 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
m.Any("/activate", user.Activate)
|
||||
m.Any("/activate_email", user.ActivateEmail)
|
||||
m.Get("/email2user", user.Email2User)
|
||||
m.Get("/recover_account", user.ResetPasswd)
|
||||
m.Post("/recover_account", user.ResetPasswdPost)
|
||||
m.Get("/forgot_password", user.ForgotPasswd)
|
||||
m.Post("/forgot_password", user.ForgotPasswdPost)
|
||||
m.Get("/logout", user.SignOut)
|
||||
|
|
|
@ -1144,70 +1144,85 @@ func ForgotPasswdPost(ctx *context.Context) {
|
|||
ctx.HTML(200, tplForgotPassword)
|
||||
}
|
||||
|
||||
// ResetPasswd render the reset password page
|
||||
// Keep consistent behavior between phases of account recovery
|
||||
func commonResetPassword(ctx *context.Context) *models.User {
|
||||
code := ctx.Query("code")
|
||||
|
||||
ctx.Data["Title"] = ctx.Tr("auth.reset_password")
|
||||
ctx.Data["Code"] = code
|
||||
|
||||
if nil != ctx.User {
|
||||
ctx.Data["user_signed_in"] = true
|
||||
}
|
||||
|
||||
if len(code) == 0 {
|
||||
ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fail early, don't frustrate the user
|
||||
u := models.VerifyUserActiveCode(code)
|
||||
if u == nil {
|
||||
ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Show the user that they are affecting the account that they intended to
|
||||
ctx.Data["user_email"] = u.Email
|
||||
|
||||
if nil != ctx.User && u.ID != ctx.User.ID {
|
||||
ctx.Flash.Error(ctx.Tr("auth.reset_password_wrong_user", ctx.User.Email, u.Email))
|
||||
return nil
|
||||
}
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// ResetPasswd render the account recovery page
|
||||
func ResetPasswd(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.reset_password")
|
||||
|
||||
// TODO for security and convenience, show the username / email here
|
||||
|
||||
code := ctx.Query("code")
|
||||
if len(code) == 0 {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
ctx.Data["Code"] = code
|
||||
ctx.Data["IsResetForm"] = true
|
||||
|
||||
_ = commonResetPassword(ctx)
|
||||
|
||||
ctx.HTML(200, tplResetPassword)
|
||||
}
|
||||
|
||||
// ResetPasswdPost response from reset password request
|
||||
// ResetPasswdPost response from account recovery request
|
||||
func ResetPasswdPost(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.reset_password")
|
||||
|
||||
code := ctx.Query("code")
|
||||
if len(code) == 0 {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
ctx.Data["Code"] = code
|
||||
|
||||
if u := models.VerifyUserActiveCode(code); u != nil {
|
||||
// Validate password length.
|
||||
passwd := ctx.Query("password")
|
||||
if len(passwd) < setting.MinPasswordLength {
|
||||
ctx.Data["IsResetForm"] = true
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplResetPassword, nil)
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
if u.Rands, err = models.GetUserSalt(); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
if u.Salt, err = models.GetUserSalt(); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Just in case the user is signed in to another account
|
||||
handleSignOut(ctx)
|
||||
|
||||
u.HashPassword(passwd)
|
||||
if err := models.UpdateUserCols(u, "passwd", "rands", "salt"); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("User password reset: %s", u.Name)
|
||||
|
||||
// TODO change the former form to have password retype and remember me,
|
||||
// then sign in here instead of redirecting
|
||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
||||
u := commonResetPassword(ctx)
|
||||
if nil == u {
|
||||
// Flash Error has been set
|
||||
ctx.HTML(200, tplResetPassword)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsResetFailed"] = true
|
||||
ctx.HTML(200, tplResetPassword)
|
||||
// Validate password length.
|
||||
passwd := ctx.Query("password")
|
||||
if len(passwd) < setting.MinPasswordLength {
|
||||
ctx.Data["IsResetForm"] = true
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplResetPassword, nil)
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
if u.Rands, err = models.GetUserSalt(); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
if u.Salt, err = models.GetUserSalt(); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
|
||||
u.HashPassword(passwd)
|
||||
if err := models.UpdateUserCols(u, "passwd", "rands", "salt"); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("User password reset: %s", u.Name)
|
||||
|
||||
remember := len(ctx.Query("remember")) != 0
|
||||
handleSignInFull(ctx, u, remember, true)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
<footer>
|
||||
<div class="ui container">
|
||||
<div class="ui left">
|
||||
© Gitea {{if (or .ShowFooterVersion .PageIsAdmin)}}{{.i18n.Tr "version"}}: {{AppVer}}{{end}} {{if ShowFooterTemplateLoadTime}}{{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong> {{.i18n.Tr "template"}}: <strong>{{call .TmplLoadTimes}}</strong>{{end}}
|
||||
© AJ ONeal, founder of <a target="_blank" href="https://ppl.family">ppl</a>.
|
||||
Automated HTTPS via <a href="https://git.coolaj86.com/coolaj86/greenlock-express.js" target="_blank">Greenlock.js</a> and <a href="https://git.coolaj86.com/coolaj86/acme-v2.js" target="_blank">Let's Encrypt</a>
|
||||
</div>
|
||||
<div class="ui right links">
|
||||
{{if .ShowFooterBranding}}
|
||||
|
@ -28,10 +29,12 @@
|
|||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<a href="{{AppSubUrl}}/vendor/librejs.html" data-jslicense="1">JavaScript licenses</a>
|
||||
{{if .EnableSwaggerEndpoint}}<a href="{{AppSubUrl}}/api/swagger">API</a>{{end}}
|
||||
<a target="_blank" rel="noopener" href="https://gitea.io">{{.i18n.Tr "website"}}</a>
|
||||
{{if (or .ShowFooterVersion .PageIsAdmin)}}<span class="version">{{GoVer}}</span>{{end}}
|
||||
| Powered by <a target="_blank" rel="noopener" href="https://gitea.io">Gitea</a> {{if (or .ShowFooterVersion .PageIsAdmin)}}: v{{AppVer}}{{end}}
|
||||
| {{if (or .ShowFooterVersion .PageIsAdmin)}}<span class="version">{{GoVer}}</span>{{end}}
|
||||
<!--
|
||||
| {{if ShowFooterTemplateLoadTime}}{{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong>
|
||||
{{.i18n.Tr "template"}}: <strong>{{call .TmplLoadTimes}}</strong>{{end}} -->
|
||||
| <a href="{{AppSubUrl}}/api/swagger">API</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
|
|
@ -7,348 +7,57 @@
|
|||
</div>
|
||||
<div class="hero">
|
||||
<h1 class="ui icon header title">
|
||||
Gitea - Git with a cup of tea
|
||||
Let's Code, Decentralized!
|
||||
</h1>
|
||||
<h2>{{.i18n.Tr "app_desc"}}</h2>
|
||||
<h2>Login with GitHub or
|
||||
<br>Register a new account to contribute.</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{if eq .Lang "de-DE"}}
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-flame"></i> Einfach zu installieren
|
||||
</h1>
|
||||
<p class="large">
|
||||
Starte einfach <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">die Anwendung</a> für deine Plattform. Gitea gibt es auch für <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>, <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a> oder als <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">Installationspaket</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-device-desktop"></i> Plattformübergreifend
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea läuft überall. <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> kompiliert für: Windows, macOS, Linux, ARM, etc. Wähle dasjenige System, was dir am meisten gefällt!
|
||||
</p>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-git-branch"></i> Hurrah for Gitea!
|
||||
</h1>
|
||||
<p class="large">
|
||||
I'm using Gitea, which is likely to become the first decentralized git platform.
|
||||
Help support decentralization by <a target="_blank"
|
||||
href="https://git.coolaj86.com/coolaj86/gitea-installer.sh">installing gitea</a>
|
||||
for yourself!
|
||||
</p>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-rocket"></i> Leichtgewicht
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea hat minimale Systemanforderungen und kann selbst auf einem günstigen und stromsparenden Raspberry Pi betrieben werden.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> Quelloffen
|
||||
</h1>
|
||||
<p class="large">
|
||||
Der komplette Code befindet sich auf <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Unterstütze uns bei der Verbesserung dieses Projekts. Trau dich!
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-circuit-board"></i> Hurrah for RPi!
|
||||
</h1>
|
||||
<p class="large">
|
||||
Home servers are the only thing that can save us from our centralized overlords.
|
||||
Gitea can run on a Raspberry Pi.
|
||||
</p>
|
||||
</div>
|
||||
{{else if eq .Lang "zh-TW"}}
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-flame"></i> 易安裝
|
||||
</h1>
|
||||
<p class="large">
|
||||
直接用 <a target="_blank" rel="noopener" href="https://docs.gitea.io/zh-cn/install-from-binary/">執行檔安裝</a>,還可以透過 <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> 或 <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>,以及 <a target="_blank" rel="noopener" href="https://docs.gitea.io/zh-cn/install-from-package/">套件</a>安装。
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-device-desktop"></i> 跨平台
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea 可以運作在任何 <a target="_blank" rel="noopener" href="http://golang.org/">Go 語言</a>能夠編譯的平台: Windows, macOS, Linux, ARM 等等。挑一個您喜歡的就好。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-mail"></i> For Neo-Luddites
|
||||
</h1>
|
||||
<p class="large">
|
||||
Email was the web's first decentralized and distributed protocol.
|
||||
It may be old news, but its paradigms are the best hope for our futures.
|
||||
If we don't take back the web soon then GitHub, Facebook, Slack, Medium,
|
||||
etc will dictate our futures for us.
|
||||
</p>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-rocket"></i> 輕量級
|
||||
</h1>
|
||||
<p class="large">
|
||||
一個便宜的樹莓派 Raspberry Pi 就可以滿足 Gitea 的最低系統需求,節省機器資源!
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> 開源化
|
||||
</h1>
|
||||
<p class="large">
|
||||
所有程式碼都在 <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a> 上,加入我們讓 Gitea 更好,別害羞,你可以做到的。
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> Lv. 99 Code Whisperers Welcome
|
||||
</h1>
|
||||
<p class="large">
|
||||
If you love code more than build tools, we'll make fast friends. :)
|
||||
</p>
|
||||
</div>
|
||||
{{else if eq .Lang "zh-CN"}}
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-flame"></i> 易安装
|
||||
</h1>
|
||||
<p class="large">
|
||||
您除了可以根据操作系统平台通过 <a target="_blank" rel="noopener" href="https://docs.gitea.io/zh-cn/install-from-binary/">二进制运行</a>,还可以通过 <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> 或 <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>,以及 <a target="_blank" rel="noopener" href="https://docs.gitea.io/zh-cn/install-from-package/">包管理</a> 安装。
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-device-desktop"></i> 跨平台
|
||||
</h1>
|
||||
<p class="large">
|
||||
任何 <a target="_blank" rel="noopener" href="http://golang.org/">Go 语言</a> 支持的平台都可以运行 Gitea,包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-rocket"></i> 轻量级
|
||||
</h1>
|
||||
<p class="large">
|
||||
一个廉价的树莓派的配置足以满足 Gitea 的最低系统硬件要求。最大程度上节省您的服务器资源!
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> 开源化
|
||||
</h1>
|
||||
<p class="large">
|
||||
所有的代码都开源在 <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a> 上,赶快加入我们来共同发展这个伟大的项目!还等什么?成为贡献者吧!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{else if eq .Lang "fr-FR"}}
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-flame"></i> Facile à installer
|
||||
</h1>
|
||||
<p class="large">
|
||||
Il suffit de <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">lancer l'exécutable</a> correspondant à votre système.
|
||||
Ou d'utiliser Gitea avec <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> ou
|
||||
<a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>
|
||||
ou en l'installant depuis un <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">package</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-device-desktop"></i> Multi-plateforme
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea tourne partout où <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> peut être compilé : Windows, macOS, Linux, ARM, etc. Choisissez votre préféré !
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-rocket"></i> Léger
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea utilise peu de ressources. Il peut même tourner sur un Raspberry Pi très bon marché. Économisez l'énergie de vos serveurs !
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> Open Source
|
||||
</h1>
|
||||
<p class="large">
|
||||
Toutes les sources sont sur <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a> ! Rejoignez-nous et contribuez à rendre ce projet encore meilleur.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{else if eq .Lang "es-ES"}}
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-flame"></i> Fácil de instalar
|
||||
</h1>
|
||||
<p class="large">
|
||||
Simplemente <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">arranca el binario</a> para tu plataforma. O usa Gitea con <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> o <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, o utilice el <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">paquete</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-device-desktop"></i> Multiplatforma
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea funciona en cualquier parte, <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> puede compilarse en: Windows, macOS, Linux, ARM, etc. !Elige tu favorita!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-rocket"></i> Ligero
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea tiene pocos requisitos y puede funcionar en una Raspberry Pi barata. !Ahorra energía!
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> Open Source
|
||||
</h1>
|
||||
<p class="large">
|
||||
¡Está todo en <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Uniros contribuyendo a hacer este proyecto todavía mejor. ¡No seas tímido y colabora!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{else if eq .Lang "pt-BR"}}
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-flame"></i> Fácil de instalar
|
||||
</h1>
|
||||
<p class="large">
|
||||
Simplesmente <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">rode o executável</a> para o seu sistema operacional. Ou obtenha o Gitea com o <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> ou <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, ou baixe o <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">pacote</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-device-desktop"></i> Multi-plataforma
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea roda em qualquer sistema operacional em que <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> consegue compilar: Windows, macOS, Linux, ARM, etc. Escolha qual você gosta mais!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-rocket"></i> Leve e rápido
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea utiliza poucos recursos e consegue mesmo rodar no barato Raspberry Pi. Economize energia elétrica da sua máquina!
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> Código aberto
|
||||
</h1>
|
||||
<p class="large">
|
||||
Está tudo no <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Contribua e torne este projeto ainda melhor. Não tenha vergonha de contribuir!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{else if eq .Lang "ru-RU"}}
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-flame"></i> Простой в установке
|
||||
</h1>
|
||||
<p class="large">
|
||||
Просто <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">запустите исполняемый файл</a> для вашей платформы. Изпользуйте Gitea с <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> или <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, или загрузите <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">пакет</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-device-desktop"></i> Кроссплатформенный
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea работает на любой операционной системе, которая может компилировать <a target="_blank" rel="noopener" href="http://golang.org/">Go</a>: Windows, macOS, Linux, ARM и т. д. Выбирайте, что вам больше нравится!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-rocket"></i> Легковесный
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea имеет низкие системные требования и может работать на недорогом Raspberry Pi. Экономьте энергию вашей машины!
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> Открытый исходный код
|
||||
</h1>
|
||||
<p class="large">
|
||||
Всё это на <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Присоединяйтесь к нам, внося вклад, чтобы сделать этот проект еще лучше. Не бойтесь помогать!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{else if eq .Lang "nl-NL"}}
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-flame"></i> Makkelijk te installeren
|
||||
</h1>
|
||||
<p class="large">
|
||||
Je hoeft alleen maar de <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">binary</a> uit te voeren. Of gebruik Gitea met <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>, <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, of download een <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">installatiepakket</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-device-desktop"></i> Cross-platform
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea werkt op alles waar <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> op kan compileren: Windows, macOS, Linux, ARM, etc. Kies het platform dat bij je past!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-rocket"></i> Lichtgewicht
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea heeft hele lage systeemeisen, je kunt Gitea al draaien op een goedkope Raspberry Pi.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> Open Source
|
||||
</h1>
|
||||
<p class="large">
|
||||
Alles staat op <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Help ons door mee te bouwen aan Gitea, samen maken we dit project nog beter. Aarzel dus niet om een bijdrage te leveren!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-flame"></i> Easy to install
|
||||
</h1>
|
||||
<p class="large">
|
||||
Simply <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">run the binary</a> for your platform. Or ship Gitea with <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> or <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, or get it <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">packaged</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-device-desktop"></i> Cross-platform
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea runs anywhere <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> can compile for: Windows, macOS, Linux, ARM, etc. Choose the one you love!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-rocket"></i> Lightweight
|
||||
</h1>
|
||||
<p class="large">
|
||||
Gitea has low minimal requirements and can run on an inexpensive Raspberry Pi. Save your machine energy!
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
<i class="octicon octicon-code"></i> Open Source
|
||||
</h1>
|
||||
<p class="large">
|
||||
It's all on <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Join us by contributing to make this project even better. Don't be shy to be a contributor!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<!-- should have one more of the above -->
|
||||
</div>
|
||||
<!-- the above may be repeated -->
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<p>Hi <b>{{.Username}}</b>, this is your registration confirmation email for {{AppName}}!</p>
|
||||
<p>You can now login via username: {{.Username}}.</p>
|
||||
<p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p>
|
||||
<p>If this account has been created for you, please <a href="{{AppUrl}}user/forgot_password">reset your password</a> first.</p>
|
||||
<p>If this account has been created for you, please <a href="{{AppUrl}}user/forgot_password">set your password</a> first.</p>
|
||||
<p>© <a target="_blank" rel="noopener" href="{{AppUrl}}">{{AppName}}</a></p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>{{.Username}}, you have requested to reset your password</title>
|
||||
<title>{{.Username}}, you have requested to recover your account</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Hi <b>{{.Username}}</b>,</p>
|
||||
<p>Please click the following link to reset your password within <b>{{.ResetPwdCodeLives}}</b>:</p>
|
||||
<p><a href="{{AppUrl}}user/reset_password?code={{.Code}}">{{AppUrl}}user/reset_password?code={{.Code}}</a></p>
|
||||
<p>Please click the following link to recover your account within <b>{{.ResetPwdCodeLives}}</b>:</p>
|
||||
<p><a href="{{AppUrl}}user/recover_account?code={{.Code}}">{{AppUrl}}user/recover_account?code={{.Code}}</a></p>
|
||||
<p>Not working? Try copying and pasting it to your browser.</p>
|
||||
<p>© <a target="_blank" rel="noopener" href="{{AppUrl}}">{{AppName}}</a></p>
|
||||
</body>
|
||||
|
|
|
@ -28,17 +28,17 @@
|
|||
{{if .IsRepositoryAdmin}}<a id="manage_topic" style="cursor:pointer;margin-left:10px;">{{.i18n.Tr "repo.topic.manage_topics"}}</a>{{end}}
|
||||
</div>
|
||||
{{if .IsRepositoryAdmin}}
|
||||
<div class="ui repo-topic-edit grid" id="topic_edit" >
|
||||
<div class="ui repo-topic-edit grid" id="topic_edit" style="display:none">
|
||||
<div class="fourteen wide column">
|
||||
<div class="ui fluid multiple search selection dropdown">
|
||||
<input type="hidden" name="topics" value="{{range $i, $v := .Topics}}{{.Name}}{{if lt (Add $i 1) (len $.Topics)}},{{end}}{{end}}">
|
||||
{{range .Topics}}
|
||||
<a class="ui green basic label topic transition visible" data-value="{{.Name}}" style="display: inline-block !important;">{{.Name}}<i class="delete icon"></i></a>
|
||||
<div class="ui green basic label topic transition visible" data-value="{{.Name}}" style="display: inline-block !important; cursor: default;">{{.Name}}<i class="delete icon"></i></div>
|
||||
{{end}}
|
||||
<div class="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="one wide column">
|
||||
<div class="two wide column">
|
||||
<a class="ui compact button primary" href="javascript:;" id="save_topic"
|
||||
data-link="{{.RepoLink}}/topics">{{.i18n.Tr "repo.topic.done"}}</a>
|
||||
</div>
|
||||
|
|
|
@ -10,11 +10,26 @@
|
|||
</h2>
|
||||
<div class="ui attached segment">
|
||||
{{template "base/alert" .}}
|
||||
{{if .user_email }}
|
||||
<div class="inline field">
|
||||
<label for="user_name">{{.i18n.Tr "email"}}</label>
|
||||
<input id="user_name" type="text" value="{{ .user_email }}" disabled>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .IsResetForm}}
|
||||
<div class="required inline field {{if .Err_Password}}error{{end}}">
|
||||
<label for="password">{{.i18n.Tr "password"}}</label>
|
||||
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" autofocus required>
|
||||
</div>
|
||||
{{if not .user_signed_in}}
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
<div class="ui checkbox">
|
||||
<label>{{.i18n.Tr "auth.remember_me"}}</label>
|
||||
<input name="remember" type="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="ui divider"></div>
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
|
|
Loading…
Reference in New Issue