From 9720f90905b20e18e6ca9c7715121533f7734d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Br=C3=B6ms?= <9416498+cez81@users.noreply.github.com> Date: Thu, 8 Feb 2018 04:29:42 +0100 Subject: [PATCH 001/106] Docs: Fix broken markdown with unescaped character (#3470) --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index a79da16b3..93b4da9d3 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -24,7 +24,7 @@ typically be found at `/etc/gitea/conf/app.ini`. The defaults provided here are best-effort (not built automatically). They are accurately recorded in [app.ini.sample](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample) -(s/master/). Any string in the format `%(X)s` is a feature powered +(s/master/\). Any string in the format `%(X)s` is a feature powered by [ini](https://github.com/go-ini/ini/#recursive-values), for reading values recursively. Values containing `#` or `;` must be quoted using `` ` `` or `"""`. @@ -118,7 +118,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `HOST`: **127.0.0.1:3306**: Database host address and port. - `NAME`: **gitea**: Database name. - `USER`: **root**: Database username. -- `PASSWD`: **\**: Database user password. Use \`your password\` for quoting if you use special characters in the password. +- `PASSWD`: **\**: Database user password. Use \`your password\` for quoting if you use special characters in the password. - `SSL_MODE`: **disable**: For PostgreSQL only. - `PATH`: **data/gitea.db**: For SQLite3 only, the database file path. From 011f128c892e86e753a8ac8d94d73e4676648db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Codru=C8=9B=20Constantin=20Gu=C8=99oi?= Date: Thu, 8 Feb 2018 15:43:08 +0000 Subject: [PATCH 002/106] Fixes missing avatars in offline mode (#3471) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Codruț Constantin Gușoi --- models/user.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/models/user.go b/models/user.go index ecfe3bca0..57abfc196 100644 --- a/models/user.go +++ b/models/user.go @@ -299,7 +299,9 @@ func (u *User) generateRandomAvatar(e Engine) error { } // NOTICE for random avatar, it still uses id as avatar name, but custom avatar use md5 // since random image is not a user's photo, there is no security for enumable - u.Avatar = fmt.Sprintf("%d", u.ID) + if u.Avatar == "" { + u.Avatar = fmt.Sprintf("%d", u.ID) + } if err = os.MkdirAll(filepath.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil { return fmt.Errorf("MkdirAll: %v", err) } From 58771acacbe33b8725397f99b5a5340d5cfbd1e8 Mon Sep 17 00:00:00 2001 From: Jonas Franz Date: Fri, 9 Feb 2018 14:11:19 +0100 Subject: [PATCH 003/106] Add EUPL v1.2 as license (Fixes go-gitea/gitea#3439) (#3475) Signed-off-by: Jonas Franz --- options/license/EUPL-1.2 | 190 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 options/license/EUPL-1.2 diff --git a/options/license/EUPL-1.2 b/options/license/EUPL-1.2 new file mode 100644 index 000000000..f44a4171e --- /dev/null +++ b/options/license/EUPL-1.2 @@ -0,0 +1,190 @@ +EUROPEAN UNION PUBLIC LICENCE v. 1.2 +EUPL © the European Union 2007, 2016 + +This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined below) which is provided under the +terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such +use is covered by a right of the copyright holder of the Work). +The Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following +notice immediately following the copyright notice for the Work: + Licensed under the EUPL +or has expressed by any other means his willingness to license under the EUPL. + +1.Definitions +In this Licence, the following terms have the following meaning: +— ‘The Licence’:this Licence. +— ‘The Original Work’:the work or software distributed or communicated by the Licensor under this Licence, available +as Source Code and also as Executable Code as the case may be. +— ‘Derivative Works’:the works or software that could be created by the Licensee, based upon the Original Work or +modifications thereof. This Licence does not define the extent of modification or dependence on the Original Work +required in order to classify a work as a Derivative Work; this extent is determined by copyright law applicable in +the country mentioned in Article 15. +— ‘The Work’:the Original Work or its Derivative Works. +— ‘The Source Code’:the human-readable form of the Work which is the most convenient for people to study and +modify. +— ‘The Executable Code’:any code which has generally been compiled and which is meant to be interpreted by +a computer as a program. +— ‘The Licensor’:the natural or legal person that distributes or communicates the Work under the Licence. +— ‘Contributor(s)’:any natural or legal person who modifies the Work under the Licence, or otherwise contributes to +the creation of a Derivative Work. +— ‘The Licensee’ or ‘You’:any natural or legal person who makes any usage of the Work under the terms of the +Licence. +— ‘Distribution’ or ‘Communication’:any act of selling, giving, lending, renting, distributing, communicating, +transmitting, or otherwise making available, online or offline, copies of the Work or providing access to its essential +functionalities at the disposal of any other natural or legal person. + +2.Scope of the rights granted by the Licence +The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, sublicensable licence to do the following, for +the duration of copyright vested in the Original Work: +— use the Work in any circumstance and for all usage, +— reproduce the Work, +— modify the Work, and make Derivative Works based upon the Work, +— communicate to the public, including the right to make available or display the Work or copies thereof to the public +and perform publicly, as the case may be, the Work, +— distribute the Work or copies thereof, +— lend and rent the Work or copies thereof, +— sublicense rights in the Work or copies thereof. +Those rights can be exercised on any media, supports and formats, whether now known or later invented, as far as the +applicable law permits so. +In the countries where moral rights apply, the Licensor waives his right to exercise his moral right to the extent allowed +by law in order to make effective the licence of the economic rights here above listed. +The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to any patents held by the Licensor, to the +extent necessary to make use of the rights granted on the Work under this Licence. + +3.Communication of the Source Code +The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as +Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with +each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to +the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to +distribute or communicate the Work. + +4.Limitations on copyright +Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the +exclusive rights of the rights owners in the Work, of the exhaustion of those rights or of other applicable limitations +thereto. + +5.Obligations of the Licensee +The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those +obligations are the following: + +Attribution right: The Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to +the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the +Licence with every copy of the Work he/she distributes or communicates. The Licensee must cause any Derivative Work +to carry prominent notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes or communicates copies of the Original Works or Derivative Works, this +Distribution or Communication will be done under the terms of this Licence or of a later version of this Licence unless +the Original Work is expressly distributed only under this version of the Licence — for example by communicating +‘EUPL v. 1.2 only’. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the +Work or Derivative Work that alter or restrict the terms of the Licence. + +Compatibility clause: If the Licensee Distributes or Communicates Derivative Works or copies thereof based upon both +the Work and another work licensed under a Compatible Licence, this Distribution or Communication can be done +under the terms of this Compatible Licence. For the sake of this clause, ‘Compatible Licence’ refers to the licences listed +in the appendix attached to this Licence. Should the Licensee's obligations under the Compatible Licence conflict with +his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail. + +Provision of Source Code: When distributing or communicating copies of the Work, the Licensee will provide +a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available +for as long as the Licensee continues to distribute or communicate the Work. +Legal Protection: This Licence does not grant permission to use the trade names, trademarks, service marks, or names +of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and +reproducing the content of the copyright notice. + +6.Chain of Authorship +The original Licensor warrants that the copyright in the Original Work granted hereunder is owned by him/her or +licensed to him/her and that he/she has the power and authority to grant the Licence. +Each Contributor warrants that the copyright in the modifications he/she brings to the Work are owned by him/her or +licensed to him/her and that he/she has the power and authority to grant the Licence. +Each time You accept the Licence, the original Licensor and subsequent Contributors grant You a licence to their contributions +to the Work, under the terms of this Licence. + +7.Disclaimer of Warranty +The Work is a work in progress, which is continuously improved by numerous Contributors. It is not a finished work +and may therefore contain defects or ‘bugs’ inherent to this type of development. +For the above reason, the Work is provided under the Licence on an ‘as is’ basis and without warranties of any kind +concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or +errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this +Licence. +This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work. + +8.Disclaimer of Liability +Except in the cases of wilful misconduct or damages directly caused to natural persons, the Licensor will in no event be +liable for any direct or indirect, material or moral, damages of any kind, arising out of the Licence or of the use of the +Work, including without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, loss +of data or any commercial damage, even if the Licensor has been advised of the possibility of such damage. However, +the Licensor will be liable under statutory product liability laws as far such laws apply to the Work. + +9.Additional agreements +While distributing the Work, You may choose to conclude an additional agreement, defining obligations or services +consistent with this Licence. However, if accepting obligations, You may act only on your own behalf and on your sole +responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by +the fact You have accepted any warranty or additional liability. + +10.Acceptance of the Licence +The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ placed under the bottom of a window +displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of +applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms +and conditions. +Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You +by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution +or Communication by You of the Work or copies thereof. + +11.Information to the public +In case of any Distribution or Communication of the Work by means of electronic communication by You (for example, +by offering to download the Work from a remote location) the distribution channel or media (for example, a website) +must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence +and the way it may be accessible, concluded, stored and reproduced by the Licensee. + +12.Termination of the Licence +The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms +of the Licence. +Such a termination will not terminate the licences of any person who has received the Work from the Licensee under +the Licence, provided such persons remain in full compliance with the Licence. + +13.Miscellaneous +Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the +Work. +If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or +enforceability of the Licence as a whole. Such provision will be construed or reformed so as necessary to make it valid +and enforceable. +The European Commission may publish other linguistic versions or new versions of this Licence or updated versions of +the Appendix, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. +New versions of the Licence will be published with a unique version number. +All linguistic versions of this Licence, approved by the European Commission, have identical value. Parties can take +advantage of the linguistic version of their choice. + +14.Jurisdiction +Without prejudice to specific agreement between parties, +— any litigation resulting from the interpretation of this License, arising between the European Union institutions, +bodies, offices or agencies, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice +of the European Union, as laid down in article 272 of the Treaty on the Functioning of the European Union, +— any litigation arising between other parties and resulting from the interpretation of this License, will be subject to +the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business. + +15.Applicable Law +Without prejudice to specific agreement between parties, +— this Licence shall be governed by the law of the European Union Member State where the Licensor has his seat, +resides or has his registered office, +— this licence shall be governed by Belgian law if the Licensor has no seat, residence or registered office inside +a European Union Member State. + + + Appendix + +‘Compatible Licences’ according to Article 5 EUPL are: +— GNU General Public License (GPL) v. 2, v. 3 +— GNU Affero General Public License (AGPL) v. 3 +— Open Software License (OSL) v. 2.1, v. 3.0 +— Eclipse Public License (EPL) v. 1.0 +— CeCILL v. 2.0, v. 2.1 +— Mozilla Public Licence (MPL) v. 2 +— GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 +— Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for works other than software +— European Union Public Licence (EUPL) v. 1.1, v. 1.2 +— Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+). + +The European Commission may update this Appendix to later versions of the above licences without producing +a new version of the EUPL, as long as they provide the rights granted in Article 2 of this Licence and protect the +covered Source Code from exclusive appropriation. +All other changes or additions to this Appendix require the production of a new EUPL version. From 6eaeb01ecf1471517bbd4882ab7450f4f45a6f1c Mon Sep 17 00:00:00 2001 From: Ethan Koenig Date: Sat, 10 Feb 2018 10:19:26 -0800 Subject: [PATCH 004/106] Update code.gitea.io/git (#3482) --- models/git_diff.go | 12 ++++- models/repo_indexer.go | 52 +++++-------------- vendor/code.gitea.io/git/parse.go | 81 ++++++++++++++++++++++++++++++ vendor/code.gitea.io/git/tree.go | 83 +------------------------------ vendor/vendor.json | 6 +-- 5 files changed, 108 insertions(+), 126 deletions(-) create mode 100644 vendor/code.gitea.io/git/parse.go diff --git a/models/git_diff.go b/models/git_diff.go index 9e361d05f..7b0b672ff 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -14,6 +14,7 @@ import ( "io/ioutil" "os" "os/exec" + "strconv" "strings" "code.gitea.io/git" @@ -368,8 +369,15 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D a := line[beg+2 : middle] b := line[middle+3:] if hasQuote { - a = string(git.UnescapeChars([]byte(a[1 : len(a)-1]))) - b = string(git.UnescapeChars([]byte(b[1 : len(b)-1]))) + var err error + a, err = strconv.Unquote(a) + if err != nil { + return nil, fmt.Errorf("Unquote: %v", err) + } + b, err = strconv.Unquote(b) + if err != nil { + return nil, fmt.Errorf("Unquote: %v", err) + } } curFile = &DiffFile{ diff --git a/models/repo_indexer.go b/models/repo_indexer.go index ecd629587..b4f7bf1bd 100644 --- a/models/repo_indexer.go +++ b/models/repo_indexer.go @@ -231,43 +231,17 @@ func addDelete(filename string, repo *Repository, batch rupture.FlushingBatch) e } // parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command -func parseGitLsTreeOutput(stdout string) ([]fileUpdate, error) { - lines := strings.Split(stdout, "\n") - updates := make([]fileUpdate, 0, len(lines)) - for _, line := range lines { - // expect line to be " \t" - line = strings.TrimSpace(line) - if len(line) == 0 { - continue +func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) { + entries, err := git.ParseTreeEntries(stdout) + if err != nil { + return nil, err + } + updates := make([]fileUpdate, len(entries)) + for i, entry := range entries { + updates[i] = fileUpdate{ + Filename: entry.Name(), + BlobSha: entry.ID.String(), } - firstSpaceIndex := strings.IndexByte(line, ' ') - if firstSpaceIndex < 0 { - log.Error(4, "Misformatted git ls-tree output: %s", line) - continue - } - tabIndex := strings.IndexByte(line, '\t') - if tabIndex < 42+firstSpaceIndex || tabIndex == len(line)-1 { - log.Error(4, "Misformatted git ls-tree output: %s", line) - continue - } - if objectType := line[firstSpaceIndex+1 : tabIndex-41]; objectType != "blob" { - // submodules appear as commit objects, we do not index submodules - continue - } - - blobSha := line[tabIndex-40 : tabIndex] - filename := line[tabIndex+1:] - if filename[0] == '"' { - var err error - filename, err = strconv.Unquote(filename) - if err != nil { - return nil, err - } - } - updates = append(updates, fileUpdate{ - Filename: filename, - BlobSha: blobSha, - }) } return updates, nil } @@ -276,7 +250,7 @@ func parseGitLsTreeOutput(stdout string) ([]fileUpdate, error) { func genesisChanges(repo *Repository, revision string) (*repoChanges, error) { var changes repoChanges stdout, err := git.NewCommand("ls-tree", "--full-tree", "-r", revision). - RunInDir(repo.RepoPath()) + RunInDirBytes(repo.RepoPath()) if err != nil { return nil, err } @@ -327,11 +301,11 @@ func nonGenesisChanges(repo *Repository, revision string) (*repoChanges, error) cmd := git.NewCommand("ls-tree", "--full-tree", revision, "--") cmd.AddArguments(updatedFilenames...) - stdout, err = cmd.RunInDir(repo.RepoPath()) + lsTreeStdout, err := cmd.RunInDirBytes(repo.RepoPath()) if err != nil { return nil, err } - changes.Updates, err = parseGitLsTreeOutput(stdout) + changes.Updates, err = parseGitLsTreeOutput(lsTreeStdout) return &changes, err } diff --git a/vendor/code.gitea.io/git/parse.go b/vendor/code.gitea.io/git/parse.go new file mode 100644 index 000000000..5c964f16e --- /dev/null +++ b/vendor/code.gitea.io/git/parse.go @@ -0,0 +1,81 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "bytes" + "fmt" + "strconv" +) + +// ParseTreeEntries parses the output of a `git ls-tree` command. +func ParseTreeEntries(data []byte) ([]*TreeEntry, error) { + return parseTreeEntries(data, nil) +} + +func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) { + entries := make([]*TreeEntry, 0, 10) + for pos := 0; pos < len(data); { + // expect line to be of the form " \t" + entry := new(TreeEntry) + entry.ptree = ptree + if pos+6 > len(data) { + return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data)) + } + switch string(data[pos : pos+6]) { + case "100644": + entry.mode = EntryModeBlob + entry.Type = ObjectBlob + pos += 12 // skip over "100644 blob " + case "100755": + entry.mode = EntryModeExec + entry.Type = ObjectBlob + pos += 12 // skip over "100755 blob " + case "120000": + entry.mode = EntryModeSymlink + entry.Type = ObjectBlob + pos += 12 // skip over "120000 blob " + case "160000": + entry.mode = EntryModeCommit + entry.Type = ObjectCommit + pos += 14 // skip over "160000 object " + case "040000": + entry.mode = EntryModeTree + entry.Type = ObjectTree + pos += 12 // skip over "040000 tree " + default: + return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+6])) + } + + if pos+40 > len(data) { + return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data)) + } + id, err := NewIDFromString(string(data[pos : pos+40])) + if err != nil { + return nil, fmt.Errorf("Invalid ls-tree output: %v", err) + } + entry.ID = id + pos += 41 // skip over sha and trailing space + + end := pos + bytes.IndexByte(data[pos:], '\n') + if end < pos { + return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data)) + } + + // In case entry name is surrounded by double quotes(it happens only in git-shell). + if data[pos] == '"' { + entry.name, err = strconv.Unquote(string(data[pos:end])) + if err != nil { + return nil, fmt.Errorf("Invalid ls-tree output: %v", err) + } + } else { + entry.name = string(data[pos:end]) + } + + pos = end + 1 + entries = append(entries, entry) + } + return entries, nil +} diff --git a/vendor/code.gitea.io/git/tree.go b/vendor/code.gitea.io/git/tree.go index 05e7afd12..4654dac30 100644 --- a/vendor/code.gitea.io/git/tree.go +++ b/vendor/code.gitea.io/git/tree.go @@ -5,8 +5,6 @@ package git import ( - "bytes" - "fmt" "strings" ) @@ -30,84 +28,6 @@ func NewTree(repo *Repository, id SHA1) *Tree { } } -var escapeChar = []byte("\\") - -// UnescapeChars reverses escaped characters. -func UnescapeChars(in []byte) []byte { - if bytes.Index(in, escapeChar) == -1 { - return in - } - - endIdx := len(in) - 1 - isEscape := false - out := make([]byte, 0, endIdx+1) - for i := range in { - if in[i] == '\\' && !isEscape { - isEscape = true - continue - } - isEscape = false - out = append(out, in[i]) - } - return out -} - -// parseTreeData parses tree information from the (uncompressed) raw -// data from the tree object. -func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) { - entries := make([]*TreeEntry, 0, 10) - l := len(data) - pos := 0 - for pos < l { - entry := new(TreeEntry) - entry.ptree = tree - step := 6 - switch string(data[pos : pos+step]) { - case "100644": - entry.mode = EntryModeBlob - entry.Type = ObjectBlob - case "100755": - entry.mode = EntryModeExec - entry.Type = ObjectBlob - case "120000": - entry.mode = EntryModeSymlink - entry.Type = ObjectBlob - case "160000": - entry.mode = EntryModeCommit - entry.Type = ObjectCommit - - step = 8 - case "040000": - entry.mode = EntryModeTree - entry.Type = ObjectTree - default: - return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+step])) - } - pos += step + 6 // Skip string type of entry type. - - step = 40 - id, err := NewIDFromString(string(data[pos : pos+step])) - if err != nil { - return nil, err - } - entry.ID = id - pos += step + 1 // Skip half of SHA1. - - step = bytes.IndexByte(data[pos:], '\n') - - // In case entry name is surrounded by double quotes(it happens only in git-shell). - if data[pos] == '"' { - entry.name = string(UnescapeChars(data[pos+1 : pos+step-1])) - } else { - entry.name = string(data[pos : pos+step]) - } - - pos += step + 1 - entries = append(entries, entry) - } - return entries, nil -} - // SubTree get a sub tree by the sub dir path func (t *Tree) SubTree(rpath string) (*Tree, error) { if len(rpath) == 0 { @@ -142,12 +62,11 @@ func (t *Tree) ListEntries() (Entries, error) { if t.entriesParsed { return t.entries, nil } - t.entriesParsed = true stdout, err := NewCommand("ls-tree", t.ID.String()).RunInDirBytes(t.repo.Path) if err != nil { return nil, err } - t.entries, err = parseTreeData(t, stdout) + t.entries, err = parseTreeEntries(stdout, t) return t.entries, err } diff --git a/vendor/vendor.json b/vendor/vendor.json index 520cf8e22..7397cac40 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -3,10 +3,10 @@ "ignore": "test appengine", "package": [ { - "checksumSHA1": "Gz+a5Qo4PCiB/Gf2f02v8HEAxDM=", + "checksumSHA1": "j6YyQxuOYRs94MVEamvnbE6ZtD0=", "path": "code.gitea.io/git", - "revision": "6798d0f202cdc7187c00a467b586a4bdee27e8c9", - "revisionTime": "2018-01-14T14:37:32Z" + "revision": "827f97aaaa6a4ab5c31b1b799c56687a8cf6aade", + "revisionTime": "2018-02-10T03:05:43Z" }, { "checksumSHA1": "Qtq0kW+BnpYMOriaoCjMa86WGG8=", From 2cb4649acf73ce9a7b6c2b3f707673d89a789f46 Mon Sep 17 00:00:00 2001 From: Jonas Franz Date: Sun, 11 Feb 2018 14:42:28 +0100 Subject: [PATCH 005/106] Escape search query (#3486) Signed-off-by: Jonas Franz --- modules/templates/helper.go | 7 +++++++ templates/repo/search.tmpl | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/templates/helper.go b/modules/templates/helper.go index d6be25ceb..3f3d6083f 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -27,6 +27,7 @@ import ( "golang.org/x/net/html/charset" "golang.org/x/text/transform" "gopkg.in/editorconfig/editorconfig-core-go.v1" + "html" ) // NewFuncMap returns functions for injecting to templates @@ -179,6 +180,7 @@ func NewFuncMap() []template.FuncMap { return dict, nil }, "Printf": fmt.Sprintf, + "Escape": Escape, }} } @@ -197,6 +199,11 @@ func Str2html(raw string) template.HTML { return template.HTML(markup.Sanitize(raw)) } +// Escape escapes a HTML string +func Escape(raw string) string { + return html.EscapeString(raw) +} + // List traversings the list func List(l *list.List) chan interface{} { e := l.Front() diff --git a/templates/repo/search.tmpl b/templates/repo/search.tmpl index 19a9d4474..3ddc5de86 100644 --- a/templates/repo/search.tmpl +++ b/templates/repo/search.tmpl @@ -14,7 +14,7 @@ {{if .Keyword}}

- {{.i18n.Tr "repo.search.results" .Keyword .RepoLink .RepoName | Str2html}} + {{.i18n.Tr "repo.search.results" (.Keyword|Escape) .RepoLink .RepoName | Str2html }}

JavaScript licenses - API + {{if .EnableSwaggerEndpoint}}API{{end}} {{.i18n.Tr "website"}} {{if (or .ShowFooterVersion .PageIsAdmin)}}{{GoVer}}{{end}} From 869d73a25c1b8c8399f14389916780e72eb792f0 Mon Sep 17 00:00:00 2001 From: Richard Coleman Date: Fri, 16 Feb 2018 01:56:10 +0000 Subject: [PATCH 010/106] Add info from #2286, minor fixes to YAML indentation (#3338) * Add info from #2286, minor fixes to YAML indentation * Add space to make YAML valid again --- .../doc/installation/with-docker.en-us.md | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/content/doc/installation/with-docker.en-us.md b/docs/content/doc/installation/with-docker.en-us.md index c47639148..efcb56b3e 100644 --- a/docs/content/doc/installation/with-docker.en-us.md +++ b/docs/content/doc/installation/with-docker.en-us.md @@ -28,6 +28,8 @@ the official [install instructions](https://docs.docker.com/compose/install/). The most simple setup just creates a volume and a network and starts the `gitea/gitea:latest` image as a service. Since there is no database available one can be initialized using SQLite3. Create a directory like `gitea` and paste the following content into a file named `docker-compose.yml`. +Note that the volume should be owned by the user/group with the UID/GID specified in the config file. +If you don't give the volume correct permissions, the container may not start. ```yaml version: "2" @@ -39,6 +41,9 @@ networks: services: server: image: gitea/gitea:latest + environment: + - USER_UID=1000 + - USER_GID=1000 restart: always networks: - gitea @@ -65,6 +70,9 @@ networks: services: server: image: gitea/gitea:latest + environment: + - USER_UID=1000 + - USER_GID=1000 restart: always networks: - gitea @@ -92,6 +100,9 @@ networks: services: server: image: gitea/gitea:latest + environment: + - USER_UID=1000 + - USER_GID=1000 restart: always networks: - gitea @@ -132,14 +143,17 @@ networks: services: server: image: gitea/gitea:latest + environment: + - USER_UID=1000 + - USER_GID=1000 restart: always networks: - gitea volumes: - ./gitea:/data - ports: - - "3000:3000" - - "222:22" + ports: + - "3000:3000" + - "222:22" + depends_on: + - db + @@ -160,7 +174,8 @@ services: To use named volumes instead of host volumes, define and use the named volume within the `docker-compose.yml` configuration. This change will automatically -create the required volume. +create the required volume. You don't need to worry about permissions with +named volumes, Docker will deal with that automatically. ```diff version: "2" From 4b48a45bacdb3ddedad41d739d1b45bc0eb9ac17 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 16 Feb 2018 01:57:33 +0000 Subject: [PATCH 011/106] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 7 ------- 1 file changed, 7 deletions(-) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 3d11c5eef..9583b9f1c 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -63,7 +63,6 @@ cancel=キャンセル install=インストール title=初期設定 docker_helper=DockerでGiteaを稼動する場合は、このページに変更を加える前に、 ガイドラインをよく読んでください。 -requite_db_desc=Gitea には、MySQL、PostgreSQL、SQLite3、または TiDB が必要です。 db_title=データベース設定 db_type=データベースの種類 host=ホスト @@ -709,7 +708,6 @@ issues.label_deletion_success=ラベルは正常に削除されました。 issues.label.filter_sort.alphabetically=アルファベット順 issues.label.filter_sort.reverse_alphabetically=逆アルファベット順 issues.label.filter_sort.by_size=サイズ -issues.label.filter_sort.reverse_by_size=長さの逆順 issues.num_participants=参加者数 %d issues.attachment.open_tab=`クリックして新しいタブで "%s" を見る` issues.attachment.download=`クリックして "%s" をダウンロード` @@ -1208,16 +1206,12 @@ dashboard.delete_inactivate_accounts=非アクティブのアカウントをす dashboard.delete_inactivate_accounts_success=すべての非アクティブなアカウントは削除されました。 dashboard.delete_repo_archives=リポジトリのすべてのアーカイブを削除 dashboard.delete_repo_archives_success=リポジトリのすべてのアーカイブが削除されました。 -dashboard.delete_missing_repos=Gitファイルが失われたリポジトリのすべてのレコードを削除 -dashboard.delete_missing_repos_success=Gitファイルが削除されたリポジトリのすべてのレコードが削除されました。 dashboard.git_gc_repos=すべてのリポジトリでガベージコレクションを実行 dashboard.git_gc_repos_success=すべてのリポジトリでガベージコレクションが実行されました。 dashboard.resync_all_sshkeys=GiteaのSSHキーのために'.ssh/authorized_keys'ファイルを再生成する。内蔵SSHサーバーを使っている場合は、これを行う必要はありません。 dashboard.resync_all_sshkeys_success=Giteaが管理するすべての公開鍵が書き込まれました。 dashboard.resync_all_hooks=すべてリポジトリの pre-receive, update, post-receive フックを更新する。 dashboard.resync_all_hooks_success=すべてリポジトリの pre-receive, update, post-receive フックが更新されました。 -dashboard.reinit_missing_repos=レコードの存在するすべての失われたGitリポジトリを再初期化する -dashboard.reinit_missing_repos_success=レコードの存在するすべての失われたGitリポジトリが再初期化されました。 dashboard.sync_external_users=外部ユーザーデータの同期 dashboard.sync_external_users_started=外部ユーザーの同期を開始しました dashboard.server_uptime=サーバーの稼働時間 @@ -1295,7 +1289,6 @@ repos.private=プライベート repos.watches=ウォッチ repos.stars=お気に入り repos.issues=課題 -repos.size=容量 auths.auth_manage_panel=認証管理パネル auths.new=新しいソースを追加 From 9303fc2015ac7eff7192ffe56d8a27488f81a03a Mon Sep 17 00:00:00 2001 From: bugreport0 <32939607+bugreport0@users.noreply.github.com> Date: Sat, 17 Feb 2018 00:32:40 +1030 Subject: [PATCH 012/106] Fix ellipses, 'a[n]' and 'username' (issue #3512). (#3518) --- options/locale/locale_en-US.ini | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index d676aabe4..a7c338c10 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -17,7 +17,7 @@ page = Page template = Template language = Language notifications = Notifications -create_new = Create... +create_new = Create… user_profile_and_more = User profile and more signed_in_as = Signed in as enable_javascript = This website works better with JavaScript @@ -155,12 +155,12 @@ uname_holder = Username or email password_holder = Password switch_dashboard_context = Switch Dashboard Context my_repos = My Repositories -show_more_repos = Show more repositories ... +show_more_repos = Show more repositories… collaborative_repos = Collaborative Repositories my_orgs = My Organizations my_mirrors = My Mirrors view_home = View %s -search_repos = Find a repository ... +search_repos = Find a repository… issues.in_your_repos = In your repositories @@ -249,7 +249,7 @@ Content = Content require_error = ` cannot be empty.` alpha_dash_error = ` must be valid alphanumeric or dash(-_) characters.` alpha_dash_dot_error = ` must be valid alphanumeric, dash(-_) or dot characters.` -git_ref_name_error = ` must be well formed git reference name.` +git_ref_name_error = ` must be a well formed git reference name.` size_error = ` must be size %s.` min_size_error = ` must contain at least %s characters.` max_size_error = ` must contain at most %s characters.` @@ -335,7 +335,7 @@ enable_custom_avatar = Use Custom Avatar choose_new_avatar = Choose new avatar update_avatar = Update Avatar Setting delete_current_avatar = Delete Current Avatar -uploaded_avatar_not_a_image = Uploaded file is not a image. +uploaded_avatar_not_a_image = Uploaded file is not an image. update_avatar_success = Your avatar setting has been updated. change_password = Change Password @@ -565,7 +565,7 @@ editor.fork_before_edit = You must fork this repository before editing the file editor.delete_this_file = Delete this file editor.must_have_write_access = You must have write access to make or propose changes to this file editor.file_delete_success = File '%s' has been deleted successfully! -editor.name_your_file = Name your file... +editor.name_your_file = Name your file… editor.filename_help = To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace. editor.or = or editor.cancel_lower = cancel @@ -574,10 +574,10 @@ editor.add_tmpl = Add '%s/' editor.add = Add '%s' editor.update = Update '%s' editor.delete = Delete '%s' -editor.commit_message_desc = Add an optional extended description... +editor.commit_message_desc = Add an optional extended description… editor.commit_directly_to_this_branch = Commit directly to the %s branch. editor.create_new_branch = Create a new branch for this commit and start a pull request. -editor.new_branch_name_desc = New branch name... +editor.new_branch_name_desc = New branch name… editor.cancel = Cancel editor.filename_cannot_be_empty = Filename cannot be empty. editor.branch_already_exists = Branch '%s' already exists in this repository. @@ -589,7 +589,7 @@ editor.file_changed_while_editing = The file content has been changed since you editor.file_already_exists = A file with name '%s' already exists in this repository. editor.no_changes_to_show = There are no changes to show. editor.fail_to_update_file = Failed to update/create file '%s' with error: %v -editor.add_subdir = Add subdirectory... +editor.add_subdir = Add subdirectory… editor.unable_to_upload_files = Failed to upload files to '%s' with error: %v editor.upload_files_to_dir = Upload files to '%s' editor.cannot_commit_to_protected_branch = Can not commit to protected branch '%s'. @@ -626,7 +626,7 @@ issues.new.no_assignee = No assignee issues.no_ref = No Branch/Tag Specified issues.create = Create Issue issues.new_label = New Label -issues.new_label_placeholder = Label name... +issues.new_label_placeholder = Label name… issues.create_label = Create Label issues.label_templates.title = Load a predefined set of labels issues.label_templates.info = There are not any labels yet. You can click on the "New Label" button above to create one or use a predefined set below. @@ -897,7 +897,7 @@ settings.tracker_url_format = External Issue Tracker URL Format settings.tracker_issue_style = External Issue Tracker Naming Style: settings.tracker_issue_style.numeric = Numeric settings.tracker_issue_style.alphanumeric = Alphanumeric -settings.tracker_url_format_desc = You can use placeholder {user} {repo} {index} for user name, repository name and issue index. +settings.tracker_url_format_desc = You can use placeholder {user} {repo} {index} for username, repository name and issue index. settings.enable_timetracker = Enable time tracker settings.allow_only_contributors_to_track_time = Allow only contributors to track time settings.pulls_desc = Enable pull requests to accept public contributions @@ -914,7 +914,7 @@ settings.convert_confirm = Confirm Conversion settings.convert_succeed = Repository has been converted to a regular repository. settings.transfer = Transfer Ownership settings.transfer_desc = Transfer this repository to another user or to an organization in which you have admin rights. -settings.transfer_notices_1 = - You will lose access if the new owner is a individual user. +settings.transfer_notices_1 = - You will lose access if the new owner is an individual user. settings.transfer_notices_2 = - You will preserve access if the new owner is an organization and if you're one of the owners. settings.transfer_form_title = Please enter the following information to confirm your operation: settings.wiki_delete = Erase Wiki Data @@ -938,7 +938,7 @@ settings.delete_collaborator = Delete settings.collaborator_deletion = Collaborator Deletion settings.collaborator_deletion_desc = This user will no longer have collaboration access to this repository after deletion. Do you want to continue? settings.remove_collaborator_success = Collaborator has been removed. -settings.search_user_placeholder = Search user... +settings.search_user_placeholder = Search user… settings.org_not_allowed_to_be_collaborator = Organization is not allowed to be added as a collaborator. settings.user_is_org_member = User is organization member who cannot be added as a collaborator. settings.add_webhook = Add Webhook @@ -1029,7 +1029,7 @@ settings.remove_protected_branch_success= Branch %s protect options removed succ settings.protected_branch_deletion=To delete a protected branch settings.protected_branch_deletion_desc=Anyone with write permissions will be able to push directly to this branch. Are you sure? settings.default_branch_desc = The default branch is considered the "base" branch in your repository against which all pull requests and code commits are automatically made, unless you specify a different branch. -settings.choose_branch = Choose a branch... +settings.choose_branch = Choose a branch… settings.no_protected_branch = There are no protected branches diff.browse_source = Browse Source @@ -1063,7 +1063,7 @@ release.title = Title release.content = Content release.write = Write release.preview = Preview -release.loading = Loading... +release.loading = Loading… release.prerelease_desc = This is a pre-release release.prerelease_helper = We'll point out that this release is not production-ready. release.cancel = Cancel @@ -1177,7 +1177,7 @@ teams.read_permission_desc = This team grants Read access: memb teams.write_permission_desc = This team grants Write access: members can read from and push to the team's repositories. teams.admin_permission_desc = This team grants Admin access: members can read from, push to, and add collaborators to the team's repositories. teams.repositories = Team Repositories -teams.search_repo_placeholder = Search repository... +teams.search_repo_placeholder = Search repository… teams.add_team_repository = Add Team Repository teams.remove_repo = Remove teams.add_nonexistent_repo = "The repository you're trying to add does not exist; please create it first." @@ -1316,7 +1316,7 @@ auths.bind_password_helper = Warning: This password is stored in plain text. It auths.user_base = User Search Base auths.user_dn = User DN auths.attribute_username = Username attribute -auths.attribute_username_placeholder = Leave empty to use sign-in form field value for user name. +auths.attribute_username_placeholder = Leave empty to use sign-in form field value for username. auths.attribute_name = First name attribute auths.attribute_surname = Surname attribute auths.attribute_mail = Email attribute From b29c3583156ad51d57e24c62eb540290410e9608 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 16 Feb 2018 14:03:54 +0000 Subject: [PATCH 013/106] [skip ci] Updated translations via Crowdin --- options/locale/locale_ru-RU.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 39a59fd5c..de8e20abf 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -1061,7 +1061,7 @@ release.target=Цель release.tag_helper=Выберите существующий тег, или создайте новый. release.title=Заголовок release.content=Содержимое -release.write=Запись +release.write=Редактирование release.preview=Предварительный просмотр release.loading=Загрузка... release.prerelease_desc=Это предварительный релиз From 02bc92a5c9dd2e5123c0d7a6946b3ebd5e5a8dda Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Sun, 18 Feb 2018 16:38:50 +0200 Subject: [PATCH 014/106] Fix app.ini sample file link in docs (#3529) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lauris Bukšis-Haberkorns --- docs/content/page/index.en-us.md | 2 +- docs/content/page/index.fr-fr.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/page/index.en-us.md b/docs/content/page/index.en-us.md index 0f22fcfe5..85bcc772a 100644 --- a/docs/content/page/index.en-us.md +++ b/docs/content/page/index.en-us.md @@ -74,7 +74,7 @@ Windows, on architectures like amd64, i386, ARM, PowerPC, and others. - MSSQL - TiDB (experimental, not recommended) - Configuration file - - [app.ini](https://github.com/go-gitea/gitea/blob/master/conf/app.ini) + - [app.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample) - Admin panel - Statistics - Actions diff --git a/docs/content/page/index.fr-fr.md b/docs/content/page/index.fr-fr.md index 6876b6697..bb7fb5bfe 100755 --- a/docs/content/page/index.fr-fr.md +++ b/docs/content/page/index.fr-fr.md @@ -69,7 +69,7 @@ Le but de ce projet est de fournir de la manière la plus simple, la plus rapide - MSSQL - [TiDB](https://github.com/pingcap/tidb) (expérimental) - Fichier de configuration - - Voir [ici](https://github.com/go-gitea/gitea/blob/master/conf/app.ini) + - Voir [ici](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample) - Panel d'administration - Statistiques - Actions From e59fe7c8d9eb8e49858cb2d59e8732f6058756ff Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 18 Feb 2018 14:39:52 +0000 Subject: [PATCH 015/106] [skip ci] Updated translations via Crowdin --- options/locale/locale_bg-BG.ini | 12 ------------ options/locale/locale_cs-CZ.ini | 12 ------------ options/locale/locale_de-DE.ini | 21 +++++++++------------ options/locale/locale_es-ES.ini | 16 ---------------- options/locale/locale_fi-FI.ini | 11 ----------- options/locale/locale_fr-FR.ini | 17 ----------------- options/locale/locale_hu-HU.ini | 28 ++++++++++++++-------------- options/locale/locale_id-ID.ini | 17 ----------------- options/locale/locale_it-IT.ini | 12 ------------ options/locale/locale_ja-JP.ini | 17 ----------------- options/locale/locale_ko-KR.ini | 16 ---------------- options/locale/locale_lt-LT.ini | 3 --- options/locale/locale_lv-LV.ini | 17 ----------------- options/locale/locale_nb-NO.ini | 1 - options/locale/locale_nl-NL.ini | 17 ----------------- options/locale/locale_no-NO.ini | 1 - options/locale/locale_pl-PL.ini | 17 ----------------- options/locale/locale_pt-BR.ini | 17 ----------------- options/locale/locale_ru-RU.ini | 17 ----------------- options/locale/locale_sr-SP.ini | 12 ------------ options/locale/locale_sv-SE.ini | 16 ---------------- options/locale/locale_tr-TR.ini | 17 ----------------- options/locale/locale_uk-UA.ini | 5 ----- options/locale/locale_zh-CN.ini | 17 ----------------- options/locale/locale_zh-HK.ini | 17 ----------------- options/locale/locale_zh-TW.ini | 17 ----------------- 26 files changed, 23 insertions(+), 347 deletions(-) diff --git a/options/locale/locale_bg-BG.ini b/options/locale/locale_bg-BG.ini index ec57d5bf4..7b3fef8fa 100644 --- a/options/locale/locale_bg-BG.ini +++ b/options/locale/locale_bg-BG.ini @@ -13,7 +13,6 @@ version=Версия page=Страница template=Шаблон language=Език -create_new=Създаване... user_profile_and_more=Потребителски профил и пр. signed_in_as=Вписан като @@ -213,7 +212,6 @@ enable_custom_avatar=Разреши потребителски аватар choose_new_avatar=Избор на нов аватар update_avatar=Запази настройките на аватара delete_current_avatar=Изтрий аватар -uploaded_avatar_not_a_image=Каченият файл не е изображение. change_password=Промяна на собствената парола old_password=Текуща парола @@ -341,7 +339,6 @@ editor.fork_before_edit=Първо трябва да разклоните хра editor.delete_this_file=Изтрий този файл editor.must_have_write_access=Трябва да имате права за писане за да предложите промени в този файл editor.file_delete_success=Файл '%s' е изтрит успешно! -editor.name_your_file=Име на файл... editor.filename_help=За да добавите директория, въведете името ѝ и натиснете /. За да я премахнете, позиционирайте се в началото на полето и натиснете BackSpace. editor.or=или editor.cancel_lower=отказ @@ -350,10 +347,8 @@ editor.add_tmpl=Добави '%s/' editor.add=Добави '%s' editor.update=Модифицирай '%s' editor.delete=Изтрий '%s' -editor.commit_message_desc=Добавяне на опционално разширено описание... editor.commit_directly_to_this_branch=Запази ревизия директно в клон %s. editor.create_new_branch=Създай нов клон от тази ревизия и изпрати заявки за сливане. -editor.new_branch_name_desc=Име на нов клон... editor.cancel=Отказ editor.filename_cannot_be_empty=Името не може да бъде празно. editor.branch_already_exists=Клон '%s' вече съществува в това хранилище. @@ -363,7 +358,6 @@ editor.file_editing_no_longer_exists=Файл '%s' който редактира editor.file_already_exists=Файл с име '%s' вече съществува в това хранилище. editor.no_changes_to_show=Няма промени. editor.fail_to_update_file=Невъзможно модифициране/създаване на файл '%s' заради грешка: %v -editor.add_subdir=Добави поддиректория... editor.unable_to_upload_files=Невъзможно качване на файлове в '%s' заради грешка: %v editor.upload_files_to_dir=Качи файлове в '%s' @@ -390,7 +384,6 @@ issues.new.clear_assignee=Изчисти изпълнител issues.new.no_assignee=Няма изпълнител issues.create=Създай задача issues.new_label=Нов етикет -issues.new_label_placeholder=Име на етикета... issues.create_label=Създай етикет issues.label_templates.title=Зареждане на предварително зададен набор от етикети issues.label_templates.helper=Изберете набор етикети @@ -541,7 +534,6 @@ settings.tracker_url_format=Формат на URL адрес на външна settings.tracker_issue_style=Стил на именуване на външна система за проследяване на задачи: settings.tracker_issue_style.numeric=Цифров settings.tracker_issue_style.alphanumeric=Символен -settings.tracker_url_format_desc=Можете да използвате текстови маркери {user} {repo} {index} за потребителско име, име на хранилище и индекс на задача съответно. settings.pulls_desc=Включва заявки за сливане за да може да се приемат външни доработки settings.danger_zone=Опасна зона settings.new_owner_has_same_repo=Новият притежател вече има хранилище със същото име. Изберете друго име. @@ -565,7 +557,6 @@ settings.delete_collaborator=Премахни settings.collaborator_deletion=Премахване на сътрудник settings.collaborator_deletion_desc=Този потребител няма да има достъп на сътрудник до хранилището след изтриването. Желаете ли да продължите? settings.remove_collaborator_success=Сътрудникът е премахнат. -settings.search_user_placeholder=Име на потребител... settings.org_not_allowed_to_be_collaborator=Невъзможно добавяне на организация като сътрудник. settings.user_is_org_member=Потребителят вече участва в организацията и не може да бъде добавен като сътрудник. settings.add_webhook=Добави уеб-кука @@ -646,7 +637,6 @@ release.title=Заглавие release.content=Съдържание release.write=Редактор release.preview=Преглед -release.loading=Зареждане... release.prerelease_desc=Това е предварителна версия release.prerelease_helper=Ние ще отбележим, че тази версия не е готова за продукционна употреба. release.cancel=Отказ @@ -721,7 +711,6 @@ teams.read_permission_desc=Този екип предоставя достъп teams.write_permission_desc=Този екип предоставя достъп за писане: участниците могат да четат от и да предават към хранилищата на този екип. teams.admin_permission_desc=Този екип предоставя администраторски достъп: участниците могат да четат от, да предават към и да добавя нови сътрудници към хранилищата на този екип. teams.repositories=Хранилища на екипа -teams.search_repo_placeholder=Име на хранилище... teams.add_team_repository=Добави хранилище на екипа teams.remove_repo=Премахни teams.add_nonexistent_repo=Хранилището, което се опитвате да добавите не съществува. Моля първо го създайте! @@ -825,7 +814,6 @@ auths.bind_password=Парола за свръзка auths.user_base=Базов OU за търсене auths.user_dn=Име (DN) на потребител auths.attribute_username=Атрибут за име -auths.attribute_username_placeholder=Оставете празно за да използва потребителското име от форма за вписване. auths.attribute_name=Атрибут за име auths.attribute_surname=Атрибут за фамилия auths.attribute_mail=Атрибут за ел. поща diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index de34e26c3..1595c2e64 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -13,7 +13,6 @@ version=Verze page=Strana template=Šablona language=Jazyk -create_new=Vytořit... user_profile_and_more=Uživatelský profil a další signed_in_as=Přihlášen jako @@ -213,7 +212,6 @@ enable_custom_avatar=Povolit uživatelskou ikonu uživatele choose_new_avatar=Vybrat novou ikonu uživatele update_avatar=Aktualizovat nastavení ikony uživatele delete_current_avatar=Smazat aktuální ikonu uživatele -uploaded_avatar_not_a_image=Nahraný soubor není obrázkem. change_password=Změna hesla old_password=Stávající heslo @@ -342,7 +340,6 @@ editor.fork_before_edit=Musíte provést rozvětvení repositáře před úpravo editor.delete_this_file=Odstranit tento soubor editor.must_have_write_access=Musíte mít přístup pro zápis pro dělání či navrhování změn tohoto souboru editor.file_delete_success=Soubor '%s' byl úspěšně odstraněn! -editor.name_your_file=Pojmenujte váš soubor... editor.filename_help=Pro vložení adresáře prostě napište jméno a přidejte /. K odstranění adresáře běžte na začátek pole a stiskněte backspace. editor.or=nebo editor.cancel_lower=zrušit @@ -351,10 +348,8 @@ editor.add_tmpl=Přidat '%s/' editor.add=Přidat '%s' editor.update=Aktualizovat "%s editor.delete=Smazat '%s' -editor.commit_message_desc=Přidat dobrovolný rozšířený popis... editor.commit_directly_to_this_branch=Uložte změny revize přímo do větve %s. editor.create_new_branch=Vytvořit novou větev pro tuto revizi a spustit požadavek na stažení. -editor.new_branch_name_desc=Nový název větve... editor.cancel=Zrušit editor.filename_cannot_be_empty=Název souboru nemůže být prázdný. editor.branch_already_exists=Repositář větev '%s' již obsahuje. @@ -364,7 +359,6 @@ editor.file_editing_no_longer_exists=Soubor '%s', který upravujete, již neexis editor.file_already_exists=Soubor '%s' již existuje v tomto repozitáři. editor.no_changes_to_show=Žádné změny k zobrazení. editor.fail_to_update_file=Vytvoření nebo změna souboru '%s' skončilo chybou: %v -editor.add_subdir=Přidat podadresář... editor.unable_to_upload_files=Nepodařilo se nahrát soubor '%s'. Chyba: %v editor.upload_files_to_dir=Nahrát soubory do '%s' @@ -391,7 +385,6 @@ issues.new.clear_assignee=Smazat zpracovatele issues.new.no_assignee=Bez zpracovatele issues.create=Vytvořit úkol issues.new_label=Nový štítek -issues.new_label_placeholder=Název štítku... issues.create_label=Vytvořit štítek issues.label_templates.title=Nahrát předdefinovanou sadu značek issues.label_templates.helper=Vyberte sadu značek @@ -541,7 +534,6 @@ settings.tracker_url_format=Formát URL externího systému úkolů settings.tracker_issue_style=Styl pojmenování externího systému úkolů: settings.tracker_issue_style.numeric=Číselný settings.tracker_issue_style.alphanumeric=Alfanumerický -settings.tracker_url_format_desc=Můžete použít zástupné výrazy {user} {repo} {index} pro uživatelské jméno, název repositáře a index úkolu. settings.pulls_desc=Povolit požadavky na stažení, aby veřejné příspěvky mohly být akceptovány settings.danger_zone=Nebezpečná zóna settings.new_owner_has_same_repo=Nový vlastník již repositář se stejným názvem má. Vyberte, prosíme, jiné jméno. @@ -565,7 +557,6 @@ settings.delete_collaborator=Smazat settings.collaborator_deletion=Smazání spolupracovníka settings.collaborator_deletion_desc=Tento uživatel po tom, co bude smazán, již nebude mít přístup do tohoto repositáře pro spolupráci. Chcete pokračovat? settings.remove_collaborator_success=Spolupracovník byl smazán. -settings.search_user_placeholder=Hledat uživatele... settings.org_not_allowed_to_be_collaborator=Není dovoleno přidat organizaci jako spolupracovníka. settings.user_is_org_member=Uživatel je již členem organizace, tudíž nemůže být přidán jako spolupracovník. settings.add_webhook=Přidat webový háček @@ -647,7 +638,6 @@ release.title=Název release.content=Obsah release.write=Zapsat release.preview=Náhled -release.loading=Načítání... release.prerelease_desc=Toto je předběžná verze release.prerelease_helper=Zdůrazníme, že toto vydání není hotovo pro produkční nasazení. release.cancel=Zrušit @@ -722,7 +712,6 @@ teams.read_permission_desc=Členství v tom týmu poskytuje právo čten teams.write_permission_desc=Členství v tom týmu poskytuje právo zápisu: členové mohou číst z a nahrávat do repositářů týmu. teams.admin_permission_desc=Členství v tom týmu poskytuje právo správce: členové mohou číst z, nahrávat do a přidávat spolupracovníky do repositářů týmu. teams.repositories=Repositáře týmu -teams.search_repo_placeholder=Hledat repositář... teams.add_team_repository=Přidat repositář týmu teams.remove_repo=Smazat teams.add_nonexistent_repo=Repositář, který se snažíte přidat, neexistuje. Prosím, nejdříve jej vytvořte. @@ -825,7 +814,6 @@ auths.bind_password=Heslo připojení auths.user_base=Výchozí bod hledání uživatelů auths.user_dn=DN uživatele auths.attribute_username=Atribut uživatelského jména -auths.attribute_username_placeholder=Zanechat prázdné pro použití hodnoty pole uživatelského jména z přihlašovacího formuláře. auths.attribute_name=Křestní jméno auths.attribute_surname=Příjmení auths.attribute_mail=E-mailová adresa diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 2128484eb..2597774d3 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -17,7 +17,7 @@ page=Seite template=Vorlage language=Sprache notifications=Benachrichtigungen -create_new=Erstellen... +create_new=Erstellen… user_profile_and_more=Benutzerprofil und mehr signed_in_as=Angemeldet als enable_javascript=Diese Webseite funktioniert besser mit JavaScript @@ -155,12 +155,12 @@ uname_holder=Benutzername oder E-Mail password_holder=Passwort switch_dashboard_context=Kontext der Übersichtsseite wechseln my_repos=Meine Repositories -show_more_repos=Mehr Repositories anzeigen... +show_more_repos=Zeige mehr Repositories… collaborative_repos=Gemeinschaftliche Repositories my_orgs=Meine Organisationen my_mirrors=Meine Mirrors view_home=%s betrachten -search_repos=Finde eine Repository ... +search_repos=Finde eine Repository… issues.in_your_repos=Eigene Repositories @@ -249,7 +249,6 @@ Content=Inhalt require_error=` darf nicht leer sein.` alpha_dash_error=` kann ausschließlich alphanumerische Zeichen und (-_) enthalten.` alpha_dash_dot_error=` müssen gültige alphanumerische, dash(-_) oder Punkt-Zeichen sein. ` -git_ref_name_error=` muss ein wohlgeformter Git-Referenzname sein ` size_error=` muss die Größe %s haben.` min_size_error=` muss mindestens %s Zeichen enthalten.` max_size_error=` darf höchstens %s Zeichen enthalten.` @@ -565,7 +564,7 @@ editor.fork_before_edit=Du musst dieses Repository forken um die Datei bearbeite editor.delete_this_file=Datei löschen editor.must_have_write_access=Du musst Schreibzugriff haben, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen editor.file_delete_success=Die Datei '%s' wurde erfolgreich gelöscht! -editor.name_your_file=Dateinamen eingeben... +editor.name_your_file=Dateinamen eingeben… editor.filename_help=Um einen Ordner hinzuzufügen, gib den Namen ein und drücke /. Um einen Ordner zu entfernen, gehe zum Anfang des Feldes und drücke die Rücktaste. editor.or=oder editor.cancel_lower=abbrechen @@ -574,10 +573,9 @@ editor.add_tmpl='%s/' hinzufügen editor.add='%s' hinzufügen editor.update='%s' ändern editor.delete='%s' löschen -editor.commit_message_desc=Eine ausführlichere (optionale) Beschreibung hinzufügen... +editor.commit_message_desc=Eine ausführlichere (optionale) Beschreibung hinzufügen… editor.commit_directly_to_this_branch=Direkt in die %s-Branch einchecken. editor.create_new_branch=Einen neuen Branch für diesen Commit erstellen und einen Pull Request starten. -editor.new_branch_name_desc=Neuer Branch Name... editor.cancel=Abbrechen editor.filename_cannot_be_empty=Der Dateiname darf nicht leer sein. editor.branch_already_exists=Branch '%s' existiert bereits in diesem Repository. @@ -589,7 +587,7 @@ editor.file_changed_while_editing=Seit dem Start der Bearbeitung hat sich die Da editor.file_already_exists=Eine Datei mit dem Namen '%s' existiert bereits in diesem Repository. editor.no_changes_to_show=Keine Änderungen vorhanden. editor.fail_to_update_file=Fehler beim Ändern/Erstellen der Datei '%s'. Fehler: %v -editor.add_subdir=Unterverzeichnis erstellen... +editor.add_subdir=Unterverzeichnis erstellen… editor.unable_to_upload_files=Fehler beim Hochladen der Dateien zu '%s'. Fehler: %v editor.upload_files_to_dir=Dateien hochladen nach '%s' editor.cannot_commit_to_protected_branch=Auf die geschützte Branch "%s" kann nicht geschrieben werden. @@ -626,7 +624,7 @@ issues.new.no_assignee=Niemand zuständig issues.no_ref=Keine Branch/Tag angegeben issues.create=Issue erstellen issues.new_label=Neues Label -issues.new_label_placeholder=Label-Name... +issues.new_label_placeholder=Label-Name… issues.create_label=Label erstellen issues.label_templates.title=Lade vordefinierte Label issues.label_templates.info=Es sind noch keine Label vorhanden. Du kannst vordefinierte Label benutzen, oder auf "Neues Label" klicken um eines zu erstellen. @@ -938,7 +936,7 @@ settings.delete_collaborator=Löschen settings.collaborator_deletion=Mitarbeiter löschen settings.collaborator_deletion_desc=Nach dem Löschen wird dieser Benutzer keinen Zugriff mehr als Mitarbeiter auf dieses Repository haben. Möchtest du fortfahren? settings.remove_collaborator_success=Mitarbeiter wurde entfernt. -settings.search_user_placeholder=Benutzer suchen... +settings.search_user_placeholder=Benutzer suchen… settings.org_not_allowed_to_be_collaborator=Eine Organisation kann nicht als Mitarbeiter hinzugefügt werden. settings.user_is_org_member=Benutzer ist ein Organisationsmitglied und kann nicht als Mitarbeiter hinzugefügt werden. settings.add_webhook=Webhook hinzufügen @@ -1029,7 +1027,6 @@ settings.remove_protected_branch_success=Branch-Protection für %s erfolgreich e settings.protected_branch_deletion=Eine geschützte Branch löschen settings.protected_branch_deletion_desc=Jeder mit Schreibzugriff wird direkt in diese Branch pushen können. Bist du sicher? settings.default_branch_desc=Die Standardbranch ist als "basis"-Branch in deinem Repository definiert, Commits und Pull-Requests werden automatisch mit dieser Branch durchgeführt wenn du keine andere angibst. -settings.choose_branch=Wähle einen Branch... settings.no_protected_branch=Es gibt keine geschützten Branches diff.browse_source=Quellcode durchsuchen @@ -1177,7 +1174,7 @@ teams.read_permission_desc=Dieses Team hat Lesezugriff: Mitglie teams.write_permission_desc=Dieses Team hat Schreibzugriff: Mitglieder können Team-Repositories einsehen und darauf pushen. teams.admin_permission_desc=Dieses Team hat Adminzugriff: Mitglieder dieses Teams können pullen, pushen und Mitarbeiter zu Team-Repositories hinzufügen. teams.repositories=Team-Repositories -teams.search_repo_placeholder=Repository durchsuchen... +teams.search_repo_placeholder=Repository durchsuchen… teams.add_team_repository=Team-Repository hinzufügen teams.remove_repo=Entfernen teams.add_nonexistent_repo=Das Repository, das du hinzufügen möchten, existiert nicht. Bitte erstelle es zuerst. diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index e30d2b4cf..68f2f156e 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -17,7 +17,6 @@ page=Página template=Plantilla language=Idioma notifications=Notificaciones -create_new=Crear... user_profile_and_more=Perfil de usuario y más signed_in_as=Identificado como enable_javascript=Este sitio web funciona mejor con JavaScript @@ -150,12 +149,10 @@ uname_holder=Nombre de usuario o correo electrónico password_holder=Contraseña switch_dashboard_context=Cambiar el contexto del Dashboard my_repos=Mis repositorios -show_more_repos=Mostrar más repositorios... collaborative_repos=Repositorios colaborativos my_orgs=Mis organizaciones my_mirrors=Mis réplicas view_home=Ver %s -search_repos=Encontrar un repositorio... issues.in_your_repos=En tus repositorios @@ -326,7 +323,6 @@ enable_custom_avatar=Activar avatar personalizado choose_new_avatar=Selecciona nuevo avatar update_avatar=Actualizar configuración del avatar delete_current_avatar=Eliminar avatar -uploaded_avatar_not_a_image=El archivo enviado no es una imagen. update_avatar_success=La configuración de tu avatar se ha actualizado correctamente. change_password=Cambiar contraseña @@ -550,7 +546,6 @@ editor.fork_before_edit=Debes hacer un fork de este repositorio antes de editar editor.delete_this_file=Eliminar este archivo editor.must_have_write_access=Debes tener permisos de escritura para hacer o proponer cambios a este archivo editor.file_delete_success=¡El archivo '%s' ha sido eliminado con éxito! -editor.name_your_file=Nombra tu archivo... editor.filename_help=Para añadir un directorio, simplemente escribelo y presiona /. Para eliminar un directorio, ve al principio del campo y presiona retroceso. editor.or=o editor.cancel_lower=cancelar @@ -559,10 +554,8 @@ editor.add_tmpl=Añadir '%s' editor.add=Añadir '%s' editor.update=Actualizar '%s' editor.delete=Eliminar '%s' -editor.commit_message_desc=Añadir una descripción extendida opcional... editor.commit_directly_to_this_branch=Hacer commit directamente en la rama %s. editor.create_new_branch=Crear una nueva rama para este commit y hacer un pull request. -editor.new_branch_name_desc=Nombre de la rama nueva... editor.cancel=Cancelar editor.filename_cannot_be_empty=El nombre del archivo no puede estar vacío. editor.branch_already_exists=La rama '%s' ya existe en este repositorio. @@ -574,7 +567,6 @@ editor.file_changed_while_editing=Desde que comenzó a editar, el contenido del editor.file_already_exists=Ya existe un archivo con nombre '%s' en este repositorio. editor.no_changes_to_show=No existen cambios para mostrar. editor.fail_to_update_file=Error al actualizar/crear el archivo '%s', error: %v -editor.add_subdir=Añadir subdirectorio... editor.unable_to_upload_files=Error al subir archivos a '%s', error: %v editor.upload_files_to_dir=Subir archivos a '%s' editor.cannot_commit_to_protected_branch=No se puede hacer commit a la rama protegida '%s'. @@ -608,7 +600,6 @@ issues.new.clear_assignee=Limpiar asignado issues.new.no_assignee=Sin asignado issues.create=Crear incidencia issues.new_label=Nueva Etiqueta -issues.new_label_placeholder=Nombre etiqueta... issues.create_label=Crear etiqueta issues.label_templates.title=Carga un conjunto predefinido de etiquetas issues.label_templates.info=Todavía no hay ninguna etiqueta. Puede hacer clic en el botón "Nueva Etiqueta" debajo, para crear uno o utilizar un conjunto predefinido. @@ -827,7 +818,6 @@ settings.tracker_url_format=Formato URL del tracker de incidencias externo settings.tracker_issue_style=Estilo de etiquetado del tracker externo de incidencias: settings.tracker_issue_style.numeric=Numérico settings.tracker_issue_style.alphanumeric=Alfanumérico -settings.tracker_url_format_desc=Puedes usar las plantillas {user} {repo} {index} para el nombre de usuario, nombre del repositorio e índice de la incidencia. settings.enable_timetracker=Habilitar rastreador de tiempo settings.allow_only_contributors_to_track_time=Permitir que sólo los contribuyentes registren el tiempo settings.pulls_desc=Habilitar Pull Requests para aceptar contribuciones públicas @@ -840,7 +830,6 @@ settings.convert_confirm=Confirmar conversión settings.convert_succeed=El repositorio se ha convertido en un repositorio regular. settings.transfer=Transferir la propiedad settings.transfer_desc=Transferir este repositorio a otro usuario u organización donde tengas permisos de administración. -settings.transfer_notices_1=- Perderá el acceso si el nuevo propietario es un usuario individual. settings.transfer_notices_2=- Conservará el privilegio de acceso si el nuevo propietario es una organización y usted es uno de los propietarios de dicha organización. settings.transfer_form_title=Por favor, introduce la siguiente información para confirmar la operación: settings.wiki_delete=Eliminar datos de la wiki @@ -864,7 +853,6 @@ settings.delete_collaborator=Eliminar settings.collaborator_deletion=Eliminar colaborador settings.collaborator_deletion_desc=Este usuario no podrá colaborar en este repositorio tras eliminarlo. ¿Desea continuar? settings.remove_collaborator_success=El colaborador ha sido eliminado. -settings.search_user_placeholder=Buscar usuario... settings.org_not_allowed_to_be_collaborator=Las organizaciones no tiene permitido ser añadidas como colaboradores. settings.user_is_org_member=El usuario es miembro de la organización, no puede ser añadido como colaborador. settings.add_webhook=Añadir Webhook @@ -941,7 +929,6 @@ settings.remove_protected_branch_success=Opciones de protección de la rama %s e settings.protected_branch_deletion=Para eliminar una rama protegida settings.protected_branch_deletion_desc=Cualquiera con permisos de escritura podrá hacer un push directamente en esta rama. ¿Estás seguro? settings.default_branch_desc=La rama por defecto es considerada la rama "base" en tu repositorio contra la cual se hacen todas las peticiones pull y commits de código automáticamente, a menos que especifiques una rama distinta. -settings.choose_branch=Elige una rama... settings.no_protected_branch=No hay ramas protegidas diff.browse_source=Explorar el Código @@ -974,7 +961,6 @@ release.title=Título release.content=Contenido release.write=Escribir release.preview=Vista previa -release.loading=Cargando... release.prerelease_desc=Esta es una pre-release release.prerelease_helper=Esta release está marcada como no apta para producción. release.cancel=Cancelar @@ -1088,7 +1074,6 @@ teams.read_permission_desc=Este equipo tiene permisos de LecturaEscritura: sus miembros pueden leer y hacer push a los repositorios del equipo. teams.admin_permission_desc=Este equipo tiene permisos de Administración: sus miembros pueden leer, hacer push y añadir colaboradores a los repositorios del equipo. teams.repositories=Repositorios del equipo -teams.search_repo_placeholder=Buscar repositorio... teams.add_team_repository=Añadir repositorio al equipo teams.remove_repo=Eliminar teams.add_nonexistent_repo=El repositorio que estás intentando añadir no existe, por favor, créalo primero. @@ -1210,7 +1195,6 @@ auths.bind_password_helper=Advertencia: Esta contraseña se almacena en texto si auths.user_base=Base de búsqueda de usuarios auths.user_dn=DN de Usuario auths.attribute_username=Atributo de nombre de usuario -auths.attribute_username_placeholder=Dejar vacío para usar el campo de inicio de sesión como nombre de usuario. auths.attribute_name=Atributo nombre auths.attribute_surname=Atributo apellido auths.attribute_mail=Atributo correo electrónico diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 09c6ec884..fe596052f 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -14,7 +14,6 @@ page=Sivu template=Malli language=Kieli notifications=Ilmoitukset -create_new=Luo... user_profile_and_more=Käyttäjäprofiili ja lisää signed_in_as=Kirjautuneena käyttäjänä @@ -215,7 +214,6 @@ enable_custom_avatar=Ota käyttöön mukautettu profiilikuva choose_new_avatar=Valitse uusi profiilikuva update_avatar=Päivitä profiilikuva asetus delete_current_avatar=Poista nykyinen profiilikuva -uploaded_avatar_not_a_image=Palvelimelle lähetetty tiedosto ei ole kuva. change_password=Vaihda salasana old_password=Nykyinen salasana @@ -343,18 +341,15 @@ editor.edit_this_file=Muokkaa tätä tiedostoa editor.delete_this_file=Poista tämä tiedosto editor.must_have_write_access=Sinulla on oltava kirjoitusoikeus tehdäksesi tai ehdottaaksesi muutoksia tähän tiedostoon editor.file_delete_success=Tiedosto "%s" on poistettu onnistuneesti! -editor.name_your_file=Nimeä tiedostosi... editor.or=tai editor.cancel_lower=peruuta editor.add_tmpl=Lisää '%s/' editor.add=Lisää "%s editor.update=Päivitä '%s' editor.delete=Poista "%s -editor.commit_message_desc=Lisää pidennetty selite (valinnainen)... editor.cancel=Peruuta editor.filename_cannot_be_empty=Tiedostonimi ei voi olla tyhjä. editor.no_changes_to_show=Ei muutoksia näytettäväksi. -editor.add_subdir=Lisää alihakemisto... commits.commits=Commitit commits.search=Etsi commiteista @@ -379,7 +374,6 @@ issues.new.clear_assignee=Tyhjennä osoitettu issues.new.no_assignee=Ei osoitettua issues.create=Ilmoita ongelma issues.new_label=Uusi tunniste -issues.new_label_placeholder=Tunnisteen nimi... issues.create_label=Luo tunniste issues.open_tab=%d avoinna issues.close_tab=%d suljettu @@ -520,7 +514,6 @@ settings.use_external_issue_tracker=Käytä ulkoista vikaseurantaa settings.tracker_url_format=Ulkoisen vikaseurannan URL muoto settings.tracker_issue_style.numeric=Numeerinen settings.tracker_issue_style.alphanumeric=Aakkosnumeerinen -settings.tracker_url_format_desc=Voit käyttää paikkamerkkiä {user} {repo} {index} käyttäjänimelle, reponimelle ja vikanumerolle. settings.pulls_desc=Ota käyttöön pull-pyynnöt salliaksesi julkiset koodilahjoitukset settings.danger_zone=Vaaravyöhyke settings.new_owner_has_same_repo=Uudella omistajalla on jo samanniminen repo. Ole hyvä ja valitse toinen nimi. @@ -544,7 +537,6 @@ settings.delete_collaborator=Poista settings.collaborator_deletion=Yhteistyökumppanin poistaminen settings.collaborator_deletion_desc=Tällä käyttäjällä ei tule enää olemaan yhteistyö pääsyä tähän repoon poistamisen jälkeen. Haluatko jatkaa? settings.remove_collaborator_success=Yhteistyökumppani on poistettu. -settings.search_user_placeholder=Etsi käyttäjä... settings.org_not_allowed_to_be_collaborator=Yhteistyökumppaniksi ei voi lisätä organisaatiota. settings.user_is_org_member=Käyttäjä on organisaation jäsen, jota ei voi lisätä yhteistyökumppaniksi. settings.add_webhook=Lisää webkoukku @@ -617,7 +609,6 @@ release.title=Otsikko release.content=Sisältö release.write=Kirjoita release.preview=Esikatselu -release.loading=Ladataan... release.prerelease_desc=Tämä on esiversio release.prerelease_helper=Huomautamme että tämä versio ei ole tuotantovalmis. release.cancel=Peruuta @@ -693,7 +684,6 @@ teams.read_permission_desc=Tämä tiimi myöntää lukuoikeuden teams.write_permission_desc=Tämä tiimi myöntää kirjoitusoikeuden: jäsenet voivat lukea ja pushata tiimin repoihin. teams.admin_permission_desc=Tämä tiimi myöntää ylläpito-oikeuden: jäsenet voivat lukea, pushata, ja lisätä yhteistyökumppaneita tiimin repoihin. teams.repositories=Tiimin repot -teams.search_repo_placeholder=Etsi repo... teams.add_team_repository=Lisää tiimirepo teams.remove_repo=Poista teams.add_nonexistent_repo=Repo jota yrität lisätä ei ole vielä olemassa, ole hyvä ja luo se ensin. @@ -798,7 +788,6 @@ auths.bind_password=Liitä salasana auths.user_base=Käyttäjä hakuperuste auths.user_dn=Käyttäjä DN auths.attribute_username=Käyttäjänimen määrite -auths.attribute_username_placeholder=Jätä tyhjäksi käyttääksesi kirjautumislomakkeen käyttäjänimeä. auths.attribute_name=Etunimen määrite auths.attribute_surname=Sukunimen määrite auths.attribute_mail=Sähköposti määrite diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 9e0906d7c..c2a0d1cfe 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -17,7 +17,6 @@ page=Page template=Modèle language=Langue notifications=Notifications -create_new=Créer... user_profile_and_more=Profil utilisateur et plus signed_in_as=Connecté en tant que enable_javascript=Ce site fonctionne mieux avec JavaScript @@ -155,12 +154,10 @@ uname_holder=Nom d'utilisateur ou e-mail password_holder=Mot de passe switch_dashboard_context=Basculer le contexte du tableau de bord my_repos=Mes dépôts -show_more_repos=Afficher plus de dépôts... collaborative_repos=Dépôts collaboratifs my_orgs=Mes organisations my_mirrors=Mes miroirs view_home=Voir %s -search_repos=Trouver un dépôt ... issues.in_your_repos=Dans vos dépôts @@ -249,7 +246,6 @@ Content=Contenu require_error=` ne peut pas être vide.` alpha_dash_error=` doivent être des caractères alphanumériques valides ou des tirets (-_).` alpha_dash_dot_error=` doivent être des caractères alphanumériques valides, des tirets (-_) ou des points.` -git_ref_name_error=` doit être un nom de référence Git bien formé.` size_error=` doit être à la taille de %s.` min_size_error=` %s caractères minimum ` max_size_error=` %s caractères maximum ` @@ -335,7 +331,6 @@ enable_custom_avatar=Activer l'avatar personnalisé choose_new_avatar=Sélectionner un nouvel avatar update_avatar=Mettre à jour l'avatar delete_current_avatar=Supprimer l'avatar actuel -uploaded_avatar_not_a_image=Le fichier téléchargé n'est pas une image. update_avatar_success=Votre avatar a été mis à jour. change_password=Modifier le mot de passe @@ -565,7 +560,6 @@ editor.fork_before_edit=Vous devez bifurquer ce dépôt avant de modifier le fic editor.delete_this_file=Supprimer ce fichier editor.must_have_write_access=Vous devez avoir un accès en écriture pour appliquer ou proposer des modifications à ce fichier editor.file_delete_success=Fichier '%s' a été supprimé avec succès! -editor.name_your_file=Nommez votre fichier... editor.filename_help=Pour ajouter un répertoire, il suffit de le saisir puis d'appuyer sur /. Pour supprimer un répertoire, aller au début du champ et appuyez sur retour arrière. editor.or=ou editor.cancel_lower=annuler @@ -574,10 +568,8 @@ editor.add_tmpl=Ajouter '%s/' editor.add=Ajouter '%s' editor.update=Mettre à jour '%s' editor.delete=Supprimer '%s' -editor.commit_message_desc=Ajouter une description détaillée facultative... editor.commit_directly_to_this_branch=Soumettre directement dans la branche %s. editor.create_new_branch=Créer une nouvelle branche pour cette révision et envoyer une nouvelle demande d'ajout. -editor.new_branch_name_desc=Nouveau nom de la branche... editor.cancel=Annuler editor.filename_cannot_be_empty=Nom de fichier ne peut pas être vide. editor.branch_already_exists=La branche '%s' existe déjà dans ce dépôt. @@ -589,7 +581,6 @@ editor.file_changed_while_editing=Le contenu du fichier a changé depuis que vou editor.file_already_exists=La branche '%s' existe déjà dans ce dépôt. editor.no_changes_to_show=Il n’y a aucun changement à afficher. editor.fail_to_update_file=Échec lors de la mise à jour/création du fichier '%s' avec l’erreur : %v -editor.add_subdir=Ajouter un sous-répertoire... editor.unable_to_upload_files=Échec lors de l'envoie du fichier '%s' avec l’erreur : %v editor.upload_files_to_dir=Transférer les fichiers vers '%s' editor.cannot_commit_to_protected_branch=Impossible de créer une révision sur la branche protégée '%s'. @@ -626,7 +617,6 @@ issues.new.no_assignee=Pas d'assignataire issues.no_ref=Aucune branche/tag spécifiés issues.create=Créer un ticket issues.new_label=Nouvelle étiquette -issues.new_label_placeholder=Nom de l'étiquette... issues.create_label=Créer une étiquette issues.label_templates.title=Charger un ensemble prédéfini d'étiquettes issues.label_templates.info=Il n'y a pas encore d'étiquettes. Vous pouvez cliquer sur le bouton "Nouvelle étiquette" pour en créer une ou en utiliser une prédéfinies ci-dessous. @@ -897,7 +887,6 @@ settings.tracker_url_format=Format de l'URL du système de tickets settings.tracker_issue_style=Style de nommage des tickets : settings.tracker_issue_style.numeric=Numérique settings.tracker_issue_style.alphanumeric=Alphanumérique -settings.tracker_url_format_desc=Vous pouvez utiliser l'espace réservé {user} {repo} {index} pour le nom d'utilisateur, le nom du dépôt et le numéro de bug. settings.enable_timetracker=Activer le traqueur de temps settings.allow_only_contributors_to_track_time=N'autoriser que les contributeurs à suivre le temps settings.pulls_desc=Activer les pull requests pour accepter les contributions publiques @@ -914,7 +903,6 @@ settings.convert_confirm=Confirmer la conversion settings.convert_succeed=Le dépôt a été converti en dépôt ordinaire. settings.transfer=Changer de propriétaire settings.transfer_desc=Transférer ce dépôt à un autre utilisateur ou une organisation dont vous possédez des droits d'administrateur. -settings.transfer_notices_1=- Vous perdrez l'accès si le nouveau propriétaire est un utilisateur individuel. settings.transfer_notices_2=- Vous conserverez l'accès si le nouveau propriétaire est une organisation et que vous en êtes un des propriétaires. settings.transfer_form_title=Merci de fournir les informations suivantes pour confirmer votre opération : settings.wiki_delete=Effacer les données du Wiki @@ -938,7 +926,6 @@ settings.delete_collaborator=Supprimer settings.collaborator_deletion=Suppression d'un collaborateur settings.collaborator_deletion_desc=Cet utilisateur n'aura plus accès pour collaborer à ce dépôt après sa suppression. Voulez-vous continuer? settings.remove_collaborator_success=Collaborateur supprimé. -settings.search_user_placeholder=Rechercher un utilisateur... settings.org_not_allowed_to_be_collaborator=Une organisation n'est pas autorisée à être ajoutée en tant que collaborateur. settings.user_is_org_member=Cet utilisateur ne peut pas être ajouté en tant que collaborateur car il fait partie d'une organisation. settings.add_webhook=Ajouter un déclencheur Web @@ -1029,7 +1016,6 @@ settings.remove_protected_branch_success=Paramètres de protection de la branche settings.protected_branch_deletion=Pour supprimer une branche protégée settings.protected_branch_deletion_desc=Quiconque ayant permission d'écriture pourra pousser directement sur cette branche. Êtes-vous sûr ? settings.default_branch_desc=La branche par défaut est considérée comme la branche de "base" sur laquelle toutes les demandes d'ajout et toutes les révisions sont poussées automatiquement, à moins que vous ne spécifiez une branche différente. -settings.choose_branch=Choisissez une branche... settings.no_protected_branch=Il n’y a aucune branche protégée diff.browse_source=Parcourir la source @@ -1063,7 +1049,6 @@ release.title=Titre release.content=Contenu release.write=Écrire release.preview=Prévisualiser -release.loading=Chargement… release.prerelease_desc=Il s'agit d'une version préliminaire release.prerelease_helper=Nous soulignerons que cette version est considérée comme non prête pour la production. release.cancel=Annuler @@ -1177,7 +1162,6 @@ teams.read_permission_desc=Cette équipe permet l'accès en lectureécriture : les membres peuvent participer à ses dépôts. teams.admin_permission_desc=Cette équipe permet l'accès en administrateur : les membres peuvent voir, participer et ajouter des collaborateurs à ses dépôts. teams.repositories=Dépôts de l'Équipe -teams.search_repo_placeholder=Rechercher dans le dépôt... teams.add_team_repository=Ajouter un Dépôt à l'Équipe teams.remove_repo=Supprimer teams.add_nonexistent_repo=Dépôt inexistant, veuillez d'abord le créer. @@ -1316,7 +1300,6 @@ auths.bind_password_helper=Attention: Le mot de passe est stocké en clair. Il e auths.user_base=Utilisateur Search Base auths.user_dn=Utilisateur DN auths.attribute_username=Attribut nom d'utilisateur -auths.attribute_username_placeholder=Laisser vide pour utiliser la valeur du formulaire d'authentification comme nom d'utilisateur. auths.attribute_name=Attribut du prénom auths.attribute_surname=Attribut du nom de famille auths.attribute_mail=Attribut de l'e-mail diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 045346b58..356aa3b63 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -17,7 +17,7 @@ page=Oldal template=Sablon language=Nyelv notifications=Értesítések -create_new=Létrehozás... +create_new=Létrehozás… user_profile_and_more=Felhasználói profil és egyebek signed_in_as=Bejelentkezve mint enable_javascript=Ez oldal jobban működik JavaScript támogatással @@ -155,12 +155,12 @@ uname_holder=Felhasználónév vagy E-mail password_holder=Jelszó switch_dashboard_context=Műszerfal nézőpont váltás my_repos=Tárolóim -show_more_repos=További tárolók... +show_more_repos=Több tároló mutatása… collaborative_repos=Együttműködési tárolók my_orgs=Szervezeteim my_mirrors=Tükreim view_home=Nézet %s -search_repos=Tároló keresése... +search_repos=Tároló keresés… issues.in_your_repos=A tárolóidban @@ -249,7 +249,7 @@ Content=Tartalom require_error=` nem lehet üres` alpha_dash_error=` betű, szám vagy kötőjel (-_) karakterek lehetnek.` alpha_dash_dot_error=` betű, szám vagy kötőjel (-_) vagy pont karakterek lehetnek.` -git_ref_name_error=` egy jól formált git referenciának kell lennie.` +git_ref_name_error=` egy git referenciának kell lennie.` size_error=` %s méretűnek kell lennie.` min_size_error=` legalább %s karaktert kell tartalmaznia.` max_size_error=` legfeljebb %s karaktert tartalmazhat.` @@ -565,7 +565,7 @@ editor.fork_before_edit=Először csinálnia kell egy másolatot tárolóról mi editor.delete_this_file=A fájl törlése editor.must_have_write_access=Írási jog szükséges hogy módosíthassa, vagy módosításokat javasolhasson ehhez a fájlhoz editor.file_delete_success=A(z) '%s' fájl sikeresen törölve! -editor.name_your_file=Nevezd el a fájlod... +editor.name_your_file=Fájl elnevezése… editor.filename_help=Egy könyvtár hozzáadásához gépelje be és üssön egy /-t. Egy könyvtár eltávolításához menyjen a mező elejére és nyomjon backspace-t. editor.or=vagy editor.cancel_lower=mégsem @@ -574,10 +574,10 @@ editor.add_tmpl='%s/' hozzáadása editor.add='%s' hozzáadása editor.update='%s' módosítása editor.delete='%s' törlése -editor.commit_message_desc=Opcionális hosszabb leírás hozzáadása... +editor.commit_message_desc=Opcionális hosszabb leírás hozzáadása… editor.commit_directly_to_this_branch=Mentés egyenesen a(z) %s ágba. editor.create_new_branch=Hozzon létre egy új ágat ennek a commit-nak és indíts egy egyesítési kérést. -editor.new_branch_name_desc=Új ág neve... +editor.new_branch_name_desc=Új ág neve… editor.cancel=Mégsem editor.filename_cannot_be_empty=A fájlnév nem lehet üres. editor.branch_already_exists=A(z) '%s' ág már létezik ebben a tárolóban. @@ -589,7 +589,7 @@ editor.file_changed_while_editing=A fájlt tartalma megváltozott mióta elkezdt editor.file_already_exists=A(z) '%s' nevű fájl már létezik a tárolóban. editor.no_changes_to_show=Nincsen megjeleníthető változás. editor.fail_to_update_file=Nem sikerült létrehozni/módosítani a következő fájlt: '%s' A hiba oka: %v -editor.add_subdir=Alkönyvtár hozzáadása... +editor.add_subdir=Alkönyvtár hozzáadása… editor.unable_to_upload_files=Nem sikerült feltölteni a fájlokat a "%s" hiba: %v editor.upload_files_to_dir=Fájlok feltöltése a következőre: '%s' editor.cannot_commit_to_protected_branch=Nem lehet a következő védett ágra commit-olni: '%s'. @@ -626,7 +626,7 @@ issues.new.no_assignee=Nincs megbízott issues.no_ref=Nincsen ág/címke megadva issues.create=Hibajegy létrehozása issues.new_label=Új címke -issues.new_label_placeholder=Címke neve... +issues.new_label_placeholder=Címke neve… issues.create_label=Címke létrehozása issues.label_templates.title=Előre definiált címkék betöltése issues.label_templates.info=Még nincsenek címkék. Rákattinthatsz az "Új Címke" gombra felül hogy létrehozz egyet, vagy választhatsz egy már létezőt a lenti listából. @@ -914,7 +914,7 @@ settings.convert_confirm=Átalakítás Megerősítése settings.convert_succeed=A tárolót egy rendes tárolóvá kell konvertálni. settings.transfer=Tulajdonjog átadása settings.transfer_desc=A tároló tulajdonának átruházása egy másik felhasználóra, vagy egy szervezetre ahol rendszergazdai jogai van. -settings.transfer_notices_1=- El fogja veszteni a hozzáférését, ha az új tulajdonos egy egyéni felhasználó. +settings.transfer_notices_1=- El fogja veszteni a hozzáférését, ha az új tulajdonos egy önálló felhasználó. settings.transfer_notices_2=- Megmarad a hozzáférése, ha az új tulajdonos egy szervezet és te az egyik tulajdonosa vagy. settings.transfer_form_title=Kérlek, add meg a követező információt a művelet megerősítéséhez: settings.wiki_delete=Wiki adatok törlése @@ -938,7 +938,7 @@ settings.delete_collaborator=Törlés settings.collaborator_deletion=Együttműködő törlése settings.collaborator_deletion_desc=Ennek a felhasználónak nem lesz joga közreműködni a tárolóban a törlés után. Biztos, hogy folytatni szeretné? settings.remove_collaborator_success=Az együttműködő eltávolítva. -settings.search_user_placeholder=Felhasználók keresése... +settings.search_user_placeholder=Felhasználó keresése… settings.org_not_allowed_to_be_collaborator=Szervezet hozzáadása együttműködőként nem engedélyezett. settings.user_is_org_member=A felhasználó olyan szervezeti tag, aki nem adható hozzá együttműködőként. settings.add_webhook=Webhook hozzáadása @@ -1029,7 +1029,7 @@ settings.remove_protected_branch_success=%s ág védelme opciók sikeresen eltá settings.protected_branch_deletion=Védett ág törlése settings.protected_branch_deletion_desc=Bárki írási joggal tud majd push-olni közvetlenül erre az ágra. Biztos vagy benne? settings.default_branch_desc=Az alapértelmezett ág az "alap", ahova automatikusan az összes commit készül, és az egyesítési kérések is ezt veszik az összehasonlítás alapjául, ha nem állítasz be egy másik ágat. -settings.choose_branch=Válasszon egy ágat... +settings.choose_branch=Válasszon egy ágat… settings.no_protected_branch=Nincsenek védett ágak diff.browse_source=Forráskód böngészése @@ -1063,7 +1063,7 @@ release.title=Cím release.content=Tartalom release.write=Írás release.preview=Előnézet -release.loading=Betöltés... +release.loading=Betöltés… release.prerelease_desc=Ez egy előzetes kiadás release.prerelease_helper=Tájékoztatjuk, hogy a kiadás nem kész éles rendszerben használatra. release.cancel=Mégsem @@ -1177,7 +1177,7 @@ teams.read_permission_desc=Ez a csoport Olvasási jogosultságo teams.write_permission_desc=Ez a csoport Írási jogosultságot ad: a tagok olvasni és feltölteni is tudnak a csoport tárolóiba. teams.admin_permission_desc=A csoport rendszergazdai jogosultságot ad: a tagok olvasási, írási jogosultsággal rendelkeznek és együttműködőket adhatnak hozzá a csoport tárolóihoz. teams.repositories=Csoport tárolói -teams.search_repo_placeholder=Tároló keresés... +teams.search_repo_placeholder=Tároló keresése… teams.add_team_repository=Új csoport tároló teams.remove_repo=Eltávolítás teams.add_nonexistent_repo=A tároló, melybe feltölteni szeretne, még nem létezik; először hozza létre. diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 92305d8f4..c5d071e5f 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -17,7 +17,6 @@ page=Halaman template=Contoh language=Bahasa notifications=Notifikasi -create_new=Buat... user_profile_and_more=Profil pengguna dan lainnya signed_in_as=Masuk sebagai enable_javascript=Situs web ini bekerja lebih baik dengan JavaScript @@ -155,12 +154,10 @@ uname_holder=Nama pengguna atau surel password_holder=Kata Sandi switch_dashboard_context=Alihkan Dasbor Konteks my_repos=Repositori Saya -show_more_repos=Tampilkan repositori lainnya ... collaborative_repos=Repositori Kolaboratif my_orgs=Organisasi Saya my_mirrors=Duplikat Saya view_home=Lihat %s -search_repos=Cari sebuah repositori ... issues.in_your_repos=Dalam repositori anda @@ -249,7 +246,6 @@ Content=Konten require_error=` tidak boleh kosong.` alpha_dash_error=` harus berupa alfanumerik yang valid atau karakter tanda garis(-_).` alpha_dash_dot_error=` harus berupa alfanumerik yang valid, karakter tanda garis(-_) atau titik.` -git_ref_name_error=` harus berupa nama referensi git yang terbentuk dengan baik.` size_error=` harus berukuran %s.` min_size_error=` harus berisi karakter %s setidaknya.` max_size_error=` harus mengandung paling banyak %s karakter.` @@ -335,7 +331,6 @@ enable_custom_avatar=Gunakan Avatar Pilihan choose_new_avatar=Pilih avatar baru update_avatar=Perbarui Pengaturan Avatar delete_current_avatar=Hapus Avatar Saat Ini -uploaded_avatar_not_a_image=Berkas yang diunggah bukanlah gambar. update_avatar_success=Pengaturan avatar anda telah diperbarui. change_password=Ganti Kata Sandi @@ -565,7 +560,6 @@ editor.fork_before_edit=Anda harus fork repositori ini sebelum mengubah berkasny editor.delete_this_file=Hapus berkas ini editor.must_have_write_access=Anda harus memiliki akses menulis untuk membuat atau mengusulkan perubahan ke berkas ini editor.file_delete_success=File '%s' telah berhasil dihapus! -editor.name_your_file=Nama file anda... editor.filename_help=Untuk menambahkan direktori, ketik saja itu dan tekan /. Untuk menghilangkan direktori, pergi ke permulaan dari bidang dan tekan backspace. editor.or=atau editor.cancel_lower=batalkan @@ -574,10 +568,8 @@ editor.add_tmpl=Tambah '%s/' editor.add=Menambah '%s' editor.update=Memperbarui '%s' editor.delete=Menghapus '%s' -editor.commit_message_desc=Tambahkan sebuah deskripsi opsional yang diperpanjang... editor.commit_directly_to_this_branch=Komitmen langsung ke %s cabang. editor.create_new_branch=Membuat new branch untuk tarik komit ini mulai permintaan. -editor.new_branch_name_desc=Nama cabang terbaru... editor.cancel=Membatalkan editor.filename_cannot_be_empty=Nama file tidak boleh kosong. editor.branch_already_exists=Cabang '%s' sudah ada di repositori ini. @@ -589,7 +581,6 @@ editor.file_changed_while_editing=Konten file ini sudah berubah semenjak anda mu editor.file_already_exists=Sebuah berkas dengan nama '%s' sudah ada didalam gudang penyimpanan. editor.no_changes_to_show=Tidak ada perubahan untuk ditampilkan. editor.fail_to_update_file=Gagal untuk memperbarui/buat berkas '%s' dengan kesalahan: %v -editor.add_subdir=Menambah subdirektori... editor.unable_to_upload_files=Gagal untuk mengunggah berkas ke '%s' dengan kesalahan: %v editor.upload_files_to_dir=Unggah berkas ke '%s' editor.cannot_commit_to_protected_branch=Tidak dapat berkomitmen padang cabang yang dilindungi '%s'. @@ -626,7 +617,6 @@ issues.new.no_assignee=Tidak ada penerima issues.no_ref=Tidak Ada Cabang/Tag Ditentukan issues.create=Buat Masalah issues.new_label=Label Baru -issues.new_label_placeholder=Nama label... issues.create_label=Buat Label issues.label_templates.title=Muat sebuah label yang telah ditentukan issues.label_templates.info=Belum ada label apapun. Anda dapat mengklik tombol "New Label" di atas untuk membuat atau menggunakan yang telah ditentukan di bawah. @@ -897,7 +887,6 @@ settings.tracker_url_format=Format URL pelacak edisi Eksternal settings.tracker_issue_style=Isu Penamaan Tracker Isu Eksternal: settings.tracker_issue_style.numeric=Numerik settings.tracker_issue_style.alphanumeric=Alfhanumerik -settings.tracker_url_format_desc=Anda dapat menggunakan placeholder {user} {repo} {index} untuk nama pengguna, nama repositori dan indeks masalah. settings.enable_timetracker=Mengaktifkan pelacak waktu settings.allow_only_contributors_to_track_time=Izinkan hanya kontributor untuk melacak waktu settings.pulls_desc=Mengaktifkan permintaan menarik untuk menerima sumbangan publik @@ -914,7 +903,6 @@ settings.convert_confirm=Konfirmasi Konversi settings.convert_succeed=Repositori telah dikonversi ke repositori biasa. settings.transfer=Transfer Kepemilikan settings.transfer_desc=Transfer repositori ini ke pengguna lain atau ke sebuah organisasi di mana anda memiliki hak admin. -settings.transfer_notices_1=- Anda akan kehilangan akses jika pemilik baru adalah individu pengguna. settings.transfer_notices_2=- Anda akan mempertahankan akses jika pemilik baru suatu organisasi dan jika anda salah satu dari pemilik. settings.transfer_form_title=Silakan masukkan informasi berikut untuk mengkonfirmasi operasi anda: settings.wiki_delete=Menghapus Data Wiki @@ -938,7 +926,6 @@ settings.delete_collaborator=Hapus settings.collaborator_deletion=Penghapusan Kolaborator settings.collaborator_deletion_desc=Pengguna ini tidak akan lagi memiliki akses kolaborasi untuk gudang penyimpanan ini setelah penghapusan. Apakah anda ingin melanjutkan? settings.remove_collaborator_success=Kolaborator telah dihapus. -settings.search_user_placeholder=Telusuri pengguna... settings.org_not_allowed_to_be_collaborator=Organisasi tidak diizinkan untuk ditambahkan sebagai kolaborator. settings.user_is_org_member=Pengguna adalah anggota organisasi yang tidak bisa ditambahkan sebagai kolaborator. settings.add_webhook=Tambahkan Webhook @@ -1029,7 +1016,6 @@ settings.remove_protected_branch_success=Cabang %s melindungi pilihan yang telah settings.protected_branch_deletion=Menghapus cabang yang di lindungi settings.protected_branch_deletion_desc=Siapa pun dengan izin menulis akan mampu mendorong langsung ke cabang ini. Apakah anda yakin? settings.default_branch_desc=Cabang default dianggap sebagai "dasar" cabang di repositori anda terhadap semua permintaan tarik dan kode berkomitmen secara otomatis, kecuali jika anda menentukan cabang berbeda. -settings.choose_branch=Memilih cabang... settings.no_protected_branch=Tidak ada cabang yang dilindungi diff.browse_source=Telusuri Sumber @@ -1063,7 +1049,6 @@ release.title=Judul release.content=Konten release.write=Menulis release.preview=Pratinjau -release.loading=Pemuatan... release.prerelease_desc=Ini adalah pra-rilis release.prerelease_helper=Kami akan menunjukkan bahwa rilis ini tidak siap-diproduksi. release.cancel=Membatalkan @@ -1177,7 +1162,6 @@ teams.read_permission_desc=Bantuan tim Baca mengakses: anggota teams.write_permission_desc=Bantuan tim ini Tulis mengakses: anggota dapat membaca dan mendorong kepada repositori tim. teams.admin_permission_desc=Bantuan tim ini Pengelola mengakses: anggota dapat membaca, mendorong, dan menambahkan kolaburator ke repositori tim. teams.repositories=Tim repositori -teams.search_repo_placeholder=Cari repositori... teams.add_team_repository=Tambahkan Tim Repositori teams.remove_repo=Menghapus teams.add_nonexistent_repo=Repositori yang ingin Anda tambahkan tidak ada; Silahkan buat terlebih dahulu. @@ -1313,7 +1297,6 @@ auths.bind_password_helper=Peringatan: password Ini disimpan dalam bentuk teks b auths.user_base=Basis pencarian pengguna auths.user_dn=Pengguna DN auths.attribute_username=Atribut nama pengguna -auths.attribute_username_placeholder=Biarkan kosong untuk menggunakan nilai bidang formulir untuk masuk sebagai nama pengguna. auths.attribute_name=Atribut nama depan auths.attribute_surname=Atribut nama keluarga auths.attribute_mail=Atribut email diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index a41bbd64c..078a2a3ed 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -17,7 +17,6 @@ page=Pagina template=Template language=Lingua notifications=Notifiche -create_new=Crea... user_profile_and_more=Profilo utente e altro signed_in_as=Accesso effettuato come enable_javascript=Questo sito funziona meglio con JavaScript @@ -154,12 +153,10 @@ uname_holder=Nome Utente o E-mail password_holder=Password switch_dashboard_context=Cambia Dashboard Context my_repos=I miei Repository -show_more_repos=Mostra altri repository... collaborative_repos=Repository Condivisi my_orgs=Le mie Organizzazioni my_mirrors=I miei Mirror view_home=Vedi %s -search_repos=Trova un repository ... issues.in_your_repos=Nei tuoi repository @@ -248,7 +245,6 @@ Content=Contenuto require_error=` non può essere vuoto.` alpha_dash_error=` ammessi solo caratteri alfanumerici o trattini(-_).` alpha_dash_dot_error=` ammessi solo caratteri alfanumerici, trattini(-_) o punti.` -git_ref_name_error=`deve essere ben formato come nome di riferimento.` size_error='deve essere %s.' min_size_error=` deve contenere almeno %s caratteri.` max_size_error=` deve contenere massimo %s caratteri.` @@ -334,7 +330,6 @@ enable_custom_avatar=Abilita avatar personalizzato choose_new_avatar=Scegli un nuovo avatar update_avatar=Aggiorna le impostazioni avatar delete_current_avatar=Elimina Avatar attuale -uploaded_avatar_not_a_image=Il file caricato non è un'immagine. update_avatar_success=Le impostazioni del tuo avatar sono state aggiornate. change_password=Cambia Password @@ -497,10 +492,8 @@ editor.add_tmpl=Aggiungi '%s/' editor.add=Aggiungi '%s' editor.update=Aggiornare '%s' editor.delete=Eliminare '%s' -editor.commit_message_desc=Aggiungi una descrizione estesa facoltativa... editor.commit_directly_to_this_branch=Impegnarsi direttamente con il %s branch. editor.create_new_branch=Creare un nuovo branch per questo commit e inizia una pull request. -editor.new_branch_name_desc=Nome del nuovo branch... editor.cancel=Cancellare editor.filename_cannot_be_empty=Il nome del file non può essere vuoto. editor.branch_already_exists=Branch '%s' esiste già in questo repository. @@ -512,7 +505,6 @@ editor.file_changed_while_editing=Il contenuto del file è stato modificato da q editor.file_already_exists=Un file con nome '%s' esiste già in questo repository. editor.no_changes_to_show=Non ci sono cambiamenti da mostrare. editor.fail_to_update_file=Errore durante l'aggiornamento/ creazione del file '%s' con errore: %v -editor.add_subdir=Aggiungi sottocartella... editor.unable_to_upload_files=Impossibile caricare i file su '%s' con errore:%v commits.search=Ricerca una versione @@ -537,7 +529,6 @@ issues.new.clear_assignee=Cancella l'assegnatario issues.new.no_assignee=Nessun assegnatario issues.create=Crea Problema issues.new_label=Nuova etichetta -issues.new_label_placeholder=Nome dell'etichetta... issues.create_label=Crea Etichetta issues.open_tab=%d Aperti issues.close_tab=%d Chiusi @@ -706,7 +697,6 @@ settings.delete_collaborator=Elimina settings.collaborator_deletion=Eliminazione collaboratore settings.collaborator_deletion_desc=Questo utente non potrà più collaborare a questo repository dopo l'eliminazione. Si desidera continuare? settings.remove_collaborator_success=Il collaboratore è stato rimosso. -settings.search_user_placeholder=Cerca utente... settings.org_not_allowed_to_be_collaborator=Un'organizzazione non può essere aggiunta come collaboratore. settings.user_is_org_member=L'utente è un membro dell'organizzazione che non può essere aggiunto come collaboratore. settings.add_webhook=Aggiungi Webhook @@ -772,7 +762,6 @@ release.title=Titolo release.content=Contenuto release.write=Scrivi release.preview=Anteprima -release.loading=Caricamento... release.prerelease_desc=Questo è un pre-rilascio release.prerelease_helper=Precisiamo che questo rilascio non è pronta per la produzione. release.cancel=Annulla @@ -845,7 +834,6 @@ teams.read_permission_desc=Questo Team concede accesso di LetturaScrittura: i membri possono leggere e pushare i repository del Team. teams.admin_permission_desc=Questo Team concede accesso di Amministratore: i membri possono leggere i, pushare a, e aggiungere collaboratori ai repository del Team. teams.repositories=Repository di Squadra -teams.search_repo_placeholder=Cerca repository... teams.add_team_repository=Aggiungere Repository di Squadra teams.remove_repo=Rimuovi teams.add_nonexistent_repo=Il repository che stai tentando di aggiungere non esiste, crealo prima. diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 9583b9f1c..120c1ed31 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -17,7 +17,6 @@ page=ページ template=テンプレート language=言語 notifications=通知 -create_new=作成... user_profile_and_more=ユーザープロフィール等 signed_in_as=ログイン済み enable_javascript=このサイトはJavaScriptを使用しています @@ -154,12 +153,10 @@ uname_holder=ユーザー名またはEメールアドレス password_holder=パスワード switch_dashboard_context=ダッシュ ボードのコンテキストを切替 my_repos=自分のリポジトリ -show_more_repos=リポジトリをさらに表示する… collaborative_repos=共同リポジトリ my_orgs=自分の組織 my_mirrors=自分のミラー view_home=ビュー %s -search_repos=レポジトリーを探す... issues.in_your_repos=あなたのリポジトリ @@ -248,7 +245,6 @@ Content=コンテンツ require_error=`は空にできません` alpha_dash_error=`は英数字、ダッシュ(-_)のみ使用可能です。` alpha_dash_dot_error=`は英数字、ダッシュ(-_)、ドットのみ使用可能です。` -git_ref_name_error=`は有効なGit参照名である必要があります。` size_error=`サイズは %s である必要があります` min_size_error=`は%s文字以上である必要があります。` max_size_error=`は%s文字以下である必要があります。` @@ -334,7 +330,6 @@ enable_custom_avatar=カスタムのアバターを有効にする choose_new_avatar=新しいアバターを選択 update_avatar=アバターの設定を更新 delete_current_avatar=現在のアバターを削除 -uploaded_avatar_not_a_image=アップロードされたファイルは画像ではない。 update_avatar_success=アバター設定が更新されました。 change_password=パスワードを変更 @@ -564,7 +559,6 @@ editor.fork_before_edit=このファイルを編集する前にこのリポジ editor.delete_this_file=このファイルを削除 editor.must_have_write_access=このファイルを作成または変更の提案をするには、書き込み権限が必要です。 editor.file_delete_success=ファイル '%s' は正常に削除されました。 -editor.name_your_file=ファイル名を指定... editor.filename_help=ディレクトリを作成するには、/ を入力してください。ディレクトリを削除するには、入力欄の先頭でバックスペースを押してください。 editor.or=または editor.cancel_lower=キャンセル @@ -573,10 +567,8 @@ editor.add_tmpl='%s/' を追加 editor.add='%s' を追加 editor.update='%s' を更新 editor.delete='%s' を削除 -editor.commit_message_desc=詳細を追加... editor.commit_directly_to_this_branch=ブランチ%sへ直接コミットする。 editor.create_new_branch=新しいブランチにコミットしてプルリクエストを作成する。 -editor.new_branch_name_desc=新しいブランチ名... editor.cancel=キャンセル editor.filename_cannot_be_empty=ファイル名を入力してください。 editor.branch_already_exists=ブランチ '%s' は、このリポジトリに既に存在します。 @@ -588,7 +580,6 @@ editor.file_changed_while_editing=あなたが編集をはじめて以降、フ editor.file_already_exists=ファイル '%s' は既に存在します。 editor.no_changes_to_show=表示する変更箇所はありません。 editor.fail_to_update_file=ファイル '%s' を作成または変更できませんでした: %v -editor.add_subdir=サブディレクトリを追加... editor.unable_to_upload_files='%s' へファイルをアップロードすることができませんでした: %v editor.upload_files_to_dir='%s' にファイルをアップロードする editor.cannot_commit_to_protected_branch=保護されたブランチ '%s' にコミットすることはできません。 @@ -625,7 +616,6 @@ issues.new.no_assignee=担当者なし issues.no_ref=ブランチ/タグが指定されていません issues.create=問題を作成 issues.new_label=新しいラベル -issues.new_label_placeholder=ラベル名... issues.create_label=ラベルを作成 issues.label_templates.title=予め定義されたラベルセットを読み込む issues.label_templates.info=まだラベルはありません。上の"新しいラベル"をクリックして新しいラベルを作成するか、以下の予め定義されたラベルセットを使うことができます。 @@ -895,7 +885,6 @@ settings.tracker_url_format=外部課題トラッキングツール URLのフォ settings.tracker_issue_style=外部の課題トラッキングツールの命名規則: settings.tracker_issue_style.numeric=数値 settings.tracker_issue_style.alphanumeric=英数字 -settings.tracker_url_format_desc=プレースホルダ{user} {repo} {index}を利用できます。それぞれユーザー名、リポジトリ名、課題番号です。 settings.enable_timetracker=タイムトラッカーを有効にする settings.allow_only_contributors_to_track_time=コントリビューターのみにタイムトラッキングを許可 settings.pulls_desc=プルリクエストを有効にしてコントリビューションを受け入れる @@ -912,7 +901,6 @@ settings.convert_confirm=続行する settings.convert_succeed=通常のリポジトリに変更されました。 settings.transfer=オーナー移転 settings.transfer_desc=リポジトリをあなたが管理者権限を持っている別のユーザーまた組織に移譲します。 -settings.transfer_notices_1=- 新しい所有者が個人ユーザーの場合、あなたはリポジトリにアクセスできなくなります。 settings.transfer_notices_2=- 新しい所有者が組織で、あなたがその組織の所有者である場合はアクセス権が残ります。 settings.transfer_form_title=操作を確認するために、以下の情報を入力してください: settings.wiki_delete=Wikiのデータ消去 @@ -936,7 +924,6 @@ settings.delete_collaborator=削除 settings.collaborator_deletion=共同編集者の削除 settings.collaborator_deletion_desc=削除後、このユーザーはこのリポジトリへアクセスできなくなります。続行しますか? settings.remove_collaborator_success=共同編集者が削除されました。 -settings.search_user_placeholder=Search users settings.org_not_allowed_to_be_collaborator=組織を共同編集者として追加することはできません。 settings.user_is_org_member=ユーザーは組織の一員なので、共同編集者として追加することはできません。 settings.add_webhook=Webhook を追加 @@ -1027,7 +1014,6 @@ settings.remove_protected_branch_success=ブランチ %s の保護設定は正 settings.protected_branch_deletion=保護されたブランチの削除 settings.protected_branch_deletion_desc=書き込み権限のあるユーザーはこのブランチに直接プッシュできるようになります。よろしいですか? settings.default_branch_desc=デフォルトブランチはプルリクエストやコミットが自動的に作成される際、別のブランチが指定されなかった場合に"ベース"として選択されるブランチです。 -settings.choose_branch=ブランチを選択する... settings.no_protected_branch=保護されたブランチがありません diff.browse_source=ソースを参照 @@ -1061,7 +1047,6 @@ release.title=タイトル release.content=コンテント release.write=書込み release.preview=プレビュー -release.loading=読み込み中… release.prerelease_desc=これはリリース前のものです release.prerelease_helper=このリリースは非プロダクション利用として識別します。 release.cancel=キャンセル @@ -1175,7 +1160,6 @@ teams.read_permission_desc=このチームは読み取り権限 teams.write_permission_desc=このチームは書き込み権限を持ち: メンバーはリポジトリの表示及リポジトリへのプッシュができます。 teams.admin_permission_desc=このチームは管理者の権限を持ち: メンバーはチームのリポジトリに対して、読み取り、プッシュや共同編集者の追加ができます。 teams.repositories=チームのリポジトリ -teams.search_repo_placeholder=リポジトリを検索 teams.add_team_repository=チームのリポジトリを追加 teams.remove_repo=削除(Remove) teams.add_nonexistent_repo=追加しようとしているリポジトリは存在しません。まずはじめに作成してください。 @@ -1309,7 +1293,6 @@ auths.bind_password_helper=警告: このパスワードは暗号化されずに auths.user_base=ユーザ検索ベース auths.user_dn=ユーザーDN auths.attribute_username=ユーザー名の属性 -auths.attribute_username_placeholder=ログインフォームの値を使う場合は空にしてください。 auths.attribute_name=名前属性 auths.attribute_surname=名字属性 auths.attribute_mail=Eメール属性 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index dff13de80..62269dc60 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -16,7 +16,6 @@ page=페이지 template=템플릿 language=언어 notifications=알림 -create_new=만들기... user_profile_and_more=사용자 프로필 및 기타 signed_in_as=다음 사용자로 로그인됨 @@ -150,12 +149,10 @@ uname_holder=사용자 이름이나 이메일 password_holder=비밀번호 switch_dashboard_context=대시보드 컨텍스트 바꾸기 my_repos=내 저장소 -show_more_repos=더 많은 저장소 보기... collaborative_repos=협업 저장소 my_orgs=내 조직 my_mirrors=내 미러 저장소들 view_home=%s 보기 -search_repos=저장소 찾기.. issues.in_your_repos=당신의 저장소에 @@ -241,7 +238,6 @@ Content=컨텐츠 require_error=` 비어 있을 수 없습니다.` alpha_dash_error=`은(는) 숫자, 알파벳, 대시(-_) 문자로만 구성되어야 합니다.` alpha_dash_dot_error=` 숫자, 알파벳, 점(.), 대시(-_) 문자로만 구성되어야 합니다.` -git_ref_name_error=` 유효한 git 레퍼런스명이어야 합니다.` size_error=` %s 글자여야 합니다.` min_size_error=` 최소 %s 글자여야 합니다.` max_size_error=` %s 글자를 넘을 수 없습니다.` @@ -317,7 +313,6 @@ enable_custom_avatar=사용자정의 아바타를 사용 choose_new_avatar=새로운 아바타 선택 update_avatar=아바타 설정 업데이트 delete_current_avatar=현재 아바타 삭제 -uploaded_avatar_not_a_image=업로드 된 파일은 이미지가 아닙니다. update_avatar_success=아바타 설정이 성공적으로 변경되었습니다.. change_password=비밀번호 변경 @@ -508,7 +503,6 @@ editor.fork_before_edit=파일을 편집 하기 전에 이 저장소를 포크 editor.delete_this_file=이 파일을 삭제 editor.must_have_write_access=이 파일에 변경 사항을 제안하기 위해서는 쓰기 권한이 있어야 합니다. editor.file_delete_success='%s' 파일이 성공적으로 삭제 되었습니다! -editor.name_your_file=파일 명... editor.filename_help=디렉토리를 추가하려면, 디렉토리명을 입력하고 /를 누르십시오. 디렉토리를 제거하려면 필드의 시작 부분으로 이동하여 백 스페이스 키를 누릅니다. editor.or=혹은 editor.cancel_lower=취소 @@ -517,10 +511,8 @@ editor.add_tmpl=추가 '%s/' editor.add=추가 '%s' editor.update=업데이트 '%s' editor.delete=삭제 '%s' -editor.commit_message_desc=선택적 확장 설명을 추가 editor.commit_directly_to_this_branch=%s 브랜치에서 직접 커밋해주세요. editor.create_new_branch=이 커밋에 대한 새로운 브랜치를 만들고 끌어오기 요청을 시작합니다. -editor.new_branch_name_desc=새로운 브랜치 명 editor.cancel=취소 editor.filename_cannot_be_empty=파일명이 빈칸입니다. editor.branch_already_exists=이 저장소에 브랜치 '%s'가 이미 존재합니다. @@ -532,7 +524,6 @@ editor.file_changed_while_editing=수정을 시작한 이후에 파일 내용이 editor.file_already_exists=이 저장소에 이름이 '%s'인 파일이 이미 존재합니다. editor.no_changes_to_show=표시할 변경사항이 없습니다. editor.fail_to_update_file=파일 '%s'를 변경/추가 하는데 실패하였습니다. 에러: %v -editor.add_subdir=하위 디렉토리 추가... editor.unable_to_upload_files=파일 '%s'를 업로드하는데 실패하였습니다. 에러: %v editor.upload_files_to_dir=파일 업로드 '%s' editor.cannot_commit_to_protected_branch=보호된 브랜치 '%s'에 커밋할수 없습니다. @@ -568,7 +559,6 @@ issues.new.no_assignee=담당자 없음 issues.no_ref=Branch/Tag 가 지정되어 있지 않습니다. issues.create=이슈 생성 issues.new_label=새로운 레이블 -issues.new_label_placeholder=레이블 이름... issues.create_label=레이블 만들기 issues.label_templates.title=사전정의 라벨 로드 issues.label_templates.info=아직 라벨이 없습니다. 위의 '새 라벨' 버튼을 클릭하여 라벨을 하나 만들거나 사전 정의 세트를 사용할 수 있습니다. @@ -752,7 +742,6 @@ settings.tracker_url_format=외부 이슈 트래커 URL 형식 settings.tracker_issue_style=외부 이슈 트래커 명명 스타일: settings.tracker_issue_style.numeric=숫자 settings.tracker_issue_style.alphanumeric=문자 숫자 -settings.tracker_url_format_desc={user} {repo} {index} 사용자 명, 저장소 명, 이슈 인덱스를 사용하여 표시자를 사용할 수 있습니다. settings.pulls_desc=끌어오기 요청을 공개적으로 기여받을 수 있도록 활성화합니다. settings.danger_zone=위험 설정 settings.new_owner_has_same_repo=새로운 소유자가 같은 이름의 저장소를 이미 가지고 있습니다. 다른 이름을 선택해주세요. @@ -780,7 +769,6 @@ settings.delete_collaborator=제거 settings.collaborator_deletion=공동작업자 삭제 settings.collaborator_deletion_desc=이 사용자는 더 이상 이 저장소의 공동 작업을 위한 접근 권한을 가질 수 없게 됩니다. 계속 하시겠습니까? settings.remove_collaborator_success=공동작업자가 삭제 되었습니다. -settings.search_user_placeholder=사용자 검색... settings.org_not_allowed_to_be_collaborator=조직을 공동 작업자로 추가할 수 없습니다. settings.user_is_org_member=사용자가 조직 구성원이므로 공동 작업자로 추가할 수 없습니다. settings.add_webhook=Webhook 추가 @@ -843,7 +831,6 @@ settings.protected_branch=브랜치 보호 settings.add_protected_branch=보호 활성화 settings.delete_protected_branch=보호 비활성화 settings.protected_branch_deletion_desc=쓰기 권한이 있는 모든 사용자가 이 브랜치에 직접 푸시 할 수있게 됩니다. 확실한가요? -settings.choose_branch=브랜치를 선택하세요... settings.no_protected_branch=보호된 브랜치가 없습니다. diff.browse_source=소스 검색 @@ -876,7 +863,6 @@ release.title=제목 release.content=컨텐츠 release.write=쓰기 release.preview=미리보기 -release.loading=로딩중... release.prerelease_desc=이것은 사전 릴리즈 release.prerelease_helper=이 릴리즈는 제품-준비가 되어있지 않았음을 알려드립니다. release.cancel=취소 @@ -967,7 +953,6 @@ teams.read_permission_desc=이 팀의 읽기 권한을 부여: teams.write_permission_desc=이 팀의 쓰기 권한을 부여: 회원은 이 팀의 저장소를 읽거나 푸시할 수 있습니다. teams.admin_permission_desc=이 팀의 관리자 권한을 부여: 회원은 이 팀의 저장소를 읽거나 푸시하거나 추가하고 공동 작업자를 추가할 수 있습니다. teams.repositories=팀 저장소 -teams.search_repo_placeholder=저장소 검색... teams.add_team_repository=팀 저장소 추가 teams.remove_repo=삭제 teams.add_nonexistent_repo=추가하려는 저장소를 존재하지 않습니다. 먼저 생성해주세요. @@ -1070,7 +1055,6 @@ auths.bind_password=비밀번호 연결 auths.user_base=사용자 검색 기준 auths.user_dn=사용자 DN auths.attribute_username=유저 명 속성 -auths.attribute_username_placeholder=사용자 이름에 대한 로그인 폼 필드 값을 사용하려면 비워 둡니다. auths.attribute_name=이름 속성 auths.attribute_surname=성씨 속성 auths.attribute_mail=이메일 속성 diff --git a/options/locale/locale_lt-LT.ini b/options/locale/locale_lt-LT.ini index d1e347f8c..bfdddef52 100644 --- a/options/locale/locale_lt-LT.ini +++ b/options/locale/locale_lt-LT.ini @@ -13,7 +13,6 @@ page=Puslapis template=Šablonas language=Kalba notifications=Pranešimai -create_new=Sukurti... user_profile_and_more=Vartotojo profilis ir daugiau signed_in_as=Prisijungta kaip @@ -87,7 +86,6 @@ my_repos=Mano saugyklos my_orgs=Mano organizacijos my_mirrors=Mano veidrodžiai view_home=Rodyti %s -search_repos=Rasti saugyklą... issues.in_your_repos=Savo saugyklose @@ -249,7 +247,6 @@ issues=Problemos editor.edit_this_file=Redaguoti šį failą editor.delete_this_file=Ištrinti šį failą editor.file_delete_success=Sėkmingai panaikintas failas '%s'! -editor.name_your_file=Pavadinkite failą... editor.or=arba editor.cancel_lower=atšaukti editor.add=Pridėti '%s' diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index b27557d79..d9c4f3ce5 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -17,7 +17,6 @@ page=Lapa template=Sagatave language=Valoda notifications=Paziņojumi -create_new=Izveidot... user_profile_and_more=Lietotāja profilu un vairāk signed_in_as=Pierakstījies kā enable_javascript=Šī lapa labāk darbojas, ja pārlūkam ir pieejams JavaScript @@ -155,12 +154,10 @@ uname_holder=Lietotājvārds vai e-pasts password_holder=Parole switch_dashboard_context=Mainīt infopaneļa kontekstu my_repos=Mani repozitoriji -show_more_repos=Parādīt vairāk repozitorijus ... collaborative_repos=Sadarbības repozitoriji my_orgs=Manas organizācijas my_mirrors=Mani spoguļi view_home=Skatīties %s -search_repos=Meklēt repozitoriju... issues.in_your_repos=Jūsu repozitorijos @@ -249,7 +246,6 @@ Content=Saturs require_error=` nedrīkst būt tukšs.` alpha_dash_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus vai domuzīmes (-_).` alpha_dash_dot_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus, domuzīmes (-_) vai punktu.` -git_ref_name_error=` jābūt korektam git references nosaukumam.` size_error=` jābūt %s simbolus garam.` min_size_error=` jabūt vismaz %s simbolu garumā.` max_size_error=` jabūt ne mazāk kā %s simbolu garumā.` @@ -335,7 +331,6 @@ enable_custom_avatar=Iespējot maināmu profila attēlu choose_new_avatar=Izvēlēties jaunu profila attēlu update_avatar=Saglabāt profila bildi delete_current_avatar=Dzēst pašreizējo profila bildi -uploaded_avatar_not_a_image=Augšupielādētais fails nav attēls. update_avatar_success=Profila attēls tika saglabāts. change_password=Mainīt paroli @@ -565,7 +560,6 @@ editor.fork_before_edit=Lai varētu labot failu ir nepieciešams atdalīt repozi editor.delete_this_file=Dzēst šo failu editor.must_have_write_access=Jums ir jābūt rakstīšanas tiesībām, lai varētu veikt vai piedāvāt izmaiņas šim failam editor.file_delete_success=Fails '%s' ir veiksmīgi izdzēsts! -editor.name_your_file=Ievadiet faila nosaukumu... editor.filename_help=Lai pievienotu direktoriju, ierakstiet tās nosaukumu un nospiediet /. Lai noņemtu direktoriju, ielieciet kursoru pirms faila nosaukuma un nospiediet atpakaļatkāpes taustiņu. editor.or=vai editor.cancel_lower=atcelt @@ -574,10 +568,8 @@ editor.add_tmpl=Pievienot '%s/' editor.add=Pievienot '%s' editor.update=Atjaunināt '%s' editor.delete=Dzēst '%s' -editor.commit_message_desc=Pievienot neobligātu paplašinātu aprakstu... editor.commit_directly_to_this_branch=Apstiprināt revīzijas izmaiņas atzarā %s. editor.create_new_branch=Izveidot jaunu atzaru un izmaiņu pieprasījumu šai revīzijai. -editor.new_branch_name_desc=Jaunā atzara nosaukums... editor.cancel=Atcelt editor.filename_cannot_be_empty=Nav ievadīts faila nosaukums. editor.branch_already_exists=Atzars '%s' šajā repozitorijā jau eksistē. @@ -589,7 +581,6 @@ editor.file_changed_while_editing=Faila saturs ir mainījies kopš Jūs sākāt editor.file_already_exists=Fails ar nosaukumu '%s' repozitorijā jau eksistē. editor.no_changes_to_show=Nav izmaiņu, ko rādīt. editor.fail_to_update_file=Neizdevās izmainīt/izveidot failu '%s', kļūda: %v -editor.add_subdir=Pievienot apakšdirektoriju... editor.unable_to_upload_files=Neizdevās augšupielādēt failus uz direktoriju '%s', kļūda: %v editor.upload_files_to_dir=Augšupielādēt failus uz direktoriju '%s' editor.cannot_commit_to_protected_branch=Nav atļauts veikt izmaiņas aizsargātam atzaram '%s'. @@ -626,7 +617,6 @@ issues.new.no_assignee=Nav atbildīgā issues.no_ref=Nav norādīts atzars/tags issues.create=Pieteikt problēmu issues.new_label=Jauna etiķete -issues.new_label_placeholder=Etiķetes nosaukums... issues.create_label=Izveidot etiķeti issues.label_templates.title=Ielādēt sākotnēji noteikto etiķešu kopu issues.label_templates.info=Nav izveidota neviena etiķete. Jūs varat noklikšķināt uz "Jauna etiķete" augstāk, lai to izveidotu vai izmantot zemāk piedāvātās etiķetes. @@ -897,7 +887,6 @@ settings.tracker_url_format=Ārējā problēmu sekotāja adreses formāts settings.tracker_issue_style=Ārējā problēmu reģistra nosaukumu stils: settings.tracker_issue_style.numeric=Cipari settings.tracker_issue_style.alphanumeric=Burti un cipari -settings.tracker_url_format_desc=Jūs varat izmantot {user}{repo}{index} lietotājvārdam, repozitorija nosaukumam un problēmas identifikātoram. settings.enable_timetracker=Iespējot laika uzskaiti settings.allow_only_contributors_to_track_time=Atļaut tikai dalībniekiem uzskaitīt laiku settings.pulls_desc=Iespējot izmaiņu pieprasījumus lai saņemtu publiskus ieguldījumus @@ -914,7 +903,6 @@ settings.convert_confirm=Apstiprināt konvertēšanu settings.convert_succeed=Repozitorijs tika izmainīts par parastu repozitoriju. settings.transfer=Mainīt īpašnieku settings.transfer_desc=Mainīt šī repozitorija īpašnieku uz citu lietotāju vai organizāciju, kurai Jums ir administratora tiesībs. -settings.transfer_notices_1=- Jūs zaudēsiet piekļuvi, ja jaunais īpašnieks ir individuāls lietotājs. settings.transfer_notices_2=- Jūs saglabāsiet piekļuvi, ja jaunais īpašnieks ir organizācija un Jūs esat viens no tās īpašniekiem. settings.transfer_form_title=Ievadiet sekojošu informāciju, lai apstiprinātu savu darbību: settings.wiki_delete=Dzēst Vikivietnes datus @@ -938,7 +926,6 @@ settings.delete_collaborator=Dzēst settings.collaborator_deletion=Līdzstrādnieka dzēšana settings.collaborator_deletion_desc=Šim lietotājam pēc dzēšanas vairs nebūs sadarbības pieejas šai krātuvei. Vai vēlaties turpināt? settings.remove_collaborator_success=Līdzstrādnieks tika noņemts. -settings.search_user_placeholder=Meklēt lietotāju... settings.org_not_allowed_to_be_collaborator=Organizāciju nav atļauts pievienot kā līdzstrādnieku. settings.user_is_org_member=Lietotājs ir organizācijas biedrs, kas nevar tikt pievienots kā līdzstrādnieks. settings.add_webhook=Pievienot tīmekļa āķi @@ -1029,7 +1016,6 @@ settings.remove_protected_branch_success=Atzara %s aizsardzība veiksmīgi noņe settings.protected_branch_deletion=Lai dzēstu atzara aizsardzību settings.protected_branch_deletion_desc=Ikviens ar rakstīšanas tiesībām varēs nosūtīt izmaiņas uz šo zaru. Vai patiešām to vēlaties? settings.default_branch_desc=Noklusētais atzars tiek uzskatīts par bāzes atzaru repozitorijā uz kuru tiks veidoti izmaiņu pieprasījumu un pēc noklusējuma tiek veiktas koda izmaiņas, ja vien nav norādīts cits atzars. -settings.choose_branch=Izvēlieties atzaru... settings.no_protected_branch=Nav neviena aizsargātā atzara diff.browse_source=Pārlūkot izejas kodu @@ -1063,7 +1049,6 @@ release.title=Virsraksts release.content=Saturs release.write=Rakstīt release.preview=Priekšskatītījums -release.loading=Notiek ielāde... release.prerelease_desc=Šī ir pirmslaidiena versija release.prerelease_helper=Tiks norādīts, ka šis laidiens nav gatavs lietošanai produkcijas režīmā. release.cancel=Atcelt @@ -1177,7 +1162,6 @@ teams.read_permission_desc=Šai komandai ir lasīšanas tiesīb teams.write_permission_desc=Šai komandai ir rakstīšanas tiesības: dalībnieki var lasīt un nosūtīt izmaiņas repozitorijiem. teams.admin_permission_desc=Šai komandai ir administratora tiesības: dalībnieki var lasīt, rakstīt un pievienot citus dalībniekus komandas repozitorijiem. teams.repositories=Komandas repozitoriji -teams.search_repo_placeholder=Meklēt repozitorijā... teams.add_team_repository=Pievienot komandas repozitoriju teams.remove_repo=Noņemt teams.add_nonexistent_repo=Repozitorijs, kuram Jūs mēģinat pievienot neeksistē, sākumā izveidojiet to. @@ -1316,7 +1300,6 @@ auths.bind_password_helper=Brīdinājums: Šī parole tiks glabāta nešifrētā auths.user_base=Lietotāja pamatnosacījumi auths.user_dn=Lietotāja DN auths.attribute_username=Lietotājvārda atribūts -auths.attribute_username_placeholder=Atstājiet tukšu, lai izmantotu lietotājvārdu ar kuru autorizējaties. auths.attribute_name=Vārda atribūts auths.attribute_surname=Uzvārda atribūts auths.attribute_mail=E-pasta atribūts diff --git a/options/locale/locale_nb-NO.ini b/options/locale/locale_nb-NO.ini index e62b363bc..6cff76956 100644 --- a/options/locale/locale_nb-NO.ini +++ b/options/locale/locale_nb-NO.ini @@ -17,7 +17,6 @@ page=Side template=Mal language=Språk notifications=Varsler -create_new=Opprett... user_profile_and_more=Brukerprofil med mer signed_in_as=Logget inn som enable_javascript=Dette nettstedet fungerer bedre med JavaScript diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 9b56e11f5..8777f3d7f 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -17,7 +17,6 @@ page=Pagina template=Sjabloon language=Taal notifications=Meldingen -create_new=Creëren... user_profile_and_more=Gebruikersprofiel en meer signed_in_as=Aangemeld als enable_javascript=Deze website werkt beter met JavaScript @@ -155,12 +154,10 @@ uname_holder=Gebruikersnaam of e-mail password_holder=Wachtwoord switch_dashboard_context=Wissel voorpaginacontext my_repos=Mijn repositories -show_more_repos=Toon meer repositories... collaborative_repos=Gedeelde repositories my_orgs=Mijn organisaties my_mirrors=Mijn kopieën view_home=Bekijk %s -search_repos=Zoek een repository... issues.in_your_repos=In uw repositories @@ -249,7 +246,6 @@ Content=Inhoud require_error=kan niet leeg zijn. alpha_dash_error=` moeten valide alfanumerieke karakters of streepjes (-_) zijn.` alpha_dash_dot_error=` moeten valide alfanumerieke karakters, streepjes (-_) of punten zijn.` -git_ref_name_error=` moet een correct geformatteerde git referentie naam zijn.` size_error=moet groter zijn dan %s min_size_error=moet minimaal %s karakters bevatten. max_size_error=mag maximaal %s karakters bevatten. @@ -335,7 +331,6 @@ enable_custom_avatar=Aangepaste avatar inschakelen choose_new_avatar=Kies een nieuwe avatar update_avatar=Avatar instelling bijwerken delete_current_avatar=Verwijder huidige avatar -uploaded_avatar_not_a_image=Geüpload bestand is geen afbeelding. update_avatar_success=Instellingen voor avatar succesvol bijgewerkt. change_password=Verander wachtwoord @@ -557,7 +552,6 @@ editor.must_be_on_a_branch=U moet in een branch zijn om aanpassingen te maken of editor.fork_before_edit=U moet deze repository eerst forken om dit bestand aan te kunnen passen editor.delete_this_file=Verwijder dit bestand editor.file_delete_success=Bestand '%s' is succesvol verwijderd! -editor.name_your_file=Bestandsnaam... editor.or=of editor.cancel_lower=annuleer editor.commit_changes=Wijzigingen doorvoeren @@ -565,9 +559,7 @@ editor.add_tmpl='%s/' toevoegen editor.add='%s' toevoegen editor.update='%s' updaten editor.delete='%s' verwijderen -editor.commit_message_desc=Voeg een optionele beschrijving toe... editor.create_new_branch=Maak een nieuwe branch voor deze commit en start van een pull-aanvraag. -editor.new_branch_name_desc=Nieuwe branch naam... editor.cancel=Annuleer editor.filename_cannot_be_empty=Bestandsnaam mag niet leeg zijn. editor.branch_already_exists=Branch '%s' bestaat al in deze repository. @@ -578,7 +570,6 @@ editor.file_changed_while_editing=Inhoud van het bestand is gewijzigd sinds u be editor.file_already_exists=Een bestand met de naam '%s' bestaat al in deze repository. editor.no_changes_to_show=Er zijn geen wijzigingen om weer te geven. editor.fail_to_update_file=Update/maken van bestand '%s' is mislukt: %v -editor.add_subdir=Submap toevoegen... editor.upload_files_to_dir=Bestanden uploaden naar '%s' commits.commits=Commits @@ -607,7 +598,6 @@ issues.new.clear_assignee=Verwijder verantwoordelijke issues.new.no_assignee=Geen verantwoordelijke issues.create=Maak probleem issues.new_label=Nieuw Label -issues.new_label_placeholder=Tekst label... issues.create_label=Maak label issues.label_templates.title=Laad een vooraf gedefinieerde set labels issues.label_templates.helper=Selecteer een labelset @@ -823,7 +813,6 @@ settings.use_external_issue_tracker=Externe issuetracker gebruiken settings.tracker_url_format=URL-formaat externe issuetracker settings.tracker_issue_style.numeric=Nummeriek settings.tracker_issue_style.alphanumeric=Alfanummeriek -settings.tracker_url_format_desc=U kan de aanduidingen {user} {repo} {index} gebruiken voor de gebruikersnaam, de naam van de repository en de lijst van open tickets. settings.pulls_desc=Schakel 'pull request' in om publieke bijdragen te mogelijk te maken settings.danger_zone=Gevaren zone settings.new_owner_has_same_repo=De nieuwe eigenaar heeft al een repository met deze naam @@ -834,7 +823,6 @@ settings.convert_confirm=Conversie bevestigen settings.convert_succeed=Deze repository is geconverteerd naar een normale repository. settings.transfer=Eigendom overdragen settings.transfer_desc=Draag deze repo over aan een andere gebruiker of een organisatie waar u beheerders rechten heeft. -settings.transfer_notices_1=- U verliest toegang als de nieuwe gebruiker een individuele gebruiker is. settings.transfer_notices_2=- U behoudt toegang indien de nieuwe eigenaar een organisatie is en U één van de eigenaren van de organisatie bent. settings.transfer_form_title=Voer de volgende informatie in om de bewerking te bevestigen: settings.wiki_delete=Wiki gegevens verwijderen @@ -856,7 +844,6 @@ settings.delete_collaborator=Verwijderen settings.collaborator_deletion=Verwijder Medewerker settings.collaborator_deletion_desc=Deze gebruiker zal niet langer toegang hebben tot deze repository. Wilt U doorgaan? settings.remove_collaborator_success=medewerker is verwijderd. -settings.search_user_placeholder=Zoek gebruiker... settings.org_not_allowed_to_be_collaborator=De organisatie kan niet toegevoegd worden als medewerker. settings.user_is_org_member=Gebruiker is lid van de organisatie die als een medewerker kan niet worden toegevoegd. settings.add_webhook=Webhook toevoegen @@ -922,7 +909,6 @@ settings.protect_whitelist_search_teams=Zoek teams settings.add_protected_branch=Bescherming aanzetten settings.delete_protected_branch=Bescherming uitzetten settings.remove_protected_branch_success=%s is ontgrendeld -settings.choose_branch=Kies een branch... settings.no_protected_branch=Er zijn geen beschermde branches diff.browse_source=Bladeren bron @@ -951,7 +937,6 @@ release.title=Titel release.content=Inhoud release.write=Schrijf release.preview=Voorbeeld -release.loading=Laden... release.prerelease_desc=Dit is een beta-versie release.prerelease_helper=Wij wijzen u erop dat deze release is niet geschikt voor productie doeleinden. release.cancel=Annuleren @@ -1048,7 +1033,6 @@ teams.read_permission_desc=Dit team heeft Lees rechten : leden teams.write_permission_desc=Dit team heeft Schrijf rechten : leden kunnen repositories lezen en push aanvragen verwerken. teams.admin_permission_desc=Dit team heeft Beheerders rechten : leden kunnen repositories lezen en push aanvragen verwerken en medewerkers toevoegen. teams.repositories=Teamrepositories -teams.search_repo_placeholder=Repository zoeken... teams.add_team_repository=Nieuwe teamrepositorie aanmaken teams.remove_repo=Verwijder teams.add_nonexistent_repo=De opslagplaats die u probeert toe te voegen bestaat niet: maak deze eerst aan. @@ -1169,7 +1153,6 @@ auths.bind_dn=Binden DN auths.bind_password=Bind wachtwoord auths.bind_password_helper=Opgelet: Dit wachtwoord wordt opgeslagen als leesbare tekst. Gebruik geen account met verhoogde rechten. auths.attribute_username=Gebruikersnaam attribuut -auths.attribute_username_placeholder=Laat leeg om het login veld van het formulier te gebruiken als gebruikersnaam. auths.attribute_name=Voornaam attribuut auths.attribute_surname=Achternaam attribuut auths.attribute_mail=E-mail attribuut diff --git a/options/locale/locale_no-NO.ini b/options/locale/locale_no-NO.ini index 63fd70985..60127da43 100644 --- a/options/locale/locale_no-NO.ini +++ b/options/locale/locale_no-NO.ini @@ -15,7 +15,6 @@ page=Side template=Mal language=Språk notifications=Varsler -create_new=Opprett... user_profile_and_more=Brukerprofil med mer signed_in_as=Logget inn som diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 87ed83b59..0d85b724b 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -17,7 +17,6 @@ page=Strona template=Szablon language=Język notifications=Powiadomienia -create_new=Utwórz... user_profile_and_more=Profil użytkownika i więcej signed_in_as=Zalogowany jako enable_javascript=Strona działa najlepiej z JavaScript @@ -154,12 +153,10 @@ uname_holder=Nazwa użytkownika lub e-mail password_holder=Hasło switch_dashboard_context=Przełącz kontekst pulpitu my_repos=Moje repozytoria -show_more_repos=Pokaż więcej repozytoriów ... collaborative_repos=Wspólne repozytoria my_orgs=Moje organizacje my_mirrors=Moje kopie lustrzane view_home=Zobacz %s -search_repos=Znajdź repozytorium ... issues.in_your_repos=W Twoich repozytoriach @@ -248,7 +245,6 @@ Content=Treść require_error=` nie może być puste.` alpha_dash_error=` musi się składać ze znaków alfanumerycznych, myślników lub podkreśleń.` alpha_dash_dot_error=` musi się składać ze znaków alfanumerycznych, myślników, podkreśleń lub kropek.` -git_ref_name_error=` misi być prawidłową nazwą git.` size_error=` musi być wielkości %s.` min_size_error=` musi zawierać co najwyżej %s znaków.` max_size_error=` musi zawierać co najwyżej %s znaków.` @@ -333,7 +329,6 @@ enable_custom_avatar=Włącz niestandardowe awatary choose_new_avatar=Wybierz nowy avatar update_avatar=Zaktualizuj ustawienia awatara delete_current_avatar=Usuń obecny Avatar -uploaded_avatar_not_a_image=Załadowany plik nie jest obrazem. update_avatar_success=Ustawienia Twojego awatara zostały zaktualizowane. change_password=Zmień hasło @@ -560,7 +555,6 @@ editor.fork_before_edit=Musisz sforkować to repozytorium przed edycją tego pli editor.delete_this_file=Usuń ten plik editor.must_have_write_access=Musisz mieć uprawnienia do zapisu, aby zgłosić lub zaproponować zmiany do tego pliku editor.file_delete_success=Plik '%s' został usunięty pomyślnie! -editor.name_your_file=Nazwij plik... editor.filename_help=Aby dodać katalog, wpisz nazwę i naciśnij przycisk /. Aby usunąć katalog, przejdź do początku pola i naciśnij klawisz backspace. editor.or=lub editor.cancel_lower=anuluj @@ -569,10 +563,8 @@ editor.add_tmpl=Dodaj '%s/' editor.add=Dodaj '%s' editor.update=Zaktualizuj '%s' editor.delete=Usuń '%s' -editor.commit_message_desc=Dodaj dodatkowy rozszerzony opis... editor.commit_directly_to_this_branch=Zmieniaj bezpośrednio gałąź %s. editor.create_new_branch=Stwórz nową gałąź dla tego commita i rozpocznij pull request. -editor.new_branch_name_desc=Nazwa nowej gałęzi... editor.cancel=Anuluj editor.filename_cannot_be_empty=Nazwa pliku nie może być pusta. editor.branch_already_exists=Gałąź '%s' już istnieje w tym repozytorium. @@ -584,7 +576,6 @@ editor.file_changed_while_editing=Zawartość pliku została w międzyczasie zmi editor.file_already_exists=Nazwa pliku '%s' już istnieje w tym repozytorium. editor.no_changes_to_show=Brak zmian do pokazania. editor.fail_to_update_file=Tworzenie/aktualizacja pliku '%s' nie powiodła się z błędem: %v -editor.add_subdir=Dodaj podkatalog... editor.unable_to_upload_files=Wysyłanie plików do '%s' nie powiodło się z błędem: %v editor.upload_files_to_dir=Prześlij pliki do '%s' editor.cannot_commit_to_protected_branch=Nie można commitować do chronionej gałęzi '%s'. @@ -621,7 +612,6 @@ issues.new.no_assignee=Brak przypisania issues.no_ref=Nie określono gałęzi/etykiety issues.create=Utwórz problem issues.new_label=Nowa etykieta -issues.new_label_placeholder=Etykieta... issues.create_label=Utwórz etykietę issues.label_templates.title=Załaduj wstępnie przygotowany zestaw etykiet issues.label_templates.info=Nie ma jeszcze żadnych etykiet. Kliknij na przycisk „Nowa etykieta” powyżej, aby utworzyć lub użyć poniższego zestawu wstępnie zdefiniowanego. @@ -882,7 +872,6 @@ settings.tracker_url_format=Format dla adresu URL zewnętrznego systemu settings.tracker_issue_style=Styl nazw zewnętrznego systemu zgłaszania problemów: settings.tracker_issue_style.numeric=Numeryczny settings.tracker_issue_style.alphanumeric=Alfanumeryczne -settings.tracker_url_format_desc=Symbole zastępcze {user} {repo} {index} mogą być użyte dla nazwy użytkownika, nazwy repozytorium i numeru problemu. settings.enable_timetracker=Włącz śledzenie czasu settings.allow_only_contributors_to_track_time=Pozwól jedynie współpracownikom na śledzenie czasu settings.pulls_desc=Włącz obsługę pull request, aby akceptować publiczny wkład @@ -896,7 +885,6 @@ settings.convert_confirm=Potwierdź konwersję settings.convert_succeed=Typ repozytorium został zamieniony na regularne. settings.transfer=Przeniesienie własności settings.transfer_desc=Przenieś to repozytorium do innego użytkownika lub organizacji gdzie masz uprawnienia administratora. -settings.transfer_notices_1=- Stracisz dostęp jeśli nowy właściciel jest indywidualnym użytkownikiem. settings.transfer_notices_2=- Zachowasz dostęp jeśli nowym właścicielem jest organizacja, której jesteś współwłaścicielem. settings.transfer_form_title=Wpisz następujące dane, w celu potwierdzenia operacji: settings.wiki_delete=Kasowanie danych Wiki @@ -920,7 +908,6 @@ settings.delete_collaborator=Usuń settings.collaborator_deletion=Usunięcie współpracownika settings.collaborator_deletion_desc=Ten użytkownik nie będzie miał dostępu współpracownika do repozytorium. Czy chcesz kontynuować? settings.remove_collaborator_success=Współpracownik został usunięty. -settings.search_user_placeholder=Szukaj użytkownika... settings.org_not_allowed_to_be_collaborator=Organizacji nie można dodać jako współpracownika. settings.user_is_org_member=Użytkownik jest członkiem organizacji, który nie może być dodany jako współpracownik. settings.add_webhook=Dodaj webhooka @@ -1010,7 +997,6 @@ settings.remove_protected_branch_success=Pomyślnie usunięto ustawienia ochrony settings.protected_branch_deletion=W celu usunięcia chronionej gałęzi settings.protected_branch_deletion_desc=Każdy z prawami zapisu będzie w stanie wypychać zmiany bezpośrednio do tej gałęzi. Jesteś pewien/pewna? settings.default_branch_desc=Domyślna gałąź jest uznawana za "bazową". Dopóki nie ustawisz innej gałęzi, wszystkie pull requesty i commity będą automatycznie kierowane do bazowej. -settings.choose_branch=Wybierz gałąź... settings.no_protected_branch=Nie ma chronionych gałęzi diff.browse_source=Przeglądaj źródła @@ -1044,7 +1030,6 @@ release.title=Tytuł release.content=Treść release.write=Napisz release.preview=Podgląd -release.loading=Ładowanie... release.prerelease_desc=To jest wersja wstępna release.prerelease_helper=Oznacz to wydanie jako wersję wstępną. release.cancel=Anuluj @@ -1158,7 +1143,6 @@ teams.read_permission_desc=Ten zespół daje dostęp do odczytu teams.write_permission_desc=Ten zespół daje dostęp do zapisu: członkowie mogą wyświetlać i wysyłać do repozytoriów zespołu. teams.admin_permission_desc=Ten zespół daje dostęp pełny: członkowie mogą wyświetlać, wysyłać i dodawać współpracowników do repozytoriów zespołu. teams.repositories=Repozytoria zespołu -teams.search_repo_placeholder=Przeszukaj repozytorium... teams.add_team_repository=Dodaj repozytorium zespołu teams.remove_repo=Usuń teams.add_nonexistent_repo=Repozytorium, które próbujesz dodać, nie istnieje. Proszę je najpierw utworzyć. @@ -1297,7 +1281,6 @@ auths.bind_password_helper=Uwaga: To hasło jest przechowywane bez szyfrowania. auths.user_base=Baza wyszukiwania auths.user_dn=DN użytkownika auths.attribute_username=Atrybut nazwy użytkownika -auths.attribute_username_placeholder=Zostaw puste, aby użyć wartości podanej podczas logowania. auths.attribute_name=Atrybut imienia auths.attribute_surname=Atrybut nazwiska auths.attribute_mail=Atrybut e-mail diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index d8481f3ce..6610b1cfe 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -17,7 +17,6 @@ page=Página template=Template language=Idioma notifications=Notificações -create_new=Criar... user_profile_and_more=Perfil do usuário e configurações signed_in_as=Logado como enable_javascript=Este site funciona melhor com JavaScript @@ -155,12 +154,10 @@ uname_holder=Nome de usuário ou e-mail password_holder=Senha switch_dashboard_context=Trocar contexto do painel de controle my_repos=Meus repositórios -show_more_repos=Mostrar mais repositórios... collaborative_repos=Repositórios colaborativos my_orgs=Minhas organizações my_mirrors=Meus mirrors view_home=Ver %s -search_repos=Encontre um repositório... issues.in_your_repos=Em seus repositórios @@ -249,7 +246,6 @@ Content=Conteúdo require_error=` não pode estar vazio.` alpha_dash_error=` devem ser caracteres alfanuméricos, hífen (-) ou sublinhado (_).` alpha_dash_dot_error=` devem ser caracteres alfanuméricos, hífen (-) sublinhado (_) or ponto (.).` -git_ref_name_error=` deve ser um nome de referência Git válido.` size_error=`deve ser do tamanho %s.` min_size_error=` deve conter pelo menos %s caracteres.` max_size_error=` deve conter no máximo %s caracteres.` @@ -335,7 +331,6 @@ enable_custom_avatar=Habilitar avatar customizado choose_new_avatar=Escolha um novo avatar update_avatar=Atualizar configuração de avatar delete_current_avatar=Excluir o avatar atual -uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem. update_avatar_success=Suas configurações de Avatar foram atualizadas. change_password=Mudança de senha @@ -565,7 +560,6 @@ editor.fork_before_edit=Você deve fazer fork deste repositório antes de editar editor.delete_this_file=Excluir este arquivo editor.must_have_write_access=Você deve ter permissão de escrita para fazer ou propor mudanças neste arquivo editor.file_delete_success=Arquivo '%s' excluído com sucesso! -editor.name_your_file=Nomeie seu arquivo... editor.filename_help=Para adicionar uma pasta, apenas digite o nome e pressione /. Para remover uma pasta, vá para o começo do campo e pressione backspace. editor.or=ou editor.cancel_lower=cancelar @@ -574,10 +568,8 @@ editor.add_tmpl=Adicionar '%s/' editor.add=Adicionar '%s' editor.update=Atualizar '%s' editor.delete=Excluir '%s' -editor.commit_message_desc=Adicione uma descrição detalhada opcional... editor.commit_directly_to_this_branch=Confirme diretamente no branch %s. editor.create_new_branch=Crie um novo branch para este commit e crie um pull request. -editor.new_branch_name_desc=Novo nome do ramo... editor.cancel=Cancelar editor.filename_cannot_be_empty=Nome do arquivo não pode ser vazio. editor.branch_already_exists=Branch '%s' já existe neste repositório. @@ -589,7 +581,6 @@ editor.file_changed_while_editing=O conteúdo do arquivo mudou desde que você c editor.file_already_exists=Um arquivo com nome '%s' já existe neste repositório. editor.no_changes_to_show=Nenhuma alteração a mostrar. editor.fail_to_update_file=Houve erro ao criar ou atualizar arquivo '%s': %v -editor.add_subdir=Adicionar o subdiretório... editor.unable_to_upload_files=Houve erro ao fazer upload de arquivos para '%s': %v editor.upload_files_to_dir=Enviar arquivos para '%s' editor.cannot_commit_to_protected_branch=Branch '%s' está protegida para commits. @@ -626,7 +617,6 @@ issues.new.no_assignee=Não atribuída issues.no_ref=Nenhuma Branch/Tag especificado issues.create=Criar issue issues.new_label=Nova etiqueta -issues.new_label_placeholder=Nome da etiqueta... issues.create_label=Criar etiqueta issues.label_templates.title=Carregue um conjunto de etiquetas pré-definidas issues.label_templates.info=Não há nenhuma etiqueta ainda. Você pode clicar no botão "Nova etiqueta" acima para criar uma ou usar um conjunto pré-definido acima. @@ -897,7 +887,6 @@ settings.tracker_url_format=Formato de URL do issue tracker externo settings.tracker_issue_style=Estilo de nome de issue tracker externo: settings.tracker_issue_style.numeric=Numérico settings.tracker_issue_style.alphanumeric=Alfanumérico -settings.tracker_url_format_desc=Você pode usar o espaço reservado {user} {repo} {index} para o nome do usuário, índice de nome e a issue do repositório. settings.enable_timetracker=Habilitar contador de tempo settings.allow_only_contributors_to_track_time=Permitir apenas colaboradores controlar o contador de tempo settings.pulls_desc=Habilitar pull requests para aceitar contribuições públicas @@ -914,7 +903,6 @@ settings.convert_confirm=Confirmar conversão settings.convert_succeed=Repositório foi convertido em um repositório comum. settings.transfer=Transferir propriedade settings.transfer_desc=Transferir este repositório para outro usuário ou para uma organização onde você tem direitos de administrador. -settings.transfer_notices_1=- Você perderá acesso se o novo owner é um usuário individual. settings.transfer_notices_2=- Você continuará a ter acesso se o novo owner for uma organização e você é um dos owners. settings.transfer_form_title=Por favor entre a seguinte informação para confirmar a operação: settings.wiki_delete=Excluir dados da wiki @@ -938,7 +926,6 @@ settings.delete_collaborator=Excluir settings.collaborator_deletion=Exclusão de colaborador settings.collaborator_deletion_desc=Este usuário não terá mais acesso de colaboração neste repositório após a exclusão. Você quer continuar? settings.remove_collaborator_success=O colaborador foi removido. -settings.search_user_placeholder=Pesquisar usuário... settings.org_not_allowed_to_be_collaborator=Organização não tem permissão para ser adicionada como um colaborador. settings.user_is_org_member=O usuário é um membro da organização que não pode ser adicionado como um colaborador. settings.add_webhook=Adicionar webhook @@ -1029,7 +1016,6 @@ settings.remove_protected_branch_success=Opções de proteção da branch %s alt settings.protected_branch_deletion=Para deletar a proteção de branch settings.protected_branch_deletion_desc=Qualquer um com permissões de escrita poderá fazer push diretamente para este branch. Tem certeza? settings.default_branch_desc=O branch default é considerado o "base branch" no seu repositório para todos os pull requests abertos e commit feitos automaticamente, a menos que você especifique outro branch. -settings.choose_branch=Escolha um branch... settings.no_protected_branch=No há branches protegidos diff.browse_source=Ver código fonte @@ -1063,7 +1049,6 @@ release.title=Título release.content=Conteúdo release.write=Escrever release.preview=Visualizar -release.loading=Carregando... release.prerelease_desc=Esta é uma versão prévia release.prerelease_helper=Vou salientar que esta versão é identificada como não pronta para produção. release.cancel=Cancelar @@ -1177,7 +1162,6 @@ teams.read_permission_desc=Essa equipe concede acesso para Leituraescrita: Membros podem ler e fazer push para os repositórios da equipe. teams.admin_permission_desc=Esta equipe concede acesso de Administrador: Membros podem ler, fazer push e adicionar outros colaboradores para os repositórios da equipe. teams.repositories=Repositórios da equipe -teams.search_repo_placeholder=Pesquisar repositório... teams.add_team_repository=Adicionar repositório da equipe teams.remove_repo=Remover teams.add_nonexistent_repo=O repositório que você está tentando adicionar não existe, por favor, crie-o primeiro. @@ -1316,7 +1300,6 @@ auths.bind_password_helper=Atenção: Esta senha é armazenada em texto sem form auths.user_base=Base de pesquisa do usuário auths.user_dn=Usuário do DN auths.attribute_username=Atributo nome de usuário -auths.attribute_username_placeholder=Deixe em branco para usar o valor do campo do formulário de login para o nome do usuário. auths.attribute_name=Atributo primeiro nome auths.attribute_surname=Atributo sobrenome auths.attribute_mail=Atributo e-mail diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index de8e20abf..325ec6e84 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -17,7 +17,6 @@ page=Страница template=Шаблон language=Язык notifications=Уведомления -create_new=Создать... user_profile_and_more=Профиль пользователя и прочее signed_in_as=Вы вошли как enable_javascript=Пожалуйста, включите JavaScript @@ -155,12 +154,10 @@ uname_holder=Имя пользователя или E-mail password_holder=Пароль switch_dashboard_context=Переключить контекст панели управления my_repos=Мои репозитории -show_more_repos=Показать больше репозиториев... collaborative_repos=Совместные репозитории my_orgs=Мои организации my_mirrors=Мои зеркала view_home=Показать %s -search_repos=Поиск репозитория... issues.in_your_repos=В ваших репозиториях @@ -249,7 +246,6 @@ Content=Содержимое require_error=` не может быть пустым.` alpha_dash_error=` должен быть допустимым символьным, числовым значением, или символами _ и -.` alpha_dash_dot_error=` должен содержать только буквы, цифры, или символы ._-` -git_ref_name_error=` должно быть правильным ссылочным именем git.` size_error=` должен быть размер %s.` min_size_error=«должен содержать по крайней мере %s символов.» max_size_error=` должен содержать максимум %s символов.` @@ -335,7 +331,6 @@ enable_custom_avatar=Включить собственный аватар choose_new_avatar=Выбрать новый аватар update_avatar=Обновить настройку аватара delete_current_avatar=Удалить текущий аватар -uploaded_avatar_not_a_image=Загружаемый файл не является изображением. update_avatar_success=Настройка вашего аватара обновлена. change_password=Сменить пароль @@ -565,7 +560,6 @@ editor.fork_before_edit=Создайте ветку репозитория пе editor.delete_this_file=Удалить файл editor.must_have_write_access=Вам необходимо иметь доступ на запись, чтобы вносить или предлагать правки этого файла editor.file_delete_success=Файл «%s» был успешно удален! -editor.name_your_file=Назовите свой файл... editor.filename_help=Чтобы добавить каталог, просто наберите название и нажмите /. Чтобы удалить каталог, перейдите к началу поля и нажмите клавишу backspace. editor.or=или editor.cancel_lower=отмена @@ -574,10 +568,8 @@ editor.add_tmpl=Добавить '%s/' editor.add=Добавить '%s' editor.update=Изменить '%s' editor.delete=Удалить '%s' -editor.commit_message_desc=Добавьте необязательное расширенное описание... editor.commit_directly_to_this_branch=Сделайте коммит прямо в ветку %s. editor.create_new_branch=Создайте новую ветку для этого коммита, и сделайте Pull Request. -editor.new_branch_name_desc=Новое название ветки... editor.cancel=Отмена editor.filename_cannot_be_empty=Имя файла не может быть пустым. editor.branch_already_exists=Ветка «%s» уже существует в этом репозитории. @@ -589,7 +581,6 @@ editor.file_changed_while_editing=Содержимое файла изменил editor.file_already_exists=Файл с именем «%s» уже существует в этом репозитории. editor.no_changes_to_show=Нет изменений. editor.fail_to_update_file=Не удалось обновить/создать файл «%s» из-за ошибки: %v -editor.add_subdir=Добавьте подкаталог... editor.unable_to_upload_files=Не удалось загрузить файлы в «%s» из-за ошибки: %v editor.upload_files_to_dir=Загрузить файлы '%s' editor.cannot_commit_to_protected_branch=Не можете коммитить в защищенную ветку '%s'. @@ -626,7 +617,6 @@ issues.new.no_assignee=Нет ответственного issues.no_ref=Не указана ветка или тэг issues.create=Добавить задачу issues.new_label=Новая метка -issues.new_label_placeholder=Имя метки... issues.create_label=Добавить метку issues.label_templates.title=Загрузить набор предопределённых меток issues.label_templates.info=Меток пока нет. Вы можете нажать на кнопку «Создать метку», чтобы создать новую или использовать одну из готового набора ниже. @@ -897,7 +887,6 @@ settings.tracker_url_format=Внешний формат ссылки систе settings.tracker_issue_style=Стиль Именования Внешней Системы Учета Задач: settings.tracker_issue_style.numeric=Цифровой settings.tracker_issue_style.alphanumeric=Буквенноцифровой -settings.tracker_url_format_desc=Вы можете использовать шаблон {user} {repo} {index} для имени пользователя, репозитория и номера задачи. settings.enable_timetracker=Включить отслеживание времени settings.allow_only_contributors_to_track_time=Учитывать только участников разработки в подсчёте времени settings.pulls_desc=Система Pull Request'ов создана для упрощения совместной работы над репозиторием @@ -914,7 +903,6 @@ settings.convert_confirm=Подтвердите преобразование settings.convert_succeed=Репозиторий успешно преобразован в обычный. settings.transfer=Передать права собственности settings.transfer_desc=Передать репозиторий другому пользователю или организации где у вас есть права администратора. -settings.transfer_notices_1=- Вы можете потерять доступ, если новый владелец является отдельным пользователем. settings.transfer_notices_2=- Вы сохраните доступ, если новым владельцем станет организация, владельцем которой вы являетесь. settings.transfer_form_title=Введите сопутствующую информацию для подтверждения операции: settings.wiki_delete=Стереть данные Вики @@ -938,7 +926,6 @@ settings.delete_collaborator=Удалить settings.collaborator_deletion=Удаление соавтора settings.collaborator_deletion_desc=Этот пользователь больше не будет иметь доступа для совместной работы в этом репозитории после удаления. Вы хотите продолжить? settings.remove_collaborator_success=Соавтор был удален. -settings.search_user_placeholder=Поиск пользователя... settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы. settings.user_is_org_member=Пользователь является членом организации, члены которой не могут быть добавлены в качестве соавтора. settings.add_webhook=Добавить Webhook @@ -1029,7 +1016,6 @@ settings.remove_protected_branch_success=Защита ветки %s была у settings.protected_branch_deletion=Для удаления защищённой ветки settings.protected_branch_deletion_desc=Любой пользователь с разрешениями на запись сможет выполнять push в эту ветку. Вы уверены? settings.default_branch_desc=Главная ветка является "базовой" для вашего репозитория, на которую по умолчанию направлены все Pull Request'ы и которая является лицом вашего репозитория. Первое, что увидит посетитель — это содержимое главной ветки. -settings.choose_branch=Выберите ветку... settings.no_protected_branch=Нет защищённых веток diff.browse_source=Просмотр исходного кода @@ -1063,7 +1049,6 @@ release.title=Заголовок release.content=Содержимое release.write=Редактирование release.preview=Предварительный просмотр -release.loading=Загрузка... release.prerelease_desc=Это предварительный релиз release.prerelease_helper=Отдельно отметим, что этот релиз не готов к использованию в продакшене. release.cancel=Отменить @@ -1177,7 +1162,6 @@ teams.read_permission_desc=Эта команда предоставляет до teams.write_permission_desc=Эта команда предоставляет доступ на Запись: члены могут получать и выполнять push команды в репозитории. teams.admin_permission_desc=Эта команда имеет административный доступ: участники могут читать, редактировать содержимое и выполнять административные функции (например, добавлять соавторов к её репозиториям). teams.repositories=Репозитории группы разработки -teams.search_repo_placeholder=Поиск репозитория... teams.add_team_repository=Добавить репозиторий группы разработки teams.remove_repo=Удалить teams.add_nonexistent_repo=Вы добавляете в отсутствующий репозиторий, пожалуйста сначала его создайте. @@ -1316,7 +1300,6 @@ auths.bind_password_helper=Предупреждение: Этот пароль auths.user_base=База для поиска пользователя auths.user_dn=DN пользователя auths.attribute_username=Имя пользователя -auths.attribute_username_placeholder=Оставьте пустым, чтобы использовать имя пользователя для регистрации. auths.attribute_name=Имя auths.attribute_surname=Фамилия auths.attribute_mail=Email diff --git a/options/locale/locale_sr-SP.ini b/options/locale/locale_sr-SP.ini index aeb522e37..e5e366ddc 100644 --- a/options/locale/locale_sr-SP.ini +++ b/options/locale/locale_sr-SP.ini @@ -13,7 +13,6 @@ version=Верзија page=Страница template=Шаблон language=Језик -create_new=Креирај... user_profile_and_more=Профил корисника и остало signed_in_as=Пријављени сте као @@ -212,7 +211,6 @@ enable_custom_avatar=Укључи ваш аватар choose_new_avatar=Изаберите нови аватар update_avatar=Ажурирајте поставке аватара delete_current_avatar=Обришите тренутни аватар -uploaded_avatar_not_a_image=Учитана датотека није слика. change_password=Промените лозинку old_password=Тренутна лозинка @@ -340,7 +338,6 @@ editor.fork_before_edit=Морате креирати огранак да би editor.delete_this_file=Уклони ову датотеку editor.must_have_write_access=Морате имати права на писање да предложите промене овој датотеци editor.file_delete_success=Датотека '%s' је успешно избрисана! -editor.name_your_file=Именуј датотеку... editor.filename_help=Да би додали директориум, искуцаије име и кликните /. Да уклоните директоријум, усмерите маркер на почетак поља и притисните тастер backspace. editor.or=или editor.cancel_lower=откажи @@ -349,10 +346,8 @@ editor.add_tmpl=Додај '%s/' editor.add=Додај '%s' editor.update=Ажурирај '%s' editor.delete=Уклони '%s' -editor.commit_message_desc=Додајте додатни детаљан опис... editor.commit_directly_to_this_branch=Изврши комит директно на %s грану. editor.create_new_branch=Креирај нову грану за овај комит и поднеси захтев за спајање. -editor.new_branch_name_desc=Име нове гране... editor.cancel=Откажи editor.filename_cannot_be_empty=Име датотеке неможе бити празно. editor.branch_already_exists=Грана '%s' већ постоји за ово спремиште. @@ -362,7 +357,6 @@ editor.file_editing_no_longer_exists=Датотека '%s' више не пос editor.file_already_exists=Датотека са именом '%s' већ постоји у овом спремишту. editor.no_changes_to_show=Нема никаквих промена. editor.fail_to_update_file=Промена над '%s' није успело са грешком: %v -editor.add_subdir=Додај поддиректоријуми... editor.unable_to_upload_files=Учитање датотеке '%s' није успело са грешкном: %v editor.upload_files_to_dir=Пошаљи датотеке на '%s' @@ -389,7 +383,6 @@ issues.new.clear_assignee=Уклони одговорног issues.new.no_assignee=Нема одговорних issues.create=Додај задатак issues.new_label=Нова лабела -issues.new_label_placeholder=Име лабеле... issues.create_label=Креирај лабелу issues.label_templates.title=Преузмите унапред дефинисани скуп лабела issues.label_templates.helper=Изаберите скуп лабела @@ -539,7 +532,6 @@ settings.tracker_url_format=Спољни формат везе система з settings.tracker_issue_style=Стил именовања на спољном систему: settings.tracker_issue_style.numeric=Нумерично settings.tracker_issue_style.alphanumeric=Алфанумерично -settings.tracker_url_format_desc=Можете да користите шаблон {user} {repo} {index} за корисничко име, спремишта и задатака. settings.pulls_desc=Омогући систем захтева за спајање да би сте преузели јавних доприноса settings.danger_zone=Опасна зона settings.new_owner_has_same_repo=Нови власник већ има спремиште по истим називом. Молимо вас изаберите друго име. @@ -563,7 +555,6 @@ settings.delete_collaborator=Уклони settings.collaborator_deletion=Брисање сарадника settings.collaborator_deletion_desc=Овај корисник неће имати приступ као сарадник овом спремишту након уклањања. Дали желите да наставите? settings.remove_collaborator_success=Сарадник је уклоњен. -settings.search_user_placeholder=Претрага корисника... settings.org_not_allowed_to_be_collaborator=Неможе се додати организација као сарадник. settings.user_is_org_member=Корисник је члан организације и потом неможе бити додат као сарадник. settings.add_webhook=Додај Webhook @@ -643,7 +634,6 @@ release.title=Наслов release.content=Садржај release.write=Напиши release.preview=Преглед -release.loading=Учитавање... release.prerelease_desc=Ово је пред-издање release.prerelease_helper=Посебно имајте на уму да ово издање није спремно за ширу употребу. release.cancel=Откажи @@ -718,7 +708,6 @@ teams.read_permission_desc=Овај тим даје приступ на teams.write_permission_desc=Овај тим даје приступ на Писање: чланови могу да виде и врше push операције на спремишта. teams.admin_permission_desc=Овај тим даје администраторки приступ: чланови могу да виде, врше push операције, и додавају сараднике. teams.repositories=Тимска спремишта -teams.search_repo_placeholder=Претражи спремиште... teams.add_team_repository=Додај тимско спремиште teams.remove_repo=Уклони teams.add_nonexistent_repo=Овакво спремиште не постоји, молим вас прво да га направите. @@ -820,7 +809,6 @@ auths.bind_password=Bind лозинкa auths.user_base=База претраживање корисника auths.user_dn=DN корисника auths.attribute_username=Атрибут username -auths.attribute_username_placeholder=Оставите празно да бисте користили корисничко име за регистрацију. auths.attribute_name=Име атрибута auths.attribute_surname=Презиме атрибута auths.attribute_mail=Е-маил адреса diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 56e2c4184..9204bfd50 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -17,7 +17,6 @@ page=Sida template=Mall language=Språk notifications=Notiser -create_new=Skapa... user_profile_and_more=Användarprofil med mera signed_in_as=Inloggad som enable_javascript=Denna hemsida fungerar bättre med JavaScript @@ -153,12 +152,10 @@ uname_holder=Användarnamn eller e-post password_holder=Lösenord switch_dashboard_context=Växla Visad Instrumentpanel my_repos=Mina utvecklingskataloger -show_more_repos=Visa flera repos ... collaborative_repos=Kollaborativa Utvecklingskataloger my_orgs=Mina organisationer my_mirrors=Mina speglar view_home=Visa %s -search_repos=Leta efter utvecklingskatalog ... issues.in_your_repos=I dina utvecklingskataloger @@ -247,7 +244,6 @@ Content=Innehåll require_error=får inte vara tomt alpha_dash_error=` får bara innehålla bokstäver, nummer och bindestreck (-_).` alpha_dash_dot_error=` får bara innehålla bokstäver, nummer, bindestreck (-_) och punkt` -git_ref_name_error='måste vara ett för git välformaterat referensnamn.' size_error=` måste vara av storleken %s` min_size_error=` måste innehålla minst %s tecken.` max_size_error=` får inte innehålla mer än %s tecken.` @@ -333,7 +329,6 @@ enable_custom_avatar=Aktivera Egen Avatar choose_new_avatar=Välj ny avatar update_avatar=Uppdatera Avatarinställningar delete_current_avatar=Tag bort aktuell avatar -uploaded_avatar_not_a_image=Den uppladdade filen är inte en bild. update_avatar_success=Dina avatarinställningar har uppdaterats. change_password=Ändra lösenord @@ -562,7 +557,6 @@ editor.fork_before_edit=Du måste förgrena detta förråd innan du kan redigera editor.delete_this_file=Tag bort denna fil editor.must_have_write_access=Du måste ha skrivrättigheter för att genomföra eller föreslå ändringar i denna fil editor.file_delete_success=Filen '%s' har tagits bort! -editor.name_your_file=Namnge din fil... editor.filename_help=För att lägga till en katalog, skriv dess namn och tryck /. För att ta bort en katalog, gå till början av fältet och tryck på backsteg. editor.or=eller editor.cancel_lower=avbryt @@ -571,10 +565,8 @@ editor.add_tmpl=Lägg till '%s/' editor.add=Lägg till '%s' editor.update=Uppdatera '%s' editor.delete=Tag bort '%s' -editor.commit_message_desc=Lägg till en valfri utökad beskrivning... editor.commit_directly_to_this_branch=Checka in direkt till grenen %s. editor.create_new_branch=Skapa en ny gren för denna incheckning och påbörja en hämtningsbegäran. -editor.new_branch_name_desc=Nytt grennamn... editor.cancel=Avbryt editor.filename_cannot_be_empty=Filnamnet får inte vara tomt. editor.branch_already_exists=Grenen '%s' finns redan i förrådet. @@ -586,7 +578,6 @@ editor.file_changed_while_editing=Filinnhållet har ändrats sedan du började r editor.file_already_exists=En fil med namnet '%s' finns redan i förrådet. editor.no_changes_to_show=Det finns inga ändringar att visa. editor.fail_to_update_file=Uppdateringen/skapandet av filen '%s' misslyckades med felet: %v -editor.add_subdir=Lägg till underkatalog... editor.unable_to_upload_files=Uppladdning av filen '%s' misslyckades med felet: %v editor.upload_files_to_dir=Ladda upp filer till '%s' @@ -614,7 +605,6 @@ issues.new.clear_assignee=Rensa förvärvare issues.new.no_assignee=Ingen förvärvare issues.create=Skapa Ärende issues.new_label=Ny etikett -issues.new_label_placeholder=Etikettnamn... issues.create_label=Skapa Etikett issues.label_templates.title=Ladda en fördefinierad uppsättning etiketter issues.label_templates.info=Det finns inga etiketter än. Du kan klicka på knappen "Ny etikett" ovan för att skapa en, eller använda en fördefinierad uppsättning nedan. @@ -825,7 +815,6 @@ settings.tracker_url_format=URL-Format För Extern Ärendehanterare settings.tracker_issue_style=Namngivningsstil hos det externa ärendehanteringsystemet: settings.tracker_issue_style.numeric=Numerisk settings.tracker_issue_style.alphanumeric=Alfanumerisk -settings.tracker_url_format_desc=Du kan använda platshållaren {user} {repo} {index} för användarnamn, reponamn, och ärendenummer. settings.pulls_desc=Aktivera pullförfrågningar för att ta emot publika bidrag settings.danger_zone=Högrisksområde settings.new_owner_has_same_repo=Den nya ägaren har redan ett repo med det namnet. Vänligen välj ett annat namn. @@ -835,7 +824,6 @@ settings.convert_confirm=Bekräfta Konvertering settings.convert_succeed=Repot har konverterats till ett vanligt repo. settings.transfer=Överför Ägarskap settings.transfer_desc=Överför detta repo till en annan användare, eller till en organisation där du har administratörsrättigheter. -settings.transfer_notices_1=- Du kommer förlora åtkomst om den nya ägaren är en enskild användare. settings.transfer_notices_2=- Du kommer bevara tillgång om den nya ägaren är en organisation, och om du är en av ägarna. settings.transfer_form_title=Ange följande information för att bekräfta åtgärden: settings.wiki_delete=Tag bort wikidata @@ -858,7 +846,6 @@ settings.delete_collaborator=Tag bort settings.collaborator_deletion=Borttagning av deltagare settings.collaborator_deletion_desc=Denna användare kommer förlora sin åtkomst till förrådet. Vill du fortsätta? settings.remove_collaborator_success=Deltagare har tagits bort. -settings.search_user_placeholder=Sök användare... settings.org_not_allowed_to_be_collaborator=Organisationen kan inte läggas till som en deltagare. settings.user_is_org_member=Änvändaren är en organisationsmedlem som inte kan bli tillagd som deltagare. settings.add_webhook=Lägg Till Webbhook @@ -945,7 +932,6 @@ release.title=Titel release.content=Innehåll release.write=Skriv release.preview=Förhandsgranska -release.loading=Laddar... release.prerelease_desc=Detta är ett försläpp release.prerelease_helper=Vi kommer att påpeka att detta släpp inte är produktionsredo. release.cancel=Avbryt @@ -1030,7 +1016,6 @@ teams.read_permission_desc=Medlemskap i detta team ger läsrättigheter< teams.write_permission_desc=Medlemskap i detta team ger skrivrättigheter: medlemmar kan läsa från och ladda upp till teamets förråd. teams.admin_permission_desc=Medlemskap i detta team ger administratörsrättigheter: medlemmar kan läsa från, ladda upp till och lägga till deltagare till teamets förråd. teams.repositories=Teamförråd -teams.search_repo_placeholder=Sök förråd... teams.add_team_repository=Lägg till teamförråd teams.remove_repo=Ta bort teams.add_nonexistent_repo=Förrådet du försöka lägga till finns inte, vänligen skapa det först. @@ -1146,7 +1131,6 @@ auths.bind_password_helper=Varning: Detta lösenord lagras i klartext. Använd i auths.user_base=Användarsökbas auths.user_dn=Användarnas DN auths.attribute_username=Användarnamnsattribut -auths.attribute_username_placeholder=Lämna tom för att använda inloggningsformuläretets användarnamn. auths.attribute_name=Förnamnsattribut auths.attribute_surname=Efternamnsattribut auths.attribute_mail=E-postattribut diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index e489c44df..90294a69e 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -17,7 +17,6 @@ page=Sayfa template=Şablon language=Dil notifications=Bildirimler -create_new=Oluştur... user_profile_and_more=Kullanıcı profili ve daha fazlası signed_in_as=Giriş yapan: enable_javascript=Bu web sayfasi javascript ile daha iyi çalışır @@ -154,12 +153,10 @@ uname_holder=Kullanıcı Adı veya E-Posta password_holder=Parola switch_dashboard_context=Panoya Geçiş Yap my_repos=Depolarım -show_more_repos=Daha fazla depo göster ... collaborative_repos=Katkıya Açık Depolar my_orgs=Organizasyonlarım my_mirrors=Yansılarım view_home=%s Görüntüle -search_repos=Depo bul ... issues.in_your_repos=Depolarınızda @@ -249,7 +246,6 @@ require_error=` boş olamaz.` alpha_dash_error=` geçerli alfanümerik veya çizgi(-_) karakterleri olmalıdır.`   alpha_dash_dot_error=` geçerli alfanümerik, çizgi(-_) veya nokta karakterleri olmalıdır.` -git_ref_name_error=` git referans ismi iyi oluşturulmuş olmalıdır.` size_error=` uzunluk en fazla %s olmalıdır.` min_size_error=` en az %s karakter içermelidir.` max_size_error=` en fazla %s karakter içermelidir.` @@ -335,7 +331,6 @@ enable_custom_avatar=Özel Avatarı Etkinleştir choose_new_avatar=Yeni Avatar Seç update_avatar=Avatar Ayarlarını Güncelle delete_current_avatar=Güncel Avatarı Sil -uploaded_avatar_not_a_image=Yüklenen dosya bir resim dosyası değil. update_avatar_success=Avatar ayarınız güncelleştirildi. change_password=Parolayı Değiştir @@ -563,7 +558,6 @@ editor.fork_before_edit=Dosyayı düzenlemeden önce bu depoyu forklamalısını editor.delete_this_file=Bu dosyayı sil editor.must_have_write_access=Bu dosyaya değişiklikler yapmak veya önermek için yazma erişiminizin olması gerekir editor.file_delete_success='%s' dosyası başarıyla silindi! -editor.name_your_file=Dosyanızı isimlendirin... editor.filename_help=Dizine eklemek için, sadece yazın ve basın /. Bir dizini kaldırmak için, alanın başlangıcına gidin ve boşluk tuşuna basın. editor.or=veya editor.cancel_lower=iptal @@ -572,10 +566,8 @@ editor.add_tmpl=Ekle '%s/' editor.add='%s' ekle editor.update='%s' güncelle editor.delete='%s' sil -editor.commit_message_desc=İsteğe bağlı uzun bir açıklama ekleyin... editor.commit_directly_to_this_branch=Doğrudan %s bölümüne uygula. editor.create_new_branch=Bu işlem için bir yeni branş oluşturun ve bir çekme istediği başlatın. -editor.new_branch_name_desc=Yeni bölüm adı... editor.cancel=İptal editor.filename_cannot_be_empty=Dosya adı boş olamaz. editor.branch_already_exists='%s' bölümü bu depoda zaten mevcut. @@ -587,7 +579,6 @@ editor.file_changed_while_editing=Düzenlemeye başladığınızdan bu yana dosy editor.file_already_exists=Bu depoda '%s' isimli bir dosya zaten mevcut. editor.no_changes_to_show=Gösterilecek değişiklik yok. editor.fail_to_update_file=Şu hata ile '%s' dosyasını güncelleme/oluşturma başarısız oldu: %v -editor.add_subdir=Alt dizin ekle... editor.unable_to_upload_files=Şu hata ile dosyalar '%s' 'a yüklenemedi: %v editor.upload_files_to_dir=Dosyaları '%s' 'a yükle editor.cannot_commit_to_protected_branch=Korunan bölüm '%s' 'e uygulanamıyor. @@ -624,7 +615,6 @@ issues.new.no_assignee=Atanan Kişi Yok issues.no_ref=Bölüm/Etiket Belirtilmedi issues.create=Sorun Oluştur issues.new_label=Yeni Etiket -issues.new_label_placeholder=Etiket adı... issues.create_label=Etiket Oluştur issues.label_templates.title=Önceden tanımlanmış bir etiket seti yükle issues.label_templates.info=Henüz hiç etiket yok. Bir tane oluşturmak için yukarıdaki "Yeni Etiket" düğmesine tıklayabilir veya aşağıdan önceden tanımlanmış bir set kullanabilirsiniz. @@ -890,7 +880,6 @@ settings.tracker_url_format=Harici Sorun Takipçisi Bağlantı Formatı settings.tracker_issue_style=Harici Hata İzleyicisi Adlandırma Stili: settings.tracker_issue_style.numeric=Sayısal settings.tracker_issue_style.alphanumeric=Alfanumerik -settings.tracker_url_format_desc=Kullanıcı adı, depo ismi ve hata indeksi için {kullanıcı} {depo} {indeks} tutucusunu kullanabilirsiniz. settings.enable_timetracker=Zaman izleyiciyi etkinleştir settings.allow_only_contributors_to_track_time=Zamanı izlemek için sadece katkıda bulunanlara izin ver settings.pulls_desc=Herkese açık katkıları kabul etmek için değişiklik isteklerini etkinleştirin @@ -904,7 +893,6 @@ settings.convert_confirm=Sohbeti Onayla settings.convert_succeed=Depo düzenli bir depoya dönüştürüldü. settings.transfer=Sahipliği Aktar settings.transfer_desc=Bu depoyu başka bir kullanıcıya veya yönetici yetkilerine sahip olduğunuz başka bir organizasyona aktarın. -settings.transfer_notices_1=- Yeni sahip bireysel bir kullanıcıysa erişiminizi kaybedeceksiniz. settings.transfer_notices_2=- Yeni sahip bir organizasyonsa ve siz sahiplerden biriyseniz erişimi koruyacaksınız. settings.transfer_form_title=İşleminizi onaylamak için lütfen aşağıdaki bilgileri girin: settings.wiki_delete=Wiki Verisini Sil @@ -928,7 +916,6 @@ settings.delete_collaborator=Sil settings.collaborator_deletion=Katkıcı Silme settings.collaborator_deletion_desc=Kullanıcı, silme işleminden sonra bu depoya olan erişim iznini kaybedecektir. Devam etmek istiyor musunuz? settings.remove_collaborator_success=Katkıcı silindi. -settings.search_user_placeholder=Kullanıcı ara... settings.org_not_allowed_to_be_collaborator=Organizasyon, bir katkıcı olarak eklenemez. settings.user_is_org_member=Kullanıcı organizasyon üyesi olduğu için katkıcı olarak eklenemez. settings.add_webhook=Web İsteği Ekle @@ -1017,7 +1004,6 @@ settings.remove_protected_branch_success=Branş %s koruma ayarları başarıyla settings.protected_branch_deletion=Korunan bir branşı silmek için settings.protected_branch_deletion_desc=Yazma izinleri olan herhangi biri bu branşa doğrudan itebilecek. Emin misiniz? settings.default_branch_desc=Varsayılan branş, farklı bir branş belirtmediğiniz sürece tüm çekme isteklerinin ve kod işlemelerinin otomatik olarak yapılması karşısında deponuzdaki "taban" şube olarak düşünülür. -settings.choose_branch=Bir branş seç... settings.no_protected_branch=Korunan bölüm yok diff.browse_source=Kaynağa Gözat @@ -1050,7 +1036,6 @@ release.title=Başlık release.content=İçerik release.write=Yaz release.preview=Önizle -release.loading=Yükleniyor... release.prerelease_desc=Bu bir ön sürümdür release.prerelease_helper=Bu sürümün üretime hazır olmadığını işaret edeceğiz. release.cancel=İptal @@ -1163,7 +1148,6 @@ teams.read_permission_desc=Bu takımın yetkilerinden Okuma izn teams.write_permission_desc=Bu takımın yetkilerinden Yazma izni: üyeler okuyabilir ve takımın depolarına push yapabilir. teams.admin_permission_desc=Bu takımın yetkilerinden Yönetici izni: üyeler okuyabilir, push yapabilir ve takımın depolarına yeni katkıcılar ekleyebilir. teams.repositories=Ekip Depoları -teams.search_repo_placeholder=Depo ara... teams.add_team_repository=Ekip Deposu Ekle teams.remove_repo=Kaldır teams.add_nonexistent_repo=Eklemeye çalıştığınz depo mevcut değil. Lütfen önce oluşturun. @@ -1300,7 +1284,6 @@ auths.bind_password_helper=Uyarı: Bu şifre düz metin halinde saklanıyor. Sal auths.user_base=Kullanıcı Arama Tabanı auths.user_dn=Kullanıcı DN'i auths.attribute_username=Kullanıcı özelliği -auths.attribute_username_placeholder=Kullanıcı adı için giriş yapma form alanı kullanmak için boş bırakın. auths.attribute_name=Ad özelliği auths.attribute_surname=Soyad özelliği auths.attribute_mail=E-posta özelliği diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 2723d4634..af94e0a56 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -15,7 +15,6 @@ page=Сторінка template=Шаблон language=Мова notifications=Сповіщення -create_new=Створити... user_profile_and_more=Профіль користувача та інше signed_in_as=Увійшов як enable_javascript=Цей веб-сайт працює краще з JavaScript @@ -121,7 +120,6 @@ uname_holder=Ім'я користувача або електронна пошт password_holder=Пароль switch_dashboard_context=Змінити дошку my_repos=Мої репозиторії -show_more_repos=Показати більше репозиторіїв... collaborative_repos=Спільні репозиторії my_orgs=Мої організації my_mirrors=Мої дзеркала @@ -337,7 +335,6 @@ editor.edit_file=Редагування файла editor.preview_changes=Попередній перегляд змін editor.edit_this_file=Редагувати цей файл editor.delete_this_file=Видалити цей файл -editor.name_your_file=Дайте назву файлу... editor.or=або editor.cancel_lower=відміна editor.commit_changes=Зафіксувати зміни @@ -367,7 +364,6 @@ issues.new.assignee=Призначено issues.new.clear_assignee=Прибрати відповідального issues.new.no_assignee=Немає відповідального issues.new_label=Нова мітка -issues.new_label_placeholder=Назва мітки... issues.create_label=Створити мітку issues.label_templates.helper=Оберіть набір міток issues.label_templates.use=Використовуйте набір міток @@ -455,7 +451,6 @@ settings.confirm_delete=Підтвердження видалення settings.add_collaborator=Додати нового співавтора settings.delete_collaborator=Видалити settings.collaborator_deletion=Видалення співавтора -settings.search_user_placeholder=Пошук користувача... settings.org_not_allowed_to_be_collaborator=Організації не можуть бути додані як співавтори. settings.user_is_org_member=Користувач входить в організацію, член якої не може бути доданий як співавтор. settings.slack_color=Колір diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 3afb5f76d..0f5209ad1 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -17,7 +17,6 @@ page=页面 template=模板 language=语言选项 notifications=通知 -create_new=创建... user_profile_and_more=用户信息及更多 signed_in_as=已登录用户 enable_javascript=使用 JavaScript能使本网站更好的工作。 @@ -155,12 +154,10 @@ uname_holder=用户名或邮箱 password_holder=密码 switch_dashboard_context=切换控制面板用户 my_repos=我的仓库 -show_more_repos=显示更多仓库... collaborative_repos=参与协作的仓库 my_orgs=我的组织 my_mirrors=我的镜像 view_home=访问 %s -search_repos=查找仓库... issues.in_your_repos=属于该用户仓库的 @@ -249,7 +246,6 @@ Content=内容 require_error=不能为空。 alpha_dash_error=必须为英文字母、阿拉伯数字或横线(-_)。 alpha_dash_dot_error=必须为英文字母、阿拉伯数字、横线(-_)或点。 -git_ref_name_error=必须是格式良好的 git 引用名称。 size_error=长度必须为 %s。 min_size_error=长度最小为 %s 个字符。 max_size_error=长度最大为 %s 个字符。 @@ -335,7 +331,6 @@ enable_custom_avatar=启动自定义头像 choose_new_avatar=选择新的头像 update_avatar=更新头像设置 delete_current_avatar=删除当前头像 -uploaded_avatar_not_a_image=上传的文件不是一张图片! update_avatar_success=您的头像设置更新成功! change_password=修改密码 @@ -565,7 +560,6 @@ editor.fork_before_edit=您必须派生此仓库才能对此文件进行修改 editor.delete_this_file=删除此文件 editor.must_have_write_access=您必须具有可写权限才能对此文件进行修改操作 editor.file_delete_success=文件 '%s' 删除成功! -editor.name_your_file=命名文件... editor.filename_help=输入名称后按下 / 键即可添加目录,或将光标移至输入框最左侧按下退格键移除目录。 editor.or=或 editor.cancel_lower=取消 @@ -574,10 +568,8 @@ editor.add_tmpl=添加 '%s/<文件名>' editor.add=添加 '%s' editor.update=更新 '%s' editor.delete=删除 '%s' -editor.commit_message_desc=添加一个可选的扩展描述... editor.commit_directly_to_this_branch=直接提交至 %s 分支。 editor.create_new_branch=为此提交创建一个 新的分支 并发起合并请求。 -editor.new_branch_name_desc=新的分支名称... editor.cancel=取消 editor.filename_cannot_be_empty=文件名不能为空。 editor.branch_already_exists=此仓库已存在名为 '%s' 的分支。 @@ -589,7 +581,6 @@ editor.file_changed_while_editing=文件内容在您进行编辑时已经发生 editor.file_already_exists=此仓库已经存在名为 '%s' 的文件。 editor.no_changes_to_show=没有可以显示的变更。 editor.fail_to_update_file=更新/创建文件 '%s' 时发生错误:%v -editor.add_subdir=添加子目录... editor.unable_to_upload_files=上传文件至 '%s' 时发生错误:%v editor.upload_files_to_dir=上传文件至 '%s' editor.cannot_commit_to_protected_branch=不可以提交到受保护的分支 '%s'。 @@ -626,7 +617,6 @@ issues.new.no_assignee=未指派成员 issues.no_ref=分支/标记未指定 issues.create=创建工单 issues.new_label=创建标签 -issues.new_label_placeholder=标签名称... issues.create_label=创建标签 issues.label_templates.title=加载预定义的标签模板 issues.label_templates.info=此仓库还未创建任何标签,您可以通过上方的 "创建标签" 创建一个新的标签或加载一组预定义的标签。 @@ -897,7 +887,6 @@ settings.tracker_url_format=外部工单管理系统的 URL 格式 settings.tracker_issue_style=外部工单管理系统命名风格: settings.tracker_issue_style.numeric=纯数字形式 settings.tracker_issue_style.alphanumeric=英文字母数字组合形式 -settings.tracker_url_format_desc=您可以使用 {user} {repo} {index} 分别作为用户名、仓库名和工单索引的占位符。 settings.enable_timetracker=启用时间跟踪 settings.allow_only_contributors_to_track_time=只允许参与者跟踪时间 settings.pulls_desc=启用合并请求以接受社区贡献 @@ -914,7 +903,6 @@ settings.convert_confirm=确认转换 settings.convert_succeed=此仓库已经转换为普通仓库。 settings.transfer=转移仓库所有权 settings.transfer_desc=您可以将仓库转移至您拥有管理员权限的帐户或组织。 -settings.transfer_notices_1=- 如果新拥有者是个人,你将无法再访问。 settings.transfer_notices_2=- 如果新拥有者是组织,你将成为组织的拥有者之一 settings.transfer_form_title=请输入以下信息以确认您的操作: settings.wiki_delete=清除 Wiki 数据 @@ -938,7 +926,6 @@ settings.delete_collaborator=删除 settings.collaborator_deletion=删除协作者 settings.collaborator_deletion_desc=此用户被删除后将不再拥有相关的协作权限。是否继续? settings.remove_collaborator_success=被操作的协作者已经被收回权限! -settings.search_user_placeholder=搜索用户... settings.org_not_allowed_to_be_collaborator=组织不允许被添加为仓库协作者! settings.user_is_org_member=被操作的用户是组织成员,因此无法添加为协作者! settings.add_webhook=添加 Web 钩子 @@ -1029,7 +1016,6 @@ settings.remove_protected_branch_success=分支 %s 保护设定删除成功。 settings.protected_branch_deletion=若要删除一个受保护的分支 settings.protected_branch_deletion_desc=具有写权限的任何人都将能够直接推向这个分支。是否确定? settings.default_branch_desc=默认分支被认为是仓库中的"基础"分支,如果不特别指定所有的合并请求和代码提交默认提交到这个分支。 -settings.choose_branch=选择一个分支... settings.no_protected_branch=没有受保护的分支 diff.browse_source=浏览代码 @@ -1063,7 +1049,6 @@ release.title=标题 release.content=内容 release.write=内容编辑 release.preview=效果预览 -release.loading=正在加载... release.prerelease_desc=这是一个预发行版本 release.prerelease_helper=我们会告知用户不建议将本次发布投入生产环境使用。 release.cancel=取消 @@ -1177,7 +1162,6 @@ teams.read_permission_desc=该团队拥有对所属仓库的 读取读取写入 的权限。 teams.admin_permission_desc=该团队拥有一定的 管理 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。 teams.repositories=团队仓库 -teams.search_repo_placeholder=搜索仓库... teams.add_team_repository=添加团队仓库 teams.remove_repo=移除仓库 teams.add_nonexistent_repo=您尝试添加到团队的仓库不存在,请先创建仓库! @@ -1316,7 +1300,6 @@ auths.bind_password_helper=警告: 此密码以纯文本格式存储。强烈建 auths.user_base=用户搜索基准 auths.user_dn=用户 DN auths.attribute_username=用户名属性 -auths.attribute_username_placeholder=留空表示使用用户登录时所使用的用户名 auths.attribute_name=名字属性 auths.attribute_surname=姓氏属性 auths.attribute_mail=邮箱属性 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index 8f29eb9dd..9de661890 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -17,7 +17,6 @@ page=頁面 template=樣板 language=語言 notifications=訊息 -create_new=建立... enable_javascript=本網站在啟用 JavaScript 的情況下可以運作的更好。 email=電子郵件 @@ -145,12 +144,10 @@ uname_holder=使用者名稱或電郵地址 password_holder=密碼 switch_dashboard_context=切換控制面版用戶 my_repos=我的儲存庫 -show_more_repos=顯示更多儲存庫... collaborative_repos=參與協作的儲存庫 my_orgs=我的組織 my_mirrors=我的鏡像 view_home=訪問 %s -search_repos=搜尋儲存庫 ... issues.in_your_repos=屬於該用戶儲存庫的 @@ -238,7 +235,6 @@ Content=內容 require_error=不能為空。 alpha_dash_error=`必須為英文字母、阿拉伯數字或橫線(-_)。` alpha_dash_dot_error=`必須為英文字母、阿拉伯數字、橫線(-_)或點。` -git_ref_name_error=`必須是格式良好的 git 參考名稱。` size_error=長度必須為 %s。 min_size_error=長度最小為 %s 個字符。 max_size_error=長度最大為 %s 個字符。 @@ -321,7 +317,6 @@ enable_custom_avatar=啟動自定義頭像 choose_new_avatar=選擇新的頭像 update_avatar=更新頭像設定 delete_current_avatar=刪除當前頭像 -uploaded_avatar_not_a_image=上傳的文件不是一張圖片! update_avatar_success=成功更新您的頭像設定! change_password=修改密碼 @@ -544,7 +539,6 @@ editor.fork_before_edit=你必須在編輯檔案之前備份此檔案 editor.delete_this_file=刪除此文件 editor.must_have_write_access=您必須具有寫存取權限,或提出對此檔案的更改 editor.file_delete_success=已成功刪除 '%s' ! -editor.name_your_file=命名您的檔... editor.filename_help=輸入名稱後按下 / 鍵即可新增資料夾,或將滑鼠移至輸入格最左側按下Backspace移除資料夾。 editor.or=或 editor.cancel_lower=取消 @@ -553,10 +547,8 @@ editor.add_tmpl=新增 %s/' editor.add=新增 '%s' editor.update=更新 '%s' editor.delete=刪除 '%s' -editor.commit_message_desc=新增一個可選的擴充描述... editor.commit_directly_to_this_branch=直接提交到 %s 分支。 editor.create_new_branch=建立 新的分支 為此提交和開始合併請求。 -editor.new_branch_name_desc=新的分支名稱... editor.cancel=取消 editor.filename_cannot_be_empty=檔案名不能為空。 editor.branch_already_exists='%s' 已存在於此存儲庫。 @@ -568,7 +560,6 @@ editor.file_changed_while_editing=從您開始編輯後,檔案內容已被更 editor.file_already_exists=帶有名稱 '%s' 的檔已經存在在這個資料庫中。 editor.no_changes_to_show=沒有可以顯示的變更。 editor.fail_to_update_file=上傳/建立檔案 '%s' 失敗, 錯誤訊息: %v -editor.add_subdir=新增子目錄... editor.unable_to_upload_files=上傳檔案失敗到 '%s', 錯誤訊息: %v editor.upload_files_to_dir=上傳檔案到 '%s' editor.cannot_commit_to_protected_branch=無法提交到受保護的分支 '%s'。 @@ -604,7 +595,6 @@ issues.new.clear_assignee=取消指派成員 issues.new.no_assignee=未指派成員 issues.create=建立問題 issues.new_label=建立標籤 -issues.new_label_placeholder=標籤名稱... issues.create_label=建立標籤 issues.label_templates.title=載入一組預定義的標籤 issues.label_templates.info=沒有任何標籤。你可以點選上面建立一個或按下面"新建標籤"按鈕來使用一組預定義。 @@ -805,7 +795,6 @@ settings.tracker_url_format=外部問題管理系統的 URL 格式 settings.tracker_issue_style=外部公單管理系統命名風格: settings.tracker_issue_style.numeric=數字 settings.tracker_issue_style.alphanumeric=字母及數字 -settings.tracker_url_format_desc=您可以使用 {user} {repo} {index} 分別作為用戶名、儲存庫名和問題索引的占位符。 settings.pulls_desc=啟用合併請求以接受社區貢獻 settings.danger_zone=危險操作區 settings.new_owner_has_same_repo=新的儲存庫擁有者已經存在同名儲存庫! @@ -816,7 +805,6 @@ settings.convert_confirm=確認轉換 settings.convert_succeed=儲存庫已成功轉換為一般類型。 settings.transfer=轉移儲存庫所有權 settings.transfer_desc=您可以將儲存庫轉移至您擁有管理員權限的帳戶或組織。 -settings.transfer_notices_1=- 如果您將儲存庫轉移給個人用戶,您將會丟失操作權限。 settings.transfer_notices_2=- 如果新的所有者的是組織且你是此組織的所有者之一,您的操作權限將被保留。 settings.transfer_form_title=請輸入以下訊息以確認您的操作: settings.wiki_delete=刪除 Wiki 資料 @@ -839,7 +827,6 @@ settings.delete_collaborator=刪除 settings.collaborator_deletion=協同者刪除 settings.collaborator_deletion_desc=刪除後此使用者將不再有協同者權限存取此儲存庫。你想要繼續嗎? settings.remove_collaborator_success=被操作的協作者已經被收回權限! -settings.search_user_placeholder=搜尋用戶... settings.org_not_allowed_to_be_collaborator=組織不允許被加為協同者。 settings.user_is_org_member=被操作的用戶是組織成員,因此無法新增為協作者! settings.add_webhook=建立 Webhook @@ -913,7 +900,6 @@ settings.remove_protected_branch_success=%s 解鎖成功 settings.protected_branch_deletion=刪除一個受保護的分支 settings.protected_branch_deletion_desc=任何具有寫入權限的使用者都可以直接推進這個分支,您確定嗎? settings.default_branch_desc=預設分支被認為是"基準"分支,預期全部的合併請求以及程式碼提交將自動完成到此分支,除非您指定不同的分支。 -settings.choose_branch=選擇一個分支 settings.no_protected_branch=沒有受保護的分支 diff.browse_source=瀏覽代碼 @@ -947,7 +933,6 @@ release.title=標題 release.content=內容 release.write=內容編輯 release.preview=效果預覽 -release.loading=正在加載... release.prerelease_desc=這是一個預發佈版本 release.prerelease_helper=我們會告知用戶不建議將本發佈投入生產環境使用。 release.cancel=取消 @@ -1045,7 +1030,6 @@ teams.read_permission_desc=該團隊擁有對所屬儲存庫的 讀取讀取寫入 的權限。 teams.admin_permission_desc=該團隊擁有一定的 管理 權限,團隊成員可以讀取、複製、推送以及新增其它儲存庫協作者。 teams.repositories=團隊儲存庫 -teams.search_repo_placeholder=搜尋儲存庫... teams.add_team_repository=新增團隊儲存庫 teams.remove_repo=移除儲存庫 teams.add_nonexistent_repo=您嘗試新增到團隊的儲存庫不存在,請先建立儲存庫! @@ -1184,7 +1168,6 @@ auths.bind_password_helper=警告:此密碼將以明文形式儲存。請不 auths.user_base=用戶搜尋基準 auths.user_dn=用戶 DN auths.attribute_username=用戶名屬性 -auths.attribute_username_placeholder=留空表示使用用戶登錄時所使用的用戶名 auths.attribute_name=名子屬性 auths.attribute_surname=姓氏屬性 auths.attribute_mail=電子郵箱屬性 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 438b5e8c0..5b1d10a6d 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -17,7 +17,6 @@ page=頁面 template=樣板 language=語言 notifications=訊息 -create_new=建立... user_profile_and_more=用戶訊息及更多 signed_in_as=已登入用戶 enable_javascript=本網站在啟用 JavaScript 的情況下可以運作的更好。 @@ -155,12 +154,10 @@ uname_holder=用戶名或郵箱 password_holder=密碼 switch_dashboard_context=切換控制面版用戶 my_repos=我的儲存庫 -show_more_repos=顯示更多儲存庫... collaborative_repos=參與協作的儲存庫 my_orgs=我的組織 my_mirrors=我的鏡像 view_home=訪問 %s -search_repos=搜尋儲存庫 ... issues.in_your_repos=屬於該用戶儲存庫的 @@ -249,7 +246,6 @@ Content=內容 require_error=不能為空。 alpha_dash_error=`必須為英文字母、阿拉伯數字或橫線(-_)。` alpha_dash_dot_error=`必須為英文字母、阿拉伯數字、橫線(-_)或點。` -git_ref_name_error=`必須是格式良好的 git 參考名稱。` size_error=長度必須為 %s。 min_size_error=長度最小為 %s 個字符。 max_size_error=長度最大為 %s 個字符。 @@ -335,7 +331,6 @@ enable_custom_avatar=啟動自定義頭像 choose_new_avatar=選擇新的頭像 update_avatar=更新頭像設定 delete_current_avatar=刪除當前頭像 -uploaded_avatar_not_a_image=上傳的文件不是一張圖片! update_avatar_success=成功更新您的頭像設定! change_password=修改密碼 @@ -563,7 +558,6 @@ editor.fork_before_edit=在編輯此檔案前,你必須先 Fork 此儲存庫 editor.delete_this_file=刪除此檔案 editor.must_have_write_access=您必須具有寫存取權限,或提出對此檔案的更改 editor.file_delete_success=已成功刪除 '%s' ! -editor.name_your_file=命名您的檔案... editor.filename_help=輸入名稱後按下 / 鍵即可新增資料夾,或將滑鼠移至輸入格最左側按下Backspace移除資料夾。 editor.or=或 editor.cancel_lower=取消 @@ -572,10 +566,8 @@ editor.add_tmpl=新增 %s/' editor.add=新增 '%s' editor.update=更新 '%s' editor.delete=刪除 '%s' -editor.commit_message_desc=新增一個可選的擴充描述... editor.commit_directly_to_this_branch=直接提交到 %s 分支。 editor.create_new_branch=建立 新的分支 為此提交和開始合併請求。 -editor.new_branch_name_desc=新的分支名稱... editor.cancel=取消 editor.filename_cannot_be_empty=檔案名不能為空。 editor.branch_already_exists='%s' 已存在於此存儲庫。 @@ -587,7 +579,6 @@ editor.file_changed_while_editing=從您開始編輯後,檔案內容已被更 editor.file_already_exists=帶有名稱 '%s' 的檔已經存在在這個資料庫中。 editor.no_changes_to_show=沒有可以顯示的變更。 editor.fail_to_update_file=上傳/建立檔案 '%s' 失敗, 錯誤訊息: %v -editor.add_subdir=新增子目錄... editor.unable_to_upload_files=上傳檔案失敗到 '%s', 錯誤訊息: %v editor.upload_files_to_dir=上傳檔案到 '%s' editor.cannot_commit_to_protected_branch=無法提交到受保護的分支 '%s'。 @@ -624,7 +615,6 @@ issues.new.no_assignee=未指派成員 issues.no_ref=未指定分支或標籤 issues.create=建立問題 issues.new_label=建立標籤 -issues.new_label_placeholder=標籤名稱... issues.create_label=建立標籤 issues.label_templates.title=載入一組預定義的標籤 issues.label_templates.info=沒有任何標籤。你可以點選上面建立一個或按下面"新建標籤"按鈕來使用一組預定義。 @@ -880,7 +870,6 @@ settings.tracker_url_format=外部問題管理系統的 URL 格式 settings.tracker_issue_style=外部公單管理系統命名風格: settings.tracker_issue_style.numeric=數字 settings.tracker_issue_style.alphanumeric=字母及數字 -settings.tracker_url_format_desc=您可以使用 {user} {repo} {index} 分別作為用戶名、儲存庫名和問題索引的占位符。 settings.enable_timetracker=啟用時間追蹤 settings.allow_only_contributors_to_track_time=僅允許貢獻者追蹤時間 settings.pulls_desc=啟用合併請求以接受社區貢獻 @@ -894,7 +883,6 @@ settings.convert_confirm=確認轉換 settings.convert_succeed=儲存庫已成功轉換為一般類型。 settings.transfer=轉移儲存庫所有權 settings.transfer_desc=您可以將儲存庫轉移至您擁有管理員權限的帳戶或組織。 -settings.transfer_notices_1=- 如果您將儲存庫轉移給個人用戶,您將會丟失操作權限。 settings.transfer_notices_2=- 如果新的所有者的是組織且你是此組織的所有者之一,您的操作權限將被保留。 settings.transfer_form_title=請輸入以下訊息以確認您的操作: settings.wiki_delete=刪除 Wiki 資料 @@ -917,7 +905,6 @@ settings.delete_collaborator=刪除 settings.collaborator_deletion=協同者刪除 settings.collaborator_deletion_desc=刪除後此使用者將不再有協同者權限存取此儲存庫。你想要繼續嗎? settings.remove_collaborator_success=被操作的協作者已經被收回權限! -settings.search_user_placeholder=搜尋用戶... settings.org_not_allowed_to_be_collaborator=組織不允許被加為協同者。 settings.user_is_org_member=被操作的用戶是組織成員,因此無法新增為協作者! settings.add_webhook=建立 Webhook @@ -1006,7 +993,6 @@ settings.remove_protected_branch_success=%s 解鎖成功 settings.protected_branch_deletion=刪除一個受保護的分支 settings.protected_branch_deletion_desc=任何具有寫入權限的使用者都可以直接推進這個分支,您確定嗎? settings.default_branch_desc=預設分支被認為是"基準"分支,預期全部的合併請求以及程式碼提交將自動完成到此分支,除非您指定不同的分支。 -settings.choose_branch=選擇一個分支 settings.no_protected_branch=沒有受保護的分支 diff.browse_source=瀏覽代碼 @@ -1040,7 +1026,6 @@ release.title=標題 release.content=內容 release.write=內容編輯 release.preview=效果預覽 -release.loading=正在加載... release.prerelease_desc=這是一個預發佈版本 release.prerelease_helper=我們會告知用戶不建議將本發佈投入生產環境使用。 release.cancel=取消 @@ -1151,7 +1136,6 @@ teams.read_permission_desc=該團隊擁有對所屬儲存庫的 讀取讀取寫入 的權限。 teams.admin_permission_desc=該團隊擁有一定的 管理 權限,團隊成員可以讀取、複製、推送以及新增其它儲存庫協作者。 teams.repositories=團隊儲存庫 -teams.search_repo_placeholder=搜尋儲存庫... teams.add_team_repository=新增團隊儲存庫 teams.remove_repo=移除儲存庫 teams.add_nonexistent_repo=您嘗試新增到團隊的儲存庫不存在,請先建立儲存庫! @@ -1290,7 +1274,6 @@ auths.bind_password_helper=警告:此密碼將以明文形式儲存。請不 auths.user_base=用戶搜尋基準 auths.user_dn=用戶 DN auths.attribute_username=用戶名屬性 -auths.attribute_username_placeholder=留空表示使用用戶登錄時所使用的用戶名 auths.attribute_name=名子屬性 auths.attribute_surname=姓氏屬性 auths.attribute_mail=電子郵箱屬性 From 96c268c0fcc22604103f67821d66fef39944e80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Codru=C8=9B=20Constantin=20Gu=C8=99oi?= Date: Sun, 18 Feb 2018 18:14:37 +0000 Subject: [PATCH 016/106] Implements generator cli for secrets (#3531) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Codruț Constantin Gușoi --- cmd/generate.go | 83 ++++++++++++++++++++++++++++ main.go | 1 + models/migrations/migrations.go | 6 +-- models/twofactor.go | 4 +- models/user.go | 3 +- modules/base/tool.go | 29 ---------- modules/base/tool_test.go | 6 --- modules/generate/generate.go | 89 +++++++++++++++++++++++++++++++ modules/generate/generate_test.go | 20 +++++++ modules/setting/setting.go | 28 ++-------- routers/install.go | 10 +++- routers/user/auth_openid.go | 3 +- 12 files changed, 215 insertions(+), 67 deletions(-) create mode 100644 cmd/generate.go create mode 100644 modules/generate/generate.go create mode 100644 modules/generate/generate_test.go diff --git a/cmd/generate.go b/cmd/generate.go new file mode 100644 index 000000000..27c5d7884 --- /dev/null +++ b/cmd/generate.go @@ -0,0 +1,83 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Copyright 2016 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 cmd + +import ( + "fmt" + + "code.gitea.io/gitea/modules/generate" + + "github.com/urfave/cli" +) + +var ( + // CmdGenerate represents the available generate sub-command. + CmdGenerate = cli.Command{ + Name: "generate", + Usage: "Command line interface for running generators", + Subcommands: []cli.Command{ + subcmdSecret, + }, + } + + subcmdSecret = cli.Command{ + Name: "secret", + Usage: "Generate a secret token", + Subcommands: []cli.Command{ + microcmdGenerateInternalToken, + microcmdGenerateLfsJwtSecret, + microcmdGenerateSecretKey, + }, + } + + microcmdGenerateInternalToken = cli.Command{ + Name: "INTERNAL_TOKEN", + Usage: "Generate a new INTERNAL_TOKEN", + Action: runGenerateInternalToken, + } + + microcmdGenerateLfsJwtSecret = cli.Command{ + Name: "LFS_JWT_SECRET", + Usage: "Generate a new LFS_JWT_SECRET", + Action: runGenerateLfsJwtSecret, + } + + microcmdGenerateSecretKey = cli.Command{ + Name: "SECRET_KEY", + Usage: "Generate a new SECRET_KEY", + Action: runGenerateSecretKey, + } +) + +func runGenerateInternalToken(c *cli.Context) error { + internalToken, err := generate.NewInternalToken() + if err != nil { + return err + } + + fmt.Printf("%s\n", internalToken) + return nil +} + +func runGenerateLfsJwtSecret(c *cli.Context) error { + JWTSecretBase64, err := generate.NewLfsJwtSecret() + if err != nil { + return err + } + + fmt.Printf("%s\n", JWTSecretBase64) + return nil +} + +func runGenerateSecretKey(c *cli.Context) error { + secretKey, err := generate.NewSecretKey() + if err != nil { + return err + } + + fmt.Printf("%s\n", secretKey) + return nil +} diff --git a/main.go b/main.go index 788637f70..179132f58 100644 --- a/main.go +++ b/main.go @@ -45,6 +45,7 @@ arguments - which can alternatively be run by running the subcommand web.` cmd.CmdDump, cmd.CmdCert, cmd.CmdAdmin, + cmd.CmdGenerate, } app.Flags = append(app.Flags, []cli.Flag{}...) app.Action = cmd.CmdWeb.Action diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 23235f781..d79d40371 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -20,7 +20,7 @@ import ( gouuid "github.com/satori/go.uuid" "gopkg.in/ini.v1" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) @@ -539,10 +539,10 @@ func generateOrgRandsAndSalt(x *xorm.Engine) (err error) { } for _, org := range orgs { - if org.Rands, err = base.GetRandomString(10); err != nil { + if org.Rands, err = generate.GetRandomString(10); err != nil { return err } - if org.Salt, err = base.GetRandomString(10); err != nil { + if org.Salt, err = generate.GetRandomString(10); err != nil { return err } if _, err = sess.Id(org.ID).Update(org); err != nil { diff --git a/models/twofactor.go b/models/twofactor.go index 526ab917e..789315021 100644 --- a/models/twofactor.go +++ b/models/twofactor.go @@ -16,7 +16,7 @@ import ( "github.com/pquerna/otp/totp" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -33,7 +33,7 @@ type TwoFactor struct { // GenerateScratchToken recreates the scratch token the user is using. func (t *TwoFactor) GenerateScratchToken() error { - token, err := base.GetRandomString(8) + token, err := generate.GetRandomString(8) if err != nil { return err } diff --git a/models/user.go b/models/user.go index 57abfc196..fa41deec9 100644 --- a/models/user.go +++ b/models/user.go @@ -34,6 +34,7 @@ import ( "code.gitea.io/gitea/modules/avatar" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -638,7 +639,7 @@ func IsUserExist(uid int64, name string) (bool, error) { // GetUserSalt returns a random user salt token. func GetUserSalt() (string, error) { - return base.GetRandomString(10) + return generate.GetRandomString(10) } // NewGhostUser creates and returns a fake user for someone has deleted his/her account. diff --git a/modules/base/tool.go b/modules/base/tool.go index 347241e6b..16ac4dbff 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -14,7 +14,6 @@ import ( "html/template" "io" "math" - "math/big" "net/http" "net/url" "path" @@ -88,25 +87,6 @@ func BasicAuthEncode(username, password string) string { return base64.StdEncoding.EncodeToString([]byte(username + ":" + password)) } -// GetRandomString generate random string by specify chars. -func GetRandomString(n int) (string, error) { - const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - - buffer := make([]byte, n) - max := big.NewInt(int64(len(alphanum))) - - for i := 0; i < n; i++ { - index, err := randomInt(max) - if err != nil { - return "", err - } - - buffer[i] = alphanum[index] - } - - return string(buffer), nil -} - // GetRandomBytesAsBase64 generates a random base64 string from n bytes func GetRandomBytesAsBase64(n int) string { bytes := make([]byte, 32) @@ -119,15 +99,6 @@ func GetRandomBytesAsBase64(n int) string { return base64.RawURLEncoding.EncodeToString(bytes) } -func randomInt(max *big.Int) (int, error) { - rand, err := rand.Int(rand.Reader, max) - if err != nil { - return 0, err - } - - return int(rand.Int64()), nil -} - // VerifyTimeLimitCode verify time limit code func VerifyTimeLimitCode(data string, minutes int, code string) bool { if len(code) <= 18 { diff --git a/modules/base/tool_test.go b/modules/base/tool_test.go index ffa17fae0..f99edd5fb 100644 --- a/modules/base/tool_test.go +++ b/modules/base/tool_test.go @@ -107,12 +107,6 @@ func TestBasicAuthEncode(t *testing.T) { assert.Equal(t, "Zm9vOmJhcg==", BasicAuthEncode("foo", "bar")) } -func TestGetRandomString(t *testing.T) { - randomString, err := GetRandomString(4) - assert.NoError(t, err) - assert.Len(t, randomString, 4) -} - // TODO: Test PBKDF2() // TODO: Test VerifyTimeLimitCode() // TODO: Test CreateTimeLimitCode() diff --git a/modules/generate/generate.go b/modules/generate/generate.go new file mode 100644 index 000000000..d0e759301 --- /dev/null +++ b/modules/generate/generate.go @@ -0,0 +1,89 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Copyright 2016 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 generate + +import ( + "crypto/rand" + "encoding/base64" + "io" + "math/big" + "time" + + "github.com/dgrijalva/jwt-go" +) + +// GetRandomString generate random string by specify chars. +func GetRandomString(n int) (string, error) { + const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + + buffer := make([]byte, n) + max := big.NewInt(int64(len(alphanum))) + + for i := 0; i < n; i++ { + index, err := randomInt(max) + if err != nil { + return "", err + } + + buffer[i] = alphanum[index] + } + + return string(buffer), nil +} + +// NewInternalToken generate a new value intended to be used by INTERNAL_TOKEN. +func NewInternalToken() (string, error) { + secretBytes := make([]byte, 32) + _, err := io.ReadFull(rand.Reader, secretBytes) + if err != nil { + return "", err + } + + secretKey := base64.RawURLEncoding.EncodeToString(secretBytes) + + now := time.Now() + + var internalToken string + internalToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ + "nbf": now.Unix(), + }).SignedString([]byte(secretKey)) + if err != nil { + return "", err + } + + return internalToken, nil +} + +// NewLfsJwtSecret generate a new value intended to be used by LFS_JWT_SECRET. +func NewLfsJwtSecret() (string, error) { + JWTSecretBytes := make([]byte, 32) + _, err := io.ReadFull(rand.Reader, JWTSecretBytes) + if err != nil { + return "", err + } + + JWTSecretBase64 := base64.RawURLEncoding.EncodeToString(JWTSecretBytes) + return JWTSecretBase64, nil +} + +// NewSecretKey generate a new value intended to be used by SECRET_KEY. +func NewSecretKey() (string, error) { + secretKey, err := GetRandomString(64) + if err != nil { + return "", err + } + + return secretKey, nil +} + +func randomInt(max *big.Int) (int, error) { + rand, err := rand.Int(rand.Reader, max) + if err != nil { + return 0, err + } + + return int(rand.Int64()), nil +} diff --git a/modules/generate/generate_test.go b/modules/generate/generate_test.go new file mode 100644 index 000000000..538471af4 --- /dev/null +++ b/modules/generate/generate_test.go @@ -0,0 +1,20 @@ +package generate + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMain(m *testing.M) { + retVal := m.Run() + + os.Exit(retVal) +} + +func TestGetRandomString(t *testing.T) { + randomString, err := GetRandomString(4) + assert.NoError(t, err) + assert.Len(t, randomString, 4) +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 936dac85c..9ef175d20 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -6,10 +6,8 @@ package setting import ( - "crypto/rand" "encoding/base64" "fmt" - "io" "net" "net/mail" "net/url" @@ -24,12 +22,12 @@ import ( "time" "code.gitea.io/git" + "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/log" _ "code.gitea.io/gitea/modules/minwinsvc" // import minwinsvc for windows services "code.gitea.io/gitea/modules/user" "github.com/Unknwon/com" - "github.com/dgrijalva/jwt-go" _ "github.com/go-macaron/cache/memcache" // memcache plugin for cache _ "github.com/go-macaron/cache/redis" "github.com/go-macaron/session" @@ -834,16 +832,12 @@ func NewContext() { n, err := base64.RawURLEncoding.Decode(LFS.JWTSecretBytes, []byte(LFS.JWTSecretBase64)) if err != nil || n != 32 { - //Generate new secret and save to config - - _, err := io.ReadFull(rand.Reader, LFS.JWTSecretBytes) - + LFS.JWTSecretBase64, err = generate.NewLfsJwtSecret() if err != nil { - log.Fatal(4, "Error reading random bytes: %v", err) + log.Fatal(4, "Error generating JWT Secret for custom config: %v", err) + return } - LFS.JWTSecretBase64 = base64.RawURLEncoding.EncodeToString(LFS.JWTSecretBytes) - // Save secret cfg := ini.Empty() if com.IsFile(CustomConf) { @@ -913,19 +907,7 @@ func NewContext() { DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(false) InternalToken = sec.Key("INTERNAL_TOKEN").String() if len(InternalToken) == 0 { - secretBytes := make([]byte, 32) - _, err := io.ReadFull(rand.Reader, secretBytes) - if err != nil { - log.Fatal(4, "Error reading random bytes: %v", err) - } - - secretKey := base64.RawURLEncoding.EncodeToString(secretBytes) - - now := time.Now() - InternalToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ - "nbf": now.Unix(), - }).SignedString([]byte(secretKey)) - + InternalToken, err = generate.NewInternalToken() if err != nil { log.Fatal(4, "Error generate internal token: %v", err) } diff --git a/routers/install.go b/routers/install.go index c180d947f..2a7ec93d2 100644 --- a/routers/install.go +++ b/routers/install.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/user" @@ -275,7 +276,12 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) { if form.LFSRootPath != "" { cfg.Section("server").Key("LFS_START_SERVER").SetValue("true") cfg.Section("server").Key("LFS_CONTENT_PATH").SetValue(form.LFSRootPath) - cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(base.GetRandomBytesAsBase64(32)) + var secretKey string + if secretKey, err = generate.NewLfsJwtSecret(); err != nil { + ctx.RenderWithErr(ctx.Tr("install.lfs_jwt_secret_failed", err), tplInstall, &form) + return + } + cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(secretKey) } else { cfg.Section("server").Key("LFS_START_SERVER").SetValue("false") } @@ -315,7 +321,7 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) { cfg.Section("security").Key("INSTALL_LOCK").SetValue("true") var secretKey string - if secretKey, err = base.GetRandomString(10); err != nil { + if secretKey, err = generate.NewSecretKey(); err != nil { ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), tplInstall, &form) return } diff --git a/routers/user/auth_openid.go b/routers/user/auth_openid.go index c784d7e1e..7df40bcc9 100644 --- a/routers/user/auth_openid.go +++ b/routers/user/auth_openid.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/auth/openid" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -348,7 +349,7 @@ func RegisterOpenIDPost(ctx *context.Context, cpt *captcha.Captcha, form auth.Si if len < 256 { len = 256 } - password, err := base.GetRandomString(len) + password, err := generate.GetRandomString(len) if err != nil { ctx.RenderWithErr(err.Error(), tplSignUpOID, form) return From ae30315a62644774756df64af0ca1ef405853a57 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Sun, 18 Feb 2018 22:06:37 +0200 Subject: [PATCH 017/106] Fix escaping changed title in comments (#3530) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix escaping changed title in comments * Fix escaping of wiki page titile Signed-off-by: Lauris Bukšis-Haberkorns --- integrations/pull_create_test.go | 41 +++++++++++++++++-- integrations/pull_merge_test.go | 8 ++-- integrations/repo_activity_test.go | 6 +-- .../repo/issue/view_content/comments.tmpl | 28 ++++++------- templates/repo/wiki/view.tmpl | 2 +- 5 files changed, 60 insertions(+), 25 deletions(-) diff --git a/integrations/pull_create_test.go b/integrations/pull_create_test.go index 89abccf88..1d53aa3b6 100644 --- a/integrations/pull_create_test.go +++ b/integrations/pull_create_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" ) -func testPullCreate(t *testing.T, session *TestSession, user, repo, branch string) *httptest.ResponseRecorder { +func testPullCreate(t *testing.T, session *TestSession, user, repo, branch, title string) *httptest.ResponseRecorder { req := NewRequest(t, "GET", path.Join(user, repo)) resp := session.MakeRequest(t, req, http.StatusOK) @@ -35,7 +35,7 @@ func testPullCreate(t *testing.T, session *TestSession, user, repo, branch strin assert.True(t, exists, "The template has changed") req = NewRequestWithValues(t, "POST", link, map[string]string{ "_csrf": htmlDoc.GetCSRF(), - "title": "This is a pull title", + "title": title, }) resp = session.MakeRequest(t, req, http.StatusFound) @@ -47,7 +47,7 @@ func TestPullCreate(t *testing.T) { session := loginUser(t, "user1") testRepoFork(t, session, "user2", "repo1", "user1", "repo1") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") - resp := testPullCreate(t, session, "user1", "repo1", "master") + resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title") // check the redirected URL url := resp.HeaderMap.Get("Location") @@ -68,3 +68,38 @@ func TestPullCreate(t *testing.T) { assert.Regexp(t, `Subject: \[PATCH\] Update 'README.md'`, resp.Body) assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one } + +func TestPullCreate_TitleEscape(t *testing.T) { + prepareTestEnv(t) + session := loginUser(t, "user1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") + resp := testPullCreate(t, session, "user1", "repo1", "master", "XSS PR") + + // check the redirected URL + url := resp.HeaderMap.Get("Location") + assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url) + + // Edit title + req := NewRequest(t, "GET", url) + resp = session.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + editTestTitleURL, exists := htmlDoc.doc.Find("#save-edit-title").First().Attr("data-update-url") + assert.True(t, exists, "The template has changed") + + req = NewRequestWithValues(t, "POST", editTestTitleURL, map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "title": "XSS PR", + }) + session.MakeRequest(t, req, http.StatusOK) + + req = NewRequest(t, "GET", url) + resp = session.MakeRequest(t, req, http.StatusOK) + htmlDoc = NewHTMLParser(t, resp.Body) + titleHTML, err := htmlDoc.doc.Find(".comments .event .text b").First().Html() + assert.NoError(t, err) + assert.Equal(t, "<i>XSS PR</i>", titleHTML) + titleHTML, err = htmlDoc.doc.Find(".comments .event .text b").Next().Html() + assert.NoError(t, err) + assert.Equal(t, "<u>XSS PR</u>", titleHTML) +} diff --git a/integrations/pull_merge_test.go b/integrations/pull_merge_test.go index b12323933..aabb2c78f 100644 --- a/integrations/pull_merge_test.go +++ b/integrations/pull_merge_test.go @@ -56,7 +56,7 @@ func TestPullMerge(t *testing.T) { testRepoFork(t, session, "user2", "repo1", "user1", "repo1") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") - resp := testPullCreate(t, session, "user1", "repo1", "master") + resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title") elem := strings.Split(test.RedirectURL(resp), "/") assert.EqualValues(t, "pulls", elem[3]) @@ -69,7 +69,7 @@ func TestPullRebase(t *testing.T) { testRepoFork(t, session, "user2", "repo1", "user1", "repo1") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") - resp := testPullCreate(t, session, "user1", "repo1", "master") + resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title") elem := strings.Split(test.RedirectURL(resp), "/") assert.EqualValues(t, "pulls", elem[3]) @@ -83,7 +83,7 @@ func TestPullSquash(t *testing.T) { testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n") - resp := testPullCreate(t, session, "user1", "repo1", "master") + resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title") elem := strings.Split(test.RedirectURL(resp), "/") assert.EqualValues(t, "pulls", elem[3]) @@ -96,7 +96,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) { testRepoFork(t, session, "user2", "repo1", "user1", "repo1") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n") - resp := testPullCreate(t, session, "user1", "repo1", "feature/test") + resp := testPullCreate(t, session, "user1", "repo1", "feature/test", "This is a pull title") elem := strings.Split(test.RedirectURL(resp), "/") assert.EqualValues(t, "pulls", elem[3]) diff --git a/integrations/repo_activity_test.go b/integrations/repo_activity_test.go index 40983cbe1..fcdbda2c8 100644 --- a/integrations/repo_activity_test.go +++ b/integrations/repo_activity_test.go @@ -22,16 +22,16 @@ func TestRepoActivity(t *testing.T) { // Create PRs (1 merged & 2 proposed) testRepoFork(t, session, "user2", "repo1", "user1", "repo1") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") - resp := testPullCreate(t, session, "user1", "repo1", "master") + resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title") elem := strings.Split(test.RedirectURL(resp), "/") assert.EqualValues(t, "pulls", elem[3]) testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge) testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/better_readme", "README.md", "Hello, World (Edited Again)\n") - testPullCreate(t, session, "user1", "repo1", "feat/better_readme") + testPullCreate(t, session, "user1", "repo1", "feat/better_readme", "This is a pull title") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/much_better_readme", "README.md", "Hello, World (Edited More)\n") - testPullCreate(t, session, "user1", "repo1", "feat/much_better_readme") + testPullCreate(t, session, "user1", "repo1", "feat/much_better_readme", "This is a pull title") // Create issues (3 new issues) testNewIssue(t, session, "user2", "repo1", "Issue 1", "Description 1") diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 49a0216e8..3557c5d3c 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -103,7 +103,7 @@ {{.Poster.Name}} - {{if .Content}}{{$.i18n.Tr "repo.issues.add_label_at" .Label.ForegroundColor .Label.Color .Label.Name $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_label_at" .Label.ForegroundColor .Label.Color .Label.Name $createdStr | Safe}}{{end}} + {{if .Content}}{{$.i18n.Tr "repo.issues.add_label_at" .Label.ForegroundColor .Label.Color (.Label.Name|Escape) $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_label_at" .Label.ForegroundColor .Label.Color (.Label.Name|Escape) $createdStr | Safe}}{{end}} {{end}} {{else if eq .Type 8}} @@ -113,7 +113,7 @@ {{.Poster.Name}} - {{if gt .OldMilestoneID 0}}{{if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.change_milestone_at" .OldMilestone.Name .Milestone.Name $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_milestone_at" .OldMilestone.Name $createdStr | Safe}}{{end}}{{else if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.add_milestone_at" .Milestone.Name $createdStr | Safe}}{{end}} + {{if gt .OldMilestoneID 0}}{{if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.change_milestone_at" (.OldMilestone.Name|Escape) (.Milestone.Name|Escape) $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_milestone_at" (.OldMilestone.Name|Escape) $createdStr | Safe}}{{end}}{{else if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.add_milestone_at" (.Milestone.Name|Escape) $createdStr | Safe}}{{end}} {{else if eq .Type 9}}
@@ -131,23 +131,23 @@ {{else if eq .Type 10}}
+ + + + {{.Poster.Name}} + {{$.i18n.Tr "repo.issues.change_title_at" (.OldTitle|Escape) (.NewTitle|Escape) $createdStr | Safe}} +
- - - - {{.Poster.Name}} - {{$.i18n.Tr "repo.issues.change_title_at" .OldTitle .NewTitle $createdStr | Safe}} - {{else if eq .Type 11}}
+ + + + {{.Poster.Name}} + {{$.i18n.Tr "repo.issues.delete_branch_at" .CommitSHA $createdStr | Safe}} +
- - - - {{.Poster.Name}} - {{$.i18n.Tr "repo.issues.delete_branch_at" .CommitSHA $createdStr | Safe}} - {{else if eq .Type 12}}
diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index dfd368cd3..93b7c1064 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -104,7 +104,7 @@ {{.i18n.Tr "repo.wiki.delete_page_button"}}
-

{{.i18n.Tr "repo.wiki.delete_page_notice_1" $title | Safe}}

+

{{.i18n.Tr "repo.wiki.delete_page_notice_1" ($title|Escape) | Safe}}

{{template "base/delete_modal_actions" .}}
From 3a9c6988216968b8c4ec0082ce148819ae1e9069 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Sun, 18 Feb 2018 23:19:40 +0200 Subject: [PATCH 018/106] Force remove test repo root path in case previous test is still locking it (#3528) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lauris Bukšis-Haberkorns --- models/unit_tests.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/models/unit_tests.go b/models/unit_tests.go index 8fdeb0b14..962b1a494 100644 --- a/models/unit_tests.go +++ b/models/unit_tests.go @@ -9,6 +9,7 @@ import ( "os" "path/filepath" "testing" + "time" "code.gitea.io/gitea/modules/setting" @@ -72,6 +73,18 @@ func createTestEngine(fixturesDir string) error { return InitFixtures(&testfixtures.SQLite{}, fixturesDir) } +func removeAllWithRetry(dir string) error { + var err error + for i := 0; i < 20; i++ { + err = os.RemoveAll(dir) + if err == nil { + break + } + time.Sleep(100 * time.Millisecond) + } + return err +} + // PrepareTestDatabase load test fixtures into test database func PrepareTestDatabase() error { return LoadFixtures() @@ -81,7 +94,7 @@ func PrepareTestDatabase() error { // by tests that use the above MainTest(..) function. func PrepareTestEnv(t testing.TB) { assert.NoError(t, PrepareTestDatabase()) - assert.NoError(t, os.RemoveAll(setting.RepoRootPath)) + assert.NoError(t, removeAllWithRetry(setting.RepoRootPath)) metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta") assert.NoError(t, com.CopyDir(metaPath, setting.RepoRootPath)) } From fb2c176491ebc0f18e6ef25038ca84db561539e2 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 18 Feb 2018 21:20:48 +0000 Subject: [PATCH 019/106] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 3 +++ options/locale/locale_it-IT.ini | 27 +++++++++++++++++++++++++++ options/locale/locale_lv-LV.ini | 17 +++++++++++++++++ options/locale/locale_pl-PL.ini | 11 +++++++++++ 4 files changed, 58 insertions(+) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 2597774d3..942c005b7 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -249,6 +249,7 @@ Content=Inhalt require_error=` darf nicht leer sein.` alpha_dash_error=` kann ausschließlich alphanumerische Zeichen und (-_) enthalten.` alpha_dash_dot_error=` müssen gültige alphanumerische, dash(-_) oder Punkt-Zeichen sein. ` +git_ref_name_error=` muss ein wohlgeformter Git-Referenzname sein.` size_error=` muss die Größe %s haben.` min_size_error=` muss mindestens %s Zeichen enthalten.` max_size_error=` darf höchstens %s Zeichen enthalten.` @@ -576,6 +577,7 @@ editor.delete='%s' löschen editor.commit_message_desc=Eine ausführlichere (optionale) Beschreibung hinzufügen… editor.commit_directly_to_this_branch=Direkt in die %s-Branch einchecken. editor.create_new_branch=Einen neuen Branch für diesen Commit erstellen und einen Pull Request starten. +editor.new_branch_name_desc=Neuer Branchname… editor.cancel=Abbrechen editor.filename_cannot_be_empty=Der Dateiname darf nicht leer sein. editor.branch_already_exists=Branch '%s' existiert bereits in diesem Repository. @@ -1027,6 +1029,7 @@ settings.remove_protected_branch_success=Branch-Protection für %s erfolgreich e settings.protected_branch_deletion=Eine geschützte Branch löschen settings.protected_branch_deletion_desc=Jeder mit Schreibzugriff wird direkt in diese Branch pushen können. Bist du sicher? settings.default_branch_desc=Die Standardbranch ist als "basis"-Branch in deinem Repository definiert, Commits und Pull-Requests werden automatisch mit dieser Branch durchgeführt wenn du keine andere angibst. +settings.choose_branch=Wähle einen Branch… settings.no_protected_branch=Es gibt keine geschützten Branches diff.browse_source=Quellcode durchsuchen diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 078a2a3ed..9b6a51346 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -365,21 +365,41 @@ keep_email_private_popup=Il tuo indirizzo email sarà nascosto agli altri utenti openid_desc=Gli indirizzi OpenID ti permetteranno di delegare l'autenticazione al tuo fornitore di scelta manage_ssh_keys=Gestisci chiavi SSH +manage_gpg_keys=Gestisci Chiavi GPG add_key=Aggiungi Chiave ssh_desc=Queste sono le chiavi SSH associate a la tua conta. Perchè queste chiavi consentono a chiunque le usi di accedere ai propri repository, è molto importante assicurarsi di riconoscerle. gpg_desc=Queste sono le chiavi GPG associate a la tua conta. Perchè queste chiavi consentono di confermare, è molto importante mantenere la chiave privata corrispondente al sicuro. ssh_helper= Hai bisogno di aiuto? Dai un'occhiata alla guida di GitHub crea le tue chiavi SSH o risolvere problemi comuni puoi trovare usando SSH. +gpg_helper=Hai bisogno di aiuto? Dai un'occhiata alla guida di GitHub riguardo il GPG. add_new_key=Aggiungi Chiave SSH +add_new_gpg_key=Aggiungi Chiave GPG +ssh_key_been_used=Questa chiave pubblica è già stata utilizzata. +ssh_key_name_used=Una chiave pubblica con stesso nome esiste già. +gpg_key_id_used=Una chiave GPG pubblica con stesso id esiste già. +subkeys=Sottochiavi +key_id=ID chiave key_name=Nome della Chiave key_content=Contenuto +add_key_success=La tua chiave SSH '%s' è stata aggiunta. +add_gpg_key_success=La tua chiave GPG '%s' è stata aggiunta. delete_key=Elimina ssh_key_deletion=Eliminazione chiave SSH +gpg_key_deletion=Eliminazione chiave GPG ssh_key_deletion_desc=Rimuovendo questa chiave SSH tutti gli accessi saranno revocati usando questa chiave SSH per la tua conta. Vuoi continuare? +ssh_key_deletion_success=La chiave SSH è stata eliminata. +gpg_key_deletion_success=La chiave GPG è stata eliminata. add_on=Aggiunto il +valid_until=Valido fino al +valid_forever=Valido per sempre last_used=Ultimo accesso il no_activity=Nessuna attività recente can_read_info=Letto can_write_info=Scrivere +key_state_desc=Questa chiave è stata utilizzata negli ultimi 7 giorni +token_state_desc=Questo token è stato utilizzato negli ultimi 7 giorni +show_openid=Mostra nel profilo +hide_openid=Nascondi dal profilo +ssh_disabled=SSH disabilitato manage_social=Gestisci gli Account Sociali Associati social_desc=Questa è una lista di conta social associati. Per motivi di sicurrezza, assicurati di riconoscere tutte queste voci, in quanto possono essere utilizzate per accedere a la tua conta. @@ -398,17 +418,24 @@ delete_token_success=Il token di accesso personale è stato rimosso. Non dimenti twofa_desc=Gitea supporta l'autenticazione a due fattori per migliorare la sicurezza de la tua conta. twofa_disable=Disattiva verifica in due passaggi +twofa_disable_note=Se necessario, è possibile disattivare l'autenticazione a due fattori. +twofa_disabled=L'autenticazione a due fattori è stata disattivata. +or_enter_secret=O immettere il segreto: %s +remove_account_link=Rimuovi account collegato +repos_none=Non possiedi alcun repository delete_account=Elimina Account delete_prompt=L'operazione eliminerà permanentemente l'account e NON POTRÀ essere annullata! confirm_delete_account=Conferma Eliminazione delete_account_title=Eliminazione account +delete_account_desc=Sei sicuro di voler eliminare definitivamente questo account? [repo] owner=Proprietario repo_name=Nome Repository +repo_name_helper=Un buon nome per un repository è costituito da parole chiavi corte, memorabili e uniche. visibility=Visibilità visiblity_helper=Questo repository è privato visiblity_fork_helper=(La modifica di questo valore avrà effetto su tutti i fork) diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index d9c4f3ce5..eb58947bf 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -17,6 +17,7 @@ page=Lapa template=Sagatave language=Valoda notifications=Paziņojumi +create_new=Izveidot… user_profile_and_more=Lietotāja profilu un vairāk signed_in_as=Pierakstījies kā enable_javascript=Šī lapa labāk darbojas, ja pārlūkam ir pieejams JavaScript @@ -154,10 +155,12 @@ uname_holder=Lietotājvārds vai e-pasts password_holder=Parole switch_dashboard_context=Mainīt infopaneļa kontekstu my_repos=Mani repozitoriji +show_more_repos=Parādīt vairāk repozitorijus… collaborative_repos=Sadarbības repozitoriji my_orgs=Manas organizācijas my_mirrors=Mani spoguļi view_home=Skatīties %s +search_repos=Meklēt repozitoriju… issues.in_your_repos=Jūsu repozitorijos @@ -246,6 +249,7 @@ Content=Saturs require_error=` nedrīkst būt tukšs.` alpha_dash_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus vai domuzīmes (-_).` alpha_dash_dot_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus, domuzīmes (-_) vai punktu.` +git_ref_name_error=` jābūt korektam git references nosaukumam.` size_error=` jābūt %s simbolus garam.` min_size_error=` jabūt vismaz %s simbolu garumā.` max_size_error=` jabūt ne mazāk kā %s simbolu garumā.` @@ -331,6 +335,7 @@ enable_custom_avatar=Iespējot maināmu profila attēlu choose_new_avatar=Izvēlēties jaunu profila attēlu update_avatar=Saglabāt profila bildi delete_current_avatar=Dzēst pašreizējo profila bildi +uploaded_avatar_not_a_image=Augšupielādētais fails nav attēls. update_avatar_success=Profila attēls tika saglabāts. change_password=Mainīt paroli @@ -560,6 +565,7 @@ editor.fork_before_edit=Lai varētu labot failu ir nepieciešams atdalīt repozi editor.delete_this_file=Dzēst šo failu editor.must_have_write_access=Jums ir jābūt rakstīšanas tiesībām, lai varētu veikt vai piedāvāt izmaiņas šim failam editor.file_delete_success=Fails '%s' ir veiksmīgi izdzēsts! +editor.name_your_file=Ievadiet faila nosaukumu… editor.filename_help=Lai pievienotu direktoriju, ierakstiet tās nosaukumu un nospiediet /. Lai noņemtu direktoriju, ielieciet kursoru pirms faila nosaukuma un nospiediet atpakaļatkāpes taustiņu. editor.or=vai editor.cancel_lower=atcelt @@ -568,8 +574,10 @@ editor.add_tmpl=Pievienot '%s/' editor.add=Pievienot '%s' editor.update=Atjaunināt '%s' editor.delete=Dzēst '%s' +editor.commit_message_desc=Pievienot neobligātu paplašinātu aprakstu… editor.commit_directly_to_this_branch=Apstiprināt revīzijas izmaiņas atzarā %s. editor.create_new_branch=Izveidot jaunu atzaru un izmaiņu pieprasījumu šai revīzijai. +editor.new_branch_name_desc=Jaunā atzara nosaukums… editor.cancel=Atcelt editor.filename_cannot_be_empty=Nav ievadīts faila nosaukums. editor.branch_already_exists=Atzars '%s' šajā repozitorijā jau eksistē. @@ -581,6 +589,7 @@ editor.file_changed_while_editing=Faila saturs ir mainījies kopš Jūs sākāt editor.file_already_exists=Fails ar nosaukumu '%s' repozitorijā jau eksistē. editor.no_changes_to_show=Nav izmaiņu, ko rādīt. editor.fail_to_update_file=Neizdevās izmainīt/izveidot failu '%s', kļūda: %v +editor.add_subdir=Pievienot apakšdirektoriju… editor.unable_to_upload_files=Neizdevās augšupielādēt failus uz direktoriju '%s', kļūda: %v editor.upload_files_to_dir=Augšupielādēt failus uz direktoriju '%s' editor.cannot_commit_to_protected_branch=Nav atļauts veikt izmaiņas aizsargātam atzaram '%s'. @@ -617,6 +626,7 @@ issues.new.no_assignee=Nav atbildīgā issues.no_ref=Nav norādīts atzars/tags issues.create=Pieteikt problēmu issues.new_label=Jauna etiķete +issues.new_label_placeholder=Etiķetes nosaukums… issues.create_label=Izveidot etiķeti issues.label_templates.title=Ielādēt sākotnēji noteikto etiķešu kopu issues.label_templates.info=Nav izveidota neviena etiķete. Jūs varat noklikšķināt uz "Jauna etiķete" augstāk, lai to izveidotu vai izmantot zemāk piedāvātās etiķetes. @@ -887,6 +897,7 @@ settings.tracker_url_format=Ārējā problēmu sekotāja adreses formāts settings.tracker_issue_style=Ārējā problēmu reģistra nosaukumu stils: settings.tracker_issue_style.numeric=Cipari settings.tracker_issue_style.alphanumeric=Burti un cipari +settings.tracker_url_format_desc=Jūs varat izmantot {user}{repo}{index} lietotājvārdam, repozitorija nosaukumam un problēmas identifikātoram. settings.enable_timetracker=Iespējot laika uzskaiti settings.allow_only_contributors_to_track_time=Atļaut tikai dalībniekiem uzskaitīt laiku settings.pulls_desc=Iespējot izmaiņu pieprasījumus lai saņemtu publiskus ieguldījumus @@ -903,6 +914,7 @@ settings.convert_confirm=Apstiprināt konvertēšanu settings.convert_succeed=Repozitorijs tika izmainīts par parastu repozitoriju. settings.transfer=Mainīt īpašnieku settings.transfer_desc=Mainīt šī repozitorija īpašnieku uz citu lietotāju vai organizāciju, kurai Jums ir administratora tiesībs. +settings.transfer_notices_1=- Jūs zaudēsiet piekļuvi, ja jaunais īpašnieks ir individuāls lietotājs. settings.transfer_notices_2=- Jūs saglabāsiet piekļuvi, ja jaunais īpašnieks ir organizācija un Jūs esat viens no tās īpašniekiem. settings.transfer_form_title=Ievadiet sekojošu informāciju, lai apstiprinātu savu darbību: settings.wiki_delete=Dzēst Vikivietnes datus @@ -926,6 +938,7 @@ settings.delete_collaborator=Dzēst settings.collaborator_deletion=Līdzstrādnieka dzēšana settings.collaborator_deletion_desc=Šim lietotājam pēc dzēšanas vairs nebūs sadarbības pieejas šai krātuvei. Vai vēlaties turpināt? settings.remove_collaborator_success=Līdzstrādnieks tika noņemts. +settings.search_user_placeholder=Meklēt lietotāju… settings.org_not_allowed_to_be_collaborator=Organizāciju nav atļauts pievienot kā līdzstrādnieku. settings.user_is_org_member=Lietotājs ir organizācijas biedrs, kas nevar tikt pievienots kā līdzstrādnieks. settings.add_webhook=Pievienot tīmekļa āķi @@ -1016,6 +1029,7 @@ settings.remove_protected_branch_success=Atzara %s aizsardzība veiksmīgi noņe settings.protected_branch_deletion=Lai dzēstu atzara aizsardzību settings.protected_branch_deletion_desc=Ikviens ar rakstīšanas tiesībām varēs nosūtīt izmaiņas uz šo zaru. Vai patiešām to vēlaties? settings.default_branch_desc=Noklusētais atzars tiek uzskatīts par bāzes atzaru repozitorijā uz kuru tiks veidoti izmaiņu pieprasījumu un pēc noklusējuma tiek veiktas koda izmaiņas, ja vien nav norādīts cits atzars. +settings.choose_branch=Izvēlieties atzaru… settings.no_protected_branch=Nav neviena aizsargātā atzara diff.browse_source=Pārlūkot izejas kodu @@ -1049,6 +1063,7 @@ release.title=Virsraksts release.content=Saturs release.write=Rakstīt release.preview=Priekšskatītījums +release.loading=Notiek ielāde… release.prerelease_desc=Šī ir pirmslaidiena versija release.prerelease_helper=Tiks norādīts, ka šis laidiens nav gatavs lietošanai produkcijas režīmā. release.cancel=Atcelt @@ -1162,6 +1177,7 @@ teams.read_permission_desc=Šai komandai ir lasīšanas tiesīb teams.write_permission_desc=Šai komandai ir rakstīšanas tiesības: dalībnieki var lasīt un nosūtīt izmaiņas repozitorijiem. teams.admin_permission_desc=Šai komandai ir administratora tiesības: dalībnieki var lasīt, rakstīt un pievienot citus dalībniekus komandas repozitorijiem. teams.repositories=Komandas repozitoriji +teams.search_repo_placeholder=Meklēt repozitorijā… teams.add_team_repository=Pievienot komandas repozitoriju teams.remove_repo=Noņemt teams.add_nonexistent_repo=Repozitorijs, kuram Jūs mēģinat pievienot neeksistē, sākumā izveidojiet to. @@ -1300,6 +1316,7 @@ auths.bind_password_helper=Brīdinājums: Šī parole tiks glabāta nešifrētā auths.user_base=Lietotāja pamatnosacījumi auths.user_dn=Lietotāja DN auths.attribute_username=Lietotājvārda atribūts +auths.attribute_username_placeholder=Atstājiet tukšu, lai izmantotu lietotājvārdu ar kuru autorizējaties. auths.attribute_name=Vārda atribūts auths.attribute_surname=Uzvārda atribūts auths.attribute_mail=E-pasta atribūts diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 0d85b724b..902597ec4 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -62,6 +62,7 @@ cancel=Anuluj install=Instalacja title=Wstępna konfiguracja docker_helper=Jeśli używasz Gitea wewnątrz Dockera, proszę przeczytaj wytyczne zanim zmienisz coś na tej stronie. +requite_db_desc=Gitea wymaga MySQL, MSSQL, PostgreSQL, SQLite3 lub TiDB. db_title=Ustawienia bazy danych db_type=Typ bazy danych host=Serwer @@ -265,6 +266,7 @@ openid_been_used=Adres OpenID '%s' jest już używany. username_password_incorrect=Nieprawidłowa nazwa użytkownika lub hasło. enterred_invalid_repo_name=Upewnij się, że wprowadzona nazwa repozytorium jest poprawna. enterred_invalid_owner_name=Upewnij się, że nazwa właściciela repozytorium jest poprawna. +enterred_invalid_password=Proszę się upewnić, że wprowadzone hasło jest poprawne. user_not_exist=Użytkownik nie istnieje. last_org_owner=Usuwany użytkownik jest ostatnim członkiem ekipy właścicieli. Musi być inny właściciel. cannot_add_org_to_team=Organizacja nie może zostać dodana jako członek zespołu. @@ -394,6 +396,8 @@ valid_until=Ważne do valid_forever=Ważne bezterminowo last_used=Ostatnio użyto no_activity=Brak aktywności +can_read_info=Odczyt +can_write_info=Zapis key_state_desc=Ten klucz był użyty w ciągu ostatnich 7 dni token_state_desc=Ten token był użyty w ciągu ostatnich 7 dni show_openid=Pokaż w profilu @@ -620,10 +624,13 @@ issues.label_templates.use=Użyj ten zestaw etykiet issues.label_templates.fail_to_load_file=Ładowanie pliku szablonu etykiety '%s' nie powiodło się: %v issues.add_label_at=dodano etykietę
%s
%s issues.remove_label_at=usunięto etykietę
%s
%s +issues.add_milestone_at=`dodano do %s kamień milowy %s` issues.change_milestone_at=`zmodyfikował kamień milowy z %s na %s %s` +issues.remove_milestone_at=`usunięto z %s kamień milowy %s` issues.deleted_milestone=`(usunięto)` issues.self_assign_at=`samo przypisany do %s` issues.add_assignee_at=`został przypisany przez %s %s` +issues.remove_assignee_at=`usunięto przypisanie %s` issues.change_title_at=`zmieniono tytuł z %s na %s %s` issues.delete_branch_at=`usunął gałąź %s %s` issues.open_tab=Otwarte %d @@ -739,6 +746,8 @@ pulls.can_auto_merge_desc=Ten pull request może być automatycznie scalony. pulls.cannot_auto_merge_desc=Ten pull request nie może być automatycznie scalony z powodu konfliktów. pulls.cannot_auto_merge_helper=Proszę scalić ręcznie, aby rozwiązać konflikty. pulls.merge_pull_request=Scal pull request +pulls.rebase_merge_pull_request=Zmień bazę i scal +pulls.invalid_merge_option=Nie możesz użyć opcji scalenia dla tego pull requestu milestones.new=Nowy kamień milowy milestones.open_tab=Otwarte %d @@ -875,7 +884,9 @@ settings.tracker_issue_style.alphanumeric=Alfanumeryczne settings.enable_timetracker=Włącz śledzenie czasu settings.allow_only_contributors_to_track_time=Pozwól jedynie współpracownikom na śledzenie czasu settings.pulls_desc=Włącz obsługę pull request, aby akceptować publiczny wkład +settings.pulls.ignore_whitespace=Ignoruj zmiany w białych znakach podczas sprawdzania konfliktów settings.pulls.allow_merge_commits=Zezwól na komentarze przy scalaniu +settings.pulls.allow_rebase_merge=Zezwalaj na scalanie gałęzi poprzez zmianę bazy settings.danger_zone=Strefa niebezpieczeństwa settings.new_owner_has_same_repo=Nowy właściciel już posiada repozytorium o tej samej nazwie. settings.convert=Konwersja na repozytorium regularne From 58893384e848b54687c21d6d2ca38b70b3036ae2 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Mon, 19 Feb 2018 04:39:26 +0200 Subject: [PATCH 020/106] Add issue closed time column to fix activity closed issues list (#3537) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lauris Bukšis-Haberkorns --- models/issue.go | 8 +++++++- models/issue_milestone_test.go | 6 ++++-- models/migrations/migrations.go | 2 ++ models/migrations/v57.go | 30 ++++++++++++++++++++++++++++++ models/repo_activity.go | 8 ++++++-- templates/repo/activity.tmpl | 2 +- 6 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 models/migrations/v57.go diff --git a/models/issue.go b/models/issue.go index d10c521db..9106db281 100644 --- a/models/issue.go +++ b/models/issue.go @@ -49,6 +49,7 @@ type Issue struct { DeadlineUnix util.TimeStamp `xorm:"INDEX"` CreatedUnix util.TimeStamp `xorm:"INDEX created"` UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` + ClosedUnix util.TimeStamp `xorm:"INDEX"` Attachments []*Attachment `xorm:"-"` Comments []*Comment `xorm:"-"` @@ -612,8 +613,13 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository, return nil } issue.IsClosed = isClosed + if isClosed { + issue.ClosedUnix = util.TimeStampNow() + } else { + issue.ClosedUnix = 0 + } - if err = updateIssueCols(e, issue, "is_closed"); err != nil { + if err = updateIssueCols(e, issue, "is_closed", "closed_unix"); err != nil { return err } diff --git a/models/issue_milestone_test.go b/models/issue_milestone_test.go index f7987d45a..c57f92439 100644 --- a/models/issue_milestone_test.go +++ b/models/issue_milestone_test.go @@ -214,13 +214,15 @@ func TestChangeMilestoneIssueStats(t *testing.T) { "is_closed=0").(*Issue) issue.IsClosed = true - _, err := x.Cols("is_closed").Update(issue) + issue.ClosedUnix = util.TimeStampNow() + _, err := x.Cols("is_closed", "closed_unix").Update(issue) assert.NoError(t, err) assert.NoError(t, changeMilestoneIssueStats(x.NewSession(), issue)) CheckConsistencyFor(t, &Milestone{}) issue.IsClosed = false - _, err = x.Cols("is_closed").Update(issue) + issue.ClosedUnix = 0 + _, err = x.Cols("is_closed", "closed_unix").Update(issue) assert.NoError(t, err) assert.NoError(t, changeMilestoneIssueStats(x.NewSession(), issue)) CheckConsistencyFor(t, &Milestone{}) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index d79d40371..dfaef2c78 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -166,6 +166,8 @@ var migrations = []Migration{ NewMigration("add writable deploy keys", addModeToDeploKeys), // v56 -> v57 NewMigration("remove is_owner, num_teams columns from org_user", removeIsOwnerColumnFromOrgUser), + // v57 -> v58 + NewMigration("add closed_unix column for issues", addIssueClosedTime), } // Migrate database to current version diff --git a/models/migrations/v57.go b/models/migrations/v57.go new file mode 100644 index 000000000..3a79a5cca --- /dev/null +++ b/models/migrations/v57.go @@ -0,0 +1,30 @@ +// Copyright 2017 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 migrations + +import ( + "fmt" + + "code.gitea.io/gitea/modules/util" + + "github.com/go-xorm/xorm" +) + +func addIssueClosedTime(x *xorm.Engine) error { + // Issue see models/issue.go + type Issue struct { + ClosedUnix util.TimeStamp `xorm:"INDEX"` + } + + if err := x.Sync2(new(Issue)); err != nil { + return fmt.Errorf("Sync2: %v", err) + } + + if _, err := x.Exec("UPDATE `issue` SET `closed_unix` = `updated_unix` WHERE `is_closed` = ?", true); err != nil { + return err + } + + return nil +} diff --git a/models/repo_activity.go b/models/repo_activity.go index 839a74a7e..c3017e8e3 100644 --- a/models/repo_activity.go +++ b/models/repo_activity.go @@ -176,7 +176,7 @@ func (stats *ActivityStats) FillIssues(repoID int64, fromTime time.Time) error { // Closed issues sess := issuesForActivityStatement(repoID, fromTime, true, false) - sess.OrderBy("issue.updated_unix DESC") + sess.OrderBy("issue.closed_unix DESC") stats.ClosedIssues = make(IssueList, 0) if err = sess.Find(&stats.ClosedIssues); err != nil { return err @@ -228,7 +228,11 @@ func issuesForActivityStatement(repoID int64, fromTime time.Time, closed, unreso if !unresolved { sess.And("issue.is_pull = ?", false) - sess.And("issue.created_unix >= ?", fromTime.Unix()) + if closed { + sess.And("issue.closed_unix >= ?", fromTime.Unix()) + } else { + sess.And("issue.created_unix >= ?", fromTime.Unix()) + } } else { sess.And("issue.created_unix < ?", fromTime.Unix()) sess.And("issue.updated_unix >= ?", fromTime.Unix()) diff --git a/templates/repo/activity.tmpl b/templates/repo/activity.tmpl index cd528582f..f5454afb9 100644 --- a/templates/repo/activity.tmpl +++ b/templates/repo/activity.tmpl @@ -134,7 +134,7 @@

{{$.i18n.Tr "repo.activity.closed_issue_label"}}
#{{.Index}} {{.Title}} - {{TimeSinceUnix .UpdatedUnix $.Lang}} + {{TimeSinceUnix .ClosedUnix $.Lang}}

{{end}} From 6f751409b4f996af83e88064877271efa90534f9 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Mon, 19 Feb 2018 05:23:41 +0200 Subject: [PATCH 021/106] Document generate commands (#3532) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Document generate commands Signed-off-by: Lauris Bukšis-Haberkorns * Fix examples and grammar Signed-off-by: Lauris Bukšis-Haberkorns --- docs/content/doc/usage/command-line.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/content/doc/usage/command-line.md b/docs/content/doc/usage/command-line.md index 63f4a2a90..cf6feeaf5 100644 --- a/docs/content/doc/usage/command-line.md +++ b/docs/content/doc/usage/command-line.md @@ -95,3 +95,19 @@ in the current directory. - Examples: - `gitea dump` - `gitea dump --verbose` + +#### generate + +Generates random values and tokens for usage in configuration file. Useful for generating values +for automatic deployments. + +- Commands: + - `secret`: + - Options: + - `INTERNAL_TOKEN`: Token used for an internal API call authentication. + - `LFS_JWT_SECRET`: LFS authentication secret. + - `SECRET_KEY`: Global secret key. + - Examples: + - `gitea generate secret INTERNAL_TOKEN` + - `gitea generate secret LFS_JWT_SECRET` + - `gitea generate secret SECRET_KEY` From 7b297808cee599f5ff58b9f6afa64d3ee980998e Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Mon, 19 Feb 2018 07:10:51 +0200 Subject: [PATCH 022/106] Update markbates/goth library (#3533) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lauris Bukšis-Haberkorns --- vendor/github.com/markbates/goth/README.md | 97 +++++----- .../markbates/goth/gothic/gothic.go | 168 +++++++++++++++--- .../goth/providers/bitbucket/bitbucket.go | 12 +- .../goth/providers/dropbox/dropbox.go | 21 +-- .../goth/providers/facebook/facebook.go | 16 +- .../markbates/goth/providers/gitlab/gitlab.go | 2 +- .../markbates/goth/providers/gplus/gplus.go | 10 +- .../providers/openidConnect/openidConnect.go | 32 ++-- .../goth/providers/openidConnect/session.go | 4 +- .../goth/providers/twitter/twitter.go | 24 +-- vendor/vendor.json | 58 +++--- 11 files changed, 284 insertions(+), 160 deletions(-) diff --git a/vendor/github.com/markbates/goth/README.md b/vendor/github.com/markbates/goth/README.md index b481683bc..05b19fce5 100644 --- a/vendor/github.com/markbates/goth/README.md +++ b/vendor/github.com/markbates/goth/README.md @@ -8,6 +8,10 @@ protocol providers, as long as they implement the `Provider` and `Session` inter This package was inspired by [https://github.com/intridea/omniauth](https://github.com/intridea/omniauth). +## Goth Needs a New Maintainer + +[https://blog.gobuffalo.io/goth-needs-a-new-maintainer-626cd47ca37b](https://blog.gobuffalo.io/goth-needs-a-new-maintainer-626cd47ca37b) - TL;DR: I, @markbates, won't be responding to any more issues, PRs, etc... for this package. A new maintainer needs to be found ASAP. Is this you? + ## Installation ```text @@ -18,6 +22,8 @@ $ go get github.com/markbates/goth * Amazon * Auth0 +* Azure AD +* Battle.net * Bitbucket * Box * Cloud Foundry @@ -26,6 +32,7 @@ $ go get github.com/markbates/goth * Digital Ocean * Discord * Dropbox +* Eve Online * Facebook * Fitbit * GitHub @@ -38,6 +45,7 @@ $ go get github.com/markbates/goth * Lastfm * Linkedin * Meetup +* MicrosoftOnline * OneDrive * OpenID Connect (auto discovery) * Paypal @@ -50,7 +58,9 @@ $ go get github.com/markbates/goth * Twitch * Twitter * Uber +* VK * Wepay +* Xero * Yahoo * Yammer @@ -71,17 +81,51 @@ $ go get github.com/markbates/goth ```text $ cd goth/examples $ go get -v -$ go build +$ go build $ ./examples ``` Now open up your browser and go to [http://localhost:3000](http://localhost:3000) to see the example. -To actually use the different providers, please make sure you configure them given the system environments as defined in the examples/main.go file +To actually use the different providers, please make sure you set environment variables. Example given in the examples/main.go file + +## Security Notes + +By default, gothic uses a `CookieStore` from the `gorilla/sessions` package to store session data. + +As configured, this default store (`gothic.Store`) will generate cookies with `Options`: + +```go +&Options{ + Path: "/", + Domain: "", + MaxAge: 86400 * 30, + HttpOnly: true, + Secure: false, + } +``` + +To tailor these fields for your application, you can override the `gothic.Store` variable at startup. + +The follow snippet show one way to do this: + +```go +key := "" // Replace with your SESSION_SECRET or similar +maxAge := 86400 * 30 // 30 days +isProd := false // Set to true when serving over https + +store := sessions.NewCookieStore([]byte(key)) +store.MaxAge(maxAge) +store.Options.Path = "/" +store.Options.HttpOnly = true // HttpOnly should always be enabled +store.Options.Secure = isProd + +gothic.Store = store +``` ## Issues -Issues always stand a significantly better chance of getting fixed if the are accompanied by a +Issues always stand a significantly better chance of getting fixed if they are accompanied by a pull request. ## Contributing @@ -94,50 +138,3 @@ Would I love to see more providers? Certainly! Would you love to contribute one? 4. Commit your changes (git commit -am 'Add some feature') 5. Push to the branch (git push origin my-new-feature) 6. Create new Pull Request - -## Contributors - -* Mark Bates -* Tyler Bunnell -* Corey McGrillis -* willemvd -* Rakesh Goyal -* Andy Grunwald -* Glenn Walker -* Kevin Fitzpatrick -* Ben Tranter -* Sharad Ganapathy -* Andrew Chilton -* sharadgana -* Aurorae -* Craig P Jolicoeur -* Zac Bergquist -* Geoff Franks -* Raphael Geronimi -* Noah Shibley -* lumost -* oov -* Felix Lamouroux -* Rafael Quintela -* Tyler -* DenSm -* Samy KACIMI -* dante gray -* Noah -* Jacob Walker -* Marin Martinic -* Roy -* Omni Adams -* Sasa Brankovic -* dkhamsing -* Dante Swift -* Attila Domokos -* Albin Gilles -* Syed Zubairuddin -* Johnny Boursiquot -* Jerome Touffe-Blin -* bryanl -* Masanobu YOSHIOKA -* Jonathan Hall -* HaiMing.Yin -* Sairam Kunala diff --git a/vendor/github.com/markbates/goth/gothic/gothic.go b/vendor/github.com/markbates/goth/gothic/gothic.go index f6aaf2d11..8b8e11494 100644 --- a/vendor/github.com/markbates/goth/gothic/gothic.go +++ b/vendor/github.com/markbates/goth/gothic/gothic.go @@ -8,10 +8,18 @@ See https://github.com/markbates/goth/examples/main.go to see this in action. package gothic import ( + "bytes" + "compress/gzip" + "encoding/base64" "errors" "fmt" + "io/ioutil" + "math/rand" "net/http" + "net/url" "os" + "strings" + "time" "github.com/gorilla/mux" "github.com/gorilla/sessions" @@ -27,15 +35,21 @@ var defaultStore sessions.Store var keySet = false +var gothicRand *rand.Rand + func init() { key := []byte(os.Getenv("SESSION_SECRET")) keySet = len(key) != 0 - Store = sessions.NewCookieStore([]byte(key)) + + cookieStore := sessions.NewCookieStore([]byte(key)) + cookieStore.Options.HttpOnly = true + Store = cookieStore defaultStore = Store + gothicRand = rand.New(rand.NewSource(time.Now().UnixNano())) } /* -BeginAuthHandler is a convienence handler for starting the authentication process. +BeginAuthHandler is a convenience handler for starting the authentication process. It expects to be able to get the name of the provider from the query parameters as either "provider" or ":provider". @@ -65,8 +79,16 @@ var SetState = func(req *http.Request) string { return state } - return "state" - + // If a state query param is not passed in, generate a random + // base64-encoded nonce so that the state on the auth URL + // is unguessable, preventing CSRF attacks, as described in + // + // https://auth0.com/docs/protocols/oauth2/oauth-state#keep-reading + nonceBytes := make([]byte, 64) + for i := 0; i < 64; i++ { + nonceBytes[i] = byte(gothicRand.Int63() % 256) + } + return base64.URLEncoding.EncodeToString(nonceBytes) } // GetState gets the state returned by the provider during the callback. @@ -87,7 +109,6 @@ I would recommend using the BeginAuthHandler instead of doing all of these steps yourself, but that's entirely up to you. */ func GetAuthURL(res http.ResponseWriter, req *http.Request) (string, error) { - if !keySet && defaultStore == Store { fmt.Println("goth/gothic: no SESSION_SECRET environment variable is set. The default cookie store is not available and any calls will fail. Ignore this warning if you are using a different store.") } @@ -130,7 +151,7 @@ as either "provider" or ":provider". See https://github.com/markbates/goth/examples/main.go to see this in action. */ var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.User, error) { - + defer Logout(res, req) if !keySet && defaultStore == Store { fmt.Println("goth/gothic: no SESSION_SECRET environment variable is set. The default cookie store is not available and any calls will fail. Ignore this warning if you are using a different store.") } @@ -155,6 +176,11 @@ var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.Us return goth.User{}, err } + err = validateState(req, sess) + if err != nil { + return goth.User{}, err + } + user, err := provider.FetchUser(sess) if err == nil { // user can be found with existing session data @@ -173,7 +199,43 @@ var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.Us return goth.User{}, err } - return provider.FetchUser(sess) + gu, err := provider.FetchUser(sess) + return gu, err +} + +// validateState ensures that the state token param from the original +// AuthURL matches the one included in the current (callback) request. +func validateState(req *http.Request, sess goth.Session) error { + rawAuthURL, err := sess.GetAuthURL() + if err != nil { + return err + } + + authURL, err := url.Parse(rawAuthURL) + if err != nil { + return err + } + + originalState := authURL.Query().Get("state") + if originalState != "" && (originalState != req.URL.Query().Get("state")) { + return errors.New("state token mismatch") + } + return nil +} + +// Logout invalidates a user session. +func Logout(res http.ResponseWriter, req *http.Request) error { + session, err := Store.Get(req, SessionName) + if err != nil { + return err + } + session.Options.MaxAge = -1 + session.Values = make(map[interface{}]interface{}) + err = session.Save(req, res) + if err != nil { + return errors.New("Could not delete user session ") + } + return nil } // GetProviderName is a function used to get the name of a provider @@ -184,36 +246,96 @@ var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.Us var GetProviderName = getProviderName func getProviderName(req *http.Request) (string, error) { - provider := req.URL.Query().Get("provider") - if provider == "" { - if p, ok := mux.Vars(req)["provider"]; ok { + + // get all the used providers + providers := goth.GetProviders() + + // loop over the used providers, if we already have a valid session for any provider (ie. user is already logged-in with a provider), then return that provider name + for _, provider := range providers { + p := provider.Name() + session, _ := Store.Get(req, p+SessionName) + value := session.Values[p] + if _, ok := value.(string); ok { return p, nil } } - if provider == "" { - provider = req.URL.Query().Get(":provider") + + // try to get it from the url param "provider" + if p := req.URL.Query().Get("provider"); p != "" { + return p, nil } - if provider == "" { - return provider, errors.New("you must select a provider") + + // try to get it from the url param ":provider" + if p := req.URL.Query().Get(":provider"); p != "" { + return p, nil } - return provider, nil + + // try to get it from the context's value of "provider" key + if p, ok := mux.Vars(req)["provider"]; ok { + return p, nil + } + + // try to get it from the go-context's value of "provider" key + if p, ok := req.Context().Value("provider").(string); ok { + return p, nil + } + + // if not found then return an empty string with the corresponding error + return "", errors.New("you must select a provider") } func storeInSession(key string, value string, req *http.Request, res http.ResponseWriter) error { - session, _ := Store.Get(req, key + SessionName) + session, _ := Store.Get(req, SessionName) - session.Values[key] = value + if err := updateSessionValue(session, key, value); err != nil { + return err + } return session.Save(req, res) } func getFromSession(key string, req *http.Request) (string, error) { - session, _ := Store.Get(req, key + SessionName) - - value := session.Values[key] - if value == nil { + session, _ := Store.Get(req, SessionName) + value, err := getSessionValue(session, key) + if err != nil { return "", errors.New("could not find a matching session for this request") } - return value.(string), nil -} \ No newline at end of file + return value, nil +} + +func getSessionValue(session *sessions.Session, key string) (string, error) { + value := session.Values[key] + if value == nil { + return "", fmt.Errorf("could not find a matching session for this request") + } + + rdata := strings.NewReader(value.(string)) + r, err := gzip.NewReader(rdata) + if err != nil { + return "", err + } + s, err := ioutil.ReadAll(r) + if err != nil { + return "", err + } + + return string(s), nil +} + +func updateSessionValue(session *sessions.Session, key, value string) error { + var b bytes.Buffer + gz := gzip.NewWriter(&b) + if _, err := gz.Write([]byte(value)); err != nil { + return err + } + if err := gz.Flush(); err != nil { + return err + } + if err := gz.Close(); err != nil { + return err + } + + session.Values[key] = b.String() + return nil +} diff --git a/vendor/github.com/markbates/goth/providers/bitbucket/bitbucket.go b/vendor/github.com/markbates/goth/providers/bitbucket/bitbucket.go index 06d9c923c..c19734770 100644 --- a/vendor/github.com/markbates/goth/providers/bitbucket/bitbucket.go +++ b/vendor/github.com/markbates/goth/providers/bitbucket/bitbucket.go @@ -9,9 +9,9 @@ import ( "net/http" "net/url" + "fmt" "github.com/markbates/goth" "golang.org/x/oauth2" - "fmt" ) const ( @@ -26,10 +26,10 @@ const ( // one manually. func New(clientKey, secret, callbackURL string, scopes ...string) *Provider { p := &Provider{ - ClientKey: clientKey, - Secret: secret, - CallbackURL: callbackURL, - providerName: "bitbucket", + ClientKey: clientKey, + Secret: secret, + CallbackURL: callbackURL, + providerName: "bitbucket", } p.config = newConfig(p, scopes) return p @@ -125,7 +125,7 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { func userFromReader(reader io.Reader, user *goth.User) error { u := struct { - ID string `json:"uuid"` + ID string `json:"uuid"` Links struct { Avatar struct { URL string `json:"href"` diff --git a/vendor/github.com/markbates/goth/providers/dropbox/dropbox.go b/vendor/github.com/markbates/goth/providers/dropbox/dropbox.go index 61533d405..262905806 100644 --- a/vendor/github.com/markbates/goth/providers/dropbox/dropbox.go +++ b/vendor/github.com/markbates/goth/providers/dropbox/dropbox.go @@ -8,15 +8,16 @@ import ( "net/http" "strings" + "fmt" + "github.com/markbates/goth" "golang.org/x/oauth2" - "fmt" ) const ( - authURL = "https://www.dropbox.com/1/oauth2/authorize" - tokenURL = "https://api.dropbox.com/1/oauth2/token" - accountURL = "https://api.dropbox.com/1/account/info" + authURL = "https://www.dropbox.com/oauth2/authorize" + tokenURL = "https://api.dropbox.com/oauth2/token" + accountURL = "https://api.dropbox.com/2/users/get_current_account" ) // Provider is the implementation of `goth.Provider` for accessing Dropbox. @@ -40,10 +41,10 @@ type Session struct { // create one manually. func New(clientKey, secret, callbackURL string, scopes ...string) *Provider { p := &Provider{ - ClientKey: clientKey, - Secret: secret, - CallbackURL: callbackURL, - providerName: "dropbox", + ClientKey: clientKey, + Secret: secret, + CallbackURL: callbackURL, + providerName: "dropbox", } p.config = newConfig(p, scopes) return p @@ -86,7 +87,7 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName) } - req, err := http.NewRequest("GET", accountURL, nil) + req, err := http.NewRequest("POST", accountURL, nil) if err != nil { return user, err } @@ -161,7 +162,7 @@ func newConfig(p *Provider, scopes []string) *oauth2.Config { func userFromReader(r io.Reader, user *goth.User) error { u := struct { - Name string `json:"display_name"` + Name string `json:"display_name"` NameDetails struct { NickName string `json:"familiar_name"` } `json:"name_details"` diff --git a/vendor/github.com/markbates/goth/providers/facebook/facebook.go b/vendor/github.com/markbates/goth/providers/facebook/facebook.go index e0cfdf1e3..266bbe220 100644 --- a/vendor/github.com/markbates/goth/providers/facebook/facebook.go +++ b/vendor/github.com/markbates/goth/providers/facebook/facebook.go @@ -11,12 +11,12 @@ import ( "net/http" "net/url" - "github.com/markbates/goth" - "golang.org/x/oauth2" - "fmt" "crypto/hmac" "crypto/sha256" "encoding/hex" + "fmt" + "github.com/markbates/goth" + "golang.org/x/oauth2" ) const ( @@ -30,10 +30,10 @@ const ( // one manually. func New(clientKey, secret, callbackURL string, scopes ...string) *Provider { p := &Provider{ - ClientKey: clientKey, - Secret: secret, - CallbackURL: callbackURL, - providerName: "facebook", + ClientKey: clientKey, + Secret: secret, + CallbackURL: callbackURL, + providerName: "facebook", } p.config = newConfig(p, scopes) return p @@ -129,7 +129,7 @@ func userFromReader(reader io.Reader, user *goth.User) error { FirstName string `json:"first_name"` LastName string `json:"last_name"` Link string `json:"link"` - Picture struct { + Picture struct { Data struct { URL string `json:"url"` } `json:"data"` diff --git a/vendor/github.com/markbates/goth/providers/gitlab/gitlab.go b/vendor/github.com/markbates/goth/providers/gitlab/gitlab.go index fe188c01a..533632e7f 100644 --- a/vendor/github.com/markbates/goth/providers/gitlab/gitlab.go +++ b/vendor/github.com/markbates/goth/providers/gitlab/gitlab.go @@ -11,9 +11,9 @@ import ( "net/url" "strconv" + "fmt" "github.com/markbates/goth" "golang.org/x/oauth2" - "fmt" ) // These vars define the Authentication, Token, and Profile URLS for Gitlab. If diff --git a/vendor/github.com/markbates/goth/providers/gplus/gplus.go b/vendor/github.com/markbates/goth/providers/gplus/gplus.go index 06655c2f7..4726aa349 100644 --- a/vendor/github.com/markbates/goth/providers/gplus/gplus.go +++ b/vendor/github.com/markbates/goth/providers/gplus/gplus.go @@ -11,9 +11,9 @@ import ( "net/url" "strings" + "fmt" "github.com/markbates/goth" "golang.org/x/oauth2" - "fmt" ) const ( @@ -27,10 +27,10 @@ const ( // one manually. func New(clientKey, secret, callbackURL string, scopes ...string) *Provider { p := &Provider{ - ClientKey: clientKey, - Secret: secret, - CallbackURL: callbackURL, - providerName: "gplus", + ClientKey: clientKey, + Secret: secret, + CallbackURL: callbackURL, + providerName: "gplus", } p.config = newConfig(p, scopes) return p diff --git a/vendor/github.com/markbates/goth/providers/openidConnect/openidConnect.go b/vendor/github.com/markbates/goth/providers/openidConnect/openidConnect.go index 7ffd11c60..44419ba15 100644 --- a/vendor/github.com/markbates/goth/providers/openidConnect/openidConnect.go +++ b/vendor/github.com/markbates/goth/providers/openidConnect/openidConnect.go @@ -1,17 +1,17 @@ package openidConnect import ( + "bytes" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "github.com/markbates/goth" + "golang.org/x/oauth2" + "io/ioutil" "net/http" "strings" - "fmt" - "encoding/json" - "encoding/base64" - "io/ioutil" - "errors" - "golang.org/x/oauth2" - "github.com/markbates/goth" "time" - "bytes" ) const ( @@ -89,14 +89,14 @@ func New(clientKey, secret, callbackURL, openIDAutoDiscoveryURL string, scopes . Secret: secret, CallbackURL: callbackURL, - UserIdClaims: []string{subjectClaim}, - NameClaims: []string{NameClaim}, - NickNameClaims: []string{NicknameClaim, PreferredUsernameClaim}, - EmailClaims: []string{EmailClaim}, - AvatarURLClaims:[]string{PictureClaim}, - FirstNameClaims:[]string{GivenNameClaim}, - LastNameClaims: []string{FamilyNameClaim}, - LocationClaims: []string{AddressClaim}, + UserIdClaims: []string{subjectClaim}, + NameClaims: []string{NameClaim}, + NickNameClaims: []string{NicknameClaim, PreferredUsernameClaim}, + EmailClaims: []string{EmailClaim}, + AvatarURLClaims: []string{PictureClaim}, + FirstNameClaims: []string{GivenNameClaim}, + LastNameClaims: []string{FamilyNameClaim}, + LocationClaims: []string{AddressClaim}, providerName: "openid-connect", } diff --git a/vendor/github.com/markbates/goth/providers/openidConnect/session.go b/vendor/github.com/markbates/goth/providers/openidConnect/session.go index a34584fde..d223cf875 100644 --- a/vendor/github.com/markbates/goth/providers/openidConnect/session.go +++ b/vendor/github.com/markbates/goth/providers/openidConnect/session.go @@ -1,12 +1,12 @@ package openidConnect import ( + "encoding/json" "errors" "github.com/markbates/goth" - "encoding/json" + "golang.org/x/oauth2" "strings" "time" - "golang.org/x/oauth2" ) // Session stores data during the auth process with the OpenID Connect provider. diff --git a/vendor/github.com/markbates/goth/providers/twitter/twitter.go b/vendor/github.com/markbates/goth/providers/twitter/twitter.go index 3703f2197..2ce20e780 100644 --- a/vendor/github.com/markbates/goth/providers/twitter/twitter.go +++ b/vendor/github.com/markbates/goth/providers/twitter/twitter.go @@ -9,10 +9,11 @@ import ( "io/ioutil" "net/http" + "fmt" + "github.com/markbates/goth" "github.com/mrjones/oauth" "golang.org/x/oauth2" - "fmt" ) var ( @@ -30,10 +31,10 @@ var ( // If you'd like to use authenticate instead of authorize, use NewAuthenticate instead. func New(clientKey, secret, callbackURL string) *Provider { p := &Provider{ - ClientKey: clientKey, - Secret: secret, - CallbackURL: callbackURL, - providerName: "twitter", + ClientKey: clientKey, + Secret: secret, + CallbackURL: callbackURL, + providerName: "twitter", } p.consumer = newConsumer(p, authorizeURL) return p @@ -43,10 +44,10 @@ func New(clientKey, secret, callbackURL string) *Provider { // NewAuthenticate uses the authenticate URL instead of the authorize URL. func NewAuthenticate(clientKey, secret, callbackURL string) *Provider { p := &Provider{ - ClientKey: clientKey, - Secret: secret, - CallbackURL: callbackURL, - providerName: "twitter", + ClientKey: clientKey, + Secret: secret, + CallbackURL: callbackURL, + providerName: "twitter", } p.consumer = newConsumer(p, authenticateURL) return p @@ -107,7 +108,7 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { response, err := p.consumer.Get( endpointProfile, - map[string]string{"include_entities": "false", "skip_status": "true"}, + map[string]string{"include_entities": "false", "skip_status": "true", "include_email": "true"}, sess.AccessToken) if err != nil { return user, err @@ -126,6 +127,9 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { user.Name = user.RawData["name"].(string) user.NickName = user.RawData["screen_name"].(string) + if user.RawData["email"] != nil { + user.Email = user.RawData["email"].(string) + } user.Description = user.RawData["description"].(string) user.AvatarURL = user.RawData["profile_image_url"].(string) user.UserID = user.RawData["id_str"].(string) diff --git a/vendor/vendor.json b/vendor/vendor.json index 7397cac40..c6a10a585 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -666,64 +666,64 @@ "revisionTime": "2017-10-25T03:15:54Z" }, { - "checksumSHA1": "O3KUfEXQPfdQ+tCMpP2RAIRJJqY=", + "checksumSHA1": "q9MD1ienC+kmKq5i51oAktQEV1E=", "path": "github.com/markbates/goth", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { - "checksumSHA1": "MkFKwLV3icyUo4oP0BgEs+7+R1Y=", + "checksumSHA1": "+nosptSgGb2qCAR6CSHV2avwmNg=", "path": "github.com/markbates/goth/gothic", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { - "checksumSHA1": "crNSlQADjX6hcxykON2tFCqY4iw=", + "checksumSHA1": "pJ+Cws/TU22K6tZ/ALFOvvH1K5U=", "path": "github.com/markbates/goth/providers/bitbucket", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { - "checksumSHA1": "1Kp4DKkJNVn135Xg8H4a6CFBNy8=", + "checksumSHA1": "bKokLof0Pkk5nEhW8NdbfcVzuqk=", "path": "github.com/markbates/goth/providers/dropbox", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { - "checksumSHA1": "cGs1da29iOBJh5EAH0icKDbN8CA=", + "checksumSHA1": "VzbroIA9R00Ig3iGnOlZLU7d4ls=", "path": "github.com/markbates/goth/providers/facebook", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { "checksumSHA1": "P6nBZ850aaekpOcoXNdRhK86bH8=", "path": "github.com/markbates/goth/providers/github", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { - "checksumSHA1": "o/109paSRy9HqV87gR4zUZMMSzs=", + "checksumSHA1": "ld488t+yGoTwtmiCSSggEX4fxVk=", "path": "github.com/markbates/goth/providers/gitlab", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { - "checksumSHA1": "cX6kR9y94BWFZvI/7UFrsFsP3FQ=", + "checksumSHA1": "qXEulD7vnwY9hFrxh91Pm5YrvTM=", "path": "github.com/markbates/goth/providers/gplus", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { - "checksumSHA1": "sMYKhqAUZXM1+T/TjlMhWh8Vveo=", + "checksumSHA1": "wsOBzyp4LKDhfCPmX1LLP7T0S3U=", "path": "github.com/markbates/goth/providers/openidConnect", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { - "checksumSHA1": "1w0V6jYXaGlEtZcMeYTOAAucvgw=", + "checksumSHA1": "o6RqMbbE8QNZhNT9TsAIRMPI8tg=", "path": "github.com/markbates/goth/providers/twitter", - "revision": "90362394a367f9d77730911973462a53d69662ba", - "revisionTime": "2017-02-23T14:12:10Z" + "revision": "bc7deaf077a50416cf3a23aa5903d2a7b5a30ada", + "revisionTime": "2018-02-15T02:27:40Z" }, { "checksumSHA1": "61HNjGetaBoMp8HBOpuEZRSim8g=", From 7b104f0cd03cf3df2b10f6f447857fe389654df1 Mon Sep 17 00:00:00 2001 From: Ethan Koenig Date: Tue, 20 Feb 2018 04:50:42 -0800 Subject: [PATCH 023/106] Populate URL field of API commits (#3546) * Populate URL field of API commits * fix orgmode_test --- modules/markup/html.go | 36 ++++++------------ modules/markup/html_test.go | 48 ++++++------------------ modules/markup/markdown/markdown.go | 9 +++-- modules/markup/markdown/markdown_test.go | 29 +++++++------- modules/markup/orgmode/orgmode_test.go | 6 +-- modules/util/util.go | 21 +++++++++++ modules/util/util_test.go | 36 ++++++++++++++++++ routers/api/v1/convert/convert.go | 23 ++++++++---- routers/api/v1/misc/markdown.go | 4 +- routers/api/v1/misc/markdown_test.go | 8 ++-- routers/api/v1/repo/branch.go | 4 +- 11 files changed, 126 insertions(+), 98 deletions(-) create mode 100644 modules/util/util_test.go diff --git a/modules/markup/html.go b/modules/markup/html.go index 772c521ea..e29cbe445 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -15,8 +15,8 @@ import ( "strings" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/Unknwon/com" "golang.org/x/net/html" @@ -112,20 +112,6 @@ func cutoutVerbosePrefix(prefix string) string { return prefix } -// URLJoin joins url components, like path.Join, but preserving contents -func URLJoin(base string, elems ...string) string { - u, err := url.Parse(base) - if err != nil { - log.Error(4, "URLJoin: Invalid base URL %s", base) - return "" - } - joinArgs := make([]string, 0, len(elems)+1) - joinArgs = append(joinArgs, u.Path) - joinArgs = append(joinArgs, elems...) - u.Path = path.Join(joinArgs...) - return u.String() -} - // RenderIssueIndexPatternOptions options for RenderIssueIndexPattern function type RenderIssueIndexPatternOptions struct { // url to which non-special formatting should be linked. If empty, @@ -177,7 +163,7 @@ func RenderIssueIndexPattern(rawBytes []byte, opts RenderIssueIndexPatternOption } if opts.Metas == nil { buf.WriteString(``) buf.Write(remainder[startIndex:endIndex]) @@ -228,7 +214,7 @@ func renderFullSha1Pattern(rawBytes []byte, urlPrefix string) []byte { path := protocol + "://" + paths author := string(m[3]) repoName := string(m[4]) - path = URLJoin(path, author, repoName) + path = util.URLJoin(path, author, repoName) ltype := "src" itemType := m[5] if IsSameDomain(paths) { @@ -260,7 +246,7 @@ func renderFullSha1Pattern(rawBytes []byte, urlPrefix string) []byte { text += ")" } rawBytes = bytes.Replace(rawBytes, all, []byte(fmt.Sprintf( - `%s`, URLJoin(path, ltype, string(sha))+urlSuffix, text)), -1) + `%s`, util.URLJoin(path, ltype, string(sha))+urlSuffix, text)), -1) } return rawBytes } @@ -399,9 +385,9 @@ func RenderShortLinks(rawBytes []byte, urlPrefix string, noLink bool, isWikiMark urlPrefix = strings.Replace(urlPrefix, "/src/", "/raw/", 1) } if isWikiMarkdown { - link = URLJoin("wiki", "raw", link) + link = util.URLJoin("wiki", "raw", link) } - link = URLJoin(urlPrefix, link) + link = util.URLJoin(urlPrefix, link) } title := props["title"] if title == "" { @@ -420,9 +406,9 @@ func RenderShortLinks(rawBytes []byte, urlPrefix string, noLink bool, isWikiMark name = fmt.Sprintf(``, link, alt, title) } else if !absoluteLink { if isWikiMarkdown { - link = URLJoin("wiki", link) + link = util.URLJoin("wiki", link) } - link = URLJoin(urlPrefix, link) + link = util.URLJoin(urlPrefix, link) } if noLink { rawBytes = bytes.Replace(rawBytes, orig, []byte(name), -1) @@ -445,7 +431,7 @@ func RenderCrossReferenceIssueIndexPattern(rawBytes []byte, urlPrefix string, me repo := string(bytes.Split(m, []byte("#"))[0]) issue := string(bytes.Split(m, []byte("#"))[1]) - link := fmt.Sprintf(`%s`, URLJoin(setting.AppURL, repo, "issues", issue), m) + link := fmt.Sprintf(`%s`, util.URLJoin(setting.AppURL, repo, "issues", issue), m) rawBytes = bytes.Replace(rawBytes, m, []byte(link), 1) } return rawBytes @@ -463,7 +449,7 @@ func renderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte { // Although unlikely, deadbeef and 1234567 are valid short forms of SHA1 hash // as used by git and github for linking and thus we have to do similar. rawBytes = bytes.Replace(rawBytes, hash, []byte(fmt.Sprintf( - `%s`, URLJoin(urlPrefix, "commit", string(hash)), base.ShortSha(string(hash)))), -1) + `%s`, util.URLJoin(urlPrefix, "commit", string(hash)), base.ShortSha(string(hash)))), -1) } return rawBytes } @@ -474,7 +460,7 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string, metas map[string]strin for _, m := range ms { m = m[bytes.Index(m, []byte("@")):] rawBytes = bytes.Replace(rawBytes, m, - []byte(fmt.Sprintf(`%s`, URLJoin(setting.AppURL, string(m[1:])), m)), -1) + []byte(fmt.Sprintf(`%s`, util.URLJoin(setting.AppURL, string(m[1:])), m)), -1) } rawBytes = RenderFullIssuePattern(rawBytes) diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 4e47b47b0..92f815ad9 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -13,6 +13,7 @@ import ( . "code.gitea.io/gitea/modules/markup" _ "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" ) @@ -37,12 +38,12 @@ var alphanumericMetas = map[string]string{ // numericLink an HTML to a numeric-style issue func numericIssueLink(baseURL string, index int) string { - return link(URLJoin(baseURL, strconv.Itoa(index)), fmt.Sprintf("#%d", index)) + return link(util.URLJoin(baseURL, strconv.Itoa(index)), fmt.Sprintf("#%d", index)) } // alphanumLink an HTML link to an alphanumeric-style issue func alphanumIssueLink(baseURL string, name string) string { - return link(URLJoin(baseURL, name), name) + return link(util.URLJoin(baseURL, name), name) } // urlContentsLink an HTML link whose contents is the target URL @@ -63,31 +64,6 @@ func testRenderIssueIndexPattern(t *testing.T, input, expected string, opts Rend assert.Equal(t, expected, actual) } -func TestURLJoin(t *testing.T) { - type test struct { - Expected string - Base string - Elements []string - } - newTest := func(expected, base string, elements ...string) test { - return test{Expected: expected, Base: base, Elements: elements} - } - for _, test := range []test{ - newTest("https://try.gitea.io/a/b/c", - "https://try.gitea.io", "a/b", "c"), - newTest("https://try.gitea.io/a/b/c", - "https://try.gitea.io/", "/a/b/", "/c/"), - newTest("https://try.gitea.io/a/c", - "https://try.gitea.io/", "/a/./b/", "../c/"), - newTest("a/b/c", - "a", "b/c/"), - newTest("a/b/d", - "a/", "b/c/", "/../d/"), - } { - assert.Equal(t, test.Expected, URLJoin(test.Base, test.Elements...)) - } -} - func TestRender_IssueIndexPattern(t *testing.T) { // numeric: render inputs without valid mentions test := func(s string) { @@ -123,7 +99,7 @@ func TestRender_IssueIndexPattern2(t *testing.T) { test := func(s, expectedFmt string, indices ...int) { links := make([]interface{}, len(indices)) for i, index := range indices { - links[i] = numericIssueLink(URLJoin(setting.AppSubURL, "issues"), index) + links[i] = numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), index) } expectedNil := fmt.Sprintf(expectedFmt, links...) testRenderIssueIndexPattern(t, s, expectedNil, RenderIssueIndexPatternOptions{}) @@ -228,8 +204,8 @@ func TestRender_AutoLink(t *testing.T) { } // render valid issue URLs - test(URLJoin(setting.AppSubURL, "issues", "3333"), - numericIssueLink(URLJoin(setting.AppSubURL, "issues"), 3333)) + test(util.URLJoin(setting.AppSubURL, "issues", "3333"), + numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), 3333)) // render external issue URLs for _, externalURL := range []string{ @@ -240,7 +216,7 @@ func TestRender_AutoLink(t *testing.T) { } // render valid commit URLs - tmp := URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae") + tmp := util.URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae") test(tmp, "d8a994ef24") tmp += "#diff-2" test(tmp, "d8a994ef24 (diff-2)") @@ -260,8 +236,8 @@ func TestRender_Commits(t *testing.T) { } var sha = "b6dd6210eaebc915fd5be5579c58cce4da2e2579" - var commit = URLJoin(AppSubURL, "commit", sha) - var subtree = URLJoin(commit, "src") + var commit = util.URLJoin(AppSubURL, "commit", sha) + var subtree = util.URLJoin(commit, "src") var tree = strings.Replace(subtree, "/commit/", "/tree/", -1) var src = strings.Replace(subtree, "/commit/", "/src/", -1) @@ -284,10 +260,10 @@ func TestRender_CrossReferences(t *testing.T) { test( "gogits/gogs#12345", - `

gogits/gogs#12345

`) + `

gogits/gogs#12345

`) test( "go-gitea/gitea#12345", - `

go-gitea/gitea#12345

`) + `

go-gitea/gitea#12345

`) } func TestRender_FullIssueURLs(t *testing.T) { @@ -482,7 +458,7 @@ func TestMisc_IsSameDomain(t *testing.T) { setting.AppSubURL = AppSubURL var sha = "b6dd6210eaebc915fd5be5579c58cce4da2e2579" - var commit = URLJoin(AppSubURL, "commit", sha) + var commit = util.URLJoin(AppSubURL, "commit", sha) assert.True(t, IsSameDomain(commit)) assert.False(t, IsSameDomain("http://google.com/ncr")) diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index f0ed0e03a..2e3d180c4 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/russross/blackfriday" ) @@ -27,9 +28,9 @@ func (r *Renderer) Link(out *bytes.Buffer, link []byte, title []byte, content [] if link[0] != '#' { lnk := string(link) if r.IsWiki { - lnk = markup.URLJoin("wiki", lnk) + lnk = util.URLJoin("wiki", lnk) } - mLink := markup.URLJoin(r.URLPrefix, lnk) + mLink := util.URLJoin(r.URLPrefix, lnk) link = []byte(mLink) } } @@ -97,7 +98,7 @@ var ( func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { prefix := r.URLPrefix if r.IsWiki { - prefix = markup.URLJoin(prefix, "wiki", "src") + prefix = util.URLJoin(prefix, "wiki", "src") } prefix = strings.Replace(prefix, "/src/", "/raw/", 1) if len(link) > 0 { @@ -110,7 +111,7 @@ func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byt } } else { lnk := string(link) - lnk = markup.URLJoin(prefix, lnk) + lnk = util.URLJoin(prefix, lnk) lnk = strings.Replace(lnk, " ", "+", -1) link = []byte(lnk) } diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 9ca3de01c..c19037f62 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/markup" . "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" ) @@ -33,8 +34,8 @@ func TestRender_StandardLinks(t *testing.T) { googleRendered := `

https://google.com/

` test("", googleRendered, googleRendered) - lnk := markup.URLJoin(AppSubURL, "WikiPage") - lnkWiki := markup.URLJoin(AppSubURL, "wiki", "WikiPage") + lnk := util.URLJoin(AppSubURL, "WikiPage") + lnkWiki := util.URLJoin(AppSubURL, "wiki", "WikiPage") test("[WikiPage](WikiPage)", `

WikiPage

`, `

WikiPage

`) @@ -43,7 +44,7 @@ func TestRender_StandardLinks(t *testing.T) { func TestRender_ShortLinks(t *testing.T) { setting.AppURL = AppURL setting.AppSubURL = AppSubURL - tree := markup.URLJoin(AppSubURL, "src", "master") + tree := util.URLJoin(AppSubURL, "src", "master") test := func(input, expected, expectedWiki string) { buffer := RenderString(input, tree, nil) @@ -52,13 +53,13 @@ func TestRender_ShortLinks(t *testing.T) { assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) } - rawtree := markup.URLJoin(AppSubURL, "raw", "master") - url := markup.URLJoin(tree, "Link") - otherUrl := markup.URLJoin(tree, "OtherLink") - imgurl := markup.URLJoin(rawtree, "Link.jpg") - urlWiki := markup.URLJoin(AppSubURL, "wiki", "Link") - otherUrlWiki := markup.URLJoin(AppSubURL, "wiki", "OtherLink") - imgurlWiki := markup.URLJoin(AppSubURL, "wiki", "raw", "Link.jpg") + rawtree := util.URLJoin(AppSubURL, "raw", "master") + url := util.URLJoin(tree, "Link") + otherUrl := util.URLJoin(tree, "OtherLink") + imgurl := util.URLJoin(rawtree, "Link.jpg") + urlWiki := util.URLJoin(AppSubURL, "wiki", "Link") + otherUrlWiki := util.URLJoin(AppSubURL, "wiki", "OtherLink") + imgurlWiki := util.URLJoin(AppSubURL, "wiki", "raw", "Link.jpg") favicon := "http://google.com/favicon.ico" test( @@ -136,7 +137,7 @@ func TestRender_Images(t *testing.T) { url := "../../.images/src/02/train.jpg" title := "Train" - result := markup.URLJoin(AppSubURL, url) + result := util.URLJoin(AppSubURL, url) test( "!["+title+"]("+url+")", @@ -259,7 +260,7 @@ Here are some links to the most important topics. You can find the full list of } func TestTotal_RenderWiki(t *testing.T) { - answers := testAnswers(markup.URLJoin(AppSubURL, "wiki/"), markup.URLJoin(AppSubURL, "wiki", "raw/")) + answers := testAnswers(util.URLJoin(AppSubURL, "wiki/"), util.URLJoin(AppSubURL, "wiki", "raw/")) for i := 0; i < len(sameCases); i++ { line := RenderWiki([]byte(sameCases[i]), AppSubURL, nil) @@ -286,10 +287,10 @@ func TestTotal_RenderWiki(t *testing.T) { } func TestTotal_RenderString(t *testing.T) { - answers := testAnswers(markup.URLJoin(AppSubURL, "src", "master/"), markup.URLJoin(AppSubURL, "raw", "master/")) + answers := testAnswers(util.URLJoin(AppSubURL, "src", "master/"), util.URLJoin(AppSubURL, "raw", "master/")) for i := 0; i < len(sameCases); i++ { - line := RenderString(sameCases[i], markup.URLJoin(AppSubURL, "src", "master/"), nil) + line := RenderString(sameCases[i], util.URLJoin(AppSubURL, "src", "master/"), nil) assert.Equal(t, answers[i], line) } diff --git a/modules/markup/orgmode/orgmode_test.go b/modules/markup/orgmode/orgmode_test.go index a68ab5d3a..3846922c2 100644 --- a/modules/markup/orgmode/orgmode_test.go +++ b/modules/markup/orgmode/orgmode_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" ) @@ -30,7 +30,7 @@ func TestRender_StandardLinks(t *testing.T) { googleRendered := `

https://google.com/

` test("[[https://google.com/]]", googleRendered) - lnk := markup.URLJoin(AppSubURL, "WikiPage") + lnk := util.URLJoin(AppSubURL, "WikiPage") test("[[WikiPage][WikiPage]]", `

WikiPage

`) } @@ -46,7 +46,7 @@ func TestRender_Images(t *testing.T) { url := "../../.images/src/02/train.jpg" title := "Train" - result := markup.URLJoin(AppSubURL, url) + result := util.URLJoin(AppSubURL, url) test( "[[file:"+url+"]["+title+"]]", diff --git a/modules/util/util.go b/modules/util/util.go index e99f951f2..3a0411f64 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -4,6 +4,13 @@ package util +import ( + "net/url" + "path" + + "code.gitea.io/gitea/modules/log" +) + // OptionalBool a boolean that can be "null" type OptionalBool byte @@ -47,6 +54,20 @@ func Max(a, b int) int { return a } +// URLJoin joins url components, like path.Join, but preserving contents +func URLJoin(base string, elems ...string) string { + u, err := url.Parse(base) + if err != nil { + log.Error(4, "URLJoin: Invalid base URL %s", base) + return "" + } + joinArgs := make([]string, 0, len(elems)+1) + joinArgs = append(joinArgs, u.Path) + joinArgs = append(joinArgs, elems...) + u.Path = path.Join(joinArgs...) + return u.String() +} + // Min min of two ints func Min(a, b int) int { if a > b { diff --git a/modules/util/util_test.go b/modules/util/util_test.go new file mode 100644 index 000000000..cc5875263 --- /dev/null +++ b/modules/util/util_test.go @@ -0,0 +1,36 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestURLJoin(t *testing.T) { + type test struct { + Expected string + Base string + Elements []string + } + newTest := func(expected, base string, elements ...string) test { + return test{Expected: expected, Base: base, Elements: elements} + } + for _, test := range []test{ + newTest("https://try.gitea.io/a/b/c", + "https://try.gitea.io", "a/b", "c"), + newTest("https://try.gitea.io/a/b/c", + "https://try.gitea.io/", "/a/b/", "/c/"), + newTest("https://try.gitea.io/a/c", + "https://try.gitea.io/", "/a/./b/", "../c/"), + newTest("a/b/c", + "a", "b/c/"), + newTest("a/b/d", + "a/", "b/c/", "/../d/"), + } { + assert.Equal(t, test.Expected, URLJoin(test.Base, test.Elements...)) + } +} diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index e24ac0518..19b966971 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -13,6 +13,8 @@ import ( "code.gitea.io/git" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ) // ToEmail convert models.EmailAddress to api.Email @@ -25,35 +27,40 @@ func ToEmail(email *models.EmailAddress) *api.Email { } // ToBranch convert a commit and branch to an api.Branch -func ToBranch(b *models.Branch, c *git.Commit) *api.Branch { +func ToBranch(repo *models.Repository, b *models.Branch, c *git.Commit) *api.Branch { return &api.Branch{ Name: b.Name, - Commit: ToCommit(c), + Commit: ToCommit(repo, c), } } // ToCommit convert a commit to api.PayloadCommit -func ToCommit(c *git.Commit) *api.PayloadCommit { +func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { authorUsername := "" - author, err := models.GetUserByEmail(c.Author.Email) - if err == nil { + if author, err := models.GetUserByEmail(c.Author.Email); err == nil { authorUsername = author.Name + } else if !models.IsErrUserNotExist(err) { + log.Error(4, "GetUserByEmail: %v", err) } + committerUsername := "" - committer, err := models.GetUserByEmail(c.Committer.Email) - if err == nil { + if committer, err := models.GetUserByEmail(c.Committer.Email); err == nil { committerUsername = committer.Name + } else if !models.IsErrUserNotExist(err) { + log.Error(4, "GetUserByEmail: %v", err) } + verif := models.ParseCommitWithSignature(c) var signature, payload string if c.Signature != nil { signature = c.Signature.Signature payload = c.Signature.Payload } + return &api.PayloadCommit{ ID: c.ID.String(), Message: c.Message(), - URL: "Not implemented", + URL: util.URLJoin(repo.Link(), "commit", c.ID.String()), Author: &api.PayloadUser{ Name: c.Author.Name, Email: c.Author.Email, diff --git a/routers/api/v1/misc/markdown.go b/routers/api/v1/misc/markdown.go index ed50c1c05..fd7d1489b 100644 --- a/routers/api/v1/misc/markdown.go +++ b/routers/api/v1/misc/markdown.go @@ -8,9 +8,9 @@ import ( api "code.gitea.io/sdk/gitea" "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" + "code.gitea.io/gitea/modules/util" ) // Markdown render markdown document to HTML @@ -45,7 +45,7 @@ func Markdown(ctx *context.APIContext, form api.MarkdownOption) { switch form.Mode { case "gfm": md := []byte(form.Text) - context := markup.URLJoin(setting.AppURL, form.Context) + context := util.URLJoin(setting.AppURL, form.Context) if form.Wiki { ctx.Write([]byte(markdown.RenderWiki(md, context, nil))) } else { diff --git a/routers/api/v1/misc/markdown_test.go b/routers/api/v1/misc/markdown_test.go index 8c3051ea8..c1449589a 100644 --- a/routers/api/v1/misc/markdown_test.go +++ b/routers/api/v1/misc/markdown_test.go @@ -9,8 +9,8 @@ import ( "testing" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" api "code.gitea.io/sdk/gitea" "github.com/go-macaron/inject" @@ -53,7 +53,7 @@ func TestAPI_RenderGFM(t *testing.T) { Context: Repo, Wiki: true, } - requrl, _ := url.Parse(markup.URLJoin(AppURL, "api", "v1", "markdown")) + requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) req := &http.Request{ Method: "POST", URL: requrl, @@ -147,7 +147,7 @@ func TestAPI_RenderSimple(t *testing.T) { Text: "", Context: Repo, } - requrl, _ := url.Parse(markup.URLJoin(AppURL, "api", "v1", "markdown")) + requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) req := &http.Request{ Method: "POST", URL: requrl, @@ -166,7 +166,7 @@ func TestAPI_RenderSimple(t *testing.T) { func TestAPI_RenderRaw(t *testing.T) { setting.AppURL = AppURL - requrl, _ := url.Parse(markup.URLJoin(AppURL, "api", "v1", "markdown")) + requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) req := &http.Request{ Method: "POST", URL: requrl, diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index a82527e6a..8e44f4236 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -61,7 +61,7 @@ func GetBranch(ctx *context.APIContext) { return } - ctx.JSON(200, convert.ToBranch(branch, c)) + ctx.JSON(200, convert.ToBranch(ctx.Repo.Repository, branch, c)) } // ListBranches list all the branches of a repository @@ -98,7 +98,7 @@ func ListBranches(ctx *context.APIContext) { ctx.Error(500, "GetCommit", err) return } - apiBranches[i] = convert.ToBranch(branches[i], c) + apiBranches[i] = convert.ToBranch(ctx.Repo.Repository, branches[i], c) } ctx.JSON(200, &apiBranches) From 2f5c1ba1db39648e4be9a2905dcec09c45dbb269 Mon Sep 17 00:00:00 2001 From: Wendell Sun Date: Wed, 21 Feb 2018 09:38:03 +0800 Subject: [PATCH 024/106] Bug fix for repo releases sorted (#3522) Signed-off-by: Wendell Sun Use TimeStampNow function --- models/release.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/models/release.go b/models/release.go index 1e1d339a7..66202615d 100644 --- a/models/release.go +++ b/models/release.go @@ -36,7 +36,7 @@ type Release struct { IsPrerelease bool `xorm:"NOT NULL DEFAULT false"` IsTag bool `xorm:"NOT NULL DEFAULT false"` Attachments []*Attachment `xorm:"-"` - CreatedUnix util.TimeStamp `xorm:"created INDEX"` + CreatedUnix util.TimeStamp `xorm:"INDEX"` } func (r *Release) loadAttributes(e Engine) error { @@ -134,6 +134,8 @@ func createTag(gitRepo *git.Repository, rel *Release) error { if err != nil { return fmt.Errorf("CommitsCount: %v", err) } + } else { + rel.CreatedUnix = util.TimeStampNow() } return nil } From d27d720f05835dfc4633587aec885ab9b93b5f86 Mon Sep 17 00:00:00 2001 From: Ethan Koenig Date: Tue, 20 Feb 2018 23:38:52 -0800 Subject: [PATCH 025/106] Use unique temp dirs in unit tests (#3494) * Use unique temp dirs in unit tests * Remove temp dirs after tests run * os.RemoveAll -> removeAllWithRetry --- models/unit_tests.go | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/models/unit_tests.go b/models/unit_tests.go index 962b1a494..9013fb987 100644 --- a/models/unit_tests.go +++ b/models/unit_tests.go @@ -6,6 +6,8 @@ package models import ( "fmt" + "io/ioutil" + "net/url" "os" "path/filepath" "testing" @@ -18,7 +20,6 @@ import ( "github.com/go-xorm/xorm" "github.com/stretchr/testify/assert" "gopkg.in/testfixtures.v2" - "net/url" ) // NonexistentID an ID that will never exist @@ -27,6 +28,11 @@ const NonexistentID = 9223372036854775807 // giteaRoot a path to the gitea root var giteaRoot string +func fatalTestError(fmtStr string, args ...interface{}) { + fmt.Fprintf(os.Stderr, fmtStr, args...) + os.Exit(1) +} + // MainTest a reusable TestMain(..) function for unit tests that need to use a // test database. Creates the test database, and sets necessary settings. func MainTest(m *testing.M, pathToGiteaRoot string) { @@ -34,25 +40,36 @@ func MainTest(m *testing.M, pathToGiteaRoot string) { giteaRoot = pathToGiteaRoot fixturesDir := filepath.Join(pathToGiteaRoot, "models", "fixtures") if err = createTestEngine(fixturesDir); err != nil { - fmt.Fprintf(os.Stderr, "Error creating test engine: %v\n", err) - os.Exit(1) + fatalTestError("Error creating test engine: %v\n", err) } setting.AppURL = "https://try.gitea.io/" setting.RunUser = "runuser" setting.SSH.Port = 3000 setting.SSH.Domain = "try.gitea.io" - setting.RepoRootPath = filepath.Join(os.TempDir(), "repos") - setting.AppDataPath = filepath.Join(os.TempDir(), "appdata") + setting.RepoRootPath, err = ioutil.TempDir(os.TempDir(), "repos") + if err != nil { + fatalTestError("TempDir: %v\n", err) + } + setting.AppDataPath, err = ioutil.TempDir(os.TempDir(), "appdata") + if err != nil { + fatalTestError("TempDir: %v\n", err) + } setting.AppWorkPath = pathToGiteaRoot setting.StaticRootPath = pathToGiteaRoot setting.GravatarSourceURL, err = url.Parse("https://secure.gravatar.com/avatar/") if err != nil { - fmt.Fprintf(os.Stderr, "Error url.Parse: %v\n", err) - os.Exit(1) + fatalTestError("url.Parse: %v\n", err) } - os.Exit(m.Run()) + exitStatus := m.Run() + if err = removeAllWithRetry(setting.RepoRootPath); err != nil { + fatalTestError("os.RemoveAll: %v\n", err) + } + if err = removeAllWithRetry(setting.AppDataPath); err != nil { + fatalTestError("os.RemoveAll: %v\n", err) + } + os.Exit(exitStatus) } func createTestEngine(fixturesDir string) error { From 04b3e8cbdc2bb4eafe8feb3fe4882f010e931860 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Wed, 21 Feb 2018 18:55:34 +0800 Subject: [PATCH 026/106] refactor: reduce sql query in retrieveFeeds (#3547) --- models/action.go | 11 ++++- models/action_list.go | 98 +++++++++++++++++++++++++++++++++++++++++++ routers/user/home.go | 43 +++++-------------- 3 files changed, 118 insertions(+), 34 deletions(-) create mode 100644 models/action_list.go diff --git a/models/action.go b/models/action.go index 5333f6277..b551d79bb 100644 --- a/models/action.go +++ b/models/action.go @@ -742,5 +742,14 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { } actions := make([]*Action, 0, 20) - return actions, x.Limit(20).Desc("id").Where(cond).Find(&actions) + + if err := x.Limit(20).Desc("id").Where(cond).Find(&actions); err != nil { + return nil, fmt.Errorf("Find: %v", err) + } + + if err := ActionList(actions).LoadAttributes(); err != nil { + return nil, fmt.Errorf("LoadAttributes: %v", err) + } + + return actions, nil } diff --git a/models/action_list.go b/models/action_list.go new file mode 100644 index 000000000..6f726f4b3 --- /dev/null +++ b/models/action_list.go @@ -0,0 +1,98 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import "fmt" + +// ActionList defines a list of actions +type ActionList []*Action + +func (actions ActionList) getUserIDs() []int64 { + userIDs := make(map[int64]struct{}, len(actions)) + for _, action := range actions { + if _, ok := userIDs[action.ActUserID]; !ok { + userIDs[action.ActUserID] = struct{}{} + } + } + return keysInt64(userIDs) +} + +func (actions ActionList) loadUsers(e Engine) ([]*User, error) { + if len(actions) == 0 { + return nil, nil + } + + userIDs := actions.getUserIDs() + userMaps := make(map[int64]*User, len(userIDs)) + err := e. + In("id", userIDs). + Find(&userMaps) + if err != nil { + return nil, fmt.Errorf("find user: %v", err) + } + + for _, action := range actions { + action.ActUser = userMaps[action.ActUserID] + } + return valuesUser(userMaps), nil +} + +// LoadUsers loads actions' all users +func (actions ActionList) LoadUsers() ([]*User, error) { + return actions.loadUsers(x) +} + +func (actions ActionList) getRepoIDs() []int64 { + repoIDs := make(map[int64]struct{}, len(actions)) + for _, action := range actions { + if _, ok := repoIDs[action.RepoID]; !ok { + repoIDs[action.RepoID] = struct{}{} + } + } + return keysInt64(repoIDs) +} + +func (actions ActionList) loadRepositories(e Engine) ([]*Repository, error) { + if len(actions) == 0 { + return nil, nil + } + + repoIDs := actions.getRepoIDs() + repoMaps := make(map[int64]*Repository, len(repoIDs)) + err := e. + In("id", repoIDs). + Find(&repoMaps) + if err != nil { + return nil, fmt.Errorf("find repository: %v", err) + } + + for _, action := range actions { + action.Repo = repoMaps[action.RepoID] + } + return valuesRepository(repoMaps), nil +} + +// LoadRepositories loads actions' all repositories +func (actions ActionList) LoadRepositories() ([]*Repository, error) { + return actions.loadRepositories(x) +} + +// loadAttributes loads all attributes +func (actions ActionList) loadAttributes(e Engine) (err error) { + if _, err = actions.loadUsers(e); err != nil { + return + } + + if _, err = actions.loadRepositories(e); err != nil { + return + } + + return nil +} + +// LoadAttributes loads attributes of the actions +func (actions ActionList) LoadAttributes() error { + return actions.loadAttributes(x) +} diff --git a/routers/user/home.go b/routers/user/home.go index 5687cb4f1..2a193bbde 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -66,12 +66,14 @@ func retrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) { if ctx.User != nil { userCache[ctx.User.ID] = ctx.User } - repoCache := map[int64]*models.Repository{} for _, act := range actions { - // Cache results to reduce queries. - u, ok := userCache[act.ActUserID] + if act.ActUser != nil { + userCache[act.ActUserID] = act.ActUser + } + + repoOwner, ok := userCache[act.Repo.OwnerID] if !ok { - u, err = models.GetUserByID(act.ActUserID) + repoOwner, err = models.GetUserByID(act.Repo.OwnerID) if err != nil { if models.IsErrUserNotExist(err) { continue @@ -79,35 +81,9 @@ func retrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) { ctx.ServerError("GetUserByID", err) return } - userCache[act.ActUserID] = u + userCache[repoOwner.ID] = repoOwner } - act.ActUser = u - - repo, ok := repoCache[act.RepoID] - if !ok { - repo, err = models.GetRepositoryByID(act.RepoID) - if err != nil { - if models.IsErrRepoNotExist(err) { - continue - } - ctx.ServerError("GetRepositoryByID", err) - return - } - } - act.Repo = repo - - repoOwner, ok := userCache[repo.OwnerID] - if !ok { - repoOwner, err = models.GetUserByID(repo.OwnerID) - if err != nil { - if models.IsErrUserNotExist(err) { - continue - } - ctx.ServerError("GetUserByID", err) - return - } - } - repo.Owner = repoOwner + act.Repo.Owner = repoOwner } ctx.Data["Feeds"] = actions } @@ -154,7 +130,8 @@ func Dashboard(ctx *context.Context) { ctx.Data["MirrorCount"] = len(mirrors) ctx.Data["Mirrors"] = mirrors - retrieveFeeds(ctx, models.GetFeedsOptions{RequestedUser: ctxUser, + retrieveFeeds(ctx, models.GetFeedsOptions{ + RequestedUser: ctxUser, IncludePrivate: true, OnlyPerformedBy: false, IncludeDeleted: false, From e7cea9253530091be4e0073bfd9152f09cb5a40d Mon Sep 17 00:00:00 2001 From: Victor Polevoy Date: Thu, 22 Feb 2018 15:55:26 +0300 Subject: [PATCH 027/106] Update gogs to gitea migration manual (#3559) Updates the manual for latest gogs changes. --- docs/content/doc/upgrade/from-gogs.en-us.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/content/doc/upgrade/from-gogs.en-us.md b/docs/content/doc/upgrade/from-gogs.en-us.md index 93f2e13a2..4e16b3b78 100644 --- a/docs/content/doc/upgrade/from-gogs.en-us.md +++ b/docs/content/doc/upgrade/from-gogs.en-us.md @@ -19,9 +19,10 @@ Gogs, version 0.9.146 and older, can be easily migrated to Gitea. There are some basic steps to follow. On a Linux system run as the Gogs user: -* Create a Gogs backup with `gogs dump`. This creates `gogs-dump-[timestamp].zip` file - containing all important Gogs data. +* Create a Gogs backup with `gogs backup`. This creates `gogs-backup-[timestamp].zip` file + containing all important Gogs data. You would need it if you wanted to move to the `gogs` back later. * Download the file matching the destination platform from the [downloads page](https://dl.gitea.io/gitea). + It should be `1.0.x` version. Migrating from `gogs` to any other version is impossible. * Put the binary at the desired install location. * Copy `gogs/custom/conf/app.ini` to `gitea/custom/conf/app.ini`. * Copy custom `templates, public` from `gogs/custom/` to `gitea/custom/`. @@ -38,6 +39,11 @@ There are some basic steps to follow. On a Linux system run as the Gogs user: * Rename `gogs-data/` to `gitea-data/` * In `gitea/custom/conf/app.ini` change: +### Upgrading to most recent `gitea` version: +After successful migration from `gogs` to `gitea 1.0.x` it is possible to upgrade to the recent `gitea` version. +Simply download the file matching the destination platform from the [downloads page](https://dl.gitea.io/gitea) +and replace the binary. + FROM: ``` [database] From 845ba9d1537eb1012bb0d448265b5346ef14d2d3 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Fri, 23 Feb 2018 08:27:09 +0800 Subject: [PATCH 028/106] =?UTF-8?q?fix:=20if=20Mirrors=20repo=20no=20conte?= =?UTF-8?q?nt=20is=20fetched,=20updated=20time=20should=20not=20b=E2=80=A6?= =?UTF-8?q?=20(#3551)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: if Mirrors repo no content is fetched, updated time should not be changed * fix: sync update time from mirror repo. * fix: one single session. * update comment. Signed-off-by: Bo-Yi Wu --- models/repo_mirror.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/models/repo_mirror.go b/models/repo_mirror.go index 197889e19..97fe2406c 100644 --- a/models/repo_mirror.go +++ b/models/repo_mirror.go @@ -244,6 +244,8 @@ func MirrorUpdate() { // SyncMirrors checks and syncs mirrors. // TODO: sync more mirrors at same time. func SyncMirrors() { + sess := x.NewSession() + defer sess.Close() // Start listening on new sync requests. for repoID := range MirrorQueue.Queue() { log.Trace("SyncMirrors [repo_id: %v]", repoID) @@ -260,10 +262,22 @@ func SyncMirrors() { } m.ScheduleNextUpdate() - if err = UpdateMirror(m); err != nil { + if err = updateMirror(sess, m); err != nil { log.Error(4, "UpdateMirror [%s]: %v", repoID, err) continue } + + // Get latest commit date and update to current repository updated time + commitDate, err := git.GetLatestCommitTime(m.Repo.RepoPath()) + if err != nil { + log.Error(2, "GetLatestCommitDate [%s]: %v", m.RepoID, err) + continue + } + + if _, err = sess.Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", commitDate.Unix(), m.RepoID); err != nil { + log.Error(2, "Update repository 'updated_unix' [%s]: %v", m.RepoID, err) + continue + } } } From 19bf4ddf800dd405bddbafee7574ff4df07ed275 Mon Sep 17 00:00:00 2001 From: Wendell Sun Date: Fri, 23 Feb 2018 10:14:15 +0800 Subject: [PATCH 029/106] Fix query protected branch bug (#3563) Signed-off-by: Wendell Sun --- models/branches.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models/branches.go b/models/branches.go index 7cc0ebab4..d1921d550 100644 --- a/models/branches.go +++ b/models/branches.go @@ -6,7 +6,6 @@ package models import ( "fmt" - "strings" "time" "code.gitea.io/gitea/modules/base" @@ -70,7 +69,7 @@ func GetProtectedBranchByRepoID(RepoID int64) ([]*ProtectedBranch, error) { // GetProtectedBranchBy getting protected branch by ID/Name func GetProtectedBranchBy(repoID int64, BranchName string) (*ProtectedBranch, error) { - rel := &ProtectedBranch{RepoID: repoID, BranchName: strings.ToLower(BranchName)} + rel := &ProtectedBranch{RepoID: repoID, BranchName: BranchName} has, err := x.Get(rel) if err != nil { return nil, err From 2d1c5c3756beab3dfb3a1463d601385ab2e5db6f Mon Sep 17 00:00:00 2001 From: Wendell Sun Date: Fri, 23 Feb 2018 16:42:02 +0800 Subject: [PATCH 030/106] Fix remove team member issue (#3566) Put sess.Commit() out of the RemoveOrgUser function Add an empty line to separate import packages --- models/org.go | 22 ++++++++++++++-------- models/org_team.go | 14 +++++++++++++- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/models/org.go b/models/org.go index 095265a12..ed0d58306 100644 --- a/models/org.go +++ b/models/org.go @@ -436,8 +436,7 @@ func AddOrgUser(orgID, uid int64) error { return sess.Commit() } -// RemoveOrgUser removes user from given organization. -func RemoveOrgUser(orgID, userID int64) error { +func removeOrgUser(sess *xorm.Session, orgID, userID int64) error { ou := new(OrgUser) has, err := x. @@ -473,12 +472,6 @@ func RemoveOrgUser(orgID, userID int64) error { } } - sess := x.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { - return err - } - if _, err := sess.ID(ou.ID).Delete(ou); err != nil { return err } else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil { @@ -520,6 +513,19 @@ func RemoveOrgUser(orgID, userID int64) error { } } + return nil +} + +// RemoveOrgUser removes user from given organization. +func RemoveOrgUser(orgID, userID int64) error { + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + if err := removeOrgUser(sess, orgID, userID); err != nil { + return err + } return sess.Commit() } diff --git a/models/org_team.go b/models/org_team.go index 941b7ed2a..9d8a03141 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -10,6 +10,8 @@ import ( "strings" "code.gitea.io/gitea/modules/log" + + "github.com/go-xorm/xorm" ) const ownerTeamName = "Owners" @@ -521,7 +523,7 @@ func AddTeamMember(team *Team, userID int64) error { return sess.Commit() } -func removeTeamMember(e Engine, team *Team, userID int64) error { +func removeTeamMember(e *xorm.Session, team *Team, userID int64) error { isMember, err := isTeamMember(e, team.OrgID, team.ID, userID) if err != nil || !isMember { return err @@ -558,6 +560,16 @@ func removeTeamMember(e Engine, team *Team, userID int64) error { } } + // Check if the user is a member of any team in the organization. + if count, err := e.Count(&TeamUser{ + UID: userID, + OrgID: team.OrgID, + }); err != nil { + return err + } else if count == 0 { + return removeOrgUser(e, team.OrgID, userID) + } + return nil } From d2d0aea8a1440e54d35a9c2fb1c868071cd340d8 Mon Sep 17 00:00:00 2001 From: Wendell Sun Date: Fri, 23 Feb 2018 18:10:03 +0800 Subject: [PATCH 031/106] Fix the protected branch panic issue (#3567) --- models/branches.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/models/branches.go b/models/branches.go index d1921d550..0a3d19858 100644 --- a/models/branches.go +++ b/models/branches.go @@ -155,6 +155,10 @@ func (repo *Repository) GetProtectedBranches() ([]*ProtectedBranch, error) { // IsProtectedBranch checks if branch is protected func (repo *Repository) IsProtectedBranch(branchName string, doer *User) (bool, error) { + if doer == nil { + return true, nil + } + protectedBranch := &ProtectedBranch{ RepoID: repo.ID, BranchName: branchName, From fc265b036f6441f8b738cf32c85fd1193b5dd2f0 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Sun, 25 Feb 2018 05:17:59 +0800 Subject: [PATCH 032/106] feat: Add branch link in branch list. (#3576) --- templates/repo/branch/list.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index bc00d0d71..cd6afce91 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -38,10 +38,10 @@ {{if .IsDeleted}} - {{.Name}} + {{.Name}}

{{$.i18n.Tr "repo.branch.deleted_by" .DeletedBranch.DeletedBy.Name}} {{TimeSinceUnix .DeletedBranch.DeletedUnix $.i18n.Lang}}

{{else}} - {{.Name}} + {{.Name}}

{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}

{{end}} From 521945a2d2af421f365b5ed368833f0eb62bc0b9 Mon Sep 17 00:00:00 2001 From: bugreport0 <32939607+bugreport0@users.noreply.github.com> Date: Sun, 25 Feb 2018 14:56:25 +0100 Subject: [PATCH 033/106] Fix missing translations when updating username. (#3564) * Fix missing translations when updating username. * Fix reserved username translated string test. * Fix 'username reserved' string test a bit more. --- integrations/user_test.go | 2 +- routers/user/setting.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/integrations/user_test.go b/integrations/user_test.go index da39234c3..0b59663a4 100644 --- a/integrations/user_test.go +++ b/integrations/user_test.go @@ -92,7 +92,7 @@ func TestRenameReservedUsername(t *testing.T) { htmlDoc := NewHTMLParser(t, resp.Body) assert.Contains(t, htmlDoc.doc.Find(".ui.negative.message").Text(), - i18n.Tr("en", "user.newName_reserved"), + i18n.Tr("en", "user.form.name_reserved", reservedUsername), ) models.AssertNotExistsBean(t, &models.User{Name: reservedUsername}) diff --git a/routers/user/setting.go b/routers/user/setting.go index b674c24b4..2d8b53ff6 100644 --- a/routers/user/setting.go +++ b/routers/user/setting.go @@ -61,16 +61,16 @@ func handleUsernameChange(ctx *context.Context, newName string) { if err := models.ChangeUserName(ctx.User, newName); err != nil { switch { case models.IsErrUserAlreadyExist(err): - ctx.Flash.Error(ctx.Tr("newName_been_taken")) + ctx.Flash.Error(ctx.Tr("form.username_been_taken")) ctx.Redirect(setting.AppSubURL + "/user/settings") case models.IsErrEmailAlreadyUsed(err): ctx.Flash.Error(ctx.Tr("form.email_been_used")) ctx.Redirect(setting.AppSubURL + "/user/settings") case models.IsErrNameReserved(err): - ctx.Flash.Error(ctx.Tr("user.newName_reserved")) + ctx.Flash.Error(ctx.Tr("user.form.name_reserved", newName)) ctx.Redirect(setting.AppSubURL + "/user/settings") case models.IsErrNamePatternNotAllowed(err): - ctx.Flash.Error(ctx.Tr("user.newName_pattern_not_allowed")) + ctx.Flash.Error(ctx.Tr("user.form.name_pattern_not_allowed", newName)) ctx.Redirect(setting.AppSubURL + "/user/settings") default: ctx.ServerError("ChangeUserName", err) From 769ab1e4240f820efdb231832cb7957cb4902807 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 26 Feb 2018 18:25:45 +0800 Subject: [PATCH 034/106] fix gpg expired bug when time is zero (#3584) --- modules/util/time_stamp.go | 5 +++++ templates/user/settings/keys_gpg.tmpl | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/util/time_stamp.go b/modules/util/time_stamp.go index a03560b24..56f41882f 100644 --- a/modules/util/time_stamp.go +++ b/modules/util/time_stamp.go @@ -59,3 +59,8 @@ func (ts TimeStamp) FormatLong() string { func (ts TimeStamp) FormatShort() string { return ts.Format("Jan 02, 2006") } + +// IsZero is zero time +func (ts TimeStamp) IsZero() bool { + return ts.AsTime().IsZero() +} diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl index ac3fc3ee6..c2af8554c 100644 --- a/templates/user/settings/keys_gpg.tmpl +++ b/templates/user/settings/keys_gpg.tmpl @@ -26,7 +26,7 @@
{{$.i18n.Tr "settings.add_on"}} {{.AddedUnix.FormatShort}} - - {{if .ExpiredUnix}}{{$.i18n.Tr "settings.valid_until"}} {{.ExpiredUnix.FormatShort}}{{else}}{{$.i18n.Tr "settings.valid_forever"}}{{end}} + {{if not .ExpiredUnix.IsZero}}{{$.i18n.Tr "settings.valid_until"}} {{.ExpiredUnix.FormatShort}}{{else}}{{$.i18n.Tr "settings.valid_forever"}}{{end}}
From 535445c32ee730988033728b3b91c4d6f456e08c Mon Sep 17 00:00:00 2001 From: Morgan Bazalgette Date: Tue, 27 Feb 2018 08:09:18 +0100 Subject: [PATCH 035/106] Rework special link parsing in the post-processing of markup (#3354) * Get rid of autolink * autolink in markdown * Replace email addresses with mailto links * better handling of links * Remove autolink.js from footer * Refactor entire html.go * fix some bugs * Make tests green, move what we can to html_internal_test, various other changes to processor logic * Make markdown tests work again This is just a description to allow me to force push in order to restart the drone build. * Fix failing markdown tests in routers/api/v1/misc * Add license headers, log errors, future-proof * fix formatting --- modules/markup/html.go | 932 ++++++++++++--------- modules/markup/html_internal_test.go | 382 +++++++++ modules/markup/html_test.go | 465 ++-------- modules/markup/markdown/markdown.go | 50 +- modules/markup/markdown/markdown_test.go | 102 +-- modules/markup/markup.go | 8 +- modules/templates/helper.go | 42 +- public/js/index.js | 2 - public/vendor/plugins/autolink/LICENSE | 21 - public/vendor/plugins/autolink/autolink.js | 45 - routers/api/v1/misc/markdown_test.go | 4 +- templates/base/footer.tmpl | 1 - 12 files changed, 1029 insertions(+), 1025 deletions(-) create mode 100644 modules/markup/html_internal_test.go delete mode 100644 public/vendor/plugins/autolink/LICENSE delete mode 100644 public/vendor/plugins/autolink/autolink.js diff --git a/modules/markup/html.go b/modules/markup/html.go index e29cbe445..53f57af1e 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -6,8 +6,6 @@ package markup import ( "bytes" - "fmt" - "io" "net/url" "path" "path/filepath" @@ -20,6 +18,7 @@ import ( "github.com/Unknwon/com" "golang.org/x/net/html" + "golang.org/x/net/html/atom" ) // Issue name styles @@ -34,29 +33,40 @@ var ( // While fast, this is also incorrect and lead to false positives. // TODO: fix invalid linking issue - // MentionPattern matches string that mentions someone, e.g. @Unknwon - MentionPattern = regexp.MustCompile(`(\s|^|\W)@[0-9a-zA-Z-_\.]+`) + // mentionPattern matches all mentions in the form of "@user" + mentionPattern = regexp.MustCompile(`(?:\s|^|\W)(@[0-9a-zA-Z-_\.]+)`) - // IssueNumericPattern matches string that references to a numeric issue, e.g. #1287 - IssueNumericPattern = regexp.MustCompile(`( |^|\(|\[)#[0-9]+\b`) - // IssueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234 - IssueAlphanumericPattern = regexp.MustCompile(`( |^|\(|\[)[A-Z]{1,10}-[1-9][0-9]*\b`) - // CrossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository + // issueNumericPattern matches string that references to a numeric issue, e.g. #1287 + issueNumericPattern = regexp.MustCompile(`(?:\s|^|\W)(#[0-9]+)\b`) + // issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234 + issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\W)([A-Z]{1,10}-[1-9][0-9]*)\b`) + // crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository // e.g. gogits/gogs#12345 - CrossReferenceIssueNumericPattern = regexp.MustCompile(`( |^)[0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+#[0-9]+\b`) + crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\W)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+#[0-9]+)\b`) - // Sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae + // sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae // Although SHA1 hashes are 40 chars long, the regex matches the hash from 7 to 40 chars in length // so that abbreviated hash links can be used as well. This matches git and github useability. - Sha1CurrentPattern = regexp.MustCompile(`(?:^|\s|\()([0-9a-f]{7,40})\b`) + sha1CurrentPattern = regexp.MustCompile(`(?:\s|^|\W)([0-9a-f]{7,40})\b`) - // ShortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax - ShortLinkPattern = regexp.MustCompile(`(\[\[.*?\]\]\w*)`) + // shortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax + shortLinkPattern = regexp.MustCompile(`\[\[(.*?)\]\](\w*)`) - // AnySHA1Pattern allows to split url containing SHA into parts - AnySHA1Pattern = regexp.MustCompile(`(http\S*)://(\S+)/(\S+)/(\S+)/(\S+)/([0-9a-f]{40})(?:/?([^#\s]+)?(?:#(\S+))?)?`) + // anySHA1Pattern allows to split url containing SHA into parts + anySHA1Pattern = regexp.MustCompile(`https?://(?:\S+/){4}([0-9a-f]{40})/?([^#\s]+)?(?:#(\S+))?`) validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`) + + // While this email regex is definitely not perfect and I'm sure you can come up + // with edge cases, it is still accepted by the CommonMark specification, as + // well as the HTML5 spec: + // http://spec.commonmark.org/0.28/#email-address + // https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail) + emailRegex = regexp.MustCompile("[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*") + + // matches http/https links. used for autlinking those. partly modified from + // the original present in autolink.js + linkRegex = regexp.MustCompile(`(?:(?:http|https):\/\/(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)(?:(?:\/[\+~%\/\.\w\-]*)?\??(?:[\-\+:=&;%@\.\w]*)#?(?:[\.\!\/\\\w]*))?`) ) // regexp for full links to issues/pulls @@ -72,6 +82,10 @@ func isLink(link []byte) bool { return validLinksPattern.Match(link) } +func isLinkStr(link string) bool { + return validLinksPattern.MatchString(link) +} + func getIssueFullPattern() *regexp.Regexp { if issueFullPattern == nil { appURL := setting.AppURL @@ -87,11 +101,12 @@ func getIssueFullPattern() *regexp.Regexp { // FindAllMentions matches mention patterns in given content // and returns a list of found user names without @ prefix. func FindAllMentions(content string) []string { - mentions := MentionPattern.FindAllString(content, -1) - for i := range mentions { - mentions[i] = mentions[i][strings.Index(mentions[i], "@")+1:] // Strip @ character + mentions := mentionPattern.FindAllStringSubmatch(content, -1) + ret := make([]string, len(mentions)) + for i, val := range mentions { + ret[i] = val[1][1:] } - return mentions + return ret } // cutoutVerbosePrefix cutouts URL prefix including sub-path to @@ -112,84 +127,6 @@ func cutoutVerbosePrefix(prefix string) string { return prefix } -// RenderIssueIndexPatternOptions options for RenderIssueIndexPattern function -type RenderIssueIndexPatternOptions struct { - // url to which non-special formatting should be linked. If empty, - // no such links will be added - DefaultURL string - URLPrefix string - Metas map[string]string -} - -// addText add text to the given buffer, adding a link to the default url -// if appropriate -func (opts RenderIssueIndexPatternOptions) addText(text []byte, buf *bytes.Buffer) { - if len(text) == 0 { - return - } else if len(opts.DefaultURL) == 0 { - buf.Write(text) - return - } - buf.WriteString(``) - buf.Write(text) - buf.WriteString(``) -} - -// RenderIssueIndexPattern renders issue indexes to corresponding links. -func RenderIssueIndexPattern(rawBytes []byte, opts RenderIssueIndexPatternOptions) []byte { - opts.URLPrefix = cutoutVerbosePrefix(opts.URLPrefix) - - pattern := IssueNumericPattern - if opts.Metas["style"] == IssueNameStyleAlphanumeric { - pattern = IssueAlphanumericPattern - } - - var buf bytes.Buffer - remainder := rawBytes - for { - indices := pattern.FindIndex(remainder) - if indices == nil || len(indices) < 2 { - opts.addText(remainder, &buf) - return buf.Bytes() - } - startIndex := indices[0] - endIndex := indices[1] - opts.addText(remainder[:startIndex], &buf) - if remainder[startIndex] == '(' || remainder[startIndex] == ' ' { - buf.WriteByte(remainder[startIndex]) - startIndex++ - } - if opts.Metas == nil { - buf.WriteString(``) - buf.Write(remainder[startIndex:endIndex]) - buf.WriteString(``) - } else { - // Support for external issue tracker - buf.WriteString(``) - buf.Write(remainder[startIndex:endIndex]) - buf.WriteString(``) - } - if endIndex < len(remainder) && - (remainder[endIndex] == ')' || remainder[endIndex] == ' ') { - buf.WriteByte(remainder[endIndex]) - endIndex++ - } - remainder = remainder[endIndex:] - } -} - // IsSameDomain checks if given url string has the same hostname as current Gitea instance func IsSameDomain(s string) bool { if strings.HasPrefix(s, "/") { @@ -204,350 +141,523 @@ func IsSameDomain(s string) bool { return false } -// renderFullSha1Pattern renders SHA containing URLs -func renderFullSha1Pattern(rawBytes []byte, urlPrefix string) []byte { - ms := AnySHA1Pattern.FindAllSubmatch(rawBytes, -1) - for _, m := range ms { - all := m[0] - protocol := string(m[1]) - paths := string(m[2]) - path := protocol + "://" + paths - author := string(m[3]) - repoName := string(m[4]) - path = util.URLJoin(path, author, repoName) - ltype := "src" - itemType := m[5] - if IsSameDomain(paths) { - ltype = string(itemType) - } else if string(itemType) == "commit" { - ltype = "commit" - } - sha := m[6] - var subtree string - if len(m) > 7 && len(m[7]) > 0 { - subtree = string(m[7]) - } - var line []byte - if len(m) > 8 && len(m[8]) > 0 { - line = m[8] - } - urlSuffix := "" - text := base.ShortSha(string(sha)) - if subtree != "" { - urlSuffix = "/" + subtree - text += urlSuffix - } - if line != nil { - value := string(line) - urlSuffix += "#" - urlSuffix += value - text += " (" - text += value - text += ")" - } - rawBytes = bytes.Replace(rawBytes, all, []byte(fmt.Sprintf( - `%s`, util.URLJoin(path, ltype, string(sha))+urlSuffix, text)), -1) - } - return rawBytes +type postProcessError struct { + context string + err error } -// RenderFullIssuePattern renders issues-like URLs -func RenderFullIssuePattern(rawBytes []byte) []byte { - ms := getIssueFullPattern().FindAllSubmatch(rawBytes, -1) - for _, m := range ms { - all := m[0] - id := string(m[1]) - text := "#" + id - // TODO if m[2] is not nil, then link is to a comment, - // and we should indicate that in the text somehow - rawBytes = bytes.Replace(rawBytes, all, []byte(fmt.Sprintf( - `%s`, string(all), text)), -1) - } - return rawBytes +func (p *postProcessError) Error() string { + return "PostProcess: " + p.context + ", " + p.Error() } -func firstIndexOfByte(sl []byte, target byte) int { - for i := 0; i < len(sl); i++ { - if sl[i] == target { - return i - } - } - return -1 +type processor func(ctx *postProcessCtx, node *html.Node) + +var defaultProcessors = []processor{ + mentionProcessor, + shortLinkProcessor, + fullIssuePatternProcessor, + issueIndexPatternProcessor, + crossReferenceIssueIndexPatternProcessor, + fullSha1PatternProcessor, + sha1CurrentPatternProcessor, + emailAddressProcessor, + linkProcessor, } -func lastIndexOfByte(sl []byte, target byte) int { - for i := len(sl) - 1; i >= 0; i-- { - if sl[i] == target { - return i - } - } - return -1 +type postProcessCtx struct { + metas map[string]string + urlPrefix string + isWikiMarkdown bool + + // processors used by this context. + procs []processor + + // if set to true, when an is found, instead of just returning during + // visitNode, it will recursively visit the node exclusively running + // shortLinkProcessorFull with true. + visitLinksForShortLinks bool } -// RenderShortLinks processes [[syntax]] -// -// noLink flag disables making link tags when set to true -// so this function just replaces the whole [[...]] with the content text -// -// isWikiMarkdown is a flag to choose linking url prefix -func RenderShortLinks(rawBytes []byte, urlPrefix string, noLink bool, isWikiMarkdown bool) []byte { - ms := ShortLinkPattern.FindAll(rawBytes, -1) - for _, m := range ms { - orig := bytes.TrimSpace(m) - m = orig[2:] - tailPos := lastIndexOfByte(m, ']') + 1 - tail := []byte{} - if tailPos < len(m) { - tail = m[tailPos:] - m = m[:tailPos-1] +// PostProcess does the final required transformations to the passed raw HTML +// data, and ensures its validity. Transformations include: replacing links and +// emails with HTML links, parsing shortlinks in the format of [[Link]], like +// MediaWiki, linking issues in the format #ID, and mentions in the format +// @user, and others. +func PostProcess( + rawHTML []byte, + urlPrefix string, + metas map[string]string, + isWikiMarkdown bool, +) ([]byte, error) { + // create the context from the parameters + ctx := &postProcessCtx{ + metas: metas, + urlPrefix: urlPrefix, + isWikiMarkdown: isWikiMarkdown, + procs: defaultProcessors, + visitLinksForShortLinks: true, + } + return ctx.postProcess(rawHTML) +} + +var commitMessageProcessors = []processor{ + mentionProcessor, + fullIssuePatternProcessor, + issueIndexPatternProcessor, + crossReferenceIssueIndexPatternProcessor, + fullSha1PatternProcessor, + sha1CurrentPatternProcessor, + emailAddressProcessor, + linkProcessor, +} + +// RenderCommitMessage will use the same logic as PostProcess, but will disable +// the shortLinkProcessor and will add a defaultLinkProcessor if defaultLink is +// set, which changes every text node into a link to the passed default link. +func RenderCommitMessage( + rawHTML []byte, + urlPrefix, defaultLink string, + metas map[string]string, +) ([]byte, error) { + ctx := &postProcessCtx{ + metas: metas, + urlPrefix: urlPrefix, + procs: commitMessageProcessors, + } + if defaultLink != "" { + // we don't have to fear data races, because being + // commitMessageProcessors of fixed len and cap, every time we append + // something to it the slice is realloc+copied, so append always + // generates the slice ex-novo. + ctx.procs = append(ctx.procs, genDefaultLinkProcessor(defaultLink)) + } + return ctx.postProcess(rawHTML) +} + +var byteBodyTag = []byte("") +var byteBodyTagClosing = []byte("") + +func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { + if ctx.procs == nil { + ctx.procs = defaultProcessors + } + + // give a generous extra 50 bytes + res := make([]byte, 0, len(rawHTML)+50) + res = append(res, byteBodyTag...) + res = append(res, rawHTML...) + res = append(res, byteBodyTagClosing...) + + // parse the HTML + nodes, err := html.ParseFragment(bytes.NewReader(res), nil) + if err != nil { + return nil, &postProcessError{"invalid HTML", err} + } + + for _, node := range nodes { + ctx.visitNode(node) + } + + // Create buffer in which the data will be placed again. We know that the + // length will be at least that of res; to spare a few alloc+copy, we + // reuse res, resetting its length to 0. + buf := bytes.NewBuffer(res[:0]) + // Render everything to buf. + for _, node := range nodes { + err = html.Render(buf, node) + if err != nil { + return nil, &postProcessError{"error rendering processed HTML", err} } - m = m[:len(m)-2] - props := map[string]string{} + } - // MediaWiki uses [[link|text]], while GitHub uses [[text|link]] - // It makes page handling terrible, but we prefer GitHub syntax - // And fall back to MediaWiki only when it is obvious from the look - // Of text and link contents - sl := bytes.Split(m, []byte("|")) - for _, v := range sl { - switch bytes.Count(v, []byte("=")) { + // remove initial parts - because Render creates a whole HTML page. + res = buf.Bytes() + res = res[bytes.Index(res, byteBodyTag)+len(byteBodyTag) : bytes.LastIndex(res, byteBodyTagClosing)] - // Piped args without = sign, these are mandatory arguments - case 0: - { - sv := string(v) - if props["name"] == "" { - if isLink(v) { - // If we clearly see it is a link, we save it so + // Everything done successfully, return parsed data. + return res, nil +} - // But first we need to ensure, that if both mandatory args provided - // look like links, we stick to GitHub syntax - if props["link"] != "" { - props["name"] = props["link"] - } - - props["link"] = strings.TrimSpace(sv) - } else { - props["name"] = sv - } - } else { - props["link"] = strings.TrimSpace(sv) - } - } - - // Piped args with = sign, these are optional arguments - case 1: - { - sep := firstIndexOfByte(v, '=') - key, val := string(v[:sep]), html.UnescapeString(string(v[sep+1:])) - lastCharIndex := len(val) - 1 - if (val[0] == '"' || val[0] == '\'') && (val[lastCharIndex] == '"' || val[lastCharIndex] == '\'') { - val = val[1:lastCharIndex] - } - props[key] = val - } +func (ctx *postProcessCtx) visitNode(node *html.Node) { + // We ignore code, pre and already generated links. + switch node.Type { + case html.TextNode: + ctx.textNode(node) + case html.ElementNode: + if node.Data == "a" || node.Data == "code" || node.Data == "pre" { + if node.Data == "a" && ctx.visitLinksForShortLinks { + ctx.visitNodeForShortLinks(node) } + return } + for n := node.FirstChild; n != nil; n = n.NextSibling { + ctx.visitNode(n) + } + } + // ignore everything else +} - var name string - var link string - if props["link"] != "" { - link = props["link"] - } else if props["name"] != "" { - link = props["name"] +func (ctx *postProcessCtx) visitNodeForShortLinks(node *html.Node) { + switch node.Type { + case html.TextNode: + shortLinkProcessorFull(ctx, node, true) + case html.ElementNode: + if node.Data == "code" || node.Data == "pre" { + return } - if props["title"] != "" { - name = props["title"] - } else if props["name"] != "" { - name = props["name"] + for n := node.FirstChild; n != nil; n = n.NextSibling { + ctx.visitNodeForShortLinks(n) + } + } +} + +// textNode runs the passed node through various processors, in order to handle +// all kinds of special links handled by the post-processing. +func (ctx *postProcessCtx) textNode(node *html.Node) { + for _, processor := range ctx.procs { + processor(ctx, node) + } +} + +func createLink(href, content string) *html.Node { + textNode := &html.Node{ + Type: html.TextNode, + Data: content, + } + linkNode := &html.Node{ + FirstChild: textNode, + LastChild: textNode, + Type: html.ElementNode, + Data: "a", + DataAtom: atom.A, + Attr: []html.Attribute{ + {Key: "href", Val: href}, + }, + } + textNode.Parent = linkNode + return linkNode +} + +// replaceContent takes a text node, and in its content it replaces a section of +// it with the specified newNode. An example to visualize how this can work can +// be found here: https://play.golang.org/p/5zP8NnHZ03s +func replaceContent(node *html.Node, i, j int, newNode *html.Node) { + // get the data before and after the match + before := node.Data[:i] + after := node.Data[j:] + + // Replace in the current node the text, so that it is only what it is + // supposed to have. + node.Data = before + + // Get the current next sibling, before which we place the replaced data, + // and after that we place the new text node. + nextSibling := node.NextSibling + node.Parent.InsertBefore(newNode, nextSibling) + if after != "" { + node.Parent.InsertBefore(&html.Node{ + Type: html.TextNode, + Data: after, + }, nextSibling) + } +} + +func mentionProcessor(_ *postProcessCtx, node *html.Node) { + m := mentionPattern.FindStringSubmatchIndex(node.Data) + if m == nil { + return + } + // Replace the mention with a link to the specified user. + mention := node.Data[m[2]:m[3]] + replaceContent(node, m[2], m[3], createLink(util.URLJoin(setting.AppURL, mention[1:]), mention)) +} + +func shortLinkProcessor(ctx *postProcessCtx, node *html.Node) { + shortLinkProcessorFull(ctx, node, false) +} + +func shortLinkProcessorFull(ctx *postProcessCtx, node *html.Node, noLink bool) { + m := shortLinkPattern.FindStringSubmatchIndex(node.Data) + if m == nil { + return + } + + content := node.Data[m[2]:m[3]] + tail := node.Data[m[4]:m[5]] + props := make(map[string]string) + + // MediaWiki uses [[link|text]], while GitHub uses [[text|link]] + // It makes page handling terrible, but we prefer GitHub syntax + // And fall back to MediaWiki only when it is obvious from the look + // Of text and link contents + sl := strings.Split(content, "|") + for _, v := range sl { + if equalPos := strings.IndexByte(v, '='); equalPos == -1 { + // There is no equal in this argument; this is a mandatory arg + if props["name"] == "" { + if isLinkStr(v) { + // If we clearly see it is a link, we save it so + + // But first we need to ensure, that if both mandatory args provided + // look like links, we stick to GitHub syntax + if props["link"] != "" { + props["name"] = props["link"] + } + + props["link"] = strings.TrimSpace(v) + } else { + props["name"] = v + } + } else { + props["link"] = strings.TrimSpace(v) + } } else { - name = link + // There is an equal; optional argument. + + sep := strings.IndexByte(v, '=') + key, val := v[:sep], html.UnescapeString(v[sep+1:]) + + // When parsing HTML, x/net/html will change all quotes which are + // not used for syntax into UTF-8 quotes. So checking val[0] won't + // be enough, since that only checks a single byte. + if (strings.HasPrefix(val, "“") && strings.HasSuffix(val, "”")) || + (strings.HasPrefix(val, "‘") && strings.HasSuffix(val, "’")) { + const lenQuote = len("‘") + val = val[lenQuote : len(val)-lenQuote] + } + props[key] = val + } + } + + var name, link string + if props["link"] != "" { + link = props["link"] + } else if props["name"] != "" { + link = props["name"] + } + if props["title"] != "" { + name = props["title"] + } else if props["name"] != "" { + name = props["name"] + } else { + name = link + } + + name += tail + image := false + switch ext := filepath.Ext(string(link)); ext { + // fast path: empty string, ignore + case "": + break + case ".jpg", ".jpeg", ".png", ".tif", ".tiff", ".webp", ".gif", ".bmp", ".ico", ".svg": + image = true + } + + childNode := &html.Node{} + linkNode := &html.Node{ + FirstChild: childNode, + LastChild: childNode, + Type: html.ElementNode, + Data: "a", + DataAtom: atom.A, + } + childNode.Parent = linkNode + absoluteLink := isLinkStr(link) + if !absoluteLink { + link = strings.Replace(link, " ", "+", -1) + } + urlPrefix := ctx.urlPrefix + if image { + if !absoluteLink { + if IsSameDomain(urlPrefix) { + urlPrefix = strings.Replace(urlPrefix, "/src/", "/raw/", 1) + } + if ctx.isWikiMarkdown { + link = util.URLJoin("wiki", "raw", link) + } + link = util.URLJoin(urlPrefix, link) + } + title := props["title"] + if title == "" { + title = props["alt"] + } + if title == "" { + title = path.Base(string(name)) + } + alt := props["alt"] + if alt == "" { + alt = name } - name += string(tail) - image := false - ext := filepath.Ext(string(link)) - if ext != "" { - switch ext { - case ".jpg", ".jpeg", ".png", ".tif", ".tiff", ".webp", ".gif", ".bmp", ".ico", ".svg": - { - image = true - } - } + // make the childNode an image - if we can, we also place the alt + childNode.Type = html.ElementNode + childNode.Data = "img" + childNode.DataAtom = atom.Img + childNode.Attr = []html.Attribute{ + {Key: "src", Val: link}, + {Key: "title", Val: title}, + {Key: "alt", Val: alt}, } - absoluteLink := isLink([]byte(link)) + if alt == "" { + childNode.Attr = childNode.Attr[:2] + } + } else { if !absoluteLink { - link = strings.Replace(link, " ", "+", -1) - } - if image { - if !absoluteLink { - if IsSameDomain(urlPrefix) { - urlPrefix = strings.Replace(urlPrefix, "/src/", "/raw/", 1) - } - if isWikiMarkdown { - link = util.URLJoin("wiki", "raw", link) - } - link = util.URLJoin(urlPrefix, link) - } - title := props["title"] - if title == "" { - title = props["alt"] - } - if title == "" { - title = path.Base(string(name)) - } - alt := props["alt"] - if alt == "" { - alt = name - } - if alt != "" { - alt = `alt="` + alt + `"` - } - name = fmt.Sprintf(``, link, alt, title) - } else if !absoluteLink { - if isWikiMarkdown { + if ctx.isWikiMarkdown { link = util.URLJoin("wiki", link) } link = util.URLJoin(urlPrefix, link) } - if noLink { - rawBytes = bytes.Replace(rawBytes, orig, []byte(name), -1) + childNode.Type = html.TextNode + childNode.Data = name + } + if noLink { + linkNode = childNode + } else { + linkNode.Attr = []html.Attribute{{Key: "href", Val: link}} + } + replaceContent(node, m[0], m[1], linkNode) +} + +func fullIssuePatternProcessor(ctx *postProcessCtx, node *html.Node) { + m := getIssueFullPattern().FindStringSubmatchIndex(node.Data) + if m == nil { + return + } + link := node.Data[m[0]:m[1]] + id := "#" + node.Data[m[2]:m[3]] + // TODO if m[4]:m[5] is not nil, then link is to a comment, + // and we should indicate that in the text somehow + replaceContent(node, m[0], m[1], createLink(link, id)) +} + +func issueIndexPatternProcessor(ctx *postProcessCtx, node *html.Node) { + prefix := cutoutVerbosePrefix(ctx.urlPrefix) + + // default to numeric pattern, unless alphanumeric is requested. + pattern := issueNumericPattern + if ctx.metas["style"] == IssueNameStyleAlphanumeric { + pattern = issueAlphanumericPattern + } + + match := pattern.FindStringSubmatchIndex(node.Data) + if match == nil { + return + } + id := node.Data[match[2]:match[3]] + var link *html.Node + if ctx.metas == nil { + link = createLink(util.URLJoin(prefix, "issues", id[1:]), id) + } else { + // Support for external issue tracker + if ctx.metas["style"] == IssueNameStyleAlphanumeric { + ctx.metas["index"] = id } else { - rawBytes = bytes.Replace(rawBytes, orig, - []byte(fmt.Sprintf(`%s`, link, name)), -1) + ctx.metas["index"] = id[1:] } + link = createLink(com.Expand(ctx.metas["format"], ctx.metas), id) } - return rawBytes + replaceContent(node, match[2], match[3], link) } -// RenderCrossReferenceIssueIndexPattern renders issue indexes from other repositories to corresponding links. -func RenderCrossReferenceIssueIndexPattern(rawBytes []byte, urlPrefix string, metas map[string]string) []byte { - ms := CrossReferenceIssueNumericPattern.FindAll(rawBytes, -1) - for _, m := range ms { - if m[0] == ' ' || m[0] == '(' { - m = m[1:] // ignore leading space or opening parentheses +func crossReferenceIssueIndexPatternProcessor(ctx *postProcessCtx, node *html.Node) { + m := crossReferenceIssueNumericPattern.FindStringSubmatchIndex(node.Data) + if m == nil { + return + } + ref := node.Data[m[2]:m[3]] + + parts := strings.SplitN(ref, "#", 2) + repo, issue := parts[0], parts[1] + + replaceContent(node, m[2], m[3], + createLink(util.URLJoin(setting.AppURL, repo, "issues", issue), ref)) +} + +// fullSha1PatternProcessor renders SHA containing URLs +func fullSha1PatternProcessor(ctx *postProcessCtx, node *html.Node) { + m := anySHA1Pattern.FindStringSubmatchIndex(node.Data) + if m == nil { + return + } + // take out what's relevant + urlFull := node.Data[m[0]:m[1]] + hash := node.Data[m[2]:m[3]] + + var subtree, line string + + // optional, we do them depending on the length. + if m[7] > 0 { + line = node.Data[m[6]:m[7]] + } + if m[5] > 0 { + subtree = node.Data[m[4]:m[5]] + } + + text := base.ShortSha(hash) + if subtree != "" { + text += "/" + subtree + } + if line != "" { + text += " (" + text += line + text += ")" + } + + replaceContent(node, m[0], m[1], createLink(urlFull, text)) +} + +// sha1CurrentPatternProcessor renders SHA1 strings to corresponding links that +// are assumed to be in the same repository. +func sha1CurrentPatternProcessor(ctx *postProcessCtx, node *html.Node) { + m := sha1CurrentPattern.FindStringSubmatchIndex(node.Data) + if m == nil { + return + } + hash := node.Data[m[2]:m[3]] + // The regex does not lie, it matches the hash pattern. + // However, a regex cannot know if a hash actually exists or not. + // We could assume that a SHA1 hash should probably contain alphas AND numerics + // but that is not always the case. + // Although unlikely, deadbeef and 1234567 are valid short forms of SHA1 hash + // as used by git and github for linking and thus we have to do similar. + replaceContent(node, m[2], m[3], + createLink(util.URLJoin(ctx.urlPrefix, "commit", hash), base.ShortSha(hash))) +} + +// emailAddressProcessor replaces raw email addresses with a mailto: link. +func emailAddressProcessor(ctx *postProcessCtx, node *html.Node) { + m := emailRegex.FindStringIndex(node.Data) + if m == nil { + return + } + mail := node.Data[m[0]:m[1]] + replaceContent(node, m[0], m[1], createLink("mailto:"+mail, mail)) +} + +// linkProcessor creates links for any HTTP or HTTPS URL not captured by +// markdown. +func linkProcessor(ctx *postProcessCtx, node *html.Node) { + m := linkRegex.FindStringIndex(node.Data) + if m == nil { + return + } + uri := node.Data[m[0]:m[1]] + replaceContent(node, m[0], m[1], createLink(uri, uri)) +} + +func genDefaultLinkProcessor(defaultLink string) processor { + return func(ctx *postProcessCtx, node *html.Node) { + ch := &html.Node{ + Parent: node, + Type: html.TextNode, + Data: node.Data, } - repo := string(bytes.Split(m, []byte("#"))[0]) - issue := string(bytes.Split(m, []byte("#"))[1]) - - link := fmt.Sprintf(`%s`, util.URLJoin(setting.AppURL, repo, "issues", issue), m) - rawBytes = bytes.Replace(rawBytes, m, []byte(link), 1) + node.Type = html.ElementNode + node.Data = "a" + node.DataAtom = atom.A + node.Attr = []html.Attribute{{Key: "href", Val: defaultLink}} + node.FirstChild, node.LastChild = ch, ch } - return rawBytes -} - -// renderSha1CurrentPattern renders SHA1 strings to corresponding links that assumes in the same repository. -func renderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte { - ms := Sha1CurrentPattern.FindAllSubmatch(rawBytes, -1) - for _, m := range ms { - hash := m[1] - // The regex does not lie, it matches the hash pattern. - // However, a regex cannot know if a hash actually exists or not. - // We could assume that a SHA1 hash should probably contain alphas AND numerics - // but that is not always the case. - // Although unlikely, deadbeef and 1234567 are valid short forms of SHA1 hash - // as used by git and github for linking and thus we have to do similar. - rawBytes = bytes.Replace(rawBytes, hash, []byte(fmt.Sprintf( - `%s`, util.URLJoin(urlPrefix, "commit", string(hash)), base.ShortSha(string(hash)))), -1) - } - return rawBytes -} - -// RenderSpecialLink renders mentions, indexes and SHA1 strings to corresponding links. -func RenderSpecialLink(rawBytes []byte, urlPrefix string, metas map[string]string, isWikiMarkdown bool) []byte { - ms := MentionPattern.FindAll(rawBytes, -1) - for _, m := range ms { - m = m[bytes.Index(m, []byte("@")):] - rawBytes = bytes.Replace(rawBytes, m, - []byte(fmt.Sprintf(`%s`, util.URLJoin(setting.AppURL, string(m[1:])), m)), -1) - } - - rawBytes = RenderFullIssuePattern(rawBytes) - rawBytes = RenderShortLinks(rawBytes, urlPrefix, false, isWikiMarkdown) - rawBytes = RenderIssueIndexPattern(rawBytes, RenderIssueIndexPatternOptions{ - URLPrefix: urlPrefix, - Metas: metas, - }) - rawBytes = RenderCrossReferenceIssueIndexPattern(rawBytes, urlPrefix, metas) - rawBytes = renderFullSha1Pattern(rawBytes, urlPrefix) - rawBytes = renderSha1CurrentPattern(rawBytes, urlPrefix) - return rawBytes -} - -var ( - leftAngleBracket = []byte("") -) - -var noEndTags = []string{"img", "input", "br", "hr"} - -// PostProcess treats different types of HTML differently, -// and only renders special links for plain text blocks. -func PostProcess(rawHTML []byte, urlPrefix string, metas map[string]string, isWikiMarkdown bool) []byte { - startTags := make([]string, 0, 5) - var buf bytes.Buffer - tokenizer := html.NewTokenizer(bytes.NewReader(rawHTML)) - -OUTER_LOOP: - for html.ErrorToken != tokenizer.Next() { - token := tokenizer.Token() - switch token.Type { - case html.TextToken: - buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix, metas, isWikiMarkdown)) - - case html.StartTagToken: - buf.WriteString(token.String()) - tagName := token.Data - // If this is an excluded tag, we skip processing all output until a close tag is encountered. - if strings.EqualFold("a", tagName) || strings.EqualFold("code", tagName) || strings.EqualFold("pre", tagName) { - stackNum := 1 - for html.ErrorToken != tokenizer.Next() { - token = tokenizer.Token() - - // Copy the token to the output verbatim - buf.Write(RenderShortLinks([]byte(token.String()), urlPrefix, true, isWikiMarkdown)) - - if token.Type == html.StartTagToken && !com.IsSliceContainsStr(noEndTags, token.Data) { - stackNum++ - } - - // If this is the close tag to the outer-most, we are done - if token.Type == html.EndTagToken { - stackNum-- - - if stackNum <= 0 && strings.EqualFold(tagName, token.Data) { - break - } - } - } - continue OUTER_LOOP - } - - if !com.IsSliceContainsStr(noEndTags, tagName) { - startTags = append(startTags, tagName) - } - - case html.EndTagToken: - if len(startTags) == 0 { - buf.WriteString(token.String()) - break - } - - buf.Write(leftAngleBracket) - buf.WriteString(startTags[len(startTags)-1]) - buf.Write(rightAngleBracket) - startTags = startTags[:len(startTags)-1] - default: - buf.WriteString(token.String()) - } - } - - if io.EOF == tokenizer.Err() { - return buf.Bytes() - } - - // If we are not at the end of the input, then some other parsing error has occurred, - // so return the input verbatim. - return rawHTML } diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go new file mode 100644 index 000000000..ff07bab91 --- /dev/null +++ b/modules/markup/html_internal_test.go @@ -0,0 +1,382 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +package markup + +import ( + "fmt" + "strconv" + "strings" + "testing" + + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" +) + +const AppURL = "http://localhost:3000/" +const Repo = "gogits/gogs" +const AppSubURL = AppURL + Repo + "/" + +// alphanumLink an HTML link to an alphanumeric-style issue +func alphanumIssueLink(baseURL string, name string) string { + return link(util.URLJoin(baseURL, name), name) +} + +// numericLink an HTML to a numeric-style issue +func numericIssueLink(baseURL string, index int) string { + return link(util.URLJoin(baseURL, strconv.Itoa(index)), fmt.Sprintf("#%d", index)) +} + +// urlContentsLink an HTML link whose contents is the target URL +func urlContentsLink(href string) string { + return link(href, href) +} + +// link an HTML link +func link(href, contents string) string { + return fmt.Sprintf("%s", href, contents) +} + +var numericMetas = map[string]string{ + "format": "https://someurl.com/{user}/{repo}/{index}", + "user": "someUser", + "repo": "someRepo", + "style": IssueNameStyleNumeric, +} + +var alphanumericMetas = map[string]string{ + "format": "https://someurl.com/{user}/{repo}/{index}", + "user": "someUser", + "repo": "someRepo", + "style": IssueNameStyleAlphanumeric, +} + +func TestRender_IssueIndexPattern(t *testing.T) { + // numeric: render inputs without valid mentions + test := func(s string) { + testRenderIssueIndexPattern(t, s, s, nil) + testRenderIssueIndexPattern(t, s, s, &postProcessCtx{metas: numericMetas}) + } + + // should not render anything when there are no mentions + test("") + test("this is a test") + test("test 123 123 1234") + test("#") + test("# # #") + test("# 123") + test("#abcd") + test("test#1234") + test("#1234test") + test(" test #1234test") + + // should not render issue mention without leading space + test("test#54321 issue") + + // should not render issue mention without trailing space + test("test #54321issue") +} + +func TestRender_IssueIndexPattern2(t *testing.T) { + setting.AppURL = AppURL + setting.AppSubURL = AppSubURL + + // numeric: render inputs with valid mentions + test := func(s, expectedFmt string, indices ...int) { + links := make([]interface{}, len(indices)) + for i, index := range indices { + links[i] = numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), index) + } + expectedNil := fmt.Sprintf(expectedFmt, links...) + testRenderIssueIndexPattern(t, s, expectedNil, nil) + + for i, index := range indices { + links[i] = numericIssueLink("https://someurl.com/someUser/someRepo/", index) + } + expectedNum := fmt.Sprintf(expectedFmt, links...) + testRenderIssueIndexPattern(t, s, expectedNum, &postProcessCtx{metas: numericMetas}) + } + + // should render freestanding mentions + test("#1234 test", "%s test", 1234) + test("test #8 issue", "test %s issue", 8) + test("test issue #1234", "test issue %s", 1234) + + // should render mentions in parentheses + test("(#54321 issue)", "(%s issue)", 54321) + test("test (#9801 extra) issue", "test (%s extra) issue", 9801) + test("test (#1)", "test (%s)", 1) + + // should render multiple issue mentions in the same line + test("#54321 #1243", "%s %s", 54321, 1243) + test("wow (#54321 #1243)", "wow (%s %s)", 54321, 1243) + test("(#4)(#5)", "(%s)(%s)", 4, 5) + test("#1 (#4321) test", "%s (%s) test", 1, 4321) +} + +func TestRender_IssueIndexPattern3(t *testing.T) { + setting.AppURL = AppURL + setting.AppSubURL = AppSubURL + + // alphanumeric: render inputs without valid mentions + test := func(s string) { + testRenderIssueIndexPattern(t, s, s, &postProcessCtx{metas: alphanumericMetas}) + } + test("") + test("this is a test") + test("test 123 123 1234") + test("#") + test("# 123") + test("#abcd") + test("test #123") + test("abc-1234") // issue prefix must be capital + test("ABc-1234") // issue prefix must be _all_ capital + test("ABCDEFGHIJK-1234") // the limit is 10 characters in the prefix + test("ABC1234") // dash is required + test("test ABC- test") // number is required + test("test -1234 test") // prefix is required + test("testABC-123 test") // leading space is required + test("test ABC-123test") // trailing space is required + test("ABC-0123") // no leading zero +} + +func TestRender_IssueIndexPattern4(t *testing.T) { + setting.AppURL = AppURL + setting.AppSubURL = AppSubURL + + // alphanumeric: render inputs with valid mentions + test := func(s, expectedFmt string, names ...string) { + links := make([]interface{}, len(names)) + for i, name := range names { + links[i] = alphanumIssueLink("https://someurl.com/someUser/someRepo/", name) + } + expected := fmt.Sprintf(expectedFmt, links...) + testRenderIssueIndexPattern(t, s, expected, &postProcessCtx{metas: alphanumericMetas}) + } + test("OTT-1234 test", "%s test", "OTT-1234") + test("test T-12 issue", "test %s issue", "T-12") + test("test issue ABCDEFGHIJ-1234567890", "test issue %s", "ABCDEFGHIJ-1234567890") +} + +func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *postProcessCtx) { + if ctx == nil { + ctx = new(postProcessCtx) + } + ctx.procs = []processor{issueIndexPatternProcessor} + if ctx.urlPrefix == "" { + ctx.urlPrefix = AppSubURL + } + res, err := ctx.postProcess([]byte(input)) + assert.NoError(t, err) + assert.Equal(t, expected, string(res)) +} + +func TestRender_AutoLink(t *testing.T) { + setting.AppURL = AppURL + setting.AppSubURL = AppSubURL + + test := func(input, expected string) { + buffer, err := PostProcess([]byte(input), setting.AppSubURL, nil, false) + assert.Equal(t, err, nil) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) + buffer, err = PostProcess([]byte(input), setting.AppSubURL, nil, true) + assert.Equal(t, err, nil) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) + } + + // render valid issue URLs + test(util.URLJoin(setting.AppSubURL, "issues", "3333"), + numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), 3333)) + + // render valid commit URLs + tmp := util.URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae") + test(tmp, "d8a994ef24") + tmp += "#diff-2" + test(tmp, "d8a994ef24 (diff-2)") + + // render other commit URLs + tmp = "https://external-link.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2" + test(tmp, "d8a994ef24 (diff-2)") +} + +func TestRender_FullIssueURLs(t *testing.T) { + setting.AppURL = AppURL + setting.AppSubURL = AppSubURL + + test := func(input, expected string) { + ctx := new(postProcessCtx) + ctx.procs = []processor{fullIssuePatternProcessor} + if ctx.urlPrefix == "" { + ctx.urlPrefix = AppSubURL + } + result, err := ctx.postProcess([]byte(input)) + assert.NoError(t, err) + assert.Equal(t, expected, string(result)) + } + test("Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6", + "Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6") + test("Look here http://localhost:3000/person/repo/issues/4", + `Look here #4`) + test("http://localhost:3000/person/repo/issues/4#issuecomment-1234", + `#4`) +} + +func TestRegExp_issueNumericPattern(t *testing.T) { + trueTestCases := []string{ + "#1234", + "#0", + "#1234567890987654321", + " #12", + } + falseTestCases := []string{ + "# 1234", + "# 0", + "# ", + "#", + "#ABC", + "#1A2B", + "", + "ABC", + } + + for _, testCase := range trueTestCases { + assert.True(t, issueNumericPattern.MatchString(testCase)) + } + for _, testCase := range falseTestCases { + assert.False(t, issueNumericPattern.MatchString(testCase)) + } +} + +func TestRegExp_sha1CurrentPattern(t *testing.T) { + trueTestCases := []string{ + "d8a994ef243349f321568f9e36d5c3f444b99cae", + "abcdefabcdefabcdefabcdefabcdefabcdefabcd", + } + falseTestCases := []string{ + "test", + "abcdefg", + "abcdefghijklmnopqrstuvwxyzabcdefghijklmn", + "abcdefghijklmnopqrstuvwxyzabcdefghijklmO", + } + + for _, testCase := range trueTestCases { + assert.True(t, sha1CurrentPattern.MatchString(testCase)) + } + for _, testCase := range falseTestCases { + assert.False(t, sha1CurrentPattern.MatchString(testCase)) + } +} + +func TestRegExp_anySHA1Pattern(t *testing.T) { + testCases := map[string][]string{ + "https://github.com/jquery/jquery/blob/a644101ed04d0beacea864ce805e0c4f86ba1cd1/test/unit/event.js#L2703": { + "a644101ed04d0beacea864ce805e0c4f86ba1cd1", + "test/unit/event.js", + "L2703", + }, + "https://github.com/jquery/jquery/blob/a644101ed04d0beacea864ce805e0c4f86ba1cd1/test/unit/event.js": { + "a644101ed04d0beacea864ce805e0c4f86ba1cd1", + "test/unit/event.js", + "", + }, + "https://github.com/jquery/jquery/commit/0705be475092aede1eddae01319ec931fb9c65fc": { + "0705be475092aede1eddae01319ec931fb9c65fc", + "", + "", + }, + "https://github.com/jquery/jquery/tree/0705be475092aede1eddae01319ec931fb9c65fc/src": { + "0705be475092aede1eddae01319ec931fb9c65fc", + "src", + "", + }, + "https://try.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2": { + "d8a994ef243349f321568f9e36d5c3f444b99cae", + "", + "diff-2", + }, + } + + for k, v := range testCases { + assert.Equal(t, anySHA1Pattern.FindStringSubmatch(k)[1:], v) + } +} + +func TestRegExp_mentionPattern(t *testing.T) { + trueTestCases := []string{ + "@Unknwon", + "@ANT_123", + "@xxx-DiN0-z-A..uru..s-xxx", + " @lol ", + " @Te/st", + } + falseTestCases := []string{ + "@ 0", + "@ ", + "@", + "", + "ABC", + } + + for _, testCase := range trueTestCases { + res := mentionPattern.MatchString(testCase) + assert.True(t, res) + } + for _, testCase := range falseTestCases { + res := mentionPattern.MatchString(testCase) + assert.False(t, res) + } +} + +func TestRegExp_issueAlphanumericPattern(t *testing.T) { + trueTestCases := []string{ + "ABC-1234", + "A-1", + "RC-80", + "ABCDEFGHIJ-1234567890987654321234567890", + } + falseTestCases := []string{ + "RC-08", + "PR-0", + "ABCDEFGHIJK-1", + "PR_1", + "", + "#ABC", + "", + "ABC", + "GG-", + "rm-1", + } + + for _, testCase := range trueTestCases { + assert.True(t, issueAlphanumericPattern.MatchString(testCase)) + } + for _, testCase := range falseTestCases { + assert.False(t, issueAlphanumericPattern.MatchString(testCase)) + } +} + +func TestRegExp_shortLinkPattern(t *testing.T) { + trueTestCases := []string{ + "[[stuff]]", + "[[]]", + "[[stuff|title=Difficult name with spaces*!]]", + } + falseTestCases := []string{ + "test", + "abcdefg", + "[[]", + "[[", + "[]", + "]]", + "abcdefghijklmnopqrstuvwxyz", + } + + for _, testCase := range trueTestCases { + assert.True(t, shortLinkPattern.MatchString(testCase)) + } + for _, testCase := range falseTestCases { + assert.False(t, shortLinkPattern.MatchString(testCase)) + } +} diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 92f815ad9..203db243d 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -5,227 +5,17 @@ package markup_test import ( - "fmt" - "strconv" "strings" "testing" . "code.gitea.io/gitea/modules/markup" - _ "code.gitea.io/gitea/modules/markup/markdown" + "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" ) -const AppURL = "http://localhost:3000/" -const Repo = "gogits/gogs" -const AppSubURL = AppURL + Repo + "/" - -var numericMetas = map[string]string{ - "format": "https://someurl.com/{user}/{repo}/{index}", - "user": "someUser", - "repo": "someRepo", - "style": IssueNameStyleNumeric, -} - -var alphanumericMetas = map[string]string{ - "format": "https://someurl.com/{user}/{repo}/{index}", - "user": "someUser", - "repo": "someRepo", - "style": IssueNameStyleAlphanumeric, -} - -// numericLink an HTML to a numeric-style issue -func numericIssueLink(baseURL string, index int) string { - return link(util.URLJoin(baseURL, strconv.Itoa(index)), fmt.Sprintf("#%d", index)) -} - -// alphanumLink an HTML link to an alphanumeric-style issue -func alphanumIssueLink(baseURL string, name string) string { - return link(util.URLJoin(baseURL, name), name) -} - -// urlContentsLink an HTML link whose contents is the target URL -func urlContentsLink(href string) string { - return link(href, href) -} - -// link an HTML link -func link(href, contents string) string { - return fmt.Sprintf("%s", href, contents) -} - -func testRenderIssueIndexPattern(t *testing.T, input, expected string, opts RenderIssueIndexPatternOptions) { - if len(opts.URLPrefix) == 0 { - opts.URLPrefix = AppSubURL - } - actual := string(RenderIssueIndexPattern([]byte(input), opts)) - assert.Equal(t, expected, actual) -} - -func TestRender_IssueIndexPattern(t *testing.T) { - // numeric: render inputs without valid mentions - test := func(s string) { - testRenderIssueIndexPattern(t, s, s, RenderIssueIndexPatternOptions{}) - testRenderIssueIndexPattern(t, s, s, RenderIssueIndexPatternOptions{Metas: numericMetas}) - } - - // should not render anything when there are no mentions - test("") - test("this is a test") - test("test 123 123 1234") - test("#") - test("# # #") - test("# 123") - test("#abcd") - test("##1234") - test("test#1234") - test("#1234test") - test(" test #1234test") - - // should not render issue mention without leading space - test("test#54321 issue") - - // should not render issue mention without trailing space - test("test #54321issue") -} - -func TestRender_IssueIndexPattern2(t *testing.T) { - setting.AppURL = AppURL - setting.AppSubURL = AppSubURL - - // numeric: render inputs with valid mentions - test := func(s, expectedFmt string, indices ...int) { - links := make([]interface{}, len(indices)) - for i, index := range indices { - links[i] = numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), index) - } - expectedNil := fmt.Sprintf(expectedFmt, links...) - testRenderIssueIndexPattern(t, s, expectedNil, RenderIssueIndexPatternOptions{}) - - for i, index := range indices { - links[i] = numericIssueLink("https://someurl.com/someUser/someRepo/", index) - } - expectedNum := fmt.Sprintf(expectedFmt, links...) - testRenderIssueIndexPattern(t, s, expectedNum, RenderIssueIndexPatternOptions{Metas: numericMetas}) - } - - // should render freestanding mentions - test("#1234 test", "%s test", 1234) - test("test #8 issue", "test %s issue", 8) - test("test issue #1234", "test issue %s", 1234) - - // should render mentions in parentheses - test("(#54321 issue)", "(%s issue)", 54321) - test("test (#9801 extra) issue", "test (%s extra) issue", 9801) - test("test (#1)", "test (%s)", 1) - - // should render multiple issue mentions in the same line - test("#54321 #1243", "%s %s", 54321, 1243) - test("wow (#54321 #1243)", "wow (%s %s)", 54321, 1243) - test("(#4)(#5)", "(%s)(%s)", 4, 5) - test("#1 (#4321) test", "%s (%s) test", 1, 4321) -} - -func TestRender_IssueIndexPattern3(t *testing.T) { - setting.AppURL = AppURL - setting.AppSubURL = AppSubURL - - // alphanumeric: render inputs without valid mentions - test := func(s string) { - testRenderIssueIndexPattern(t, s, s, RenderIssueIndexPatternOptions{Metas: alphanumericMetas}) - } - test("") - test("this is a test") - test("test 123 123 1234") - test("#") - test("##1234") - test("# 123") - test("#abcd") - test("test #123") - test("abc-1234") // issue prefix must be capital - test("ABc-1234") // issue prefix must be _all_ capital - test("ABCDEFGHIJK-1234") // the limit is 10 characters in the prefix - test("ABC1234") // dash is required - test("test ABC- test") // number is required - test("test -1234 test") // prefix is required - test("testABC-123 test") // leading space is required - test("test ABC-123test") // trailing space is required - test("ABC-0123") // no leading zero -} - -func TestRender_IssueIndexPattern4(t *testing.T) { - setting.AppURL = AppURL - setting.AppSubURL = AppSubURL - - // alphanumeric: render inputs with valid mentions - test := func(s, expectedFmt string, names ...string) { - links := make([]interface{}, len(names)) - for i, name := range names { - links[i] = alphanumIssueLink("https://someurl.com/someUser/someRepo/", name) - } - expected := fmt.Sprintf(expectedFmt, links...) - testRenderIssueIndexPattern(t, s, expected, RenderIssueIndexPatternOptions{Metas: alphanumericMetas}) - } - test("OTT-1234 test", "%s test", "OTT-1234") - test("test T-12 issue", "test %s issue", "T-12") - test("test issue ABCDEFGHIJ-1234567890", "test issue %s", "ABCDEFGHIJ-1234567890") -} - -func TestRenderIssueIndexPatternWithDefaultURL(t *testing.T) { - setting.AppURL = AppURL - setting.AppSubURL = AppSubURL - - test := func(input string, expected string) { - testRenderIssueIndexPattern(t, input, expected, RenderIssueIndexPatternOptions{ - DefaultURL: AppURL, - }) - } - test("hello #123 world", - fmt.Sprintf(`hello `, AppURL)+ - fmt.Sprintf(`#123 `, AppSubURL)+ - fmt.Sprintf(`world`, AppURL)) - test("hello (#123) world", - fmt.Sprintf(`hello `, AppURL)+ - fmt.Sprintf(`(#123)`, AppSubURL)+ - fmt.Sprintf(` world`, AppURL)) -} - -func TestRender_AutoLink(t *testing.T) { - setting.AppURL = AppURL - setting.AppSubURL = AppSubURL - - test := func(input, expected string) { - buffer := RenderSpecialLink([]byte(input), setting.AppSubURL, nil, false) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) - buffer = RenderSpecialLink([]byte(input), setting.AppSubURL, nil, true) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) - } - - // render valid issue URLs - test(util.URLJoin(setting.AppSubURL, "issues", "3333"), - numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), 3333)) - - // render external issue URLs - for _, externalURL := range []string{ - "http://1111/2222/ssss-issues/3333?param=blah&blahh=333", - "http://test.com/issues/33333", - "https://issues/333"} { - test(externalURL, externalURL) - } - - // render valid commit URLs - tmp := util.URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae") - test(tmp, "d8a994ef24") - tmp += "#diff-2" - test(tmp, "d8a994ef24 (diff-2)") - - // render other commit URLs - tmp = "https://external-link.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2" - test(tmp, "d8a994ef24 (diff-2)") -} - func TestRender_Commits(t *testing.T) { setting.AppURL = AppURL setting.AppSubURL = AppSubURL @@ -239,13 +29,12 @@ func TestRender_Commits(t *testing.T) { var commit = util.URLJoin(AppSubURL, "commit", sha) var subtree = util.URLJoin(commit, "src") var tree = strings.Replace(subtree, "/commit/", "/tree/", -1) - var src = strings.Replace(subtree, "/commit/", "/src/", -1) test(sha, `

b6dd6210ea

`) test(sha[:7], `

b6dd621

`) test(sha[:39], `

b6dd6210ea

`) test(commit, `

b6dd6210ea

`) - test(tree, `

b6dd6210ea/src

`) + test(tree, `

b6dd6210ea/src

`) test("commit "+sha, `

commit b6dd6210ea

`) } @@ -266,193 +55,6 @@ func TestRender_CrossReferences(t *testing.T) { `

go-gitea/gitea#12345

`) } -func TestRender_FullIssueURLs(t *testing.T) { - setting.AppURL = AppURL - setting.AppSubURL = AppSubURL - - test := func(input, expected string) { - result := RenderFullIssuePattern([]byte(input)) - assert.Equal(t, expected, string(result)) - } - test("Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6", - "Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6") - test("Look here http://localhost:3000/person/repo/issues/4", - `Look here #4`) - test("http://localhost:3000/person/repo/issues/4#issuecomment-1234", - `#4`) -} - -func TestRegExp_MentionPattern(t *testing.T) { - trueTestCases := []string{ - "@Unknwon", - "@ANT_123", - "@xxx-DiN0-z-A..uru..s-xxx", - " @lol ", - " @Te/st", - } - falseTestCases := []string{ - "@ 0", - "@ ", - "@", - "", - "ABC", - } - - for _, testCase := range trueTestCases { - res := MentionPattern.MatchString(testCase) - if !res { - println() - println(testCase) - } - assert.True(t, res) - } - for _, testCase := range falseTestCases { - res := MentionPattern.MatchString(testCase) - if res { - println() - println(testCase) - } - assert.False(t, res) - } -} - -func TestRegExp_IssueNumericPattern(t *testing.T) { - trueTestCases := []string{ - "#1234", - "#0", - "#1234567890987654321", - "[#1234]", - } - falseTestCases := []string{ - "# 1234", - "# 0", - "# ", - "#", - "#ABC", - "#1A2B", - "", - "ABC", - "[]", - "[x]", - } - - for _, testCase := range trueTestCases { - assert.True(t, IssueNumericPattern.MatchString(testCase)) - } - for _, testCase := range falseTestCases { - assert.False(t, IssueNumericPattern.MatchString(testCase)) - } -} - -func TestRegExp_IssueAlphanumericPattern(t *testing.T) { - trueTestCases := []string{ - "ABC-1234", - "A-1", - "RC-80", - "ABCDEFGHIJ-1234567890987654321234567890", - "[JIRA-134]", - } - falseTestCases := []string{ - "RC-08", - "PR-0", - "ABCDEFGHIJK-1", - "PR_1", - "", - "#ABC", - "", - "ABC", - "GG-", - "rm-1", - "[]", - } - - for _, testCase := range trueTestCases { - assert.True(t, IssueAlphanumericPattern.MatchString(testCase)) - } - for _, testCase := range falseTestCases { - assert.False(t, IssueAlphanumericPattern.MatchString(testCase)) - } -} - -func TestRegExp_Sha1CurrentPattern(t *testing.T) { - trueTestCases := []string{ - "d8a994ef243349f321568f9e36d5c3f444b99cae", - "abcdefabcdefabcdefabcdefabcdefabcdefabcd", - } - falseTestCases := []string{ - "test", - "abcdefg", - "abcdefghijklmnopqrstuvwxyzabcdefghijklmn", - "abcdefghijklmnopqrstuvwxyzabcdefghijklmO", - } - - for _, testCase := range trueTestCases { - assert.True(t, Sha1CurrentPattern.MatchString(testCase)) - } - for _, testCase := range falseTestCases { - assert.False(t, Sha1CurrentPattern.MatchString(testCase)) - } -} - -func TestRegExp_AnySHA1Pattern(t *testing.T) { - testCases := map[string][]string{ - "https://github.com/jquery/jquery/blob/a644101ed04d0beacea864ce805e0c4f86ba1cd1/test/unit/event.js#L2703": { - "https", - "github.com", - "jquery", - "jquery", - "blob", - "a644101ed04d0beacea864ce805e0c4f86ba1cd1", - "test/unit/event.js", - "L2703", - }, - "https://github.com/jquery/jquery/blob/a644101ed04d0beacea864ce805e0c4f86ba1cd1/test/unit/event.js": { - "https", - "github.com", - "jquery", - "jquery", - "blob", - "a644101ed04d0beacea864ce805e0c4f86ba1cd1", - "test/unit/event.js", - "", - }, - "https://github.com/jquery/jquery/commit/0705be475092aede1eddae01319ec931fb9c65fc": { - "https", - "github.com", - "jquery", - "jquery", - "commit", - "0705be475092aede1eddae01319ec931fb9c65fc", - "", - "", - }, - "https://github.com/jquery/jquery/tree/0705be475092aede1eddae01319ec931fb9c65fc/src": { - "https", - "github.com", - "jquery", - "jquery", - "tree", - "0705be475092aede1eddae01319ec931fb9c65fc", - "src", - "", - }, - "https://try.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2": { - "https", - "try.gogs.io", - "gogs", - "gogs", - "commit", - "d8a994ef243349f321568f9e36d5c3f444b99cae", - "", - "diff-2", - }, - } - - for k, v := range testCases { - assert.Equal(t, AnySHA1Pattern.FindStringSubmatch(k)[1:], v) - } -} - func TestMisc_IsSameDomain(t *testing.T) { setting.AppURL = AppURL setting.AppSubURL = AppSubURL @@ -464,3 +66,66 @@ func TestMisc_IsSameDomain(t *testing.T) { assert.False(t, IsSameDomain("http://google.com/ncr")) assert.False(t, IsSameDomain("favicon.ico")) } + +func TestRender_ShortLinks(t *testing.T) { + setting.AppURL = AppURL + setting.AppSubURL = AppSubURL + tree := util.URLJoin(AppSubURL, "src", "master") + + test := func(input, expected, expectedWiki string) { + buffer := markdown.RenderString(input, tree, nil) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) + buffer = markdown.RenderWiki([]byte(input), setting.AppSubURL, nil) + assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) + } + + rawtree := util.URLJoin(AppSubURL, "raw", "master") + url := util.URLJoin(tree, "Link") + otherURL := util.URLJoin(tree, "OtherLink") + imgurl := util.URLJoin(rawtree, "Link.jpg") + urlWiki := util.URLJoin(AppSubURL, "wiki", "Link") + otherURLWiki := util.URLJoin(AppSubURL, "wiki", "OtherLink") + imgurlWiki := util.URLJoin(AppSubURL, "wiki", "raw", "Link.jpg") + favicon := "http://google.com/favicon.ico" + + test( + "[[Link]]", + `

Link

`, + `

Link

`) + test( + "[[Link.jpg]]", + `

Link.jpg

`, + `

Link.jpg

`) + test( + "[["+favicon+"]]", + `

`, + `

`) + test( + "[[Name|Link]]", + `

Name

`, + `

Name

`) + test( + "[[Name|Link.jpg]]", + `

Name

`, + `

Name

`) + test( + "[[Name|Link.jpg|alt=AltName]]", + `

AltName

`, + `

AltName

`) + test( + "[[Name|Link.jpg|title=Title]]", + `

Title

`, + `

Title

`) + test( + "[[Name|Link.jpg|alt=AltName|title=Title]]", + `

AltName

`, + `

AltName

`) + test( + "[[Name|Link.jpg|alt=\"AltName\"|title='Title']]", + `

AltName

`, + `

AltName

`) + test( + "[[Link]] [[OtherLink]]", + `

Link OtherLink

`, + `

Link OtherLink

`) +} diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 2e3d180c4..901edb80a 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -22,17 +22,20 @@ type Renderer struct { IsWiki bool } +var byteMailto = []byte("mailto:") + // Link defines how formal links should be processed to produce corresponding HTML elements. func (r *Renderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { - if len(link) > 0 && !markup.IsLink(link) { - if link[0] != '#' { - lnk := string(link) - if r.IsWiki { - lnk = util.URLJoin("wiki", lnk) - } - mLink := util.URLJoin(r.URLPrefix, lnk) - link = []byte(mLink) + // special case: this is not a link, a hash link or a mailto:, so it's a + // relative URL + if len(link) > 0 && !markup.IsLink(link) && + link[0] != '#' && !bytes.HasPrefix(link, byteMailto) { + lnk := string(link) + if r.IsWiki { + lnk = util.URLJoin("wiki", lnk) } + mLink := util.URLJoin(r.URLPrefix, lnk) + link = []byte(mLink) } r.Renderer.Link(out, link, title, content) @@ -124,30 +127,33 @@ func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byt out.WriteString("") } +const ( + blackfridayExtensions = 0 | + blackfriday.EXTENSION_NO_INTRA_EMPHASIS | + blackfriday.EXTENSION_TABLES | + blackfriday.EXTENSION_FENCED_CODE | + blackfriday.EXTENSION_STRIKETHROUGH | + blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK + blackfridayHTMLFlags = 0 | + blackfriday.HTML_SKIP_STYLE | + blackfriday.HTML_OMIT_CONTENTS | + blackfriday.HTML_USE_SMARTYPANTS +) + // RenderRaw renders Markdown to HTML without handling special links. func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte { - htmlFlags := 0 - htmlFlags |= blackfriday.HTML_SKIP_STYLE - htmlFlags |= blackfriday.HTML_OMIT_CONTENTS renderer := &Renderer{ - Renderer: blackfriday.HtmlRenderer(htmlFlags, "", ""), + Renderer: blackfriday.HtmlRenderer(blackfridayHTMLFlags, "", ""), URLPrefix: urlPrefix, IsWiki: wikiMarkdown, } - // set up the parser - extensions := 0 - extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS - extensions |= blackfriday.EXTENSION_TABLES - extensions |= blackfriday.EXTENSION_FENCED_CODE - extensions |= blackfriday.EXTENSION_STRIKETHROUGH - extensions |= blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK - + exts := blackfridayExtensions if setting.Markdown.EnableHardLineBreak { - extensions |= blackfriday.EXTENSION_HARD_LINE_BREAK + exts |= blackfriday.EXTENSION_HARD_LINE_BREAK } - body = blackfriday.Markdown(body, renderer, extensions) + body = blackfriday.Markdown(body, renderer, exts) return body } diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index c19037f62..605094df4 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -8,7 +8,6 @@ import ( "strings" "testing" - "code.gitea.io/gitea/modules/markup" . "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -41,69 +40,6 @@ func TestRender_StandardLinks(t *testing.T) { `

WikiPage

`) } -func TestRender_ShortLinks(t *testing.T) { - setting.AppURL = AppURL - setting.AppSubURL = AppSubURL - tree := util.URLJoin(AppSubURL, "src", "master") - - test := func(input, expected, expectedWiki string) { - buffer := RenderString(input, tree, nil) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) - buffer = RenderWiki([]byte(input), setting.AppSubURL, nil) - assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) - } - - rawtree := util.URLJoin(AppSubURL, "raw", "master") - url := util.URLJoin(tree, "Link") - otherUrl := util.URLJoin(tree, "OtherLink") - imgurl := util.URLJoin(rawtree, "Link.jpg") - urlWiki := util.URLJoin(AppSubURL, "wiki", "Link") - otherUrlWiki := util.URLJoin(AppSubURL, "wiki", "OtherLink") - imgurlWiki := util.URLJoin(AppSubURL, "wiki", "raw", "Link.jpg") - favicon := "http://google.com/favicon.ico" - - test( - "[[Link]]", - `

Link

`, - `

Link

`) - test( - "[[Link.jpg]]", - `

Link.jpg

`, - `

Link.jpg

`) - test( - "[["+favicon+"]]", - `

`, - `

`) - test( - "[[Name|Link]]", - `

Name

`, - `

Name

`) - test( - "[[Name|Link.jpg]]", - `

Name

`, - `

Name

`) - test( - "[[Name|Link.jpg|alt=AltName]]", - `

AltName

`, - `

AltName

`) - test( - "[[Name|Link.jpg|title=Title]]", - `

Title

`, - `

Title

`) - test( - "[[Name|Link.jpg|alt=AltName|title=Title]]", - `

AltName

`, - `

AltName

`) - test( - "[[Name|Link.jpg|alt=\"AltName\"|title='Title']]", - `

AltName

`, - `

AltName

`) - test( - "[[Link]] [[OtherLink]]", - `

Link OtherLink

`, - `

Link OtherLink

`) -} - func TestMisc_IsMarkdownFile(t *testing.T) { setting.Markdown.FileExtensions = []string{".md", ".markdown", ".mdown", ".mkd"} trueTestCases := []string{ @@ -141,35 +77,11 @@ func TestRender_Images(t *testing.T) { test( "!["+title+"]("+url+")", - `

`+title+`

`) + `

`+title+`

`) test( "[["+title+"|"+url+"]]", - `

`+title+`

`) -} - -func TestRegExp_ShortLinkPattern(t *testing.T) { - trueTestCases := []string{ - "[[stuff]]", - "[[]]", - "[[stuff|title=Difficult name with spaces*!]]", - } - falseTestCases := []string{ - "test", - "abcdefg", - "[[]", - "[[", - "[]", - "]]", - "abcdefghijklmnopqrstuvwxyz", - } - - for _, testCase := range trueTestCases { - assert.True(t, markup.ShortLinkPattern.MatchString(testCase)) - } - for _, testCase := range falseTestCases { - assert.False(t, markup.ShortLinkPattern.MatchString(testCase)) - } + `

`+title+`

`) } func testAnswers(baseURLContent, baseURLImages string) []string { @@ -185,7 +97,7 @@ func testAnswers(baseURLContent, baseURLImages string) []string { @@ -201,14 +113,14 @@ func testAnswers(baseURLContent, baseURLImages string) []string { - + - + @@ -218,9 +130,9 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
  1. Package your libGDX application -images/1.png
  2. +images/1.png
  3. Perform a test run by hitting the Run! button. -images/2.png
  4. +images/2.png
`, } diff --git a/modules/markup/markup.go b/modules/markup/markup.go index ba28ec53c..d17270fb0 100644 --- a/modules/markup/markup.go +++ b/modules/markup/markup.go @@ -7,6 +7,8 @@ package markup import ( "path/filepath" "strings" + + "code.gitea.io/gitea/modules/log" ) // Init initialize regexps for markdown parsing @@ -69,7 +71,11 @@ func RenderWiki(filename string, rawBytes []byte, urlPrefix string, metas map[st func render(parser Parser, rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) []byte { urlPrefix = strings.Replace(urlPrefix, " ", "+", -1) result := parser.Render(rawBytes, urlPrefix, metas, isWiki) - result = PostProcess(result, urlPrefix, metas, isWiki) + // TODO: one day the error should be returned. + result, err := PostProcess(result, urlPrefix, metas, isWiki) + if err != nil { + log.Error(3, "PostProcess: %v", err) + } return SanitizeBytes(result) } diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 3f3d6083f..98900c753 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -10,6 +10,7 @@ import ( "encoding/json" "errors" "fmt" + "html" "html/template" "mime" "net/url" @@ -27,7 +28,6 @@ import ( "golang.org/x/net/html/charset" "golang.org/x/text/transform" "gopkg.in/editorconfig/editorconfig-core-go.v1" - "html" ) // NewFuncMap returns functions for injecting to templates @@ -280,26 +280,21 @@ func ReplaceLeft(s, old, new string) string { // RenderCommitMessage renders commit message with XSS-safe and special links. func RenderCommitMessage(msg, urlPrefix string, metas map[string]string) template.HTML { - return renderCommitMessage(msg, markup.RenderIssueIndexPatternOptions{ - URLPrefix: urlPrefix, - Metas: metas, - }) + return RenderCommitMessageLink(msg, urlPrefix, "", metas) } // RenderCommitMessageLink renders commit message as a XXS-safe link to the provided // default url, handling for special links. -func RenderCommitMessageLink(msg, urlPrefix string, urlDefault string, metas map[string]string) template.HTML { - return renderCommitMessage(msg, markup.RenderIssueIndexPatternOptions{ - DefaultURL: urlDefault, - URLPrefix: urlPrefix, - Metas: metas, - }) -} - -func renderCommitMessage(msg string, opts markup.RenderIssueIndexPatternOptions) template.HTML { +func RenderCommitMessageLink(msg, urlPrefix, urlDefault string, metas map[string]string) template.HTML { cleanMsg := template.HTMLEscapeString(msg) - fullMessage := string(markup.RenderIssueIndexPattern([]byte(cleanMsg), opts)) - msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n") + // we can safely assume that it will not return any error, since there + // shouldn't be any special HTML. + fullMessage, err := markup.RenderCommitMessage([]byte(cleanMsg), urlPrefix, urlDefault, metas) + if err != nil { + log.Error(3, "RenderCommitMessage: %v", err) + return "" + } + msgLines := strings.Split(strings.TrimSpace(string(fullMessage)), "\n") if len(msgLines) == 0 { return template.HTML("") } @@ -308,16 +303,13 @@ func renderCommitMessage(msg string, opts markup.RenderIssueIndexPatternOptions) // RenderCommitBody extracts the body of a commit message without its title. func RenderCommitBody(msg, urlPrefix string, metas map[string]string) template.HTML { - return renderCommitBody(msg, markup.RenderIssueIndexPatternOptions{ - URLPrefix: urlPrefix, - Metas: metas, - }) -} - -func renderCommitBody(msg string, opts markup.RenderIssueIndexPatternOptions) template.HTML { cleanMsg := template.HTMLEscapeString(msg) - fullMessage := string(markup.RenderIssueIndexPattern([]byte(cleanMsg), opts)) - body := strings.Split(strings.TrimSpace(fullMessage), "\n") + fullMessage, err := markup.RenderCommitMessage([]byte(cleanMsg), urlPrefix, "", metas) + if err != nil { + log.Error(3, "RenderCommitMessage: %v", err) + return "" + } + body := strings.Split(strings.TrimSpace(string(fullMessage)), "\n") if len(body) == 0 { return template.HTML("") } diff --git a/public/js/index.js b/public/js/index.js index 137e50f9c..5d3d2a013 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -771,7 +771,6 @@ function initWikiForm() { function (data) { preview.innerHTML = '
' + data + '
'; emojify.run($('.editor-preview')[0]); - $('.editor-preview').autolink(); } ); }, 0); @@ -1549,7 +1548,6 @@ $(document).ready(function () { node.append(''); }); }); - $('.markdown').autolink(); $('.issue-checkbox').click(function() { var numChecked = $('.issue-checkbox').children('input:checked').length; diff --git a/public/vendor/plugins/autolink/LICENSE b/public/vendor/plugins/autolink/LICENSE deleted file mode 100644 index bb35e8b86..000000000 --- a/public/vendor/plugins/autolink/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 egoist 0x142857@gmail.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/public/vendor/plugins/autolink/autolink.js b/public/vendor/plugins/autolink/autolink.js deleted file mode 100644 index 2993954ab..000000000 --- a/public/vendor/plugins/autolink/autolink.js +++ /dev/null @@ -1,45 +0,0 @@ -(function () { - var re = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-]*)?\??(?:[\-\+:=&;%@\.\w]*)#?(?:[\.\!\/\\\w]*))?)/g; - function textNodesUnder(node) { - var textNodes = []; - if(typeof document.createTreeWalker === 'function') { - // Efficient TreeWalker - var currentNode, walker; - walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false); - while(currentNode = walker.nextNode()) { - textNodes.push(currentNode); - } - } else { - // Less efficient recursive function - for(node = node.firstChild; node; node = node.nextSibling) { - if(node.nodeType === 3) { - textNodes.push(node); - } else { - textNodes = textNodes.concat(textNodesUnder(node)); - } - } - } - return textNodes; - } - - function processNode(node) { - re.lastIndex = 0; - var results = re.exec(node.textContent); - if(results !== null) { - if($(node).parents().filter('code').length === 0) { - $(node).replaceWith( - $('').html( - node.nodeValue.replace(re, '$1') - ) - ); - } - } - } - - jQuery.fn.autolink = function () { - this.each(function () { - textNodesUnder(this).forEach(processNode); - }); - return this; - }; -})(); diff --git a/routers/api/v1/misc/markdown_test.go b/routers/api/v1/misc/markdown_test.go index c1449589a..f9503bc63 100644 --- a/routers/api/v1/misc/markdown_test.go +++ b/routers/api/v1/misc/markdown_test.go @@ -73,7 +73,7 @@ func TestAPI_RenderGFM(t *testing.T) { `, // wine-staging wiki home extract: special wiki syntax, images @@ -96,7 +96,7 @@ Here are some links to the most important topics. You can find the full list of

Here are some links to the most important topics. You can find the full list of pages at the sidebar.

Configuration -images/icon-bug.png

+images/icon-bug.png

`, // Guard wiki sidebar: special syntax `[[Guardfile-DSL / Configuring-Guard|Guardfile-DSL---Configuring-Guard]]`, diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl index 18d59d92c..c0f5a83d7 100644 --- a/templates/base/footer.tmpl +++ b/templates/base/footer.tmpl @@ -122,7 +122,6 @@ emojiTribute.attach(document.getElementById('content')) {{end}} - From 2cd3622ddc340a67d95e1471f1e13bda383ef95b Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 27 Feb 2018 07:10:26 +0000 Subject: [PATCH 036/106] [skip ci] Updated translations via Crowdin --- options/locale/locale_ru-RU.ini | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 325ec6e84..cb019b90f 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -17,6 +17,7 @@ page=Страница template=Шаблон language=Язык notifications=Уведомления +create_new=Создать… user_profile_and_more=Профиль пользователя и прочее signed_in_as=Вы вошли как enable_javascript=Пожалуйста, включите JavaScript @@ -154,10 +155,12 @@ uname_holder=Имя пользователя или E-mail password_holder=Пароль switch_dashboard_context=Переключить контекст панели управления my_repos=Мои репозитории +show_more_repos=Показать больше репозиториев… collaborative_repos=Совместные репозитории my_orgs=Мои организации my_mirrors=Мои зеркала view_home=Показать %s +search_repos=Поиск репозитория… issues.in_your_repos=В ваших репозиториях @@ -246,6 +249,7 @@ Content=Содержимое require_error=` не может быть пустым.` alpha_dash_error=` должен быть допустимым символьным, числовым значением, или символами _ и -.` alpha_dash_dot_error=` должен содержать только буквы, цифры, или символы ._-` +git_ref_name_error=` должно быть правильным ссылочным именем git.` size_error=` должен быть размер %s.` min_size_error=«должен содержать по крайней мере %s символов.» max_size_error=` должен содержать максимум %s символов.` @@ -331,6 +335,7 @@ enable_custom_avatar=Включить собственный аватар choose_new_avatar=Выбрать новый аватар update_avatar=Обновить настройку аватара delete_current_avatar=Удалить текущий аватар +uploaded_avatar_not_a_image=Загружаемый файл не является изображением. update_avatar_success=Настройка вашего аватара обновлена. change_password=Сменить пароль @@ -560,6 +565,7 @@ editor.fork_before_edit=Создайте ветку репозитория пе editor.delete_this_file=Удалить файл editor.must_have_write_access=Вам необходимо иметь доступ на запись, чтобы вносить или предлагать правки этого файла editor.file_delete_success=Файл «%s» был успешно удален! +editor.name_your_file=Назовите свой файл… editor.filename_help=Чтобы добавить каталог, просто наберите название и нажмите /. Чтобы удалить каталог, перейдите к началу поля и нажмите клавишу backspace. editor.or=или editor.cancel_lower=отмена @@ -568,8 +574,10 @@ editor.add_tmpl=Добавить '%s/' editor.add=Добавить '%s' editor.update=Изменить '%s' editor.delete=Удалить '%s' +editor.commit_message_desc=Добавьте необязательное расширенное описание… editor.commit_directly_to_this_branch=Сделайте коммит прямо в ветку %s. editor.create_new_branch=Создайте новую ветку для этого коммита, и сделайте Pull Request. +editor.new_branch_name_desc=Новое название ветки… editor.cancel=Отмена editor.filename_cannot_be_empty=Имя файла не может быть пустым. editor.branch_already_exists=Ветка «%s» уже существует в этом репозитории. @@ -581,6 +589,7 @@ editor.file_changed_while_editing=Содержимое файла изменил editor.file_already_exists=Файл с именем «%s» уже существует в этом репозитории. editor.no_changes_to_show=Нет изменений. editor.fail_to_update_file=Не удалось обновить/создать файл «%s» из-за ошибки: %v +editor.add_subdir=Добавьте подкаталог… editor.unable_to_upload_files=Не удалось загрузить файлы в «%s» из-за ошибки: %v editor.upload_files_to_dir=Загрузить файлы '%s' editor.cannot_commit_to_protected_branch=Не можете коммитить в защищенную ветку '%s'. @@ -617,6 +626,7 @@ issues.new.no_assignee=Нет ответственного issues.no_ref=Не указана ветка или тэг issues.create=Добавить задачу issues.new_label=Новая метка +issues.new_label_placeholder=Имя метки… issues.create_label=Добавить метку issues.label_templates.title=Загрузить набор предопределённых меток issues.label_templates.info=Меток пока нет. Вы можете нажать на кнопку «Создать метку», чтобы создать новую или использовать одну из готового набора ниже. @@ -887,6 +897,7 @@ settings.tracker_url_format=Внешний формат ссылки систе settings.tracker_issue_style=Стиль Именования Внешней Системы Учета Задач: settings.tracker_issue_style.numeric=Цифровой settings.tracker_issue_style.alphanumeric=Буквенноцифровой +settings.tracker_url_format_desc=Вы можете использовать шаблон {user} {repo} {index} для имени пользователя, репозитория и номера задачи. settings.enable_timetracker=Включить отслеживание времени settings.allow_only_contributors_to_track_time=Учитывать только участников разработки в подсчёте времени settings.pulls_desc=Система Pull Request'ов создана для упрощения совместной работы над репозиторием @@ -903,6 +914,7 @@ settings.convert_confirm=Подтвердите преобразование settings.convert_succeed=Репозиторий успешно преобразован в обычный. settings.transfer=Передать права собственности settings.transfer_desc=Передать репозиторий другому пользователю или организации где у вас есть права администратора. +settings.transfer_notices_1=- Вы можете потерять доступ, если новый владелец является отдельным пользователем. settings.transfer_notices_2=- Вы сохраните доступ, если новым владельцем станет организация, владельцем которой вы являетесь. settings.transfer_form_title=Введите сопутствующую информацию для подтверждения операции: settings.wiki_delete=Стереть данные Вики @@ -926,6 +938,7 @@ settings.delete_collaborator=Удалить settings.collaborator_deletion=Удаление соавтора settings.collaborator_deletion_desc=Этот пользователь больше не будет иметь доступа для совместной работы в этом репозитории после удаления. Вы хотите продолжить? settings.remove_collaborator_success=Соавтор был удален. +settings.search_user_placeholder=Поиск пользователя… settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы. settings.user_is_org_member=Пользователь является членом организации, члены которой не могут быть добавлены в качестве соавтора. settings.add_webhook=Добавить Webhook @@ -1016,6 +1029,7 @@ settings.remove_protected_branch_success=Защита ветки %s была у settings.protected_branch_deletion=Для удаления защищённой ветки settings.protected_branch_deletion_desc=Любой пользователь с разрешениями на запись сможет выполнять push в эту ветку. Вы уверены? settings.default_branch_desc=Главная ветка является "базовой" для вашего репозитория, на которую по умолчанию направлены все Pull Request'ы и которая является лицом вашего репозитория. Первое, что увидит посетитель — это содержимое главной ветки. +settings.choose_branch=Выберите ветку… settings.no_protected_branch=Нет защищённых веток diff.browse_source=Просмотр исходного кода @@ -1049,6 +1063,7 @@ release.title=Заголовок release.content=Содержимое release.write=Редактирование release.preview=Предварительный просмотр +release.loading=Загрузка… release.prerelease_desc=Это предварительный релиз release.prerelease_helper=Отдельно отметим, что этот релиз не готов к использованию в продакшене. release.cancel=Отменить @@ -1162,6 +1177,7 @@ teams.read_permission_desc=Эта команда предоставляет до teams.write_permission_desc=Эта команда предоставляет доступ на Запись: члены могут получать и выполнять push команды в репозитории. teams.admin_permission_desc=Эта команда имеет административный доступ: участники могут читать, редактировать содержимое и выполнять административные функции (например, добавлять соавторов к её репозиториям). teams.repositories=Репозитории группы разработки +teams.search_repo_placeholder=Поиск репозитория… teams.add_team_repository=Добавить репозиторий группы разработки teams.remove_repo=Удалить teams.add_nonexistent_repo=Вы добавляете в отсутствующий репозиторий, пожалуйста сначала его создайте. @@ -1300,6 +1316,7 @@ auths.bind_password_helper=Предупреждение: Этот пароль auths.user_base=База для поиска пользователя auths.user_dn=DN пользователя auths.attribute_username=Имя пользователя +auths.attribute_username_placeholder=Оставьте пустым, чтобы использовать имя пользователя для регистрации. auths.attribute_name=Имя auths.attribute_surname=Фамилия auths.attribute_mail=Email From 8606d9f5bc01fce90159c9bdef9989a31a865e38 Mon Sep 17 00:00:00 2001 From: Allen Wild Date: Fri, 2 Mar 2018 04:09:43 -0500 Subject: [PATCH 037/106] Add admin dashboard option to run health checks (#3606) There's one for git gc, why not git fsck too? Also add a couple more trace logs to GitFsck to see progress --- models/repo.go | 2 ++ options/locale/locale_en-US.ini | 2 ++ routers/admin/admin.go | 4 ++++ templates/admin/dashboard.tmpl | 4 ++++ 4 files changed, 12 insertions(+) diff --git a/models/repo.go b/models/repo.go index ba5b7b36a..cddd57dc3 100644 --- a/models/repo.go +++ b/models/repo.go @@ -2172,6 +2172,7 @@ func GitFsck() { func(idx int, bean interface{}) error { repo := bean.(*Repository) repoPath := repo.RepoPath() + log.Trace(fmt.Sprintf("Running health check for repository %s", repoPath)) if err := git.Fsck(repoPath, setting.Cron.RepoHealthCheck.Timeout, setting.Cron.RepoHealthCheck.Args...); err != nil { desc := fmt.Sprintf("Failed to health check repository (%s): %v", repoPath, err) log.Warn(desc) @@ -2183,6 +2184,7 @@ func GitFsck() { }); err != nil { log.Error(4, "GitFsck: %v", err) } + log.Trace("Finished: GitFsck") } // GitGcRepos calls 'git gc' to remove unnecessary files and optimize the local repository diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a7c338c10..8f1f4f5f5 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1220,6 +1220,8 @@ dashboard.reinit_missing_repos = Reinitialize all missing Git repositories for w dashboard.reinit_missing_repos_success = All missing Git repositories for which records existed have been reinitialized. dashboard.sync_external_users = Synchronize external user data dashboard.sync_external_users_started = External user synchronization started +dashboard.git_fsck = Execute health checks on all repositories +dashboard.git_fsck_started = Repository health checks started dashboard.server_uptime = Server Uptime dashboard.current_goroutine = Current Goroutines dashboard.current_memory_usage = Current Memory Usage diff --git a/routers/admin/admin.go b/routers/admin/admin.go index 39a8f718c..9b18847d6 100644 --- a/routers/admin/admin.go +++ b/routers/admin/admin.go @@ -122,6 +122,7 @@ const ( syncRepositoryUpdateHook reinitMissingRepository syncExternalUsers + gitFsck ) // Dashboard show admin panel dashboard @@ -161,6 +162,9 @@ func Dashboard(ctx *context.Context) { case syncExternalUsers: success = ctx.Tr("admin.dashboard.sync_external_users_started") go models.SyncExternalUsers() + case gitFsck: + success = ctx.Tr("admin.dashboard.git_fsck_started") + go models.GitFsck() } if err != nil { diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index 23fc4a422..9ab23f887 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -49,6 +49,10 @@
+ + + +
images/icon-install.pngimages/icon-install.png Installation
images/icon-usage.pngimages/icon-usage.png Usage
{{.i18n.Tr "admin.dashboard.sync_external_users"}} {{.i18n.Tr "admin.dashboard.operation_run"}}
{{.i18n.Tr "admin.dashboard.git_fsck"}} {{.i18n.Tr "admin.dashboard.operation_run"}}
From f44c31f869bf7dc7018b572b7bfaedca2902a6f8 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 2 Mar 2018 09:11:11 +0000 Subject: [PATCH 038/106] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 942c005b7..fb0e7c282 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -664,7 +664,7 @@ issues.filter_sort.recentupdate=Kürzlich aktualisiert issues.filter_sort.leastupdate=Am längsten nicht aktualisiert issues.filter_sort.mostcomment=Am meisten kommentiert issues.filter_sort.leastcomment=Am wenigsten kommentiert -issues.action_open=Offen +issues.action_open=Öffnen issues.action_close=Schließen issues.action_label=Label issues.action_milestone=Meilenstein From 595da53d3cbc1cec22583ea202e686acfa95c59f Mon Sep 17 00:00:00 2001 From: bugreport0 <32939607+bugreport0@users.noreply.github.com> Date: Fri, 2 Mar 2018 21:31:15 +0100 Subject: [PATCH 039/106] Fix incorrect 'Erase Wiki Data' string identifier. (#3613) --- templates/repo/settings/options.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 3bc1a209f..d5235d070 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -399,7 +399,7 @@ {{if .Repository.UnitEnabled $.UnitTypeWiki}} -
+
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index fd9f4f330..7c353ad30 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -185,7 +185,7 @@ {{end}}
{{.i18n.Tr "admin.config.mailer_user"}}
{{if .Mailer.User}}{{.Mailer.User}}{{else}}(empty){{end}}

- + {{.CsrfTokenHtml}}
diff --git a/templates/explore/code.tmpl b/templates/explore/code.tmpl index 600348621..742ed5944 100644 --- a/templates/explore/code.tmpl +++ b/templates/explore/code.tmpl @@ -2,7 +2,7 @@
{{template "explore/navbar" .}}
- +
diff --git a/templates/explore/search.tmpl b/templates/explore/search.tmpl index 6f37bcb23..906dd06ca 100644 --- a/templates/explore/search.tmpl +++ b/templates/explore/search.tmpl @@ -15,7 +15,7 @@
- +
diff --git a/templates/org/settings/delete.tmpl b/templates/org/settings/delete.tmpl index dc1858e5c..3b0ee09b1 100644 --- a/templates/org/settings/delete.tmpl +++ b/templates/org/settings/delete.tmpl @@ -13,7 +13,7 @@

{{.i18n.Tr "org.settings.delete_prompt" | Str2html}}

- + {{.CsrfTokenHtml}}
diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl index 4503976e0..8a8e2c369 100644 --- a/templates/repo/commits_table.tmpl +++ b/templates/repo/commits_table.tmpl @@ -5,7 +5,7 @@
{{if .PageIsCommits}} - + diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 91db56c98..9f705c967 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -10,7 +10,7 @@
{{if .RepoSearchEnabled}}