Browse Source

Merge branch 'dev' into newcollaboration

pull/900/head
Peter Smit 10 years ago
parent
commit
03af37554e
  1. 8
      .travis.yml
  2. 11
      README.md
  3. 6
      README_ZH.md
  4. 2
      cmd/fix.go
  5. 24
      cmd/web.go
  6. 7
      conf/app.ini
  7. 3
      conf/locale/TRANSLATORS
  8. 17
      conf/locale/locale_en-US.ini
  9. 728
      conf/locale/locale_ja-JP.ini
  10. 124
      conf/locale/locale_ru-RU.ini
  11. 2
      gogs.go
  12. 46
      models/action.go
  13. 16
      models/models.go
  14. 61
      models/publickey.go
  15. 12
      models/repo.go
  16. 1
      models/user.go
  17. 7
      modules/auth/auth.go
  18. 41
      modules/auth/user_form.go
  19. 12
      modules/base/markdown.go
  20. 12
      modules/base/template.go
  21. 30
      modules/base/tool.go
  22. 2
      modules/middleware/auth.go
  23. 2
      modules/setting/setting.go
  24. 16
      public/js/app.js
  25. 23
      public/ng/css/gogs.css
  26. 83
      public/ng/js/gogs.js
  27. 10
      public/ng/js/min/gogs-min.js
  28. 3
      public/ng/less/gogs/repository.less
  29. 2
      public/ng/less/gogs/settings.less
  30. 4
      routers/admin/admin.go
  31. 156
      routers/install.go
  32. 4
      routers/repo/commit.go
  33. 8
      routers/repo/download.go
  34. 4
      routers/repo/view.go
  35. 46
      scripts/init/freebsd/gogs
  36. 2
      scripts/start.bat
  37. 2
      scripts/start.sh
  38. 2
      templates/.VERSION
  39. 2
      templates/admin/config.tmpl
  40. 5
      templates/admin/dashboard.tmpl
  41. 6
      templates/home.tmpl
  42. 48
      templates/install.tmpl
  43. 2
      templates/repo/commits_table.tmpl
  44. 22
      templates/repo/diff.tmpl
  45. 4
      templates/repo/view_list.tmpl
  46. 18
      templates/user/settings/email.tmpl
  47. 2
      templates/user/settings/nav.tmpl

8
.travis.yml

@ -3,5 +3,13 @@ language: go
go:
- 1.2
- 1.3
- 1.4
- tip
sudo: false
script: go build -v
notifications:
email:
- u@gogs.io

11
README.md

@ -1,18 +1,19 @@
Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0bc450ac6f09bc56b9640a50aa/s/ "wercker status")](https://app.wercker.com/project/bykey/ad0bdb0bc450ac6f09bc56b9640a50aa) [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs)
Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs)
=====================
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gogits/gogs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Gogs(Go Git Service) is a painless self-hosted Git Service written in Go.
![Demo](https://gowalker.org/public/gogs_demo.gif)
![Demo](http://gogs.qiniudn.com/gogs_demo.gif)
##### Current version: 0.5.11 Beta
##### Current version: 0.5.12 Beta
### NOTICES
- Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) has been reset in **June 21, 2014** and will reset multiple times after. Please do **NOT** put your important data on the site.
- Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) has been reset in **Jan 28, 2015** and will reset multiple times after. Please do **NOT** put your important data on the site.
- Demo site [try.gogs.io](https://try.gogs.io) is running under `dev` branch.
- If you think there are vulnerabilities in the project, please talk private to **u@gogs.io**, thanks!
#### Other language version
@ -50,7 +51,7 @@ The goal of this project is to make the easiest, fastest and most painless way t
- Drone CI integration
- Supports MySQL, PostgreSQL and SQLite3
- Social account login(GitHub, Google, QQ, Weibo)
- Multi-language support([7 languages](https://crowdin.com/project/gogs))
- Multi-language support([9 languages](https://crowdin.com/project/gogs))
## System Requirements

6
README_ZH.md

@ -3,9 +3,9 @@ Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0b
Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。
![Demo](https://gowalker.org/public/gogs_demo.gif)
![Demo](http://gogs.qiniudn.com/gogs_demo.gif)
##### 当前版本:0.5.11 Beta
##### 当前版本:0.5.12 Beta
## 开发目的
@ -39,7 +39,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- Drone CI 持续部署集成
- 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
- 社交帐号登录(GitHub、Google、QQ、微博)
- 多语言支持([7 种语言]([more](https://crowdin.com/project/gogs)))
- 多语言支持([9 种语言]([more](https://crowdin.com/project/gogs)))
## 系统要求

2
cmd/fix.go

@ -164,7 +164,7 @@ func runFixLocation(ctx *cli.Context) {
fmt.Scanln()
// Fix in authorized_keys file.
sshPath := path.Join(models.SshPath, "authorized_keys")
sshPath := path.Join(models.SSHPath, "authorized_keys")
if com.IsFile(sshPath) {
fmt.Printf("Fixing pathes in file: %s\n", sshPath)
if err := rewriteAuthorizedKeys(sshPath, oldPath, execPath); err != nil {

24
cmd/web.go

@ -53,7 +53,9 @@ var CmdWeb = cli.Command{
Description: `Gogs web server is the only thing you need to run,
and it takes care of all the other things for you`,
Action: runWeb,
Flags: []cli.Flag{},
Flags: []cli.Flag{
cli.StringFlag{"port, p", "3000", "Temporary port number to prevent conflict", ""},
},
}
type VerChecker struct {
@ -75,13 +77,13 @@ func checkVersion() {
// Check dependency version.
checkers := []VerChecker{
{"github.com/Unknwon/macaron", macaron.Version, "0.5.0"},
{"github.com/Unknwon/macaron", macaron.Version, "0.5.1"},
{"github.com/macaron-contrib/binding", binding.Version, "0.0.4"},
{"github.com/macaron-contrib/cache", cache.Version, "0.0.7"},
{"github.com/macaron-contrib/csrf", csrf.Version, "0.0.1"},
{"github.com/macaron-contrib/csrf", csrf.Version, "0.0.3"},
{"github.com/macaron-contrib/i18n", i18n.Version, "0.0.5"},
{"github.com/macaron-contrib/session", session.Version, "0.1.6"},
{"gopkg.in/ini.v1", ini.Version, "1.0.1"},
{"gopkg.in/ini.v1", ini.Version, "1.2.0"},
}
for _, c := range checkers {
ver := strings.Join(strings.Split(c.Version(), ".")[:3], ".")
@ -162,7 +164,7 @@ func newMacaron() *macaron.Macaron {
return m
}
func runWeb(*cli.Context) {
func runWeb(ctx *cli.Context) {
routers.GlobalInit()
checkVersion()
@ -179,9 +181,9 @@ func runWeb(*cli.Context) {
// Routers.
m.Get("/", ignSignIn, routers.Home)
m.Get("/explore", ignSignIn, routers.Explore)
// FIXME: when i'm binding form here???
m.Get("/install", bindIgnErr(auth.InstallForm{}), routers.Install)
m.Post("/install", bindIgnErr(auth.InstallForm{}), routers.InstallPost)
m.Combo("/install", routers.InstallInit).
Get(routers.Install).
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost)
m.Group("", func() {
m.Get("/pulls", user.Pulls)
m.Get("/issues", user.Issues)
@ -460,6 +462,12 @@ func runWeb(*cli.Context) {
// Not found handler.
m.NotFound(routers.NotFound)
// Flag for port number in case first time run conflict.
if ctx.IsSet("port") {
setting.AppUrl = strings.Replace(setting.AppUrl, setting.HttpPort, ctx.String("port"), 1)
setting.HttpPort = ctx.String("port")
}
var err error
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubUrl)

7
conf/app.ini

@ -1,3 +1,6 @@
# NEVER EVER MODIFY THIS FILE
# PLEASE MAKE CHANGES ON CORRESPONDING CUSTOM CONFIG FILE
; App name that shows on every page title
APP_NAME = Gogs: Go Git Service
; Change it if you run locally
@ -275,5 +278,5 @@ INTERVAL = 24
ARGS =
[i18n]
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL,lv-LV,ru-RU
NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands,Latviešu,Русский
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL,lv-LV,ru-RU,ja-JP
NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands,Latviešu,Русский,日本语

3
conf/locale/TRANSLATORS

@ -1,6 +1,9 @@
# This file lists all PUBLIC individuals having contributed content to the translation.
# Order of name is meaningless.
Akihiro YAGASAKI <yaggytter@momiage.com>
Christoph Kisfeld <christoph.kisfeld@gmail.com>
Thomas Fanninger <gogs.thomas@fanninger.at>
Łukasz Jan Niemier <lukasz@niemier.pl>
Lafriks <lafriks@gmail.com>
Miguel de la Cruz <miguel@mcrx.me>

17
conf/locale/locale_en-US.ini

@ -59,6 +59,8 @@ run_user = Run User
run_user_helper = The user must have access to Repository Root Path and run Gogs.
domain = Domain
domain_helper = This affects SSH clone URLs.
http_port = HTTP Port
http_port_helper = Port number which application will listen on.
app_url = Application URL
app_url_helper = This affects HTTP/HTTPS clone URL and somewhere in e-mail.
email_title = E-mail Service Settings (Optional)
@ -512,6 +514,8 @@ dashboard.delete_repo_archives = Delete all repositories archives
dashboard.delete_repo_archives_success = All repositories archives have been deleted successfully.
dashboard.git_gc_repos = Do garbage collection on repositories
dashboard.git_gc_repos_success = All repositories have done garbage collection successfully.
dashboard.resync_all_sshkeys = Rewrite '.ssh/autorized_key' file(caution: non-Gogs keys will be lost)
dashboard.resync_all_sshkeys_success = All public keys have been rewritten successfully.
dashboard.server_uptime = Server Uptime
dashboard.current_goroutine = Current Goroutines
dashboard.current_memory_usage = Current Memory Usage
@ -712,16 +716,3 @@ months = %d months %s
years = %d years %s
raw_seconds = seconds
raw_minutes = minutes

728
conf/locale/locale_ja-JP.ini

@ -0,0 +1,728 @@
app_desc=Go言語で実装したセルフホストGitサーバ
home=ホーム
dashboard=ダッシュボード
explore=エスクプローラ
help=ヘルプ
sign_in=サインイン
social_sign_in=SNSでサインイン: ステップ2 <small>アカウント連携</small>
sign_out=サインアウト
sign_up=サインアップ
register=登録
website=WEBサイト
version=バージョン
page=ページ
template=テンプレート
language=言語
username=ユーザ名
email=E-mail
password=パスワード
re_type=再入力
captcha=キャプチャ
repository=リポジトリ
organization=組織
mirror=ミラー
new_repo=新しいリポジトリ
new_migrate=新しい移行
new_fork=新しいフォークのリポジトリ
new_org=新しい組織
manage_org=組織を管理
admin_panel=管理者パネル
account_settings=アカウント設定
settings=設定
news_feed=ニュースのフィード
pull_requests=プルリクエスト
issues=課題
cancel=キャンセル
[install]
install=インストール
title=初回実行のインストール手順
requite_db_desc=Gogs には、MySQL や PostgreSQL 、SQLite3 が必要です。
db_type=データベースの種類
host=ホスト
user=ユーザ
password=パスワード
db_name=データベース名
db_helper=Mysql INNODB エンジン utf8_general_ci の文字セットを使用してください。
ssl_mode=SSL モード
path=パス
sqlite_helper=SQLite3 データベースのファイル パス
general_title=Gogs の全般設定
repo_path=リポジトリのルートパス
repo_path_helper=すべての Git リモート リポジトリはこのディレクトリに保存されます。
run_user=実行ユーザ
run_user_helper=ユーザーはリポジトリ ルートパスへのアクセス、及びGogs を実行する権限を所有する必要があります。
domain=ドメイン
domain_helper=これはSSHクローンURLに影響する。
app_url=アプリケーションの URL
app_url_helper=この設定は、HTTP / HTTPSのクローンURLおよび、一部のメールボックスへのリンクに影響を与えます。
email_title=E-mailサービス設定(Optional)
smtp_host=SMTP ホスト
mailer_user=送信者の電子メール
mailer_password=送信者のパスワード
notify_title=通知 Settings(Optional)
register_confirm=登録の確認を有効にする
mail_notify=メール通知を有効にする
admin_title=管理者アカウントの設定
admin_name=ユーザ名
admin_password=パスワード
confirm_password=パスワード確認
admin_email=E-mail
install_gogs=Gogs をインストール
test_git_failed='Git' コマンドテストに失敗: %v
sqlite3_not_available=このリリース バージョンは SQLite3 をサポートしていません。gobuild バージョンではない、公式のバイナリ バージョンを %s からダウンロードしてください。
invalid_db_setting=データベースの設定が正しくありません: %v
invalid_repo_path=リポジトリのルート パスが無効です: %v
run_user_not_match=実行ユーザーは、現在のユーザーではない: %s-> %s
save_config_failed=構成の保存に失敗した: %v
invalid_admin_setting=管理者アカウントの設定が無効です: %v
install_success=ようこそ!我々はあなたが Gogs を選んでくれて嬉しいです!楽しみましょう!
[home]
uname_holder=ユーザー名またはEメール
password_holder=パスワード
switch_dashboard_context=ダッシュ ボードのコンテキストを切替
my_repos=私のリポジトリ
collaborative_repos=共同リポジトリ
my_orgs=私の組織
my_mirrors=私のミラー
[explore]
repos=リポジトリ
[auth]
create_new_account=新規アカウントを作成
register_hepler_msg=すでにアカウントをお持ちですか?今すぐログイン !
social_register_hepler_msg=すでにアカウントをお持ちですか?今すぐバインド !
disable_register_prompt=申し訳ありませんが、登録が無効になっています。サイト管理者に問い合わせてください。
disable_register_mail=申し訳ありませんが、登録メールの確認機能が無効になっています。
remember_me=ログイン状態を保持する
forgot_password=パスワードを忘れた
forget_password=パスワードを忘れた?
sign_up_now=アカウントが必要ですか?今すぐサインアップ
confirmation_mail_sent_prompt=新しい確認メールを <b>%s</b> に送りました。登録を完了させるために、%d時間以内にあなたのメールボックスを確認してください。
sign_in_email=E-mailでサイイン
active_your_account=アカウントをアクティブ
resent_limit_prompt=申し訳ありませんが、アクティベーションメールは頻繁に送信しています。3 分お待ちください。
has_unconfirmed_mail=こんにちは %s さん、あなたの電子メール アドレス (<b>%s</b>) は未確認です。もし確認メールをまだ確認できていないか、改めて再送信する場合は、下のボタンをクリックしてください。
resend_mail=アクティベーションメールを再送信するにはここをクリック
email_not_associate=この電子メール アドレスは、アカウントには関連付けられません。
send_reset_mail=パスワードリセットのメールを再送するにはここをクリック
reset_password=パスワードリセット
invalid_code=申し訳ありませんが、確認用コードが期限切れまたは無効です。
reset_password_helper=パスワードをリセットするにはここをクリック
password_too_short=6文字未満のパスワードは設定できません。
[form]
UserName=ユーザ名
RepoName=リポジトリ名
Email=Eメールアドレス
Password=パスワード
Retype=パスワードを再入力
SSHTitle=SSH キーの名前
HttpsUrl=HTTPS URL
PayloadUrl=ペイロードの URL
TeamName=チーム名
AuthName=承認名
AdminEmail=管理者の電子メール
require_error=空にできません
alpha_dash_error=アルファベット、数字、ハイフン"-"、アンダースコア"_"のいずれかの必要があります
alpha_dash_dot_error=' アルファベット、数値、ダッシュ(-)、アンダースコア(_) 、ドット(.)のいずれかを入力する必要があります。 '
min_size_error=' 少なくとも %s 文字の必要があります '
max_size_error=' %s 文字以下の必要があります '
email_error=' は有効な電子メール アドレスではない '
url_error=' は有効な URL はありません。 '
unknown_error=不明なエラー:
captcha_incorrect=Captcha が一致しませんでした。
password_not_match=パスワードと確認用パスワードが一致同していません。
username_been_taken=ユーザー名は既に使用されています。
repo_name_been_taken=リポジトリ名は既に使用されています。
org_name_been_taken=組織名は既に使用されています。
team_name_been_taken=チーム名は既に使用されています。
email_been_used=電子メール アドレスは既に使用されています。
ssh_key_been_used=パブリック キー名が使用されています。
illegal_username=あなたのユーザ名に無効な文字が含まれます。
illegal_repo_name=リポジトリ名には無効な文字が含まれています。
illegal_org_name=組織名に無効な文字が含まれています。
illegal_team_name=チーム名に無効な文字が含まれています。
username_password_incorrect=ユーザー名またはパスワードが正しくありません。
enterred_invalid_repo_name=入力したリポジトリの名前が正しいかどうかを確認してください。
enterred_invalid_owner_name=入力された所有者名が正しいかどうかを確認してください。
enterred_invalid_password=入力したパスワードが正しいかを確認してください。
user_not_exist=指定されたユーザーは存在しません。
last_org_owner=削除するユーザーはチームの最後のメンバーです。別の所有者設定が必要です。
invalid_ssh_key=SSHを確認できません:%s
unable_verify_ssh_key=GogsはあなたのSSH keyを確認できません。しかし、我々は有効とみなしますので、自分自身で確認してください。
auth_failed=認証に失敗しました: %v
still_own_repo=アカウント所有のリポジトリがあり、リポジトリの削除または所有者の移譲が必要です。
still_has_org=アカウントはまだ組織のメンバーであり、組織から退出するか削除する必要があります。
org_still_own_repo=この組織はまだリポジトリの所有しています、リポジトリを削除または転送する必要があります。
still_own_user=この認証はまだ一部のユーザーによって使用されています。一部のユーザを移動させてから、もう一度削除してください。
target_branch_not_exist=ターゲットブランチが存在しない
[user]
change_avatar=gravatar.com で自分のアバターを変更
change_custom_avatar=設定で自分のアバターを変更
join_on=参加しました
repositories=リポジトリ
activity=パブリック・アクティビティ
followers=フォロワー
starred=スター
following=フォロー
[settings]
profile=プロフィール
password=パスワード
ssh_keys=SSH キー
social=SNSアカウント
applications=アプリケーション
orgs=組織
delete=アカウントを削除
uid=Uid
public_profile=パブリック プロフィール
profile_desc=あなたのメールアドレスは公開され、任意のアカウント関連の通知に使用されます。また、Webベースの操作はサイトを介して行います。
full_name=フルネーム
website=WEBサイト
location=ロケーション
update_profile=プロファイル更新
update_profile_success=あなたのプロフィールが更新されました。
change_username=ユーザー名が変更されました
change_username_desc=ユーザー名が変更されている、継続したいですか?これはあなたのアカウントに関連するすべてのリンクに影響を与える。
continue=続行
cancel=キャンセル
enable_custom_avatar=カスタムのアバターを有効にする
enable_custom_avatar_helper=Gravatarからのフェッチを無効にするのを、有効にします
choose_new_avatar=新しいアバターを選択
update_avatar=アバターの設定を更新
uploaded_avatar_not_a_image=アップロードされたファイルは画像ではない。
no_custom_avatar_available=利用可能なカスタム アバターがないため、有効にできません。
update_avatar_success=あなたのアバターの設定が更新されました。
change_password=パスワードを変更
old_password=現在のパスワード
new_password=新しいパスワード
password_incorrect=現在のパスワードが正しくありません。
change_password_success=パスワードが正常に変更されました。今すぐ新しいパスワード経由でサインインすることができます。
emails=E-mail アドレス
manage_emails=E-mail アドレスを管理
email_desc=あなたのプライマリメールアドレスは、通知やその他の操作に使用されます。
primary=プライマリー
primary_email=プライマリに設定
delete_email=削除
add_new_email=新しいe-mailアドレスを追加
add_email=電子メールを追加します。
add_email_success=新しいe-mail アドレスが追加されました。
manage_ssh_keys=SSH キーを管理
add_key=キーを追加
ssh_desc=これはあなたのアカウントに関連付けられている SSH キーの一覧です。あなたが認識していないキーを削除します。
ssh_helper=<strong>ヘルプが必要ですか?</strong> 我々のガイドをご覧ください。 <a href="%s"> SSH キーを生成</a> <a href="%s"> SSH の一般的な問題</a>
add_new_key=SSH キーを追加
key_name=キーの名前
key_content=コンテンツ
add_key_success=新しい SSH キーが追加されました !
delete_key=削除
add_on=追加された
last_used=最終使用日
no_activity=最近の活動なし
manage_social=関連付けられているSNSアカウントを管理
social_desc=これは関連付けられたソーシャルアカウントのリストです。あなたが認識していない結び付けを削除します。
unbind=バインド解除
unbind_success=SNSアカウントがバインドされていない。
manage_access_token=個人のアクセス トークンを管理
generate_new_token=新しいトークンを生成
tokens_desc=生成したトークンを利用して Gogs の API にアクセスすることができます。
new_token_desc=今のところ、全てのトークンはあなたのアカウントにフルアクセスできます。
token_name=トークン名
generate_token=トークンを生成
generate_token_succees=新しいアクセス トークンは正常に生成されました !今すぐあなたの新しいアクセス トークンをコピーしておいてください。二度と見ることはできませんので確認してください!
delete_token=削除
delete_token_success=個人のアクセス トークンは正常に削除されました!同時にあなたのアプリケーションを更新することを忘れないでください。
delete_account=アカウントを削除
delete_prompt=この操作はあなたのアカウントを完全に削除し、復旧<strong>できない</strong> !
confirm_delete_account=削除の確認
delete_account_title=アカウントの削除
delete_account_desc=このアカウントは永久に削除しようとしている、継続しますか?
[repo]
owner=オーナー
repo_name=リポジトリ名
repo_name_helper=偉大なリポジトリ名は短い。思い出に残り、そして<strong>一意</strong>だ。
visibility=ビジビリティ
visiblity_helper=このリポジトリは <span class="label label-red label-radius"> プライベート</span> です。
fork_repo=フォークのリポジトリ
fork_from=フォーク元
fork_visiblity_helper=フォークされたリポジトリは可視状態を変更できません
repo_desc=説明
repo_lang=言語
repo_lang_helper=.gitignore ファイルを選択
license=ライセンス
license_helper=ライセンス ファイルを選択
init_readme=README.md 付きでリポジトリを初期化
create_repo=リポジトリを作成
default_branch=デフォルトのブランチ
mirror_interval=ミラー 間隔(時)
goget_meta=Go-Get メタ
goget_meta_helper=このリポジトリは <span class="label label-blue label-radius"> Go-Getable </span> になります
need_auth=認証が必要
migrate_type=マイグレーションの種類
migrate_type_helper=このリポジトリは <span class="label label-blue label-radius"> ミラー</span> になります
migrate_repo=リポジトリを移行
copy_link=コピー
click_to_copy=クリップボードにコピー
copied=コピー成功
clone_helper=クローニングのヘルプが必要ですか?<a target="_blank"href="%s"> ヘルプ</a> を参照してください!
unwatch=Unwatch
watch=Watch
unstar=Unstar
star=Star
fork=Fork
no_desc=説明なし
quick_guide=クイック ガイド
clone_this_repo=このリポジトリのクローンを作成
create_new_repo_command=コマンドラインで新しいリポジトリを作成します。
push_exist_repo=コマンド ・ ラインから既存のリポジトリをプッシュ
branch=ブランチ
tree=ツリー
branch_and_tags=ブランチ& タグ
branches=ブランチ
tags=タグ
issues=課題
commits=コミット
releases=リリース
file_raw=生データ
file_history=履歴
file_view_raw=生データを見る
commits.commits=コミット
commits.search=コミットの検索
commits.find=検索
commits.author=作者
commits.message=メッセージ
commits.date=日付
commits.older=古い
commits.newer=新しい
settings=設定
settings.options=オプション
settings.collaboration=コラボレーション
settings.hooks=Webhooks
settings.githooks=Git のフック
settings.deploy_keys=デプロイキー
settings.basic_settings=基本設定
settings.danger_zone=危険地帯
settings.site=公式サイト
settings.update_settings=設定の更新
settings.change_reponame=リポジトリ名が変更されました
settings.change_reponame_desc=リポジトリの名前が変更されています、継続しますか?このリポジトリ関連すべてのリンクに影響を与えます。
settings.transfer=オーナー移転
settings.transfer_desc=リポジトリをあなたが管理者権限を持っている別のユーザーまた組織に移譲します。
settings.new_owner_has_same_repo=新しいオーナーは、既に同じ名前のリポジトリを持っています。
settings.delete=このリポジトリを削除
settings.delete_desc=リポジトリを削除すると元に戻せません。確実に確認してください。
settings.transfer_notices=<p>-新オーナーは個人ユーザの場合、あなたはにアクセスできなくなります。</p><p>-新オーナーは組織であり、かつあなたが組織のオーナーに所属する場合、あなたはアクセス権を維持します。</p>
settings.update_settings_success=リポジトリ オプションが更新されました。
settings.transfer_owner=新しいオーナー
settings.make_transfer=転送
settings.transfer_succeed=リポジトリの所有権は正常に転送されました。
settings.confirm_delete=削除の確認
settings.add_collaborator=新しい共同編集者を追加
settings.add_collaborator_success=新しい共同編集者が追加されました。
settings.remove_collaborator_success=共同編集者が削除されました。
settings.user_is_org_member=ユーザーは組織の一員なので、共同編集者として追加することはできません。
settings.add_webhook=Webhook を追加
settings.hooks_desc=Webhooksは、Gogsで特定のイベントの発生時に指定された外部サービスに通知を許可します。イベントが発生すると、それぞれ指定されたUrlに、POSTリクエストが送られます。詳細はこちらのの <a target="_blank"href="%s"> Webhooks ガイド</a>をご覧ください。
settings.githooks_desc=Git のフックは Git 自体によって提供されています。以下のリストのファイルを編集して、サポートされているフックのカスタム操作を適用することができます。
settings.githook_edit_desc=もしフックがアクティブではない場合は、サンプルコンテンツが表示されます。コンテンツを空白にするにはこのフックを無効にします。
settings.githook_name=フックの名前
settings.githook_content=コンテンツをフック
settings.update_githook=フックを更新
settings.remove_hook_success=Webhookが削除されました。
settings.add_webhook_desc=私たちは、指定されたURLに購読されたイベントの詳細を <code>POST</code>リクエストとして送信します。あなたは、異なるデータ受信モード(JSONまたは, <code>x-www-form-urlencoded</code>, <em>その他</em>) を設定することができます。詳細については、<a target="_blank" href="%s">Webhookガイド</a>を参照してください。
settings.payload_url=ペイロードの URL
settings.content_type=コンテンツ タイプ
settings.secret=秘密
settings.event_desc=どのイベントをこのWEBフックのトリガーにしますか?
settings.event_push_only=<code>push</code> イベントのみ
settings.active=アクティブ
settings.active_helper=このフックのトリガーが引かれた時に、イベントの詳細を配信します。
settings.add_hook_success=新しい webhook が追加されました。
settings.update_webhook=Webhookを更新
settings.update_hook_success=Webhook を更新しました。
settings.delete_webhook=Webhook を削除
settings.recent_deliveries=最近のデリバリー
settings.hook_type=フックタイプ
settings.add_slack_hook_desc=<a href="%s"> Slack</a> インテグレーションをリポジトリに追加します。
settings.slack_token=トークン
settings.slack_domain=ドメイン
settings.slack_channel=チャンネル
diff.browse_source=ソースを参照
diff.parent=
diff.commit=コミット
diff.data_not_available=差分データは利用できません。
diff.show_diff_stats=差分情報を表示
diff.stats_desc=共有<strong>%d 個のファイルを変更した</strong>、<strong>%d 個の追加</strong> と <strong>%d 個の削除</strong>を含む
diff.bin=BIN
diff.view_file=ファイルの表示
release.releases=リリース
release.new_release=新しいリリース
release.draft=ドラフト
release.prerelease=プレリリース
release.stable=安定
release.edit=編集
release.ahead=このリリース以降 %s へ <strong>%d</strong> コミット
release.source_code=ソース コード
release.tag_name=タグ名
release.target=ターゲット
release.tag_helper=既存のタグを選択するか、新しいタグを作成し発行します。
release.release_title=リリース タイトル
release.content_with_md=<a href="%s"> Markdown</a> コンテンツ
release.write=書込み
release.preview=プレビュー
release.content_placeholder=コンテンツを書く
release.loading=読み込み中…
release.prerelease_desc=これはリリース前のものです
release.prerelease_helper=このリリースは非プロダクション利用として識別します。
release.publish=リリースを発行
release.save_draft=下書きを保存
release.edit_release=リリースを編集
release.tag_name_already_exist=このタグ名には既にリリースが存在します。
[org]
org_name_holder=組織名
org_name_helper=偉大な組織の名は短く覚えやすいです。
org_email_helper=組織の電子メールはすべての通知や確認を受け取ります。
create_org=組織を作成
repo_updated=更新した
people=人々
invite_someone=誰かを招待
teams=チーム
lower_members=メンバー
lower_repositories=リポジトリ
create_new_team=新しいチームを作成
org_desc=説明
team_name=チーム名
team_desc=説明
team_name_helper=会話の時、この名前を使用しチーム名を表明します。
team_desc_helper=このチームに関する全ての情報は?
team_permission_desc=このチームに必要な権限レベルは?
settings=設定
settings.options=オプション
settings.full_name=フルネーム
settings.website=WEBサイト
settings.location=ロケーション
settings.update_settings=設定の更新
settings.change_orgname=組織名が変更されました
settings.change_orgname_desc=組織名が変更されています、継続しますか?これはすべての関連リンクに影響を与えます。
settings.update_setting_success=組織の設定が更新されました。
settings.delete=組織を削除
settings.delete_account=この組織を削除
settings.delete_prompt=操作はこの組織を完全に削除し、復旧<strong>できない</strong>!
settings.confirm_delete_account=削除の確認
settings.delete_org_title=組織の削除
settings.delete_org_desc=この組織は完全に削除されます、継続しますか?
settings.hooks_desc=この組織のもとで <strong>すべてのリポジトリ</strong> に対してトリガーされる webhook を追加します。
members.public=パブリック
members.public_helper=プライベートにする
members.private=プライベート
members.private_helper=公開する
members.owner=オーナー
members.member=メンバー
members.conceal=隠す
members.remove=削除
members.leave=退出
members.invite_desc=%s に招待する新しいメンバーをユーザ名を入力してください:
members.invite_now=今すぐ招待
teams.join=参加
teams.leave=退出
teams.read_access=読み取りアクセス権
teams.read_access_helper=このチームはリポジトリの閲覧とクローンをすることができます。
teams.write_access=書き込みアクセス権
teams.write_access_helper=このチームはリポジトリを読むだけではなく、プッシュすることもできます。
teams.admin_access=管理者のアクセス権
teams.admin_access_helper=このチームはリポジトリにプッシュ/プル、及び他の共同編集者を追加することができます。
teams.no_desc=このチームは説明がありません。
teams.settings=設定
teams.owners_permission_desc=オーナーは<strong>すべてのリポジトリ</strong> へのフルアクセス権、組織の <strong>管理権限</strong>を持ちます。
teams.members=チーム メンバー
teams.update_settings=設定の更新
teams.delete_team=このチームを削除
teams.add_team_member=チーム メンバーを追加
teams.delete_team_title=チームの削除
teams.delete_team_desc=このチームを削除します、継続しますか?このチームのメンバーはいくつかのリポジトリへのアクセスを失う可能性があります。
teams.delete_team_success=指定のチームが正常に削除されました。
teams.read_permission_desc=このチームは<strong>読み取り</strong>権限を持ち: メンバーはリポジトリの表示及びクローンの作成ができます。
teams.write_permission_desc=このチームは<strong>書き込み</strong>権限を持ち: メンバーはリポジトリの表示及リポジトリへのプッシュができます。
teams.admin_permission_desc=このチームは<strong>管理者</strong>の権限を持ち: メンバーはチームのリポジトリに対して、読み取り、プッシュや共同編集者の追加ができます。
teams.repositories=チームのリポジトリ
teams.add_team_repository=チームのリポジトリを追加
teams.remove_repo=削除(Remove)
teams.add_nonexistent_repo=追加しようとしているリポジトリは存在しません。まずはじめに作成してください。
[admin]
dashboard=ダッシュボード
users=ユーザ
organizations=組織
repositories=リポジトリ
authentication=認証
config=コンフィギュレーション
notices=システム通知
monitor=モニタリング
prev=前へ
next=次へ
dashboard.statistic=統計
dashboard.operations=操作
dashboard.system_status=システム モニターのステータス
dashboard.statistic_info=Gogs データベースは <b>%d</b> ユーザ, <b>%d</b> 組織, <b>%d</b> 公開鍵, <b>%d</b> リポジトリ, <b>%d</b> ウォッチ, <b>%d</b> スター, <b>%d</b> 行動, <b>%d</b> アクセス, <b>%d</b> 問題, <b>%d</b> コメント, <b>%d</b> ソーシャルアカウント, <b>%d</b> フォロー, <b>%d</b> ミラー, <b>%d</b> リリース, <b>%d</b> ログイン元, <b>%d</b> webhook, <b>%d</b> マイルストーン, <b>%d</b> ラベル, <b>%d</b> フックタスク, <b>%d</b> チーム, <b>%d</b> アップデートタスク, <b>%d</b> 添付ファイル の情報を持っています。
dashboard.operation_name=操作の名前
dashboard.operation_switch=スイッチ
dashboard.operation_run=実行
dashboard.clean_unbind_oauth=結び付けられていない OAuth をクリーン
dashboard.clean_unbind_oauth_success=結び付けられていない全ての OAuth を正常に削除しました。
dashboard.delete_inactivate_accounts=非アクティブのアカウントをすべて削除
dashboard.delete_inactivate_accounts_success=すべての非アクティブアカウントは正常に削除されました。
dashboard.delete_repo_archives=リポジトリのすべてのアーカイブを削除
dashboard.delete_repo_archives_success=リポジトリのすべてのアーカイブが正常に削除されました。
dashboard.git_gc_repos=リポジトリでのガベージコレクションを実行します。
dashboard.git_gc_repos_success=すべてのリポジトリは正常にガベージ コレクションを行いました。
dashboard.server_uptime=サーバーの稼働時間
dashboard.current_goroutine=現在のGoroutine
dashboard.current_memory_usage=現在のメモリ使用量
dashboard.total_memory_allocated=割り当てられたメモリの合計
dashboard.memory_obtained=配分されたメモリ量
dashboard.pointer_lookup_times=ポインタ参照回数
dashboard.memory_allocate_times=メモリ割当回数
dashboard.memory_free_times=メモリ解放回数
dashboard.current_heap_usage=現在のヒープ使用量
dashboard.heap_memory_obtained=配分されたヒープ メモリ量
dashboard.heap_memory_idle=アイドルのヒープ メモリ量
dashboard.heap_memory_in_use=使用中のヒープ メモリ
dashboard.heap_memory_released=ヒープ メモリが解放されました
dashboard.heap_objects=ヒープ オブジェクト
dashboard.bootstrap_stack_usage=ブートストラップスタック使用量
dashboard.stack_memory_obtained=配分されたスタック メモリ量
dashboard.mspan_structures_usage=MSpan 構造体の使用量
dashboard.mspan_structures_obtained=配分されたMSpan 構造体
dashboard.mcache_structures_usage=MCache 構造体の使用量
dashboard.mcache_structures_obtained=分配されたMCache 構造体
dashboard.profiling_bucket_hash_table_obtained=ハッシュテーブル分析に割り当てられたメモリ
dashboard.gc_metadata_obtained=GCメタデータ取得
dashboard.other_system_allocation_obtained=他のシステムに割り当てられたメモリ
dashboard.next_gc_recycle=次回のGCリサイクル
dashboard.last_gc_time=前回GCからの時間
dashboard.total_gc_time=GC一時停止の合計
dashboard.total_gc_pause=GC一時停止の合計
dashboard.last_gc_pause=直近のGC一時停止
dashboard.gc_times=GC実行回数
users.user_manage_panel=ユーザー管理パネル
users.new_account=新規アカウントを作成
users.name=名前
users.activated=アクティブ化
users.admin=アドミン
users.repos=リポジトリ
users.created=作成されました
users.edit=編集
users.auth_source=認証元
users.local=ローカル
users.auth_login_name=認証ログイン名
users.update_profile_success=アカウントのプロファイルが更新されました。
users.edit_account=アカウントの編集
users.is_activated=アカウントがアクティブされました
users.is_admin=このアカウントには管理者の権限を持つ
users.allow_git_hook=このアカウントには Git のフックを作成する権限を持つ
users.update_profile=アカウント ・ プロファイルを更新
users.delete_account=このアカウントを削除
users.still_own_repo=アカウント所有のリポジトリがあり、リポジトリの削除または所有者の移譲が必要です。
users.still_has_org=アカウントはまだ組織のメンバーであり、組織から退出するか削除する必要があります。
orgs.org_manage_panel=組織の管理パネル
orgs.name=名前
orgs.teams=チーム
orgs.members=メンバー
repos.repo_manage_panel=リポジトリの管理パネル
repos.owner=オーナー
repos.name=名前
repos.private=プライベート
repos.watches=Watches
repos.stars=Stars
repos.issues=課題
auths.auth_manage_panel=承認の管理パネル
auths.new=新しい認証元を追加
auths.name=名前
auths.type=タイプ
auths.enabled=Enabled
auths.updated=Updated
auths.auth_type=認証の種類
auths.auth_name=認証名
auths.domain=ドメイン
auths.host=ホスト
auths.port=ポート
auths.base_dn=ベースのドメイン名
auths.attributes=属性検索
auths.filter=検索フィルター
auths.ms_ad_sa=Ms Ad SA
auths.smtp_auth=SMTP 認証の種類
auths.smtphost=SMTP ホスト
auths.smtpport=SMTP ポート
auths.enable_tls=TLS 暗号化を有効にする
auths.enable_auto_register=自動登録を有効にする
auths.tips=ヒント
auths.edit=認証設定を編集
auths.activated=認証がアクティブされました
auths.update_success=認証の設定が正常に更新されました。
auths.update=認証設定の更新
auths.delete=この権限を削除
auths.delete_auth_title=認証の削除
auths.delete_auth_desc=認証を削除します、継続しますか?
config.server_config=サーバーの構成
config.app_name=アプリケーション名
config.app_ver=アプリケーションのバージョン
config.app_url=アプリケーションの URL
config.domain=ドメイン
config.offline_mode=オフラインモード
config.disable_router_log=ルーターのログを無効にする
config.run_user=実行ユーザ
config.run_mode=実行モード
config.repo_root_path=リポジトリのルートパス
config.static_file_root_path=静的ファイルのルートパス
config.log_file_root_path=ログ ファイルのルート パス
config.script_type=スクリプトの種類
config.reverse_auth_user=リバース認証ユーザ
config.db_config=データベースの構成
config.db_type=タイプ
config.db_host=ホスト
config.db_name=名前
config.db_user=ユーザ
config.db_ssl_mode=SSL モード
config.db_ssl_mode_helper=(「postgres」のみ)
config.db_path=パス
config.db_path_helper=(「sqlite3」のみ)
config.service_config=サービスの構成
config.register_email_confirm=電子メールの確認を必要
config.disable_register=登録を無効にする
config.require_sign_in_view=サインインを要求
config.mail_notify=メール通知
config.enable_cache_avatar=アバターのキャッシュを有効にします。
config.active_code_lives=コードリンクの有効期限をアクティブ
config.reset_password_code_lives=パスワードリンクの有効期限をリセット
config.webhook_config=Webhook設定
config.task_interval=タスクの間隔
config.deliver_timeout=送信タイムアウト
config.mailer_config=メーラーの構成
config.mailer_enabled=有効にした
config.mailer_name=名前
config.mailer_host=ホスト
config.mailer_user=ユーザ
config.oauth_config=OAuth 構成
config.oauth_enabled=Enabled
config.cache_config=キャッシュの構成
config.cache_adapter=キャッシュ アダプター
config.cache_interval=キャッシュ間隔
config.cache_conn=キャッシュ接続
config.session_config=セッションの構成
config.session_provider=セッション プロバイダー
config.provider_config=プロバイダーの構成
config.cookie_name=クッキー名
config.enable_set_cookie=クッキーの設定を有効にする
config.gc_interval_time=GC 間隔
config.session_life_time=セッションのライフタイム
config.https_only=HTTPS のみ
config.cookie_life_time=クッキーのライフタイム
config.picture_config=画像構成
config.picture_service=画像サービス
config.disable_gravatar=グラバターを無効にする
config.log_config=ログの構成
config.log_mode=ログ モード
monitor.cron=Cron タスク
monitor.name=名前
monitor.schedule=スケジュール
monitor.next=次回
monitor.previous=前回
monitor.execute_times=実行回数
monitor.process=実行中のプロセス
monitor.desc=説明
monitor.start=開始日時
monitor.execute_time=実行時間:
notices.system_notice_list=システム通知
notices.type=タイプ
notices.type_1=リポジトリ
notices.desc=説明
notices.op=Op。
notices.delete_success=システム通知が正常に削除されました。
[action]
create_repo=リポジトリ <a href="%s/%s"> %s</a>を作成しました
commit_repo=<a href="%s/%s">%s</a>を<a href="%s/%s/src/%s">%s</a>にプッシュしました
create_issue=問題 <a href="%s/%s/issues/%s"> %s #%s</a> を開きました
comment_issue=問題 <a href="%s/%s/issues/%s"> %s #%s</a> のコメント
transfer_repo=リポジトリ <code>%s</code> を <a href="/%s%s">%s</a> へ転送しました
push_tag=<a href="%s/%s">%s</a> に タグ <a href="%s/%s/src/%s">%s</a> をプッシュしました
compare_2_commits=これら 2 のコミットの比較を閲覧する
[tool]
ago=
from_now=今から
now=
1s=1 秒 %s
1m=1 分 %s
1h=1 時間 %s
1d=1 日 %s
1w=1 週間 %s
1mon=1 ヶ月 %s
1y=1 年間 %s
seconds=%d 秒 %s
minutes=%d 分の %s
hours=%d 時間 %s
days=%d 日 %s
weeks=%d 週間 %s
months=%d ヶ月 %s
years=%d 年 %s
raw_seconds=
raw_minutes=

124
conf/locale/locale_ru-RU.ini

@ -61,7 +61,7 @@ domain=Домен
domain_helper=This affects SSH clone URLs.
app_url=URL приложения
app_url_helper=This affects HTTP/HTTPS clone URL and somewhere in e-mail.
email_title=E-mail Service Settings (Optional)
email_title=Настройки службы электронной почты (опционально)
smtp_host=Узел SMTP
mailer_user=Электронная почта отправителя
mailer_password=Пароль отправителя
@ -75,7 +75,7 @@ confirm_password=Подтвердить пароль
admin_email=Эл. почта
install_gogs=Установить Gogs
test_git_failed=Не удалось проверить 'git' команду: %v
sqlite3_not_available=Your release version does not support SQLite3, please download the official binary version from %s, NOT the gobuild version.
sqlite3_not_available=Ваша версия не поддерживает SQLite3, пожалуйста скачайте официальную бинарную версию от %s, а не версию gobuild.
invalid_db_setting=Настройки базы данных не правильные: %v
invalid_repo_path=Недопустимый путь к корню репозитория: %v
run_user_not_match=Run user isn't the current user: %s -> %s
@ -98,9 +98,9 @@ repos=Репозитории
[auth]
create_new_account=Создать новый аккаунт
register_hepler_msg=Уже есть аккаунт? Авторизуйтесь!
social_register_hepler_msg=Уже есть учетная запись? Свяжите ее соцсетью!
social_register_hepler_msg=Уже есть учетная запись? Свяжите ее с соцсетью!
disable_register_prompt=Извините, возможность регистрации отключена. Пожалуйста, свяжитесь с администратором сайта.
disable_register_mail=Sorry, Register Mail Confirmation has been disabled.
disable_register_mail=К сожалению подтверждение регистрации по почте отключено.
remember_me=Запомнить меня
forgot_password=Забыли пароль
forget_password=Забыли пароль?
@ -109,7 +109,7 @@ confirmation_mail_sent_prompt=Новое письмо для подтвержд
sign_in_email=Войдите в свой адрес электронной почты
active_your_account=Активируйте свой аккаунт
resent_limit_prompt=Вы слишком часто отправляете письмо с активацией. Подождите 3 минуты, пожалуйста.
has_unconfirmed_mail=Hi %s, you have an unconfirmed e-mail address <b>%s</b>). If you haven't received a confirmation e-mail or need to resend a new one, please click on the button below.
has_unconfirmed_mail=Здравствуйте, %s! У вас есть неподтвержденный адрес электронной почты (<b>%s</b>). Если вам не приходило письмо с подтверждением или нужно выслать новое письмо, нажмите на кнопку ниже.
resend_mail=Нажмите здесь, чтобы переотправить активационное письмо
email_not_associate=Этот адрес электронной почты не связан ни с одной учетной записью.
send_reset_mail=Нажмите сюда, чтобы отправить письмо для сброса пароля
@ -157,17 +157,17 @@ enterred_invalid_repo_name=Пожалуйста, убедитесь, что вв
enterred_invalid_owner_name=Убедитесь, что введенное имя владельца верное.
enterred_invalid_password=Убедитесь, что введенный пароль верен.
user_not_exist=Данный пользователь не существует.
last_org_owner=The user to remove is the last member in owner team. There must be another owner.
last_org_owner=Удаляемый пользователь является последним в команде владельцев. Должен быть хотя бы один владелец.
invalid_ssh_key=К сожалению, мы не смогли проверить ваш SSH-ключ: %s
unable_verify_ssh_key=Gogs не может проверить ваш SSH-ключ, но мы допускаем, что он действителен. Пожалуйста, удостоверьтесь самостоятельно, что ключ действителен.
auth_failed=Ошибка аутентификации: %v
still_own_repo=Your account still have ownership of repository, you have to delete or transfer them first.
still_has_org=Your account still have membership of organization, you have to left or delete them first.
still_own_repo=На вашем аккаунте все еще остается как минимум один репозиторий, сначала вам нужно удалить или передать его.
still_has_org=Вы находитесь в организации, сперва Вам необходимо покинуть ее или удалить.
org_still_own_repo=Данная организация все еще является владельцем репозиториев, необходимо удалить или переместить их в начале.
still_own_user=This authentication still has used by some users, you should move them and then delete again.
still_own_user=Эта проверка подлинности по-прежнему используется некоторыми пользователями, вы должны переместить их и затем снова удалить.
target_branch_not_exist=Целевая ветка не существует
@ -192,7 +192,7 @@ delete=Удалить аккаунт
uid=UID
public_profile=Открытый профиль
profile_desc=Your E-mail address is public and will be used for any account related notifications, and any web based operations made via the site.
profile_desc=Адрес вашей электронной почты является публичным и будет использован для любых уведомлений, связанных с аккаунтом, а также для любых действий, совершенных через сайт.
full_name=ФИО
website=Веб-сайт
location=Местоположение
@ -217,15 +217,15 @@ new_password=Новый пароль
password_incorrect=Текущий пароль не правильный.
change_password_success=Пароль сменен успешно. Теперь вы можете войти с новым паролем.
emails=E-mail Addresses
manage_emails=Manage e-mail addresses
email_desc=Your primary e-mail address will be used for notifications and other operations.
primary=Primary
primary_email=Set as primary
delete_email=Delete
add_new_email=Add new e-mail address
add_email=Add e-mail
add_email_success=Your new E-mail address was successfully added.
emails=Адреса электронной почты
manage_emails=Управление адресами электронной почты
email_desc=Ваш основной адрес электронной почты будет использован для уведомлений и других операций.
primary=Основной
primary_email=Установить как основной
delete_email=Удалить
add_new_email=Добавить новый адрес электронной почты
add_email=Добавить электронную почту
add_email_success=Новый адрес электронной почты успешно добавлен.
manage_ssh_keys=Управление SSH ключами
add_key=Добавить ключ
@ -240,20 +240,20 @@ add_on=Добавлено
last_used=Последний раз использовался
no_activity=Еще не применялся
manage_social=Manage Associated Social Accounts
social_desc=This is a list of associated social accounts. Remove any binding that you do not recognize.
manage_social=Управление привязанными учетными записями в соцсетях
social_desc=Это список привязанных учетных записей в соцсетях. Удаляйте любые неизвестные вам привязки.
unbind=Отвязать
unbind_success=Социальная учетная запись отвязана.
manage_access_token=Manage Personal Access Tokens
manage_access_token=Управление Токенами Персонального Доступа
generate_new_token=Создать новый token
tokens_desc=Tokens you have generated that can be used to access the Gogs API.
new_token_desc=As for now, every token will have full access to your account.
tokens_desc=Созданные вами токены могут использоваться для доступа к Gogs API.
new_token_desc=Пока что каждый токен будет иметь полный доступ к вашей учетной записи.
token_name=Имя маркера
generate_token=Генерировать маркер
generate_token_succees=New access token has been generated successfully! Make sure to copy your new personal access token now. You won't be able to see it again!
generate_token_succees=Успешно создан новый токен доступа! Пожалуйста сделайте копию вашего нового токена персонального доступа. Вы не сможете увидеть его снова!
delete_token=Удалить
delete_token_success=Personal access token has been deleted successfully! Don't forget to update your applications as well.
delete_token_success=Персональный токен доступа был успешно удален! Не забудьте так же обновить ваши приложения.
delete_account=Удалить свой аккаунт
delete_prompt=Этим действием вы удалите свою учетную запись навсегда и <strong>НЕ СМОЖЕТЕ</strong> ее вернуть!
@ -285,7 +285,7 @@ goget_meta_helper=This repository will be <span class="label label-blue label-ra
need_auth=Требуется авторизация
migrate_type=Тип миграции
migrate_type_helper=Этот репозиторий будет <span class="label label-blue label-radius">зеркалом</span>
migrate_repo=Migrate Repository
migrate_repo=Перенос репозитория
copy_link=Копировать
click_to_copy=Скопировать в буфер обмена
@ -322,7 +322,7 @@ commits.author=Автор
commits.message=Сообщение
commits.date=Дата
commits.older=Раньше
commits.newer=Newer
commits.newer=Новее
settings=Настройки
settings.options=Опции
@ -347,9 +347,9 @@ settings.transfer_owner=Новый владелец
settings.make_transfer=Выполнить передачу
settings.transfer_succeed=Repository ownership has been transferred successfully.
settings.confirm_delete=Подтвердить удаление
settings.add_collaborator=Add New Collaborator
settings.add_collaborator_success=New collaborator has been added.
settings.remove_collaborator_success=Collaborator has been removed.
settings.add_collaborator=Добавить нового соавтора
settings.add_collaborator_success=Был добавлен новый соавтор.
settings.remove_collaborator_success=Соавтор был удален.
settings.user_is_org_member=User is organization member who cannot be added as a collaborator.
settings.add_webhook=Добавить Webhook
settings.hooks_desc=Webhooks allow external services to be notified when certain events happen on Gogs. When the specified events happen, we'll send a POST request to each of the URLs you provide. Learn more in our <a target="_blank" href="%s">Webhooks Guide</a>.
@ -462,14 +462,14 @@ members.invite_now=Пригласите сейчас
teams.join=Объединить
teams.leave=Выйти
teams.read_access=Доступ на чтение
teams.read_access_helper=This team will be able to view and clone its repositories.
teams.read_access_helper=Эта команда будет иметь возможность просматривать и клонировать ее репозитории.
teams.write_access=Доступ на запись
teams.write_access_helper=This team will be able to read its repositories, as well as push to them.
teams.write_access_helper=Эта команда будет в состоянии прочитать ее репозитории, а также посылать изменения.
teams.admin_access=Доступ администратора
teams.admin_access_helper=This team will be able to push/pull to its repositories, as well as add other collaborators to them.
teams.no_desc=Эта группа не имеет описания
teams.settings=Настройки
teams.owners_permission_desc=Owners have full access to <strong>all repositories</strong> and have <strong>admin rights</strong> to the organization.
teams.owners_permission_desc=Владельцы имеют полный доступ ко <strong>всем репозиториям</strong> и имеют <strong>права администратора</strong> организации.
teams.members=Члены группы разработки
teams.update_settings=Обновить настройки
teams.delete_team=Удалить эту группу разработки
@ -486,7 +486,7 @@ teams.remove_repo=Удалить
teams.add_nonexistent_repo=Вы добавляете в отсутствующий репозиторий, пожалуйста сначала его создайте.
[admin]
dashboard=Dashboard
dashboard=Панель управления
users=Пользователи
organizations=Организации
repositories=Репозитории
@ -508,14 +508,14 @@ dashboard.clean_unbind_oauth=Clean unbound OAuthes
dashboard.clean_unbind_oauth_success=All unbind OAuthes have been deleted successfully.
dashboard.delete_inactivate_accounts=Удалить все неактивированные учетные записи
dashboard.delete_inactivate_accounts_success=Все неактивированные учетные записи удалены успешно.
dashboard.delete_repo_archives=Delete all repositories archives
dashboard.delete_repo_archives_success=All repositories archives have been deleted successfully.
dashboard.git_gc_repos=Do garbage collection on repositories
dashboard.git_gc_repos_success=All repositories have done garbage collection successfully.
dashboard.delete_repo_archives=Удаление всех архивов репозиториев
dashboard.delete_repo_archives_success=Все архивы репозиториев были успешно удалены.
dashboard.git_gc_repos=Выполнить сборку мусора на репозиториях
dashboard.git_gc_repos_success=Сборка мусора на всех репозиториях успешно выполнена.
dashboard.server_uptime=Время непрерывной работы сервера
dashboard.current_goroutine=Current Goroutines
dashboard.current_memory_usage=Текущее использование памяти
dashboard.total_memory_allocated=Total Memory Allocated
dashboard.total_memory_allocated=Всего памяти выделено
dashboard.memory_obtained=Memory Obtained
dashboard.pointer_lookup_times=Pointer Lookup Times
dashboard.memory_allocate_times=Memory Allocate Times
@ -543,7 +543,7 @@ dashboard.last_gc_pause=Last GC Pause
dashboard.gc_times=GC Times
users.user_manage_panel=User Manage Panel
users.new_account=Create New Account
users.new_account=Создать новый аккаунт
users.name=Имя
users.activated=Активирован
users.admin=Администратор
@ -560,7 +560,7 @@ users.is_admin=У этой учетной записи есть права ад
users.allow_git_hook=Пользователь имеет право создать Git перехватчик
users.update_profile=Обновить профиль учетной записи
users.delete_account=Удалить эту учетную запись
users.still_own_repo=This account still have ownership of repository, you have to delete or transfer them first.
users.still_own_repo=На вашем аккаунте все еще остается как минимум один репозиторий, сначала вам нужно удалить или передать его.
users.still_has_org=This account still have membership of organization, you have to left or delete them first.
orgs.org_manage_panel=Управление группами
@ -630,30 +630,30 @@ config.db_path=Path
config.db_path_helper=(for "sqlite3" only)
config.service_config=Service Configuration
config.register_email_confirm=Require E-mail Confirmation
config.disable_register=Disable Registration
config.require_sign_in_view=Require Sign In View
config.mail_notify=Mail Notification
config.enable_cache_avatar=Enable Cache Avatar
config.disable_register=Отключить регистрацию
config.require_sign_in_view=Для просмотра необходима авторизация
config.mail_notify=Почтовые уведомления
config.enable_cache_avatar=Кешировать аватар
config.active_code_lives=Active Code Lives
config.reset_password_code_lives=Reset Password Code Lives
config.webhook_config=Настройка автоматического обновления репозиции
config.task_interval=Task Interval
config.deliver_timeout=Deliver Timeout
config.mailer_config=Mailer Configuration
config.mailer_enabled=Enabled
config.mailer_name=Name
config.mailer_host=Host
config.mailer_user=User
config.oauth_config=OAuth Configuration
config.oauth_enabled=Enabled
config.cache_config=Cache Configuration
config.task_interval=Интервал задания
config.deliver_timeout=Задержка доставки
config.mailer_config=Настройки почты
config.mailer_enabled=Включено
config.mailer_name=Имя
config.mailer_host=Сервер
config.mailer_user=Пользователь
config.oauth_config=Конфигурация OAuth
config.oauth_enabled=Включено
config.cache_config=Настройки кеша
config.cache_adapter=Cache Adapter
config.cache_interval=Cache Interval
config.cache_conn=Cache Connection
config.session_config=Session Configuration
config.session_provider=Session Provider
config.provider_config=Provider Config
config.cookie_name=Cookie Name
config.cookie_name=Имя файла cookie
config.enable_set_cookie=Enable Set Cookie
config.gc_interval_time=GC Interval Time
config.session_life_time=Время жизни сессии
@ -674,7 +674,7 @@ monitor.execute_times=Execute Times
monitor.process=Запущенные процессы
monitor.desc=Описание
monitor.start=Start Time
monitor.execute_time=Execution Time
monitor.execute_time=Время выполнения
notices.system_notice_list=Система уведомлений
notices.type=Тип
@ -684,7 +684,7 @@ notices.op=Op.
notices.delete_success=System notice has been deleted successfully.
[action]
create_repo=created repository <a href="%s/%s">%s</a>
create_repo=создан репозиторий <a href="%s/%s"> %s</a>
commit_repo=pushed to <a href="%s/%s/src/%s">%s</a> at <a href="%s/%s">%s</a>
create_issue=opened issue <a href="%s/%s/issues/%s">%s#%s</a>
comment_issue=commented on issue <a href="%s/%s/issues/%s">%s#%s</a>
@ -703,9 +703,9 @@ now=сейчас
1w=1 week %s
1mon=1 month %s
1y=1 year %s
seconds=%d seconds %s
minutes=%d minutes %s
hours=%d hours %s
seconds=%d секунд %s
minutes=%d минут %s
hours=%d часов %s
days=%d days %s
weeks=%d weeks %s
months=%d months %s

2
gogs.go

@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting"
)
const APP_VER = "0.5.12.0120 Beta"
const APP_VER = "0.5.12.0204 Beta"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())

46
models/action.go

@ -41,12 +41,14 @@ var (
var (
// Same as Github. See https://help.github.com/articles/closing-issues-via-commit-messages
IssueKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
IssueKeywordsPat *regexp.Regexp
IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
IssueCloseKeywordsPat *regexp.Regexp
IssueReferenceKeywordsPat *regexp.Regexp
)
func init() {
IssueKeywordsPat = regexp.MustCompile(fmt.Sprintf(`(?i)(?:%s) \S+`, strings.Join(IssueKeywords, "|")))
IssueCloseKeywordsPat = regexp.MustCompile(fmt.Sprintf(`(?i)(?:%s) \S+`, strings.Join(IssueCloseKeywords, "|")))
IssueReferenceKeywordsPat = regexp.MustCompile(fmt.Sprintf(`(?i)(?:) \S+`))
}
// Action represents user operation type and other information to repository.,
@ -110,13 +112,13 @@ func (a Action) GetIssueInfos() []string {
func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, commits []*base.PushCommit) error {
for _, c := range commits {
refs := IssueKeywordsPat.FindAllString(c.Message, -1)
references := IssueReferenceKeywordsPat.FindAllString(c.Message, -1)
for _, ref := range refs {
for _, ref := range references {
ref := ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, func(c rune) bool {
return !unicode.IsDigit(c)
})
return !unicode.IsDigit(c)
})
if len(ref) == 0 {
continue
@ -144,6 +146,35 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMIT, message, nil); err != nil {
return err
}
}
closes := IssueCloseKeywordsPat.FindAllString(c.Message, -1)
for _, ref := range closes {
ref := ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, func(c rune) bool {
return !unicode.IsDigit(c)
})
if len(ref) == 0 {
continue
}
// Add repo name if missing
if ref[0] == '#' {
ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref)
} else if strings.Contains(ref, "/") == false {
// We don't support User#ID syntax yet
// return ErrNotImplemented
continue
}
issue, err := GetIssueByRef(ref)
if err != nil {
return err
}
if issue.RepoId == repoId {
if issue.IsClosed {
@ -168,6 +199,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
}
}
}
}
return nil

16
models/models.go

@ -33,7 +33,7 @@ var (
HasEngine bool
DbCfg struct {
Type, Host, Name, User, Pwd, Path, SslMode string
Type, Host, Name, User, Passwd, Path, SSLMode string
}
EnableSQLite3 bool
@ -59,10 +59,10 @@ func LoadModelsConfig() {
DbCfg.Host = sec.Key("HOST").String()
DbCfg.Name = sec.Key("NAME").String()
DbCfg.User = sec.Key("USER").String()
if len(DbCfg.Pwd) == 0 {
DbCfg.Pwd = sec.Key("PASSWD").String()
if len(DbCfg.Passwd) == 0 {
DbCfg.Passwd = sec.Key("PASSWD").String()
}
DbCfg.SslMode = sec.Key("SSL_MODE").String()
DbCfg.SSLMode = sec.Key("SSL_MODE").String()
DbCfg.Path = sec.Key("PATH").MustString("data/gogs.db")
}
@ -71,7 +71,7 @@ func getEngine() (*xorm.Engine, error) {
switch DbCfg.Type {
case "mysql":
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name)
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name)
case "postgres":
var host, port = "127.0.0.1", "5432"
fields := strings.Split(DbCfg.Host, ":")
@ -82,7 +82,7 @@ func getEngine() (*xorm.Engine, error) {
port = fields[1]
}
cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode)
DbCfg.User, DbCfg.Passwd, host, port, DbCfg.Name, DbCfg.SSLMode)
case "sqlite3":
if !EnableSQLite3 {
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
@ -98,7 +98,7 @@ func getEngine() (*xorm.Engine, error) {
func NewTestEngine(x *xorm.Engine) (err error) {
x, err = getEngine()
if err != nil {
return fmt.Errorf("models.init(fail to connect to database): %v", err)
return fmt.Errorf("connect to database: %v", err)
}
x.SetMapper(core.GonicMapper{})
@ -108,7 +108,7 @@ func NewTestEngine(x *xorm.Engine) (err error) {
func SetEngine() (err error) {
x, err = getEngine()
if err != nil {
return fmt.Errorf("models.init(fail to connect to database): %v", err)
return fmt.Errorf("connect to database: %v", err)
}
x.SetMapper(core.GonicMapper{})

61
models/publickey.go

@ -33,7 +33,7 @@ const (
)
var (
ErrKeyAlreadyExist = errors.New("Public key already exist")
ErrKeyAlreadyExist = errors.New("Public key already exists")
ErrKeyNotExist = errors.New("Public key does not exist")
ErrKeyUnableVerify = errors.New("Unable to verify public key")
)
@ -41,7 +41,7 @@ var (
var sshOpLocker = sync.Mutex{}
var (
SshPath string // SSH directory.
SSHPath string // SSH directory.
appPath string // Execution(binary) path.
)
@ -72,9 +72,9 @@ func init() {
appPath = strings.Replace(appPath, "\\", "/", -1)
// Determine and create .ssh path.
SshPath = filepath.Join(homeDir(), ".ssh")
if err = os.MkdirAll(SshPath, 0700); err != nil {
log.Fatal(4, "fail to create SshPath(%s): %v\n", SshPath, err)
SSHPath = filepath.Join(homeDir(), ".ssh")
if err = os.MkdirAll(SSHPath, 0700); err != nil {
log.Fatal(4, "fail to create '%s': %v", SSHPath, err)
}
}
@ -244,16 +244,17 @@ func CheckPublicKeyString(content string) (bool, error) {
}
// saveAuthorizedKeyFile writes SSH key content to authorized_keys file.
func saveAuthorizedKeyFile(key *PublicKey) error {
func saveAuthorizedKeyFile(keys ...*PublicKey) error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
fpath := filepath.Join(SshPath, "authorized_keys")
fpath := filepath.Join(SSHPath, "authorized_keys")
f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return err
}
defer f.Close()
finfo, err := f.Stat()
if err != nil {
return err
@ -269,8 +270,12 @@ func saveAuthorizedKeyFile(key *PublicKey) error {
}
}
_, err = f.WriteString(key.GetAuthorizedString())
return err
for _, key := range keys {
if _, err = f.WriteString(key.GetAuthorizedString()); err != nil {
return err
}
}
return nil
}
// AddPublicKey adds new public key to database and authorized_keys file.
@ -413,8 +418,8 @@ func DeletePublicKey(key *PublicKey) error {
return err
}
fpath := filepath.Join(SshPath, "authorized_keys")
tmpPath := filepath.Join(SshPath, "authorized_keys.tmp")
fpath := filepath.Join(SSHPath, "authorized_keys")
tmpPath := filepath.Join(SSHPath, "authorized_keys.tmp")
if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
return err
} else if err = os.Remove(fpath); err != nil {
@ -422,3 +427,37 @@ func DeletePublicKey(key *PublicKey) error {
}
return os.Rename(tmpPath, fpath)
}
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again.
func RewriteAllPublicKeys() error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
tmpPath := filepath.Join(SSHPath, "authorized_keys.tmp")
f, err := os.Create(tmpPath)
if err != nil {
return err
}
defer os.Remove(tmpPath)
err = x.Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
_, err = f.WriteString((bean.(*PublicKey)).GetAuthorizedString())
return err
})
f.Close()
if err != nil {
return err
}
fpath := filepath.Join(SSHPath, "authorized_keys")
if com.IsExist(fpath) {
if err = os.Remove(fpath); err != nil {
return err
}
}
if err = os.Rename(tmpPath, fpath); err != nil {
return err
}
return nil
}

12
models/repo.go

@ -7,7 +7,6 @@ package models
import (
"errors"
"fmt"
"html"
"html/template"
"io/ioutil"
"os"
@ -218,11 +217,9 @@ func (repo *Repository) HasAccess(uname string) bool {
// DescriptionHtml does special handles to description and return HTML string.
func (repo *Repository) DescriptionHtml() template.HTML {
sanitize := func(s string) string {
// TODO(nuss-justin): Improve sanitization. Strip all tags?
ss := html.EscapeString(s)
return fmt.Sprintf(`<a href="%s" target="_blank">%s</a>`, ss, ss)
return fmt.Sprintf(`<a href="%[1]s" target="_blank">%[1]s</a>`, s)
}
return template.HTML(DescPattern.ReplaceAllStringFunc(base.XSSString(repo.Description), sanitize))
return template.HTML(DescPattern.ReplaceAllStringFunc(base.Sanitizer.Sanitize(repo.Description), sanitize))
}
// IsRepositoryExist returns true if the repository with given name under user has already existed.
@ -507,6 +504,11 @@ func initRepository(f string, u *User, repo *Repository, initReadme bool, repoLa
}
if len(fileName) == 0 {
// Re-fetch the repository from database before updating it (else it would
// override changes that were done earlier with sql)
if repo, err = GetRepositoryById(repo.Id); err != nil {
return err
}
repo.IsBare = true
repo.DefaultBranch = "master"
return UpdateRepository(repo)

1
models/user.go

@ -477,6 +477,7 @@ func UpdateUser(u *User) error {
}
u.Avatar = avatar.HashEmail(u.AvatarEmail)
u.FullName = base.Sanitizer.Sanitize(u.FullName)
_, err = x.Id(u.Id).AllCols().Update(u)
return err
}

7
modules/auth/auth.go

@ -9,6 +9,7 @@ import (
"reflect"
"strings"
"github.com/Unknwon/com"
"github.com/Unknwon/macaron"
"github.com/macaron-contrib/binding"
"github.com/macaron-contrib/session"
@ -135,6 +136,10 @@ type Form interface {
binding.Validator
}
func init() {
binding.SetNameMapper(com.ToSnakeCase)
}
// AssignForm assign form values back to the template data.
func AssignForm(form interface{}, data map[string]interface{}) {
typ := reflect.TypeOf(form)
@ -152,6 +157,8 @@ func AssignForm(form interface{}, data map[string]interface{}) {
// Allow ignored fields in the struct
if fieldName == "-" {
continue
} else if len(fieldName) == 0 {
fieldName = com.ToSnakeCase(field.Name)
}
data[fieldName] = val.Field(i).Interface()

41
modules/auth/user_form.go

@ -12,26 +12,27 @@ import (
)
type InstallForm struct {
Database string `form:"database" binding:"Required"`
DbHost string `form:"host"`
DbUser string `form:"user"`
DbPasswd string `form:"passwd"`
DatabaseName string `form:"database_name"`
SslMode string `form:"ssl_mode"`
DatabasePath string `form:"database_path"`
RepoRootPath string `form:"repo_path" binding:"Required"`
RunUser string `form:"run_user" binding:"Required"`
Domain string `form:"domain" binding:"Required"`
AppUrl string `form:"app_url" binding:"Required"`
SmtpHost string `form:"smtp_host"`
SmtpEmail string `form:"mailer_user"`
SmtpPasswd string `form:"mailer_pwd"`
RegisterConfirm string `form:"register_confirm"`
MailNotify string `form:"mail_notify"`
AdminName string `form:"admin_name" binding:"Required;AlphaDashDot;MaxSize(30)"`
AdminPasswd string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(255)"`
ConfirmPasswd string `form:"confirm_passwd" binding:"Required;MinSize(6);MaxSize(255)"`
AdminEmail string `form:"admin_email" binding:"Required;Email;MaxSize(50)"`
DbType string `binding:"Required"`
DbHost string
DbUser string
DbPasswd string
DbName string
SSLMode string
DbPath string
RepoRootPath string `binding:"Required"`
RunUser string `binding:"Required"`
Domain string `binding:"Required"`
HTTPPort string `binding:"Required"`
AppUrl string `binding:"Required"`
SMTPHost string
SMTPEmail string
SMTPPasswd string
RegisterConfirm string
MailNotify string
AdminName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
AdminPasswd string `binding:"Required;MinSize(6);MaxSize(255)"`
AdminConfirmPasswd string `binding:"Required;MinSize(6);MaxSize(255)"`
AdminEmail string `binding:"Required;Email;MaxSize(50)"`
}
func (f *InstallForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

12
modules/base/markdown.go

@ -63,12 +63,18 @@ func IsImageFile(data []byte) (string, bool) {
return contentType, false
}
// IsReadmeFile returns true if given file name suppose to be a README file.
func IsReadmeFile(name string) bool {
name = strings.ToLower(name)
if len(name) < 6 {
return false
} else if len(name) == 6 {
if name == "readme" {
return true
}
return false
}
if name[:6] == "readme" {
if name[:7] == "readme." {
return true
}
return false
@ -103,7 +109,7 @@ var (
MentionPattern = regexp.MustCompile(`@[0-9a-zA-Z_]{1,}`)
commitPattern = regexp.MustCompile(`(\s|^)https?.*commit/[0-9a-zA-Z]+(#+[0-9a-zA-Z-]*)?`)
issueFullPattern = regexp.MustCompile(`(\s|^)https?.*issues/[0-9]+(#+[0-9a-zA-Z-]*)?`)
issueIndexPattern = regexp.MustCompile(`#[0-9]+`)
issueIndexPattern = regexp.MustCompile(`( |^)#[0-9]+`)
sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`)
)
@ -212,7 +218,7 @@ func RenderRawMarkdown(body []byte, urlPrefix string) []byte {
func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte {
body := RenderSpecialLink(rawBytes, urlPrefix)
body = RenderRawMarkdown(body, urlPrefix)
body = XSS(body)
body = Sanitizer.SanitizeBytes(body)
return body
}

12
modules/base/template.go

@ -13,7 +13,6 @@ import (
"strings"
"time"
"github.com/microcosm-cc/bluemonday"
"golang.org/x/net/html/charset"
"golang.org/x/text/transform"
@ -21,11 +20,8 @@ import (
"github.com/gogits/gogs/modules/setting"
)
// FIXME: use me to Markdown API renders
var p = bluemonday.UGCPolicy()
func Str2html(raw string) template.HTML {
return template.HTML(p.Sanitize(raw))
return template.HTML(Sanitizer.Sanitize(raw))
}
func Range(l int) []int {
@ -90,6 +86,11 @@ func ToUtf8(content string) string {
return res
}
// RenderCommitMessage renders commit message with XSS-safe and special links.
func RenderCommitMessage(msg, urlPrefix string) template.HTML {
return template.HTML(string(RenderIssueIndexPattern([]byte(template.HTMLEscapeString(msg)), urlPrefix)))
}
var mailDomains = map[string]string{
"gmail.com": "gmail.com",
}
@ -163,6 +164,7 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
"EscapePound": func(str string) string {
return strings.Replace(str, "#", "%23", -1)
},
"RenderCommitMessage": RenderCommitMessage,
}
type Actioner interface {

30
modules/base/tool.go

@ -15,17 +15,19 @@ import (
"hash"
"html/template"
"math"
"regexp"
"strings"
"time"
"github.com/Unknwon/com"
"github.com/Unknwon/i18n"
"github.com/microcosm-cc/bluemonday"
"github.com/gogits/gogs/modules/avatar"
"github.com/gogits/gogs/modules/setting"
)
var Sanitizer = bluemonday.UGCPolicy()
// Encode string to md5 hex value.
func EncodeMd5(str string) string {
m := md5.New()
@ -473,29 +475,3 @@ func DateFormat(t time.Time, format string) string {
format = replacer.Replace(format)
return t.Format(format)
}
type xssFilter struct {
reg *regexp.Regexp
repl []byte
}
var (
whiteSpace = []byte(" ")
xssFilters = []xssFilter{
{regexp.MustCompile(`\ [ONon]\w*=["]*`), whiteSpace},
{regexp.MustCompile(`<[SCRIPTscript]{6}`), whiteSpace},
{regexp.MustCompile(`=[` + "`" + `'"]*[JAVASCRIPTjavascript \t\0&#x0D;]*:`), whiteSpace},
}
)
// XSS goes through all the XSS filters to make user input content as safe as possible.
func XSS(in []byte) []byte {
for _, filter := range xssFilters {
in = filter.reg.ReplaceAll(in, filter.repl)
}
return in
}
func XSSString(in string) string {
return string(XSS([]byte(in)))
}

2
modules/middleware/auth.go

@ -54,7 +54,7 @@ func Toggle(options *ToggleOptions) macaron.Handler {
if strings.HasSuffix(ctx.Req.RequestURI, "watch") {
return
}
ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
ctx.Redirect(setting.AppSubUrl + "/user/login")
return
} else if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {

2
modules/setting/setting.go

@ -178,7 +178,7 @@ func NewConfigContext() {
log.Fatal(4, "Fail to load custom 'conf/app.ini': %v", err)
}
} else {
log.Warn("No custom 'conf/app.ini' found, please go to '/install'")
log.Warn("No custom 'conf/app.ini' found, ignore this if you're running first time")
}
Cfg.NameMapper = ini.AllCapsUnderscore

16
public/js/app.js

@ -1052,22 +1052,6 @@ function initRepoSetting() {
return;
}
Gogits.getUsers($this.val(), $this.next());
/*$.ajax({
url: '/api/v1/users/search?q=' + $this.val(),
dataType: "json",
success: function (json) {
if (json.ok && json.data.length) {
var html = '';
$.each(json.data, function (i, item) {
html += '<li><img src="' + item.avatar + '">' + item.username + '</li>';
});
$this.next().toggleShow();
$this.next().find('ul').html(html);
} else {
$this.next().toggleHide();
}
}
});*/
}).on('focus', function () {
if (!$(this).val()) {
$(this).next().toggleHide();

23
public/ng/css/gogs.css

@ -1630,6 +1630,10 @@ The register and sign-in page style
background-color: #d1ffd6 !important;
border-color: #b4e2b4 !important;
}
.diff-file-box .code-diff tbody tr.add-code td.selected-line,
.diff-file-box .code-diff tbody tr.add-code td.selected-line pre {
background-color: #ffffdd !important;
}
.diff-file-box .code-diff tbody tr:hover td,
.diff-file-box .code-diff tbody tr:hover pre {
background-color: #FFF8D2 !important;
@ -1761,6 +1765,7 @@ The register and sign-in page style
#org-setting-form,
#repo-setting-form,
#user-profile-form,
#add-email-form,
.repo-setting-form {
background-color: #FFF;
padding: 30px 0;
@ -1769,6 +1774,7 @@ The register and sign-in page style
#org-setting-form textarea,
#repo-setting-form textarea,
#user-profile-form textarea,
#add-email-form textarea,
.repo-setting-form textarea {
margin-left: 4px;
height: 100px;
@ -1777,11 +1783,13 @@ The register and sign-in page style
#org-setting-form label,
#repo-setting-form label,
#user-profile-form label,
#add-email-form label,
.repo-setting-form label,
#auth-setting-form .form-label,
#org-setting-form .form-label,
#repo-setting-form .form-label,
#user-profile-form .form-label,
#add-email-form .form-label,
.repo-setting-form .form-label {
width: 240px;
}
@ -1789,6 +1797,7 @@ The register and sign-in page style
#org-setting-form .ipt,
#repo-setting-form .ipt,
#user-profile-form .ipt,
#add-email-form .ipt,
.repo-setting-form .ipt {
width: 360px;
}
@ -1796,6 +1805,7 @@ The register and sign-in page style
#org-setting-form .field,
#repo-setting-form .field,
#user-profile-form .field,
#add-email-form .field,
.repo-setting-form .field {
margin-bottom: 24px;
}
@ -1813,6 +1823,7 @@ The register and sign-in page style
#repo-hooks-history-panel,
#user-social-panel,
#user-applications-panel,
#user-email-panel,
#user-ssh-panel {
margin-bottom: 20px;
}
@ -1820,6 +1831,7 @@ The register and sign-in page style
#repo-hooks-history-panel .setting-list,
#user-social-panel .setting-list,
#user-applications-panel .setting-list,
#user-email-panel .setting-list,
#user-ssh-panel .setting-list {
background-color: #FFF;
}
@ -1827,6 +1839,7 @@ The register and sign-in page style
#repo-hooks-history-panel .setting-list li,
#user-social-panel .setting-list li,
#user-applications-panel .setting-list li,
#user-email-panel .setting-list li,
#user-ssh-panel .setting-list li {
padding: 8px 20px;
border-bottom: 1px solid #eaeaea;
@ -1835,6 +1848,7 @@ The register and sign-in page style
#repo-hooks-history-panel .setting-list li.ssh:hover,
#user-social-panel .setting-list li.ssh:hover,
#user-applications-panel .setting-list li.ssh:hover,
#user-email-panel .setting-list li.ssh:hover,
#user-ssh-panel .setting-list li.ssh:hover {
background-color: #ffffEE;
}
@ -1842,6 +1856,7 @@ The register and sign-in page style
#repo-hooks-history-panel .setting-list li i,
#user-social-panel .setting-list li i,
#user-applications-panel .setting-list li i,
#user-email-panel .setting-list li i,
#user-ssh-panel .setting-list li i {
padding-right: 5px;
}
@ -1849,6 +1864,7 @@ The register and sign-in page style
#repo-hooks-history-panel .active-icon,
#user-social-panel .active-icon,
#user-applications-panel .active-icon,
#user-email-panel .active-icon,
#user-ssh-panel .active-icon {
width: 10px;
height: 10px;
@ -1861,6 +1877,7 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-content,
#user-social-panel .ssh-content,
#user-applications-panel .ssh-content,
#user-email-panel .ssh-content,
#user-ssh-panel .ssh-content {
margin-left: 24px;
}
@ -1868,6 +1885,7 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-content .octicon,
#user-social-panel .ssh-content .octicon,
#user-applications-panel .ssh-content .octicon,
#user-email-panel .ssh-content .octicon,
#user-ssh-panel .ssh-content .octicon {
margin-right: 4px;
}
@ -1875,16 +1893,19 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-content .print,
#user-social-panel .ssh-content .print,
#user-applications-panel .ssh-content .print,
#user-email-panel .ssh-content .print,
#user-ssh-panel .ssh-content .print,
#repo-hooks-panel .ssh-content .access,
#repo-hooks-history-panel .ssh-content .access,
#user-social-panel .ssh-content .access,
#user-applications-panel .ssh-content .access,
#user-email-panel .ssh-content .access,
#user-ssh-panel .ssh-content .access,
#repo-hooks-panel .ssh-content .activity,
#repo-hooks-history-panel .ssh-content .activity,
#user-social-panel .ssh-content .activity,
#user-applications-panel .ssh-content .activity,
#user-email-panel .ssh-content .activity,
#user-ssh-panel .ssh-content .activity {
color: #888;
}
@ -1892,6 +1913,7 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-content .access,
#user-social-panel .ssh-content .access,
#user-applications-panel .ssh-content .access,
#user-email-panel .ssh-content .access,
#user-ssh-panel .ssh-content .access {
max-width: 500px;
}
@ -1899,6 +1921,7 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-btn,
#user-social-panel .ssh-btn,
#user-applications-panel .ssh-btn,
#user-email-panel .ssh-btn,
#user-ssh-panel .ssh-btn {
margin-top: 6px;
}

83
public/ng/js/gogs.js

@ -202,6 +202,78 @@ var Gogs = {};
}).trigger('hashchange');
};
// Render diff view.
Gogs.renderDiffView = function () {
function selectRange($list, $select, $from) {
$list.removeClass('active');
$list.parents('tr').find('td').removeClass('selected-line');
if ($from) {
var a = parseInt($select.attr('rel').substr(1));
var b = parseInt($from.attr('rel').substr(1));
var c;
if (a != b) {
if (a > b) {
c = a;
a = b;
b = c;
}
var classes = [];
for (i = a; i <= b; i++) {
classes.push('[rel=L' + i + ']');
}
$list.filter(classes.join(',')).addClass('active');
$list.filter(classes.join(',')).parents('tr').find('td').addClass('selected-line');
$.changeHash('#L' + a + '-' + 'L' + b);
return
}
}
$select.addClass('active');
$select.parents('tr').find('td').addClass('selected-line');
$.changeHash('#' + $select.attr('rel'));
}
$(document).on('click', '.code-diff .lines-num span', function (e) {
var $select = $(this);
var $list = $select.parent().siblings('.lines-code').parents().find('td.lines-num > span');
selectRange(
$list,
$list.filter('[rel=' + $select.attr('rel') + ']'),
(e.shiftKey && $list.filter('.active').length ? $list.filter('.active').eq(0) : null)
);
$.deSelect();
});
$('.code-diff .lines-code > pre').each(function () {
var $pre = $(this);
var $lineCode = $pre.parent();
var $lineNums = $lineCode.siblings('.lines-num');
if ($lineNums.length > 0) {
var nums = $pre.find('ol.linenums > li').length;
for (var i = 1; i <= nums; i++) {
$lineNums.append('<span id="L' + i + '" rel="L' + i + '">' + i + '</span>');
}
}
});
$(window).on('hashchange', function (e) {
var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/);
var $list = $('.code-diff td.lines-num > span');
var $first;
if (m) {
$first = $list.filter('[rel=' + m[1] + ']');
selectRange($list, $first, $list.filter('[rel=' + m[2] + ']'));
$("html, body").scrollTop($first.offset().top - 200);
return;
}
m = window.location.hash.match(/^#(L\d+)$/);
if (m) {
$first = $list.filter('[rel=' + m[1] + ']');
selectRange($list, $first);
$("html, body").scrollTop($first.offset().top - 200);
}
}).trigger('hashchange');
};
// Search users by keyword.
Gogs.searchUsers = function (val, $target) {
var notEmpty = function (str) {
@ -287,7 +359,12 @@ var Gogs = {};
function initCore() {
Gogs.renderMarkdown();
Gogs.renderCodeView();
if ($('.code-diff').length == 0) {
Gogs.renderCodeView();
} else {
Gogs.renderDiffView();
}
// Switch list.
$('.js-tab-nav').click(function (e) {
@ -508,7 +585,7 @@ function initRepoSetting() {
$ul.toggleShow();
}
}).next().next().find('ul').on("click", 'li', function () {
$('#repo-collaborator').val($(this).text());
$('#repo-collaborator').val($(this).find('.username').text());
$ul.toggleHide();
});
}
@ -608,7 +685,7 @@ function initTeamMembersList() {
$ul.toggleShow();
}
}).next().next().find('ul').on("click", 'li', function () {
$('#org-team-members-add').val($(this).text());
$('#org-team-members-add').val($(this).find('.username').text());
$ul.toggleHide();
});
}

10
public/ng/js/min/gogs-min.js vendored

File diff suppressed because one or more lines are too long

3
public/ng/less/gogs/repository.less

@ -665,6 +665,9 @@
background-color: #d1ffd6 !important;
border-color: #b4e2b4 !important;
}
td.selected-line, td.selected-line pre {
background-color: #ffffdd !important;
}
}
&:hover {
td, pre {

2
public/ng/less/gogs/settings.less

@ -35,6 +35,7 @@
#org-setting-form,
#repo-setting-form,
#user-profile-form,
#add-email-form,
.repo-setting-form {
background-color: #FFF;
padding: 30px 0;
@ -69,6 +70,7 @@
#repo-hooks-history-panel,
#user-social-panel,
#user-applications-panel,
#user-email-panel,
#user-ssh-panel {
margin-bottom: 20px;
.setting-list {

4
routers/admin/admin.go

@ -118,6 +118,7 @@ const (
CLEAN_INACTIVATE_USER
CLEAN_REPO_ARCHIVES
GIT_GC_REPOS
SYNC_SSH_AUTHORIZED_KEY
)
func Dashboard(ctx *middleware.Context) {
@ -144,6 +145,9 @@ func Dashboard(ctx *middleware.Context) {
case GIT_GC_REPOS:
success = ctx.Tr("admin.dashboard.git_gc_repos_success")
err = models.GitGcRepos()
case SYNC_SSH_AUTHORIZED_KEY:
success = ctx.Tr("admin.dashboard.resync_all_sshkeys_success")
err = models.RewriteAllPublicKeys()
}
if err != nil {

156
routers/install.go

@ -14,6 +14,7 @@ import (
"github.com/Unknwon/com"
"github.com/Unknwon/macaron"
"github.com/go-xorm/xorm"
"gopkg.in/ini.v1"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
@ -73,12 +74,7 @@ func GlobalInit() {
checkRunMode()
}
func renderDbOption(ctx *middleware.Context) {
ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"}
}
// @router /install [get]
func Install(ctx *middleware.Context, form auth.InstallForm) {
func InstallInit(ctx *middleware.Context) {
if setting.InstallLock {
ctx.Handle(404, "Install", errors.New("Installation is prohibited"))
return
@ -87,46 +83,35 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
ctx.Data["Title"] = ctx.Tr("install.install")
ctx.Data["PageIsInstall"] = true
// FIXME: when i'm ckeching length here? should they all be 0 no matter when?
// Get and assign values to install form.
if len(form.DbHost) == 0 {
form.DbHost = models.DbCfg.Host
}
if len(form.DbUser) == 0 {
form.DbUser = models.DbCfg.User
}
if len(form.DbPasswd) == 0 {
form.DbPasswd = models.DbCfg.Pwd
}
if len(form.DatabaseName) == 0 {
form.DatabaseName = models.DbCfg.Name
}
if len(form.DatabasePath) == 0 {
form.DatabasePath = models.DbCfg.Path
}
ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"}
}
if len(form.RepoRootPath) == 0 {
form.RepoRootPath = setting.RepoRootPath
}
if len(form.RunUser) == 0 {
// Note: it's not normall to use SSH in windows so current user can be first option(not git).
if setting.IsWindows && setting.RunUser == "git" {
form.RunUser = os.Getenv("USER")
if len(form.RunUser) == 0 {
form.RunUser = os.Getenv("USERNAME")
}
} else {
form.RunUser = setting.RunUser
func Install(ctx *middleware.Context) {
form := auth.InstallForm{}
form.DbHost = models.DbCfg.Host
form.DbUser = models.DbCfg.User
form.DbPasswd = models.DbCfg.Passwd
form.DbName = models.DbCfg.Name
form.DbPath = models.DbCfg.Path
form.RepoRootPath = setting.RepoRootPath
// Note(unknwon): it's hard for Windows users change a running user,
// so just use current one if config says default.
if setting.IsWindows && setting.RunUser == "git" {
form.RunUser = os.Getenv("USER")
if len(form.RunUser) == 0 {
form.RunUser = os.Getenv("USERNAME")
}
}
if len(form.Domain) == 0 {
form.Domain = setting.Domain
}
if len(form.AppUrl) == 0 {
form.AppUrl = setting.AppUrl
} else {
form.RunUser = setting.RunUser
}
renderDbOption(ctx)
form.Domain = setting.Domain
form.HTTPPort = setting.HttpPort
form.AppUrl = setting.AppUrl
curDbOp := ""
if models.EnableSQLite3 {
curDbOp = "SQLite3" // Default when enabled.
@ -138,16 +123,7 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
}
func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
if setting.InstallLock {
ctx.Handle(404, "InstallPost", errors.New("Installation is prohibited"))
return
}
ctx.Data["Title"] = ctx.Tr("install.install")
ctx.Data["PageIsInstall"] = true
renderDbOption(ctx)
ctx.Data["CurDbOption"] = form.Database
ctx.Data["CurDbOption"] = form.DbType
if ctx.HasError() {
ctx.HTML(200, INSTALL)
@ -162,18 +138,17 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
// Pass basic check, now test configuration.
// Test database setting.
dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "SQLite3": "sqlite3"}
models.DbCfg.Type = dbTypes[form.Database]
models.DbCfg.Type = dbTypes[form.DbType]
models.DbCfg.Host = form.DbHost
models.DbCfg.User = form.DbUser
models.DbCfg.Pwd = form.DbPasswd
models.DbCfg.Name = form.DatabaseName
models.DbCfg.SslMode = form.SslMode
models.DbCfg.Path = form.DatabasePath
models.DbCfg.Passwd = form.DbPasswd
models.DbCfg.Name = form.DbName
models.DbCfg.SSLMode = form.SSLMode
models.DbCfg.Path = form.DbPath
// Set test engine.
var x *xorm.Engine
if err := models.NewTestEngine(x); err != nil {
// FIXME: should use core.QueryDriver (github.com/go-xorm/core)
if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "http://gogs.io/docs/installation/install_from_binary.html"), INSTALL, &form)
} else {
@ -194,7 +169,6 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
if len(curUser) == 0 {
curUser = os.Getenv("USERNAME")
}
// Does not check run user when the install lock is off.
if form.RunUser != curUser {
ctx.Data["Err_RunUser"] = true
ctx.RenderWithErr(ctx.Tr("install.run_user_not_match", form.RunUser, curUser), INSTALL, &form)
@ -202,47 +176,53 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
}
// Check admin password.
if form.AdminPasswd != form.ConfirmPasswd {
if form.AdminPasswd != form.AdminConfirmPasswd {
ctx.Data["Err_AdminPasswd"] = true
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), INSTALL, form)
return
}
if form.AppUrl[len(form.AppUrl)-1] != '/' {
form.AppUrl += "/"
}
// Save settings.
setting.Cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type)
setting.Cfg.Section("database").Key("HOST").SetValue(models.DbCfg.Host)
setting.Cfg.Section("database").Key("NAME").SetValue(models.DbCfg.Name)
setting.Cfg.Section("database").Key("USER").SetValue(models.DbCfg.User)
setting.Cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Pwd)
setting.Cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SslMode)
setting.Cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path)
setting.Cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)
setting.Cfg.Section("").Key("RUN_USER").SetValue(form.RunUser)
setting.Cfg.Section("server").Key("DOMAIN").SetValue(form.Domain)
setting.Cfg.Section("server").Key("ROOT_URL").SetValue(form.AppUrl)
if len(strings.TrimSpace(form.SmtpHost)) > 0 {
setting.Cfg.Section("mailer").Key("ENABLED").SetValue("true")
setting.Cfg.Section("mailer").Key("HOST").SetValue(form.SmtpHost)
setting.Cfg.Section("mailer").Key("USER").SetValue(form.SmtpEmail)
setting.Cfg.Section("mailer").Key("PASSWD").SetValue(form.SmtpPasswd)
setting.Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(form.RegisterConfirm == "on"))
setting.Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(form.MailNotify == "on"))
cfg := ini.Empty()
cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type)
cfg.Section("database").Key("HOST").SetValue(models.DbCfg.Host)
cfg.Section("database").Key("NAME").SetValue(models.DbCfg.Name)
cfg.Section("database").Key("USER").SetValue(models.DbCfg.User)
cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Passwd)
cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SSLMode)
cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path)
cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)
cfg.Section("").Key("RUN_USER").SetValue(form.RunUser)
cfg.Section("server").Key("DOMAIN").SetValue(form.Domain)
cfg.Section("server").Key("HTTP_PORT").SetValue(form.HTTPPort)
cfg.Section("server").Key("ROOT_URL").SetValue(form.AppUrl)
if len(strings.TrimSpace(form.SMTPHost)) > 0 {
cfg.Section("mailer").Key("ENABLED").SetValue("true")
cfg.Section("mailer").Key("HOST").SetValue(form.SMTPHost)
cfg.Section("mailer").Key("USER").SetValue(form.SMTPEmail)
cfg.Section("mailer").Key("PASSWD").SetValue(form.SMTPPasswd)
cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(form.RegisterConfirm == "on"))
cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(form.MailNotify == "on"))
}
setting.Cfg.Section("").Key("RUN_MODE").SetValue("prod")
cfg.Section("").Key("RUN_MODE").SetValue("prod")
setting.Cfg.Section("session").Key("PROVIDER").SetValue("file")
cfg.Section("session").Key("PROVIDER").SetValue("file")
setting.Cfg.Section("log").Key("MODE").SetValue("file")
cfg.Section("log").Key("MODE").SetValue("file")
setting.Cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
setting.Cfg.Section("security").Key("SECRET_KEY").SetValue(base.GetRandomString(15))
cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
cfg.Section("security").Key("SECRET_KEY").SetValue(base.GetRandomString(15))
os.MkdirAll("custom/conf", os.ModePerm)
if err := setting.Cfg.SaveTo(path.Join(setting.CustomPath, "conf/app.ini")); err != nil {
if err := cfg.SaveTo(path.Join(setting.CustomPath, "conf/app.ini")); err != nil {
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), INSTALL, &form)
return
}
@ -264,5 +244,5 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
log.Info("First-time run install finished!")
ctx.Flash.Success(ctx.Tr("install.install_success"))
ctx.Redirect(setting.AppSubUrl + "/user/login")
ctx.Redirect(form.AppUrl + "user/login")
}

4
routers/repo/commit.go

@ -37,7 +37,7 @@ func RenderIssueLinks(oldCommits *list.List, repoLink string) *list.List {
newCommits := list.New()
for e := oldCommits.Front(); e != nil; e = e.Next() {
c := e.Value.(*git.Commit)
c.CommitMessage = string(base.RenderIssueIndexPattern([]byte(c.CommitMessage), repoLink))
c.CommitMessage = c.CommitMessage
newCommits.PushBack(c)
}
return newCommits
@ -206,7 +206,7 @@ func Diff(ctx *middleware.Context) {
commitId := ctx.Repo.CommitId
commit := ctx.Repo.Commit
commit.CommitMessage = string(base.RenderIssueIndexPattern([]byte(commit.CommitMessage), ctx.Repo.RepoLink))
commit.CommitMessage = commit.CommitMessage
diff, err := models.GetDiffCommit(models.RepoPath(userName, repoName),
commitId, setting.Git.MaxGitDiffLines)
if err != nil {

8
routers/repo/download.go

@ -25,16 +25,16 @@ func ServeBlob(ctx *middleware.Context, blob *git.Blob) error {
buf = buf[:n]
}
contentType, isTextFile := base.IsTextFile(buf)
_, isTextFile := base.IsTextFile(buf)
_, isImageFile := base.IsImageFile(buf)
ctx.Resp.Header().Set("Content-Type", contentType)
ctx.Resp.Header().Set("Content-Type", "text/plain")
if !isTextFile && !isImageFile {
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+path.Base(ctx.Repo.TreeName))
ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
}
ctx.Resp.Write(buf)
io.Copy(ctx.Resp, dataRc)
return nil
_, err = io.Copy(ctx.Resp, dataRc)
return err
}
func SingleDownload(ctx *middleware.Context) {

4
routers/repo/view.go

@ -156,9 +156,9 @@ func Home(ctx *middleware.Context) {
for _, f := range files {
switch c := f[1].(type) {
case *git.Commit:
c.CommitMessage = string(base.RenderIssueIndexPattern([]byte(c.CommitMessage), ctx.Repo.RepoLink))
c.CommitMessage = c.CommitMessage
case *git.SubModuleFile:
c.CommitMessage = string(base.RenderIssueIndexPattern([]byte(c.CommitMessage), ctx.Repo.RepoLink))
c.CommitMessage = c.CommitMessage
}
}
ctx.Data["Files"] = files

46
scripts/init/freebsd/gogs

@ -0,0 +1,46 @@
#!/bin/sh
#
# $FreeBSD$
#
# PROVIDE: gogs
# REQUIRE: NETWORKING SYSLOG
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf to enable gogs:
#
#gogs_enable="YES"
. /etc/rc.subr
name="gogs"
rcvar="gogs_enable"
load_rc_config $name
: ${gogs_user:="git"}
: ${gogs_enable:="NO"}
: ${gogs_directory:="/home/git"}
command="${gogs_directory}/scripts/start.sh"
pidfile="${gogs_directory}/${name}.pid"
start_cmd="${name}_start"
stop_cmd="${name}_stop"
gogs_start() {
cd ${gogs_directory}
export USER=${gogs_user}
export HOME=${gogs_directory}
/usr/sbin/daemon -f -u ${gogs_user} -p ${pidfile} $command
}
gogs_stop() {
if [ ! -f $pidfile ]; then
echo "GOGS PID File not found. Maybe GOGS is not running?"
else
kill $(cat $pidfile)
fi
}
run_rc_command "$1"

2
scripts/start.bat

@ -1,2 +0,0 @@
@echo off
..\\gogs.exe web

2
scripts/start.sh

@ -3,7 +3,7 @@
# Use of this source code is governed by a MIT-style
# license that can be found in the LICENSE file.
#
# start gogs web
# MUST EXECUTE THIS AT ROOT DIRECTORY: ./scripts/start.sh
#
IFS='
'

2
templates/.VERSION

@ -1 +1 @@
0.5.12.0120 Beta
0.5.12.0204 Beta

2
templates/admin/config.tmpl

@ -61,7 +61,7 @@
<dt>{{.i18n.Tr "admin.config.db_user"}}</dt>
<dd>{{.DbCfg.User}}</dd>
<dt>{{.i18n.Tr "admin.config.db_ssl_mode"}}</dt>
<dd>{{.DbCfg.SslMode}} {{.i18n.Tr "admin.config.db_ssl_mode_helper"}}</dd>
<dd>{{.DbCfg.SSLMode}} {{.i18n.Tr "admin.config.db_ssl_mode_helper"}}</dd>
<dt>{{.i18n.Tr "admin.config.db_path"}}</dt>
<dd>{{.DbCfg.Path}} {{.i18n.Tr "admin.config.db_path_helper"}}</dd>
</dl>

5
templates/admin/dashboard.tmpl

@ -48,6 +48,11 @@
<td>{{.i18n.Tr "admin.dashboard.git_gc_repos"}}</td>
<td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=4">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td>
</tr>
<tr>
<td>{{.i18n.Tr "admin.dashboard.resync_all_sshkeys"}}</td>
<td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=5">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td>
</tr>
</tbody>
</table>
</div>

6
templates/home.tmpl

@ -28,7 +28,7 @@
<div class="grid-1-2 left">
<i class="octicon octicon-flame"></i>
<b>Einfach zu installieren</b>
<p>Starte einfach <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">die Anwendung</a> für deine Plattform. Gogs gibt es auch für <a target="_blank" href="https://github.com/gogits/gogs/tree/master/dockerfiles">Docker</a>, <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a> oder als <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">Installationspaket</a>.</p>
<p>Starte einfach <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">die Anwendung</a> für deine Plattform. Gogs gibt es auch für <a target="_blank" href="https://github.com/gogits/gogs/tree/master/docker">Docker</a>, <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a> oder als <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">Installationspaket</a>.</p>
</div>
<div class="grid-1-2 left">
<i class="octicon octicon-device-desktop"></i>
@ -49,7 +49,7 @@
<div class="grid-1-2 left">
<i class="octicon octicon-flame"></i>
<b>易安装</b>
<p>您除了可以根据操作系统平台通过 <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">二进制运行</a>,还可以通过 <a target="_blank" href="https://github.com/gogits/gogs/tree/master/dockerfiles">Docker</a> 或 <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a>,以及 <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">包管理</a> 安装。</p>
<p>您除了可以根据操作系统平台通过 <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">二进制运行</a>,还可以通过 <a target="_blank" href="https://github.com/gogits/gogs/tree/master/docker">Docker</a> 或 <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a>,以及 <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">包管理</a> 安装。</p>
</div>
<div class="grid-1-2 left">
<i class="octicon octicon-device-desktop"></i>
@ -70,7 +70,7 @@
<div class="grid-1-2 left">
<i class="octicon octicon-flame"></i>
<b>Easy to install</b>
<p>Simply <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">run the binary</a> for your platform. Or ship Gogs with <a target="_blank" href="https://github.com/gogits/gogs/tree/master/dockerfiles">Docker</a> or <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a>, or get it <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">packaged</a>.</p>
<p>Simply <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">run the binary</a> for your platform. Or ship Gogs with <a target="_blank" href="https://github.com/gogits/gogs/tree/master/docker">Docker</a> or <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a>, or get it <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">packaged</a>.</p>
</div>
<div class="grid-1-2 left">
<i class="octicon octicon-device-desktop"></i>

48
templates/install.tmpl

@ -13,7 +13,7 @@
<div class="text-center panel-desc">{{.i18n.Tr "install.requite_db_desc"}}</div>
<div class="field">
<label class="req">{{.i18n.Tr "install.db_type"}}</label>
<select name="database" id="install-database" class="form-control">
<select name="db_type" id="install-database" class="form-control">
{{range .DbOptions}}
<option value="{{.}}"{{if eq $.CurDbOption .}}selected{{end}}>{{.}}</option>
{{end}}
@ -22,20 +22,20 @@
<div class="server-sql {{if eq .CurDbOption "SQLite3"}}hide{{end}}">
<div class="field">
<label class="req" for="host">{{.i18n.Tr "install.host"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbHost}}ipt-error{{end}}" id="host" name="host" value="{{.host}}" />
<label class="req" for="db_host">{{.i18n.Tr "install.host"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbHost}}ipt-error{{end}}" id="db_host" name="db_host" value="{{.db_host}}" />
</div>
<div class="field">
<label class="req" for="user">{{.i18n.Tr "install.user"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbUser}}ipt-error{{end}}" id="user" name="user" value="{{.user}}" />
<label class="req" for="db_user">{{.i18n.Tr "install.user"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbUser}}ipt-error{{end}}" id="db_user" name="db_user" value="{{.db_user}}" />
</div>
<div class="field">
<label class="req" for="passwd">{{.i18n.Tr "install.password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbPasswd}}ipt-error{{end}}" id="passwd" name="passwd" type="password" value="{{.passwd}}" />
<label class="req" for="db_passwd">{{.i18n.Tr "install.password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbPasswd}}ipt-error{{end}}" id="db_passwd" name="db_passwd" type="password" value="{{.db_passwd}}" />
</div>
<div class="field">
<label class="req" for="database_name">{{.i18n.Tr "install.db_name"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DatabaseName}}ipt-error{{end}}" id="database_name" name="database_name" value="{{.database_name}}" />
<label class="req" for="db_name">{{.i18n.Tr "install.db_name"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbName}}ipt-error{{end}}" id="db_name" name="db_name" value="{{.db_name}}" />
<label></label>
<span class="help">{{.i18n.Tr "install.db_helper"}}</span>
</div>
@ -51,8 +51,8 @@
</div>
<div class="field sqlite-setting {{if not (eq .CurDbOption "SQLite3")}}hide{{end}}">
<label class="req" for="database_path">{{.i18n.Tr "install.path"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DatabasePath}}ipt-error{{end}}" id="database_path" name="database_path" value="{{.database_path}}" />
<label class="req" for="db_path">{{.i18n.Tr "install.path"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbPath}}ipt-error{{end}}" id="db_path" name="db_path" value="{{.db_path}}" />
<label></label>
<span class="help">{{.i18n.Tr "install.sqlite_helper"}}</span>
</div>
@ -61,8 +61,8 @@
<div class="text-center panel-desc">{{.i18n.Tr "install.general_title"}}</div>
<div class="field">
<label class="req" for="repo_path">{{.i18n.Tr "install.repo_path"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_RepoRootPath}}ipt-error{{end}}" id="repo_path" name="repo_path" value="{{.repo_path}}" required />
<label class="req" for="repo_root_path">{{.i18n.Tr "install.repo_path"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_RepoRootPath}}ipt-error{{end}}" id="repo_root_path" name="repo_root_path" value="{{.repo_root_path}}" required />
<label></label>
<span class="help">{{.i18n.Tr "install.repo_path_helper"}}</span>
</div>
@ -78,6 +78,12 @@
<label></label>
<span class="help">{{.i18n.Tr "install.domain_helper"}}</span>
</div>
<div class="field">
<label class="req" for="http_port">{{.i18n.Tr "install.http_port"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_HttpPort}}ipt-error{{end}}" id="http_port" name="http_port" value="{{.http_port}}" required />
<label></label>
<span class="help">{{.i18n.Tr "install.http_port_helper"}}</span>
</div>
<div class="field">
<label class="req" for="app_url">{{.i18n.Tr "install.app_url"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AppUrl}}ipt-error{{end}}" id="app_url" name="app_url" value="{{.app_url}}" required />
@ -93,12 +99,12 @@
<input class="ipt ipt-large ipt-radius {{if .Err_SmtpHost}}ipt-error{{end}}" id="smtp_host" name="smtp_host" value="{{.smtp_host}}" />
</div>
<div class="field">
<label for="mailer_user">{{.i18n.Tr "install.mailer_user"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_SmtpEmail}}ipt-error{{end}}" id="mailer_user" name="mailer_user" value="{{.mailer_user}}" />
<label for="smtp_user">{{.i18n.Tr "install.mailer_user"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_SMTPEmail}}ipt-error{{end}}" id="smtp_user" name="smtp_user" value="{{.smtp_user}}" />
</div>
<div class="field">
<label for="mailer_pwd">{{.i18n.Tr "install.mailer_password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_SmtpPasswd}}ipt-error{{end}}" id="mailer_pwd" name="mailer_pwd" type="password" value="{{.mailer_pwd}}" />
<label for="smtp_pwd">{{.i18n.Tr "install.mailer_password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_SMTPPasswd}}ipt-error{{end}}" id="smtp_pwd" name="smtp_pwd" type="password" value="{{.smtp_pwd}}" />
</div>
<hr>
@ -122,12 +128,12 @@
<input class="ipt ipt-large ipt-radius {{if .Err_AdminName}}ipt-error{{end}}" id="admin_name" name="admin_name" value="{{.admin_name}}" required />
</div>
<div class="field">
<label class="req" for="admin_pwd">{{.i18n.Tr "install.admin_password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AdminPasswd}}ipt-error{{end}}" id="admin_pwd" name="admin_pwd" type="password" value="{{.admin_pwd}}" required />
<label class="req" for="admin_passwd">{{.i18n.Tr "install.admin_password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AdminPasswd}}ipt-error{{end}}" id="admin_passwd" name="admin_passwd" type="password" value="{{.admin_passwd}}" required />
</div>
<div class="field">
<label class="req" for="confirm_passwd">{{.i18n.Tr "install.confirm_password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AdminPasswd}}ipt-error{{end}}" id="confirm_passwd" name="confirm_passwd" type="password" required />
<label class="req" for="admin_confirm_passwd">{{.i18n.Tr "install.confirm_password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AdminPasswd}}ipt-error{{end}}" id="admin_confirm_passwd" name="admin_confirm_passwd" type="password" required />
</div>
<div class="field">
<label class="req" for="admin_email">{{.i18n.Tr "install.admin_email"}}</label>

2
templates/repo/commits_table.tmpl

@ -32,7 +32,7 @@
{{end}}
</td>
<td class="sha"><a rel="nofollow" class="label label-green" href="{{AppSubUrl}}/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
<td class="message"><span class="text-truncate">{{Str2html .Summary}}</span></td>
<td class="message"><span class="text-truncate">{{RenderCommitMessage .Summary $.RepoLink}}</span></td>
<td class="date">{{TimeSince .Author.When $.Lang}}</td>
</tr>
{{end}}

22
templates/repo/diff.tmpl

@ -17,7 +17,7 @@
<div class="panel panel-info panel-radius diff-head-box">
<div class="panel-header">
<a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{.SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a>
<h4 class="commit-message">{{Str2html .Commit.Message}}</h4>
<h4 class="commit-message">{{RenderCommitMessage .Commit.Message $.RepoLink}}</h4>
</div>
<div class="panel-body">
<span class="pull-right">
@ -74,11 +74,11 @@
</ol>
</div>
{{range .Diff.Files}}
{{range $i, $file := .Diff.Files}}
<div class="panel panel-radius diff-file-box diff-box file-content" id="diff-{{.Index}}">
<div class="panel-header">
<div class="diff-counter count pull-left">
{{if not .IsBin}}
{{if not $file.IsBin}}
<span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span>
<span class="bar">
<span class="pull-left add"></span>
@ -90,9 +90,9 @@
{{end}}
</div>
<a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{$.SourcePath}}/{{.Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
<span class="file">{{.Name}}</span>
<span class="file">{{$file.Name}}</span>
</div>
{{$isImage := (call $.IsImageFile .Name)}}
{{$isImage := (call $.IsImageFile $file.Name)}}
<div class="panel-body file-body file-code code-view code-diff">
{{if $isImage}}
<div class="text-center">
@ -101,18 +101,18 @@
{{else}}
<table>
<tbody>
{{range .Sections}}
{{range .Lines}}
<tr class="{{DiffLineTypeToStr .Type}}-code nl-1 ol-1">
{{range $j, $section := $file.Sections}}
{{range $k, $line := $section.Lines}}
<tr class="{{DiffLineTypeToStr .Type}}-code nl-{{$i}} ol-{{$i}}">
<td class="lines-num lines-num-old">
<span rel="L1">{{if .LeftIdx}}{{.LeftIdx}}{{end}}</span>
<span rel="diff-{{Add $i 1}}L{{$j}}{{$k}}">{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}</span>
</td>
<td class="lines-num lines-num-new">
<span rel="L1">{{if .RightIdx}}{{.RightIdx}}{{end}}</span>
<span rel="diff-{{Add $i 1}}L{{$j}}{{$k}}">{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}</span>
</td>
<td class="lines-code">
<pre>{{.Content}}</pre>
<pre>{{$line.Content}}</pre>
</td>
</tr>
{{end}}

4
templates/repo/view_list.tmpl

@ -14,7 +14,7 @@
</span>
<span class="last-commit"><a href="{{.RepoLink}}/commit/{{.LastCommit.Id}}" rel="nofollow">
<strong>{{ShortSha .LastCommit.Id.String}}</strong></a>
<span class="text-truncate">{{Str2html .LastCommit.Summary}}</span>
<span class="text-truncate">{{RenderCommitMessage .LastCommit.Summary .RepoLink}}</span>
</span>
<span class="age right">{{TimeSince .LastCommit.Author.When $.Lang}}</span>
</th>
@ -53,7 +53,7 @@
<a rel="nofollow" class="label label-green" href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}} ">{{SubStr $commit.Id.String 0 10}} </a>
</td>
<td class="message">
<span class="text-truncate">{{Str2html $commit.Summary}}</span>
<span class="text-truncate">{{RenderCommitMessage $commit.Summary $.RepoLink}}</span>
</td>
<td class="age">{{TimeSince $commit.Committer.When $.Lang}}</td>
</tr>

18
templates/user/settings/email.tmpl

@ -36,19 +36,21 @@
{{end}}
</li>
{{end}}
<form action="{{AppSubUrl}}/user/settings/email" method="post">
{{.CsrfTokenHtml}}
<p class="panel-header"><strong>{{.i18n.Tr "settings.add_new_email"}}</strong></p>
<p class="field">
</ul>
<div class="panel-header">
<strong>{{.i18n.Tr "settings.add_new_email"}}</strong>
</div>
<form class="form form-align panel-body" id="add-email-form" action="{{AppSubUrl}}/user/settings/email" method="post">
{{.CsrfTokenHtml}}
<p class="field">
<label class="req" for="email">{{.i18n.Tr "email"}}</label>
<input class="ipt ipt-radius" id="email" name="email" type="text" required />
<input class="ipt ipt-large ipt-radius" id="email" name="email" type="text" required />
</p>
<p class="field">
<label></label>
<button class="btn btn-green btn-radius" id="email-add-btn">{{.i18n.Tr "settings.add_email"}}</button>
<button class="btn btn-green btn-large btn-radius" id="email-add-btn">{{.i18n.Tr "settings.add_email"}}</button>
</p>
</form>
</ul>
</form>
</div>
</div>
</div>

2
templates/user/settings/nav.tmpl

@ -4,7 +4,7 @@
<ul class="menu menu-vertical switching-list grid-1-5 left">
<li {{if .PageIsSettingsProfile}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings">{{.i18n.Tr "settings.profile"}}</a></li>
<li {{if .PageIsSettingsPassword}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/password">{{.i18n.Tr "settings.password"}}</a></li>
<li {{if .PageIsSettingsEmail}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/email">{{.i18n.Tr "settings.emails"}}</a></li>
<li {{if .PageIsSettingsEmails}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/email">{{.i18n.Tr "settings.emails"}}</a></li>
<li {{if .PageIsSettingsSSHKeys}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/ssh">{{.i18n.Tr "settings.ssh_keys"}}</a></li>
<li {{if .PageIsSettingsSocial}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/social">{{.i18n.Tr "settings.social"}}</a></li>
<li {{if .PageIsSettingsApplications}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/applications">{{.i18n.Tr "settings.applications"}}</a></li>

Loading…
Cancel
Save