mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-27 14:13:52 +03:00
Remove dependent on session auth for api/v1 routers (#19321)
* Remove dependent on session auth for api/v1 routers * Remove unnecessary session on API context * remove missed header * fix test * fix missed api/v1
This commit is contained in:
parent
75f8534c3a
commit
3c3d49899f
22 changed files with 219 additions and 161 deletions
|
@ -168,12 +168,11 @@ func TestAPIEditIssue(t *testing.T) {
|
||||||
func TestAPISearchIssues(t *testing.T) {
|
func TestAPISearchIssues(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
session := loginUser(t, "user2")
|
token := getUserToken(t, "user2")
|
||||||
token := getTokenForLoggedInUser(t, session)
|
|
||||||
|
|
||||||
link, _ := url.Parse("/api/v1/repos/issues/search")
|
link, _ := url.Parse("/api/v1/repos/issues/search")
|
||||||
req := NewRequest(t, "GET", link.String())
|
req := NewRequest(t, "GET", link.String()+"?token="+token)
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
var apiIssues []*api.Issue
|
var apiIssues []*api.Issue
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 10)
|
assert.Len(t, apiIssues, 10)
|
||||||
|
@ -181,7 +180,7 @@ func TestAPISearchIssues(t *testing.T) {
|
||||||
query := url.Values{"token": {token}}
|
query := url.Values{"token": {token}}
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 10)
|
assert.Len(t, apiIssues, 10)
|
||||||
|
|
||||||
|
@ -189,9 +188,10 @@ func TestAPISearchIssues(t *testing.T) {
|
||||||
before := time.Unix(999307200, 0).Format(time.RFC3339)
|
before := time.Unix(999307200, 0).Format(time.RFC3339)
|
||||||
query.Add("since", since)
|
query.Add("since", since)
|
||||||
query.Add("before", before)
|
query.Add("before", before)
|
||||||
|
query.Add("token", token)
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 8)
|
assert.Len(t, apiIssues, 8)
|
||||||
query.Del("since")
|
query.Del("since")
|
||||||
|
@ -200,14 +200,14 @@ func TestAPISearchIssues(t *testing.T) {
|
||||||
query.Add("state", "closed")
|
query.Add("state", "closed")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
|
|
||||||
query.Set("state", "all")
|
query.Set("state", "all")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.EqualValues(t, "15", resp.Header().Get("X-Total-Count"))
|
assert.EqualValues(t, "15", resp.Header().Get("X-Total-Count"))
|
||||||
assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit
|
assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit
|
||||||
|
@ -215,49 +215,49 @@ func TestAPISearchIssues(t *testing.T) {
|
||||||
query.Add("limit", "20")
|
query.Add("limit", "20")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 15)
|
assert.Len(t, apiIssues, 15)
|
||||||
|
|
||||||
query = url.Values{"assigned": {"true"}, "state": {"all"}}
|
query = url.Values{"assigned": {"true"}, "state": {"all"}, "token": {token}}
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 1)
|
assert.Len(t, apiIssues, 1)
|
||||||
|
|
||||||
query = url.Values{"milestones": {"milestone1"}, "state": {"all"}}
|
query = url.Values{"milestones": {"milestone1"}, "state": {"all"}, "token": {token}}
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 1)
|
assert.Len(t, apiIssues, 1)
|
||||||
|
|
||||||
query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}}
|
query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}, "token": {token}}
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
|
|
||||||
query = url.Values{"owner": {"user2"}} // user
|
query = url.Values{"owner": {"user2"}, "token": {token}} // user
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 6)
|
assert.Len(t, apiIssues, 6)
|
||||||
|
|
||||||
query = url.Values{"owner": {"user3"}} // organization
|
query = url.Values{"owner": {"user3"}, "token": {token}} // organization
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 3)
|
assert.Len(t, apiIssues, 3)
|
||||||
|
|
||||||
query = url.Values{"owner": {"user3"}, "team": {"team1"}} // organization + team
|
query = url.Values{"owner": {"user3"}, "team": {"team1"}, "token": {token}} // organization + team
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
}
|
}
|
||||||
|
@ -265,12 +265,11 @@ func TestAPISearchIssues(t *testing.T) {
|
||||||
func TestAPISearchIssuesWithLabels(t *testing.T) {
|
func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
token := getUserToken(t, "user1")
|
||||||
token := getTokenForLoggedInUser(t, session)
|
|
||||||
|
|
||||||
link, _ := url.Parse("/api/v1/repos/issues/search")
|
link, _ := url.Parse("/api/v1/repos/issues/search")
|
||||||
req := NewRequest(t, "GET", link.String())
|
req := NewRequest(t, "GET", link.String()+"?token="+token)
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
var apiIssues []*api.Issue
|
var apiIssues []*api.Issue
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
|
|
||||||
|
@ -280,14 +279,14 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||||
query.Add("token", token)
|
query.Add("token", token)
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 10)
|
assert.Len(t, apiIssues, 10)
|
||||||
|
|
||||||
query.Add("labels", "label1")
|
query.Add("labels", "label1")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
|
|
||||||
|
@ -295,7 +294,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||||
query.Set("labels", "label1,label2")
|
query.Set("labels", "label1,label2")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
|
|
||||||
|
@ -303,7 +302,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||||
query.Set("labels", "orglabel4")
|
query.Set("labels", "orglabel4")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 1)
|
assert.Len(t, apiIssues, 1)
|
||||||
|
|
||||||
|
@ -312,7 +311,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||||
query.Add("state", "all")
|
query.Add("state", "all")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
|
|
||||||
|
@ -320,7 +319,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||||
query.Set("labels", "label1,orglabel4")
|
query.Set("labels", "label1,orglabel4")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,8 @@ import (
|
||||||
|
|
||||||
func TestAPIOrgCreate(t *testing.T) {
|
func TestAPIOrgCreate(t *testing.T) {
|
||||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
token := getUserToken(t, "user1")
|
||||||
|
|
||||||
token := getTokenForLoggedInUser(t, session)
|
|
||||||
org := api.CreateOrgOption{
|
org := api.CreateOrgOption{
|
||||||
UserName: "user1_org",
|
UserName: "user1_org",
|
||||||
FullName: "User1's organization",
|
FullName: "User1's organization",
|
||||||
|
@ -32,7 +31,7 @@ func TestAPIOrgCreate(t *testing.T) {
|
||||||
Visibility: "limited",
|
Visibility: "limited",
|
||||||
}
|
}
|
||||||
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs?token="+token, &org)
|
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs?token="+token, &org)
|
||||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
resp := MakeRequest(t, req, http.StatusCreated)
|
||||||
|
|
||||||
var apiOrg api.Organization
|
var apiOrg api.Organization
|
||||||
DecodeJSON(t, resp, &apiOrg)
|
DecodeJSON(t, resp, &apiOrg)
|
||||||
|
@ -50,13 +49,13 @@ func TestAPIOrgCreate(t *testing.T) {
|
||||||
FullName: org.FullName,
|
FullName: org.FullName,
|
||||||
})
|
})
|
||||||
|
|
||||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s", org.UserName)
|
req = NewRequestf(t, "GET", "/api/v1/orgs/%s?token=%s", org.UserName, token)
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiOrg)
|
DecodeJSON(t, resp, &apiOrg)
|
||||||
assert.EqualValues(t, org.UserName, apiOrg.UserName)
|
assert.EqualValues(t, org.UserName, apiOrg.UserName)
|
||||||
|
|
||||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", org.UserName)
|
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token=%s", org.UserName, token)
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
var repos []*api.Repository
|
var repos []*api.Repository
|
||||||
DecodeJSON(t, resp, &repos)
|
DecodeJSON(t, resp, &repos)
|
||||||
|
@ -64,8 +63,8 @@ func TestAPIOrgCreate(t *testing.T) {
|
||||||
assert.False(t, repo.Private)
|
assert.False(t, repo.Private)
|
||||||
}
|
}
|
||||||
|
|
||||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", org.UserName)
|
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members?token=%s", org.UserName, token)
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
// user1 on this org is public
|
// user1 on this org is public
|
||||||
var users []*api.User
|
var users []*api.User
|
||||||
|
|
|
@ -25,12 +25,11 @@ func TestAPIListReleases(t *testing.T) {
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
session := loginUser(t, user2.LowerName)
|
token := getUserToken(t, user2.LowerName)
|
||||||
token := getTokenForLoggedInUser(t, session)
|
|
||||||
|
|
||||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/releases", user2.Name, repo.Name))
|
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/releases", user2.Name, repo.Name))
|
||||||
link.RawQuery = url.Values{"token": {token}}.Encode()
|
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||||
resp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||||
var apiReleases []*api.Release
|
var apiReleases []*api.Release
|
||||||
DecodeJSON(t, resp, &apiReleases)
|
DecodeJSON(t, resp, &apiReleases)
|
||||||
if assert.Len(t, apiReleases, 3) {
|
if assert.Len(t, apiReleases, 3) {
|
||||||
|
@ -53,13 +52,11 @@ func TestAPIListReleases(t *testing.T) {
|
||||||
|
|
||||||
// test filter
|
// test filter
|
||||||
testFilterByLen := func(auth bool, query url.Values, expectedLength int, msgAndArgs ...string) {
|
testFilterByLen := func(auth bool, query url.Values, expectedLength int, msgAndArgs ...string) {
|
||||||
link.RawQuery = query.Encode()
|
|
||||||
if auth {
|
if auth {
|
||||||
query.Set("token", token)
|
query.Set("token", token)
|
||||||
resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
|
||||||
} else {
|
|
||||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
|
||||||
}
|
}
|
||||||
|
link.RawQuery = query.Encode()
|
||||||
|
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiReleases)
|
DecodeJSON(t, resp, &apiReleases)
|
||||||
assert.Len(t, apiReleases, expectedLength, msgAndArgs)
|
assert.Len(t, apiReleases, expectedLength, msgAndArgs)
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,36 +59,34 @@ func TestAPIRepoTopic(t *testing.T) {
|
||||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository)
|
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository)
|
||||||
|
|
||||||
// Get user2's token
|
// Get user2's token
|
||||||
session := loginUser(t, user2.Name)
|
token2 := getUserToken(t, user2.Name)
|
||||||
token2 := getTokenForLoggedInUser(t, session)
|
|
||||||
|
|
||||||
// Test read topics using login
|
// Test read topics using login
|
||||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/topics", user2.Name, repo2.Name)
|
url := fmt.Sprintf("/api/v1/repos/%s/%s/topics", user2.Name, repo2.Name)
|
||||||
req := NewRequest(t, "GET", url)
|
req := NewRequest(t, "GET", url+"?token="+token2)
|
||||||
res := session.MakeRequest(t, req, http.StatusOK)
|
res := MakeRequest(t, req, http.StatusOK)
|
||||||
var topics *api.TopicName
|
var topics *api.TopicName
|
||||||
DecodeJSON(t, res, &topics)
|
DecodeJSON(t, res, &topics)
|
||||||
assert.ElementsMatch(t, []string{"topicname1", "topicname2"}, topics.TopicNames)
|
assert.ElementsMatch(t, []string{"topicname1", "topicname2"}, topics.TopicNames)
|
||||||
|
|
||||||
// Log out user2
|
// Log out user2
|
||||||
session = emptyTestSession(t)
|
|
||||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/topics?token=%s", user2.Name, repo2.Name, token2)
|
url = fmt.Sprintf("/api/v1/repos/%s/%s/topics?token=%s", user2.Name, repo2.Name, token2)
|
||||||
|
|
||||||
// Test delete a topic
|
// Test delete a topic
|
||||||
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "Topicname1", token2)
|
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "Topicname1", token2)
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
// Test add an existing topic
|
// Test add an existing topic
|
||||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "Golang", token2)
|
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "Golang", token2)
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
// Test add a topic
|
// Test add a topic
|
||||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "topicName3", token2)
|
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "topicName3", token2)
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
// Test read topics using token
|
// Test read topics using token
|
||||||
req = NewRequest(t, "GET", url)
|
req = NewRequest(t, "GET", url)
|
||||||
res = session.MakeRequest(t, req, http.StatusOK)
|
res = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, res, &topics)
|
DecodeJSON(t, res, &topics)
|
||||||
assert.ElementsMatch(t, []string{"topicname2", "golang", "topicname3"}, topics.TopicNames)
|
assert.ElementsMatch(t, []string{"topicname2", "golang", "topicname3"}, topics.TopicNames)
|
||||||
|
|
||||||
|
@ -97,9 +95,9 @@ func TestAPIRepoTopic(t *testing.T) {
|
||||||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||||
Topics: newTopics,
|
Topics: newTopics,
|
||||||
})
|
})
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
MakeRequest(t, req, http.StatusNoContent)
|
||||||
req = NewRequest(t, "GET", url)
|
req = NewRequest(t, "GET", url)
|
||||||
res = session.MakeRequest(t, req, http.StatusOK)
|
res = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, res, &topics)
|
DecodeJSON(t, res, &topics)
|
||||||
assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
|
assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
|
||||||
|
|
||||||
|
@ -108,9 +106,9 @@ func TestAPIRepoTopic(t *testing.T) {
|
||||||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||||
Topics: newTopics,
|
Topics: newTopics,
|
||||||
})
|
})
|
||||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||||
req = NewRequest(t, "GET", url)
|
req = NewRequest(t, "GET", url)
|
||||||
res = session.MakeRequest(t, req, http.StatusOK)
|
res = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, res, &topics)
|
DecodeJSON(t, res, &topics)
|
||||||
assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
|
assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
|
||||||
|
|
||||||
|
@ -119,9 +117,9 @@ func TestAPIRepoTopic(t *testing.T) {
|
||||||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||||
Topics: newTopics,
|
Topics: newTopics,
|
||||||
})
|
})
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
MakeRequest(t, req, http.StatusNoContent)
|
||||||
req = NewRequest(t, "GET", url)
|
req = NewRequest(t, "GET", url)
|
||||||
res = session.MakeRequest(t, req, http.StatusOK)
|
res = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, res, &topics)
|
DecodeJSON(t, res, &topics)
|
||||||
assert.Len(t, topics.TopicNames, 25)
|
assert.Len(t, topics.TopicNames, 25)
|
||||||
|
|
||||||
|
@ -130,29 +128,27 @@ func TestAPIRepoTopic(t *testing.T) {
|
||||||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||||
Topics: newTopics,
|
Topics: newTopics,
|
||||||
})
|
})
|
||||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||||
|
|
||||||
// Test add a topic when there is already maximum
|
// Test add a topic when there is already maximum
|
||||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "t26", token2)
|
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "t26", token2)
|
||||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||||
|
|
||||||
// Test delete a topic that repo doesn't have
|
// Test delete a topic that repo doesn't have
|
||||||
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "Topicname1", token2)
|
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "Topicname1", token2)
|
||||||
session.MakeRequest(t, req, http.StatusNotFound)
|
MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
|
||||||
// Get user4's token
|
// Get user4's token
|
||||||
session = loginUser(t, user4.Name)
|
token4 := getUserToken(t, user4.Name)
|
||||||
token4 := getTokenForLoggedInUser(t, session)
|
|
||||||
session = emptyTestSession(t)
|
|
||||||
|
|
||||||
// Test read topics with write access
|
// Test read topics with write access
|
||||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/topics?token=%s", user3.Name, repo3.Name, token4)
|
url = fmt.Sprintf("/api/v1/repos/%s/%s/topics?token=%s", user3.Name, repo3.Name, token4)
|
||||||
req = NewRequest(t, "GET", url)
|
req = NewRequest(t, "GET", url)
|
||||||
res = session.MakeRequest(t, req, http.StatusOK)
|
res = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, res, &topics)
|
DecodeJSON(t, res, &topics)
|
||||||
assert.Empty(t, topics.TopicNames)
|
assert.Empty(t, topics.TopicNames)
|
||||||
|
|
||||||
// Test add a topic to repo with write access (requires repo admin access)
|
// Test add a topic to repo with write access (requires repo admin access)
|
||||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user3.Name, repo3.Name, "topicName", token4)
|
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user3.Name, repo3.Name, "topicName", token4)
|
||||||
session.MakeRequest(t, req, http.StatusForbidden)
|
MakeRequest(t, req, http.StatusForbidden)
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,11 +224,9 @@ func TestAPITeamSearch(t *testing.T) {
|
||||||
|
|
||||||
var results TeamSearchResults
|
var results TeamSearchResults
|
||||||
|
|
||||||
session := loginUser(t, user.Name)
|
token := getUserToken(t, user.Name)
|
||||||
csrf := GetCSRF(t, session, "/"+org.Name)
|
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s&token=%s", org.Name, "_team", token)
|
||||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "_team")
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
req.Header.Add("X-Csrf-Token", csrf)
|
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
||||||
DecodeJSON(t, resp, &results)
|
DecodeJSON(t, resp, &results)
|
||||||
assert.NotEmpty(t, results.Data)
|
assert.NotEmpty(t, results.Data)
|
||||||
assert.Len(t, results.Data, 1)
|
assert.Len(t, results.Data, 1)
|
||||||
|
@ -236,9 +234,8 @@ func TestAPITeamSearch(t *testing.T) {
|
||||||
|
|
||||||
// no access if not organization member
|
// no access if not organization member
|
||||||
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
|
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
|
||||||
session = loginUser(t, user5.Name)
|
token5 := getUserToken(t, user5.Name)
|
||||||
csrf = GetCSRF(t, session, "/"+org.Name)
|
|
||||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "team")
|
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s&token=%s", org.Name, "team", token5)
|
||||||
req.Header.Add("X-Csrf-Token", csrf)
|
MakeRequest(t, req, http.StatusForbidden)
|
||||||
session.MakeRequest(t, req, http.StatusForbidden)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,15 @@ func TestUserHeatmap(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
adminUsername := "user1"
|
adminUsername := "user1"
|
||||||
normalUsername := "user2"
|
normalUsername := "user2"
|
||||||
session := loginUser(t, adminUsername)
|
token := getUserToken(t, adminUsername)
|
||||||
|
|
||||||
fakeNow := time.Date(2011, 10, 20, 0, 0, 0, 0, time.Local)
|
fakeNow := time.Date(2011, 10, 20, 0, 0, 0, 0, time.Local)
|
||||||
timeutil.Set(fakeNow)
|
timeutil.Set(fakeNow)
|
||||||
defer timeutil.Unset()
|
defer timeutil.Unset()
|
||||||
|
|
||||||
urlStr := fmt.Sprintf("/api/v1/users/%s/heatmap", normalUsername)
|
urlStr := fmt.Sprintf("/api/v1/users/%s/heatmap?token=%s", normalUsername, token)
|
||||||
req := NewRequest(t, "GET", urlStr)
|
req := NewRequest(t, "GET", urlStr)
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
var heatmap []*models.UserHeatmapData
|
var heatmap []*models.UserHeatmapData
|
||||||
DecodeJSON(t, resp, &heatmap)
|
DecodeJSON(t, resp, &heatmap)
|
||||||
var dummyheatmap []*models.UserHeatmapData
|
var dummyheatmap []*models.UserHeatmapData
|
||||||
|
|
|
@ -359,6 +359,10 @@ func emptyTestSession(t testing.TB) *TestSession {
|
||||||
return &TestSession{jar: jar}
|
return &TestSession{jar: jar}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getUserToken(t testing.TB, userName string) string {
|
||||||
|
return getTokenForLoggedInUser(t, loginUser(t, userName))
|
||||||
|
}
|
||||||
|
|
||||||
func loginUser(t testing.TB, userName string) *TestSession {
|
func loginUser(t testing.TB, userName string) *TestSession {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if session, ok := loginSessionCache[userName]; ok {
|
if session, ok := loginSessionCache[userName]; ok {
|
||||||
|
|
|
@ -448,27 +448,29 @@ func TestSearchIssues(t *testing.T) {
|
||||||
func TestSearchIssuesWithLabels(t *testing.T) {
|
func TestSearchIssuesWithLabels(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
token := getUserToken(t, "user1")
|
||||||
|
|
||||||
link, _ := url.Parse("/api/v1/repos/issues/search")
|
link, _ := url.Parse("/api/v1/repos/issues/search?token=" + token)
|
||||||
req := NewRequest(t, "GET", link.String())
|
req := NewRequest(t, "GET", link.String())
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
var apiIssues []*api.Issue
|
var apiIssues []*api.Issue
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
|
|
||||||
assert.Len(t, apiIssues, 10)
|
assert.Len(t, apiIssues, 10)
|
||||||
|
|
||||||
query := url.Values{}
|
query := url.Values{
|
||||||
|
"token": []string{token},
|
||||||
|
}
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 10)
|
assert.Len(t, apiIssues, 10)
|
||||||
|
|
||||||
query.Add("labels", "label1")
|
query.Add("labels", "label1")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
|
|
||||||
|
@ -476,7 +478,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
|
||||||
query.Set("labels", "label1,label2")
|
query.Set("labels", "label1,label2")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
|
|
||||||
|
@ -484,7 +486,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
|
||||||
query.Set("labels", "orglabel4")
|
query.Set("labels", "orglabel4")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 1)
|
assert.Len(t, apiIssues, 1)
|
||||||
|
|
||||||
|
@ -493,7 +495,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
|
||||||
query.Add("state", "all")
|
query.Add("state", "all")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
|
|
||||||
|
@ -501,7 +503,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
|
||||||
query.Set("labels", "label1,orglabel4")
|
query.Set("labels", "label1,orglabel4")
|
||||||
link.RawQuery = query.Encode()
|
link.RawQuery = query.Encode()
|
||||||
req = NewRequest(t, "GET", link.String())
|
req = NewRequest(t, "GET", link.String())
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ package context
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -20,8 +19,6 @@ import (
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/web/middleware"
|
"code.gitea.io/gitea/modules/web/middleware"
|
||||||
auth_service "code.gitea.io/gitea/services/auth"
|
auth_service "code.gitea.io/gitea/services/auth"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// APIContext is a specific context for API service
|
// APIContext is a specific context for API service
|
||||||
|
@ -191,17 +188,6 @@ func (ctx *APIContext) SetLinkHeader(total, pageSize int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequireCSRF requires a validated a CSRF token
|
|
||||||
func (ctx *APIContext) RequireCSRF() {
|
|
||||||
headerToken := ctx.Req.Header.Get(ctx.csrf.GetHeaderName())
|
|
||||||
formValueToken := ctx.Req.FormValue(ctx.csrf.GetFormName())
|
|
||||||
if len(headerToken) > 0 || len(formValueToken) > 0 {
|
|
||||||
Validate(ctx.Context, ctx.csrf)
|
|
||||||
} else {
|
|
||||||
ctx.Context.Error(http.StatusUnauthorized, "Missing CSRF token.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckForOTP validates OTP
|
// CheckForOTP validates OTP
|
||||||
func (ctx *APIContext) CheckForOTP() {
|
func (ctx *APIContext) CheckForOTP() {
|
||||||
if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) {
|
if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) {
|
||||||
|
@ -253,17 +239,14 @@ func APIAuth(authMethod auth_service.Method) func(*APIContext) {
|
||||||
|
|
||||||
// APIContexter returns apicontext as middleware
|
// APIContexter returns apicontext as middleware
|
||||||
func APIContexter() func(http.Handler) http.Handler {
|
func APIContexter() func(http.Handler) http.Handler {
|
||||||
csrfOpts := getCsrfOpts()
|
|
||||||
|
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
locale := middleware.Locale(w, req)
|
locale := middleware.Locale(w, req)
|
||||||
ctx := APIContext{
|
ctx := APIContext{
|
||||||
Context: &Context{
|
Context: &Context{
|
||||||
Resp: NewResponse(w),
|
Resp: NewResponse(w),
|
||||||
Data: map[string]interface{}{},
|
Data: map[string]interface{}{},
|
||||||
Locale: locale,
|
Locale: locale,
|
||||||
Session: session.GetSession(req),
|
|
||||||
Repo: &Repository{
|
Repo: &Repository{
|
||||||
PullRequest: &PullRequest{},
|
PullRequest: &PullRequest{},
|
||||||
},
|
},
|
||||||
|
@ -273,7 +256,6 @@ func APIContexter() func(http.Handler) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Req = WithAPIContext(WithContext(req, ctx.Context), &ctx)
|
ctx.Req = WithAPIContext(WithContext(req, ctx.Context), &ctx)
|
||||||
ctx.csrf = Csrfer(csrfOpts, ctx.Context)
|
|
||||||
|
|
||||||
// If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
|
// If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
|
||||||
if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") {
|
if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") {
|
||||||
|
@ -285,7 +267,6 @@ func APIContexter() func(http.Handler) http.Handler {
|
||||||
|
|
||||||
ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
|
ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
|
||||||
|
|
||||||
ctx.Data["CsrfToken"] = html.EscapeString(ctx.csrf.GetToken())
|
|
||||||
ctx.Data["Context"] = &ctx
|
ctx.Data["Context"] = &ctx
|
||||||
|
|
||||||
next.ServeHTTP(ctx.Resp, ctx.Req)
|
next.ServeHTTP(ctx.Resp, ctx.Req)
|
||||||
|
|
|
@ -216,7 +216,6 @@ func reqToken() func(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ctx.IsSigned {
|
if ctx.IsSigned {
|
||||||
ctx.RequireCSRF()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Error(http.StatusUnauthorized, "reqToken", "token is required")
|
ctx.Error(http.StatusUnauthorized, "reqToken", "token is required")
|
||||||
|
@ -584,8 +583,7 @@ func bind(obj interface{}) http.HandlerFunc {
|
||||||
func buildAuthGroup() *auth.Group {
|
func buildAuthGroup() *auth.Group {
|
||||||
group := auth.NewGroup(
|
group := auth.NewGroup(
|
||||||
&auth.OAuth2{},
|
&auth.OAuth2{},
|
||||||
&auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API
|
&auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API
|
||||||
auth.SharedSession, // FIXME: this should be removed once all UI don't reference API/v1, see https://github.com/go-gitea/gitea/pull/16052
|
|
||||||
)
|
)
|
||||||
if setting.Service.EnableReverseProxyAuth {
|
if setting.Service.EnableReverseProxyAuth {
|
||||||
group.Add(&auth.ReverseProxy{})
|
group.Add(&auth.ReverseProxy{})
|
||||||
|
@ -596,11 +594,9 @@ func buildAuthGroup() *auth.Group {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routes registers all v1 APIs routes to web application.
|
// Routes registers all v1 APIs routes to web application.
|
||||||
func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
func Routes() *web.Route {
|
||||||
m := web.NewRoute()
|
m := web.NewRoute()
|
||||||
|
|
||||||
m.Use(sessioner)
|
|
||||||
|
|
||||||
m.Use(securityHeaders())
|
m.Use(securityHeaders())
|
||||||
if setting.CORSConfig.Enabled {
|
if setting.CORSConfig.Enabled {
|
||||||
m.Use(cors.Handler(cors.Options{
|
m.Use(cors.Handler(cors.Options{
|
||||||
|
@ -609,7 +605,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||||
// setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
|
// setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
|
||||||
AllowedMethods: setting.CORSConfig.Methods,
|
AllowedMethods: setting.CORSConfig.Methods,
|
||||||
AllowCredentials: setting.CORSConfig.AllowCredentials,
|
AllowCredentials: setting.CORSConfig.AllowCredentials,
|
||||||
AllowedHeaders: []string{"Authorization", "X-CSRFToken", "X-Gitea-OTP"},
|
AllowedHeaders: []string{"Authorization", "X-Gitea-OTP"},
|
||||||
MaxAge: int(setting.CORSConfig.MaxAge.Seconds()),
|
MaxAge: int(setting.CORSConfig.MaxAge.Seconds()),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,6 @@ import (
|
||||||
"code.gitea.io/gitea/services/repository/archiver"
|
"code.gitea.io/gitea/services/repository/archiver"
|
||||||
"code.gitea.io/gitea/services/task"
|
"code.gitea.io/gitea/services/task"
|
||||||
"code.gitea.io/gitea/services/webhook"
|
"code.gitea.io/gitea/services/webhook"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func mustInit(fn func() error) {
|
func mustInit(fn func() error) {
|
||||||
|
@ -174,20 +172,8 @@ func NormalRoutes() *web.Route {
|
||||||
r.Use(middle)
|
r.Use(middle)
|
||||||
}
|
}
|
||||||
|
|
||||||
sessioner := session.Sessioner(session.Options{
|
r.Mount("/", web_routers.Routes())
|
||||||
Provider: setting.SessionConfig.Provider,
|
r.Mount("/api/v1", apiv1.Routes())
|
||||||
ProviderConfig: setting.SessionConfig.ProviderConfig,
|
|
||||||
CookieName: setting.SessionConfig.CookieName,
|
|
||||||
CookiePath: setting.SessionConfig.CookiePath,
|
|
||||||
Gclifetime: setting.SessionConfig.Gclifetime,
|
|
||||||
Maxlifetime: setting.SessionConfig.Maxlifetime,
|
|
||||||
Secure: setting.SessionConfig.Secure,
|
|
||||||
SameSite: setting.SessionConfig.SameSite,
|
|
||||||
Domain: setting.SessionConfig.Domain,
|
|
||||||
})
|
|
||||||
|
|
||||||
r.Mount("/", web_routers.Routes(sessioner))
|
|
||||||
r.Mount("/api/v1", apiv1.Routes(sessioner))
|
|
||||||
r.Mount("/api/internal", private.Routes())
|
r.Mount("/api/internal", private.Routes())
|
||||||
if setting.Packages.Enabled {
|
if setting.Packages.Enabled {
|
||||||
r.Mount("/api/packages", packages_router.Routes())
|
r.Mount("/api/packages", packages_router.Routes())
|
||||||
|
|
98
routers/web/misc/markdown.go
Normal file
98
routers/web/misc/markdown.go
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Copyright 2022 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 misc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
"code.gitea.io/gitea/modules/markup"
|
||||||
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
"mvdan.cc/xurls/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Markdown render markdown document to HTML
|
||||||
|
func Markdown(ctx *context.Context) {
|
||||||
|
// swagger:operation POST /markdown miscellaneous renderMarkdown
|
||||||
|
// ---
|
||||||
|
// summary: Render a markdown document as HTML
|
||||||
|
// parameters:
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/MarkdownOption"
|
||||||
|
// consumes:
|
||||||
|
// - application/json
|
||||||
|
// produces:
|
||||||
|
// - text/html
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/MarkdownRender"
|
||||||
|
// "422":
|
||||||
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
|
form := web.GetForm(ctx).(*api.MarkdownOption)
|
||||||
|
|
||||||
|
if ctx.HasAPIError() {
|
||||||
|
ctx.Error(http.StatusUnprocessableEntity, "", ctx.GetErrMsg())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(form.Text) == 0 {
|
||||||
|
_, _ = ctx.Write([]byte(""))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch form.Mode {
|
||||||
|
case "comment":
|
||||||
|
fallthrough
|
||||||
|
case "gfm":
|
||||||
|
urlPrefix := form.Context
|
||||||
|
meta := map[string]string{}
|
||||||
|
if !strings.HasPrefix(setting.AppSubURL+"/", urlPrefix) {
|
||||||
|
// check if urlPrefix is already set to a URL
|
||||||
|
linkRegex, _ := xurls.StrictMatchingScheme("https?://")
|
||||||
|
m := linkRegex.FindStringIndex(urlPrefix)
|
||||||
|
if m == nil {
|
||||||
|
urlPrefix = util.URLJoin(setting.AppURL, form.Context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ctx.Repo != nil && ctx.Repo.Repository != nil {
|
||||||
|
// "gfm" = Github Flavored Markdown - set this to render as a document
|
||||||
|
if form.Mode == "gfm" {
|
||||||
|
meta = ctx.Repo.Repository.ComposeDocumentMetas()
|
||||||
|
} else {
|
||||||
|
meta = ctx.Repo.Repository.ComposeMetas()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if form.Mode == "gfm" {
|
||||||
|
meta["mode"] = "document"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := markdown.Render(&markup.RenderContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
URLPrefix: urlPrefix,
|
||||||
|
Metas: meta,
|
||||||
|
IsWiki: form.Wiki,
|
||||||
|
}, strings.NewReader(form.Text), ctx.Resp); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if err := markdown.RenderRaw(&markup.RenderContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
URLPrefix: form.Context,
|
||||||
|
}, strings.NewReader(form.Text), ctx.Resp); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,13 +25,13 @@ import (
|
||||||
"code.gitea.io/gitea/modules/validation"
|
"code.gitea.io/gitea/modules/validation"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/modules/web/routing"
|
"code.gitea.io/gitea/modules/web/routing"
|
||||||
"code.gitea.io/gitea/routers/api/v1/misc"
|
|
||||||
"code.gitea.io/gitea/routers/web/admin"
|
"code.gitea.io/gitea/routers/web/admin"
|
||||||
"code.gitea.io/gitea/routers/web/auth"
|
"code.gitea.io/gitea/routers/web/auth"
|
||||||
"code.gitea.io/gitea/routers/web/dev"
|
"code.gitea.io/gitea/routers/web/dev"
|
||||||
"code.gitea.io/gitea/routers/web/events"
|
"code.gitea.io/gitea/routers/web/events"
|
||||||
"code.gitea.io/gitea/routers/web/explore"
|
"code.gitea.io/gitea/routers/web/explore"
|
||||||
"code.gitea.io/gitea/routers/web/feed"
|
"code.gitea.io/gitea/routers/web/feed"
|
||||||
|
"code.gitea.io/gitea/routers/web/misc"
|
||||||
"code.gitea.io/gitea/routers/web/org"
|
"code.gitea.io/gitea/routers/web/org"
|
||||||
"code.gitea.io/gitea/routers/web/repo"
|
"code.gitea.io/gitea/routers/web/repo"
|
||||||
"code.gitea.io/gitea/routers/web/user"
|
"code.gitea.io/gitea/routers/web/user"
|
||||||
|
@ -46,6 +46,7 @@ import (
|
||||||
_ "code.gitea.io/gitea/modules/session" // to registers all internal adapters
|
_ "code.gitea.io/gitea/modules/session" // to registers all internal adapters
|
||||||
|
|
||||||
"gitea.com/go-chi/captcha"
|
"gitea.com/go-chi/captcha"
|
||||||
|
"gitea.com/go-chi/session"
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"github.com/go-chi/cors"
|
"github.com/go-chi/cors"
|
||||||
|
@ -85,7 +86,7 @@ func buildAuthGroup() *auth_service.Group {
|
||||||
group := auth_service.NewGroup(
|
group := auth_service.NewGroup(
|
||||||
&auth_service.OAuth2{}, // FIXME: this should be removed and only applied in download and oauth realted routers
|
&auth_service.OAuth2{}, // FIXME: this should be removed and only applied in download and oauth realted routers
|
||||||
&auth_service.Basic{}, // FIXME: this should be removed and only applied in download and git/lfs routers
|
&auth_service.Basic{}, // FIXME: this should be removed and only applied in download and git/lfs routers
|
||||||
auth_service.SharedSession,
|
&auth_service.Session{},
|
||||||
)
|
)
|
||||||
if setting.Service.EnableReverseProxyAuth {
|
if setting.Service.EnableReverseProxyAuth {
|
||||||
group.Add(&auth_service.ReverseProxy{})
|
group.Add(&auth_service.ReverseProxy{})
|
||||||
|
@ -96,7 +97,7 @@ func buildAuthGroup() *auth_service.Group {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routes returns all web routes
|
// Routes returns all web routes
|
||||||
func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
func Routes() *web.Route {
|
||||||
routes := web.NewRoute()
|
routes := web.NewRoute()
|
||||||
|
|
||||||
routes.Use(web.WrapWithPrefix(public.AssetsURLPathPrefix, public.AssetsHandlerFunc(&public.Options{
|
routes.Use(web.WrapWithPrefix(public.AssetsURLPathPrefix, public.AssetsHandlerFunc(&public.Options{
|
||||||
|
@ -105,6 +106,17 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||||
CorsHandler: CorsHandler(),
|
CorsHandler: CorsHandler(),
|
||||||
}), "AssetsHandler"))
|
}), "AssetsHandler"))
|
||||||
|
|
||||||
|
sessioner := session.Sessioner(session.Options{
|
||||||
|
Provider: setting.SessionConfig.Provider,
|
||||||
|
ProviderConfig: setting.SessionConfig.ProviderConfig,
|
||||||
|
CookieName: setting.SessionConfig.CookieName,
|
||||||
|
CookiePath: setting.SessionConfig.CookiePath,
|
||||||
|
Gclifetime: setting.SessionConfig.Gclifetime,
|
||||||
|
Maxlifetime: setting.SessionConfig.Maxlifetime,
|
||||||
|
Secure: setting.SessionConfig.Secure,
|
||||||
|
SameSite: setting.SessionConfig.SameSite,
|
||||||
|
Domain: setting.SessionConfig.Domain,
|
||||||
|
})
|
||||||
routes.Use(sessioner)
|
routes.Use(sessioner)
|
||||||
|
|
||||||
routes.Use(Recovery())
|
routes.Use(Recovery())
|
||||||
|
@ -878,6 +890,7 @@ func RegisterRoutes(m *web.Route) {
|
||||||
m.Group("/comments/{id}", func() {
|
m.Group("/comments/{id}", func() {
|
||||||
m.Get("/attachments", repo.GetCommentAttachments)
|
m.Get("/attachments", repo.GetCommentAttachments)
|
||||||
})
|
})
|
||||||
|
m.Post("/markdown", bindIgnErr(structs.MarkdownOption{}), misc.Markdown)
|
||||||
m.Group("/labels", func() {
|
m.Group("/labels", func() {
|
||||||
m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), repo.NewLabel)
|
m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), repo.NewLabel)
|
||||||
m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), repo.UpdateLabel)
|
m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), repo.UpdateLabel)
|
||||||
|
|
|
@ -20,16 +20,6 @@ import (
|
||||||
"code.gitea.io/gitea/modules/web/middleware"
|
"code.gitea.io/gitea/modules/web/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The purpose of the following three function variables is to let the linter know that
|
|
||||||
// those functions are not dead code and are actually being used
|
|
||||||
var (
|
|
||||||
_ = handleSignIn
|
|
||||||
|
|
||||||
// SharedSession the session auth should only be used by web, but now both web and API/v1
|
|
||||||
// will use it. We can remove this after Web removed dependent API/v1
|
|
||||||
SharedSession = &Session{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Init should be called exactly once when the application starts to allow plugins
|
// Init should be called exactly once when the application starts to allow plugins
|
||||||
// to allocate necessary resources
|
// to allocate necessary resources
|
||||||
func Init() {
|
func Init() {
|
||||||
|
|
|
@ -162,7 +162,7 @@
|
||||||
<div class="ui comment form">
|
<div class="ui comment form">
|
||||||
<div class="ui top attached tabular menu">
|
<div class="ui top attached tabular menu">
|
||||||
<a class="active write item">{{$.i18n.Tr "write"}}</a>
|
<a class="active write item">{{$.i18n.Tr "write"}}</a>
|
||||||
<a class="preview item" data-url="{{$.Repository.APIURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
<a class="preview item" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached active write tab segment">
|
<div class="ui bottom attached active write tab segment">
|
||||||
<textarea class="review-textarea" tabindex="1" name="content"></textarea>
|
<textarea class="review-textarea" tabindex="1" name="content"></textarea>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<input type="hidden" name="diff_base_cid">
|
<input type="hidden" name="diff_base_cid">
|
||||||
<div class="ui top tabular menu" data-write="write" data-preview="preview">
|
<div class="ui top tabular menu" data-write="write" data-preview="preview">
|
||||||
<a class="active item" data-tab="write">{{$.root.i18n.Tr "write"}}</a>
|
<a class="active item" data-tab="write">{{$.root.i18n.Tr "write"}}</a>
|
||||||
<a class="item" data-tab="preview" data-url="{{$.root.Repository.APIURL}}/markdown" data-context="{{$.root.RepoLink}}">{{$.root.i18n.Tr "preview"}}</a>
|
<a class="item" data-tab="preview" data-url="{{$.root.Repository.HTMLURL}}/markdown" data-context="{{$.root.RepoLink}}">{{$.root.i18n.Tr "preview"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui active tab" data-tab="write">
|
<div class="ui active tab" data-tab="write">
|
||||||
|
|
|
@ -31,13 +31,13 @@
|
||||||
<div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff">
|
<div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff">
|
||||||
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{.i18n.Tr "repo.editor.new_file"}}{{else}}{{.i18n.Tr "repo.editor.edit_file"}}{{end}}</a>
|
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{.i18n.Tr "repo.editor.new_file"}}{{else}}{{.i18n.Tr "repo.editor.edit_file"}}{{end}}</a>
|
||||||
{{if not .IsNewFile}}
|
{{if not .IsNewFile}}
|
||||||
<a class="item" data-tab="preview" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-preview-file-modes="{{.PreviewableFileModes}}" data-markdown-mode="gfm">{{svg "octicon-eye"}} {{.i18n.Tr "preview"}}</a>
|
<a class="item" data-tab="preview" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-preview-file-modes="{{.PreviewableFileModes}}" data-markdown-mode="gfm">{{svg "octicon-eye"}} {{.i18n.Tr "preview"}}</a>
|
||||||
<a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}" data-context="{{.BranchLink}}">{{svg "octicon-diff"}} {{.i18n.Tr "repo.editor.preview_changes"}}</a>
|
<a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}" data-context="{{.BranchLink}}">{{svg "octicon-diff"}} {{.i18n.Tr "repo.editor.preview_changes"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached active tab segment" data-tab="write">
|
<div class="ui bottom attached active tab segment" data-tab="write">
|
||||||
<textarea id="edit_area" name="content" class="hide" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
|
<textarea id="edit_area" name="content" class="hide" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
|
||||||
data-url="{{.Repository.APIURL}}/markdown"
|
data-url="{{.Repository.HTMLURL}}/markdown"
|
||||||
data-context="{{.RepoLink}}"
|
data-context="{{.RepoLink}}"
|
||||||
data-markdown-file-exts="{{.MarkdownFileExts}}"
|
data-markdown-file-exts="{{.MarkdownFileExts}}"
|
||||||
data-line-wrap-extensions="{{.LineWrapExtensions}}">
|
data-line-wrap-extensions="{{.LineWrapExtensions}}">
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<div class="ui top tabular menu" data-write="write" data-preview="preview">
|
<div class="ui top tabular menu" data-write="write" data-preview="preview">
|
||||||
<a class="active item" data-tab="write">{{.i18n.Tr "write"}}</a>
|
<a class="active item" data-tab="write">{{.i18n.Tr "write"}}</a>
|
||||||
<a class="item" data-tab="preview" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "preview"}}</a>
|
<a class="item" data-tab="preview" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "preview"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui bottom active tab" data-tab="write">
|
<div class="ui bottom active tab" data-tab="write">
|
||||||
<textarea id="content" class="edit_area js-quick-submit" name="content" tabindex="4" data-id="issue-{{.RepoName}}" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.Repo.RepoLink}}">
|
<textarea id="content" class="edit_area js-quick-submit" name="content" tabindex="4" data-id="issue-{{.RepoName}}" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.Repo.RepoLink}}">
|
||||||
{{- if .BodyQuery}}{{.BodyQuery}}{{else if .IssueTemplate}}{{.IssueTemplate}}{{else if .PullRequestTemplate}}{{.PullRequestTemplate}}{{else}}{{.content}}{{end -}}
|
{{- if .BodyQuery}}{{.BodyQuery}}{{else if .IssueTemplate}}{{.IssueTemplate}}{{else if .PullRequestTemplate}}{{.PullRequestTemplate}}{{else}}{{.content}}{{end -}}
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -195,7 +195,7 @@
|
||||||
<div class="ui comment form">
|
<div class="ui comment form">
|
||||||
<div class="ui top tabular menu">
|
<div class="ui top tabular menu">
|
||||||
<a class="active write item">{{$.i18n.Tr "write"}}</a>
|
<a class="active write item">{{$.i18n.Tr "write"}}</a>
|
||||||
<a class="preview item" data-url="{{$.Repository.APIURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
<a class="preview item" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui bottom active tab write">
|
<div class="ui bottom active tab write">
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
<label>{{.i18n.Tr "repo.release.content"}}</label>
|
<label>{{.i18n.Tr "repo.release.content"}}</label>
|
||||||
<div class="ui top tabular menu" data-write="write" data-preview="preview">
|
<div class="ui top tabular menu" data-write="write" data-preview="preview">
|
||||||
<a class="active write item" data-tab="write">{{$.i18n.Tr "write"}}</a>
|
<a class="active write item" data-tab="write">{{$.i18n.Tr "write"}}</a>
|
||||||
<a class="preview item" data-tab="preview" data-url="{{$.Repository.APIURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
<a class="preview item" data-tab="preview" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom active tab" data-tab="write">
|
<div class="ui bottom active tab" data-tab="write">
|
||||||
<textarea name="content">{{.content}}</textarea>
|
<textarea name="content">{{.content}}</textarea>
|
||||||
|
|
|
@ -21,11 +21,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="ui top attached tabular menu previewtabs" data-write="write" data-preview="preview">
|
<div class="ui top attached tabular menu previewtabs" data-write="write" data-preview="preview">
|
||||||
<a class="active item" data-tab="write">{{.i18n.Tr "write"}}</a>
|
<a class="active item" data-tab="write">{{.i18n.Tr "write"}}</a>
|
||||||
<a class="item" data-tab="preview" data-url="{{$.Repository.APIURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
<a class="item" data-tab="preview" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="field content" data-loading="{{.i18n.Tr "loading"}}">
|
<div class="field content" data-loading="{{.i18n.Tr "loading"}}">
|
||||||
<div class="ui bottom active tab" data-tab="write">
|
<div class="ui bottom active tab" data-tab="write">
|
||||||
<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}">{{if .PageIsWikiEdit}}{{.content}}{{else}}{{.i18n.Tr "repo.wiki.welcome"}}{{end}}</textarea>
|
<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.RepoLink}}">{{if .PageIsWikiEdit}}{{.content}}{{else}}{{.i18n.Tr "repo.wiki.welcome"}}{{end}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|
Loading…
Reference in a new issue