diff --git a/.bra.toml b/.bra.toml index a5afa27675..d0229e8ab9 100644 --- a/.bra.toml +++ b/.bra.toml @@ -1,5 +1,8 @@ [run] -init_cmds = [["./gogs", "web"]] +init_cmds = [ + ["grep", "-rn", "FIXME", "."], + ["./gogs", "web"] +] watch_all = true watch_dirs = [ "$WORKDIR/conf/locale", @@ -11,7 +14,7 @@ watch_dirs = [ watch_exts = [".go", ".ini"] build_delay = 1500 cmds = [ - ["go", "install"], - ["go", "build"], + ["go", "install", "-tags", "sqlite cert"], + ["go", "build", "-tags", "sqlite cert"], ["./gogs", "web"] ] \ No newline at end of file diff --git a/.gobuild.yml b/.gobuild.yml index 23c7c43cd3..3a2f361d56 100644 --- a/.gobuild.yml +++ b/.gobuild.yml @@ -16,6 +16,6 @@ settings: then go install -v else - go get -v -tags "sqlite redis memecache" github.com/gogits/gogs - go install -v -tags "sqlite redis memecache" + go get -v -tags "sqlite redis memcache cert" github.com/gogits/gogs + go install -v -tags "sqlite redis memcache cert" fi diff --git a/.gopmfile b/.gopmfile index 3ba514afc8..8f13d5157b 100644 --- a/.gopmfile +++ b/.gopmfile @@ -8,7 +8,7 @@ github.com/Unknwon/cae = commit:2e70a1351b github.com/Unknwon/com = commit:2cbcbc6916 github.com/Unknwon/goconfig = commit:0f8d8dc1c0 github.com/Unknwon/i18n = commit:47baeff8d0 -github.com/Unknwon/macaron = +github.com/Unknwon/macaron = commit:4927b78ad9 github.com/codegangsta/cli = commit:7381bc4e62 github.com/go-sql-driver/mysql = commit:8111ee3ec3 github.com/go-xorm/core = commit:750aae0fa5 @@ -17,13 +17,14 @@ github.com/gogits/gfm = commit:40f747a9c0 github.com/gogits/oauth2 = commit:99cbec870a github.com/lib/pq = commit:b021d0ef20 github.com/macaron-contrib/cache = commit:204d8e5137 -github.com/macaron-contrib/captcha = -github.com/macaron-contrib/csrf = -github.com/macaron-contrib/i18n = -github.com/macaron-contrib/session = +github.com/macaron-contrib/captcha = commit:d37d37eeea +github.com/macaron-contrib/csrf = commit:8e980822b0 +github.com/macaron-contrib/i18n = commit:2246f45894 +github.com/macaron-contrib/session = commit:42ad41e323 github.com/macaron-contrib/toolbox = commit:57127bcc89 github.com/mattn/go-sqlite3 = commit:a80c27ba33 github.com/nfnt/resize = commit:581d15cb53 +github.com/russross/blackfriday = commit:05b8cefd6a github.com/saintfish/chardet = commit:3af4cd4741 [res] diff --git a/README.md b/README.md index b7ff264e35..b6dd1ea5fd 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -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://drone.io/github.com/gogits/gogs/status.png)](https://drone.io/github.com/gogits/gogs/latest) +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) is a painless self-hosted Git Service written in Go. ![Demo](https://gowalker.org/public/gogs_demo.gif) -##### Current version: 0.5.4 Beta +##### Current version: 0.5.5 Beta ### NOTICES @@ -32,11 +32,13 @@ The goal of this project is to make the easiest, fastest and most painless way t - Activity timeline - SSH/HTTP(S) protocol support - SMTP/LDAP/reverse proxy authentication support +- Reverse proxy suburl support - Register/delete/rename account - Create/manage/delete organization with team management - Create/migrate/mirror/delete/watch/rename/transfer public/private repository - Repository viewer/release/issue tracker - Repository and Organization level webhooks +- Repository Git hooks - Add/remove repository collaborators - Gravatar and cache support - Mail service(register, issue) @@ -44,7 +46,7 @@ The goal of this project is to make the easiest, fastest and most painless way t - Slack webhook integration - Supports MySQL, PostgreSQL and SQLite3 - Social account login(GitHub, Google, QQ, Weibo) -- Multi-language support(English, Chinese, Germany, French etc.) +- Multi-language support(English, Simplified Chinese, Traditional Chinese, Germany, French, Dutch etc.) ## System Requirements @@ -57,7 +59,7 @@ Make sure you install [Prerequirements](http://gogs.io/docs/installation/) first There are 5 ways to install Gogs: -- [Install from binary](http://gogs.io/docs/installation/install_from_binary.md): **STRONGLY RECOMMENDED** +- [Install from binary](http://gogs.io/docs/installation/install_from_binary.md) - [Install from source](http://gogs.io/docs/installation/install_from_source.md) - [Install from packages](http://gogs.io/docs/installation/install_from_packages.md) - [Ship with Docker](https://github.com/gogits/gogs/tree/master/docker) diff --git a/README_ZH.md b/README_ZH.md index d704053f22..a8cefa44f9 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -1,11 +1,11 @@ -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://drone.io/github.com/gogits/gogs/status.png)](https://drone.io/github.com/gogits/gogs/latest) +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) 是一个基于 Go 语言的自助 Git 服务。 ![Demo](https://gowalker.org/public/gogs_demo.gif) -##### 当前版本:0.5.4 Beta +##### 当前版本:0.5.5 Beta ## 开发目的 @@ -23,19 +23,21 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自 - 活动时间线 - 支持 SSH/HTTP(S) 协议 - 支持 SMTP/LDAP/反向代理 用户认证 -- 注册/删除/重命名 用户 -- 创建/管理/删除 组织以及团队管理功能 -- 创建/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库 -- 仓库 浏览/发布/工单管理 -- 仓库和组织级别 Web 钩子 -- 添加/删除 仓库协作者 -- Gravatar 以及缓存支持 -- 邮件服务(注册、Issue) +- 支持反向代理子路径 +- 支持 注册/删除/重命名 用户 +- 支持 创建/管理/删除 组织以及团队管理功能 +- 支持 创建/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库 +- 支持仓库 浏览/发布/工单管理 +- 支持仓库和组织级别 Web 钩子 +- 支持仓库 Git 钩子 +- 支持 添加/删除 仓库协作者 +- 支持 Gravatar 以及本地缓存 +- 支持邮件服务(注册、Issue) - 管理员面板 - Slack Web 钩子集成 - 支持 MySQL、PostgreSQL 以及 SQLite3 数据库 - 社交帐号登录(GitHub、Google、QQ、微博) -- 多语言支持(英文、简体中文、德语、法语等等) +- 多语言支持(英文、简体中文、繁体中文、德语、法语、荷兰语等等) ## 系统要求 @@ -48,7 +50,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自 然后,您可以通过以下 5 种方式来安装 Gogs: -- [二进制安装](http://gogs.io/docs/installation/install_from_binary.md): **强烈推荐** +- [二进制安装](http://gogs.io/docs/installation/install_from_binary.md) - [源码安装](http://gogs.io/docs/installation/install_from_source.md) - [包管理安装](http://gogs.io/docs/installation/install_from_packages.md) - [采用 Docker 部署](https://github.com/gogits/gogs/tree/master/docker) diff --git a/cmd/cert.go b/cmd/cert.go index b693b7d94e..631c4c6823 100644 --- a/cmd/cert.go +++ b/cmd/cert.go @@ -1,3 +1,5 @@ +// +build cert + // Copyright 2009 The Go Authors. All rights reserved. // Copyright 2014 The Gogs Authors. All rights reserved. // Use of this source code is governed by a MIT-style diff --git a/cmd/cert_stub.go b/cmd/cert_stub.go new file mode 100644 index 0000000000..2029f4cbce --- /dev/null +++ b/cmd/cert_stub.go @@ -0,0 +1,34 @@ +// +build !cert + +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +package cmd + +import ( + "fmt" + "time" + + "github.com/codegangsta/cli" +) + +var CmdCert = cli.Command{ + Name: "cert", + Usage: "Generate self-signed certificate", + Description: `Generate a self-signed X.509 certificate for a TLS server. +Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`, + Action: runCert, + Flags: []cli.Flag{ + cli.StringFlag{"host", "", "Comma-separated hostnames and IPs to generate a certificate for", ""}, + cli.StringFlag{"ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521", ""}, + cli.IntFlag{"rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set", ""}, + cli.StringFlag{"start-date", "", "Creation date formatted as Jan 1 15:04:05 2011", ""}, + cli.DurationFlag{"duration", 365 * 24 * time.Hour, "Duration that certificate is valid for", ""}, + cli.BoolFlag{"ca", "whether this cert should be its own Certificate Authority", ""}, + }, +} + +func runCert(ctx *cli.Context) { + fmt.Println("Command cert not available, please use build tags 'cert' to rebuild.") +} diff --git a/cmd/dump.go b/cmd/dump.go index 414912243c..fe3763f077 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -60,6 +60,7 @@ func runDump(ctx *cli.Context) { z.AddFile("gogs-db.sql", path.Join(workDir, "gogs-db.sql")) z.AddFile("custom/conf/app.ini", path.Join(workDir, "custom/conf/app.ini")) z.AddDir("log", path.Join(workDir, "log")) + // FIXME: SSH key file. if err = z.Close(); err != nil { os.Remove(fileName) log.Fatalf("Fail to save %s: %v", fileName, err) diff --git a/cmd/web.go b/cmd/web.go index 72a58bc995..395658f6ed 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -61,10 +61,18 @@ func checkVersion() { log.Fatal(4, "Binary and template file version does not match, did you forget to recompile?") } - // Macaron. + // Check dependency version. macaronVer := git.MustParseVersion(strings.Join(strings.Split(macaron.Version(), ".")[:3], ".")) - if macaronVer.LessThan(git.MustParseVersion("0.1.8")) { - log.Fatal(4, "Macaron version does not match, did you forget to update?(github.com/Unknwon/macaron)") + if macaronVer.LessThan(git.MustParseVersion("0.2.0")) { + log.Fatal(4, "Package macaron version is too old, did you forget to update?(github.com/Unknwon/macaron)") + } + i18nVer := git.MustParseVersion(i18n.Version()) + if i18nVer.LessThan(git.MustParseVersion("0.0.2")) { + log.Fatal(4, "Package i18n version is too old, did you forget to update?(github.com/macaron-contrib/i18n)") + } + sessionVer := git.MustParseVersion(session.Version()) + if sessionVer.LessThan(git.MustParseVersion("0.0.1")) { + log.Fatal(4, "Package session version is too old, did you forget to update?(github.com/macaron-contrib/session)") } } @@ -88,10 +96,12 @@ func newMacaron() *macaron.Macaron { IndentJSON: macaron.Env != macaron.PROD, })) m.Use(i18n.I18n(i18n.Options{ - SubURL: setting.AppSubUrl, - Langs: setting.Langs, - Names: setting.Names, - Redirect: true, + SubURL: setting.AppSubUrl, + Directory: path.Join(setting.ConfRootPath, "locale"), + CustomDirectory: path.Join(setting.CustomPath, "conf/locale"), + Langs: setting.Langs, + Names: setting.Names, + Redirect: true, })) m.Use(cache.Cacher(cache.Options{ Adapter: setting.CacheAdapter, @@ -239,6 +249,11 @@ func runWeb(*cli.Context) { r.Post("/:authid", bindIgnErr(auth.AuthenticationForm{}), admin.EditAuthSourcePost) r.Post("/:authid/delete", admin.DeleteAuthSource) }) + + m.Group("/notices", func(r *macaron.Router) { + r.Get("", admin.Notices) + r.Get("/:id:int/delete", admin.DeleteNotice) + }) }, adminReq) m.Get("/:username", ignSignIn, user.Profile) @@ -313,6 +328,12 @@ func runWeb(*cli.Context) { r.Get("/hooks/:id", repo.WebHooksEdit) r.Post("/hooks/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) r.Post("/hooks/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) + + m.Group("/hooks/git", func(r *macaron.Router) { + r.Get("", repo.GitHooks) + r.Get("/:name", repo.GitHooksEdit) + r.Post("/:name", repo.GitHooksEditPost) + }, middleware.GitHookService()) }) }, reqSignIn, middleware.RepoAssignment(true), reqTrueOwner) diff --git a/conf/app.ini b/conf/app.ini index 6c65fd2136..d8bbeb70a4 100644 --- a/conf/app.ini +++ b/conf/app.ini @@ -70,6 +70,8 @@ ENABLE_CACHE_AVATAR = false ENABLE_NOTIFY_MAIL = false ; More detail: https://github.com/gogits/gogs/issues/165 ENABLE_REVERSE_PROXY_AUTHENTICATION = false +; Repository Git hooks +ENABLE_GIT_HOOKS = false [webhook] ; Cron task interval in minutes @@ -256,5 +258,5 @@ CONN = MAX_GITDIFF_LINES = 10000 [i18n] -LANGS = en-US,zh-CN,de-DE,fr-CA -NAMES = English,简体中文,Deutsch,Français \ No newline at end of file +LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL +NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands diff --git a/conf/locale/locale_de-DE.ini b/conf/locale/locale_de-DE.ini index cc8b0b5d52..651fdac0c7 100644 --- a/conf/locale/locale_de-DE.ini +++ b/conf/locale/locale_de-DE.ini @@ -5,9 +5,9 @@ dashboard = Dashboard explore = Erkunden help = Hilfe sign_in = Anmelden -social_sign_in = Social Sign In: 2nd Step associate account +social_sign_in = Anmeldung über soziales Konto: zweiter Schritt Konto verknüpfen sign_out = Abmelden -sign_up = Sign up +sign_up = Registrieren register = Registrieren website = Webseite version = Version @@ -18,7 +18,7 @@ language = Sprache username = Benutzername email = E-Mail password = Passwort -re_type = wiederholen +re_type = Passwort bestätigen captcha = Captcha repository = Repository @@ -60,11 +60,11 @@ domain = Domain domain_helper = Dies hat Auswirkung auf die SSH clone URLs. app_url = Anwendungs-URL app_url_helper = Dies hat Auswirkung auf die HTTP/HTTPS clone URLs und für die E-Mails. -email_title = E-Mail-Service-Einstellungen(Optional) +email_title = E-Mail-Service-Einstellungen (optional) smtp_host = SMTP Host mailer_user = Sender E-mail mailer_password = Sender Passwort -notify_title = Benachrichtigungseinstellungen(Optional) +notify_title = Benachrichtigungseinstellungen (optional) register_confirm = Registrierungsbestätigung aktvieren mail_notify = E-Mail-Benachrichtgung aktivieren admin_title = Konto-Einstellungen für den Administrator @@ -85,14 +85,14 @@ install_success = Herzlich Willkommen! Wir sind froh, dass du dich für Gogs ent [home] uname_holder = Benutzername oder E-Mail password_holder = Passwort -switch_dashboard_context = Switch Dashboard Context +switch_dashboard_context = Dashboard Kontext wechseln my_repos = Meine Repositorys collaborative_repos = Gemeinschaftliche Repositorys my_orgs = Meine Organisationen my_mirrors = Meine Spiegel [explore] -repos = Repositories +repos = Repositorys [auth] create_new_account = Neues Konto erstellen @@ -104,9 +104,9 @@ remember_me = angemeldet bleiben forgot_password= Passwort vergessen forget_password = Passwort vergessen? sign_up_now = Du willst ein Konto? Jetzt registrieren! -confirmation_mail_sent_prompt = Eine neu Bestätigungs-E-Mail wurde an %s gesendet. Kontrolliere dein Postfach innerhalb der nächsten %d Stunden um die Registrierung abzuschließen. -sign_in_email = Melden dich mit deiner E-Mail-Adresse an -active_your_account = Aktivieren dein Konto +confirmation_mail_sent_prompt = Eine neue Bestätigungs-E-Mail wurde an %s gesendet. Kontrolliere dein Postfach innerhalb der nächsten %d Stunden, um die Registrierung abzuschließen. +sign_in_email = Melde dich mit deiner E-Mail-Adresse an +active_your_account = Aktiviere dein Konto resent_limit_prompt = Es tut uns leid, du sendest zu häufig Aktivierungs-E-Mails. Bitte warte 3 Minuten. has_unconfirmed_mail = Hallo %s, du hast eine unbestätigte E-Mail-Adresse (%s). Falls du noch keine Bestätigungs-E-Mail erhalten hast oder eine neue senden musst, klicke auf den unteren Button. resend_mail = Hier klicken, um deine Aktivierungs-E-Mail erneut zu versenden @@ -122,7 +122,7 @@ UserName = Benutzername RepoName = Repository-Name Email = E-Mail-Adresse Password = Passwort -Retype = Passwort erneut eingeben +Retype = Passwort bestätigen SSHTitle = SSH-Schlüsselname HttpsUrl = HTTPS-URL PayloadUrl = Payload-URL @@ -158,7 +158,7 @@ enterred_invalid_password = Bitte stelle sicher, dass das eingegebene Passwort r user_not_exist = Angegebener Benutzer existiert nicht. last_org_owner = Der zu entfernende Benutzer ist der letzte Teambesitzer. Es muss einen anderen Besitzer geben. -invalid_ssh_key = Leider sind wir nicht in der Lage, Ihren SSH-Schlüssel zu überprüfen: %s +invalid_ssh_key = Leider sind wir nicht in der Lage, deinen SSH-Schlüssel zu überprüfen: %s auth_failed = Authentifizierung fehlgeschlagen: %v still_own_repo = Dein Konto besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden. @@ -166,6 +166,15 @@ org_still_own_repo = Diese Organisation besitzt noch Repositorys. Diese müssen still_own_user = Diese Authentifizierung wird noch von einigen Benutzern genutzt. Entferne diese zuvor und lösche erneut. +[user] +change_avatar = Ändere dein Profilbild auf gravatar.com +join_on = Registriert +repositories = Repositorys +activity = Öffentliche Aktivität +followers = Folgen +starred = Markiert +following = Folgt + [settings] profile = Profil password = Passwort @@ -260,7 +269,7 @@ settings.transfer = Besitz übertragen settings.transfer_desc = Übertrage dieses Repository einem anderen Benutzer oder einer Organisation. settings.new_owner_has_same_repo = Neuer Eigentümer hat bereits ein Repository mit dem gleichen Namen. settings.delete = Repository löschen -settings.delete_desc = Wenn dieses Repository gelöschet ist, gibt es keinen Weg zurück. Sei dir sicher! +settings.delete_desc = Wenn dieses Repository gelöscht ist, gibt es keinen Weg zurück. Sei dir sicher! settings.update_settings_success = Repository-Optionen aktualisiert settings.transfer_owner = Neuer Besitzer settings.make_transfer = übertragen @@ -285,7 +294,7 @@ settings.update_webhook = Webhook aktualisieren settings.update_hook_success = Webhook aktualisiert settings.delete_webhook = Webhook löschen settings.recent_deliveries = letzte Zustellungen -settings.hook_type = Hook Type +settings.hook_type = Hook Typ settings.add_slack_hook_desc = Add Slack integration to your repository. settings.slack_token = Token settings.slack_domain = Domain @@ -321,7 +330,7 @@ settings.delete = Organisation löschen settings.delete_account = Diese Organisation löschen settings.delete_prompt = Die Organisation wird dauerhaft gelöscht. Dies kann NICHT rückgängig gemacht werden! settings.confirm_delete_account = Löschen -settings.hooks_desc = Add webhooks that will be triggered for all repositories under this organization. +settings.hooks_desc = Füge Webhooks hinzu, die für alle Repositorys dieser Organisation ausgelöst werden. members.public = Öffentlich members.public_helper = Privat machen @@ -372,8 +381,8 @@ next = vor dashboard.statistic = Statistik dashboard.operations = Operationen dashboard.system_status = System-Monitor-Status -dashboard.statistic_info = GoGS Datenbank hat %d Benutzer, %d Organizationen, %d öffentliche Schlüssel, %d Repositorys, %d watches, %d stars, %d actions, %d Zugriffe, %d issues, %d Kommentare, %d soziale Konten, %d follows, %d Spiegel, %d Releases, %d Login-Quellen, %d Webhooks, %d Milestones, %d Labels, %d Hook-Tasks, %d Teams, %d Aktualisierungs-Tasks, %d Anhänge. -dashboard.operation_name = Operation Name +dashboard.statistic_info = GoGS Datenbank hat %d Benutzer, %d Organisationen, %d öffentliche Schlüssel, %d Repositorys, %d Beobachtungen, %d Markierungen, %d Aktionen, %d Zugriffe, %d Issues, %d Kommentare, %d soziale Konten, %d Folgende, %d Spiegel, %d Releases, %d Login-Quellen, %d Webhooks, %d Milestones, %d Labels, %d Hook-Tasks, %d Teams, %d Aktualisierungs-Tasks, %d Anhänge. +dashboard.operation_name = Name der Operation dashboard.operation_switch = Switch dashboard.operation_run = Ausführen dashboard.clean_unbind_oauth = ungebundene OAuths bereinigen @@ -436,8 +445,8 @@ repos.repo_manage_panel = Repositorys repos.owner = Besitzer repos.name = Name repos.private = Privat -repos.watches = Watches -repos.stars = Stars +repos.watches = Beobachtungen +repos.stars = Markierungen repos.issues = Issues auths.auth_manage_panel = Authentifizierung @@ -493,11 +502,11 @@ config.db_path_helper = (nur für "sqlite3") config.service_config = Service-Einstellungen config.register_email_confirm = E-Mail-Bestätigung bei Registrierung config.disable_register = Registrierung deaktivieren -config.require_sign_in_view = Require Sign In View +config.require_sign_in_view = Ansehen erfordert Registrierung config.mail_notify = E-Mail-Benachrichtigung config.enable_cache_avatar = Avatar-Cache aktivieren -config.active_code_lives = Active Code Lives -config.reset_password_code_lives = Reset Password Code Lives +config.active_code_lives = Aktivierungscode Lebensdauer +config.reset_password_code_lives = Passwortcode Lebensdauer config.webhook_config = Webhook-Einstellungen config.task_interval = Task-Intervall config.deliver_timeout = Zeitlimit für Zustellung @@ -516,7 +525,7 @@ config.session_config = Session-Einstellungen config.session_provider = Session-Provider config.provider_config = Provider-Einstellungen config.cookie_name = Cookie-Name -config.enable_set_cookie = Enable Set Cookie +config.enable_set_cookie = Cookies einschalten config.gc_interval_time = GC-Intervallzeit config.session_life_time = Session-Lebensdauer config.https_only = nur HTTPS @@ -534,7 +543,7 @@ monitor.name = Name monitor.schedule = Zeitplan monitor.next = nächste Ausführung monitor.previous = letzte Ausführung -monitor.execute_times = Execute Times +monitor.execute_times = Anzahl Ausführungen monitor.process = Laufende Prozesse monitor.desc = Beschreibung monitor.start = Startzeit diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini index 8e68fb9803..f99a9e7285 100644 --- a/conf/locale/locale_en-US.ini +++ b/conf/locale/locale_en-US.ini @@ -159,6 +159,7 @@ user_not_exist = Given user does not exist. last_org_owner = The user to remove is the last member in owner team. There must be another owner. invalid_ssh_key = Sorry, we're not able to verify your SSH key: %s +unable_verify_ssh_key = Gogs cannot verify your SSH key, but we assume that is valid, please make sure yourself. auth_failed = Authentication failed: %v still_own_repo = Your account still have ownership of repository, you have to delete or transfer them first. @@ -273,6 +274,9 @@ tags = Tags issues = Issues commits = Commits releases = Releases +file_raw = Raw +file_history = History +file_view_raw = View Raw commits.commits = Commits commits.search = Search commits @@ -287,6 +291,7 @@ settings = Settings settings.options = Options settings.collaboration = Collaboration settings.hooks = Webhooks +settings.githooks = Git Hooks settings.deploy_keys = Deploy Keys settings.basic_settings = Basic Settings settings.danger_zone = Danger Zone @@ -308,8 +313,14 @@ settings.confirm_delete = Confirm Deletion settings.add_collaborator = Add New Collaborator settings.add_collaborator_success = New collaborator has been added. settings.remove_collaborator_success = Collaborator has been removed. +settings.user_is_org_member = User is organization member who cannot be added as a collaborator. settings.add_webhook = Add 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 Webhooks Guide. +settings.githooks_desc = Git Hooks are powered by Git itself, you can edit files of supported hooks in the list below to apply custom operations. +settings.githook_edit_desc = If hook is not active, sample content will be presented. Leave content to be blank will disable this hook. +settings.githook_name = Hook Name +settings.githook_content = Hook Content +settings.update_githook = Update Hook settings.remove_hook_success = Webhook has been removed. settings.add_webhook_desc = We’ll send a POST request to the URL below with details of any subscribed events. You can also specify which data format you'd like to receive (JSON, x-www-form-urlencoded, etc). More information can be found in Webhooks Guide. settings.payload_url = Payload URL @@ -330,6 +341,15 @@ settings.slack_token = Token settings.slack_domain = Domain settings.slack_channel = Channel +diff.browse_source = Browse Source +diff.parent = parent +diff.commit = commit +diff.data_not_available = Diff Data Not Available. +diff.show_diff_stats = Show Diff Stats +diff.stats_desc = %d changed files with %d additions and %d deletions +diff.bin = BIN +diff.view_file = View File + [org] org_name_holder = Organization Name org_name_helper = Great organization names are short and memorable. @@ -402,6 +422,7 @@ teams.admin_permission_desc = This team grants Admin access: me teams.repositories = Team Repositories teams.add_team_repository = Add Team Repository teams.remove_repo = Remove +teams.add_nonexistent_repo = The repository you're trying to add does not exist, please create it first. [admin] dashboard = Dashboard @@ -410,6 +431,7 @@ organizations = Organizations repositories = Repositories authentication = Authentications config = Configuration +notices = System Notices monitor = Monitoring prev = Prev. next = Next @@ -587,12 +609,21 @@ monitor.desc = Description monitor.start = Start Time monitor.execute_time = Execution Time +notices.system_notice_list = System Notices +notices.type = Type +notices.type_1 = Repository +notices.desc = Description +notices.op = Op. +notices.delete_success = System notice has been successfully deleted. + [action] create_repo = created repository %s commit_repo = pushed to %s at %s create_issue = opened issue %s#%s comment_issue = commented on issue %s#%s transfer_repo = transfered repository %s to %s +push_tag = pushed tag %s to %s +compare_2_commits = View comparison for these 2 commits [tool] ago = ago diff --git a/conf/locale/locale_nl-NL.ini b/conf/locale/locale_nl-NL.ini new file mode 100644 index 0000000000..4943951f44 --- /dev/null +++ b/conf/locale/locale_nl-NL.ini @@ -0,0 +1,585 @@ +app_desc = Een pijnloze self-hosted Git-dienst geschreven in Go +home = Home +dashboard = Dashboard +explore = Verkennen +help = Help +sign_in = Inloggen +social_sign_in = Social netwerk inlog: tweede stap account koppelen +sign_out = Afmelden +sign_up = Aanmelden +register = Registreer +website = Website +version = Versie +page = Pagina +template = Template +language = Taal +username = Gebruikersnaam +email = E-mail +password = Wachttwoord +re_type = Verificatie +captcha = Captcha +repository = Repositorie +organization = Organisatie +mirror = Mirror +new_repo = Nieuwe repositorie +new_migrate = Nieuwe migratie +new_org = Nieuwe organisatie +manage_org = Beheer organisaties +admin_panel = Adminpaneel +account_settings = Accountinstellingen +settings = Instellingen +news_feed = Nieuwsfeed +pull_requests = Pull-aanvragen +issues = Issues +cancel = Annuleer + +[home] +uname_holder = Gebruikersnaam of e-mail +password_holder = Wachtwoord +switch_dashboard_context = Wissel voorpaginacontext +my_repos = Mijn repositories +collaborative_repos = Gedeelde repositories +my_orgs = Mijn organisaties +my_mirrors = Mijn mirrors + +[auth] +create_new_account = Maak nieuw account aan +register_hepler_msg = Heeft u al een account? Meld u nu aan! +social_register_hepler_msg = Heeft u al een account? Koppel nu! +disable_register_prompt = Sorry, registratie is uitgeschakeld. Neem contact op met de beheerder van deze site. +disable_register_mail = Sorry, bevestiging van registratie per e-mail is uitgeschakeld. +remember_me = Onthoud mij +forgot_password = Wachtwoord vergeten +forget_password = Wachtwoord vergeten? +sign_up_now = Een account nodig? Meld u nu aan. +confirmation_mail_sent_prompt = Een bevestigingsemail is gestuurd naar %s, Bevestig u aanvraag binnen %d uren om uw registratie te voltooien. +sign_in_email = Meld u aan met uw e-mailadres +active_your_account = Activeer uw account +resent_limit_prompt = Sorry, u heeft te snel na elkaar een aanvraag gedaan voor een activatie mail. Wacht drie minuten voor uw volgende aanvraag. +has_unconfirmed_mail = Beste %s, u heeft een onbevestigde e-mailadres (%s). Als u nog geen bevestiging per e-mail heeft ontvangen, of u een nieuwe aanvraag wilt doen, klik dan op de onderstaande knop. +resend_mail = Klik hier om uw activatie mail nog een keer te verzenden +send_reset_mail = Klik hier om uw wachtwoord reset mail (nogmaals) te versturen +reset_password = Reset uw wachtwoord +invalid_code = Sorry, uw bevestigingscode is verlopen of niet meer geldig. +reset_password_helper = Klik hier om uw wachtwoord opnieuw in te stellen. +password_too_short = De lengte van uw wachtwoord moet minimaal zes karakters zijn. +email_not_associate = Dit e-mailadres is niet gekoppeld aan een account. + +[form] +UserName = Gebruikersnaam +RepoName = Repositorie naam +Email = e-mailadres +Password = Wachtwoord +Retype = Verifieer wachtwoord +SSHTitle = SSH sleutel naam +HttpsUrl = HTTPS URL +PayloadUrl = Payload URL +TeamName = Team naam +AuthName = Autorisatienaam +require_error = kan niet leeg zijn. +alpha_dash_error = moet een valide alfanumeriek of dash(-_) karakter zijn. +alpha_dash_dot_error = moet een valide alfanumeriek, dash(-_) of (.) punt karakter zijn. +min_size_error = moet minimaal %s karakters bevatten. +max_size_error = mag maximaal %s karakters bevatten. +email_error = is niet een valide e-mail adres. +url_error = is niet een valide URL. +unknown_error = Onbekende fout: +captcha_incorrect = Captcha komt niet overeen. +password_not_match = Wachtwoord en verificatie wachtwoord komen niet overeen. +username_been_taken = Gebruikersnaam is al in gebruik. +repo_name_been_taken = Repositorie naam is al in gebruik. +org_name_been_taken = Organisatie naam is al in gebruik. +team_name_been_taken = Team naam is al in gebruik. +email_been_used = e-mailadres is al in gebruik. +ssh_key_been_used = Openbare sleutel naam is al in gebruik. +illegal_username = Gebruikersnaam bevat illegale karakters. +illegal_repo_name = Repositorie naam bevat illegale karakters. +illegal_org_name = Organisatie naam bevat illegale karakters. +illegal_team_name = Team naam bevat illegale karakters. +username_password_incorrect = Gebruikersnaam of wachtwoord is niet correct. +enterred_invalid_repo_name = U heeft een onjuiste repositorie naam ingevoerd. +enterred_invalid_owner_name = U heeft een onjuiste eigenaar ingevoerd. +enterred_invalid_password = U heeft een onjuiste wachtwoord ingevoerd. +user_not_exist = Gegeven gebruiker bestaat niet. +last_org_owner = De gebruiker die u probeert te verwijderen is het enige lid (eigenaar) van dit team. U moet eerst nieuwe lid (eigenaar) aanstellen. +invalid_ssh_key = Sorry, we zijn niet in staat om uw SSH-sleutel te verifiëren: %s +auth_failed = Verificatie mislukt: %v +still_own_repo = Uw account heeft nog een eigendom op een repositorie. U moet deze eerst verwijderen of overdragen. +org_still_own_repo = De organisatie heeft nog eigendomen op repositories. U moet deze eerst verwijderen of overdragen. +still_own_user = Deze authenticatie methode wordt nog gebruikt door sommige gebruikers. U moet hen eerst verplaatsen of verwijderen. +AdminEmail = E-mail beheerder + +[settings] +profile = Profiel +password = Wachtwoord +ssh_keys = SSH-sleutels +social = Sociale netwerk-accounts +orgs = Organisaties +delete = Verwijder account +public_profile = Openbaar profiel +profile_desc = Uw e-mailadres is openbaar zichtbaar en zal gebruikt worden gebruikt voor alle account gerlateerde berichtgevingen en web bewerking gemaakt via de website. +full_name = Volledige naam +website = Website +location = Locatie +update_profile = Profile bijwerken +update_profile_success = Uw profiel is succesvol bijgewerkt. +change_password = Verander wachtwoord +old_password = Huidige wachtwoord +new_password = Nieuw wachtwoord +password_incorrect = Huidig wachtwoord is niet correct. +change_password_success = Wachtwoord is succesvol gewijzigd. U kunt nu met uw nieuwe wachtwoord inloggen. +manage_ssh_keys = Beheer SSH sleutels +add_key = Sleutel toevoegen +ssh_desc = Dit is een lijst van alle SSH sleutels die gekoppeld zijn aan uw account. Verwijder alle sleutels die u niet herkent. +ssh_helper = Hulp nodig? Bekijk onze help pagina's over SSH sleutels genereeren of over meest voorkomende SSH problemen. +add_new_key = SSH sleutel toevoegen +key_name = Sleutel naam +key_content = Inhoud +add_key_success = Nieuwe SSH sleutel is toegevoegd! +delete_key = Verwijder +add_on = Toegevoegd op +last_used = Laatst gebruikt op +no_activity = Geen recente activiteiten +manage_social = Beheer gekoppelde sociale accounts +social_desc = Dit is een lijst van de bijbehorende sociale accounts koppelingen, Verwijder eventueel koppelingen die u niet herkent. +unbind = Loskoppelen +unbind_success = Sociaal account is ontkoppeld. +delete_account = Verwijder uw account +delete_prompt = Deze handeling zal uw account definitief verwijderen, u kunt dit NIET terug draaien! +confirm_delete_account = Bevestig verwijdering +uid = uid +change_username = Username veranderd +change_username_desc = Gebruikersnaam is gewijzigd. Wilt u doorgaan? Dit zal gevolgen hebben voor alle koppelingen die betrekking hebben op uw account. +continue = Doorgaan +cancel = Annuleren +delete_account_title = Account verwijderen +delete_account_desc = Dit account zal permanent worden verwijderd. Wilt u doorgaan? + +[repo] +owner = Eigenaar +repo_name = Repositorie naam +repo_name_helper = Een goede repositorie naam is kort, memorabel en uniek. +visibility = Zichtbaarheid +visiblity_helper = Deze repositorie is prive +repo_desc = Omschrijving +repo_lang = Taal +repo_lang_helper = Selecteer een .gitignore bestand +license = Licentie +license_helper = Selecteer een licentie bestand +init_readme = Initialiseer deze repositorie met een README.md +create_repo = Nieuwe Repositorie +default_branch = Standaard branch +mirror_interval = Mirror interval(uur) +goget_meta = Go-Get Meta +goget_meta_helper = Deze repositorie is nu beschikbaar voor Go-Get +need_auth = Autorisatie vereist +migrate_type = Migratie type +migrate_type_helper = Deze repositorie zal een mirror worden +migrate_repo = Migreer repositorie +clone_helper = Hulp nodig bij het klonen? Kijk dan hier voor hulp! +unwatch = Negeren +watch = Volgen +unstar = Ontster +star = Ster +fork = Fork +settings = Instellingen +settings.options = Opties +settings.collaboration = Samenwerking +settings.hooks = Webhooks +settings.deploy_keys = Installeer sleutels +settings.basic_settings = Basis instellingen +settings.danger_zone = Gevaren zone +settings.site = Officiële site +settings.update_settings = Instellingen bewerken +settings.transfer = Eigendom overdragen +settings.transfer_desc = Draag deze repo over aan een andere gebruiker of een organisatie waar u beheerders rechten heeft. +settings.delete = Verwijder deze repositorie +settings.delete_desc = Als u eenmaal een repositorie verwijderd is er geen weg terug. Gelieve zeker te zijn van uw acties. +settings.update_settings_success = Repositorie instellingen zijn succesvol bijgewerkt. +settings.transfer_owner = Nieuwe eigenaar +settings.make_transfer = Maak overdracht +settings.confirm_delete = Bevestig verwijdering +settings.add_collaborator = Nieuwe medewerker toevoegen +settings.add_collaborator_success = medewerker is toegevoegd. +settings.remove_collaborator_success = medewerker is verwijderd. +settings.add_webhook = Webhook toevoegen +settings.hooks_desc = Webhooks maken het mogelijk om ​​externe diensten te waaarschuwen wanneer zich bepaalde gebeurtenissen voordoen op Gogs . Wanneer de opgegeven gebeurtenissen gebeuren , zullen we een POST-aanvraag aan alle URL's die u verstrekt sturen . Lees meer in onze Webhooks gids . +settings.remove_hook_success = Webhook is verwijderd. +settings.add_webhook_desc = We sturen een POST verzoek aan de onderstaande URL met de details van het geplaatste evenementen. U kunt ook aangeven welke data u wilt ontvangen (JSON, x-www-form-urlencoded, etc). U kunt meer informatie vinden in onze webhooks gids. +settings.payload_url = Payload URL +settings.content_type = Content type +settings.secret = Geheim +settings.event_desc = Bij welke gebeurtenissen wilt u dat deze webhook getriggerd wordt? +settings.event_push_only = Alleen bij de push event. +settings.active = Actief +settings.active_helper = We zullen details van de gebeurtenissen af leveren wanneer deze webhook wordt geactiveerd. +settings.add_hook_success = Nieuwe webhook toegevoegd. +settings.update_webhook = Bewerk webhook +settings.update_hook_success = Webhook is bijgewerkt. +settings.delete_webhook = Webhook verwijderen +settings.recent_deliveries = Recente bezorgingen +copy_link = Kopieer +click_to_copy = Kopieer link naar plakbord +copied = Gekopieerd +no_desc = Geen omschrijving +quick_guide = Snelstart gids +clone_this_repo = Kloon deze repositorie +create_new_repo_command = Maak een nieuwe repositorie aan vanaf de console +push_exist_repo = Push een bestaande repositorie vanaf de console +branch = Aftakking +tree = Boom +branch_and_tags = Aftakkingen & labels +branches = Aftakkingen +tags = Labels +issues = Issues +commits = Commits +releases = Publicaties +commits.commits = Commits +commits.search = Zoeken +commits.find = zoek +commits.author = Auteur +commits.message = Bericht +commits.date = Datum +commits.older = Ouder +commits.newer = Nieuwer +settings.change_reponame = Repositorienaam aangepast +settings.change_reponame_desc = De repositorienaam is veranderd. Wilt u doorgaan? Dit zal gevolgen hebben voor alle koppelingen die betrekking hebben op deze repositorie. +settings.new_owner_has_same_repo = De nieuwe eigenaar heeft al een repositorie met deze naam +settings.transfer_notices =

- U kan uw toegang verliezen als de nieuwe eigenaar een individuele gebruiker is

- . . U zal uw toegang behouden als de nieuwe eigenaar een organisatie is en u één van de eigenaren bent

+settings.transfer_succeed = Eigendom repositorie succesvol overgedragen +settings.hook_type = Type hook +settings.add_slack_hook_desc = Voeg een Slack integratie toe aan uw repositorie. +settings.slack_token = Slack token +settings.slack_domain = Slack domein +settings.slack_channel = Slack kanaal + +[org] +org_name_holder = Organisatienaam +org_name_helper = Een goede organisatienaam is kort en memorabel. +org_email_helper = Alle notificaties en bevestigingen worden op het e-mailadres van de organisatie ontvangen. +create_org = Nieuwe organisatie aanmaken +repo_updated = Geupdate +people = Mensen +invite_someone = Iemand uitnodigen +teams = Teams +lower_members = leden +lower_repositories = repositories +create_new_team = Nieuw team aanmaken +org_desc = Omschrijving +team_name = Teamnaam +team_desc = Omschrijving +team_name_helper = U gebruikt deze naam om dit team te vermelden in conversaties. +team_desc_helper = Waar gaat dit team doen? +team_permission_desc = Welke privileges zou dit team moeten hebben? +settings = Instellingen +settings.options = Opties +settings.full_name = Volledige naam +settings.website = Website +settings.location = Locatie +settings.update_settings = Instellingen bijwerken +settings.update_setting_success = Organisatie instellingen zijn succesvol bijgewerkt. +settings.delete = Verwijder organisatie +settings.delete_account = Verwijder deze organisatie +settings.delete_prompt = Deze actie zal de origanisatie permanent verwijderen. U kunt dit NIET terug draaien! +settings.confirm_delete_account = Bevestig verwijdering +members.public = Openbaar +members.public_helper = maak prive +members.private = Prive +members.private_helper = maak openbaar +members.owner = Eigenaar +members.member = Lid +members.conceal = Verbergen +members.remove = Verwijderen +members.leave = Verlaat +members.invite_desc = Begin met het typen van een gebruikersnaam om een nieuw lid aan %s uit te nodigen: +members.invite_now = Nu uitnodigen +teams.join = Lid worden +teams.leave = Vertlaat +teams.read_access = Leestoegang +teams.read_access_helper = Dit team is in staat om zijn repositories te bekijken en te klonen. +teams.write_access = Schrijf toegang +teams.write_access_helper = Dit team is in staat om zijn repositories te bekijken en push aanvragen te verwerken. +teams.admin_access = Beheerder toegang +teams.admin_access_helper = Dit team is in staat om push & pull aanvragen te verwerken en om nieuwe medewerkers toe te voegen. +teams.no_desc = Dit team heeft geen omschrijving +teams.settings = Instellingen +teams.owners_permission_desc = Eigenaren hebben volledige toegang tot alle repositories en hebben beheerder rechten over de organisatie. +teams.members = Team leden +teams.update_settings = Instellingen bijwerken +teams.delete_team = Verwijder deze team +teams.add_team_member = Nieuwe team lid aanmaken +teams.delete_team_success = Gekozen team is succesvol verwijderd. +teams.read_permission_desc = Dit team heeft Lees rechten : leden kunnen repositories lezen en klonen. +teams.write_permission_desc = Dit team heeft Schrijf rechten : leden kunnen repositories lezen en push aanvragen verwerken. +teams.admin_permission_desc = Dit team heeft Beheerders rechten : leden kunnen repositories lezen en push aanvragen verwerken en medewerkers toevoegen. +teams.repositories = Teamrepositories +teams.add_team_repository = Nieuwe teamrepositorie aanmaken +teams.remove_repo = Verwijder +settings.change_orgname = Organisatie naam veranderd +settings.change_orgname_desc = De naam van de organisatie is veranderd, wilt u doorgaan? Dit zal gevolgen hebben voor alle koppelingen die betrekking hebben op deze organisatie. +settings.delete_org_title = Verwijderen organsiatie +settings.delete_org_desc = Deze organisatie zal permanent worden verwijderd, wilt u doorgaan? +settings.hooks_desc = Een webhook toevoegen die door alle repositories in deze organisatie getriggerd kan worden. +teams.delete_team_title = Team verwijderen +teams.delete_team_desc = Dit team zal worden verwijderd. De leden van dit team zullen toegang tot alle repositories van het team verliezen. Wilt u doorgaan? + +[admin] +dashboard = Dashboard +users = Gebruikers +organizations = Orgranisaties +repositories = Repositories +authentication = Autenticaties +config = Configuratie +monitor = Bijhouden +prev = Vorige +next = Volgende +dashboard.statistic = Statistieken +dashboard.operations = Bewerkingen +dashboard.system_status = Status Systeemmonitor +dashboard.statistic_info = Gogs database heeft %d gebruikers, %d organisaties, %d openbare sleutels, %d repositories, %d volgers, %d sterren, %d acties, %d participanten, %d issues, %d reacties, %d sociale accounten, %d volgers, %d mirrors, %d publicaties, %d login bronnen, %d webhooks, %d mijlpalen, %d labels, %d hook taken, %d teams, %d bijgewerkte taken, %d bijlagen. +dashboard.operation_name = Bewerking naam +dashboard.operation_switch = Omschakelen +dashboard.operation_run = Uitvoeren +dashboard.clean_unbind_oauth = Clean unbound OAuths +dashboard.delete_inactivate_accounts = Verwijder alle inactieve accounts +dashboard.server_uptime = Uptime server +dashboard.current_goroutine = Huidige Goroutines +dashboard.current_memory_usage = Huidige geheugen gebruik +dashboard.total_memory_allocated = Totaal toegewezen geheugen +dashboard.memory_obtained = Geheugen gebruikt +dashboard.pointer_lookup_times = Pointer Lookup Times +dashboard.memory_allocate_times = Memory Allocate Times +dashboard.memory_free_times = Memory Free Times +dashboard.current_heap_usage = Current Heap Usage +dashboard.heap_memory_obtained = Heap Memory Obtained +dashboard.heap_memory_idle = Heap Memory Idle +dashboard.heap_memory_in_use = Heap Memory In Use +dashboard.heap_memory_released = Heap Memory Released +dashboard.heap_objects = Heap Objects +dashboard.bootstrap_stack_usage = Bootstrap Stack Usage +dashboard.stack_memory_obtained = Stack Memory Obtained +dashboard.mspan_structures_usage = MSpan Structures Usage +dashboard.mspan_structures_obtained = MSpan Structures Obtained +dashboard.mcache_structures_usage = MCache Structures Usage +dashboard.mcache_structures_obtained = MCache Structures Obtained +dashboard.profiling_bucket_hash_table_obtained = Profiling Bucket Hash Table Obtained +dashboard.gc_metadata_obtained = GC Metadada Obtained +dashboard.other_system_allocation_obtained = Other System Allocation Obtained +dashboard.next_gc_recycle = Volgende GC recycle +dashboard.last_gc_time = Sinds vorige GC verwerkingstijd +dashboard.total_gc_time = Totaal GC verwerkingstijd +dashboard.total_gc_pause = Totaal GC verwerkingstijd +dashboard.last_gc_pause = Laatste GC verwerkingstijd +dashboard.gc_times = GC verwerkingen +users.user_manage_panel = Gebruikers beheren +users.new_account = Nieuw account aanmaken +users.name = Naam +users.activated = Geactiveerd +users.admin = Admin +users.repos = Repos +users.created = Aangemaakt +users.edit = Bewerken +users.auth_source = Autorisatiebron +users.local = Lokaal +users.auth_login_name = Autorisatie inlognaam +users.update_profile_success = Profiel is succesvol bijgewerkt. +users.edit_account = Bewerk account +users.is_activated = Dit account is geactiveerd +users.is_admin = Dit account heeft beheerdersrechten +users.update_profile = Account profiel bijwerken +users.delete_account = Dit account verwijderen +users.still_own_repo = Dit account is nog steeds eigendom van een repositorie. U moet deze repositorie eerst verwijderen of overdragen. +orgs.org_manage_panel = Organisaties beheren +orgs.name = Naam +orgs.teams = Teams +orgs.members = Leden +repos.repo_manage_panel = Repositoriebeheerpaneel +repos.owner = Eigenaar +repos.name = Naam +repos.private = Prive +repos.watches = Volgers +repos.stars = Sterren +repos.issues = Issues +auths.auth_manage_panel = Autorisatiebeheerpaneel +auths.new = Nieuwe autorisatiebron +auths.name = Naam +auths.type = Type +auths.enabled = Ingeschakeld +auths.updated = Bijgewerkt +auths.auth_type = Autorisatietype +auths.auth_name = Autorisatienaam +auths.domain = Domein +auths.host = Host +auths.port = Poort +auths.base_dn = Base DN +auths.attributes = Zoek attributen +auths.filter = Zoek filter +auths.ms_ad_sa = Ms Ad SA +auths.smtp_auth = SMTP authenticatietype +auths.smtphost = SMTP host +auths.smtpport = SMTP poort +auths.enable_tls = Activeer TLS-encryptie +auths.enable_auto_register = Activeer automatische registratie +auths.tips = Tips +auths.edit = Bewerk autorisatie-instellingen +auths.activated = Deze autorisatiemethode is geactiveerd +auths.update_success = Autorisatie-instellingen zijn succesvol bijgewerkt. +auths.update = Update autorisatie-instellingen +auths.delete = Verwijder deze autorisatie +config.server_config = Serverconfiguratie +config.app_name = Applicatienaam +config.app_ver = Applicatieversie +config.app_url = Applicatie-URL +config.domain = Domein +config.offline_mode = Offline-modus +config.disable_router_log = Router-log uitschakelen +config.run_user = Uitvoerende gebruiker +config.run_mode = Uitvoer modus +config.repo_root_path = Repositorie basis pad +config.static_file_root_path = Statische bestanden basis pad +config.log_file_root_path = Log bestand basis pad +config.script_type = Script type +config.reverse_auth_user = Reverse Authentication User +config.db_config = Databaseconfiguratie +config.db_type = Type +config.db_host = Host +config.db_name = Naam +config.db_user = Gebruiker +config.db_ssl_mode = SSL modus +config.db_ssl_mode_helper = (alleen voor "postgres") +config.db_path = Path +config.db_path_helper = (alleen voor "sqlite3") +config.service_config = Serviceconfiguratie +config.register_email_confirm = Register Email Confirmation +config.disable_register = Registratie uitgeschakeld +config.require_sign_in_view = Inloggen vereist om te kunnen inzien +config.mail_notify = E-mailnotificaties +config.enable_cache_avatar = Avatar Cache inschakelen +config.active_code_lives = Active Code Lives +config.reset_password_code_lives = Reset Password Code Lives +config.webhook_config = Webhook configuratie +config.task_interval = Taakinterval +config.deliver_timeout = Bezorging verlooptijd +config.mailer_config = Mailerconfiguatie +config.mailer_enabled = Ingeschakeld +config.mailer_name = Naam +config.mailer_host = Host +config.mailer_user = Gebruiker +config.oauth_config = OAuth-configuratie +config.oauth_enabled = Ingeschakeld +config.cache_config = Cache-configuratie +config.cache_adapter = Cache-adapter +config.cache_interval = Cache-interval +config.cache_conn = Cache-connectie +config.session_config = Sessieconfiguratie +config.session_provider = Sessieprovider +config.provider_config = Provider config +config.cookie_name = Cookie naam +config.enable_set_cookie = Set Cookie inschakelen +config.gc_interval_time = GC interval time +config.session_life_time = Sessie duur +config.https_only = Alleen HTTPS +config.cookie_life_time = Cookie duur leeftijd +config.session_hash_function = Sessie ID Hash functie +config.session_hash_key = Sessie ID Hash sleutel +config.picture_config = Foto configuratie +config.picture_service = Foto service +config.disable_gravatar = Gravatar uitschakelen +config.log_config = Logconfiguratie +config.log_mode = Log-modus +monitor.cron = Cron-taken +monitor.name = Naam +monitor.schedule = Planning +monitor.next = Volgende +monitor.previous = Vorige +monitor.execute_times = Aantal keren uitgevoerd +monitor.process = Draaiende processen +monitor.desc = Omschrijving +monitor.start = Starttijd +monitor.execute_time = Uitvoertijd +auths.delete_auth_title = Verwijderings-autorisatie +auths.delete_auth_desc = Deze autorisatiemethode wordt verwijderd. Weet u zeker dat u wilt doorgaan? + +[action] +create_repo = repositorie aangemaakt in %s +commit_repo = push update naar %s in %s%s#%s +comment_issue = reactie op issue %s#%s +transfer_repo = repositorie verplaatst naar %s naar %s + +[tool] +ago = geleden +from_now = vanaf nu +now = nu +1s = 1 seconde %s +1m = 1 minuut %s +1h = 1 uur %s +1d = 1 dag %s +1w = 1 week %s +1mon = 1 maand %s +1y = 1 jaar %s +seconds = %d seconden %s +minutes = %d minuten %s +hours = %d uur %s +days = %d dagen %s +weeks = %d weken %s +months = %d maanden %s +years = %d jaren %s +raw_seconds = seconden +raw_minutes = minuten + +[install] +install = Installatie +title = Installatiestappen voor de eerste keer opstarten +requite_db_desc = Om Gogs te gebruiken is MySQL, PostgreSQL of SQLite3 vereist (SQLite3 is beschikbaar in de officiële versie). +db_type = Database-type +host = Host +user = Gebruikersnaam +password = Wachtwoord +db_name = Database naam +db_helper = Gebruik InnoDB engine met utf8_general_ci karakterset voor MySQL. +ssl_mode = SSL-modus +path = Pad +sqlite_helper = Het pad naar de SQLite3 database. +general_title = Algemene instellingen van Gogs +repo_path = Repositories basis directorie +repo_path_helper = Alle remote Git repositories worden in deze directorie opgeslagen +run_user = Uitvoerende gebruikersnaam +run_user_helper = Deze gebruiker moet toegang hebben tot de git repositorie directorie en moet Gogs kunnen starten +domain = Domein +domain_helper = Dit heeft invloed op de SSH kloon URLs +app_url = Applicatie URL +app_url_helper = Dit heeft invloed op de HTTP/HTTPS kloon urls en de urls die in de email worden gebruikt +email_title = Email service instellingen (Optioneel) +smtp_host = SMTP host +mailer_user = Afzender e-mail / gebruikersnaam +mailer_password = Wachtwoord +notify_title = Notificatie-instelligen (optioneel) +register_confirm = Activeer registratie emails +mail_notify = Activeer e-mailnotificaties +admin_title = Instellingen beheerdersaccount +admin_name = Gebruikersnaam +admin_password = Wachtwoord +confirm_password = Verifieer wachtwoord +admin_email = E-mailadres +install_gogs = Installeer Gogs +test_git_failed = Git test niet gelukt: 'git' commando %v +sqlite3_not_available = SQLite3 wordt niet ondersteund in uw versie. Gelieve de officiële versie downloaden vanaf http://gogs.io/docs/installation/install_from_binary.html, niet de gobuild versie downloaden. +invalid_db_setting = Uw database instellingen zijn niet correct: %v +invalid_repo_path = Repositorie basis pad is niet correct: %v +run_user_not_match = De uitvoerende gebruiker is niet de huidig gebruiker: %s -> %s +save_config_failed = Kan de configuratie niet opslaan: %v +invalid_admin_setting = Uw admin-instellingen zijn niet geldig: %v +install_success = Welkom! Wij zijn veheugd dat u voor Gogs heeft gekozen, veel plezier en tot ziens + +[explore] +repos = Repositories + +[user] +change_avatar = Verander uw avatar op Gravatar.com +join_on = Aangemeld op +repositories = repositories +activity = Openbare activiteit +followers = Volgers +starred = Sterren +following = Volgt diff --git a/conf/locale/locale_zh-CN.ini b/conf/locale/locale_zh-CN.ini index 360bf4bcc6..0c17f2d7f9 100644 --- a/conf/locale/locale_zh-CN.ini +++ b/conf/locale/locale_zh-CN.ini @@ -159,6 +159,7 @@ user_not_exist = 被操作的用户不存在! last_org_owner = 被移除用户为最后一位管理员。请添加一位新的管理员再进行移除成员操作! invalid_ssh_key = 很抱歉,我们无法验证您输入的 SSH 密钥:%s +unable_verify_ssh_key = Gogs 无法验证您输入的 SSH 密钥,但我们假设那是有效的密钥,请您自行确保其有效性! auth_failed = 授权验证失败:%v still_own_repo = 您的帐户仍然是某些仓库的拥有者,您必须先转移或删除它们才能执行删除帐户操作! @@ -273,6 +274,9 @@ tags = 标签列表 issues = 工单管理 commits = 提交历史 releases = 版本发布 +file_raw = 原始文件 +file_history = 文件历史 +file_view_raw = 查看原始文件 commits.commits = 次代码提交 commits.search = 搜索提交历史 @@ -287,6 +291,7 @@ settings = 仓库设置 settings.options = 基本设置 settings.collaboration = 管理协作者 settings.hooks = 管理 Web 钩子 +settings.githooks = 管理 Git 钩子 settings.deploy_keys = 管理部署密钥 settings.basic_settings = 基本设置 settings.danger_zone = 危险操作区 @@ -308,10 +313,16 @@ settings.confirm_delete = 确认删除仓库 settings.add_collaborator = 增加新的协作者 settings.add_collaborator_success = 成功添加新的协作者! settings.remove_collaborator_success = 被操作的协作者已经被收回权限! +settings.user_is_org_member = 被操作的用户是组织成员,因此无法添加为协作者! settings.add_webhook = 添加 Web 钩子 settings.hooks_desc = Web 钩子允许您设定在 Gogs 上发生指定事件时对指定 URL 发送 POST 通知。查看 Webhooks 文档 获取更多信息。 settings.remove_hook_success = Web 钩子删除成功! settings.add_webhook_desc = 我们会通过 POST 请求将订阅事件信息发送至向指定 URL 地址。您可以设置不同的数据接收方式(JSON 或 x-www-form-urlencoded)。 请查阅 Webhooks 文档 获取更多信息。 +settings.githooks_desc = Git 钩子是由 Git 本身提供的功能,以下为 Gogs 所支持的钩子列表。 +settings.githook_edit_desc = 如果钩子未启动,则会显示样例文件中的内容。如果想要删除某个钩子,则提交空白文本即可。 +settings.githook_name = 钩子名称 +settings.githook_content = 钩子文本 +settings.update_githook = 更新钩子设置 settings.payload_url = 推送地址 settings.content_type = 数据格式 settings.secret = 密钥文本 @@ -330,6 +341,15 @@ 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 = 共有 %d 个文件被更改,包括 %d 次插入%d 次删除 +diff.bin = 二进制 +diff.view_file = 查看文件 + [org] org_name_holder = 组织名称 org_name_helper = 伟大的组织都有一个简短而寓意深刻的名字。 @@ -402,6 +422,7 @@ teams.admin_permission_desc = 该团队拥有一定的 管理 teams.repositories = 团队仓库 teams.add_team_repository = 添加团队仓库 teams.remove_repo = 移除仓库 +teams.add_nonexistent_repo = 您尝试添加到团队的仓库不存在,请先创建仓库! [admin] dashboard = 控制面板 @@ -410,6 +431,7 @@ organizations = 组织管理 repositories = 仓库管理 authentication = 授权认证管理 config = 应用配置管理 +notices = 系统提示管理 monitor = 应用监控面板 prev = 上一页 next = 下一页 @@ -587,12 +609,21 @@ monitor.desc = 进程描述 monitor.start = 开始时间 monitor.execute_time = 已执行时间 +notices.system_notice_list = 系统提示管理 +notices.type = 提示类型 +notices.type_1 = 仓库 +notices.desc = 描述 +notices.op = 操作 +notices.delete_success = 系统提示删除成功! + [action] create_repo = 创建了仓库 %s commit_repo = 推送了 %s 分支的代码到 %s create_issue = 创建了工单 %s#%s comment_issue = 评论了工单 %s#%s transfer_repo = 将仓库 %s 转移至 %s +push_tag = 推送了标签 %s%s +compare_2_commits = 查看 2 次提交的内容对比 [tool] ago = 之前 diff --git a/conf/locale/locale_zh-HK.ini b/conf/locale/locale_zh-HK.ini new file mode 100644 index 0000000000..fca13aa750 --- /dev/null +++ b/conf/locale/locale_zh-HK.ini @@ -0,0 +1,642 @@ +app_desc = 基於 Go 語言的自助 Git 服務 + +home = 首頁 +dashboard = 控制面版 +explore = 探索 +help = 幫助 +sign_in = 登錄 +social_sign_in = 社交帳號登錄:第 2 步 關聯帳號 +sign_out = 退出 +sign_up = 註冊 +register = 註冊 +website = 官方網站 +version = 當前版本 +page = 頁面 +template = 模版 +language = 語言選項 + +username = 用戶名 +email = 郵箱 +password = 密碼 +re_type = 確認密碼 +captcha = 驗證碼 + +repository = 倉庫 +organization = 組織 +mirror = 鏡像 +new_repo = 創建新的倉庫 +new_migrate = 遷移外部倉庫 +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,但是 SQLite3 一般只有官方二進制發行版才支持。 +db_type = 數據庫類型 +host = 數據庫主機 +user = 數據庫用戶 +password = 數據庫用戶密碼 +db_name = 數據庫名稱 +db_helper = 如果您使用 MySQL,請使用 INNODB 引擎以及 utf8_general_ci 字符集。 +ssl_mode = SSL 模式 +path = 數據庫文件路徑 +sqlite_helper = SQLite3 數據庫的文件路徑。 +general_title = 應用基本設置 +repo_path = 倉庫根目錄 +repo_path_helper = 所有 Git 遠程倉庫都將被存放於該目錄。 +run_user = 執行系統用戶 +run_user_helper = 該用戶必須具有對倉庫根目錄和執行 Gogs 的操作權限。 +domain = 域名 +domain_helper = 該設置影響 SSH 克隆地址。 +app_url = 應用 URL +app_url_helper = 該設置影響 HTTP/HTTPS 克隆地址和一些郵箱中的鏈接。 +email_title = 郵件服務設置(可選) +smtp_host = SMTP 主機 +mailer_user = 發送郵箱 +mailer_password = 發送郵箱密碼 +notify_title = 通知提醒設置(可選) +register_confirm = 啟用註冊郵箱確認 +mail_notify = 啟用郵件通知提醒 +admin_title = 管理員帳號設置 +admin_name = 管理員用戶名 +admin_password = 管理員密碼 +confirm_password = 確認密碼 +admin_email = 管理員郵箱 +install_gogs = 立即安裝 +test_git_failed = 無法識別 'git' 命令:%v +sqlite3_not_available = 您所使用的發行版本不支持 SQLite3,請從 http://gogs.io/docs/installation/install_from_binary.html 下載官方二進制發行版本,而不是 gobuild 版本。 +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,祝您使用愉快,代碼從此無 BUG! + +[home] +uname_holder = 用戶名或郵箱 +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 = 一封新的確認郵件已經被發送至 %s,請檢查您的收件箱並在 %d 小時內完成確認註冊操作。 +sign_in_email = 登錄到您的郵箱 +active_your_account = 激活您的帳戶 +resent_limit_prompt = 對不起,您請求發送激活郵件過於頻繁,請等待 3 分鐘後再試! +has_unconfirmed_mail = %s 您好,系統檢測到您有一封發送至 %s 但未被確認的郵件。如果您未收到激活郵件,或需要重新發送,請單擊下方的按鈕。 +resend_mail = 單擊此處重新發送確認郵件 +email_not_associate = 您輸入的郵箱地址未被關聯到任何帳號! +send_reset_mail = 單擊此處(重新)發送您的密碼重置郵件 +reset_password = 重置密碼 +invalid_code = 對不起,您的確認代碼已過期或已失效。 +reset_password_helper = 單擊此處重置密碼 +password_too_short = 密碼長度不能少於 6 位! + +[form] +UserName = 用戶名 +RepoName = 倉庫名稱 +Email = 郵箱地址 +Password = 密碼 +Retype = 確認密碼 +SSHTitle = SSH 密鑰名稱 +HttpsUrl = HTTPS URL 地址 +PayloadUrl = 推送地址 +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 = 驗證碼未匹配。 +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 = SSH 密鑰已經被使用。 +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 +auth_failed = 授權驗證失敗:%v + +still_own_repo = 您的帳戶仍然是某些倉庫的擁有者,您必須先轉移或刪除它們才能執行刪除帳戶操作! +org_still_own_repo = 該組織仍然是某些倉庫的擁有者,您必須先轉移或刪除它們才能執行刪除組織操作! + +still_own_user = 該授權認證依舊被部分用戶使用,請先刪除該部分用戶後再試! + +[user] +change_avatar = 到 gravatar.com 上修改您的頭像 +join_on = 加入於 +repositories = 倉庫列表 +activity = 公開活動 +followers = 關註者 +starred = 已點讚 +following = 關註中 + +[settings] +profile = 個人信息 +password = 修改密碼 +ssh_keys = 管理 SSH 密鑰 +social = 社交帳號綁定 +orgs = 管理組織 +delete = 刪除帳戶 +uid = 用戶 ID + +public_profile = 公開信息 +profile_desc = 您的郵箱地址將會被公開,並被用於接收帳戶的所有提醒和通知。 +full_name = 自定義名稱 +website = 個人網站 +location = 所在地區 +update_profile = 更新信息 +update_profile_success = 您的個人信息更新成功! +change_username = 用戶名將被修改 +change_username_desc = 用戶名被修改,您確定要繼續操作嗎?這將會影響到所有與您帳戶有關的鏈接。 +continue = 繼續操作 +cancel = 取消操作 + +change_password = 修改密碼 +old_password = 當前密碼 +new_password = 新的密碼 +password_incorrect = 當前密碼不正確! +change_password_success = 密碼修改成功!您現在可以使用新的密碼登錄。 + +manage_ssh_keys = 管理 SSH 密鑰 +add_key = 增加密鑰 +ssh_desc = 以下是與您帳戶所關聯的 SSH 密鑰,如果您發現有陌生的密鑰,請立即刪除它! +ssh_helper = 需要幫助? 請查看有關 如何生成 SSH 密鑰常見 SSH 問題 尋找答案。 +add_new_key = 增加 SSH 密鑰 +key_name = 密鑰名稱 +key_content = 密鑰內容 +add_key_success = 新的 SSH 密鑰添加成功! +delete_key = 刪除 +add_on = 增加於 +last_used = 上次使用在 +no_activity = 沒有最近活動 + +manage_social = 管理關聯社交帳戶 +social_desc = 以下是與您帳戶所關聯的社交帳號,如果您發現有陌生的關聯,請立即解除綁定! +unbind = 解除綁定 +unbind_success = 社交帳號解除綁定成功! + +delete_account = 刪除當前帳戶 +delete_prompt = 刪除操作會永久清除您的帳戶信息,並且 不可恢復! +confirm_delete_account = 確認刪除帳戶 +delete_account_title = 帳戶刪除操作 +delete_account_desc = 該帳戶將被永久性刪除,您確定要繼續操作嗎? + +[repo] +owner = 擁有者 +repo_name = 倉庫名稱 +repo_name_helper = 偉大的倉庫名稱一般都較短、令人深刻並且 獨一無二 的。 +visibility = 可見度 +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 = 本倉庫將可以通過 Go Get 獲取 + +need_auth = 需要授權驗證 +migrate_type = 遷移類型 +migrate_type_helper = 本倉庫將是 鏡像 +migrate_repo = 遷移倉庫 + +copy_link = 復製鏈接 +click_to_copy = 復製到剪切簿 +copied = 復製成功 +clone_helper = 不知道如何操作?訪問 此處 查看幫助! +unwatch = 取消關註 +watch = 關註 +unstar = 取消點讚 +star = 點讚 +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 = 版本發佈 + +commits.commits = 次代碼提交 +commits.search = 搜索提交歷史 +commits.find = 查找 +commits.author = 作者 +commits.message = 備註 +commits.date = 提交日期 +commits.older = 更舊的提交 +commits.newer = 更新的提交 + +settings = 倉庫設置 +settings.options = 基本設置 +settings.collaboration = 管理協作者 +settings.hooks = 管理 Web 鉤子 +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 =

- 如果您轉移給個人用戶,您將對倉庫失去所有權限。

- 如果您轉移給您作為擁有者的組織,則可繼續保持操作權限。

+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.add_webhook = 添加 Web 鉤子 +settings.hooks_desc = Web 鉤子允許您設定在 Gogs 上發生指定事件時對指定 URL 發送 POST 通知。查看 Webhooks 文檔 獲取更多信息。 +settings.remove_hook_success = Web 鉤子刪除成功! +settings.add_webhook_desc = 我們會通過 POST 請求將訂閱事件信息發送至向指定 URL 地址。您可以設置不同的數據接收方式(JSON 或 x-www-form-urlencoded)。 請查閱 Webhooks 文檔 獲取更多信息。 +settings.githooks_desc = Git 鉤子是由 Git 本身提供的功能,以下為 Gogs 所支持的鉤子列表。 +settings.githook_edit_desc = 如果鉤子未啟動,則會顯示樣例文件中的內容。如果想要刪除某個鉤子,則提交空白文本即可。 +settings.githook_name = 鉤子名稱 +settings.githook_content = 鉤子文本 +settings.update_githook = 更新鉤子設置 +settings.payload_url = 推送地址 +settings.content_type = 數據格式 +settings.secret = 密鑰文本 +settings.event_desc = 請設置您希望觸發 Web 鉤子的事件: +settings.event_push_only = 只推送 push 事件。 +settings.active = 是否激活 +settings.active_helper = 當指定事件發生時我們將會觸發此 Web 鉤子。 +settings.add_hook_success = Web 鉤子添加成功! +settings.update_webhook = 更新 Web 鉤子 +settings.update_hook_success = Web 鉤子更新成功! +settings.delete_webhook = 刪除 Web 鉤子 +settings.recent_deliveries = 最近推送記錄 +settings.hook_type = 鉤子類型 +settings.add_slack_hook_desc = 為您的倉庫增加 Slack 集成 +settings.slack_token = 令牌 +settings.slack_domain = 域名 +settings.slack_channel = 頻道 + +[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 = 官方網站 +settings.location = 所在地區 +settings.update_settings = 更新組織設置 +settings.change_orgname = 組織名稱將被修改 +settings.change_orgname_desc = 組織名稱被修改,您確定要繼續操作嗎?這將會影響到所有與該組織有關的鏈接。 +settings.update_setting_success = 組織設置更新成功! +settings.delete = 刪除組織 +settings.delete_account = 刪除當前組織 +settings.delete_prompt = 刪除操作會永久清除該組織的信息,並且 不可恢復! +settings.confirm_delete_account = 確認刪除組織 +settings.delete_org_title = 組織刪除操作 +settings.delete_org_desc = 該組織將被永久性刪除,您確定要繼續操作嗎? +settings.hooks_desc = 在此處添加的 Web 鉤子將會應用到該組織下的 所有倉庫。 + +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 = 管理員團隊對 所有倉庫 具有操作權限,且對組織具有 管理員權限。 +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 = 該團隊擁有對所屬倉庫的 讀取 權限,團隊成員可以進行查看和克隆等只讀操作。 +teams.write_permission_desc = 該團隊擁有對所屬倉庫的 讀取寫入 的權限。 +teams.admin_permission_desc = 該團隊擁有一定的 管理 權限,團隊成員可以讀取、克隆、推送以及添加其它倉庫協作者。 +teams.repositories = 團隊倉庫 +teams.add_team_repository = 添加團隊倉庫 +teams.remove_repo = 移除倉庫 + +[admin] +dashboard = 控制面版 +users = 用戶管理 +organizations = 組織管理 +repositories = 倉庫管理 +authentication = 授權認證管理 +config = 應用配置管理 +notices = 系統提示管理 +monitor = 應用監控面版 +prev = 上一頁 +next = 下一頁 + +dashboard.statistic = 應用統計數據 +dashboard.operations = 管理員操作 +dashboard.system_status = 系統監視狀態 +dashboard.statistic_info = Gogs 數據庫統計:%d 位用戶,%d 個組織,%d 個公鑰,%d 個倉庫,%d 個倉庫關註,%d 個贊,%d 次行為,%d 條權限記錄,%d 個問題,%d 次評論,%d 個社交帳號,%d 個用戶關註,%d 個鏡像,%d 個版本發佈,%d 個登錄源,%d 個 Web 鉤子,%d 個里程碑,%d 個標籤,%d 個鉤子任務,%d 個團隊,%d 個更新任務,%d 個附件。 +dashboard.operation_name = 操作名稱 +dashboard.operation_switch = 開關 +dashboard.operation_run = 執行 +dashboard.clean_unbind_oauth = 清理未綁定社交帳號 +dashboard.delete_inactivate_accounts = 刪除所有未激活帳戶 +dashboard.server_uptime = 服務執行時間 +dashboard.current_goroutine = 當前 Goroutines 數量 +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 = 當前 Heap 內存使用量 +dashboard.heap_memory_obtained = Heap 內存佔用量 +dashboard.heap_memory_idle = Heap 內存空閒量 +dashboard.heap_memory_in_use = 正在使用的 Heap 內存 +dashboard.heap_memory_released = 被釋放的 Heap 內存 +dashboard.heap_objects = Heap 對象數量 +dashboard.bootstrap_stack_usage = 啟動 Stack 使用量 +dashboard.stack_memory_obtained = 被分配的 Stack 內存 +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 = 被分配的垃圾收集元數據內存 +dashboard.other_system_allocation_obtained = 其它被分配的系統內存 +dashboard.next_gc_recycle = 下次垃圾收集內存回收量 +dashboard.last_gc_time = 距離上次垃圾收集時間 +dashboard.total_gc_time = 垃圾收集執行時間總量 +dashboard.total_gc_pause = 垃圾收集暫停時間總量 +dashboard.last_gc_pause = 上次垃圾收集暫停時間 +dashboard.gc_times = 垃圾收集執行次數 + +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.update_profile = 更新用戶信息 +users.delete_account = 刪除該用戶 +users.still_own_repo = 該帳戶仍然是某些倉庫的擁有者,您必須先轉移或刪除它們才能執行刪除帳戶操作! + +orgs.org_manage_panel = 組織管理面版 +orgs.name = 組織名稱 +orgs.teams = 團隊數 +orgs.members = 成員數 + +repos.repo_manage_panel = 倉庫管理界面 +repos.owner = 所有者 +repos.name = 倉庫名稱 +repos.private = 私有庫 +repos.watches = 關註數 +repos.stars = 點讚數 +repos.issues = 問題數 + +auths.auth_manage_panel = 授權認證管理面版 +auths.new = 添加新的認證源 +auths.name = 認證名稱 +auths.type = 認證類型 +auths.enabled = 已啟用 +auths.updated = 最後更新時間 +auths.auth_type = 授權類型 +auths.auth_name = 授權名稱 +auths.domain = 域名 +auths.host = 主機地址 +auths.port = 主機端口 +auths.base_dn = 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 = Web 鉤子配置 +config.task_interval = 任務周期 +config.deliver_timeout = 推送超時 +config.mailer_config = 郵件配置 +config.mailer_enabled = 啟用服務 +config.mailer_name = 發送者名稱 +config.mailer_host = 郵件主機地址 +config.mailer_user = 發送者帳號 +config.oauth_config = 社交帳號配置 +config.oauth_enabled = 啟用服務 +config.cache_config = Cache 配置 +config.cache_adapter = Cache 適配器 +config.cache_interval = Cache 周期 +config.cache_conn = Cache 連接字符串 +config.session_config = Session 配置 +config.session_provider = Session 提供者 +config.provider_config = 提供者配置 +config.cookie_name = Cookie 名稱 +config.enable_set_cookie = 啟用設置 Cookie +config.gc_interval_time = 垃圾收集周期 +config.session_life_time = Session 生命周期 +config.https_only = 僅限 HTTPS +config.cookie_life_time = Cookie 生命周期 +config.session_hash_function = Session ID 哈希函數 +config.session_hash_key = Session ID 哈希健值 +config.picture_config = 圖片配置 +config.picture_service = 圖片服務 +config.disable_gravatar = 禁用 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 = 操作 +notices.delete_success = 系統提示刪除成功! + +[action] +create_repo = 創建了倉庫 %s +commit_repo = 推送了 %s 分支的代碼到 %s +create_issue = 創建了問題 %s#%s +comment_issue = 評論了問題 %s#%s +transfer_repo = 將倉庫 %s 轉移至 %s + +[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 = 分鐘 + + + + + + + + + + + + diff --git a/etc/supervisord.conf b/etc/supervisord.conf index e17f50a847..4f4d40eaea 100644 --- a/etc/supervisord.conf +++ b/etc/supervisord.conf @@ -1,12 +1,12 @@ [unix_http_server] -file=/tmp/supervisor.sock ; path to your socket file +file=log/supervisor.sock ; path to your socket file [supervisord] logfile=log/supervisord.log ; supervisord log file logfile_maxbytes=50MB ; maximum size of logfile before rotation logfile_backups=10 ; number of backed up logfiles loglevel=warn ; info, debug, warn, trace -pidfile=/tmp/supervisord.pid ; pidfile location +pidfile=log/supervisord.pid ; pidfile location nodaemon=false ; run supervisord as a daemon minfds=1024 ; number of startup file descriptors minprocs=200 ; number of process descriptors @@ -17,10 +17,10 @@ childlogdir=log supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] -serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket +serverurl=unix://log/supervisor.sock ; use a unix:// URL for a unix socket [program:gogs] -command = /root/Developer/gopath/src/github.com/gogits/gogs/start.sh ; here must be the real url, not ~ or $GOROOT like +command = gogs_start autostart = true -stdout_logfile = log/supervisor-gogs-stderr.log -stderr_logfile = log/supervisor-gogs-error.log \ No newline at end of file +stdout_logfile = log/supervisor-gogs-out.log +stderr_logfile = log/supervisor-gogs-err.log diff --git a/gogs.go b/gogs.go index 289ad19123..e0ecec251a 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.5.4.1003 Beta" +const APP_VER = "0.5.5.1013 Beta" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/action.go b/models/action.go index 4203ead38e..ef111e67a4 100644 --- a/models/action.go +++ b/models/action.go @@ -181,13 +181,19 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string, commit = &base.PushCommits{} } - refName := git.RefEndName(refFullName) + repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName) + // if not the first commit, set the compareUrl + if !strings.HasPrefix(oldCommitId, "0000000") { + commit.CompareUrl = fmt.Sprintf("%s/compare/%s...%s", repoLink, oldCommitId, newCommitId) + } bs, err := json.Marshal(commit) if err != nil { return errors.New("action.CommitRepoAction(json): " + err.Error()) } + refName := git.RefEndName(refFullName) + // Change repository bare status and update last updated time. repo, err := GetRepositoryByName(repoUserId, repoName) if err != nil { @@ -211,7 +217,6 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string, return errors.New("action.CommitRepoAction(NotifyWatchers): " + err.Error()) } - //qlog.Info("action.CommitRepoAction(end): %d/%s", repoUserId, repoName) // New push event hook. if err := repo.GetOwner(); err != nil { @@ -237,13 +242,6 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string, return nil } - repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName) - compareUrl := "" - // if not the first commit, set the compareUrl - if !strings.HasPrefix(oldCommitId, "0000000") { - compareUrl = fmt.Sprintf("%s/compare/%s...%s", repoLink, oldCommitId, newCommitId) - } - pusher_email, pusher_name := "", "" pusher, err := GetUserByName(userName) if err == nil { @@ -293,7 +291,7 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string, }, Before: oldCommitId, After: newCommitId, - CompareUrl: compareUrl, + CompareUrl: commit.CompareUrl, } for _, w := range ws { diff --git a/models/admin.go b/models/admin.go new file mode 100644 index 0000000000..493cc7afc8 --- /dev/null +++ b/models/admin.go @@ -0,0 +1,64 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "time" + + "github.com/Unknwon/com" +) + +type NoticeType int + +const ( + NOTICE_REPOSITORY NoticeType = iota + 1 +) + +// Notice represents a system notice for admin. +type Notice struct { + Id int64 + Type NoticeType + Description string `xorm:"TEXT"` + Created time.Time `xorm:"CREATED"` +} + +// TrStr returns a translation format string. +func (n *Notice) TrStr() string { + return "admin.notices.type_" + com.ToStr(n.Type) +} + +// CreateNotice creates new system notice. +func CreateNotice(tp NoticeType, desc string) error { + n := &Notice{ + Type: tp, + Description: desc, + } + _, err := x.Insert(n) + return err +} + +// CreateRepositoryNotice creates new system notice with type NOTICE_REPOSITORY. +func CreateRepositoryNotice(desc string) error { + return CreateNotice(NOTICE_REPOSITORY, desc) +} + +// CountNotices returns number of notices. +func CountNotices() int64 { + count, _ := x.Count(new(Notice)) + return count +} + +// GetNotices returns given number of notices with offset. +func GetNotices(num, offset int) ([]*Notice, error) { + notices := make([]*Notice, 0, num) + err := x.Limit(num, offset).Desc("id").Find(¬ices) + return notices, err +} + +// DeleteNotice deletes a system notice by given ID. +func DeleteNotice(id int64) error { + _, err := x.Id(id).Delete(new(Notice)) + return err +} diff --git a/models/models.go b/models/models.go index 60959c60e9..4dcc447b34 100644 --- a/models/models.go +++ b/models/models.go @@ -31,12 +31,12 @@ var ( ) func init() { - tables = append(tables, new(User), new(PublicKey), + tables = append(tables, new(User), new(PublicKey), new(Follow), new(Oauth2), new(Repository), new(Watch), new(Star), new(Action), new(Access), - new(Issue), new(Comment), new(Oauth2), new(Follow), - new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssueUser), - new(Milestone), new(Label), new(HookTask), new(Team), new(OrgUser), new(TeamUser), - new(UpdateTask), new(Attachment)) + new(Issue), new(Comment), new(Attachment), new(IssueUser), new(Label), new(Milestone), + new(Mirror), new(Release), new(LoginSource), new(Webhook), + new(UpdateTask), new(HookTask), new(Team), new(OrgUser), new(TeamUser), + new(Notice)) } func LoadModelsConfig() { diff --git a/models/org.go b/models/org.go index 31db8e3643..3232bf2ac1 100644 --- a/models/org.go +++ b/models/org.go @@ -845,20 +845,9 @@ func IsTeamMember(orgId, teamId, uid int64) bool { // GetTeamMembers returns all members in given team of organization. func GetTeamMembers(orgId, teamId int64) ([]*User, error) { - tus := make([]*TeamUser, 0, 10) - err := x.Where("org_id=?", orgId).And("team_id=?", teamId).Find(&tus) - if err != nil { - return nil, err - } - - us := make([]*User, len(tus)) - for i, tu := range tus { - us[i], err = GetUserById(tu.Uid) - if err != nil { - return nil, err - } - } - return us, nil + us := make([]*User, 0, 10) + err := x.Sql("SELECT * FROM `user` JOIN `team_user` ON `team_user`.`team_id` = ? AND `team_user`.`uid` = `user`.`id`", teamId).Find(&us) + return us, err } // GetUserTeams returns all teams that user belongs to in given origanization. diff --git a/models/publickey.go b/models/publickey.go index 8bb924e853..762d7333fa 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -33,6 +33,7 @@ const ( var ( ErrKeyAlreadyExist = errors.New("Public key already exist") ErrKeyNotExist = errors.New("Public key does not exist") + ErrKeyUnableVerify = errors.New("Unable to verify public key") ) var sshOpLocker = sync.Mutex{} @@ -108,7 +109,7 @@ var ( // CheckPublicKeyString checks if the given public key string is recognized by SSH. func CheckPublicKeyString(content string) (bool, error) { if strings.ContainsAny(content, "\n\r") { - return false, errors.New("Only a single line with a single key please") + return false, errors.New("only a single line with a single key please") } // write the key to a file… @@ -126,7 +127,7 @@ func CheckPublicKeyString(content string) (bool, error) { if err != nil { return false, errors.New("ssh-keygen -l -f: " + stderr) } else if len(stdout) < 2 { - return false, errors.New("ssh-keygen returned not enough output to evaluate the key") + return false, errors.New("ssh-keygen returned not enough output to evaluate the key: " + stdout) } // The ssh-keygen in Windows does not print key type, so no need go further. @@ -134,21 +135,22 @@ func CheckPublicKeyString(content string) (bool, error) { return true, nil } + fmt.Println(stdout) sshKeygenOutput := strings.Split(stdout, " ") if len(sshKeygenOutput) < 4 { - return false, errors.New("Not enough fields returned by ssh-keygen -l -f") + return false, ErrKeyUnableVerify } // Check if key type and key size match. - keySize, err := com.StrTo(sshKeygenOutput[0]).Int() - if err != nil { - return false, errors.New("Cannot get key size of the given key") + keySize := com.StrTo(sshKeygenOutput[0]).MustInt() + if keySize == 0 { + return false, errors.New("cannot get key size of the given key") } keyType := strings.TrimSpace(sshKeygenOutput[len(sshKeygenOutput)-1]) if minimumKeySize := MinimumKeySize[keyType]; minimumKeySize == 0 { - return false, errors.New("Sorry, unrecognized public key type") + return false, errors.New("sorry, unrecognized public key type") } else if keySize < minimumKeySize { - return false, fmt.Errorf("The minimum accepted size of a public key %s is %d", keyType, minimumKeySize) + return false, fmt.Errorf("the minimum accepted size of a public key %s is %d", keyType, minimumKeySize) } return true, nil @@ -204,7 +206,7 @@ func AddPublicKey(key *PublicKey) (err error) { if err != nil { return errors.New("ssh-keygen -l -f: " + stderr) } else if len(stdout) < 2 { - return errors.New("Not enough output for calculating fingerprint") + return errors.New("not enough output for calculating fingerprint: " + stdout) } key.Fingerprint = strings.Split(stdout, " ")[1] diff --git a/models/repo.go b/models/repo.go index 0ca8b305ea..d156621c83 100644 --- a/models/repo.go +++ b/models/repo.go @@ -23,6 +23,7 @@ import ( "github.com/Unknwon/cae/zip" "github.com/Unknwon/com" + "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/git" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/process" @@ -48,7 +49,7 @@ var ( ) var ( - DescriptionPattern = regexp.MustCompile(`https?://\S+`) + DescPattern = regexp.MustCompile(`https?://\S+`) ) func LoadRepoConfig() { @@ -165,7 +166,9 @@ type Repository struct { } func (repo *Repository) GetOwner() (err error) { - repo.Owner, err = GetUserById(repo.OwnerId) + if repo.Owner == nil { + repo.Owner, err = GetUserById(repo.OwnerId) + } return err } @@ -182,6 +185,14 @@ func (repo *Repository) IsOwnedBy(u *User) bool { return repo.OwnerId == u.Id } +func (repo *Repository) HasAccess(uname string) bool { + if err := repo.GetOwner(); err != nil { + return false + } + has, _ := HasAccess(uname, path.Join(repo.Owner.Name, repo.Name), READABLE) + return has +} + // DescriptionHtml does special handles to description and return HTML string. func (repo *Repository) DescriptionHtml() template.HTML { sanitize := func(s string) string { @@ -189,7 +200,7 @@ func (repo *Repository) DescriptionHtml() template.HTML { ss := html.EscapeString(s) return fmt.Sprintf(`%s`, ss, ss) } - return template.HTML(DescriptionPattern.ReplaceAllStringFunc(repo.Description, sanitize)) + return template.HTML(DescPattern.ReplaceAllStringFunc(base.XSSString(repo.Description), sanitize)) } // IsRepositoryExist returns true if the repository with given name under user has already existed. @@ -660,7 +671,7 @@ func RepoPath(userName, repoName string) string { func TransferOwnership(u *User, newOwner string, repo *Repository) error { newUser, err := GetUserByName(newOwner) if err != nil { - return err + return fmt.Errorf("fail to get new owner(%s): %v", newOwner, err) } // Check if new owner has repository with same name. @@ -948,9 +959,14 @@ func DeleteRepository(uid, repoId int64, userName string) error { sess.Rollback() return err } + + // Remove repository files. if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil { - sess.Rollback() - return err + desc := fmt.Sprintf("Fail to delete repository files(%s/%s): %v", userName, repo.Name, err) + log.Warn(desc) + if err = CreateRepositoryNotice(desc); err != nil { + log.Error(4, "Fail to add notice: %v", err) + } } return sess.Commit() } diff --git a/models/update.go b/models/update.go index d939a90874..33b7733e18 100644 --- a/models/update.go +++ b/models/update.go @@ -106,7 +106,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName if err = CommitRepoAction(userId, ru.Id, userName, actEmail, repos.Id, repoUserName, repoName, refName, commit, oldCommitId, newCommitId); err != nil { - log.GitLogger.Fatal(4, "runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) + log.GitLogger.Fatal(4, "CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) } return err } @@ -116,8 +116,8 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err) } + // Push new branch. var l *list.List - // if a new branch if isNew { l, err = newCommit.CommitsBefore() if err != nil { @@ -134,7 +134,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName return fmt.Errorf("runUpdate.Commit repoId: %v", err) } - // if commits push + // Push commits. commits := make([]*base.PushCommit, 0) var actEmail string for e := l.Front(); e != nil; e = e.Next() { @@ -153,9 +153,8 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName } } - //commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()}) if err = CommitRepoAction(userId, ru.Id, userName, actEmail, - repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits}, oldCommitId, newCommitId); err != nil { + repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits, ""}, oldCommitId, newCommitId); err != nil { return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) } return nil diff --git a/models/user.go b/models/user.go index ee8f8586d5..dc9b052ca8 100644 --- a/models/user.go +++ b/models/user.go @@ -488,7 +488,7 @@ func GetUserByName(name string) (*User, error) { return user, nil } -// GetUserEmailsByNames returns a slice of e-mails corresponds to names. +// GetUserEmailsByNames returns a list of e-mails corresponds to names. func GetUserEmailsByNames(names []string) []string { mails := make([]string, 0, len(names)) for _, name := range names { diff --git a/models/webhook.go b/models/webhook.go index 9508c98a5e..ac0c240977 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -235,8 +235,22 @@ func UpdateHookTask(t *HookTask) error { return err } +var ( + // Prevent duplicate deliveries. + // This happens with massive hook tasks cannot finish delivering + // before next shooting starts. + isShooting = false +) + // DeliverHooks checks and delivers undelivered hooks. +// FIXME: maybe can use goroutine to shoot a number of them at same time? func DeliverHooks() { + if isShooting { + return + } + isShooting = true + defer func() { isShooting = false }() + tasks := make([]*HookTask, 0, 10) timeout := time.Duration(setting.WebhookDeliverTimeout) * time.Second x.Where("is_delivered=?", false).Iterate(new(HookTask), @@ -255,7 +269,7 @@ func DeliverHooks() { t.IsDelivered = true - // TODO: record response. + // FIXME: record response. switch t.Type { case GOGS: { diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 233f7b1063..df5b8b69fb 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -102,7 +102,7 @@ func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs *binding.Errors, // \/ \/ \/ type CreateIssueForm struct { - IssueName string `form:"title" binding:"Required;MaxSize(50)"` + IssueName string `form:"title" binding:"Required;MaxSize(255)"` MilestoneId int64 `form:"milestoneid"` AssigneeId int64 `form:"assigneeid"` Labels string `form:"labels"` diff --git a/modules/base/markdown.go b/modules/base/markdown.go index a3db15df1a..cb08320099 100644 --- a/modules/base/markdown.go +++ b/modules/base/markdown.go @@ -13,7 +13,8 @@ import ( "regexp" "strings" - "github.com/gogits/gfm" + "github.com/russross/blackfriday" + "github.com/gogits/gogs/modules/setting" ) @@ -74,7 +75,7 @@ func IsReadmeFile(name string) bool { } type CustomRender struct { - gfm.Renderer + blackfriday.Renderer urlPrefix string } @@ -154,39 +155,40 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte { func RenderRawMarkdown(body []byte, urlPrefix string) []byte { htmlFlags := 0 - // htmlFlags |= gfm.HTML_USE_XHTML - // htmlFlags |= gfm.HTML_USE_SMARTYPANTS - // htmlFlags |= gfm.HTML_SMARTYPANTS_FRACTIONS - // htmlFlags |= gfm.HTML_SMARTYPANTS_LATEX_DASHES - // htmlFlags |= gfm.HTML_SKIP_HTML - htmlFlags |= gfm.HTML_SKIP_STYLE - htmlFlags |= gfm.HTML_SKIP_SCRIPT - htmlFlags |= gfm.HTML_GITHUB_BLOCKCODE - htmlFlags |= gfm.HTML_OMIT_CONTENTS - // htmlFlags |= gfm.HTML_COMPLETE_PAGE + // htmlFlags |= blackfriday.HTML_USE_XHTML + // htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS + // htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS + // htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES + // htmlFlags |= blackfriday.HTML_SKIP_HTML + htmlFlags |= blackfriday.HTML_SKIP_STYLE + // htmlFlags |= blackfriday.HTML_SKIP_SCRIPT + // htmlFlags |= blackfriday.HTML_GITHUB_BLOCKCODE + htmlFlags |= blackfriday.HTML_OMIT_CONTENTS + // htmlFlags |= blackfriday.HTML_COMPLETE_PAGE renderer := &CustomRender{ - Renderer: gfm.HtmlRenderer(htmlFlags, "", ""), + Renderer: blackfriday.HtmlRenderer(htmlFlags, "", ""), urlPrefix: urlPrefix, } // set up the parser extensions := 0 - extensions |= gfm.EXTENSION_NO_INTRA_EMPHASIS - extensions |= gfm.EXTENSION_TABLES - extensions |= gfm.EXTENSION_FENCED_CODE - extensions |= gfm.EXTENSION_AUTOLINK - extensions |= gfm.EXTENSION_STRIKETHROUGH - extensions |= gfm.EXTENSION_HARD_LINE_BREAK - extensions |= gfm.EXTENSION_SPACE_HEADERS - extensions |= gfm.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK + extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS + extensions |= blackfriday.EXTENSION_TABLES + extensions |= blackfriday.EXTENSION_FENCED_CODE + extensions |= blackfriday.EXTENSION_AUTOLINK + extensions |= blackfriday.EXTENSION_STRIKETHROUGH + extensions |= blackfriday.EXTENSION_HARD_LINE_BREAK + extensions |= blackfriday.EXTENSION_SPACE_HEADERS + extensions |= blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK - body = gfm.Markdown(body, renderer, extensions) + body = blackfriday.Markdown(body, renderer, extensions) return body } func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte { body := RenderSpecialLink(rawBytes, urlPrefix) body = RenderRawMarkdown(body, urlPrefix) + body = XSS(body) return body } diff --git a/modules/base/template.go b/modules/base/template.go index b1c8c161d3..6d25cd45a8 100644 --- a/modules/base/template.go +++ b/modules/base/template.go @@ -5,7 +5,6 @@ package base import ( - "bytes" "container/list" "encoding/json" "errors" @@ -107,7 +106,6 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{ return a + b }, "ActionIcon": ActionIcon, - "ActionDesc": ActionDesc, "DateFormat": DateFormat, "List": List, "Mail2Domain": func(mail string) string { @@ -162,19 +160,6 @@ func ActionIcon(opType int) string { } } -// FIXME: Legacy -const ( - TPL_CREATE_REPO = `%s created repository %s` - TPL_COMMIT_REPO = `%s pushed to %s at %s%s` - TPL_COMMIT_REPO_LI = `
user-avatar %s %s
` - TPL_CREATE_ISSUE = `%s opened issue %s#%s -
user-avatar %s
` - TPL_TRANSFER_REPO = `%s transfered repository %s to %s` - TPL_PUSH_TAG = `%s pushed tag %s at %s` - TPL_COMMENT_ISSUE = `%s commented on issue %s#%s -
user-avatar %s
` -) - type PushCommit struct { Sha1 string Message string @@ -183,8 +168,9 @@ type PushCommit struct { } type PushCommits struct { - Len int - Commits []*PushCommit + Len int + Commits []*PushCommit + CompareUrl string } func ActionContent2Commits(act Actioner) *PushCommits { @@ -195,52 +181,6 @@ func ActionContent2Commits(act Actioner) *PushCommits { return push } -// FIXME: Legacy -// ActionDesc accepts int that represents action operation type -// and returns the description. -func ActionDesc(act Actioner) string { - actUserName := act.GetActUserName() - email := act.GetActEmail() - repoUserName := act.GetRepoUserName() - repoName := act.GetRepoName() - repoLink := repoUserName + "/" + repoName - branch := act.GetBranch() - content := act.GetContent() - switch act.GetOpType() { - case 1: // Create repository. - return fmt.Sprintf(TPL_CREATE_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, repoName) - case 5: // Commit repository. - var push *PushCommits - if err := json.Unmarshal([]byte(content), &push); err != nil { - return err.Error() - } - buf := bytes.NewBuffer([]byte("\n")) - for _, commit := range push.Commits { - buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n") - } - if push.Len > 3 { - buf.WriteString(fmt.Sprintf(`
%d other commits >>
`, actUserName, repoName, branch, push.Len)) - } - return fmt.Sprintf(TPL_COMMIT_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink, - buf.String()) - case 6: // Create issue. - infos := strings.SplitN(content, "|", 2) - return fmt.Sprintf(TPL_CREATE_ISSUE, setting.AppSubUrl, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0], - AvatarLink(email), infos[1]) - case 8: // Transfer repository. - newRepoLink := content + "/" + repoName - return fmt.Sprintf(TPL_TRANSFER_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, newRepoLink, newRepoLink) - case 9: // Push tag. - return fmt.Sprintf(TPL_PUSH_TAG, setting.AppSubUrl, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink) - case 10: // Comment issue. - infos := strings.SplitN(content, "|", 2) - return fmt.Sprintf(TPL_COMMENT_ISSUE, setting.AppSubUrl, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0], - AvatarLink(email), infos[1]) - default: - return "invalid type" - } -} - func DiffTypeToStr(diffType int) string { diffTypes := map[int]string{ 1: "add", 2: "modify", 3: "del", diff --git a/modules/base/tool.go b/modules/base/tool.go index b4083d090f..38fd1e21e7 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -14,6 +14,7 @@ import ( "hash" "html/template" "math" + "regexp" "strings" "time" @@ -446,3 +447,29 @@ 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 ]*:`), 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))) +} diff --git a/modules/git/hooks.go b/modules/git/hooks.go new file mode 100644 index 0000000000..5b3c88a931 --- /dev/null +++ b/modules/git/hooks.go @@ -0,0 +1,111 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "errors" + "io/ioutil" + "os" + "path" + "strings" +) + +// hookNames is a list of Git hooks' name that are supported. +var hookNames = []string{ + "pre-applypatch", + "applypatch-msg", + "prepare-commit-msg", + "commit-msg", + "pre-commit", + "pre-rebase", + "post-commit", + "post-receive", + "post-update", +} + +var ( + ErrNotValidHook = errors.New("not a valid Git hook") +) + +// IsValidHookName returns true if given name is a valid Git hook. +func IsValidHookName(name string) bool { + for _, hn := range hookNames { + if hn == name { + return true + } + } + return false +} + +// Hook represents a Git hook. +type Hook struct { + name string + IsActive bool // Indicates whether repository has this hook. + Content string // Content of hook if it's active. + Sample string // Sample content from Git. + path string // Hook file path. +} + +// GetHook returns a Git hook by given name and repository. +func GetHook(repoPath, name string) (*Hook, error) { + if !IsValidHookName(name) { + return nil, ErrNotValidHook + } + h := &Hook{ + name: name, + path: path.Join(repoPath, "hooks", name), + } + if isFile(h.path) { + data, err := ioutil.ReadFile(h.path) + if err != nil { + return nil, err + } + h.IsActive = true + h.Content = string(data) + } else if isFile(h.path + ".sample") { + data, err := ioutil.ReadFile(h.path + ".sample") + if err != nil { + return nil, err + } + h.Sample = string(data) + } + return h, nil +} + +func (h *Hook) Name() string { + return h.name +} + +// Update updates hook settings. +func (h *Hook) Update() error { + if len(strings.TrimSpace(h.Content)) == 0 { + return os.Remove(h.path) + } + return ioutil.WriteFile(h.path, []byte(strings.Replace(h.Content, "\r", "", -1)), os.ModePerm) +} + +// ListHooks returns a list of Git hooks of given repository. +func ListHooks(repoPath string) (_ []*Hook, err error) { + if !isDir(path.Join(repoPath, "hooks")) { + return nil, errors.New("hooks path does not exist") + } + + hooks := make([]*Hook, len(hookNames)) + for i, name := range hookNames { + hooks[i], err = GetHook(repoPath, name) + if err != nil { + return nil, err + } + } + return hooks, nil +} + +func (repo *Repository) GetHook(name string) (*Hook, error) { + return GetHook(repo.Path, name) +} + +func (repo *Repository) Hooks() ([]*Hook, error) { + return ListHooks(repo.Path) +} diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 77ae3db007..ed994d48ae 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -22,6 +22,9 @@ func (repo *Repository) IsTagExist(tagName string) bool { // GetTags returns all tags of given repository. func (repo *Repository) GetTags() ([]string, error) { + if gitVer.AtLeast(MustParseVersion("2.0.0")) { + return repo.getTagsReversed() + } stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l") if err != nil { return nil, errors.New(stderr) @@ -30,6 +33,15 @@ func (repo *Repository) GetTags() ([]string, error) { return tags[:len(tags)-1], nil } +func (repo *Repository) getTagsReversed() ([]string, error) { + stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l", "--sort=-v:refname") + if err != nil { + return nil, errors.New(stderr) + } + tags := strings.Split(stdout, "\n") + return tags[:len(tags)-1], nil +} + func (repo *Repository) CreateTag(tagName, idStr string) error { _, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", tagName, idStr) if err != nil { diff --git a/modules/git/utils.go b/modules/git/utils.go index 26eef23191..6abbca557b 100644 --- a/modules/git/utils.go +++ b/modules/git/utils.go @@ -7,6 +7,7 @@ package git import ( "bytes" "container/list" + "os" "path/filepath" "strings" ) @@ -46,3 +47,23 @@ func RefEndName(refStr string) string { func filepathFromSHA1(rootdir, sha1 string) string { return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:]) } + +// isDir returns true if given path is a directory, +// or returns false when it's a file or does not exist. +func isDir(dir string) bool { + f, e := os.Stat(dir) + if e != nil { + return false + } + return f.IsDir() +} + +// isFile returns true if given path is a file, +// or returns false when it's a directory or does not exist. +func isFile(filePath string) bool { + f, e := os.Stat(filePath) + if e != nil { + return false + } + return !f.IsDir() +} diff --git a/modules/git/version.go b/modules/git/version.go index 9908d11e20..b535521ec4 100644 --- a/modules/git/version.go +++ b/modules/git/version.go @@ -74,6 +74,10 @@ func (v *Version) LessThan(that *Version) bool { return v.Compare(that) < 0 } +func (v *Version) AtLeast(that *Version) bool { + return v.Compare(that) >= 0 +} + // GetVersion returns current Git version installed. func GetVersion() (*Version, error) { if gitVer != nil { diff --git a/modules/mailer/mailer.go b/modules/mailer/mailer.go index 92cdfc7d6a..758792a351 100644 --- a/modules/mailer/mailer.go +++ b/modules/mailer/mailer.go @@ -5,7 +5,9 @@ package mailer import ( + "crypto/tls" "fmt" + "net" "net/smtp" "strings" @@ -33,7 +35,7 @@ func (m Message) Content() string { } // create mail content - content := "From: " + m.From + "<" + m.User + + content := "From: \"" + m.From + "\" <" + m.User + ">\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body return content } @@ -64,6 +66,53 @@ func processMailQueue() { } } +// sendMail allows mail with self-signed certificates. +func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipients []string, msgContent []byte) error { + client, err := smtp.Dial(hostAddressWithPort) + if err != nil { + return err + } + + host, _, _ := net.SplitHostPort(hostAddressWithPort) + tlsConn := &tls.Config{ + InsecureSkipVerify: true, + ServerName: host, + } + if err = client.StartTLS(tlsConn); err != nil { + return err + } + + if auth != nil { + if err = client.Auth(auth); err != nil { + return err + } + } + + if err = client.Mail(from); err != nil { + return err + } + + for _, rec := range recipients { + if err = client.Rcpt(rec); err != nil { + return err + } + } + + w, err := client.Data() + if err != nil { + return err + } + if _, err = w.Write([]byte(msgContent)); err != nil { + return err + } + + if err = w.Close(); err != nil { + return err + } + + return client.Quit() +} + // Direct Send mail message func Send(msg *Message) (int, error) { log.Trace("Sending mails to: %s", strings.Join(msg.To, "; ")) @@ -85,7 +134,7 @@ func Send(msg *Message) (int, error) { num := 0 for _, to := range msg.To { body := []byte("To: " + to + "\r\n" + content) - err := smtp.SendMail(setting.MailService.Host, auth, msg.From, []string{to}, body) + err := sendMail(setting.MailService.Host, auth, msg.From, []string{to}, body) if err != nil { return num, err } @@ -96,7 +145,7 @@ func Send(msg *Message) (int, error) { body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content) // send to multiple emails in one message - err := smtp.SendMail(setting.MailService.Host, auth, msg.From, msg.To, body) + err := sendMail(setting.MailService.Host, auth, msg.From, msg.To, body) if err != nil { return 0, err } else { diff --git a/modules/middleware/context.go b/modules/middleware/context.go index 90716d2c59..86e98c9071 100644 --- a/modules/middleware/context.go +++ b/modules/middleware/context.go @@ -29,7 +29,6 @@ import ( // Context represents context of a request. type Context struct { *macaron.Context - i18n.Locale Cache cache.Cache csrf csrf.CSRF Flash *session.Flash @@ -76,12 +75,6 @@ type Context struct { } } -// Query querys form parameter. -func (ctx *Context) Query(name string) string { - ctx.Req.ParseForm() - return ctx.Req.Form.Get(name) -} - // HasError returns true if error occurs in form validation. func (ctx *Context) HasApiError() bool { hasErr, ok := ctx.Data["HasError"] @@ -162,7 +155,6 @@ func Contexter() macaron.Handler { return func(c *macaron.Context, l i18n.Locale, cache cache.Cache, sess session.Store, f *session.Flash, x csrf.CSRF) { ctx := &Context{ Context: c, - Locale: l, Cache: cache, csrf: x, Flash: f, diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index c6250f6d59..78af58eac8 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -308,3 +308,13 @@ func RequireTrueOwner() macaron.Handler { } } } + +// GitHookService checks if repsitory Git hooks service has been enabled. +func GitHookService() macaron.Handler { + return func(ctx *Context) { + if !setting.Service.EnableGitHooks { + ctx.Handle(404, "GitHookService", nil) + return + } + } +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 67e48108d9..b8fc4dec2e 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -275,6 +275,7 @@ var Service struct { LdapAuth bool ActiveCodeLives int ResetPwdCodeLives int + EnableGitHooks bool } func newService() { @@ -284,6 +285,7 @@ func newService() { Service.RequireSignInView = Cfg.MustBool("service", "REQUIRE_SIGNIN_VIEW") Service.EnableCacheAvatar = Cfg.MustBool("service", "ENABLE_CACHE_AVATAR") Service.EnableReverseProxyAuth = Cfg.MustBool("service", "ENABLE_REVERSE_PROXY_AUTHENTICATION") + Service.EnableGitHooks = Cfg.MustBool("service", "ENABLE_GIT_HOOKS") } var logLevels = map[string]string{ diff --git a/public/ng/css/gogs.css b/public/ng/css/gogs.css index feb21c97c2..52a503cc4d 100644 --- a/public/ng/css/gogs.css +++ b/public/ng/css/gogs.css @@ -88,6 +88,7 @@ img.avatar-100 { z-index: 100; font-size: 12px; width: 120%; + min-width: 100px; } #footer-lang .drop-down li > a { padding: 3px 9px; @@ -270,6 +271,10 @@ img.avatar-100 { .pagination li { display: inline; } +.list-unstyled { + padding-left: 0; + list-style: none; +} .markdown { background-color: white; font-size: 16px; @@ -1397,12 +1402,10 @@ The register and sign-in page style } .code-view .lines-num span { font-family: Monaco, Menlo, Consolas, "Courier New", monospace; - line-height: 18px; - padding: 0 8px 0 10px; + line-height: 1.6; + padding: 0 10px; cursor: pointer; display: block; - margin-top: 2px; - font-size: 12px; } .code-view .lines-code > pre { border: none; @@ -1486,6 +1489,106 @@ The register and sign-in page style font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace; font-size: 14px; } +.diff-head-box { + margin-top: 10px; +} +.diff-head-box .panel-body { + padding: 10px 15px 5px 10px; +} +.diff-head-box .author img { + margin-top: -7px; +} +.diff-detail-box { + margin: 15px 0; + line-height: 30px; +} +.diff-detail-box ol { + clear: both; + padding-left: 0; + margin-bottom: 28px; +} +.diff-detail-box ol li { + list-style: none; + padding-bottom: 4px; + margin-bottom: 4px; + border-bottom: 1px dashed #DDD; + padding-left: 6px; +} +.diff-detail-box span.status { + display: inline-block; + width: 12px; + height: 12px; + margin-right: 8px; + vertical-align: middle; +} +.diff-detail-box span.status.modify { + background-color: #f0db88; +} +.diff-detail-box span.status.add { + background-color: #b4e2b4; +} +.diff-detail-box span.status.del { + background-color: #e9aeae; +} +.diff-detail-box span.status.rename { + background-color: #dad8ff; +} +.diff-box .count { + margin-right: 12px; +} +.diff-box .count .bar { + background-color: #e75316; + height: 12px; + width: 40px; + display: inline-block; + margin: 2px 4px 0 4px; + vertical-align: text-top; +} +.diff-box .count .bar .add { + background-color: #77c64a; + height: 12px; +} +.diff-box .file { + color: #888; +} +.diff-box .panel-header { + font-size: 14px; +} +.diff-file-box .code-diff tbody tr:hover td, +.diff-file-box .code-diff tbody tr:hover pre { + background-color: #FFF8D2 !important; + border-color: #F0DB88 !important; +} +.diff-file-box .file-body.file-code .lines-num-old { + border-right: 1px solid #DDD; +} +.file-content .file-body.file-code .lines-num { + text-align: right; + color: #999; + background: #fafafa; + width: 1%; +} +.diff-file-box .code-diff tbody tr.tag-code td, +.diff-file-box .code-diff tbody tr.tag-code pre { + background-color: #E0E0E0 !important; + border-color: #ADADAD !important; +} +.diff-file-box .code-diff tbody tr.del-code td, +.diff-file-box .code-diff tbody tr.del-code pre { + background-color: #ffe2dd !important; + border-color: #e9aeae !important; +} +.diff-file-box .code-diff tbody tr.add-code td, +.diff-file-box .code-diff tbody tr.add-code pre { + background-color: #d1ffd6 !important; + border-color: #b4e2b4 !important; +} +.compare-head-box { + margin-top: 10px; +} +.compare-head-box .compare { + padding: 0 15px 15px 15px; +} #admin-wrapper, #setting-wrapper { padding-bottom: 100px; diff --git a/public/ng/css/ui.css b/public/ng/css/ui.css index 9c3c8ded5d..e659180d65 100644 --- a/public/ng/css/ui.css +++ b/public/ng/css/ui.css @@ -366,6 +366,9 @@ dt { .grid-4-5 { width: 80%; } +.btn { + white-space: nowrap; +} .btn-small { font-size: 10.8px; padding: .4em .9em; @@ -457,6 +460,9 @@ dt { box-sizing: content-box; text-align: center; } +.btn-comb { + margin-left: -1px; +} .btn-disabled { opacity: .6; cursor: not-allowed; @@ -480,6 +486,10 @@ dt { .ipt-large { font-size: 14.4px; } +.ipt-textarea { + height: auto !important; + width: auto; +} .ipt-disabled, input[disabled] { background-color: #f2f2f2 !important; @@ -709,6 +719,14 @@ ul.menu-radius > li:last-child > a { border-bottom-left-radius: .3em; border-bottom-right-radius: .3em; } +.panel.panel-info { + border-color: #85c5e5; +} +.panel.panel-info > .panel-header { + color: #31708f; + background-color: #d9edf7; + border-color: #85c5e5; +} .panel.panel-warning { border-color: #F0C36D; } diff --git a/public/ng/js/gogs.js b/public/ng/js/gogs.js index 4bcdc5c8f5..eba1744b93 100644 --- a/public/ng/js/gogs.js +++ b/public/ng/js/gogs.js @@ -299,6 +299,9 @@ function initCore() { e.preventDefault(); $.magnificPopup.close(); }); + + // Collapse. + $('.collapse').hide(); } function initUserSetting() { @@ -698,6 +701,37 @@ function initProfile() { }); } +function initTimeSwitch() { + // Time switch. + $(".time-since[title]").on("click", function () { + var $this = $(this); + + var title = $this.attr("title"); + var text = $this.text(); + + $this.text(title); + $this.attr("title", text); + }); +} + +function initDiff() { + $('.diff-detail-box>a').click(function () { + $($(this).data('target')).slideToggle(100); + }) + + var $counter = $('.diff-counter'); + if ($counter.length < 1) { + return; + } + $counter.each(function (i, item) { + var $item = $(item); + var addLine = $item.find('span[data-line].add').data("line"); + var delLine = $item.find('span[data-line].del').data("line"); + var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100; + $item.find(".bar .add").css("width", addPercent + "%"); + }); +} + $(document).ready(function () { Gogs.AppSubUrl = $('head').data('suburl') || ''; initCore(); @@ -737,6 +771,10 @@ $(document).ready(function () { if ($('#user-profile-page').length) { initProfile(); } + if ($('#diff-page').length) { + initTimeSwitch(); + initDiff(); + } $('#dashboard-sidebar-menu').tabs(); $('#pull-issue-preview').markdown_preview(".issue-add-comment"); diff --git a/public/ng/js/min/gogs-min.js b/public/ng/js/min/gogs-min.js index 1538c3637d..6b7f408d2b 100644 --- a/public/ng/js/min/gogs-min.js +++ b/public/ng/js/min/gogs-min.js @@ -1,5 +1,5 @@ -function Tabs(e){function t(e){console.log("hide",e),e.removeClass("js-tab-nav-show"),$(e.data("tab-target")).removeClass("js-tab-show").hide()}function n(e){console.log("show",e),e.addClass("js-tab-nav-show"),$(e.data("tab-target")).addClass("js-tab-show").show()}var r=$(e);if(r.length){var i=r.find(".js-tab-nav-show");i.length&&$(i.data("tab-target")).addClass("js-tab-show"),r.on("click",".js-tab-nav",function(e){e.preventDefault();var o=$(this);o.hasClass("js-tab-nav-show")||(i=r.find(".js-tab-nav-show").eq(0),t(i),n(o))}),console.log("init tabs @",e)}}function Preview(e,t){function n(e){return e.find(".js-preview-input").eq(0)}function r(e){return e.hasClass("js-preview-container")?e:e.find(".js-preview-container").eq(0)}var i=$(e),o=$(t),a=n(o);if(!a.length)return void console.log("[preview]: no preview input");var s=r(o);return s.length?(i.on("click",function(){$.post("/api/v1/markdown",{text:a.val()},function(e){s.html(e)})}),void console.log("[preview]: init preview @",e,"&",t)):void console.log("[preview]: no preview container")}function initCore(){Gogs.renderMarkdown(),Gogs.renderCodeView(),$(".js-tab-nav").click(function(e){$(this).hasClass("js-tab-nav-show")||($(this).parent().find(".js-tab-nav-show").each(function(){$(this).removeClass("js-tab-nav-show"),$($(this).data("tab-target")).hide()}),$(this).addClass("js-tab-nav-show"),$($(this).data("tab-target")).show()),e.preventDefault()}),$(document).on("click",".popup-modal-dismiss",function(e){e.preventDefault(),$.magnificPopup.close()})}function initUserSetting(){var t=$("#username"),n=$("#user-profile-form");$("#change-username-btn").magnificPopup({modal:!0,callbacks:{open:function(){t.data("uname")==t.val()&&($.magnificPopup.close(),n.submit())}}}).click(function(){return t.data("uname")!=t.val()?(e.preventDefault(),!0):void 0}),$("#change-username-submit").click(function(){$.magnificPopup.close(),n.submit()}),$("#ssh-add").click(function(){$("#user-ssh-add-form").removeClass("hide")}),$("#delete-account-btn").magnificPopup({modal:!0}).click(function(e){return e.preventDefault(),!0}),$("#delete-account-submit").click(function(){$.magnificPopup.close(),$("#delete-account-form").submit()})}function initRepoCreate(){$("#repo-create-owner-list").on("click","li",function(){if(!$(this).hasClass("checked")){var e=$(this).data("uid");$("#repo-owner-id").val(e),$("#repo-owner-avatar").attr("src",$(this).find("img").attr("src")),$("#repo-owner-name").text($(this).text().trim()),$(this).parent().find(".checked").removeClass("checked"),$(this).addClass("checked"),console.log("set repo owner to uid :",e,$(this).text().trim())}}),$("#auth-button").click(function(e){$("#repo-migrate-auth").slideToggle("fast"),e.preventDefault()}),console.log("initRepoCreate")}function initRepo(){$("#repo-clone-ssh").click(function(){$(this).removeClass("btn-gray").addClass("btn-blue"),$("#repo-clone-https").removeClass("btn-blue").addClass("btn-gray"),$("#repo-clone-url").val($(this).data("link")),$(".clone-url").text($(this).data("link"))}),$("#repo-clone-https").click(function(){$(this).removeClass("btn-gray").addClass("btn-blue"),$("#repo-clone-ssh").removeClass("btn-blue").addClass("btn-gray"),$("#repo-clone-url").val($(this).data("link")),$(".clone-url").text($(this).data("link"))});var e=$("#repo-clone-copy");e.hover(function(){Gogs.bindCopy($(this))}),e.tipsy({fade:!0})}function initHookTypeChange(){$("select#hook-type").on("change",function(){hookTypes=["Gogs","Slack"];var e=$(this).val();hookTypes.forEach(function(t){e===t?$("div#"+t.toLowerCase()).toggleShow():$("div#"+t.toLowerCase()).toggleHide()})})}function initRepoSetting(){var t=$("#repo_name"),n=$("#repo-setting-form");$("#change-reponame-btn").magnificPopup({modal:!0,callbacks:{open:function(){t.data("repo-name")==t.val()&&($.magnificPopup.close(),n.submit())}}}).click(function(){return t.data("repo-name")!=t.val()?(e.preventDefault(),!0):void 0}),$("#change-reponame-submit").click(function(){$.magnificPopup.close(),n.submit()}),initHookTypeChange(),$("#transfer-repo-btn").magnificPopup({modal:!0}),$("#transfer-repo-submit").click(function(){$.magnificPopup.close(),$("#transfer-repo-form").submit()}),$("#delete-repo-btn").magnificPopup({modal:!0}),$("#delete-repo-submit").click(function(){$.magnificPopup.close(),$("#delete-repo-form").submit()}),$("#repo-collab-list hr:last-child").remove();var r=$("#repo-collaborator").next().next().find("ul");$("#repo-collaborator").on("keyup",function(){var e=$(this);return e.val()?void Gogs.searchUsers(e.val(),r):void r.toggleHide()}).on("focus",function(){$(this).val()?r.toggleShow():r.toggleHide()}).next().next().find("ul").on("click","li",function(){$("#repo-collaborator").val($(this).text()),r.toggleHide()})}function initOrgSetting(){var t=$("#orgname"),n=$("#org-setting-form");$("#change-orgname-btn").magnificPopup({modal:!0,callbacks:{open:function(){t.data("orgname")==t.val()&&($.magnificPopup.close(),n.submit())}}}).click(function(){return t.data("orgname")!=t.val()?(e.preventDefault(),!0):void 0}),$("#change-orgname-submit").click(function(){$.magnificPopup.close(),n.submit()}),$("#delete-org-btn").magnificPopup({modal:!0}).click(function(e){return e.preventDefault(),!0}),$("#delete-org-submit").click(function(){$.magnificPopup.close(),$("#delete-org-form").submit()}),initHookTypeChange()}function initInvite(){var e=$("#org-member-invite-list");$("#org-member-invite").on("keyup",function(){var t=$(this);return t.val()?void Gogs.searchUsers(t.val(),e):void e.toggleHide()}).on("focus",function(){$(this).val()?e.toggleShow():e.toggleHide()}).next().next().find("ul").on("click","li",function(){$("#org-member-invite").val($(this).text()),e.toggleHide()})}function initOrgTeamCreate(){$("#org-team-delete").magnificPopup({modal:!0}).click(function(e){return e.preventDefault(),!0}),$("#delete-team-submit").click(function(){$.magnificPopup.close();var e=$("#team-create-form");e.attr("action",e.data("delete-url"))})}function initTeamMembersList(){var e=$("#org-team-members-list");$("#org-team-members-add").on("keyup",function(){var t=$(this);return t.val()?void Gogs.searchUsers(t.val(),e):void e.toggleHide()}).on("focus",function(){$(this).val()?e.toggleShow():e.toggleHide()}).next().next().find("ul").on("click","li",function(){$("#org-team-members-add").val($(this).text()),e.toggleHide()})}function initTeamRepositoriesList(){var e=$("#org-team-repositories-list");$("#org-team-repositories-add").on("keyup",function(){var t=$(this);return t.val()?void Gogs.searchRepos(t.val(),e,"uid="+t.data("uid")):void e.toggleHide()}).on("focus",function(){$(this).val()?e.toggleShow():e.toggleHide()}).next().next().find("ul").on("click","li",function(){$("#org-team-repositories-add").val($(this).text()),e.toggleHide()})}function initAdmin(){$("#login-type").on("change",function(){var e=$(this).val();e.indexOf("0-")+1?($(".auth-name").toggleHide(),$(".pwd").find("input").attr("required","required").end().toggleShow()):($(".pwd").find("input").removeAttr("required").end().toggleHide(),$(".auth-name").toggleShow())}),$("#delete-account-btn").magnificPopup({modal:!0}).click(function(e){return e.preventDefault(),!0}),$("#delete-account-submit").click(function(){$.magnificPopup.close();var e=$("#user-profile-form");e.attr("action",e.data("delete-url"))}),$("#auth-type").on("change",function(){var e=$(this).val();2==e&&($(".ldap").toggleShow(),$(".smtp").toggleHide()),3==e&&($(".smtp").toggleShow(),$(".ldap").toggleHide())}),$("#delete-auth-btn").magnificPopup({modal:!0}).click(function(e){return e.preventDefault(),!0}),$("#delete-auth-submit").click(function(){$.magnificPopup.close();var e=$("#auth-setting-form");e.attr("action",e.data("delete-url"))})}function initInstall(){!function(){var e="127.0.0.1:3306",t="127.0.0.1:5432";$("#install-database").on("change",function(){var n=$(this).val();"SQLite3"!=n?($(".server-sql").show(),$(".sqlite-setting").addClass("hide"),"PostgreSQL"==n?($(".pgsql-setting").removeClass("hide"),$("#database-host").val()==e&&$("#database-host").val(t)):"MySQL"==n?($(".pgsql-setting").addClass("hide"),$("#database-host").val()==t&&$("#database-host").val(e)):$(".pgsql-setting").addClass("hide")):($(".server-sql").hide(),$(".pgsql-setting").hide(),$(".sqlite-setting").removeClass("hide"))})}()}function initProfile(){$("#profile-avatar").tipsy({fade:!0})}function homepage(){$("#promo-form").submit(function(e){return""===$("#username").val()?(e.preventDefault(),window.location.href=Gogs.AppSubUrl+"/user/login",!0):void 0}),$("#register-button").click(function(e){return""===$("#username").val()?(e.preventDefault(),window.location.href=Gogs.AppSubUrl+"/user/sign_up",!0):void $("#promo-form").attr("action",Gogs.AppSubUrl+"/user/sign_up")})}!function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){function n(e){var t=e.length,n=ot.type(e);return"function"===n||ot.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e}function r(e,t,n){if(ot.isFunction(t))return ot.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return ot.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(pt.test(t))return ot.filter(t,e,n);t=ot.filter(t,e)}return ot.grep(e,function(e){return ot.inArray(e,t)>=0!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t=wt[e]={};return ot.each(e.match(xt)||[],function(e,n){t[n]=!0}),t}function a(){mt.addEventListener?(mt.removeEventListener("DOMContentLoaded",s,!1),e.removeEventListener("load",s,!1)):(mt.detachEvent("onreadystatechange",s),e.detachEvent("onload",s))}function s(){(mt.addEventListener||"load"===event.type||"complete"===mt.readyState)&&(a(),ot.ready())}function l(e,t,n){if(void 0===n&&1===e.nodeType){var r="data-"+t.replace($t,"-$1").toLowerCase();if(n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:Tt.test(n)?ot.parseJSON(n):n}catch(i){}ot.data(e,t,n)}else n=void 0}return n}function c(e){var t;for(t in e)if(("data"!==t||!ot.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function u(e,t,n,r){if(ot.acceptData(e)){var i,o,a=ot.expando,s=e.nodeType,l=s?ot.cache:e,c=s?e[a]:e[a]&&a;if(c&&l[c]&&(r||l[c].data)||void 0!==n||"string"!=typeof t)return c||(c=s?e[a]=V.pop()||ot.guid++:a),l[c]||(l[c]=s?{}:{toJSON:ot.noop}),("object"==typeof t||"function"==typeof t)&&(r?l[c]=ot.extend(l[c],t):l[c].data=ot.extend(l[c].data,t)),o=l[c],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[ot.camelCase(t)]=n),"string"==typeof t?(i=o[t],null==i&&(i=o[ot.camelCase(t)])):i=o,i}}function d(e,t,n){if(ot.acceptData(e)){var r,i,o=e.nodeType,a=o?ot.cache:e,s=o?e[ot.expando]:ot.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){ot.isArray(t)?t=t.concat(ot.map(t,ot.camelCase)):t in r?t=[t]:(t=ot.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;for(;i--;)delete r[t[i]];if(n?!c(r):!ot.isEmptyObject(r))return}(n||(delete a[s].data,c(a[s])))&&(o?ot.cleanData([e],!0):rt.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}function f(){return!0}function p(){return!1}function h(){try{return mt.activeElement}catch(e){}}function m(e){var t=Ht.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function g(e,t){var n,r,i=0,o=typeof e.getElementsByTagName!==St?e.getElementsByTagName(t||"*"):typeof e.querySelectorAll!==St?e.querySelectorAll(t||"*"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||ot.nodeName(r,t)?o.push(r):ot.merge(o,g(r,t));return void 0===t||t&&ot.nodeName(e,t)?ot.merge([e],o):o}function v(e){jt.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t){return ot.nodeName(e,"table")&&ot.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function b(e){return e.type=(null!==ot.find.attr(e,"type"))+"/"+e.type,e}function x(e){var t=Zt.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function w(e,t){for(var n,r=0;null!=(n=e[r]);r++)ot._data(n,"globalEval",!t||ot._data(t[r],"globalEval"))}function C(e,t){if(1===t.nodeType&&ot.hasData(e)){var n,r,i,o=ot._data(e),a=ot._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)ot.event.add(t,n,s[n][r])}a.data&&(a.data=ot.extend({},a.data))}}function S(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!rt.noCloneEvent&&t[ot.expando]){i=ot._data(t);for(r in i.events)ot.removeEvent(t,r,i.handle);t.removeAttribute(ot.expando)}"script"===n&&t.text!==e.text?(b(t).text=e.text,x(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),rt.html5Clone&&e.innerHTML&&!ot.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&jt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}function k(t,n){var r,i=ot(n.createElement(t)).appendTo(n.body),o=e.getDefaultComputedStyle&&(r=e.getDefaultComputedStyle(i[0]))?r.display:ot.css(i[0],"display");return i.detach(),o}function T(e){var t=mt,n=Jt[e];return n||(n=k(e,t),"none"!==n&&n||(Kt=(Kt||ot("