mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-25 17:30:36 +00: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) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
token := getUserToken(t, "user2")
|
||||
|
||||
link, _ := url.Parse("/api/v1/repos/issues/search")
|
||||
req := NewRequest(t, "GET", link.String())
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
req := NewRequest(t, "GET", link.String()+"?token="+token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiIssues []*api.Issue
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
@ -181,7 +180,7 @@ func TestAPISearchIssues(t *testing.T) {
|
|||
query := url.Values{"token": {token}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
||||
|
@ -189,9 +188,10 @@ func TestAPISearchIssues(t *testing.T) {
|
|||
before := time.Unix(999307200, 0).Format(time.RFC3339)
|
||||
query.Add("since", since)
|
||||
query.Add("before", before)
|
||||
query.Add("token", token)
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 8)
|
||||
query.Del("since")
|
||||
|
@ -200,14 +200,14 @@ func TestAPISearchIssues(t *testing.T) {
|
|||
query.Add("state", "closed")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query.Set("state", "all")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.EqualValues(t, "15", resp.Header().Get("X-Total-Count"))
|
||||
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")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
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()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
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()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
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()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query = url.Values{"owner": {"user2"}} // user
|
||||
query = url.Values{"owner": {"user2"}, "token": {token}} // user
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 6)
|
||||
|
||||
query = url.Values{"owner": {"user3"}} // organization
|
||||
query = url.Values{"owner": {"user3"}, "token": {token}} // organization
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
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()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
}
|
||||
|
@ -265,12 +265,11 @@ func TestAPISearchIssues(t *testing.T) {
|
|||
func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
token := getUserToken(t, "user1")
|
||||
|
||||
link, _ := url.Parse("/api/v1/repos/issues/search")
|
||||
req := NewRequest(t, "GET", link.String())
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
req := NewRequest(t, "GET", link.String()+"?token="+token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiIssues []*api.Issue
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
|
||||
|
@ -280,14 +279,14 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Add("token", token)
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
||||
query.Add("labels", "label1")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
|
@ -295,7 +294,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Set("labels", "label1,label2")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
|
@ -303,7 +302,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Set("labels", "orglabel4")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 1)
|
||||
|
||||
|
@ -312,7 +311,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Add("state", "all")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
|
@ -320,7 +319,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Set("labels", "label1,orglabel4")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
}
|
||||
|
|
|
@ -20,9 +20,8 @@ import (
|
|||
|
||||
func TestAPIOrgCreate(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
session := loginUser(t, "user1")
|
||||
token := getUserToken(t, "user1")
|
||||
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
org := api.CreateOrgOption{
|
||||
UserName: "user1_org",
|
||||
FullName: "User1's organization",
|
||||
|
@ -32,7 +31,7 @@ func TestAPIOrgCreate(t *testing.T) {
|
|||
Visibility: "limited",
|
||||
}
|
||||
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
|
||||
DecodeJSON(t, resp, &apiOrg)
|
||||
|
@ -50,13 +49,13 @@ func TestAPIOrgCreate(t *testing.T) {
|
|||
FullName: org.FullName,
|
||||
})
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s", org.UserName)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s?token=%s", org.UserName, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiOrg)
|
||||
assert.EqualValues(t, org.UserName, apiOrg.UserName)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", org.UserName)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token=%s", org.UserName, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repos []*api.Repository
|
||||
DecodeJSON(t, resp, &repos)
|
||||
|
@ -64,8 +63,8 @@ func TestAPIOrgCreate(t *testing.T) {
|
|||
assert.False(t, repo.Private)
|
||||
}
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", org.UserName)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members?token=%s", org.UserName, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// user1 on this org is public
|
||||
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)
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
session := loginUser(t, user2.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
token := getUserToken(t, user2.LowerName)
|
||||
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/releases", user2.Name, repo.Name))
|
||||
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
|
||||
DecodeJSON(t, resp, &apiReleases)
|
||||
if assert.Len(t, apiReleases, 3) {
|
||||
|
@ -53,13 +52,11 @@ func TestAPIListReleases(t *testing.T) {
|
|||
|
||||
// test filter
|
||||
testFilterByLen := func(auth bool, query url.Values, expectedLength int, msgAndArgs ...string) {
|
||||
link.RawQuery = query.Encode()
|
||||
if auth {
|
||||
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)
|
||||
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)
|
||||
|
||||
// Get user2's token
|
||||
session := loginUser(t, user2.Name)
|
||||
token2 := getTokenForLoggedInUser(t, session)
|
||||
token2 := getUserToken(t, user2.Name)
|
||||
|
||||
// Test read topics using login
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/topics", user2.Name, repo2.Name)
|
||||
req := NewRequest(t, "GET", url)
|
||||
res := session.MakeRequest(t, req, http.StatusOK)
|
||||
req := NewRequest(t, "GET", url+"?token="+token2)
|
||||
res := MakeRequest(t, req, http.StatusOK)
|
||||
var topics *api.TopicName
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.ElementsMatch(t, []string{"topicname1", "topicname2"}, topics.TopicNames)
|
||||
|
||||
// Log out user2
|
||||
session = emptyTestSession(t)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/topics?token=%s", user2.Name, repo2.Name, token2)
|
||||
|
||||
// Test delete a topic
|
||||
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
|
||||
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
|
||||
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
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = session.MakeRequest(t, req, http.StatusOK)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
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{
|
||||
Topics: newTopics,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = session.MakeRequest(t, req, http.StatusOK)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
|
||||
|
||||
|
@ -108,9 +106,9 @@ func TestAPIRepoTopic(t *testing.T) {
|
|||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||
Topics: newTopics,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = session.MakeRequest(t, req, http.StatusOK)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
|
||||
|
||||
|
@ -119,9 +117,9 @@ func TestAPIRepoTopic(t *testing.T) {
|
|||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||
Topics: newTopics,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = session.MakeRequest(t, req, http.StatusOK)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Len(t, topics.TopicNames, 25)
|
||||
|
||||
|
@ -130,29 +128,27 @@ func TestAPIRepoTopic(t *testing.T) {
|
|||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||
Topics: newTopics,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// 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)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// 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)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Get user4's token
|
||||
session = loginUser(t, user4.Name)
|
||||
token4 := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t)
|
||||
token4 := getUserToken(t, user4.Name)
|
||||
|
||||
// Test read topics with write access
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/topics?token=%s", user3.Name, repo3.Name, token4)
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = session.MakeRequest(t, req, http.StatusOK)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Empty(t, topics.TopicNames)
|
||||
|
||||
// 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)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
|
|
@ -224,11 +224,9 @@ func TestAPITeamSearch(t *testing.T) {
|
|||
|
||||
var results TeamSearchResults
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
csrf := GetCSRF(t, session, "/"+org.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "_team")
|
||||
req.Header.Add("X-Csrf-Token", csrf)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
token := getUserToken(t, user.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s&token=%s", org.Name, "_team", token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.NotEmpty(t, results.Data)
|
||||
assert.Len(t, results.Data, 1)
|
||||
|
@ -236,9 +234,8 @@ func TestAPITeamSearch(t *testing.T) {
|
|||
|
||||
// no access if not organization member
|
||||
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
|
||||
session = loginUser(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.Header.Add("X-Csrf-Token", csrf)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
token5 := getUserToken(t, user5.Name)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s&token=%s", org.Name, "team", token5)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
|
|
@ -20,15 +20,15 @@ func TestUserHeatmap(t *testing.T) {
|
|||
defer prepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
normalUsername := "user2"
|
||||
session := loginUser(t, adminUsername)
|
||||
token := getUserToken(t, adminUsername)
|
||||
|
||||
fakeNow := time.Date(2011, 10, 20, 0, 0, 0, 0, time.Local)
|
||||
timeutil.Set(fakeNow)
|
||||
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)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var heatmap []*models.UserHeatmapData
|
||||
DecodeJSON(t, resp, &heatmap)
|
||||
var dummyheatmap []*models.UserHeatmapData
|
||||
|
|
|
@ -359,6 +359,10 @@ func emptyTestSession(t testing.TB) *TestSession {
|
|||
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 {
|
||||
t.Helper()
|
||||
if session, ok := loginSessionCache[userName]; ok {
|
||||
|
|
|
@ -448,27 +448,29 @@ func TestSearchIssues(t *testing.T) {
|
|||
func TestSearchIssuesWithLabels(t *testing.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())
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiIssues []*api.Issue
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
||||
query := url.Values{}
|
||||
query := url.Values{
|
||||
"token": []string{token},
|
||||
}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
||||
query.Add("labels", "label1")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
|
@ -476,7 +478,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
|
|||
query.Set("labels", "label1,label2")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
|
@ -484,7 +486,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
|
|||
query.Set("labels", "orglabel4")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 1)
|
||||
|
||||
|
@ -493,7 +495,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
|
|||
query.Add("state", "all")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
|
@ -501,7 +503,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
|
|||
query.Set("labels", "label1,orglabel4")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ package context
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
@ -20,8 +19,6 @@ import (
|
|||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
auth_service "code.gitea.io/gitea/services/auth"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
)
|
||||
|
||||
// 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
|
||||
func (ctx *APIContext) CheckForOTP() {
|
||||
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
|
||||
func APIContexter() func(http.Handler) http.Handler {
|
||||
csrfOpts := getCsrfOpts()
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
locale := middleware.Locale(w, req)
|
||||
ctx := APIContext{
|
||||
Context: &Context{
|
||||
Resp: NewResponse(w),
|
||||
Data: map[string]interface{}{},
|
||||
Locale: locale,
|
||||
Session: session.GetSession(req),
|
||||
Resp: NewResponse(w),
|
||||
Data: map[string]interface{}{},
|
||||
Locale: locale,
|
||||
Repo: &Repository{
|
||||
PullRequest: &PullRequest{},
|
||||
},
|
||||
|
@ -273,7 +256,6 @@ func APIContexter() func(http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
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 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.Data["CsrfToken"] = html.EscapeString(ctx.csrf.GetToken())
|
||||
ctx.Data["Context"] = &ctx
|
||||
|
||||
next.ServeHTTP(ctx.Resp, ctx.Req)
|
||||
|
|
|
@ -216,7 +216,6 @@ func reqToken() func(ctx *context.APIContext) {
|
|||
return
|
||||
}
|
||||
if ctx.IsSigned {
|
||||
ctx.RequireCSRF()
|
||||
return
|
||||
}
|
||||
ctx.Error(http.StatusUnauthorized, "reqToken", "token is required")
|
||||
|
@ -584,8 +583,7 @@ func bind(obj interface{}) http.HandlerFunc {
|
|||
func buildAuthGroup() *auth.Group {
|
||||
group := auth.NewGroup(
|
||||
&auth.OAuth2{},
|
||||
&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
|
||||
&auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API
|
||||
)
|
||||
if setting.Service.EnableReverseProxyAuth {
|
||||
group.Add(&auth.ReverseProxy{})
|
||||
|
@ -596,11 +594,9 @@ func buildAuthGroup() *auth.Group {
|
|||
}
|
||||
|
||||
// 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.Use(sessioner)
|
||||
|
||||
m.Use(securityHeaders())
|
||||
if setting.CORSConfig.Enabled {
|
||||
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
|
||||
AllowedMethods: setting.CORSConfig.Methods,
|
||||
AllowCredentials: setting.CORSConfig.AllowCredentials,
|
||||
AllowedHeaders: []string{"Authorization", "X-CSRFToken", "X-Gitea-OTP"},
|
||||
AllowedHeaders: []string{"Authorization", "X-Gitea-OTP"},
|
||||
MaxAge: int(setting.CORSConfig.MaxAge.Seconds()),
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -48,8 +48,6 @@ import (
|
|||
"code.gitea.io/gitea/services/repository/archiver"
|
||||
"code.gitea.io/gitea/services/task"
|
||||
"code.gitea.io/gitea/services/webhook"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
)
|
||||
|
||||
func mustInit(fn func() error) {
|
||||
|
@ -174,20 +172,8 @@ func NormalRoutes() *web.Route {
|
|||
r.Use(middle)
|
||||
}
|
||||
|
||||
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,
|
||||
})
|
||||
|
||||
r.Mount("/", web_routers.Routes(sessioner))
|
||||
r.Mount("/api/v1", apiv1.Routes(sessioner))
|
||||
r.Mount("/", web_routers.Routes())
|
||||
r.Mount("/api/v1", apiv1.Routes())
|
||||
r.Mount("/api/internal", private.Routes())
|
||||
if setting.Packages.Enabled {
|
||||
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/web"
|
||||
"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/auth"
|
||||
"code.gitea.io/gitea/routers/web/dev"
|
||||
"code.gitea.io/gitea/routers/web/events"
|
||||
"code.gitea.io/gitea/routers/web/explore"
|
||||
"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/repo"
|
||||
"code.gitea.io/gitea/routers/web/user"
|
||||
|
@ -46,6 +46,7 @@ import (
|
|||
_ "code.gitea.io/gitea/modules/session" // to registers all internal adapters
|
||||
|
||||
"gitea.com/go-chi/captcha"
|
||||
"gitea.com/go-chi/session"
|
||||
"github.com/NYTimes/gziphandler"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
|
@ -85,7 +86,7 @@ func buildAuthGroup() *auth_service.Group {
|
|||
group := auth_service.NewGroup(
|
||||
&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.SharedSession,
|
||||
&auth_service.Session{},
|
||||
)
|
||||
if setting.Service.EnableReverseProxyAuth {
|
||||
group.Add(&auth_service.ReverseProxy{})
|
||||
|
@ -96,7 +97,7 @@ func buildAuthGroup() *auth_service.Group {
|
|||
}
|
||||
|
||||
// Routes returns all web routes
|
||||
func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||
func Routes() *web.Route {
|
||||
routes := web.NewRoute()
|
||||
|
||||
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(),
|
||||
}), "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(Recovery())
|
||||
|
@ -878,6 +890,7 @@ func RegisterRoutes(m *web.Route) {
|
|||
m.Group("/comments/{id}", func() {
|
||||
m.Get("/attachments", repo.GetCommentAttachments)
|
||||
})
|
||||
m.Post("/markdown", bindIgnErr(structs.MarkdownOption{}), misc.Markdown)
|
||||
m.Group("/labels", func() {
|
||||
m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), repo.NewLabel)
|
||||
m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), repo.UpdateLabel)
|
||||
|
|
|
@ -20,16 +20,6 @@ import (
|
|||
"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
|
||||
// to allocate necessary resources
|
||||
func Init() {
|
||||
|
|
|
@ -162,7 +162,7 @@
|
|||
<div class="ui comment form">
|
||||
<div class="ui top attached tabular menu">
|
||||
<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 class="ui bottom attached active write tab segment">
|
||||
<textarea class="review-textarea" tabindex="1" name="content"></textarea>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<input type="hidden" name="diff_base_cid">
|
||||
<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="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 class="field">
|
||||
<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">
|
||||
<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}}
|
||||
<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>
|
||||
{{end}}
|
||||
</div>
|
||||
<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}}"
|
||||
data-url="{{.Repository.APIURL}}/markdown"
|
||||
data-url="{{.Repository.HTMLURL}}/markdown"
|
||||
data-context="{{.RepoLink}}"
|
||||
data-markdown-file-exts="{{.MarkdownFileExts}}"
|
||||
data-line-wrap-extensions="{{.LineWrapExtensions}}">
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<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="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 class="field">
|
||||
<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 -}}
|
||||
</textarea>
|
||||
</div>
|
||||
|
|
|
@ -195,7 +195,7 @@
|
|||
<div class="ui comment form">
|
||||
<div class="ui top tabular menu">
|
||||
<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 class="field">
|
||||
<div class="ui bottom active tab write">
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<label>{{.i18n.Tr "repo.release.content"}}</label>
|
||||
<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="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 class="ui bottom active tab" data-tab="write">
|
||||
<textarea name="content">{{.content}}</textarea>
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
</div>
|
||||
<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="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 class="field content" data-loading="{{.i18n.Tr "loading"}}">
|
||||
<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 class="field">
|
||||
|
|
Loading…
Reference in a new issue