Merge branch 'master' into issue-4234
This commit is contained in:
commit
0d8a446f00
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -4,6 +4,18 @@ This changelog goes through all the changes that have been made in each release
|
|||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.4.3](https://github.com/go-gitea/gitea/releases/tag/v1.4.3) - 2018-06-26
|
||||
* SECURITY
|
||||
* HTML-escape plain-text READMEs (#4192) (#4214)
|
||||
* Fix open redirect vulnerability on login screen (#4312) (#4312)
|
||||
* BUGFIXES
|
||||
* Fix broken monitoring page when running processes are shown (#4203) (#4208)
|
||||
* Fix delete comment bug (#4216) (#4228)
|
||||
* Delete reactions added to issues and comments when deleting repository (#4232) (#4237)
|
||||
* Fix wiki URL encoding bug (#4091) (#4254)
|
||||
* Fix code tab link when viewing tags (#3908) (#4263)
|
||||
* Fix webhook type conflation (#4285) (#4285)
|
||||
|
||||
## [1.4.2](https://github.com/go-gitea/gitea/releases/tag/v1.4.2) - 2018-06-04
|
||||
* BUGFIXES
|
||||
* Adjust z-index for floating labels (#3939) (#3950)
|
||||
|
|
|
|||
|
|
@ -5,19 +5,47 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
var topicPattern = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`)
|
||||
|
||||
func validateTopic(topic string) bool {
|
||||
return len(topic) <= 35 && topicPattern.MatchString(topic)
|
||||
}
|
||||
|
||||
func reformatAndRemoveIncorrectTopics(x *xorm.Engine) (err error) {
|
||||
log.Info("This migration could take up to minutes, please be patient.")
|
||||
|
||||
type Topic struct {
|
||||
ID int64
|
||||
Name string `xorm:"unique"`
|
||||
ID int64
|
||||
Name string `xorm:"UNIQUE"`
|
||||
RepoCount int
|
||||
CreatedUnix int64 `xorm:"INDEX created"`
|
||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
||||
}
|
||||
|
||||
type RepoTopic struct {
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
TopicID int64 `xorm:"UNIQUE(s)"`
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Topics []string `xorm:"TEXT JSON"`
|
||||
}
|
||||
|
||||
if err := x.Sync2(new(Topic)); err != nil {
|
||||
return fmt.Errorf("Sync2: %v", err)
|
||||
}
|
||||
if err := x.Sync2(new(RepoTopic)); err != nil {
|
||||
return fmt.Errorf("Sync2: %v", err)
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
|
|
@ -25,79 +53,99 @@ func reformatAndRemoveIncorrectTopics(x *xorm.Engine) (err error) {
|
|||
|
||||
const batchSize = 100
|
||||
touchedRepo := make(map[int64]struct{})
|
||||
topics := make([]*Topic, 0, batchSize)
|
||||
delTopicIDs := make([]int64, 0, batchSize)
|
||||
ids := make([]int64, 0, 30)
|
||||
|
||||
log.Info("Validating existed topics...")
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Validating existed topics...")
|
||||
for start := 0; ; start += batchSize {
|
||||
topics = topics[:0]
|
||||
if err := sess.Asc("id").Limit(batchSize, start).Find(&topics); err != nil {
|
||||
topics := make([]*Topic, 0, batchSize)
|
||||
if err := x.Cols("id", "name").Asc("id").Limit(batchSize, start).Find(&topics); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(topics) == 0 {
|
||||
break
|
||||
}
|
||||
for _, topic := range topics {
|
||||
if models.ValidateTopic(topic.Name) {
|
||||
if validateTopic(topic.Name) {
|
||||
continue
|
||||
}
|
||||
log.Info("Incorrect topic: id = %v, name = %q", topic.ID, topic.Name)
|
||||
|
||||
topic.Name = strings.Replace(strings.TrimSpace(strings.ToLower(topic.Name)), " ", "-", -1)
|
||||
|
||||
ids := make([]int64, 0, 30)
|
||||
if err := sess.Table("repo_topic").Cols("repo_id").
|
||||
Where("topic_id = ?", topic.ID).Find(&ids); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Touched repo ids: %v", ids)
|
||||
for _, id := range ids {
|
||||
touchedRepo[id] = struct{}{}
|
||||
}
|
||||
|
||||
if models.ValidateTopic(topic.Name) {
|
||||
log.Info("Updating topic: id = %v, name = %v", topic.ID, topic.Name)
|
||||
if _, err := sess.Table("topic").ID(topic.ID).
|
||||
Update(&Topic{Name: topic.Name}); err != nil {
|
||||
if validateTopic(topic.Name) {
|
||||
unifiedTopic := Topic{Name: topic.Name}
|
||||
exists, err := sess.Cols("id", "name").Get(&unifiedTopic)
|
||||
log.Info("Exists topic with the name %q? %v, id = %v", topic.Name, exists, unifiedTopic.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
delTopicIDs = append(delTopicIDs, topic.ID)
|
||||
if exists {
|
||||
log.Info("Updating repo_topic rows with topic_id = %v to topic_id = %v", topic.ID, unifiedTopic.ID)
|
||||
if _, err := sess.Where("topic_id = ? AND repo_id NOT IN "+
|
||||
"(SELECT rt1.repo_id FROM repo_topic rt1 INNER JOIN repo_topic rt2 "+
|
||||
"ON rt1.repo_id = rt2.repo_id WHERE rt1.topic_id = ? AND rt2.topic_id = ?)",
|
||||
topic.ID, topic.ID, unifiedTopic.ID).Update(&RepoTopic{TopicID: unifiedTopic.ID}); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Updating topic `repo_count` field")
|
||||
if _, err := sess.Exec(
|
||||
"UPDATE topic SET repo_count = (SELECT COUNT(*) FROM repo_topic WHERE topic_id = ? GROUP BY topic_id) WHERE id = ?",
|
||||
unifiedTopic.ID, unifiedTopic.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Info("Updating topic: id = %v, name = %q", topic.ID, topic.Name)
|
||||
if _, err := sess.Table("topic").ID(topic.ID).
|
||||
Update(&Topic{Name: topic.Name}); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
delTopicIDs = append(delTopicIDs, topic.ID)
|
||||
}
|
||||
}
|
||||
if err := sess.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sess.Init()
|
||||
|
||||
log.Info("Deleting incorrect topics...")
|
||||
for start := 0; ; start += batchSize {
|
||||
if (start + batchSize) < len(delTopicIDs) {
|
||||
ids = delTopicIDs[start:(start + batchSize)]
|
||||
} else {
|
||||
ids = delTopicIDs[start:]
|
||||
}
|
||||
|
||||
log.Info("Deleting 'repo_topic' rows for topics with ids = %v", ids)
|
||||
if _, err := sess.In("topic_id", ids).Delete(&models.RepoTopic{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("Deleting topics with id = %v", ids)
|
||||
if _, err := sess.In("id", ids).Delete(&Topic{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(ids) < batchSize {
|
||||
break
|
||||
}
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Deleting 'repo_topic' rows for topics with ids = %v", delTopicIDs)
|
||||
if _, err := sess.In("topic_id", delTopicIDs).Delete(&RepoTopic{}); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Deleting topics with id = %v", delTopicIDs)
|
||||
if _, err := sess.In("id", delTopicIDs).Delete(&Topic{}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sess.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repoTopics := make([]*models.RepoTopic, 0, batchSize)
|
||||
delRepoTopics := make([]*models.RepoTopic, 0, batchSize)
|
||||
tmpRepoTopics := make([]*models.RepoTopic, 0, 30)
|
||||
delRepoTopics := make([]*RepoTopic, 0, batchSize)
|
||||
|
||||
log.Info("Checking the number of topics in the repositories...")
|
||||
for start := 0; ; start += batchSize {
|
||||
repoTopics = repoTopics[:0]
|
||||
if err := sess.Cols("repo_id").Asc("repo_id").Limit(batchSize, start).
|
||||
repoTopics := make([]*RepoTopic, 0, batchSize)
|
||||
if err := x.Cols("repo_id").Asc("repo_id").Limit(batchSize, start).
|
||||
GroupBy("repo_id").Having("COUNT(*) > 25").Find(&repoTopics); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -109,8 +157,8 @@ func reformatAndRemoveIncorrectTopics(x *xorm.Engine) (err error) {
|
|||
for _, repoTopic := range repoTopics {
|
||||
touchedRepo[repoTopic.RepoID] = struct{}{}
|
||||
|
||||
tmpRepoTopics = tmpRepoTopics[:0]
|
||||
if err := sess.Where("repo_id = ?", repoTopic.RepoID).Find(&tmpRepoTopics); err != nil {
|
||||
tmpRepoTopics := make([]*RepoTopic, 0, 30)
|
||||
if err := x.Where("repo_id = ?", repoTopic.RepoID).Find(&tmpRepoTopics); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -122,13 +170,18 @@ func reformatAndRemoveIncorrectTopics(x *xorm.Engine) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
sess.Init()
|
||||
|
||||
log.Info("Deleting superfluous topics for repositories (more than 25 topics)...")
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, repoTopic := range delRepoTopics {
|
||||
log.Info("Deleting 'repo_topic' rows for 'repository' with id = %v. Topic id = %v",
|
||||
repoTopic.RepoID, repoTopic.TopicID)
|
||||
|
||||
if _, err := sess.Where("repo_id = ? AND topic_id = ?", repoTopic.RepoID,
|
||||
repoTopic.TopicID).Delete(&models.RepoTopic{}); err != nil {
|
||||
repoTopic.TopicID).Delete(&RepoTopic{}); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := sess.Exec(
|
||||
|
|
@ -138,17 +191,17 @@ func reformatAndRemoveIncorrectTopics(x *xorm.Engine) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
topicNames := make([]string, 0, 30)
|
||||
log.Info("Updating repositories 'topics' fields...")
|
||||
for repoID := range touchedRepo {
|
||||
topicNames := make([]string, 0, 30)
|
||||
if err := sess.Table("topic").Cols("name").
|
||||
Join("INNER", "repo_topic", "topic.id = repo_topic.topic_id").
|
||||
Where("repo_topic.repo_id = ?", repoID).Find(&topicNames); err != nil {
|
||||
Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id").
|
||||
Where("repo_topic.repo_id = ?", repoID).Desc("topic.repo_count").Find(&topicNames); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Updating 'topics' field for repository with id = %v", repoID)
|
||||
if _, err := sess.ID(repoID).Cols("topics").
|
||||
Update(&models.Repository{Topics: topicNames}); err != nil {
|
||||
Update(&Repository{Topics: topicNames}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ var topicPattern = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`)
|
|||
// Topic represents a topic of repositories
|
||||
type Topic struct {
|
||||
ID int64
|
||||
Name string `xorm:"unique"`
|
||||
Name string `xorm:"UNIQUE"`
|
||||
RepoCount int
|
||||
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||
|
|
@ -34,8 +34,8 @@ type Topic struct {
|
|||
|
||||
// RepoTopic represents associated repositories and topics
|
||||
type RepoTopic struct {
|
||||
RepoID int64 `xorm:"unique(s)"`
|
||||
TopicID int64 `xorm:"unique(s)"`
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
TopicID int64 `xorm:"UNIQUE(s)"`
|
||||
}
|
||||
|
||||
// ErrTopicNotExist represents an error that a topic is not exist
|
||||
|
|
@ -190,10 +190,10 @@ func SaveTopics(repoID int64, topicNames ...string) error {
|
|||
}
|
||||
}
|
||||
|
||||
topicNames = topicNames[:0]
|
||||
topicNames = make([]string, 0, 25)
|
||||
if err := sess.Table("topic").Cols("name").
|
||||
Join("INNER", "repo_topic", "topic.id = repo_topic.topic_id").
|
||||
Where("repo_topic.repo_id = ?", repoID).Find(&topicNames); err != nil {
|
||||
Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id").
|
||||
Where("repo_topic.repo_id = ?", repoID).Desc("topic.repo_count").Find(&topicNames); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
// OptionalBool a boolean that can be "null"
|
||||
|
|
@ -78,6 +79,18 @@ func URLJoin(base string, elems ...string) string {
|
|||
return joinedURL
|
||||
}
|
||||
|
||||
// IsExternalURL checks if rawURL points to an external URL like http://example.com
|
||||
func IsExternalURL(rawURL string) bool {
|
||||
parsed, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
if len(parsed.Host) != 0 && strings.Replace(parsed.Host, "www.", "", 1) != strings.Replace(setting.Domain, "www.", "", 1) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Min min of two ints
|
||||
func Min(a, b int) int {
|
||||
if a > b {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ package util
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
@ -42,3 +44,36 @@ func TestURLJoin(t *testing.T) {
|
|||
assert.Equal(t, test.Expected, URLJoin(test.Base, test.Elements...))
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsExternalURL(t *testing.T) {
|
||||
setting.Domain = "try.gitea.io"
|
||||
type test struct {
|
||||
Expected bool
|
||||
RawURL string
|
||||
}
|
||||
newTest := func(expected bool, rawURL string) test {
|
||||
return test{Expected: expected, RawURL: rawURL}
|
||||
}
|
||||
for _, test := range []test{
|
||||
newTest(false,
|
||||
"https://try.gitea.io"),
|
||||
newTest(true,
|
||||
"https://example.com/"),
|
||||
newTest(true,
|
||||
"//example.com"),
|
||||
newTest(true,
|
||||
"http://example.com"),
|
||||
newTest(false,
|
||||
"a/"),
|
||||
newTest(false,
|
||||
"https://try.gitea.io/test?param=false"),
|
||||
newTest(false,
|
||||
"test?param=false"),
|
||||
newTest(false,
|
||||
"//try.gitea.io/test?param=false"),
|
||||
newTest(false,
|
||||
"/hey/hey/hey#3244"),
|
||||
} {
|
||||
assert.Equal(t, test.Expected, IsExternalURL(test.RawURL))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,13 +54,14 @@ password=Parole
|
|||
db_name=Datu bāzes nosaukums
|
||||
path=Ceļš
|
||||
|
||||
repo_path=Repozitoriju glabāšanas vieta
|
||||
log_root_path=Žurnalizēšanas direktorija
|
||||
repo_path=Repozitoriju glabāšanas ceļš
|
||||
log_root_path=Žurnalizēšanas ceļš
|
||||
|
||||
optional_title=Neobligātie iestatījumi
|
||||
smtp_host=SMTP resursdators
|
||||
federated_avatar_lookup_popup=Iespējot apvienoto profila bilžu meklētāju, lai izmantotu atvērtā koda apvienoto servisu balstītu uz libravatar.
|
||||
openid_signin=Iespējot OpenID autorizāciju
|
||||
openid_signin_popup=Iespējot lietotāju autorizāciju ar OpenID.
|
||||
enable_captcha_popup=Lietotājam reģistrējoties, pieprasīt ievadīt drošības kodu.
|
||||
admin_password=Parole
|
||||
confirm_password=Apstipriniet paroli
|
||||
|
|
|
|||
|
|
@ -1167,6 +1167,8 @@ branch.protected_deletion_failed=A branch '%s' está protegida. Ela não pode se
|
|||
|
||||
topic.manage_topics=Gerenciar Tópicos
|
||||
topic.done=Feito
|
||||
topic.count_prompt=Você não pode selecionar mais de 25 tópicos
|
||||
topic.format_prompt=Tópicos devem começar com uma letra ou um número, podem incluir hífens (-) e não devem ter mais de 35 caracteres
|
||||
|
||||
[org]
|
||||
org_name_holder=Nome da organização
|
||||
|
|
|
|||
|
|
@ -1167,6 +1167,8 @@ branch.protected_deletion_failed=Ветка '%s' защищена. Её нель
|
|||
|
||||
topic.manage_topics=Редактировать тематические метки
|
||||
topic.done=Сохранить
|
||||
topic.count_prompt=Вы не можете выбрать более 25 тем
|
||||
topic.format_prompt=Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов
|
||||
|
||||
[org]
|
||||
org_name_holder=Название организации
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
app_desc=Зручний сервіс, власного Git хостінгу
|
||||
app_desc=Зручний сервіс, власного Git хостингу
|
||||
|
||||
home=Головна
|
||||
dashboard=Панель управління
|
||||
|
|
@ -40,6 +40,7 @@ u2f_unsupported_browser=Ваш браузер не підтримує U2F клю
|
|||
u2f_error_1=Сталася невідома помилка. Спробуйте ще раз.
|
||||
u2f_error_2=Переконайтеся, що ви використовуєте зашифроване з'єднання (https://) та відвідуєте правильну URL-адресу.
|
||||
u2f_error_3=Сервер не може обробити, ваш запит.
|
||||
u2f_error_4=Представлений ключ не дає право на цей запит. Якщо спробуєте зареєструвати його, переконайтеся, що ключ ще не зареєстровано.
|
||||
u2f_error_5=Таймаут досягнуто до того, як ваш ключ можна буде прочитати. Перезавантажте, щоб повторити спробу.
|
||||
u2f_reload=Оновити
|
||||
|
||||
|
|
@ -74,7 +75,7 @@ cancel=Відмінити
|
|||
[install]
|
||||
install=Встановлення
|
||||
title=Початкова конфігурація
|
||||
docker_helper=Якщо ви запускаєте Gitea всередині Docker, будь ласка уважно прочитайте <a target="_blank" rel="noopener" href="%s">документацію</a> перед тим, як що-небудь змінити на цій сторінці.
|
||||
docker_helper=Якщо ви запускаєте Gitea всередині Docker, будь ласка уважно прочитайте <a target="_blank" rel="noopener" href="%s">документацію</a> перед тим, як щось змінити на цій сторінці.
|
||||
requite_db_desc=Gitea потребує MySQL, PostgreSQL, MSSQL, SQLite3 або TiDB.
|
||||
db_title=Налаштування бази даних
|
||||
db_type=Тип бази даних
|
||||
|
|
@ -145,6 +146,7 @@ confirm_password=Підтвердження пароля
|
|||
admin_email=Адреса електронної пошти
|
||||
install_btn_confirm=Встановлення Gitea
|
||||
test_git_failed=Не в змозі перевірити 'git' команду: %v
|
||||
sqlite3_not_available=Ця версія Gitea не підтримує SQLite3. Будь ласка, завантажте офіційну бінарну версію з %s (не версію gobuild).
|
||||
invalid_db_setting=Налаштування бази даних є некоректними: %v
|
||||
invalid_repo_path=Помилковий шлях до кореня репозиторію: %v
|
||||
save_config_failed=Не в змозі зберегти конфігурацію: %v
|
||||
|
|
@ -294,6 +296,8 @@ unable_verify_ssh_key=Не вдається підтвердити ключ SSH;
|
|||
auth_failed=Помилка автентифікації: %v
|
||||
|
||||
still_own_repo=Ваш обліковий запис володіє одним або декількома репозиторіями; видаліть або перенесіть їх в першу чергу.
|
||||
still_has_org=Ваш обліковий запис є учасником однієї чи декількох організацій; вийдіть з них в першу чергу.
|
||||
org_still_own_repo=Ця організація як і раніше володіє одним або декількома репозиторіями; спочатку видаліть або перенесіть їх.
|
||||
|
||||
target_branch_not_exist=Цільової гілки не існує.
|
||||
|
||||
|
|
@ -367,6 +371,7 @@ primary=Основний
|
|||
primary_email=Зробити основним
|
||||
delete_email=Видалити
|
||||
email_deletion=Видалити адресу електронної пошти
|
||||
email_deletion_success=Адресу електронної пошти було видалено.
|
||||
openid_deletion=Видалити адресу OpenID
|
||||
openid_deletion_success=Адреса OpenID була видалена.
|
||||
add_new_email=Додати нову адресу електронної пошти
|
||||
|
|
@ -400,6 +405,7 @@ add_gpg_key_success=GPG ключ '%s' додано.
|
|||
delete_key=Видалити
|
||||
ssh_key_deletion=Видалити SSH ключ
|
||||
gpg_key_deletion=Видалити GPG ключ
|
||||
ssh_key_deletion_desc=Видалення ключа SSH скасовує доступ до вашого облікового запису. Продовжити?
|
||||
gpg_key_deletion_desc=Видалення GPG ключа скасовує перевірку підписаних ним комітів. Продовжити?
|
||||
ssh_key_deletion_success=SSH було видалено.
|
||||
gpg_key_deletion_success=GPG було видалено.
|
||||
|
|
@ -593,6 +599,7 @@ commits.signed_by=Підписано
|
|||
commits.gpg_key_id=Ідентифікатор GPG ключа
|
||||
|
||||
ext_issues=Зов. Проблеми
|
||||
ext_issues.desc=Посилання на зовнішню систему відстеження проблем.
|
||||
|
||||
issues.new=Нова проблема
|
||||
issues.new.labels=Мітки
|
||||
|
|
@ -614,6 +621,7 @@ issues.new_label_desc_placeholder=Опис
|
|||
issues.create_label=Створити мітку
|
||||
issues.label_templates.title=Завантажити визначений набір міток
|
||||
issues.label_templates.helper=Оберіть набір міток
|
||||
issues.label_templates.use=Використовувати набір міток
|
||||
issues.label_templates.fail_to_load_file=Не вдалося завантажити файл шаблона мітки '%s': %v
|
||||
issues.add_label_at=додав(ла) мітку <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s
|
||||
issues.add_milestone_at=`додав(ла) до <b>%s</b> етапу %s`
|
||||
|
|
@ -621,6 +629,7 @@ issues.deleted_milestone=`(видалено)`
|
|||
issues.add_assignee_at=`був призначений <b>%s</b> %s`
|
||||
issues.remove_assignee_at=`видалили із призначених %s`
|
||||
issues.change_title_at=`змінив(ла) заголовок з <b>%s</b> на <b>%s</b> %s`
|
||||
issues.delete_branch_at=`видалена гілка <b>%s</b> %s`
|
||||
issues.open_tab=%d відкрито
|
||||
issues.close_tab=%d закрито
|
||||
issues.filter_label=Мітка
|
||||
|
|
@ -702,9 +711,11 @@ issues.start_tracking=Почати відстеження часу
|
|||
issues.start_tracking_history=`почав працювати %s`
|
||||
issues.tracking_already_started=`Ви вже почали відстежувати час для цієї <a href="%s"> проблеми</a>!`
|
||||
issues.stop_tracking=Стоп
|
||||
issues.stop_tracking_history=`перестав(-ла) працювати %s`
|
||||
issues.add_time=Вручну додати час
|
||||
issues.add_time_short=Додати час
|
||||
issues.add_time_cancel=Відмінити
|
||||
issues.add_time_history=`додав(-ла) витрачений час %s`
|
||||
issues.add_time_hours=Години
|
||||
issues.add_time_minutes=Хвилини
|
||||
issues.add_time_sum_to_small=Час не введено.
|
||||
|
|
@ -713,6 +724,8 @@ issues.cancel_tracking_history=`скасував відстеження часу
|
|||
issues.time_spent_total=Загальний витрачений час
|
||||
issues.time_spent_from_all_authors=`Загальний витрачений час: %s`
|
||||
issues.due_date=Дата завершення
|
||||
issues.invalid_due_date_format=Дата закінчення має бути в форматі 'ррр-мм-дд'.
|
||||
issues.error_modifying_due_date=Не вдалося змінити дату завершення.
|
||||
issues.due_date_form=рррр-мм-дд
|
||||
issues.due_date_form_add=Додати дату завершення
|
||||
issues.due_date_form_update=Оновити дату завершення
|
||||
|
|
@ -768,6 +781,7 @@ milestones.filter_sort.most_issues=Найбільш проблем
|
|||
milestones.filter_sort.least_issues=Найменш проблем
|
||||
|
||||
ext_wiki=Зов. Вікі
|
||||
ext_wiki.desc=Посилання на зовнішню вікі.
|
||||
|
||||
wiki=Вікі
|
||||
wiki.welcome=Ласкаво просимо до Вікі.
|
||||
|
|
@ -817,6 +831,7 @@ activity.closed_issue_label=Закрито
|
|||
activity.new_issues_count_1=Нова Проблема
|
||||
activity.new_issues_count_n=%d Проблем
|
||||
activity.new_issue_label=Відкриті
|
||||
activity.title.unresolved_conv_1=%d Незавершене обговорення
|
||||
activity.unresolved_conv_label=Відкрити
|
||||
activity.title.releases_1=%d Реліз
|
||||
activity.title.releases_n=%d Релізів
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/go-macaron/captcha"
|
||||
"github.com/markbates/goth"
|
||||
|
|
@ -474,7 +475,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
|
|||
return setting.AppSubURL + "/"
|
||||
}
|
||||
|
||||
if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
|
||||
if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) {
|
||||
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
|
||||
if obeyRedirect {
|
||||
ctx.RedirectToFirst(redirectTo)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user