From 1bbf4c9768ac03b0c4fdac0993f7a864cea5faa1 Mon Sep 17 00:00:00 2001 From: Michael Dyrynda Date: Sun, 31 Aug 2014 21:06:50 +0930 Subject: [PATCH 1/4] Add missing 'new migration' link Addresses issue #399 --- templates/user/dashboard/dashboard.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/user/dashboard/dashboard.tmpl b/templates/user/dashboard/dashboard.tmpl index df4fc0b65e..bf0aba097b 100644 --- a/templates/user/dashboard/dashboard.tmpl +++ b/templates/user/dashboard/dashboard.tmpl @@ -58,6 +58,7 @@ @@ -165,4 +166,4 @@ -{{template "ng/base/footer" .}} \ No newline at end of file +{{template "ng/base/footer" .}} From c30063eefbfc58a811695ccb7d0a46d1ffcc95f5 Mon Sep 17 00:00:00 2001 From: fanningert Date: Sun, 31 Aug 2014 15:18:29 +0200 Subject: [PATCH 2/4] Update locale_de-DE.ini --- conf/locale/locale_de-DE.ini | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/conf/locale/locale_de-DE.ini b/conf/locale/locale_de-DE.ini index b40c7b7894..9fc03ee630 100644 --- a/conf/locale/locale_de-DE.ini +++ b/conf/locale/locale_de-DE.ini @@ -113,10 +113,10 @@ last_org_owner = The user to remove is the last member in owner team. There must invalid_ssh_key = Leider sind wir nicht in der Lage, Ihren SSH-Schlüssel zu überprüfen: %s auth_failed = Authentifizierung fehlgeschlagen: %v -still_own_repo = Your account still have ownership of repository, you have to delete or transfer them first. -org_still_own_repo = This organization still have ownership of repository, you have to delete or transfer them first. +still_own_repo = Ihr Konto ist noch immer der Eigentümer vom Repositorie, Sie müssen es zuerst löschen oder übertragen. +org_still_own_repo = Diese Organisation ist noch immer der Eigentümer vom Repositorie, Sie müssen es zuerst löschen oder übertragen. -still_own_user = This authentication still has used by some users, you should move them and then delete again. +still_own_user = Diese Authentifizierung wird noch immer von einigen Benutzern verwendet, Sie sollten sie verschieben und dann erneut löschen. [settings] profile = Profil @@ -132,7 +132,7 @@ full_name = Vollständiger Name website = Website location = Standort update_profile = Profil aktualisieren -update_profile_success = Your profile has been successfully updated. +update_profile_success = Ihr Profil wurde erfolgreich aktualisiert. change_password = Kennwort ändern old_password = Aktuelles Kennwort @@ -185,6 +185,7 @@ migrate_type = Migrationstyp migrate_type_helper = Dieses Repository wird ein Mirror migrate_repo = Repositorie migrieren +copy_link = Copy clone_helper = Need help cloning? Visit Help! unwatch = Beobachtung beenden watch = Beobachtung @@ -192,13 +193,18 @@ unstar = Markierung aufheben star = Markierung fork = Abspaltung +quick_guide = Kurzanleitung +clone_this_repo = Dieses Repositorie klonen +create_new_repo_command = Erstellen Sie ein neues Repositorie mittels der Kommandozeile +push_exist_repo = Push an existing repository from the command line + settings = Einstellungen settings.options = Optionen settings.collaboration = Zusammenarbeit settings.hooks = Webhooks settings.deploy_keys = Schlüssel bereitstellen settings.basic_settings = Grundeinstellungen -settings.danger_zone = Danger Zone +settings.danger_zone = Gefahrenzone settings.site = Offizielle Website settings.update_settings = Aktualisierungseinstellungen settings.transfer = Eigentum übertragen @@ -207,7 +213,7 @@ settings.delete = Dieses Repository löschen settings.delete_desc = Sobald Sie ein Repository löschen, gibt es keinen Weg zurück. Bitte seien Sie sicher. settings.update_settings_success = Repository Optionen wurde erfolgreich aktualisiert. settings.transfer_owner = Neuer Besitzer -settings.make_transfer = Make Transfer +settings.make_transfer = Übertragung erstellen settings.confirm_delete = Löschung bestätigen settings.add_collaborator = Neuer Mitarbeiter hinzufügen settings.add_collaborator_success = Neuer Mitarbeiter wurde hinzugefügt. @@ -348,7 +354,6 @@ dashboard.gc_times = GC Takt users.user_manage_panel = User Manage Panel users.new_account = Neues Konto erstellen users.name = Name -users.email = E-mail users.activated = Aktiviert users.admin = Admin users.repos = Repos From 80447f1168f06d4ffe80d9d9cb4eeb2bc1a42d66 Mon Sep 17 00:00:00 2001 From: fanningert Date: Sun, 31 Aug 2014 16:10:02 +0200 Subject: [PATCH 3/4] Update german translation with PR #404 --- conf/locale/locale_de-DE.ini | 342 +++++++++++++++++------------------ 1 file changed, 171 insertions(+), 171 deletions(-) diff --git a/conf/locale/locale_de-DE.ini b/conf/locale/locale_de-DE.ini index 9fc03ee630..07fe5f9162 100644 --- a/conf/locale/locale_de-DE.ini +++ b/conf/locale/locale_de-DE.ini @@ -1,4 +1,4 @@ -app_desc = Ein schmerzloses selbst gehostetes Git-Service welches in Go geschrieben wurde +app_desc = Ein einfacher, selbst gehostetes Git-Service, geschrieben in Go. home = Home dashboard = Dashboard @@ -12,16 +12,16 @@ register = Registrieren website = Webseite version = Version page = Seite -template = Template +template = Vorlage language = Sprache username = Benutzername -email = E-mail -password = Kennwort -re_type = neu tippen +email = E-Mail +password = Passwort +re_type = wiederholen captcha = Captcha -repository = Repositorie +repository = Repository organization = Organisation mirror = Spiegel new_repo = Neues Repository @@ -39,154 +39,154 @@ issues = Issues cancel = Abbrechen [home] -uname_holder = Benutzername oder E-mail -password_holder = Kennwort +uname_holder = Benutzername oder E-Mail +password_holder = Passwort switch_dashboard_context = Switch Dashboard Context -my_repos = Meine Repositories -collaborative_repos = Collaborative Repositories +my_repos = Meine Repositorys +collaborative_repos = Gemeinschaftliche Repositorys my_orgs = Meine Organisationen my_mirrors = Meine Spiegel [auth] create_new_account = Neues Konto erstellen -register_hepler_msg = Sie haben bereits ein Konto? Jetzt anmelden! -social_register_hepler_msg = Sie haben bereits ein Konto? Verknüpfe es jetzt! -disable_register_prompt = Es tut uns leid, die Registrierung wurde deaktiviert. Bitte wende Sie sich an den Administrator. -disable_register_mail = Es tut uns leid, die Registrierung E-Mail Bestätigung wurde deaktiviert. -remember_me = Erinnere mich -forgot_password= Kennwort vergessen -forget_password = Kennwort vergessen? -sign_up_now = Benötigen Sie ein Konto? Registrieren Sie sich jetzt. +register_hepler_msg = Du hast schon ein Konto? Jetzt anmelden! +social_register_hepler_msg = Du hast schon ein Konto? Jetzt verknüpfen! +disable_register_prompt = Es tut uns leid, die Registrierung wurde deaktiviert. Bitte wende dich an den Administrator. +disable_register_mail = Es tut uns leid, die Bestätigung der Registrierungs-E-Mail wurde deaktiviert. +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 = A new confirmation e-mail has been sent to %s, please check your inbox within the next %d hours to complete your registration. -sign_in_email = Melden Sie sich mit Ihrer E-Mailadresse an -active_your_account = Aktivieren Sie Ihr Konto +sign_in_email = Melden dich mit deiner E-Mail-Adresse an +active_your_account = Aktivieren dein Konto resent_limit_prompt = Sorry, you are sending an activation e-mail too frequently. Please wait 3 minutes. has_unconfirmed_mail = Hi %s, you have an unconfirmed email address(%s). If you haven't received a confirmation e-mail or need to resend a new one, please click on the button below. -resend_mail = Klicken Sie hier, um Ihre Aktivierungs-E-Mail erneut senden +resend_mail = Klicke hier, um deine Aktivierungs-E-Mail nochmal zu senden email_not_associate = Diese E-Mail-Adresse ist mit keinen Konto verknüpft. -send_reset_mail = Klicken Sie hier, um sich das E-Mail zum Kennwort zurücksetzen erneut zu senden -reset_password = Ihr Kennwort zurücksetzen -invalid_code = Es tut uns leid, Ihre Bestätigungscode abgelaufen ist oder nicht gültig. -reset_password_helper = Klicken Sie hier, um Ihr Kennwort zurückzusetzen -password_too_short = Passwortlänge kann nicht weniger als 6 sein. +send_reset_mail = Hier klicken, um die E-Mail zum Passwort-zurücksetzen erneut zu versenden +reset_password = Passwort zurücksetzen +invalid_code = Es tut uns leid, der Bestätigungscode ist abgelaufen oder ungültig. +reset_password_helper = Hier klicken, um das Passwort zurückzusetzen +password_too_short = Das Passwort muss mindenstens 6 Zeichen lang sein [form] UserName = Benutzername RepoName = Repository Name Email = E-Mail-Adresse -Password = Kennwort -Retype = Kennwort erneut eingeben -SSHTitle = SSH Schlüsselname -HttpsUrl = HTTPS URL +Password = Passwort +Retype = Passwort erneut eingeben +SSHTitle = SSH-Schlüsselname +HttpsUrl = HTTPS-URL PayloadUrl = Payload URL TeamName = Teamname AuthName = Authentifizierungsname require_error = ` darf nicht leer sein.` -alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.` -alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot characters.` +alpha_dash_error = ` kann ausschließlich alphanumerische Zeichen und "-_" enthalten.` +alpha_dash_dot_error = ` kann ausschließlich alphanumerische Zeichen und ".-_" enthalten.` min_size_error = ` muss mindestens %s Zeichen enthalten.` max_size_error = ` darf höchstens %s Zeichen enthalten.` email_error = ` ist keine gültige E-Mail-Adresse.` url_error = ` ist keine gültige URL.` unknown_error = Unbekannter Fehler: captcha_incorrect = Captcha stimmt nicht überein. -password_not_match = Die Kennwörter stimmen nicht überein. +password_not_match = Die Passwörter stimmen nicht überein. username_been_taken = Benutzername ist bereits vergeben. repo_name_been_taken = Repository Name ist bereits vergeben. org_name_been_taken = Organisationsname ist bereits vergeben. team_name_been_taken = Teamname ist bereits vergeben. -email_been_used = E-Mail-Adresse ist bereits vergeben. -ssh_key_been_used = Public-Key Name wird bereits verwendet. +email_been_used = E-Mail-Adresse wird bereits verwendet. +ssh_key_been_used = SSH-Schlüsselname wird bereits verwendet. illegal_username = Ihr Benutzername enthält ungültige Zeichen. -illegal_repo_name = Repository Name enthält ungültige Zeichen. +illegal_repo_name = Repository-Name enthält ungültige Zeichen. illegal_org_name = Organisationsname enthält ungültige Zeichen. illegal_team_name = Teamname enthält ungültige Zeichen. -username_password_incorrect = Benutzername oder Kennwort ist nicht korrekt. -enterred_invalid_repo_name = Bitte stellen Sie sicher, dass der eingegeben Repository Name richtig ist. -enterred_invalid_owner_name = Bitte stellen Sie sicher, dass der eingegeben Eigentümername richtig ist. +username_password_incorrect = Benutzername oder Passwort ist nicht korrekt. +enterred_invalid_repo_name = Bitte stellen Sie sicher, dass der eingegeben Repository-Name richtig ist. +enterred_invalid_owner_name = Bitte stellen Sie sicher, dass der eingegeben Besitzername richtig ist. enterred_invalid_password = Bitte stellen Sie sicher, dass das eingegebene Passwort richtig ist. user_not_exist = Angegebener Benutzer existiert nicht. -last_org_owner = The user to remove is the last member in owner team. There must be another owner. +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 auth_failed = Authentifizierung fehlgeschlagen: %v -still_own_repo = Ihr Konto ist noch immer der Eigentümer vom Repositorie, Sie müssen es zuerst löschen oder übertragen. -org_still_own_repo = Diese Organisation ist noch immer der Eigentümer vom Repositorie, Sie müssen es zuerst löschen oder übertragen. +still_own_repo = Dein Konto besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden. +org_still_own_repo = Diese Organisation besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden. -still_own_user = Diese Authentifizierung wird noch immer von einigen Benutzern verwendet, Sie sollten sie verschieben und dann erneut löschen. +still_own_user = Diese Authentifizierung wird noch von einigen Benutzern genutzt. Entferne diese zuvor und lösche erneut. [settings] profile = Profil -password = Kennwort +password = Passwort ssh_keys = SSH-Schlüssel -social = Social Konten +social = Soziale Konten orgs = Organisationen -delete = Delete Accoount +delete = Konto löschen public_profile = Öffentliches Profil profile_desc = Your Email address is public and will be used for any account related notifications, and any web based operations made via the site. full_name = Vollständiger Name -website = Website +website = Webseite location = Standort update_profile = Profil aktualisieren -update_profile_success = Ihr Profil wurde erfolgreich aktualisiert. +update_profile_success = Dein Profil wurde aktualisiert. -change_password = Kennwort ändern -old_password = Aktuelles Kennwort -new_password = Neues Kennwort -password_incorrect = Aktuelles Kennwort ist nicht korrekt. -change_password_success = Kennwort erfolgreich geändert. Sie können nun mittels des neuen Kennwortes anmelden. +change_password = Passwort ändern +old_password = Aktuelles Passwort +new_password = Neues Passwort +password_incorrect = Aktuelles Passwort ist nicht korrekt. +change_password_success = Passwort erfolgreich geändert. Du kannst dich jetzt mit dem neuen Passwort anmelden. manage_ssh_keys = SSH-Schlüssel verwalten -add_key = Schlüssel hinzufügen -ssh_desc = This is a list of SSH keys associated with your account. Remove any keys that you do not recognize. -ssh_helper = Need help? Check out our guide to generating SSH keys or troubleshoot common SSH Problems. +add_key = SSH-Schlüssel hinzufügen +ssh_desc = Dies ist eine Liste aller SSH-Schlüssel, die mit deinem Konto verküpft sind. Entferne alle Schlüssel, die du nicht kennst. +ssh_helper = Du brauchst Hilfe? Hier ist eine Anleitung zum Erzeugen von SSH-Schlüssel oder Problemlösung einfacher SSH-Probleme. add_new_key = SSH-Schlüssel hinzufügen key_name = Schlüsselname key_content = Inhalt -add_key_success = New SSH Key has been added! -delete_key = löschen +add_key_success = SSH-Schlüssel wurde hinzugefügt! +delete_key = SSH-Schlüssel löschen add_on = Hinzugefügt am last_used = Zuletzt verwendet auf no_activity = Keine neuen Aktivitäten -manage_social = Manage Associated Social Accounts -social_desc = This is a list of associated social accounts. Remove any binding that you do not recognize. +manage_social = Verküpfte soziale Konten verwalten +social_desc = Dies ist eine Liste verküpfter sozialer Konten. Entferne alle Verküpfungen, die du nicht kennst. unbind = Verknüpfung entfernen -unbind_success = Die Verknüpfung zum Social Konto wurde entfernt. +unbind_success = Die Verknüpfung zum sozialen Konto wurde entfernt. -delete_account = Löschen Sie Ihr Konto -delete_prompt = Die Operation wird Ihr Konto dauerhaft löschen und kann NICHT rückgängig gemacht werden! -confirm_delete_account = Löschung bestätigen +delete_account = Konto löschen +delete_prompt = Diese Aktion wird dein Konto dauerhaft löschen und kann NICHT rückgängig gemacht werden! +confirm_delete_account = Löschen bestätigen [repo] -owner = Eigentümer -repo_name = Repositorie Name -repo_name_helper = Tolle Repositorienamen sind kurz, einprägsam und einzigartig. +owner = Besitzer +repo_name = Repository-Name +repo_name_helper = Gute Repository-Namen sind kurz, einprägsam und einzigartig. visibility = Sichtbarkeit -visiblity_helper = Dieses Repositorie ist Privat +visiblity_helper = Dieses Repository ist Privat repo_desc = Beschreibung repo_lang = Sprache -repo_lang_helper = Wählen Sie eine .gitignore Datei +repo_lang_helper = Wähle eine .gitignore Datei license = Lizenz -license_helper = Wählen Sie eine Lizenzdatei aus -init_readme = Initialisieren dieses Repository mit einem README.md +license_helper = Wählen Sie eine Lizenz aus +init_readme = Repository mit README.md initialisieren create_repo = Repository erstellen -default_branch = Default Branch -mirror_interval = Mirror Intervall(Stunden) +default_branch = Standard-Branch +mirror_interval = Spiegel-Intervall (in Stunden) goget_meta = Go-Get Meta goget_meta_helper = This repository will be Go-Getable -need_auth = Berechtigung erforderlich +need_auth = Authorisierung benötigt migrate_type = Migrationstyp -migrate_type_helper = Dieses Repository wird ein Mirror -migrate_repo = Repositorie migrieren +migrate_type_helper = Dieses Repository wird ein Spiegel +migrate_repo = Repository migrieren -copy_link = Copy -clone_helper = Need help cloning? Visit Help! +copy_link = Klonen +clone_helper = Du brauchst Hilef beim klonen? Hier gibt esHilfe! unwatch = Beobachtung beenden watch = Beobachtung unstar = Markierung aufheben @@ -207,45 +207,45 @@ settings.basic_settings = Grundeinstellungen settings.danger_zone = Gefahrenzone settings.site = Offizielle Website settings.update_settings = Aktualisierungseinstellungen -settings.transfer = Eigentum übertragen -settings.transfer_desc = Transfer this repo to another user or to an organization where you have admin rights. -settings.delete = Dieses Repository löschen -settings.delete_desc = Sobald Sie ein Repository löschen, gibt es keinen Weg zurück. Bitte seien Sie sicher. -settings.update_settings_success = Repository Optionen wurde erfolgreich aktualisiert. +settings.transfer = Besitz übertragen +settings.transfer_desc = Übertrage dieses Repository einem anderen Benutzer oder einer Organisation. +settings.delete = Repository löschen +settings.delete_desc = Wenn dieses Repository gelöschet ist, gibt es keinen Weg zurück. Sei dir sicher! +settings.update_settings_success = Repository-Optionen wurde erfolgreich aktualisiert. settings.transfer_owner = Neuer Besitzer -settings.make_transfer = Übertragung erstellen -settings.confirm_delete = Löschung bestätigen -settings.add_collaborator = Neuer Mitarbeiter hinzufügen +settings.make_transfer = übertragen +settings.confirm_delete = Löschen bestätigen +settings.add_collaborator = Neuen Mitarbeiter hinzufügen settings.add_collaborator_success = Neuer Mitarbeiter wurde hinzugefügt. settings.remove_collaborator_success = Mitarbeiter wurde entfernt. settings.add_webhook = Webhook hinzufügen -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.hooks_desc = Webhooks erlauben es externe Dienste zu informieren, wenn etwas bestimmtes in deinem Repository passiert. GoGS sendet dann eine POST-Request an alle angegebenen URLs. Erfahre mehr in unserem Webhooks Guide. settings.remove_hook_success = Webhook wurde entfernt. -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.add_webhook_desc = GoGS sendet einen POST-Request an die unten stehende URL mit Details aller abonierten Ereignisse. Du kannst auch angeben, welches Datenformat du erhalten willst (JSON, x-www-form-urlencoded, etc). Mehr Informationen findest du im Webhooks Guide. settings.payload_url = Payload URL settings.content_type = Inhaltstyp settings.secret = Geheimnis -settings.event_desc = Durch welche Ereignisse würden Sie gerne diesen Webhook auslösen? -settings.event_push_only = Just the push event. +settings.event_desc = Welche Ereignisse sollen diesen Webhook auslösen? +settings.event_push_only = Nur das push-Ereignis. settings.active = Aktiv -settings.active_helper = We will deliver event details when this hook is triggered. +settings.active_helper = Ereignisdetails werden ausgeliefert, wenn dieser Webhook ausgelöst wird. settings.add_hook_success = Neuer Webhook wurde hinzugefügt. settings.update_webhook = Webhook aktualisieren settings.update_hook_success = Webhook wurde aktualisiert. settings.delete_webhook = Webhook löschen -settings.recent_deliveries = Jüngste Zustellungen +settings.recent_deliveries = letzte Zustellungen [org] org_name_holder = Name der Organisation -org_name_helper = Namen großer Organisationen sind kurz und einprägsam. -org_email_helper = E-Mail der Organisation empfängt alle Benachrichtigungen und Bestätigungen. +org_name_helper = Gute Namen von Organisationen sind kurz und einprägsam. +org_email_helper = Das E-Mail-Konto der Organisation empfängt alle Benachrichtigungen. create_org = Organisation erstellen repo_updated = Aktualisiert people = Personen invite_someone = Jemanden einladen teams = Teams lower_members = Mitglieder -lower_repositories = Repositories +lower_repositories = Repositorys create_new_team = Neues Team erstellen org_desc = Beschreibung team_name = Teamname @@ -260,68 +260,68 @@ settings.full_name = Vollständiger Name settings.website = Webseite settings.location = Standort settings.update_settings = Aktualisierungseinstellungen -settings.update_setting_success = Einstellung der Organisation wurde erfolgreich aktualisiert. +settings.update_setting_success = Einstellungen der Organisation wurden aktualisiert. settings.delete = Organisation löschen settings.delete_account = Diese Organisation löschen -settings.delete_prompt = Die Operation wird diese Organisation dauerhaft löschen und kann NICHT rückgängig gemacht werden! -settings.confirm_delete_account = Löschung bestätigen +settings.delete_prompt = Die Organisation wird dauerhaft gelöscht. Dies kann NICHT rückgängig gemacht werden! +settings.confirm_delete_account = Löschen bestätigen members.public = Öffentlich members.public_helper = Privat machen members.private = Privat members.private_helper = Öffentlich machen -members.owner = Eigentümer +members.owner = Besitzer members.member = Mitglied members.conceal = Verbergen members.remove = Entfernen members.leave = Verlassen -members.invite_desc = Start typing a username to invite a new member to %s: +members.invite_desc = Benutzernamen eingeben, um ihn als neues Mitglied in %s einzuladen: members.invite_now = Jetzt einladen teams.join = Beitreten teams.leave = Verlassen teams.read_access = Lesezugriff -teams.read_access_helper = This team will be able to view and clone its repositories. +teams.read_access_helper = Dieses Team wird Repositorys einsehen und klonen können. teams.write_access = Schreibzugriff -teams.write_access_helper = This team will be able to read its repositories, as well as push to them. +teams.write_access_helper = Dieses Team wird die Repositorys einsehen und in sie hinein pushen können. teams.admin_access = Adminzugriff -teams.admin_access_helper = This team will be able to push/pull to its repositories, as well as add other collaborators to them. +teams.admin_access_helper = Dieses Team wird pull- und push-Rechte für die Repositorys haben und Mitarbeiter einladen können. teams.no_desc = Dieses Team hat keine Beschreibung teams.settings = Einstellungen -teams.owners_permission_desc = Owners have full access to all repositories and have admin rights to the organization. +teams.owners_permission_desc = Besitzer haben vollen Zugriff auf alle Repositorys und Admin Rechte für diese Organisation. teams.members = Teammitglieder teams.update_settings = Einstellungen aktualisieren teams.delete_team = Dieses Team löschen teams.add_team_member = Teammitglied hinzufügen -teams.delete_team_success = Das Team wurde erfolgreich gelöscht. -teams.read_permission_desc = This team grants Read access: members can view and clone the team's repositories. -teams.write_permission_desc = This team grants Write access: members can read from and push to the team's repositories. -teams.admin_permission_desc = This team grants Admin access: members can read from, push to, and add collaborators to the team's repositories. -teams.repositories = Team Repositories -teams.add_team_repository = Teamrepositorie hinzufügen +teams.delete_team_success = Team gelöscht +teams.read_permission_desc = Dieses Team erlaubt LesezugriffSchreibzugriff: Mitglieder können Team-Repositorys einsehen und hinein pushen. +teams.admin_permission_desc = Diese Team erlaubt Adminzugriff: Mitglieder dieses Teams können pullen, pushen und dem Team Mitarbeiter hinzufügen. +teams.repositories = Team Repositorys +teams.add_team_repository = Team-Repository hinzufügen teams.remove_repo = Entfernen [admin] dashboard = Dashboard users = Benutzer organizations = Organisationen -repositories = Repositories +repositories = Repositorys authentication = Authentifizierung config = Konfiguration monitor = Monitoring -prev = Prev. -next = Next +prev = zurück +next = vor dashboard.statistic = Statistik dashboard.operations = Operationen -dashboard.system_status = System Monitor Status -dashboard.statistic_info = Gogs database has %d users, %d organizations, %d public keys, %d repositories, %d watches, %d stars, %d actions, %d accesses, %d issues, %d comments, %d social accounts, %d follows, %d mirrors, %d releases, %d login sources, %d webhooks, %d milestones, %d labels, %d hook tasks, %d teams, %d update tasks, %d attachments. +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.operation_switch = Switch -dashboard.operation_run = Run -dashboard.clean_unbind_oauth = Clean unbound OAuthes -dashboard.delete_inactivate_accounts = Alle inaktiven Konten löschen -dashboard.server_uptime = Server Uptime +dashboard.operation_run = Ausführen +dashboard.clean_unbind_oauth = ungebundene OAuthes bereinigen +dashboard.delete_inactivate_accounts = inaktiven Konten löschen +dashboard.server_uptime = Server-Uptime dashboard.current_goroutine = Aktuelle Goroutines dashboard.current_memory_usage = Aktuelle Speichernutzung dashboard.total_memory_allocated = Zugeteilter Gesamtspeicher @@ -329,29 +329,29 @@ dashboard.memory_obtained = Erhaltener Speicher 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.current_heap_usage = Aktuelle Heap-Auslastung +dashboard.heap_memory_obtained = erhaltener Heap-Memory +dashboard.heap_memory_idle = unbenutzter Heap-Memory +dashboard.heap_memory_in_use = benutzer Heap-Memory +dashboard.heap_memory_released = freigegebener Heap-Memory +dashboard.heap_objects = Heap-Objekte +dashboard.bootstrap_stack_usage = Bootstrap-Stack-Auslastung +dashboard.stack_memory_obtained = erhaltener Stack-Memory +dashboard.mspan_structures_usage = MSpan-Structures-Auslastung +dashboard.mspan_structures_obtained = erhaltene MSpan-Structures +dashboard.mcache_structures_usage = MCache-Structures-Auslastung +dashboard.mcache_structures_obtained = erhaltene MCache-Structures 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 = Next GC Recycle -dashboard.last_gc_time = Since Last GC Time -dashboard.total_gc_time = Total GC Pause -dashboard.total_gc_pause = Total GC Pause -dashboard.last_gc_pause = Last GC Pause -dashboard.gc_times = GC Takt +dashboard.gc_metadata_obtained = erhaltene GC-Metadata +dashboard.other_system_allocation_obtained = andere erhaltene Sustem-Allokatoren +dashboard.next_gc_recycle = nächster GC-Zyklus +dashboard.last_gc_time = seit leztem GC-Zyklus +dashboard.total_gc_time = gesammte GC-Zeit +dashboard.total_gc_pause = gesammte GC-Pause +dashboard.last_gc_pause = letzte GC-Pause +dashboard.gc_times = GC-Takt -users.user_manage_panel = User Manage Panel +users.user_manage_panel = Benutzerverwaltung users.new_account = Neues Konto erstellen users.name = Name users.activated = Aktiviert @@ -359,31 +359,31 @@ users.admin = Admin users.repos = Repos users.created = Erzeugt users.edit = Bearbeiten -users.auth_source = Auth Source +users.auth_source = Auth-Quelle users.local = Lokal -users.auth_login_name = Auth Login Name +users.auth_login_name = Auth-Login-Name users.update_profile_success = Kontoprofil wurde erfolgreich aktualisiert. users.edit_account = Konto bearbeiten users.is_activated = Dieses Konto ist aktiviert users.is_admin = Dieses Konto hat Administratorrechte -users.update_profile = Kontopprofil aktualisieren +users.update_profile = Kontoprofil aktualisieren users.delete_account = Dieses Konto löschen -users.still_own_repo = Dieses Konto ist noch Eigentümer von Repositories, Sie müssen zuerst diese löschen oder übertragen. +users.still_own_repo = Dieses Konto besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden. -orgs.org_manage_panel = Organization Manage Panel +orgs.org_manage_panel = Organisationenverwaltung orgs.name = Name orgs.teams = Teams orgs.members = Mitglieder -repos.repo_manage_panel = Repository Manage Panel -repos.owner = Eigentümer +repos.repo_manage_panel = Repositoryverwaltung +repos.owner = Besitzer repos.name = Name repos.private = Privat repos.watches = Watches repos.stars = Stars -repos.issues = Themen +repos.issues = Issues -auths.auth_manage_panel = Authorization Manage Panel +auths.auth_manage_panel = Authentifizierungsverwaltung auths.new = Neu Authentifizierungsquelle hinzufügen auths.name = Name auths.type = Typ @@ -408,20 +408,20 @@ auths.edit = Authentifizierungseinstellungen bearbeiten auths.activated = Diese Authentifizierung ist aktiviert auths.update_success = Authentifizierungseinstellungen wurde erfolgreich aktualisiert. auths.update = Authentifizierungseinstellungen aktualisieren -auths.delete = Diese Authentifizierung löschen +auths.delete = Authentifizierung löschen config.server_config = Server-Konfiguration config.app_name = Anwendungsname config.app_ver = Anwendungsversion -config.app_url = Anwendungs URL +config.app_url = Anwendungs-URL config.domain = Domain -config.offline_mode = Offline Mode -config.disable_router_log = Router Log deaktivieren -config.run_user = Run User -config.run_mode = Run Mode -config.repo_root_path = Repositorie Wurzelverzeichnis -config.static_file_root_path = Wurzelverzeichnis für statische Dateien -config.log_file_root_path = Wurzelverzeichnis für Log Dateien +config.offline_mode = Offline-Modus +config.disable_router_log = Router-Log deaktivieren +config.run_user = Laufzeit-Benutzer +config.run_mode = Laufzeit-Modus +config.repo_root_path = Repository-Verzeichnis +config.static_file_root_path = Verzeichnis für statische Dateien +config.log_file_root_path = Log-Verzeichnis config.script_type = Skript-Typ config.reverse_auth_user = Reverse Authentication User config.db_config = Datenbankkonfiguration @@ -429,7 +429,7 @@ config.db_type = Typ config.db_host = Host config.db_name = Name config.db_user = Benutzer -config.db_ssl_mode = SSL Modus +config.db_ssl_mode = SSL-Modus config.db_ssl_mode_helper = (nur für "postgres") config.db_path = Verzeichnis config.db_path_helper = (nur für "sqlite3") @@ -438,13 +438,13 @@ 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.mail_notify = E-Mail Benachrichtigung -config.enable_cache_avatar = Avatar Cache avtivieren +config.enable_cache_avatar = Avatar-Cache aktivieren config.active_code_lives = Active Code Lives config.reset_password_code_lives = Reset Password Code Lives config.webhook_config = Webhook Einstellungen -config.task_interval = Task Intervall +config.task_interval = Task-Intervall config.deliver_timeout = Zeitlimit für Zustellung -config.mailer_config = Mailer Einstellungen +config.mailer_config = Mailer-Einstellungen config.mailer_enabled = Aktiviert config.mailer_name = Name config.mailer_host = Host @@ -460,23 +460,23 @@ config.session_provider = Session Provider config.provider_config = Provider Einstellungen config.cookie_name = Cookie Name config.enable_set_cookie = Enable Set Cookie -config.gc_interval_time = GC Interval Time +config.gc_interval_time = GC-Intervallzeit config.session_life_time = Session Lebensdauer config.https_only = nur HTTPS config.cookie_life_time = Cookie Lebensdauer -config.session_hash_function = Session ID Hash Function -config.session_hash_key = Session ID Hash Key -config.picture_config = Bildereinstellungen -config.picture_service = Bilderservice +config.session_hash_function = Session-ID Hashfunktion +config.session_hash_key = Session-ID Hashschlüssel +config.picture_config = Bildeinstellungen +config.picture_service = Bildservice config.disable_gravatar = Gravatar deaktivieren config.log_config = Log Einstellungen config.log_mode = Log Modus -monitor.cron = Cron Tasks +monitor.cron = Cron-Tasks monitor.name = Name monitor.schedule = Zeitplan -monitor.next = Next Time -monitor.previous = Previous Time +monitor.next = nächste Ausführung +monitor.previous = letzte Ausführung monitor.execute_times = Execute Times monitor.process = Laufende Prozesse monitor.desc = Beschreibung @@ -484,7 +484,7 @@ monitor.start = Startzeit monitor.execute_time = Ausführungszeit [action] -create_repo = Repositorie erstellen %s +create_repo = Repository erstellen %s commit_repo = pushed to %s at %s create_issue = opened issue %s#%s comment_issue = commented on issue %s#%s From 2bce24068dc3c64ee5e501c48b7f080c48383970 Mon Sep 17 00:00:00 2001 From: Christopher Brickley Date: Sun, 24 Aug 2014 08:59:47 -0400 Subject: [PATCH 4/4] add Slack API webhook support --- cmd/web.go | 6 +- conf/locale/locale_en-US.ini | 5 + models/action.go | 35 ++++-- models/slack.go | 114 +++++++++++++++++++ models/webhook.go | 86 ++++++++++---- modules/auth/repo_form.go | 24 +++- public/ng/css/gogs.css | 26 ++++- public/ng/js/gogs.js | 18 ++- public/ng/less/gogs/settings.less | 16 ++- routers/repo/setting.go | 126 ++++++++++++++++++++- templates/repo/settings/gogs_hook.tmpl | 23 ++++ templates/repo/settings/hook_new.tmpl | 39 +------ templates/repo/settings/hook_settings.tmpl | 15 +++ templates/repo/settings/hook_types.tmpl | 11 ++ templates/repo/settings/slack_hook.tmpl | 20 ++++ 15 files changed, 485 insertions(+), 79 deletions(-) create mode 100644 models/slack.go create mode 100644 templates/repo/settings/gogs_hook.tmpl create mode 100644 templates/repo/settings/hook_settings.tmpl create mode 100644 templates/repo/settings/hook_types.tmpl create mode 100644 templates/repo/settings/slack_hook.tmpl diff --git a/cmd/web.go b/cmd/web.go index e0ef3a76a3..275d3fb90e 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -284,9 +284,11 @@ func runWeb(*cli.Context) { r.Route("/collaboration", "GET,POST", repo.SettingsCollaboration) r.Get("/hooks", repo.Webhooks) r.Get("/hooks/new", repo.WebHooksNew) - r.Post("/hooks/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) + r.Post("/hooks/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) + r.Post("/hooks/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) r.Get("/hooks/:id", repo.WebHooksEdit) - r.Post("/hooks/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) + r.Post("/hooks/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) + r.Post("/hooks/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) }) }, reqSignIn, middleware.RepoAssignment(true), reqTrueOwner) diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini index a99eb92e7e..946d560461 100644 --- a/conf/locale/locale_en-US.ini +++ b/conf/locale/locale_en-US.ini @@ -234,6 +234,11 @@ settings.update_webhook = Update Webhook settings.update_hook_success = Webhook has been updated. settings.delete_webhook = Delete Webhook settings.recent_deliveries = Recent Deliveries +settings.hook_type = Hook Type +settings.add_slack_hook_desc = Add Slack integration to your repository. +settings.slack_token = Token +settings.slack_domain = Domain +settings.slack_channel = Channel [org] org_name_holder = Organization Name diff --git a/models/action.go b/models/action.go index b5f692c49f..d536c84dd0 100644 --- a/models/action.go +++ b/models/action.go @@ -266,14 +266,33 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string, continue } - p.Secret = w.Secret - CreateHookTask(&HookTask{ - Type: WEBHOOK, - Url: w.Url, - Payload: p, - ContentType: w.ContentType, - IsSsl: w.IsSsl, - }) + switch w.HookTaskType { + case SLACK: + { + s, err := GetSlackPayload(p, w.Meta) + if err != nil { + return errors.New("action.GetSlackPayload: " + err.Error()) + } + CreateHookTask(&HookTask{ + Type: w.HookTaskType, + Url: w.Url, + BasePayload: s, + ContentType: w.ContentType, + IsSsl: w.IsSsl, + }) + } + default: + { + p.Secret = w.Secret + CreateHookTask(&HookTask{ + Type: w.HookTaskType, + Url: w.Url, + BasePayload: p, + ContentType: w.ContentType, + IsSsl: w.IsSsl, + }) + } + } } return nil } diff --git a/models/slack.go b/models/slack.go new file mode 100644 index 0000000000..0a55740947 --- /dev/null +++ b/models/slack.go @@ -0,0 +1,114 @@ +// 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 ( + "encoding/json" + "errors" + "fmt" + "strings" +) + +const ( + SLACK_COLOR string = "#dd4b39" +) + +type Slack struct { + Domain string `json:"domain"` + Token string `json:"token"` + Channel string `json:"channel"` +} + +type SlackPayload struct { + Channel string `json:"channel"` + Text string `json:"text"` + Username string `json:"username"` + IconUrl string `json:"icon_url"` + UnfurlLinks int `json:"unfurl_links"` + LinkNames int `json:"link_names"` + Attachments []SlackAttachment `json:"attachments"` +} + +type SlackAttachment struct { + Color string `json:"color"` + Text string `json:"text"` +} + +func GetSlackURL(domain string, token string) string { + return fmt.Sprintf( + "https://%s.slack.com/services/hooks/incoming-webhook?token=%s", + domain, + token, + ) +} + +func (p SlackPayload) GetJSONPayload() ([]byte, error) { + data, err := json.Marshal(p) + if err != nil { + return []byte{}, err + } + return data, nil +} + +func GetSlackPayload(p *Payload, meta string) (*SlackPayload, error) { + slack := &Slack{} + slackPayload := &SlackPayload{} + if err := json.Unmarshal([]byte(meta), &slack); err != nil { + return slackPayload, errors.New("GetSlackPayload meta json:" + err.Error()) + } + + // TODO: handle different payload types: push, new branch, delete branch etc. + // when they are added to gogs. Only handles push now + return getSlackPushPayload(p, slack) +} + +func getSlackPushPayload(p *Payload, slack *Slack) (*SlackPayload, error) { + // n new commits + refSplit := strings.Split(p.Ref, "/") + branchName := refSplit[len(refSplit)-1] + var commitString string + + // TODO: add commit compare before/after link when gogs adds it + if len(p.Commits) == 1 { + commitString = "1 new commit" + } else { + commitString = fmt.Sprintf("%d new commits", len(p.Commits)) + } + + text := fmt.Sprintf("[%s:%s] %s pushed by %s", p.Repo.Name, branchName, commitString, p.Pusher.Name) + var attachmentText string + + // for each commit, generate attachment text + for i, commit := range p.Commits { + attachmentText += fmt.Sprintf("<%s|%s>: %s - %s", commit.Url, commit.Id[:7], SlackFormatter(commit.Message), commit.Author.Name) + // add linebreak to each commit but the last + if i < len(p.Commits)-1 { + attachmentText += "\n" + } + } + + slackAttachments := []SlackAttachment{{Color: SLACK_COLOR, Text: attachmentText}} + + return &SlackPayload{ + Channel: slack.Channel, + Text: text, + Username: "gogs", + IconUrl: "https://raw.githubusercontent.com/gogits/gogs/master/public/img/favicon.png", + UnfurlLinks: 0, + LinkNames: 0, + Attachments: slackAttachments, + }, nil +} + +// see: https://api.slack.com/docs/formatting +func SlackFormatter(s string) string { + // take only first line of commit + first := strings.Split(s, "\n")[0] + // replace & < > + first = strings.Replace(first, "&", "&", -1) + first = strings.Replace(first, "<", "<", -1) + first = strings.Replace(first, ">", ">", -1) + return first +} diff --git a/models/webhook.go b/models/webhook.go index ced7936646..55ed4844ed 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -7,6 +7,7 @@ package models import ( "encoding/json" "errors" + "io/ioutil" "time" "github.com/gogits/gogs/modules/httplib" @@ -33,15 +34,17 @@ type HookEvent struct { // Webhook represents a web hook object. type Webhook struct { - Id int64 - RepoId int64 - Url string `xorm:"TEXT"` - ContentType HookContentType - Secret string `xorm:"TEXT"` - Events string `xorm:"TEXT"` - *HookEvent `xorm:"-"` - IsSsl bool - IsActive bool + Id int64 + RepoId int64 + Url string `xorm:"TEXT"` + ContentType HookContentType + Secret string `xorm:"TEXT"` + Events string `xorm:"TEXT"` + *HookEvent `xorm:"-"` + IsSsl bool + IsActive bool + HookTaskType HookTaskType + Meta string `xorm:"TEXT"` // store hook-specific attributes } // GetEvent handles conversion from Events to HookEvent. @@ -52,6 +55,14 @@ func (w *Webhook) GetEvent() { } } +func (w *Webhook) GetSlackHook() *Slack { + s := &Slack{} + if err := json.Unmarshal([]byte(w.Meta), s); err != nil { + log.Error(4, "webhook.GetSlackHook(%d): %v", w.Id, err) + } + return s +} + // UpdateEvent handles conversion from HookEvent to Events. func (w *Webhook) UpdateEvent() error { data, err := json.Marshal(w.HookEvent) @@ -119,8 +130,8 @@ func DeleteWebhook(hookId int64) error { type HookTaskType int const ( - WEBHOOK HookTaskType = iota + 1 - SERVICE + GOGS HookTaskType = iota + 1 + SLACK ) type HookEventType string @@ -152,6 +163,10 @@ type PayloadRepo struct { Private bool `json:"private"` } +type BasePayload interface { + GetJSONPayload() ([]byte, error) +} + // Payload represents a payload information of hook. type Payload struct { Secret string `json:"secret"` @@ -161,25 +176,33 @@ type Payload struct { Pusher *PayloadAuthor `json:"pusher"` } +func (p Payload) GetJSONPayload() ([]byte, error) { + data, err := json.Marshal(p) + if err != nil { + return []byte{}, err + } + return data, nil +} + // HookTask represents a hook task. type HookTask struct { Id int64 Uuid string Type HookTaskType Url string - *Payload `xorm:"-"` + BasePayload `xorm:"-"` PayloadContent string `xorm:"TEXT"` ContentType HookContentType EventType HookEventType IsSsl bool - IsDeliveried bool + IsDelivered bool IsSucceed bool } // CreateHookTask creates a new hook task, // it handles conversion from Payload to PayloadContent. func CreateHookTask(t *HookTask) error { - data, err := json.Marshal(t.Payload) + data, err := t.BasePayload.GetJSONPayload() if err != nil { return err } @@ -198,7 +221,7 @@ func UpdateHookTask(t *HookTask) error { // DeliverHooks checks and delivers undelivered hooks. func DeliverHooks() { timeout := time.Duration(setting.WebhookDeliverTimeout) * time.Second - x.Where("is_deliveried=?", false).Iterate(new(HookTask), + x.Where("is_delivered=?", false).Iterate(new(HookTask), func(idx int, bean interface{}) error { t := bean.(*HookTask) req := httplib.Post(t.Url).SetTimeout(timeout, timeout). @@ -212,13 +235,36 @@ func DeliverHooks() { req.Param("payload", t.PayloadContent) } - t.IsDeliveried = true + t.IsDelivered = true // TODO: record response. - if _, err := req.Response(); err != nil { - log.Error(4, "Delivery: %v", err) - } else { - t.IsSucceed = true + switch t.Type { + case GOGS: + { + if _, err := req.Response(); err != nil { + log.Error(4, "Delivery: %v", err) + } else { + t.IsSucceed = true + } + } + case SLACK: + { + if res, err := req.Response(); err != nil { + log.Error(4, "Delivery: %v", err) + } else { + defer res.Body.Close() + contents, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Error(4, "%s", err) + } else { + if string(contents) != "ok" { + log.Error(4, "slack failed with: %s", string(contents)) + } else { + t.IsSucceed = true + } + } + } + } } if err := UpdateHookTask(t); err != nil { diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 3eb0cbc564..5fd1114052 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -69,17 +69,31 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs *binding.Errors, l // \/ \/ \/ \/ \/ \/ type NewWebhookForm struct { - PayloadUrl string `form:"payload_url" binding:"Required;Url"` - ContentType string `form:"content_type" binding:"Required"` - Secret string `form:"secret"` - PushOnly bool `form:"push_only"` - Active bool `form:"active"` + HookTaskType string `form:"hook_type" binding:"Required"` + PayloadUrl string `form:"payload_url" binding:"Required;Url"` + ContentType string `form:"content_type" binding:"Required"` + Secret string `form:"secret"` + PushOnly bool `form:"push_only"` + Active bool `form:"active"` } func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { validate(errs, ctx.Data, f, l) } +type NewSlackHookForm struct { + HookTaskType string `form:"hook_type" binding:"Required"` + Domain string `form:"domain" binding:"Required` + Token string `form:"token" binding:"Required"` + Channel string `form:"channel" binding:"Required"` + PushOnly bool `form:"push_only"` + Active bool `form:"active"` +} + +func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { + validate(errs, ctx.Data, f, l) +} + // .___ // | | ______ ________ __ ____ // | |/ ___// ___/ | \_/ __ \ diff --git a/public/ng/css/gogs.css b/public/ng/css/gogs.css index d81d6f3149..0840833755 100644 --- a/public/ng/css/gogs.css +++ b/public/ng/css/gogs.css @@ -1403,14 +1403,16 @@ The register and sign-in page style #auth-setting-form, #org-setting-form, #repo-setting-form, -#user-profile-form { +#user-profile-form, +.repo-setting-form { background-color: #FFF; padding: 30px 0; } #auth-setting-form textarea, #org-setting-form textarea, #repo-setting-form textarea, -#user-profile-form textarea { +#user-profile-form textarea, +.repo-setting-form textarea { margin-left: 4px; height: 100px; } @@ -1418,24 +1420,38 @@ The register and sign-in page style #org-setting-form label, #repo-setting-form label, #user-profile-form label, +.repo-setting-form label, #auth-setting-form .form-label, #org-setting-form .form-label, #repo-setting-form .form-label, -#user-profile-form .form-label { +#user-profile-form .form-label, +.repo-setting-form .form-label { width: 240px; } #auth-setting-form .ipt, #org-setting-form .ipt, #repo-setting-form .ipt, -#user-profile-form .ipt { +#user-profile-form .ipt, +.repo-setting-form .ipt { width: 360px; } #auth-setting-form .field, #org-setting-form .field, #repo-setting-form .field, -#user-profile-form .field { +#user-profile-form .field, +.repo-setting-form .field { margin-bottom: 24px; } +#hook-type { + padding: 10px 0 0 0; + background-color: #fff; +} +#hook-type .field { + margin-bottom: 24px; +} +#hook-type label { + width: 240px; +} #repo-hooks-panel, #repo-hooks-history-panel, #user-social-panel, diff --git a/public/ng/js/gogs.js b/public/ng/js/gogs.js index bade9f3420..c08a887a4c 100644 --- a/public/ng/js/gogs.js +++ b/public/ng/js/gogs.js @@ -359,6 +359,22 @@ function initRepoSetting() { return true; } }); + + // web hook type change + $('select#hook-type').on("change", function () { + hookTypes = ['Gogs','Slack']; + + var curHook = $(this).val(); + hookTypes.forEach(function(hookType) { + if (curHook === hookType) { + $('div#'+hookType.toLowerCase()).toggleShow(); + } + else { + $('div#'+hookType.toLowerCase()).toggleHide(); + } + }); + }); + $('#transfer-button').click(function () { $('#transfer-form').show(); }); @@ -594,4 +610,4 @@ function homepage() { } $('#promo-form').attr('action', '/user/sign_up'); }); -} \ No newline at end of file +} diff --git a/public/ng/less/gogs/settings.less b/public/ng/less/gogs/settings.less index b246a947ec..80c00f2dbe 100644 --- a/public/ng/less/gogs/settings.less +++ b/public/ng/less/gogs/settings.less @@ -34,7 +34,8 @@ #auth-setting-form, #org-setting-form, #repo-setting-form, -#user-profile-form { +#user-profile-form, +.repo-setting-form { background-color: #FFF; padding: 30px 0; textarea { @@ -53,6 +54,17 @@ } } +#hook-type { + padding: 10px 0 0 0; + background-color: #fff; + .field { + margin-bottom: 24px; + } + label { + width: 240px; + } +} + #repo-hooks-panel, #repo-hooks-history-panel, #user-social-panel, @@ -109,4 +121,4 @@ .field { margin-bottom: 24px; } -} \ No newline at end of file +} diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 24c1b13a5e..fba9eed6a2 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -5,6 +5,7 @@ package repo import ( + "encoding/json" "fmt" "strings" "time" @@ -272,11 +273,17 @@ func Webhooks(ctx *middleware.Context) { ctx.HTML(200, HOOKS) } +func renderHookTypes(ctx *middleware.Context) { + ctx.Data["HookTypes"] = []string{"Gogs", "Slack"} + ctx.Data["HookType"] = "Gogs" +} + func WebHooksNew(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("repo.settings") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksNew"] = true ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} + renderHookTypes(ctx) ctx.HTML(200, HOOK_NEW) } @@ -304,8 +311,11 @@ func WebHooksNewPost(ctx *middleware.Context, form auth.NewWebhookForm) { HookEvent: &models.HookEvent{ PushOnly: form.PushOnly, }, - IsActive: form.Active, + IsActive: form.Active, + HookTaskType: models.GOGS, + Meta: "", } + if err := w.UpdateEvent(); err != nil { ctx.Handle(500, "UpdateEvent", err) return @@ -338,6 +348,19 @@ func WebHooksEdit(ctx *middleware.Context) { } return } + + // set data per HookTaskType + switch w.HookTaskType { + case models.SLACK: + { + ctx.Data["SlackHook"] = w.GetSlackHook() + ctx.Data["HookType"] = "slack" + } + default: + { + ctx.Data["HookType"] = "gogs" + } + } w.GetEvent() ctx.Data["Webhook"] = w ctx.HTML(200, HOOK_NEW) @@ -394,3 +417,104 @@ func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) { ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success")) ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", ctx.Repo.RepoLink, hookId)) } + +func SlackHooksNewPost(ctx *middleware.Context, form auth.NewSlackHookForm) { + ctx.Data["Title"] = ctx.Tr("repo.settings") + ctx.Data["PageIsSettingsHooks"] = true + ctx.Data["PageIsSettingsHooksNew"] = true + ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} + + if ctx.HasError() { + ctx.HTML(200, HOOK_NEW) + return + } + + meta, err := json.Marshal(&models.Slack{ + Domain: form.Domain, + Channel: form.Channel, + Token: form.Token, + }) + if err != nil { + ctx.Handle(500, "SlackHooksNewPost: JSON marshal failed: ", err) + return + } + + w := &models.Webhook{ + RepoId: ctx.Repo.Repository.Id, + Url: models.GetSlackURL(form.Domain, form.Token), + ContentType: models.JSON, + Secret: "", + HookEvent: &models.HookEvent{ + PushOnly: form.PushOnly, + }, + IsActive: form.Active, + HookTaskType: models.SLACK, + Meta: string(meta), + } + if err := w.UpdateEvent(); err != nil { + ctx.Handle(500, "UpdateEvent", err) + return + } else if err := models.CreateWebhook(w); err != nil { + ctx.Handle(500, "CreateWebhook", err) + return + } + + ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) + ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks") +} + +func SlackHooksEditPost(ctx *middleware.Context, form auth.NewSlackHookForm) { + ctx.Data["Title"] = ctx.Tr("repo.settings") + ctx.Data["PageIsSettingsHooks"] = true + ctx.Data["PageIsSettingsHooksEdit"] = true + + hookId := com.StrTo(ctx.Params(":id")).MustInt64() + fmt.Println("hookId slack=%d", hookId) + if hookId == 0 { + ctx.Handle(404, "setting.WebHooksEditPost", nil) + return + } + + w, err := models.GetWebhookById(hookId) + if err != nil { + if err == models.ErrWebhookNotExist { + ctx.Handle(404, "GetWebhookById", nil) + } else { + ctx.Handle(500, "GetWebhookById", err) + } + return + } + w.GetEvent() + ctx.Data["Webhook"] = w + + if ctx.HasError() { + ctx.HTML(200, HOOK_NEW) + return + } + meta, err := json.Marshal(&models.Slack{ + Domain: form.Domain, + Channel: form.Channel, + Token: form.Token, + }) + if err != nil { + ctx.Handle(500, "SlackHooksNewPost: JSON marshal failed: ", err) + return + } + + w.Url = models.GetSlackURL(form.Domain, form.Token) + w.Meta = string(meta) + w.HookEvent = &models.HookEvent{ + PushOnly: form.PushOnly, + } + w.IsActive = form.Active + if err := w.UpdateEvent(); err != nil { + ctx.Handle(500, "UpdateEvent", err) + return + } else if err := models.UpdateWebhook(w); err != nil { + ctx.Handle(500, "SlackHooksEditPost", err) + return + } + + ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success")) + ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", ctx.Repo.RepoLink, hookId)) +} diff --git a/templates/repo/settings/gogs_hook.tmpl b/templates/repo/settings/gogs_hook.tmpl new file mode 100644 index 0000000000..678d640baf --- /dev/null +++ b/templates/repo/settings/gogs_hook.tmpl @@ -0,0 +1,23 @@ +
+
+ {{.CsrfTokenHtml}} + +
{{.i18n.Tr "repo.settings.add_webhook_desc" | Str2html}}
+
+ + +
+
+ + +
+
+ + +
+ {{template "repo/settings/hook_settings" .}} +
+
diff --git a/templates/repo/settings/hook_new.tmpl b/templates/repo/settings/hook_new.tmpl index 2cd0eacb6a..7a450282b1 100644 --- a/templates/repo/settings/hook_new.tmpl +++ b/templates/repo/settings/hook_new.tmpl @@ -13,40 +13,9 @@
{{if .PageIsSettingsHooksNew}}{{.i18n.Tr "repo.settings.add_webhook"}}{{else}}{{.i18n.Tr "repo.settings.update_webhook"}}{{end}}
-
- {{.CsrfTokenHtml}} -
{{.i18n.Tr "repo.settings.add_webhook_desc" | Str2html}}
-
- - -
-
- - -
-
- - -
-
-

{{.i18n.Tr "repo.settings.event_desc"}}

- - {{.i18n.Tr "repo.settings.event_push_only" | Str2html}} -
-
- - - {{.i18n.Tr "repo.settings.active_helper"}} -
-
- - - {{if .PageIsSettingsHooksEdit}}{{.i18n.Tr "repo.settings.delete_webhook"}}{{end}} -
-
+ {{template "repo/settings/hook_types" .}} + {{template "repo/settings/gogs_hook" .}} + {{template "repo/settings/slack_hook" .}} {{if .PageIsSettingsHooksEdit}} @@ -67,4 +36,4 @@ -{{template "ng/base/footer" .}} \ No newline at end of file +{{template "ng/base/footer" .}} diff --git a/templates/repo/settings/hook_settings.tmpl b/templates/repo/settings/hook_settings.tmpl new file mode 100644 index 0000000000..7bf4e2a36c --- /dev/null +++ b/templates/repo/settings/hook_settings.tmpl @@ -0,0 +1,15 @@ +
+

{{.i18n.Tr "repo.settings.event_desc"}}

+ + {{.i18n.Tr "repo.settings.event_push_only" | Str2html}} +
+
+ + +{{.i18n.Tr "repo.settings.active_helper"}} +
+
+ + + {{if .PageIsSettingsHooksEdit}}{{.i18n.Tr "repo.settings.delete_webhook"}}{{end}} +
diff --git a/templates/repo/settings/hook_types.tmpl b/templates/repo/settings/hook_types.tmpl new file mode 100644 index 0000000000..782e2a4e73 --- /dev/null +++ b/templates/repo/settings/hook_types.tmpl @@ -0,0 +1,11 @@ +{{if .PageIsSettingsHooksNew}} +
+ + +
+{{end}} diff --git a/templates/repo/settings/slack_hook.tmpl b/templates/repo/settings/slack_hook.tmpl new file mode 100644 index 0000000000..e68571a081 --- /dev/null +++ b/templates/repo/settings/slack_hook.tmpl @@ -0,0 +1,20 @@ +
+
+ {{.CsrfTokenHtml}} + +
{{.i18n.Tr "repo.settings.add_slack_hook_desc" | Str2html}}
+
+ + +
+
+ + +
+
+ + +
+ {{template "repo/settings/hook_settings" .}} +
+