Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorVinnie Okada <vokada@mrvinn.com>2014-12-08 06:25:58 +0300
committerVinnie Okada <vokada@mrvinn.com>2014-12-08 06:25:58 +0300
commit742e6eeed221489d5f35bdfde2e6ce55db75d25f (patch)
tree710c01fbd18e81a7590819161434e19855e35a97 /app
parent7a5072c5a8f03cd7342a5f8e74e1fde0250ce360 (diff)
parentbbf9953b99d59801c72dd7b9550ee149ca77bfcf (diff)
Merge branch 'upstream-master' into markdown-preview
Conflicts: spec/routing/project_routing_spec.rb
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/activities.js.coffee4
-rw-r--r--app/assets/javascripts/admin.js.coffee4
-rw-r--r--app/assets/javascripts/application.js.coffee3
-rw-r--r--app/assets/javascripts/blob.js.coffee5
-rw-r--r--app/assets/javascripts/commit.js.coffee4
-rw-r--r--app/assets/javascripts/commit/file.js.coffee4
-rw-r--r--app/assets/javascripts/commit/image-file.js.coffee4
-rw-r--r--app/assets/javascripts/commits.js.coffee4
-rw-r--r--app/assets/javascripts/confirm_danger_modal.js.coffee4
-rw-r--r--app/assets/javascripts/dashboard.js.coffee5
-rw-r--r--app/assets/javascripts/diff.js.coffee5
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee35
-rw-r--r--app/assets/javascripts/flash.js.coffee4
-rw-r--r--app/assets/javascripts/group_avatar.js.coffee9
-rw-r--r--app/assets/javascripts/groups.js.coffee15
-rw-r--r--app/assets/javascripts/issue.js.coffee4
-rw-r--r--app/assets/javascripts/labels.js.coffee4
-rw-r--r--app/assets/javascripts/merge_request.js.coffee4
-rw-r--r--app/assets/javascripts/milestone.js.coffee4
-rw-r--r--app/assets/javascripts/namespace_select.js.coffee43
-rw-r--r--app/assets/javascripts/notes.js.coffee6
-rw-r--r--app/assets/javascripts/notes_votes.js.coffee4
-rw-r--r--app/assets/javascripts/password_strength.js.coffee31
-rw-r--r--app/assets/javascripts/profile.js.coffee45
-rw-r--r--app/assets/javascripts/project.js.coffee80
-rw-r--r--app/assets/javascripts/project_fork.js.coffee5
-rw-r--r--app/assets/javascripts/project_import.js.coffee4
-rw-r--r--app/assets/javascripts/project_new.js.coffee25
-rw-r--r--app/assets/javascripts/project_show.js.coffee15
-rw-r--r--app/assets/javascripts/project_users_select.js.coffee19
-rw-r--r--app/assets/javascripts/search_autocomplete.js.coffee4
-rw-r--r--app/assets/javascripts/stat_graph.js.coffee2
-rw-r--r--app/assets/javascripts/stat_graph_contributors.js.coffee2
-rw-r--r--app/assets/javascripts/stat_graph_contributors_graph.js.coffee6
-rw-r--r--app/assets/javascripts/team_members.js.coffee6
-rw-r--r--app/assets/javascripts/tree.js.coffee4
-rw-r--r--app/assets/javascripts/user.js.coffee3
-rw-r--r--app/assets/javascripts/users_select.js.coffee53
-rw-r--r--app/assets/javascripts/wikis.js.coffee5
-rw-r--r--app/assets/stylesheets/behaviors.scss26
-rw-r--r--app/assets/stylesheets/generic/common.scss4
-rw-r--r--app/assets/stylesheets/generic/files.scss3
-rw-r--r--app/assets/stylesheets/generic/highlight.scss4
-rw-r--r--app/assets/stylesheets/generic/issue_box.scss5
-rw-r--r--app/assets/stylesheets/generic/mobile.scss17
-rw-r--r--app/assets/stylesheets/generic/timeline.scss17
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss31
-rw-r--r--app/assets/stylesheets/highlight/white.scss8
-rw-r--r--app/assets/stylesheets/main/fonts.scss2
-rw-r--r--app/assets/stylesheets/main/mixins.scss6
-rw-r--r--app/assets/stylesheets/sections/events.scss31
-rw-r--r--app/assets/stylesheets/sections/header.scss1
-rw-r--r--app/assets/stylesheets/sections/issues.scss12
-rw-r--r--app/assets/stylesheets/sections/merge_requests.scss6
-rw-r--r--app/assets/stylesheets/sections/nav.scss2
-rw-r--r--app/assets/stylesheets/sections/notes.scss7
-rw-r--r--app/assets/stylesheets/sections/profile.scss17
-rw-r--r--app/assets/stylesheets/sections/projects.scss38
-rw-r--r--app/controllers/admin/background_jobs_controller.rb2
-rw-r--r--app/controllers/admin/projects_controller.rb10
-rw-r--r--app/controllers/application_controller.rb60
-rw-r--r--app/controllers/explore/groups_controller.rb3
-rw-r--r--app/controllers/explore/projects_controller.rb3
-rw-r--r--app/controllers/groups/group_members_controller.rb1
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb27
-rw-r--r--app/controllers/projects/application_controller.rb27
-rw-r--r--app/controllers/projects/base_tree_controller.rb3
-rw-r--r--app/controllers/projects/blame_controller.rb3
-rw-r--r--app/controllers/projects/blob_controller.rb7
-rw-r--r--app/controllers/projects/branches_controller.rb11
-rw-r--r--app/controllers/projects/commit_controller.rb15
-rw-r--r--app/controllers/projects/commits_controller.rb3
-rw-r--r--app/controllers/projects/compare_controller.rb3
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb2
-rw-r--r--app/controllers/projects/edit_tree_controller.rb4
-rw-r--r--app/controllers/projects/forks_controller.rb22
-rw-r--r--app/controllers/projects/graphs_controller.rb3
-rw-r--r--app/controllers/projects/hooks_controller.rb1
-rw-r--r--app/controllers/projects/imports_controller.rb49
-rw-r--r--app/controllers/projects/issues_controller.rb16
-rw-r--r--app/controllers/projects/merge_requests_controller.rb15
-rw-r--r--app/controllers/projects/milestones_controller.rb4
-rw-r--r--app/controllers/projects/network_controller.rb3
-rw-r--r--app/controllers/projects/new_tree_controller.rb2
-rw-r--r--app/controllers/projects/raw_controller.rb3
-rw-r--r--app/controllers/projects/refs_controller.rb3
-rw-r--r--app/controllers/projects/repositories_controller.rb12
-rw-r--r--app/controllers/projects/services_controller.rb3
-rw-r--r--app/controllers/projects/tags_controller.rb6
-rw-r--r--app/controllers/projects/team_members_controller.rb8
-rw-r--r--app/controllers/projects_controller.rb76
-rw-r--r--app/controllers/snippets_controller.rb2
-rw-r--r--app/controllers/users_controller.rb7
-rw-r--r--app/finders/issuable_finder.rb15
-rw-r--r--app/finders/snippets_finder.rb2
-rw-r--r--app/helpers/blob_helper.rb11
-rw-r--r--app/helpers/commits_helper.rb8
-rw-r--r--app/helpers/emails_helper.rb32
-rw-r--r--app/helpers/events_helper.rb22
-rw-r--r--app/helpers/git_helper.rb5
-rw-r--r--app/helpers/gitlab_markdown_helper.rb12
-rw-r--r--app/helpers/issues_helper.rb28
-rw-r--r--app/helpers/namespaces_helper.rb8
-rw-r--r--app/helpers/oauth_helper.rb4
-rw-r--r--app/helpers/profile_helper.rb6
-rw-r--r--app/helpers/projects_helper.rb4
-rw-r--r--app/helpers/sorting_helper.rb17
-rw-r--r--app/helpers/tree_helper.rb2
-rw-r--r--app/mailers/emails/profile.rb3
-rw-r--r--app/mailers/notify.rb9
-rw-r--r--app/models/ability.rb8
-rw-r--r--app/models/concerns/issuable.rb3
-rw-r--r--app/models/concerns/mentionable.rb6
-rw-r--r--app/models/event.rb4
-rw-r--r--app/models/hooks/web_hook.rb8
-rw-r--r--app/models/identity.rb5
-rw-r--r--app/models/merge_request.rb14
-rw-r--r--app/models/namespace.rb4
-rw-r--r--app/models/note.rb51
-rw-r--r--app/models/project.rb77
-rw-r--r--app/models/project_services/bamboo_service.rb105
-rw-r--r--app/models/project_services/buildbox_service.rb2
-rw-r--r--app/models/project_services/flowdock_service.rb3
-rw-r--r--app/models/project_services/gemnasium_service.rb3
-rw-r--r--app/models/project_services/gitlab_ci_service.rb4
-rw-r--r--app/models/project_services/hipchat_service.rb12
-rw-r--r--app/models/project_services/slack_service.rb13
-rw-r--r--app/models/service.rb4
-rw-r--r--app/models/user.rb40
-rw-r--r--app/services/base_service.rb6
-rw-r--r--app/services/files/base_service.rb6
-rw-r--r--app/services/git_push_service.rb24
-rw-r--r--app/services/issues/base_service.rb2
-rw-r--r--app/services/merge_requests/base_merge_service.rb3
-rw-r--r--app/services/merge_requests/base_service.rb3
-rw-r--r--app/services/merge_requests/refresh_service.rb86
-rw-r--r--app/services/notification_service.rb5
-rw-r--r--app/services/projects/create_service.rb50
-rw-r--r--app/services/projects/fork_service.rb24
-rw-r--r--app/services/system_hooks_service.rb2
-rw-r--r--app/services/test_hook_service.rb3
-rw-r--r--app/views/admin/background_jobs/show.html.haml4
-rw-r--r--app/views/admin/groups/_form.html.haml25
-rw-r--r--app/views/admin/groups/index.html.haml2
-rw-r--r--app/views/admin/groups/show.html.haml6
-rw-r--r--app/views/admin/logs/show.html.haml87
-rw-r--r--app/views/admin/projects/index.html.haml10
-rw-r--r--app/views/admin/users/index.html.haml5
-rw-r--r--app/views/admin/users/show.html.haml2
-rw-r--r--app/views/dashboard/_zero_authorized_projects.html.haml2
-rw-r--r--app/views/dashboard/issues.atom.builder21
-rw-r--r--app/views/dashboard/projects.html.haml9
-rw-r--r--app/views/dashboard/show.atom.builder25
-rw-r--r--app/views/devise/passwords/edit.html.haml4
-rw-r--r--app/views/devise/registrations/new.html.haml4
-rw-r--r--app/views/devise/sessions/_new_ldap.html.haml2
-rw-r--r--app/views/devise/sessions/_oauth_providers.html.haml2
-rw-r--r--app/views/devise/sessions/new.html.haml20
-rw-r--r--app/views/explore/groups/index.html.haml10
-rw-r--r--app/views/explore/projects/index.html.haml10
-rw-r--r--app/views/groups/edit.html.haml19
-rw-r--r--app/views/groups/issues.atom.builder13
-rw-r--r--app/views/groups/members.html.haml2
-rw-r--r--app/views/groups/new.html.haml25
-rw-r--r--app/views/groups/show.atom.builder24
-rw-r--r--app/views/layouts/_search.html.haml13
-rw-r--r--app/views/layouts/notify.html.haml1
-rw-r--r--app/views/notify/new_ssh_key_email.html.haml2
-rw-r--r--app/views/notify/new_ssh_key_email.text.erb4
-rw-r--r--app/views/profiles/passwords/edit.html.haml2
-rw-r--r--app/views/profiles/passwords/new.html.haml2
-rw-r--r--app/views/profiles/show.html.haml2
-rw-r--r--app/views/projects/_home_panel.html.haml6
-rw-r--r--app/views/projects/_issuable_filter.html.haml72
-rw-r--r--app/views/projects/_issuable_form.html.haml4
-rw-r--r--app/views/projects/_issues_nav.html.haml55
-rw-r--r--app/views/projects/blob/_actions.html.haml3
-rw-r--r--app/views/projects/blob/_remove.html.haml2
-rw-r--r--app/views/projects/branches/index.html.haml4
-rw-r--r--app/views/projects/branches/new.html.haml2
-rw-r--r--app/views/projects/compare/_form.html.haml2
-rw-r--r--app/views/projects/create.js.haml13
-rw-r--r--app/views/projects/diffs/_file.html.haml5
-rw-r--r--app/views/projects/edit.html.haml8
-rw-r--r--app/views/projects/fork.html.haml19
-rw-r--r--app/views/projects/forks/error.html.haml20
-rw-r--r--app/views/projects/forks/new.html.haml38
-rw-r--r--app/views/projects/import.html.haml31
-rw-r--r--app/views/projects/imports/new.html.haml21
-rw-r--r--app/views/projects/imports/show.html.haml9
-rw-r--r--app/views/projects/issues/_head.html.haml36
-rw-r--r--app/views/projects/issues/_issue.html.haml6
-rw-r--r--app/views/projects/issues/_issue_context.html.haml3
-rw-r--r--app/views/projects/issues/_issues.html.haml50
-rw-r--r--app/views/projects/issues/index.atom.builder13
-rw-r--r--app/views/projects/issues/index.html.haml2
-rw-r--r--app/views/projects/issues/show.html.haml6
-rw-r--r--app/views/projects/labels/index.html.haml2
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml6
-rw-r--r--app/views/projects/merge_requests/index.html.haml63
-rw-r--r--app/views/projects/merge_requests/show/_how_to_merge.html.haml6
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml4
-rw-r--r--app/views/projects/merge_requests/show/_state_widget.html.haml13
-rw-r--r--app/views/projects/milestones/index.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml2
-rw-r--r--app/views/projects/new.html.haml2
-rw-r--r--app/views/projects/new_tree/show.html.haml4
-rw-r--r--app/views/projects/no_repo.html.haml22
-rw-r--r--app/views/projects/notes/_form.html.haml2
-rw-r--r--app/views/projects/notes/_note.html.haml4
-rw-r--r--app/views/projects/services/_form.html.haml4
-rw-r--r--app/views/projects/tags/_tag.html.haml3
-rw-r--r--app/views/projects/tags/new.html.haml2
-rw-r--r--app/views/projects/team_members/_team_member.html.haml2
-rw-r--r--app/views/projects/team_members/import.html.haml2
-rw-r--r--app/views/search/_project_filter.html.haml1
-rw-r--r--app/views/search/show.html.haml2
-rw-r--r--app/views/shared/_choose_group_avatar_button.html.haml7
-rw-r--r--app/views/shared/_group_form.html.haml12
-rw-r--r--app/views/shared/_group_tips.html.haml6
-rw-r--r--app/views/shared/_promo.html.haml2
-rw-r--r--app/views/shared/_sort_dropdown.html.haml8
-rw-r--r--app/views/users/_groups.html.haml2
-rw-r--r--app/views/users/show.atom.builder12
-rw-r--r--app/views/users/show.html.haml10
-rw-r--r--app/workers/emails_on_push_worker.rb3
-rw-r--r--app/workers/project_service_worker.rb9
227 files changed, 1753 insertions, 1166 deletions
diff --git a/app/assets/javascripts/activities.js.coffee b/app/assets/javascripts/activities.js.coffee
index fdefbfb92bd..4f76d8ce486 100644
--- a/app/assets/javascripts/activities.js.coffee
+++ b/app/assets/javascripts/activities.js.coffee
@@ -1,4 +1,4 @@
-class Activities
+class @Activities
constructor: ->
Pager.init 20, true
$(".event_filter_link").bind "click", (event) =>
@@ -27,5 +27,3 @@ class Activities
event_filters.splice index, 1
$.cookie "event_filter", event_filters.join(","), { path: '/' }
-
-@Activities = Activities
diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee
index a333eed87f2..bcb2e6df7c0 100644
--- a/app/assets/javascripts/admin.js.coffee
+++ b/app/assets/javascripts/admin.js.coffee
@@ -1,4 +1,4 @@
-class Admin
+class @Admin
constructor: ->
$('input#user_force_random_password').on 'change', (elem) ->
elems = $('#user_password, #user_password_confirmation')
@@ -51,5 +51,3 @@ class Admin
$('li.group_member').bind 'ajax:success', ->
Turbolinks.visit(location.href)
-
-@Admin = Admin
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index ff0d0bb32b9..e9a28c12159 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -18,6 +18,7 @@
#= require jquery.turbolinks
#= require turbolinks
#= require bootstrap
+#= require password_strength
#= require select2
#= require raphael
#= require g.raphael-min
@@ -63,7 +64,7 @@ window.extractLast = (term) ->
return split( term ).pop()
window.rstrip = (val) ->
- return val.replace(/\s+$/, '')
+ return if val then val.replace(/\s+$/, '') else val
# Disable button if text field is empty
window.disableButtonIfEmptyField = (field_selector, button_selector) ->
diff --git a/app/assets/javascripts/blob.js.coffee b/app/assets/javascripts/blob.js.coffee
index 9db919e5a62..a5f15f80c5c 100644
--- a/app/assets/javascripts/blob.js.coffee
+++ b/app/assets/javascripts/blob.js.coffee
@@ -1,4 +1,4 @@
-class BlobView
+class @BlobView
constructor: ->
# handle multi-line select
handleMultiSelect = (e) ->
@@ -71,6 +71,3 @@ class BlobView
# Highlight the correct lines when the hash part of the URL changes
$(window).on("hashchange", highlightBlobLines)
-
-
-@BlobView = BlobView
diff --git a/app/assets/javascripts/commit.js.coffee b/app/assets/javascripts/commit.js.coffee
index 5f53439ca4b..0566e239191 100644
--- a/app/assets/javascripts/commit.js.coffee
+++ b/app/assets/javascripts/commit.js.coffee
@@ -1,6 +1,4 @@
-class Commit
+class @Commit
constructor: ->
$('.files .diff-file').each ->
new CommitFile(this)
-
-@Commit = Commit
diff --git a/app/assets/javascripts/commit/file.js.coffee b/app/assets/javascripts/commit/file.js.coffee
index 4db9116a9de..83e793863b6 100644
--- a/app/assets/javascripts/commit/file.js.coffee
+++ b/app/assets/javascripts/commit/file.js.coffee
@@ -1,7 +1,5 @@
-class CommitFile
+class @CommitFile
constructor: (file) ->
if $('.image', file).length
new ImageFile(file)
-
-@CommitFile = CommitFile
diff --git a/app/assets/javascripts/commit/image-file.js.coffee b/app/assets/javascripts/commit/image-file.js.coffee
index 607b85eb45c..9e5f49b1f69 100644
--- a/app/assets/javascripts/commit/image-file.js.coffee
+++ b/app/assets/javascripts/commit/image-file.js.coffee
@@ -1,4 +1,4 @@
-class ImageFile
+class @ImageFile
# Width where images must fits in, for 2-up this gets divided by 2
@availWidth = 900
@@ -124,5 +124,3 @@ class ImageFile
else
img.on 'load', =>
callback.call(this, domImg.naturalWidth, domImg.naturalHeight)
-
-@ImageFile = ImageFile
diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee
index 784d7d20bb1..c183e78e513 100644
--- a/app/assets/javascripts/commits.js.coffee
+++ b/app/assets/javascripts/commits.js.coffee
@@ -1,4 +1,4 @@
-class CommitsList
+class @CommitsList
@data =
ref: null
limit: 0
@@ -53,5 +53,3 @@ class CommitsList
@disable
callback: =>
this.getOld()
-
-this.CommitsList = CommitsList
diff --git a/app/assets/javascripts/confirm_danger_modal.js.coffee b/app/assets/javascripts/confirm_danger_modal.js.coffee
index 1687b7d961c..bb99edbd09e 100644
--- a/app/assets/javascripts/confirm_danger_modal.js.coffee
+++ b/app/assets/javascripts/confirm_danger_modal.js.coffee
@@ -1,4 +1,4 @@
-class ConfirmDangerModal
+class @ConfirmDangerModal
constructor: (form, text) ->
@form = form
$('.js-confirm-text').text(text || '')
@@ -16,5 +16,3 @@ class ConfirmDangerModal
$('.js-confirm-danger-submit').on 'click', =>
@form.submit()
-
-@ConfirmDangerModal = ConfirmDangerModal
diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee
index c4a0ccd9c2a..6ef5a539b8f 100644
--- a/app/assets/javascripts/dashboard.js.coffee
+++ b/app/assets/javascripts/dashboard.js.coffee
@@ -1,4 +1,4 @@
-class Dashboard
+class @Dashboard
constructor: ->
@initSidebarTab()
@@ -28,6 +28,3 @@ class Dashboard
# show tab from cookie
sidebar_filter = $.cookie(key)
$("#" + sidebar_filter).tab('show') if sidebar_filter
-
-
-@Dashboard = Dashboard
diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee
index dbe00c487dc..52b4208524f 100644
--- a/app/assets/javascripts/diff.js.coffee
+++ b/app/assets/javascripts/diff.js.coffee
@@ -1,4 +1,4 @@
-class Diff
+class @Diff
UNFOLD_COUNT = 20
constructor: ->
$(document).on('click', '.js-unfold', (event) =>
@@ -41,6 +41,3 @@ class Diff
lines = line.children().slice(0, 2)
line_numbers = ($(l).attr('data-linenumber') for l in lines)
(parseInt(line_number) for line_number in line_numbers)
-
-
-@Diff = Diff
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 00b52758fa8..e8b71a71945 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -58,15 +58,11 @@ class Dispatcher
when 'groups:show', 'projects:show'
new Activities()
shortcut_handler = new ShortcutsNavigation()
- when 'projects:new'
- new Project()
- when 'projects:edit'
- new Project()
- shortcut_handler = new ShortcutsNavigation()
- when 'projects:teams:members:index'
- new TeamMembers()
when 'groups:members'
new GroupMembers()
+ new UsersSelect()
+ when 'groups:new', 'groups:edit', 'admin:groups:edit'
+ new GroupAvatar()
when 'projects:tree:show'
new TreeView()
shortcut_handler = new ShortcutsNavigation()
@@ -79,13 +75,35 @@ class Dispatcher
# Ensure we don't create a particular shortcut handler here. This is
# already created, where the network graph is created.
shortcut_handler = true
+ when 'projects:forks:new'
+ new ProjectFork()
+ when 'users:show'
+ new User()
switch path.first()
- when 'admin' then new Admin()
+ when 'admin'
+ new Admin()
+ switch path[1]
+ when 'groups'
+ new UsersSelect()
+ when 'projects'
+ new NamespaceSelect()
when 'dashboard'
shortcut_handler = new ShortcutsDashboardNavigation()
+ when 'profiles'
+ new Profile()
when 'projects'
+ new Project()
switch path[1]
+ when 'edit'
+ shortcut_handler = new ShortcutsNavigation()
+ new ProjectNew()
+ when 'new'
+ new ProjectNew()
+ when 'show'
+ new ProjectShow()
+ when 'issues', 'merge_requests'
+ new ProjectUsersSelect()
when 'wikis'
new Wikis()
shortcut_handler = new ShortcutsNavigation()
@@ -94,6 +112,7 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation()
when 'team_members', 'deploy_keys', 'hooks', 'services', 'protected_branches'
shortcut_handler = new ShortcutsNavigation()
+ new UsersSelect()
# If we haven't installed a custom shortcut handler, install the default one
diff --git a/app/assets/javascripts/flash.js.coffee b/app/assets/javascripts/flash.js.coffee
index cf1a37eae3e..b39ab0c4475 100644
--- a/app/assets/javascripts/flash.js.coffee
+++ b/app/assets/javascripts/flash.js.coffee
@@ -1,4 +1,4 @@
-class Flash
+class @Flash
constructor: (message, type)->
flash = $(".flash-container")
flash.html("")
@@ -10,5 +10,3 @@ class Flash
flash.click -> $(@).fadeOut()
flash.show()
-
-@Flash = Flash
diff --git a/app/assets/javascripts/group_avatar.js.coffee b/app/assets/javascripts/group_avatar.js.coffee
new file mode 100644
index 00000000000..0825fd3ce52
--- /dev/null
+++ b/app/assets/javascripts/group_avatar.js.coffee
@@ -0,0 +1,9 @@
+class @GroupAvatar
+ constructor: ->
+ $('.js-choose-group-avatar-button').bind "click", ->
+ form = $(this).closest("form")
+ form.find(".js-group-avatar-input").click()
+ $('.js-group-avatar-input').bind "change", ->
+ form = $(this).closest("form")
+ filename = $(this).val().replace(/^.*[\\\/]/, '')
+ form.find(".js-avatar-filename").text(filename)
diff --git a/app/assets/javascripts/groups.js.coffee b/app/assets/javascripts/groups.js.coffee
index 4b1000f9a6a..cc905e91ea2 100644
--- a/app/assets/javascripts/groups.js.coffee
+++ b/app/assets/javascripts/groups.js.coffee
@@ -1,17 +1,4 @@
-class GroupMembers
+class @GroupMembers
constructor: ->
$('li.group_member').bind 'ajax:success', ->
$(this).fadeOut()
-
-@GroupMembers = GroupMembers
-
-$ ->
- # avatar
- $('.js-choose-group-avatar-button').bind "click", ->
- form = $(this).closest("form")
- form.find(".js-group-avatar-input").click()
-
- $('.js-group-avatar-input').bind "change", ->
- form = $(this).closest("form")
- filename = $(this).val().replace(/^.*[\\\/]/, '')
- form.find(".js-avatar-filename").text(filename)
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
index 0e2a2fa792a..597b4695a6d 100644
--- a/app/assets/javascripts/issue.js.coffee
+++ b/app/assets/javascripts/issue.js.coffee
@@ -1,4 +1,4 @@
-class Issue
+class @Issue
constructor: ->
$('.edit-issue.inline-update input[type="submit"]').hide()
$(".issue-box .inline-update").on "change", "select", ->
@@ -15,5 +15,3 @@ class Issue
"issue"
updateTaskState
)
-
-@Issue = Issue
diff --git a/app/assets/javascripts/labels.js.coffee b/app/assets/javascripts/labels.js.coffee
index d306ad64f5b..1bc8840f9ac 100644
--- a/app/assets/javascripts/labels.js.coffee
+++ b/app/assets/javascripts/labels.js.coffee
@@ -1,4 +1,4 @@
-class Labels
+class @Labels
constructor: ->
form = $('.label-form')
@setupLabelForm(form)
@@ -31,5 +31,3 @@ class Labels
# Notify the form, that color has changed
$('.label-form').trigger('keyup')
e.preventDefault()
-
-@Labels = Labels
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index 9f99ff403f8..46e06424e5a 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -1,4 +1,4 @@
-class MergeRequest
+class @MergeRequest
constructor: (@opts) ->
@initContextWidget()
this.$el = $('.merge-request')
@@ -132,5 +132,3 @@ class MergeRequest
this.$('.automerge_widget').hide()
this.$('.merge-in-progress').hide()
this.$('.automerge_widget.already_cannot_be_merged').show()
-
-this.MergeRequest = MergeRequest
diff --git a/app/assets/javascripts/milestone.js.coffee b/app/assets/javascripts/milestone.js.coffee
index ea01c318d4f..c42f31933d3 100644
--- a/app/assets/javascripts/milestone.js.coffee
+++ b/app/assets/javascripts/milestone.js.coffee
@@ -1,4 +1,4 @@
-class Milestone
+class @Milestone
@updateIssue: (li, issue_url, data) ->
$.ajax
type: "PUT"
@@ -115,5 +115,3 @@ class Milestone
Milestone.updateMergeRequest(ui.item, merge_request_url, data)
).disableSelection()
-
-@Milestone = Milestone
diff --git a/app/assets/javascripts/namespace_select.js.coffee b/app/assets/javascripts/namespace_select.js.coffee
index 00d135d1449..a02c4515ccc 100644
--- a/app/assets/javascripts/namespace_select.js.coffee
+++ b/app/assets/javascripts/namespace_select.js.coffee
@@ -1,24 +1,25 @@
-$ ->
- namespaceFormatResult = (namespace) ->
- markup = "<div class='namespace-result'>"
- markup += "<span class='namespace-kind'>" + namespace.kind + "</span>"
- markup += "<span class='namespace-path'>" + namespace.path + "</span>"
- markup += "</div>"
- markup
+class @NamespaceSelect
+ constructor: ->
+ namespaceFormatResult = (namespace) ->
+ markup = "<div class='namespace-result'>"
+ markup += "<span class='namespace-kind'>" + namespace.kind + "</span>"
+ markup += "<span class='namespace-path'>" + namespace.path + "</span>"
+ markup += "</div>"
+ markup
- formatSelection = (namespace) ->
- namespace.kind + ": " + namespace.path
+ formatSelection = (namespace) ->
+ namespace.kind + ": " + namespace.path
- $('.ajax-namespace-select').each (i, select) ->
- $(select).select2
- placeholder: "Search for namespace"
- multiple: $(select).hasClass('multiselect')
- minimumInputLength: 0
- query: (query) ->
- Api.namespaces query.term, (namespaces) ->
- data = { results: namespaces }
- query.callback(data)
+ $('.ajax-namespace-select').each (i, select) ->
+ $(select).select2
+ placeholder: "Search for namespace"
+ multiple: $(select).hasClass('multiselect')
+ minimumInputLength: 0
+ query: (query) ->
+ Api.namespaces query.term, (namespaces) ->
+ data = { results: namespaces }
+ query.callback(data)
- dropdownCssClass: "ajax-namespace-dropdown"
- formatResult: namespaceFormatResult
- formatSelection: formatSelection
+ dropdownCssClass: "ajax-namespace-dropdown"
+ formatResult: namespaceFormatResult
+ formatSelection: formatSelection
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index b6bb0c42ad4..30f8530dfda 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -1,4 +1,4 @@
-class Notes
+class @Notes
@interval: null
constructor: (notes_url, note_ids, last_fetched_at) ->
@@ -465,7 +465,3 @@ class Notes
else
form.find('.js-note-target-reopen').text('Reopen')
form.find('.js-note-target-close').text('Close')
-
-
-
-@Notes = Notes
diff --git a/app/assets/javascripts/notes_votes.js.coffee b/app/assets/javascripts/notes_votes.js.coffee
index b31eb9ac9de..65c149b7886 100644
--- a/app/assets/javascripts/notes_votes.js.coffee
+++ b/app/assets/javascripts/notes_votes.js.coffee
@@ -1,4 +1,4 @@
-class NotesVotes
+class @NotesVotes
updateVotes: ->
votes = $("#votes .votes")
notes = $("#notes-list .note .vote")
@@ -18,5 +18,3 @@ class NotesVotes
# replace vote numbers
votes.find(".upvotes").text votes.find(".upvotes").text().replace(/\d+/, upvotes)
votes.find(".downvotes").text votes.find(".downvotes").text().replace(/\d+/, downvotes)
-
-@NotesVotes = NotesVotes
diff --git a/app/assets/javascripts/password_strength.js.coffee b/app/assets/javascripts/password_strength.js.coffee
new file mode 100644
index 00000000000..825f5630266
--- /dev/null
+++ b/app/assets/javascripts/password_strength.js.coffee
@@ -0,0 +1,31 @@
+#= require pwstrength-bootstrap-1.2.2
+overwritten_messages =
+ wordSimilarToUsername: "Your password should not contain your username"
+
+overwritten_rules =
+ wordSequences: false
+
+options =
+ showProgressBar: false
+ showVerdicts: false
+ showPopover: true
+ showErrors: true
+ showStatus: true
+ errorMessages: overwritten_messages
+
+$(document).ready ->
+ profileOptions = {}
+ profileOptions.ui = options
+ profileOptions.rules =
+ activated: overwritten_rules
+
+ deviseOptions = {}
+ deviseOptions.common =
+ usernameField: "#user_username"
+ deviseOptions.ui = options
+ deviseOptions.rules =
+ activated: overwritten_rules
+
+ $("#user_password_profile").pwstrength profileOptions
+ $("#user_password_sign_up").pwstrength deviseOptions
+ $("#user_password_recover").pwstrength deviseOptions
diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee
index 0e99921f899..de356fbec77 100644
--- a/app/assets/javascripts/profile.js.coffee
+++ b/app/assets/javascripts/profile.js.coffee
@@ -1,30 +1,29 @@
-$ ->
- $('.edit_user .application-theme input, .edit_user .code-preview-theme input').click ->
- # Submit the form
- $('.edit_user').submit()
+class @Profile
+ constructor: ->
+ $('.edit_user .application-theme input, .edit_user .code-preview-theme input').click ->
+ # Submit the form
+ $('.edit_user').submit()
- new Flash("Appearance settings saved", "notice")
+ new Flash("Appearance settings saved", "notice")
- $('.update-username form').on 'ajax:before', ->
- $('.loading-gif').show()
- $(this).find('.update-success').hide()
- $(this).find('.update-failed').hide()
+ $('.update-username form').on 'ajax:before', ->
+ $('.loading-gif').show()
+ $(this).find('.update-success').hide()
+ $(this).find('.update-failed').hide()
- $('.update-username form').on 'ajax:complete', ->
- $(this).find('.btn-save').enableButton()
- $(this).find('.loading-gif').hide()
+ $('.update-username form').on 'ajax:complete', ->
+ $(this).find('.btn-save').enableButton()
+ $(this).find('.loading-gif').hide()
- $('.update-notifications').on 'ajax:complete', ->
- $(this).find('.btn-save').enableButton()
+ $('.update-notifications').on 'ajax:complete', ->
+ $(this).find('.btn-save').enableButton()
- $('.js-choose-user-avatar-button').bind "click", ->
- form = $(this).closest("form")
- form.find(".js-user-avatar-input").click()
+ $('.js-choose-user-avatar-button').bind "click", ->
+ form = $(this).closest("form")
+ form.find(".js-user-avatar-input").click()
- $('.js-user-avatar-input').bind "change", ->
- form = $(this).closest("form")
- filename = $(this).val().replace(/^.*[\\\/]/, '')
- form.find(".js-avatar-filename").text(filename)
-
- $('.profile-groups-avatars').tooltip("placement": "top")
+ $('.js-user-avatar-input').bind "change", ->
+ form = $(this).closest("form")
+ filename = $(this).val().replace(/^.*[\\\/]/, '')
+ form.find(".js-avatar-filename").text(filename)
diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee
index f4a8a178e76..5a9cc66c8f0 100644
--- a/app/assets/javascripts/project.js.coffee
+++ b/app/assets/javascripts/project.js.coffee
@@ -1,62 +1,20 @@
-class Project
+class @Project
constructor: ->
- $('.project-edit-container').on 'ajax:before', =>
- $('.project-edit-container').hide()
- $('.save-project-loader').show()
-
- @initEvents()
-
-
- initEvents: ->
- disableButtonIfEmptyField '#project_name', '.project-submit'
-
- $('#project_issues_enabled').change ->
- if ($(this).is(':checked') == true)
- $('#project_issues_tracker').removeAttr('disabled')
- else
- $('#project_issues_tracker').attr('disabled', 'disabled')
-
- $('#project_issues_tracker').change()
-
- $('#project_issues_tracker').change ->
- if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
- $('#project_issues_tracker_id').attr('disabled', 'disabled')
- else
- $('#project_issues_tracker_id').removeAttr('disabled')
-
-
-@Project = Project
-
-$ ->
- # Git clone panel switcher
- scope = $ '.git-clone-holder'
- if scope.length > 0
- $('a, button', scope).click ->
- $('a, button', scope).removeClass 'active'
- $(@).addClass 'active'
- $('#project_clone', scope).val $(@).data 'clone'
- $(".clone").text("").append $(@).data 'clone'
-
- # Ref switcher
- $('.project-refs-select').on 'change', ->
- $(@).parents('form').submit()
-
- $('.hide-no-ssh-message').on 'click', (e) ->
- path = '/'
- $.cookie('hide_no_ssh_message', 'false', { path: path })
- $(@).parents('.no-ssh-key-message').hide()
- e.preventDefault()
-
- $('.project-home-panel .star').on 'ajax:success', (e, data, status, xhr) ->
- $(@).toggleClass('on').find('.count').html(data.star_count)
- .on 'ajax:error', (e, xhr, status, error) ->
- new Flash('Star toggle failed. Try again later.', 'alert')
-
- $("a[data-toggle='tab']").on "shown.bs.tab", (e) ->
- $.cookie "default_view", $(e.target).attr("href")
-
- defaultView = $.cookie("default_view")
- if defaultView
- $("a[href=" + defaultView + "]").tab "show"
- else
- $("a[data-toggle='tab']:first").tab "show"
+ # Git clone panel switcher
+ scope = $ '.git-clone-holder'
+ if scope.length > 0
+ $('a, button', scope).click ->
+ $('a, button', scope).removeClass 'active'
+ $(@).addClass 'active'
+ $('#project_clone', scope).val $(@).data 'clone'
+ $(".clone").text("").append $(@).data 'clone'
+
+ # Ref switcher
+ $('.project-refs-select').on 'change', ->
+ $(@).parents('form').submit()
+
+ $('.hide-no-ssh-message').on 'click', (e) ->
+ path = '/'
+ $.cookie('hide_no_ssh_message', 'false', { path: path })
+ $(@).parents('.no-ssh-key-message').hide()
+ e.preventDefault()
diff --git a/app/assets/javascripts/project_fork.js.coffee b/app/assets/javascripts/project_fork.js.coffee
new file mode 100644
index 00000000000..e15a1c4ef76
--- /dev/null
+++ b/app/assets/javascripts/project_fork.js.coffee
@@ -0,0 +1,5 @@
+class @ProjectFork
+ constructor: ->
+ $('.fork-thumbnail a').on 'click', ->
+ $('.fork-namespaces').hide()
+ $('.save-project-loader').show()
diff --git a/app/assets/javascripts/project_import.js.coffee b/app/assets/javascripts/project_import.js.coffee
index 7cf44da99fe..6633564a079 100644
--- a/app/assets/javascripts/project_import.js.coffee
+++ b/app/assets/javascripts/project_import.js.coffee
@@ -1,7 +1,5 @@
-class ProjectImport
+class @ProjectImport
constructor: ->
setTimeout ->
Turbolinks.visit(location.href)
, 5000
-
-@ProjectImport = ProjectImport
diff --git a/app/assets/javascripts/project_new.js.coffee b/app/assets/javascripts/project_new.js.coffee
new file mode 100644
index 00000000000..f4a2ca813d2
--- /dev/null
+++ b/app/assets/javascripts/project_new.js.coffee
@@ -0,0 +1,25 @@
+class @ProjectNew
+ constructor: ->
+ $('.project-edit-container').on 'ajax:before', =>
+ $('.project-edit-container').hide()
+ $('.save-project-loader').show()
+
+ @initEvents()
+
+
+ initEvents: ->
+ disableButtonIfEmptyField '#project_name', '.project-submit'
+
+ $('#project_issues_enabled').change ->
+ if ($(this).is(':checked') == true)
+ $('#project_issues_tracker').removeAttr('disabled')
+ else
+ $('#project_issues_tracker').attr('disabled', 'disabled')
+
+ $('#project_issues_tracker').change()
+
+ $('#project_issues_tracker').change ->
+ if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
+ $('#project_issues_tracker_id').attr('disabled', 'disabled')
+ else
+ $('#project_issues_tracker_id').removeAttr('disabled')
diff --git a/app/assets/javascripts/project_show.js.coffee b/app/assets/javascripts/project_show.js.coffee
new file mode 100644
index 00000000000..02a7d7b731d
--- /dev/null
+++ b/app/assets/javascripts/project_show.js.coffee
@@ -0,0 +1,15 @@
+class @ProjectShow
+ constructor: ->
+ $('.project-home-panel .star').on 'ajax:success', (e, data, status, xhr) ->
+ $(@).toggleClass('on').find('.count').html(data.star_count)
+ .on 'ajax:error', (e, xhr, status, error) ->
+ new Flash('Star toggle failed. Try again later.', 'alert')
+
+ $("a[data-toggle='tab']").on "shown.bs.tab", (e) ->
+ $.cookie "default_view", $(e.target).attr("href")
+
+ defaultView = $.cookie("default_view")
+ if defaultView
+ $("a[href=" + defaultView + "]").tab "show"
+ else
+ $("a[data-toggle='tab']:first").tab "show"
diff --git a/app/assets/javascripts/project_users_select.js.coffee b/app/assets/javascripts/project_users_select.js.coffee
index cfbcd5108c8..7fb33926096 100644
--- a/app/assets/javascripts/project_users_select.js.coffee
+++ b/app/assets/javascripts/project_users_select.js.coffee
@@ -1,6 +1,6 @@
-@projectUsersSelect =
- init: ->
- $('.ajax-project-users-select').each (i, select) ->
+class @ProjectUsersSelect
+ constructor: ->
+ $('.ajax-project-users-select').each (i, select) =>
project_id = $(select).data('project-id') || $('body').data('project-id')
$(select).select2
@@ -28,14 +28,16 @@
Api.user(id, callback)
- formatResult: projectUsersSelect.projectUserFormatResult
- formatSelection: projectUsersSelect.projectUserFormatSelection
+ formatResult: (args...) =>
+ @formatResult(args...)
+ formatSelection: (args...) =>
+ @formatSelection(args...)
dropdownCssClass: "ajax-project-users-dropdown"
dropdownAutoWidth: true
escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
m
- projectUserFormatResult: (user) ->
+ formatResult: (user) ->
if user.avatar_url
avatar = user.avatar_url
else
@@ -52,8 +54,5 @@
<div class='user-username'>#{user.username}</div>
</div>"
- projectUserFormatSelection: (user) ->
+ formatSelection: (user) ->
user.name
-
-$ ->
- projectUsersSelect.init()
diff --git a/app/assets/javascripts/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee
index e144dfa1d68..c1801365266 100644
--- a/app/assets/javascripts/search_autocomplete.js.coffee
+++ b/app/assets/javascripts/search_autocomplete.js.coffee
@@ -1,4 +1,4 @@
-class SearchAutocomplete
+class @SearchAutocomplete
constructor: (search_autocomplete_path, project_id, project_ref) ->
project_id = '' unless project_id
project_ref = '' unless project_ref
@@ -9,5 +9,3 @@ class SearchAutocomplete
minLength: 1
select: (event, ui) ->
location.href = ui.item.url
-
-@SearchAutocomplete = SearchAutocomplete
diff --git a/app/assets/javascripts/stat_graph.js.coffee b/app/assets/javascripts/stat_graph.js.coffee
index b129619696f..f36c71fd25e 100644
--- a/app/assets/javascripts/stat_graph.js.coffee
+++ b/app/assets/javascripts/stat_graph.js.coffee
@@ -1,4 +1,4 @@
-class window.StatGraph
+class @StatGraph
@log: {}
@get_log: ->
@log
diff --git a/app/assets/javascripts/stat_graph_contributors.js.coffee b/app/assets/javascripts/stat_graph_contributors.js.coffee
index ab785a54543..27f0fd31d50 100644
--- a/app/assets/javascripts/stat_graph_contributors.js.coffee
+++ b/app/assets/javascripts/stat_graph_contributors.js.coffee
@@ -1,4 +1,4 @@
-class window.ContributorsStatGraph
+class @ContributorsStatGraph
init: (log) ->
@parsed_log = ContributorsStatGraphUtil.parse_log(log)
@set_current_field("commits")
diff --git a/app/assets/javascripts/stat_graph_contributors_graph.js.coffee b/app/assets/javascripts/stat_graph_contributors_graph.js.coffee
index 834c7e5dab0..9952fa0b00a 100644
--- a/app/assets/javascripts/stat_graph_contributors_graph.js.coffee
+++ b/app/assets/javascripts/stat_graph_contributors_graph.js.coffee
@@ -1,4 +1,4 @@
-class window.ContributorsGraph
+class @ContributorsGraph
MARGIN:
top: 20
right: 20
@@ -44,7 +44,7 @@ class window.ContributorsGraph
set_data: (data) ->
@data = data
-class window.ContributorsMasterGraph extends ContributorsGraph
+class @ContributorsMasterGraph extends ContributorsGraph
constructor: (@data) ->
@width = $('.container').width() - 70
@height = 200
@@ -117,7 +117,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph
@svg.select("path").attr("d", @area)
@svg.select(".y.axis").call(@y_axis)
-class window.ContributorsAuthorGraph extends ContributorsGraph
+class @ContributorsAuthorGraph extends ContributorsGraph
constructor: (@data) ->
@width = $('.container').width()/2 - 100
@height = 200
diff --git a/app/assets/javascripts/team_members.js.coffee b/app/assets/javascripts/team_members.js.coffee
deleted file mode 100644
index 5eaa8ad4ff9..00000000000
--- a/app/assets/javascripts/team_members.js.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-class TeamMembers
- constructor: ->
- $('.team-members .project-access-select').on "change", ->
- $(this.form).submit()
-
-@TeamMembers = TeamMembers
diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee
index 4852e879b68..d428db5b422 100644
--- a/app/assets/javascripts/tree.js.coffee
+++ b/app/assets/javascripts/tree.js.coffee
@@ -1,4 +1,4 @@
-class TreeView
+class @TreeView
constructor: ->
@initKeyNav()
@@ -39,5 +39,3 @@ class TreeView
else if e.which is 13
path = $('.tree-item.selected .tree-item-file-name a').attr('href')
Turbolinks.visit(path)
-
-@TreeView = TreeView
diff --git a/app/assets/javascripts/user.js.coffee b/app/assets/javascripts/user.js.coffee
new file mode 100644
index 00000000000..8a2e2421c2e
--- /dev/null
+++ b/app/assets/javascripts/user.js.coffee
@@ -0,0 +1,3 @@
+class @User
+ constructor: ->
+ $('.profile-groups-avatars').tooltip("placement": "top")
diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee
index 86318bd7d94..9eee7406511 100644
--- a/app/assets/javascripts/users_select.js.coffee
+++ b/app/assets/javascripts/users_select.js.coffee
@@ -1,5 +1,30 @@
-$ ->
- userFormatResult = (user) ->
+class @UsersSelect
+ constructor: ->
+ $('.ajax-users-select').each (i, select) =>
+ $(select).select2
+ placeholder: "Search for a user"
+ multiple: $(select).hasClass('multiselect')
+ minimumInputLength: 0
+ query: (query) ->
+ Api.users query.term, (users) ->
+ data = { results: users }
+ query.callback(data)
+
+ initSelection: (element, callback) ->
+ id = $(element).val()
+ if id isnt ""
+ Api.user(id, callback)
+
+
+ formatResult: (args...) =>
+ @formatResult(args...)
+ formatSelection: (args...) =>
+ @formatSelection(args...)
+ dropdownCssClass: "ajax-users-dropdown"
+ escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
+ m
+
+ formatResult: (user) ->
if user.avatar_url
avatar = user.avatar_url
else
@@ -11,27 +36,5 @@ $ ->
<div class='user-username'>#{user.username}</div>
</div>"
- userFormatSelection = (user) ->
+ formatSelection: (user) ->
user.name
-
- $('.ajax-users-select').each (i, select) ->
- $(select).select2
- placeholder: "Search for a user"
- multiple: $(select).hasClass('multiselect')
- minimumInputLength: 0
- query: (query) ->
- Api.users query.term, (users) ->
- data = { results: users }
- query.callback(data)
-
- initSelection: (element, callback) ->
- id = $(element).val()
- if id isnt ""
- Api.user(id, callback)
-
-
- formatResult: userFormatResult
- formatSelection: userFormatSelection
- dropdownCssClass: "ajax-users-dropdown"
- escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
- m
diff --git a/app/assets/javascripts/wikis.js.coffee b/app/assets/javascripts/wikis.js.coffee
index 17e790e5b7c..66757565d3a 100644
--- a/app/assets/javascripts/wikis.js.coffee
+++ b/app/assets/javascripts/wikis.js.coffee
@@ -1,4 +1,4 @@
-class Wikis
+class @Wikis
constructor: ->
$('.build-new-wiki').bind "click", ->
field = $('#new_wiki_path')
@@ -7,6 +7,3 @@ class Wikis
if(slug.length > 0)
location.href = path + "/" + slug
-
-
-@Wikis = Wikis
diff --git a/app/assets/stylesheets/behaviors.scss b/app/assets/stylesheets/behaviors.scss
index be4c4d07f1c..469f4f296ae 100644
--- a/app/assets/stylesheets/behaviors.scss
+++ b/app/assets/stylesheets/behaviors.scss
@@ -1,12 +1,22 @@
// Details
//--------
-.js-details-container .content { display: none; }
-.js-details-container .content.hide { display: block; }
-.js-details-container.open .content { display: block; }
-.js-details-container.open .content.hide { display: none; }
+.js-details-container {
+ .content {
+ display: none;
+ &.hide { display: block; }
+ }
+ &.open .content {
+ display: block;
+ &.hide { display: none; }
+ }
+}
// Toggle between two states.
-.js-toggler-container .turn-on { display: block; }
-.js-toggler-container .turn-off { display: none; }
-.js-toggler-container.on .turn-on { display: none; }
-.js-toggler-container.on .turn-off { display: block; }
+.js-toggler-container {
+ .turn-on { display: block; }
+ .turn-off { display: none; }
+ &.on {
+ .turn-on { display: none; }
+ .turn-off { display: block; }
+ }
+}
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index cd2f4e45e3c..2fc738c18d8 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -330,10 +330,6 @@ table {
}
}
-@media (max-width: $screen-xs-max) {
- .container .content { margin-top: 20px; }
-}
-
.wiki .highlight, .note-body .highlight {
margin-bottom: 9px;
}
diff --git a/app/assets/stylesheets/generic/files.scss b/app/assets/stylesheets/generic/files.scss
index e2b0ef0c5ea..1ed41272ac5 100644
--- a/app/assets/stylesheets/generic/files.scss
+++ b/app/assets/stylesheets/generic/files.scss
@@ -42,7 +42,6 @@
}
.file-content {
background: #fff;
- font-size: 11px;
&.image_file {
background: #eee;
@@ -54,8 +53,6 @@
}
&.wiki {
- font-size: 14px;
- line-height: 1.6;
padding: 25px;
.highlight {
diff --git a/app/assets/stylesheets/generic/highlight.scss b/app/assets/stylesheets/generic/highlight.scss
index 4110bddf4f3..ae08539d454 100644
--- a/app/assets/stylesheets/generic/highlight.scss
+++ b/app/assets/stylesheets/generic/highlight.scss
@@ -59,6 +59,10 @@
pre {
white-space: pre;
word-wrap: normal;
+
+ code {
+ font-family: $monospace_font;
+ }
}
}
}
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss
index 94149594e24..79fbad4b946 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/generic/issue_box.scss
@@ -113,6 +113,11 @@
padding: 10px 15px;
}
+ .cross-project-ref {
+ float: left;
+ padding: 10px 15px;
+ }
+
.creator {
float: right;
padding: 10px 15px;
diff --git a/app/assets/stylesheets/generic/mobile.scss b/app/assets/stylesheets/generic/mobile.scss
new file mode 100644
index 00000000000..c164b07b104
--- /dev/null
+++ b/app/assets/stylesheets/generic/mobile.scss
@@ -0,0 +1,17 @@
+/** Common mobile (screen XS) styles **/
+@media (max-width: $screen-xs-max) {
+ .container .content {
+ margin-top: 20px;
+ }
+
+ .nav.nav-tabs > li > a {
+ padding: 10px;
+ font-size: 12px;
+ margin-right: 3px;
+
+ .badge {
+ display: none;
+ }
+ }
+}
+
diff --git a/app/assets/stylesheets/generic/timeline.scss b/app/assets/stylesheets/generic/timeline.scss
index f29cf25fa4c..57e9e8ae5c5 100644
--- a/app/assets/stylesheets/generic/timeline.scss
+++ b/app/assets/stylesheets/generic/timeline.scss
@@ -75,3 +75,20 @@
}
}
}
+
+@media (max-width: $screen-xs-max) {
+ .timeline {
+ &:before {
+ background: none;
+ }
+ .timeline-entry .timeline-entry-inner {
+ .timeline-icon {
+ display: none;
+ }
+
+ .timeline-content {
+ margin-left: 0;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index 36bc5df2f44..dffa2dc9ed2 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -29,28 +29,30 @@
.hljs-tag,
.hljs-tag .hljs-title,
- .hljs-keyword,
- .hljs-literal,
.hljs-strong,
.hljs-change,
.hljs-winutils,
.hljs-flow,
.lisp .hljs-title,
.clojure .hljs-built_in,
+ .hljs-keyword,
.nginx .hljs-title,
.tex .hljs-special {
color: #F92672;
}
.hljs {
- color: #DDD;
+ color: #F8F8F2;
}
- .hljs .hljs-constant,
- .asciidoc .hljs-code {
+ .asciidoc .hljs-code,
+ .markdown .hljs-code,
+ .hljs-literal,
+ .hljs-function .hljs-keyword {
color: #66D9EF;
}
+
.hljs-code,
.hljs-class .hljs-title,
.hljs-header {
@@ -62,18 +64,27 @@
.hljs-symbol,
.hljs-symbol .hljs-string,
.hljs-value,
+ .hljs-constant,
+ .hljs-number,
.hljs-regexp {
- color: #BF79DB;
+ color: #AE81FF;
+ }
+
+ .hljs-string {
+ color: #E6DB74;
+ }
+
+ .hljs-params {
+ color: #fd971f;
}
.hljs-link_url,
.hljs-tag .hljs-value,
- .hljs-string,
.hljs-bullet,
.hljs-subst,
.hljs-title,
.hljs-emphasis,
- .haskell .hljs-type,
+ .hljs-type,
.hljs-preprocessor,
.hljs-pragma,
.ruby .hljs-class .hljs-parent,
@@ -99,12 +110,12 @@
}
.hljs-comment,
- .java .hljs-annotation,
+ .hljs-annotation,
.smartquote,
.hljs-blockquote,
.hljs-horizontal_rule,
- .python .hljs-decorator,
.hljs-template_comment,
+ .hljs-decorator,
.hljs-pi,
.hljs-doctype,
.hljs-deletion,
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index 815cf367ae8..8d5822937a0 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -186,3 +186,11 @@
}
}
}
+
+.readme-holder .wiki, .note-body, .wiki-holder {
+ .white {
+ .highlight, pre, .hljs {
+ background: #F9F9F9;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/main/fonts.scss b/app/assets/stylesheets/main/fonts.scss
index d90274a0db9..f945aaca848 100644
--- a/app/assets/stylesheets/main/fonts.scss
+++ b/app/assets/stylesheets/main/fonts.scss
@@ -1,3 +1,3 @@
/** Typo **/
-$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
+$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
$regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss
index 7f607fc4e8b..5f83913b73b 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/main/mixins.scss
@@ -58,8 +58,8 @@
}
@mixin md-typography {
- font-size: 14px;
- line-height: 1.6;
+ font-size: 15px;
+ line-height: 1.5;
img {
max-width: 100%;
@@ -93,7 +93,7 @@
blockquote p {
color: #888;
- font-size: 14px;
+ font-size: 15px;
line-height: 1.5;
}
diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss
index 656aa5b18a6..a766d6e77ab 100644
--- a/app/assets/stylesheets/sections/events.scss
+++ b/app/assets/stylesheets/sections/events.scss
@@ -47,7 +47,7 @@
.event-title {
@include str-truncated(72%);
color: #333;
- font-weight: normal;
+ font-weight: 500;
font-size: 14px;
.author_name {
color: #333;
@@ -56,12 +56,9 @@
.event-body {
margin-left: 35px;
margin-right: 100px;
+ color: #777;
- .event-info {
- color: #666;
- }
.event-note {
- color: #666;
margin-top: 5px;
.md {
@@ -72,7 +69,7 @@
border: none;
background: #f9f9f9;
border-radius: 0;
- color: #666;
+ color: #777;
margin: 0 20px;
}
@@ -120,7 +117,6 @@
padding: 3px;
padding-left: 0;
border: none;
- color: #666;
.commit-row-title {
font-size: 12px;
}
@@ -186,7 +182,24 @@
}
@media (max-width: $screen-xs-max) {
- .event-item .event-title {
- @include str-truncated(65%);
+ .event-item {
+ .event-title {
+ white-space: normal;
+ overflow: visible;
+ max-width: 100%;
+ }
+ .avatar {
+ display: none;
+ }
+
+ .event-body {
+ margin: 0;
+ border-left: 2px solid #DDD;
+ padding-left: 10px;
+ }
+
+ .event-item-timestamp {
+ display: none;
+ }
}
}
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index e0e0d60c387..9ad1a1db2cd 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -59,6 +59,7 @@ header {
}
.navbar-collapse {
+ margin-top: 47px;
padding-right: 0;
padding-left: 0;
}
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index a7fa715d2e0..9a5400fffbc 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -75,7 +75,7 @@
}
.participants {
- margin-bottom: 10px;
+ margin-bottom: 20px;
}
.issues_bulk_update {
@@ -151,4 +151,14 @@ form.edit-issue {
}
}
}
+
+ .issue {
+ &:hover .issue-actions {
+ display: none !important;
+ }
+
+ .issue-updated-at {
+ display: none;
+ }
+ }
}
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index 22f20a7df4d..ec844cc00b0 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -113,30 +113,36 @@
font-size: 15px;
border-bottom: 1px solid #BBB;
color: #777;
+ background-color: #F5F5F5;
&.ci-success {
color: $bg_success;
border-color: $border_success;
+ background-color: #F1FAF1;
}
&.ci-pending {
color: #548;
border-color: #548;
+ background-color: #F4F1FA;
}
&.ci-running {
color: $bg_warning;
border-color: $border_warning;
+ background-color: #FAF5F1;
}
&.ci-failed {
color: $bg_danger;
border-color: $border_danger;
+ background-color: #FAF1F1;
}
&.ci-error {
color: $bg_danger;
border-color: $border_danger;
+ background-color: #FAF1F1;
}
}
diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss
index 31c0a0835db..ccd672c5f67 100644
--- a/app/assets/stylesheets/sections/nav.scss
+++ b/app/assets/stylesheets/sections/nav.scss
@@ -63,7 +63,6 @@
@media (max-width: $screen-xs-max) {
font-size: 18px;
margin: 0;
-
max-height: none;
&, .container {
@@ -86,6 +85,7 @@
color: #fff;
font-weight: normal;
text-shadow: none;
+ border: none;
&:after { display: none; }
}
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index 65ad46a4579..e1f9c0cb258 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -36,13 +36,16 @@ ul.notes {
font-size: 13px;
}
.author {
- color: #555;
+ color: #333;
font-weight: bold;
font-size: 14px;
&:hover {
- color: $link_hover_color;
+ color: $link_color;
}
}
+ .author-username {
+ font-size: 14px;
+ }
}
.discussion {
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/sections/profile.scss
index 086875582f3..b9f4e317e9c 100644
--- a/app/assets/stylesheets/sections/profile.scss
+++ b/app/assets/stylesheets/sections/profile.scss
@@ -111,3 +111,20 @@
height: 50px;
}
}
+
+//CSS for password-strength indicator
+#password-strength {
+ margin-bottom: 0;
+}
+
+.has-success input {
+ background-color: #D6F1D7 !important;
+}
+
+.has-error input {
+ background-color: #F3CECE !important;
+}
+
+.has-warning input {
+ background-color: #FFE9A4 !important;
+}
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index b4ee5ccc8d7..7b894cf00bb 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -270,3 +270,41 @@ ul.nav.nav-projects-tabs {
color: #999;
}
}
+
+.fork-namespaces {
+ .thumbnail {
+
+ &.fork-exists-thumbnail {
+ border-color: #EEE;
+
+ .caption {
+ color: #999;
+ }
+ }
+
+ &.fork-thumbnail {
+ border-color: #AAA;
+
+ &:hover {
+ background-color: $hover;
+ }
+ }
+
+ a {
+ text-decoration: none;
+ }
+ }
+}
+
+@media (max-width: $screen-xs-max) {
+ .project-home-panel {
+ .star-fork-buttons {
+ padding-top: 10px;
+ padding-right: 15px;
+ }
+ }
+
+ .project-home-links {
+ display: none;
+ }
+}
diff --git a/app/controllers/admin/background_jobs_controller.rb b/app/controllers/admin/background_jobs_controller.rb
index 4c1d0df4110..338496013a0 100644
--- a/app/controllers/admin/background_jobs_controller.rb
+++ b/app/controllers/admin/background_jobs_controller.rb
@@ -1,6 +1,6 @@
class Admin::BackgroundJobsController < Admin::ApplicationController
def show
- ps_output, _ = Gitlab::Popen.popen(%W(ps -U #{Settings.gitlab.user} -o pid,pcpu,pmem,stat,start,command))
+ ps_output, _ = Gitlab::Popen.popen(%W(ps -U #{Gitlab.config.gitlab.user} -o pid,pcpu,pmem,stat,start,command))
@sidekiq_processes = ps_output.split("\n").grep(/sidekiq/)
end
end
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 2f0d344802f..7c2388e81be 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -31,17 +31,11 @@ class Admin::ProjectsController < Admin::ApplicationController
protected
def project
- id = params[:project_id] || params[:id]
-
- @project = Project.find_with_namespace(id)
+ @project = Project.find_with_namespace(params[:id])
@project || render_404
end
def group
- @group ||= project.group
- end
-
- def repository
- @repository ||= project.repository
+ @group ||= @project.group
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 13d8d2a3e0a..f1e1bebe5ce 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -5,9 +5,7 @@ class ApplicationController < ActionController::Base
before_filter :authenticate_user!
before_filter :reject_blocked!
before_filter :check_password_expiration
- before_filter :add_abilities
before_filter :ldap_security_check
- before_filter :dev_tools if Rails.env == 'development'
before_filter :default_headers
before_filter :add_gon_variables
before_filter :configure_permitted_parameters, if: :devise_controller?
@@ -73,7 +71,7 @@ class ApplicationController < ActionController::Base
end
def abilities
- @abilities ||= Six.new
+ Ability.abilities
end
def can?(object, action, subject)
@@ -81,28 +79,31 @@ class ApplicationController < ActionController::Base
end
def project
- id = params[:project_id] || params[:id]
-
- # Redirect from
- # localhost/group/project.git
- # to
- # localhost/group/project
- #
- if id =~ /\.git\Z/
- redirect_to request.original_url.gsub(/\.git\Z/, '') and return
- end
+ unless @project
+ id = params[:project_id] || params[:id]
+
+ # Redirect from
+ # localhost/group/project.git
+ # to
+ # localhost/group/project
+ #
+ if id =~ /\.git\Z/
+ redirect_to request.original_url.gsub(/\.git\Z/, '') and return
+ end
- @project = Project.find_with_namespace(id)
+ @project = Project.find_with_namespace(id)
- if @project and can?(current_user, :read_project, @project)
- @project
- elsif current_user.nil?
- @project = nil
- authenticate_user!
- else
- @project = nil
- render_404 and return
+ if @project and can?(current_user, :read_project, @project)
+ @project
+ elsif current_user.nil?
+ @project = nil
+ authenticate_user!
+ else
+ @project = nil
+ render_404 and return
+ end
end
+ @project
end
def repository
@@ -111,22 +112,10 @@ class ApplicationController < ActionController::Base
nil
end
- def add_abilities
- abilities << Ability
- end
-
def authorize_project!(action)
return access_denied! unless can?(current_user, action, project)
end
- def authorize_code_access!
- return access_denied! unless can?(current_user, :download_code, project)
- end
-
- def authorize_push!
- return access_denied! unless can?(current_user, :push_code, project)
- end
-
def authorize_labels!
# Labels should be accessible for issues and/or merge requests
authorize_read_issue! || authorize_read_merge_request!
@@ -170,9 +159,6 @@ class ApplicationController < ActionController::Base
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
end
- def dev_tools
- end
-
def default_headers
headers['X-Frame-Options'] = 'DENY'
headers['X-XSS-Protection'] = '1; mode=block'
diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb
index f8e1a31e0b3..ada7031fea4 100644
--- a/app/controllers/explore/groups_controller.rb
+++ b/app/controllers/explore/groups_controller.rb
@@ -1,7 +1,6 @@
class Explore::GroupsController < ApplicationController
skip_before_filter :authenticate_user!,
- :reject_blocked, :set_current_user_for_observers,
- :add_abilities
+ :reject_blocked, :set_current_user_for_observers
layout "explore"
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index b6fa8b7e387..d75fd8e72fa 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -1,7 +1,6 @@
class Explore::ProjectsController < ApplicationController
skip_before_filter :authenticate_user!,
- :reject_blocked,
- :add_abilities
+ :reject_blocked
layout 'explore'
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 63c05d4f33b..ca88d033878 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -19,6 +19,7 @@ class Groups::GroupMembersController < ApplicationController
def destroy
@users_group = @group.group_members.find(params[:id])
+
if can?(current_user, :destroy, @users_group) # May fail if last owner.
@users_group.destroy
respond_to do |format|
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index f46b36568f3..3e984e5007a 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -42,25 +42,32 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def handle_omniauth
if current_user
- # Change a logged-in user's authentication method:
- current_user.extern_uid = oauth['uid']
- current_user.provider = oauth['provider']
- current_user.save
+ # Add new authentication method
+ current_user.identities.find_or_create_by(extern_uid: oauth['uid'], provider: oauth['provider'])
redirect_to profile_path
else
@user = Gitlab::OAuth::User.new(oauth)
+ @user.save
- if Gitlab.config.omniauth['allow_single_sign_on'] && @user.new?
- @user.save
- end
-
- if @user.valid?
+ # Only allow properly saved users to login.
+ if @user.persisted? && @user.valid?
sign_in_and_redirect(@user.gl_user)
else
- error_message = @user.gl_user.errors.map{ |attribute, message| "#{attribute} #{message}" }.join(", ")
+ error_message =
+ if @user.gl_user.errors.any?
+ @user.gl_user.errors.map do |attribute, message|
+ "#{attribute} #{message}"
+ end.join(", ")
+ else
+ ''
+ end
+
redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
end
end
+ rescue ForbiddenAction => e
+ flash[:notice] = e.message
+ redirect_to new_user_session_path
end
def oauth
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 7e4580017dd..6b7fe06d59f 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -29,4 +29,31 @@ class Projects::ApplicationController < ApplicationController
redirect_to project_tree_path(@project, @ref), notice: "This action is not allowed unless you are on top of a branch"
end
end
+
+ def set_filter_variables(collection)
+ params[:sort] ||= 'newest'
+ params[:scope] = 'all' if params[:scope].blank?
+ params[:state] = 'opened' if params[:state].blank?
+
+ @sort = params[:sort].humanize
+
+ assignee_id = params[:assignee_id]
+ author_id = params[:author_id]
+ milestone_id = params[:milestone_id]
+
+ if assignee_id.present? && !assignee_id.to_i.zero?
+ @assignee = @project.team.find(assignee_id)
+ end
+
+ if author_id.present? && !author_id.to_i.zero?
+ @author = @project.team.find(assignee_id)
+ end
+
+ if milestone_id.present? && !milestone_id.to_i.zero?
+ @milestone = @project.milestones.find(milestone_id)
+ end
+
+ @assignees = User.where(id: collection.pluck(:assignee_id))
+ @authors = User.where(id: collection.pluck(:author_id))
+ end
end
diff --git a/app/controllers/projects/base_tree_controller.rb b/app/controllers/projects/base_tree_controller.rb
index 5e305934433..a7b1b7b40e8 100644
--- a/app/controllers/projects/base_tree_controller.rb
+++ b/app/controllers/projects/base_tree_controller.rb
@@ -1,8 +1,7 @@
class Projects::BaseTreeController < Projects::ApplicationController
include ExtractsPath
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
end
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index a3c41301676..367d1295f34 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -3,8 +3,7 @@ class Projects::BlameController < Projects::ApplicationController
include ExtractsPath
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
def show
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 7009e3b1bc8..2412800c493 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -3,10 +3,9 @@ class Projects::BlobController < Projects::ApplicationController
include ExtractsPath
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
- before_filter :authorize_push!, only: [:destroy]
+ before_filter :authorize_push_code!, only: [:destroy]
before_filter :blob
@@ -20,7 +19,7 @@ class Projects::BlobController < Projects::ApplicationController
flash[:notice] = "Your changes have been successfully committed"
redirect_to project_tree_path(@project, @ref)
else
- flash[:alert] = result[:error]
+ flash[:alert] = result[:message]
render :show
end
end
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index faa0ce67ca8..cff1a907dc2 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -1,10 +1,10 @@
class Projects::BranchesController < Projects::ApplicationController
+ include ActionView::Helpers::SanitizeHelper
# Authorize
- before_filter :authorize_read_project!
before_filter :require_non_empty_project
- before_filter :authorize_code_access!
- before_filter :authorize_push!, only: [:create, :destroy]
+ before_filter :authorize_download_code!
+ before_filter :authorize_push_code!, only: [:create, :destroy]
def index
@sort = params[:sort] || 'name'
@@ -17,8 +17,11 @@ class Projects::BranchesController < Projects::ApplicationController
end
def create
+ branch_name = sanitize(strip_tags(params[:branch_name]))
+ ref = sanitize(strip_tags(params[:ref]))
result = CreateBranchService.new(project, current_user).
- execute(params[:branch_name], params[:ref])
+ execute(branch_name, ref)
+
if result[:status] == :success
@branch = result[:branch]
redirect_to project_tree_path(@project, @branch.name)
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 66c67b661db..dac858d8e16 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -3,20 +3,19 @@
# Not to be confused with CommitsController, plural.
class Projects::CommitController < Projects::ApplicationController
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
before_filter :commit
def show
return git_not_found! unless @commit
- @line_notes = project.notes.for_commit_id(commit.id).inline
- @branches = project.repository.branch_names_contains(commit.id)
+ @line_notes = @project.notes.for_commit_id(commit.id).inline
+ @branches = @project.repository.branch_names_contains(commit.id)
@diffs = @commit.diffs
- @note = project.build_commit_note(commit)
- @notes_count = project.notes.for_commit_id(commit.id).count
- @notes = project.notes.for_commit_id(@commit.id).not_inline.fresh
+ @note = @project.build_commit_note(commit)
+ @notes_count = @project.notes.for_commit_id(commit.id).count
+ @notes = @project.notes.for_commit_id(@commit.id).not_inline.fresh
@noteable = @commit
@comments_allowed = @reply_allowed = true
@comments_target = {
@@ -32,6 +31,6 @@ class Projects::CommitController < Projects::ApplicationController
end
def commit
- @commit ||= project.repository.commit(params[:id])
+ @commit ||= @project.repository.commit(params[:id])
end
end
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index b7f09eb271d..9476b6c0284 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -4,8 +4,7 @@ class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
def show
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index 7a671e8455d..ffb8c2e4af1 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -1,7 +1,6 @@
class Projects::CompareController < Projects::ApplicationController
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
def index
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index d20937ea8ea..024b9520d30 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -42,7 +42,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
end
def enable
- project.deploy_keys << available_keys.find(params[:id])
+ @project.deploy_keys << available_keys.find(params[:id])
redirect_to project_deploy_keys_path(@project)
end
diff --git a/app/controllers/projects/edit_tree_controller.rb b/app/controllers/projects/edit_tree_controller.rb
index 8976d7c7be8..65661c80410 100644
--- a/app/controllers/projects/edit_tree_controller.rb
+++ b/app/controllers/projects/edit_tree_controller.rb
@@ -1,7 +1,7 @@
class Projects::EditTreeController < Projects::BaseTreeController
before_filter :require_branch_head
before_filter :blob
- before_filter :authorize_push!
+ before_filter :authorize_push_code!
before_filter :from_merge_request
before_filter :after_edit_path
@@ -22,7 +22,7 @@ class Projects::EditTreeController < Projects::BaseTreeController
redirect_to after_edit_path
else
- flash[:alert] = result[:error]
+ flash[:alert] = result[:message]
render :show
end
end
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
new file mode 100644
index 00000000000..a0481d11582
--- /dev/null
+++ b/app/controllers/projects/forks_controller.rb
@@ -0,0 +1,22 @@
+class Projects::ForksController < Projects::ApplicationController
+ # Authorize
+ before_filter :authorize_download_code!
+ before_filter :require_non_empty_project
+
+ def new
+ @namespaces = current_user.manageable_namespaces
+ @namespaces.delete(@project.namespace)
+ end
+
+ def create
+ namespace = Namespace.find(params[:namespace_id])
+ @forked_project = ::Projects::ForkService.new(project, current_user, namespace: namespace).execute
+
+ if @forked_project.saved? && @forked_project.forked?
+ redirect_to(@forked_project, notice: 'Project was successfully forked.')
+ else
+ @title = 'Fork project'
+ render :error
+ end
+ end
+end
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 610b4967fea..4a318cb7d56 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -1,7 +1,6 @@
class Projects::GraphsController < Projects::ApplicationController
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
def show
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index cab8fd76e6c..2d6c3111192 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -26,6 +26,7 @@ class Projects::HooksController < Projects::ApplicationController
def test
if !@project.empty_repo?
status = TestHookService.new.execute(hook, current_user)
+
if status
flash[:notice] = 'Hook successfully executed.'
else
diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
new file mode 100644
index 00000000000..b8350642804
--- /dev/null
+++ b/app/controllers/projects/imports_controller.rb
@@ -0,0 +1,49 @@
+class Projects::ImportsController < Projects::ApplicationController
+ # Authorize
+ before_filter :authorize_admin_project!
+ before_filter :require_no_repo
+ before_filter :redirect_if_progress, except: :show
+
+ def new
+ end
+
+ def create
+ @project.import_url = params[:project][:import_url]
+
+ if @project.save
+ @project.reload
+
+ if @project.import_failed?
+ @project.import_retry
+ else
+ @project.import_start
+ end
+ end
+
+ redirect_to project_import_path(@project)
+ end
+
+ def show
+ unless @project.import_in_progress?
+ if @project.import_finished?
+ redirect_to(@project) and return
+ else
+ redirect_to new_project_import_path(@project) and return
+ end
+ end
+ end
+
+ private
+
+ def require_no_repo
+ if @project.repository_exists?
+ redirect_to(@project) and return
+ end
+ end
+
+ def redirect_if_progress
+ if @project.import_in_progress?
+ redirect_to project_import_path(@project) and return
+ end
+ end
+end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index c6d526f05c5..22235123826 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -18,18 +18,12 @@ class Projects::IssuesController < Projects::ApplicationController
def index
terms = params['issue_search']
+ set_filter_variables(@project.issues)
- @issues = issues_filtered
+ @issues = IssuesFinder.new.execute(current_user, params.merge(project_id: @project.id))
@issues = @issues.full_search(terms) if terms.present?
@issues = @issues.page(params[:page]).per(20)
- assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
- @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
- @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
- sort_param = params[:sort] || 'newest'
- @sort = sort_param.humanize unless sort_param.empty?
- @assignees = User.where(id: @project.issues.pluck(:assignee_id)).active
-
respond_to do |format|
format.html
format.atom { render layout: false }
@@ -127,12 +121,6 @@ class Projects::IssuesController < Projects::ApplicationController
return render_404 unless @project.issues_enabled
end
- def issues_filtered
- params[:scope] = 'all' if params[:scope].blank?
- params[:state] = 'opened' if params[:state].blank?
- @issues = IssuesFinder.new.execute(current_user, params.merge(project_id: @project.id))
- end
-
# Since iids are implemented only in 6.1
# user may navigate to issue page using old global ids.
#
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 20a733b10e1..4d6f41e9de5 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -17,18 +17,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
def index
- params[:sort] ||= 'newest'
- params[:scope] = 'all' if params[:scope].blank?
- params[:state] = 'opened' if params[:state].blank?
+ set_filter_variables(@project.merge_requests)
@merge_requests = MergeRequestsFinder.new.execute(current_user, params.merge(project_id: @project.id))
@merge_requests = @merge_requests.page(params[:page]).per(20)
-
- @sort = params[:sort].humanize
- assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
- @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
- @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
- @assignees = User.where(id: @project.merge_requests.pluck(:assignee_id))
end
def show
@@ -225,6 +217,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@allowed_to_merge = allowed_to_merge?
@show_merge_controls = @merge_request.open? && @commits.any? && @allowed_to_merge
@source_branch = @merge_request.source_project.repository.find_branch(@merge_request.source_branch).try(:name)
+
+ if @merge_request.locked_long_ago?
+ @merge_request.unlock_mr
+ @merge_request.close
+ end
end
def allowed_to_merge?
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index d338cdedfaf..f362f449e70 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -103,7 +103,9 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def module_enabled
- return render_404 unless @project.issues_enabled
+ unless @project.issues_enabled || @project.merge_requests_enabled
+ return render_404
+ end
end
def milestone_params
diff --git a/app/controllers/projects/network_controller.rb b/app/controllers/projects/network_controller.rb
index 9832495c64f..ada1aed0df7 100644
--- a/app/controllers/projects/network_controller.rb
+++ b/app/controllers/projects/network_controller.rb
@@ -3,8 +3,7 @@ class Projects::NetworkController < Projects::ApplicationController
include ApplicationHelper
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
def show
diff --git a/app/controllers/projects/new_tree_controller.rb b/app/controllers/projects/new_tree_controller.rb
index 71a5c6499ec..ffba706b2f6 100644
--- a/app/controllers/projects/new_tree_controller.rb
+++ b/app/controllers/projects/new_tree_controller.rb
@@ -1,6 +1,6 @@
class Projects::NewTreeController < Projects::BaseTreeController
before_filter :require_branch_head
- before_filter :authorize_push!
+ before_filter :authorize_push_code!
def show
end
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 5ec9c576a66..fdbc4c5a098 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -3,8 +3,7 @@ class Projects::RawController < Projects::ApplicationController
include ExtractsPath
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
def show
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 7997c726fbb..5d9336bdc49 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -2,8 +2,7 @@ class Projects::RefsController < Projects::ApplicationController
include ExtractsPath
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
+ before_filter :authorize_download_code!
before_filter :require_non_empty_project
def switch
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index 4e0f190ed1c..3a90c1c806d 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -1,8 +1,14 @@
class Projects::RepositoriesController < Projects::ApplicationController
# Authorize
- before_filter :authorize_read_project!
- before_filter :authorize_code_access!
- before_filter :require_non_empty_project
+ before_filter :authorize_download_code!
+ before_filter :require_non_empty_project, except: :create
+ before_filter :authorize_admin_project!, only: :create
+
+ def create
+ @project.create_repository
+
+ redirect_to @project
+ end
def archive
unless can?(current_user, :download_code, @project)
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index b50f6286459..c50a1f1e75b 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -41,7 +41,8 @@ class Projects::ServicesController < Projects::ApplicationController
params.require(:service).permit(
:title, :token, :type, :active, :api_key, :subdomain,
:room, :recipients, :project_url, :webhook,
- :user_key, :device, :priority, :sound
+ :user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
+ :build_key, :server
)
end
end
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 537c94bda20..162ddef0fec 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -1,10 +1,8 @@
class Projects::TagsController < Projects::ApplicationController
# Authorize
- before_filter :authorize_read_project!
before_filter :require_non_empty_project
-
- before_filter :authorize_code_access!
- before_filter :authorize_push!, only: [:create]
+ before_filter :authorize_download_code!
+ before_filter :authorize_push_code!, only: [:create]
before_filter :authorize_admin_project!, only: [:destroy]
def index
diff --git a/app/controllers/projects/team_members_controller.rb b/app/controllers/projects/team_members_controller.rb
index 7bb799eba64..0791e6080fb 100644
--- a/app/controllers/projects/team_members_controller.rb
+++ b/app/controllers/projects/team_members_controller.rb
@@ -10,7 +10,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def new
- @user_project_relation = project.project_members.new
+ @user_project_relation = @project.project_members.new
end
def create
@@ -26,7 +26,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def update
- @user_project_relation = project.project_members.find_by(user_id: member)
+ @user_project_relation = @project.project_members.find_by(user_id: member)
@user_project_relation.update_attributes(member_params)
unless @user_project_relation.valid?
@@ -36,7 +36,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def destroy
- @user_project_relation = project.project_members.find_by(user_id: member)
+ @user_project_relation = @project.project_members.find_by(user_id: member)
@user_project_relation.destroy
respond_to do |format|
@@ -46,7 +46,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def leave
- project.project_members.find_by(user_id: current_user).destroy
+ @project.project_members.find_by(user_id: current_user).destroy
respond_to do |format|
format.html { redirect_to :back }
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index aca091e7d2c..fcff6952d38 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -4,9 +4,7 @@ class ProjectsController < ApplicationController
before_filter :repository, except: [:new, :create]
# Authorize
- before_filter :authorize_read_project!, except: [:index, :new, :create]
- before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive, :retry_import]
- before_filter :require_non_empty_project, only: [:blob, :tree, :graph]
+ before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive]
layout 'navless', only: [:new, :create, :fork]
before_filter :set_title, only: [:new, :create]
@@ -21,10 +19,11 @@ class ProjectsController < ApplicationController
def create
@project = ::Projects::CreateService.new(current_user, project_params).execute
- flash[:notice] = 'Project was successfully created.' if @project.saved?
- respond_to do |format|
- format.js
+ if @project.saved?
+ redirect_to project_path(@project), notice: 'Project was successfully created.'
+ else
+ render 'new'
end
end
@@ -49,12 +48,10 @@ class ProjectsController < ApplicationController
def show
if @project.import_in_progress?
- redirect_to import_project_path(@project)
+ redirect_to project_import_path(@project)
return
end
- return authenticate_user! unless @project.public? || current_user
-
limit = (params[:limit] || 20).to_i
@events = @project.events.recent
@events = event_filter.apply_filter(@events)
@@ -64,41 +61,24 @@ class ProjectsController < ApplicationController
respond_to do |format|
format.html do
- if @project.empty_repo?
- render "projects/empty", layout: user_layout
+ if @project.repository_exists?
+ if @project.empty_repo?
+ render "projects/empty", layout: user_layout
+ else
+ @last_push = current_user.recent_push(@project.id) if current_user
+ render :show, layout: user_layout
+ end
else
- @last_push = current_user.recent_push(@project.id) if current_user
- render :show, layout: user_layout
+ render "projects/no_repo", layout: user_layout
end
end
- format.json { pager_json("events/_events", @events.count) }
- end
- end
-
- def import
- if project.import_finished?
- redirect_to @project
- return
- end
- end
-
- def retry_import
- unless @project.import_failed?
- redirect_to import_project_path(@project)
- end
-
- @project.import_url = project_params[:import_url]
- if @project.save
- @project.reload
- @project.import_retry
+ format.json { pager_json("events/_events", @events.count) }
end
-
- redirect_to import_project_path(@project)
end
def destroy
- return access_denied! unless can?(current_user, :remove_project, project)
+ return access_denied! unless can?(current_user, :remove_project, @project)
::Projects::DestroyService.new(@project, current_user, {}).execute
@@ -115,22 +95,6 @@ class ProjectsController < ApplicationController
end
end
- def fork
- @forked_project = ::Projects::ForkService.new(project, current_user).execute
-
- respond_to do |format|
- format.html do
- if @forked_project.saved? && @forked_project.forked?
- redirect_to(@forked_project, notice: 'Project was successfully forked.')
- else
- @title = 'Fork project'
- render "fork"
- end
- end
- format.js
- end
- end
-
def autocomplete_sources
note_type = params['type']
note_id = params['type_id']
@@ -148,8 +112,8 @@ class ProjectsController < ApplicationController
end
def archive
- return access_denied! unless can?(current_user, :archive_project, project)
- project.archive!
+ return access_denied! unless can?(current_user, :archive_project, @project)
+ @project.archive!
respond_to do |format|
format.html { redirect_to @project }
@@ -157,8 +121,8 @@ class ProjectsController < ApplicationController
end
def unarchive
- return access_denied! unless can?(current_user, :archive_project, project)
- project.unarchive!
+ return access_denied! unless can?(current_user, :archive_project, @project)
+ @project.unarchive!
respond_to do |format|
format.html { redirect_to @project }
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 30fb4c5552d..bf3312fedc8 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -9,7 +9,7 @@ class SnippetsController < ApplicationController
before_filter :set_title
- skip_before_filter :authenticate_user!, only: [:index, :user_index]
+ skip_before_filter :authenticate_user!, only: [:index, :user_index, :show, :raw]
respond_to :html
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 0b442f5383a..67af1801bda 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -20,9 +20,14 @@ class UsersController < ApplicationController
# Get user activity feed for projects common for both users
@events = @user.recent_events.
- where(project_id: authorized_projects_ids).limit(20)
+ where(project_id: authorized_projects_ids).limit(30)
@title = @user.name
+
+ respond_to do |format|
+ format.html
+ format.atom { render layout: false }
+ end
end
def determine_layout
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 56c4f22120d..e1477510065 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -33,6 +33,7 @@ class IssuableFinder
items = by_search(items)
items = by_milestone(items)
items = by_assignee(items)
+ items = by_author(items)
items = by_label(items)
items = sort(items)
end
@@ -48,7 +49,7 @@ class IssuableFinder
else
[]
end
- elsif current_user && params[:authorized_only].presence
+ elsif current_user && params[:authorized_only].presence && !current_user_related?
klass.of_projects(current_user.authorized_projects).references(:project)
else
klass.of_projects(ProjectsFinder.new.execute(current_user)).references(:project)
@@ -125,6 +126,14 @@ class IssuableFinder
items
end
+ def by_author(items)
+ if params[:author_id].present?
+ items = items.where(author_id: (params[:author_id] == '0' ? nil : params[:author_id]))
+ end
+
+ items
+ end
+
def by_label(items)
if params[:label_name].present?
label_names = params[:label_name].split(",")
@@ -142,4 +151,8 @@ class IssuableFinder
def project
Project.where(id: params[:project_id]).first if params[:project_id].present?
end
+
+ def current_user_related?
+ params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
+ end
end
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index b29ab6cf40b..4b0c69f2d2f 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -29,6 +29,8 @@ class SnippetsFinder
def by_user(current_user, user, scope)
snippets = user.snippets.fresh.non_expired
+ return snippets.are_public unless current_user
+
if user == current_user
case scope
when 'are_internal' then
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 11fbf1baae7..420ac3f77c7 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -1,14 +1,9 @@
module BlobHelper
def highlightjs_class(blob_name)
- if blob_name.include?('.')
- ext = blob_name.split('.').last
- return 'language-' + ext
+ if no_highlight_files.include?(blob_name.downcase)
+ 'no-highlight'
else
- if no_highlight_files.include?(blob_name.downcase)
- 'no-highlight'
- else
- blob_name.downcase
- end
+ blob_name.downcase
end
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 0e0532b65b2..36adeadd8a5 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -87,8 +87,8 @@ module CommitsHelper
# avatar: true will prepend the avatar image
# size: size of the avatar image in px
def commit_person_link(commit, options = {})
- source_name = commit.send "#{options[:source]}_name".to_sym
- source_email = commit.send "#{options[:source]}_email".to_sym
+ source_name = clean(commit.send "#{options[:source]}_name".to_sym)
+ source_email = clean(commit.send "#{options[:source]}_email".to_sym)
user = User.find_for_commit(source_email, source_name)
person_name = user.nil? ? source_name : user.name
@@ -124,4 +124,8 @@ module CommitsHelper
def truncate_sha(sha)
Commit.truncate_sha(sha)
end
+
+ def clean(string)
+ Sanitize.clean(string, remove_contents: true)
+ end
end
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
new file mode 100644
index 00000000000..24d67c21d6b
--- /dev/null
+++ b/app/helpers/emails_helper.rb
@@ -0,0 +1,32 @@
+module EmailsHelper
+
+ # Google Actions
+ # https://developers.google.com/gmail/markup/reference/go-to-action
+ def email_action(url)
+ name = action_title(url)
+ if name
+ data = {
+ "@context" => "http://schema.org",
+ "@type" => "EmailMessage",
+ "action" => {
+ "@type" => "ViewAction",
+ "name" => name,
+ "url" => url,
+ }
+ }
+
+ content_tag :script, type: 'application/ld+json' do
+ data.to_json.html_safe
+ end
+ end
+ end
+
+ def action_title(url)
+ return unless url
+ ["merge_requests", "issues", "commit"].each do |action|
+ if url.split("/").include?(action)
+ return "View #{action.humanize.singularize}"
+ end
+ end
+ end
+end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 71f97fbb8c8..a3136926b38 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -145,4 +145,26 @@ module EventsHelper
rescue
"--broken encoding"
end
+
+ def event_to_atom(xml, event)
+ if event.proper?
+ xml.entry do
+ event_link = event_feed_url(event)
+ event_title = event_feed_title(event)
+ event_summary = event_feed_summary(event)
+
+ xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
+ xml.link href: event_link
+ xml.title truncate(event_title, length: 80)
+ xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
+ xml.media :thumbnail, width: "40", height: "40", url: avatar_icon(event.author_email)
+ xml.author do |author|
+ xml.name event.author_name
+ xml.email event.author_email
+ end
+
+ xml.summary(type: "xhtml") { |x| x << event_summary unless event_summary.nil? }
+ end
+ end
+ end
end
diff --git a/app/helpers/git_helper.rb b/app/helpers/git_helper.rb
new file mode 100644
index 00000000000..09684955233
--- /dev/null
+++ b/app/helpers/git_helper.rb
@@ -0,0 +1,5 @@
+module GitHelper
+ def strip_gpg_signature(text)
+ text.gsub(/-----BEGIN PGP SIGNATURE-----(.*)-----END PGP SIGNATURE-----/m, "")
+ end
+end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 7d3cb749829..800cacdc2c2 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -254,4 +254,16 @@ module GitlabMarkdownHelper
truncated
end
end
+
+ def cross_project_reference(project, entity)
+ path = project.path_with_namespace
+
+ if entity.kind_of?(Issue)
+ [path, entity.iid].join('#')
+ elsif entity.kind_of?(MergeRequest)
+ [path, entity.iid].join('!')
+ else
+ raise 'Not supported type'
+ end
+ end
end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 7671033b539..a5b393c1e3c 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -62,6 +62,19 @@ module IssuesHelper
''
end
+ def issue_timestamp(issue)
+ # Shows the created at time and the updated at time if different
+ ts = "#{time_ago_with_tooltip(issue.created_at, 'bottom', 'note_created_ago')}"
+ if issue.updated_at != issue.created_at
+ ts << capture_haml do
+ haml_tag :small do
+ haml_concat " (Edited #{time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_edited_ago')})"
+ end
+ end
+ end
+ ts.html_safe
+ end
+
# Checks if issues_tracker setting exists in gitlab.yml
def external_issues_tracker_enabled?
Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any?
@@ -100,4 +113,19 @@ module IssuesHelper
'issue-box-open'
end
end
+
+ def issue_to_atom(xml, issue)
+ xml.entry do
+ xml.id project_issue_url(issue.project, issue)
+ xml.link href: project_issue_url(issue.project, issue)
+ xml.title truncate(issue.title, length: 80)
+ xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
+ xml.media :thumbnail, width: "40", height: "40", url: avatar_icon(issue.author_email)
+ xml.author do |author|
+ xml.name issue.author_name
+ xml.email issue.author_email
+ end
+ xml.summary issue.title
+ end
+ end
end
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
index bf25dce2301..2bcfde62830 100644
--- a/app/helpers/namespaces_helper.rb
+++ b/app/helpers/namespaces_helper.rb
@@ -25,4 +25,12 @@ module NamespacesHelper
hidden_field_tag(id, value, class: css_class)
end
+
+ def namespace_icon(namespace, size = 40)
+ if namespace.kind_of?(Group)
+ group_icon(namespace.path)
+ else
+ avatar_icon(namespace.owner.email, size)
+ end
+ end
end
diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb
index 7024483b8b3..df18db71c84 100644
--- a/app/helpers/oauth_helper.rb
+++ b/app/helpers/oauth_helper.rb
@@ -16,4 +16,8 @@ module OauthHelper
[:twitter, :github, :google_oauth2].include?(name.to_sym)
end
end
+
+ def additional_providers
+ enabled_oauth_providers.reject{|provider| provider.to_s.starts_with?('ldap')}
+ end
end
diff --git a/app/helpers/profile_helper.rb b/app/helpers/profile_helper.rb
index 0b375558305..6480fd3886f 100644
--- a/app/helpers/profile_helper.rb
+++ b/app/helpers/profile_helper.rb
@@ -1,6 +1,6 @@
module ProfileHelper
def oauth_active_class(provider)
- if current_user.provider == provider.to_s
+ if current_user.identities.exists?(provider: provider.to_s)
'active'
end
end
@@ -10,10 +10,10 @@ module ProfileHelper
end
def show_profile_social_tab?
- enabled_social_providers.any? && !current_user.ldap_user?
+ enabled_social_providers.any?
end
def show_profile_remove_tab?
- gitlab_config.signup_enabled && !current_user.ldap_user?
+ gitlab_config.signup_enabled
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 883c1f63af6..fb5470d98e5 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -42,12 +42,12 @@ module ProjectsHelper
def project_title(project)
if project.group
content_tag :span do
- link_to(simple_sanitize(project.group.name), group_path(project.group)) + " / " + project.name
+ link_to(simple_sanitize(project.group.name), group_path(project.group)) + ' / ' + link_to(simple_sanitize(project.name), project_path(project))
end
else
owner = project.namespace.owner
content_tag :span do
- link_to(simple_sanitize(owner.name), user_path(owner)) + " / " + project.name
+ link_to(simple_sanitize(owner.name), user_path(owner)) + ' / ' + link_to(simple_sanitize(project.name), project_path(project))
end
end
end
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
new file mode 100644
index 00000000000..492e065b713
--- /dev/null
+++ b/app/helpers/sorting_helper.rb
@@ -0,0 +1,17 @@
+module SortingHelper
+ def sort_title_oldest_updated
+ 'Oldest updated'
+ end
+
+ def sort_title_recently_updated
+ 'Recently updated'
+ end
+
+ def sort_title_oldest_created
+ 'Oldest created'
+ end
+
+ def sort_title_recently_created
+ 'Recently created'
+ end
+end
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index 9c611a1c147..8e209498323 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -66,7 +66,7 @@ module TreeHelper
def tree_breadcrumbs(tree, max_links = 2)
if @path.present?
part_path = ""
- parts = @path.split("\/")
+ parts = @path.split('/')
yield('..', nil) if parts.count > max_links
diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb
index f8a7d133d1d..6d7f8eb4b02 100644
--- a/app/mailers/emails/profile.rb
+++ b/app/mailers/emails/profile.rb
@@ -1,8 +1,7 @@
module Emails
module Profile
- def new_user_email(user_id, password, token = nil)
+ def new_user_email(user_id, token = nil)
@user = User.find(user_id)
- @password = password
@target_url = user_url(@user)
@token = token
mail(to: @user.email, subject: subject("Account was created for you"))
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index bd438bab89a..6d671e6e0bd 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -11,6 +11,7 @@ class Notify < ActionMailer::Base
add_template_helper ApplicationHelper
add_template_helper GitlabMarkdownHelper
add_template_helper MergeRequestsHelper
+ add_template_helper EmailsHelper
default_url_options[:host] = Gitlab.config.gitlab.host
default_url_options[:protocol] = Gitlab.config.gitlab.protocol
@@ -25,6 +26,14 @@ class Notify < ActionMailer::Base
delay_for(2.seconds)
end
+ def test_email(recepient_email, subject, body)
+ mail(to: recepient_email,
+ subject: subject,
+ body: body.html_safe,
+ content_type: 'text/html'
+ )
+ end
+
private
# The default email address to send emails from
diff --git a/app/models/ability.rb b/app/models/ability.rb
index e155abc1449..97a72bf3635 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -262,5 +262,13 @@ class Ability
end
rules
end
+
+ def abilities
+ @abilities ||= begin
+ abilities = Six.new
+ abilities << self
+ abilities
+ end
+ end
end
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 553087946d6..f49708fd6eb 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -131,9 +131,10 @@ module Issuable
users.concat(mentions.reduce([], :|)).uniq
end
- def to_hook_data
+ def to_hook_data(user)
{
object_kind: self.class.name.underscore,
+ user: user.hook_attrs,
object_attributes: hook_attrs
}
end
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index 5938d9cb28e..6c1aa99668a 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -52,11 +52,7 @@ module Mentionable
if identifier == "all"
users += project.team.members.flatten
else
- if has_project
- id = project.team.members.find_by(username: identifier).try(:id)
- else
- id = User.find_by(username: identifier).try(:id)
- end
+ id = User.find_by(username: identifier).try(:id)
users << User.find(id) unless id.blank?
end
end
diff --git a/app/models/event.rb b/app/models/event.rb
index c0b126713a6..65b4c2edfee 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -186,10 +186,6 @@ class Event < ActiveRecord::Base
data[:ref]["refs/heads"]
end
- def new_branch?
- commit_from =~ /^00000/
- end
-
def new_ref?
commit_from =~ /^00000/
end
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index 23fa01e0b70..8479d4aecf6 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -32,7 +32,10 @@ class WebHook < ActiveRecord::Base
def execute(data)
parsed_url = URI.parse(url)
if parsed_url.userinfo.blank?
- WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }, verify: false)
+ WebHook.post(url,
+ body: data.to_json,
+ headers: { "Content-Type" => "application/json" },
+ verify: false)
else
post_url = url.gsub("#{parsed_url.userinfo}@", "")
auth = {
@@ -45,6 +48,9 @@ class WebHook < ActiveRecord::Base
verify: false,
basic_auth: auth)
end
+ rescue SocketError, Errno::ECONNREFUSED => e
+ logger.error("WebHook Error => #{e}")
+ false
end
def async_execute(data)
diff --git a/app/models/identity.rb b/app/models/identity.rb
new file mode 100644
index 00000000000..5fb1850c30b
--- /dev/null
+++ b/app/models/identity.rb
@@ -0,0 +1,5 @@
+class Identity < ActiveRecord::Base
+ belongs_to :user
+
+ validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
+end \ No newline at end of file
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 7c525b02f48..2cc427d35c2 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -70,6 +70,16 @@ class MergeRequest < ActiveRecord::Base
transition locked: :reopened
end
+ after_transition any => :locked do |merge_request, transition|
+ merge_request.locked_at = Time.now
+ merge_request.save
+ end
+
+ after_transition :locked => (any - :locked) do |merge_request, transition|
+ merge_request.locked_at = nil
+ merge_request.save
+ end
+
state :opened
state :reopened
state :closed
@@ -336,4 +346,8 @@ class MergeRequest < ActiveRecord::Base
source_project.repository.branch_names
end
end
+
+ def locked_long_ago?
+ locked_at && locked_at < (Time.now - 1.day)
+ end
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index c0c6de0ee7d..ea4b48fdd7f 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -90,4 +90,8 @@ class Namespace < ActiveRecord::Base
def kind
type == 'Group' ? 'group' : 'user'
end
+
+ def find_fork_of(project)
+ projects.joins(:forked_project_link).where('forked_project_links.forked_from_project_id = ?', project.id).first
+ end
end
diff --git a/app/models/note.rb b/app/models/note.rb
index 6f1b1a4da94..5bf645bbd1d 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -80,7 +80,7 @@ class Note < ActiveRecord::Base
note_options = {
project: project,
author: author,
- note: "_mentioned in #{gfm_reference}_",
+ note: cross_reference_note_content(gfm_reference),
system: true
}
@@ -90,7 +90,7 @@ class Note < ActiveRecord::Base
note_options.merge!(noteable: noteable)
end
- create(note_options)
+ create(note_options) unless cross_reference_disallowed?(noteable, mentioner)
end
def create_milestone_change_note(noteable, project, author, milestone)
@@ -165,6 +165,15 @@ class Note < ActiveRecord::Base
[:discussion, type.try(:underscore), id, line_code].join("-").to_sym
end
+ # Determine if cross reference note should be created.
+ # eg. mentioning a commit in MR comments which exists inside a MR
+ # should not create "mentioned in" note.
+ def cross_reference_disallowed?(noteable, mentioner)
+ if mentioner.kind_of?(MergeRequest)
+ mentioner.commits.map(&:id).include? noteable.id
+ end
+ end
+
# Determine whether or not a cross-reference note already exists.
def cross_reference_exists?(noteable, mentioner)
gfm_reference = mentioner_gfm_ref(noteable, mentioner)
@@ -174,7 +183,7 @@ class Note < ActiveRecord::Base
where(noteable_id: noteable.id)
end
- notes.where('note like ?', "_mentioned in #{gfm_reference}_").
+ notes.where('note like ?', cross_reference_note_content(gfm_reference)).
system.any?
end
@@ -182,8 +191,16 @@ class Note < ActiveRecord::Base
where("note like :query", query: "%#{query}%")
end
+ def cross_reference_note_prefix
+ '_mentioned in '
+ end
+
private
+ def cross_reference_note_content(gfm_reference)
+ cross_reference_note_prefix + "#{gfm_reference}_"
+ end
+
# Prepend the mentioner's namespaced project path to the GFM reference for
# cross-project references. For same-project references, return the
# unmodified GFM reference.
@@ -243,12 +260,16 @@ class Note < ActiveRecord::Base
def commit_author
@commit_author ||=
- project.users.find_by(email: noteable.author_email) ||
- project.users.find_by(name: noteable.author_name)
+ project.team.users.find_by(email: noteable.author_email) ||
+ project.team.users.find_by(name: noteable.author_name)
rescue
nil
end
+ def cross_reference?
+ note.start_with?(self.class.cross_reference_note_prefix)
+ end
+
def find_diff
return nil unless noteable && noteable.diffs.present?
@@ -296,7 +317,7 @@ class Note < ActiveRecord::Base
end
def diff_file_index
- line_code.split('_')[0]
+ line_code.split('_')[0] if line_code
end
def diff_file_name
@@ -312,11 +333,11 @@ class Note < ActiveRecord::Base
end
def diff_old_line
- line_code.split('_')[1].to_i
+ line_code.split('_')[1].to_i if line_code
end
def diff_new_line
- line_code.split('_')[2].to_i
+ line_code.split('_')[2].to_i if line_code
end
def generate_line_code(line)
@@ -337,6 +358,20 @@ class Note < ActiveRecord::Base
@diff_line
end
+ def diff_line_type
+ return @diff_line_type if @diff_line_type
+
+ if diff
+ diff_lines.each do |line|
+ if generate_line_code(line) == self.line_code
+ @diff_line_type = line.type
+ end
+ end
+ end
+
+ @diff_line_type
+ end
+
def truncated_diff_lines
max_number_of_lines = 16
prev_match_line = nil
diff --git a/app/models/project.rb b/app/models/project.rb
index 90d2649ba23..32b0145ca24 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -65,6 +65,7 @@ class Project < ActiveRecord::Base
has_one :gemnasium_service, dependent: :destroy
has_one :slack_service, dependent: :destroy
has_one :buildbox_service, dependent: :destroy
+ has_one :bamboo_service, dependent: :destroy
has_one :pushover_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link
@@ -135,7 +136,7 @@ class Project < ActiveRecord::Base
state_machine :import_status, initial: :none do
event :import_start do
- transition :none => :started
+ transition [:none, :finished] => :started
end
event :import_finish do
@@ -173,7 +174,7 @@ class Project < ActiveRecord::Base
end
def with_push
- includes(:events).where('events.action = ?', Event::PUSHED)
+ joins(:events).where('events.action = ?', Event::PUSHED)
end
def active
@@ -313,7 +314,7 @@ class Project < ActiveRecord::Base
end
def available_services_names
- %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack pushover buildbox)
+ %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack pushover buildbox bamboo)
end
def gitlab_ci?
@@ -389,55 +390,14 @@ class Project < ActiveRecord::Base
end
def execute_services(data)
- services.each do |service|
-
- # Call service hook only if it is active
- begin
- service.execute(data) if service.active
- rescue => e
- logger.error(e)
- end
+ services.select(&:active).each do |service|
+ service.async_execute(data)
end
end
def update_merge_requests(oldrev, newrev, ref, user)
- return true unless ref =~ /heads/
- branch_name = ref.gsub("refs/heads/", "")
- commits = self.repository.commits_between(oldrev, newrev)
- c_ids = commits.map(&:id)
-
- # Close merge requests
- mrs = self.merge_requests.opened.where(target_branch: branch_name).to_a
- mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
-
- mrs.uniq.each do |merge_request|
- MergeRequests::MergeService.new.execute(merge_request, user, nil)
- end
-
- # Update code for merge requests into project between project branches
- mrs = self.merge_requests.opened.by_branch(branch_name).to_a
- # Update code for merge requests between project and project fork
- mrs += self.fork_merge_requests.opened.by_branch(branch_name).to_a
-
- mrs.uniq.each do |merge_request|
- merge_request.reload_code
- merge_request.mark_as_unchecked
- end
-
- # Add comment about pushing new commits to merge requests
- comment_mr_with_commits(branch_name, commits, user)
-
- true
- end
-
- def comment_mr_with_commits(branch_name, commits, user)
- mrs = self.origin_merge_requests.opened.where(source_branch: branch_name).to_a
- mrs += self.fork_merge_requests.opened.where(source_branch: branch_name).to_a
-
- mrs.uniq.each do |merge_request|
- Note.create_new_commits_note(merge_request, merge_request.project,
- user, commits)
- end
+ MergeRequests::RefreshService.new(self, user).
+ execute(oldrev, newrev, ref)
end
def valid_repo?
@@ -620,4 +580,25 @@ class Project < ActiveRecord::Base
def origin_merge_requests
merge_requests.where(source_project_id: self.id)
end
+
+ def create_repository
+ if gitlab_shell.add_repository(path_with_namespace)
+ true
+ else
+ errors.add(:base, "Failed to create repository")
+ false
+ end
+ end
+
+ def repository_exists?
+ !!repository.exists?
+ end
+
+ def create_wiki
+ ProjectWiki.new(self, self.owner).wiki
+ true
+ rescue ProjectWiki::CouldNotCreateWikiError => ex
+ errors.add(:base, "Failed create wiki")
+ false
+ end
end
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
new file mode 100644
index 00000000000..b9eec9ab21e
--- /dev/null
+++ b/app/models/project_services/bamboo_service.rb
@@ -0,0 +1,105 @@
+class BambooService < CiService
+ include HTTParty
+
+ prop_accessor :bamboo_url, :build_key, :username, :password
+
+ validates :bamboo_url, presence: true,
+ format: { with: URI::regexp }, if: :activated?
+ validates :build_key, presence: true, if: :activated?
+ validates :username, presence: true,
+ if: ->(service) { service.password? }, if: :activated?
+ validates :password, presence: true,
+ if: ->(service) { service.username? }, if: :activated?
+
+ attr_accessor :response
+
+ after_save :compose_service_hook, if: :activated?
+
+ def compose_service_hook
+ hook = service_hook || build_service_hook
+ hook.save
+ end
+
+ def title
+ 'Atlassian Bamboo CI'
+ end
+
+ def description
+ 'A continuous integration and build server'
+ end
+
+ def help
+ 'You must set up automatic revision labeling and a repository trigger in Bamboo.'
+ end
+
+ def to_param
+ 'bamboo'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'bamboo_url',
+ placeholder: 'Bamboo root URL like https://bamboo.example.com' },
+ { type: 'text', name: 'build_key',
+ placeholder: 'Bamboo build plan key like KEY' },
+ { type: 'text', name: 'username',
+ placeholder: 'A user with API access, if applicable' },
+ { type: 'password', name: 'password' },
+ ]
+ end
+
+ def build_info(sha)
+ url = URI.parse("#{bamboo_url}/rest/api/latest/result?label=#{sha}")
+
+ if username.blank? && password.blank?
+ @response = HTTParty.get(parsed_url.to_s, verify: false)
+ else
+ get_url = "#{url}&os_authType=basic"
+ auth = {
+ username: username,
+ password: password,
+ }
+ @response = HTTParty.get(get_url, verify: false, basic_auth: auth)
+ end
+ end
+
+ def build_page(sha)
+ build_info(sha) if @response.nil? || !@response.code
+
+ if @response.code != 200 || @response['results']['results']['size'] == '0'
+ # If actual build link can't be determined, send user to build summary page.
+ "#{bamboo_url}/browse/#{build_key}"
+ else
+ # If actual build link is available, go to build result page.
+ result_key = @response['results']['results']['result']['planResultKey']['key']
+ "#{bamboo_url}/browse/#{result_key}"
+ end
+ end
+
+ def commit_status(sha)
+ build_info(sha) if @response.nil? || !@response.code
+ return :error unless @response.code == 200 || @response.code == 404
+
+ status = if @response.code == 404 || @response['results']['results']['size'] == '0'
+ 'Pending'
+ else
+ @response['results']['results']['result']['buildState']
+ end
+
+ if status.include?('Success')
+ 'success'
+ elsif status.include?('Failed')
+ 'failed'
+ elsif status.include?('Pending')
+ 'pending'
+ else
+ :error
+ end
+ end
+
+ def execute(_data)
+ # Bamboo requires a GET and does not take any data.
+ self.class.get("#{bamboo_url}/updateAndBuild.action?buildKey=#{build_key}",
+ verify: false)
+ end
+end
diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildbox_service.rb
index b0f8e28c97f..0ab67b79fe4 100644
--- a/app/models/project_services/buildbox_service.rb
+++ b/app/models/project_services/buildbox_service.rb
@@ -12,6 +12,8 @@
# properties :text
#
+require "addressable/uri"
+
class BuildboxService < CiService
prop_accessor :project_url, :token
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 0020b4482e5..86705f5dabd 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -37,13 +37,12 @@ class FlowdockService < Service
end
def execute(push_data)
- repo_path = File.join(Gitlab.config.gitlab_shell.repos_path, "#{project.path_with_namespace}.git")
Flowdock::Git.post(
push_data[:ref],
push_data[:before],
push_data[:after],
token: token,
- repo: repo_path,
+ repo: project.repository.path_to_repo,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s",
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
index 6d2fc06a5d0..18fdd204ecd 100644
--- a/app/models/project_services/gemnasium_service.rb
+++ b/app/models/project_services/gemnasium_service.rb
@@ -38,14 +38,13 @@ class GemnasiumService < Service
end
def execute(push_data)
- repo_path = File.join(Gitlab.config.gitlab_shell.repos_path, "#{project.path_with_namespace}.git")
Gemnasium::GitlabService.execute(
ref: push_data[:ref],
before: push_data[:before],
after: push_data[:after],
token: token,
api_key: api_key,
- repo: repo_path
+ repo: project.repository.path_to_repo
)
end
end
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index a897c4ab76b..fadebf968bc 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -28,7 +28,7 @@ class GitlabCiService < CiService
end
def commit_status_path(sha)
- project_url + "/builds/#{sha}/status.json?token=#{token}"
+ project_url + "/commits/#{sha}/status.json?token=#{token}"
end
def get_ci_build(sha)
@@ -55,7 +55,7 @@ class GitlabCiService < CiService
end
def build_page(sha)
- project_url + "/builds/#{sha}"
+ project_url + "/commits/#{sha}"
end
def builds_path
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 4078938cdbb..a848d74044c 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -15,11 +15,11 @@
class HipchatService < Service
MAX_COMMITS = 3
- prop_accessor :token, :room
+ prop_accessor :token, :room, :server
validates :token, presence: true, if: :activated?
def title
- 'Hipchat'
+ 'HipChat'
end
def description
@@ -33,7 +33,9 @@ class HipchatService < Service
def fields
[
{ type: 'text', name: 'token', placeholder: '' },
- { type: 'text', name: 'room', placeholder: '' }
+ { type: 'text', name: 'room', placeholder: '' },
+ { type: 'text', name: 'server',
+ placeholder: 'Leave blank for default. https://chat.hipchat.com' }
]
end
@@ -44,7 +46,9 @@ class HipchatService < Service
private
def gate
- @gate ||= HipChat::Client.new(token)
+ options = { api_version: 'v2' }
+ options[:server_url] = server unless server.nil?
+ @gate ||= HipChat::Client.new(token, options)
end
def create_message(push)
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index 95f3ddcef45..963f5440b6f 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -30,23 +30,20 @@ class SlackService < Service
def fields
[
- { type: 'text', name: 'webhook', placeholder: '' }
+ { type: 'text', name: 'webhook', placeholder: 'https://hooks.slack.com/services/...' }
]
end
def execute(push_data)
+ return unless webhook.present?
+
message = SlackMessage.new(push_data.merge(
project_url: project_url,
project_name: project_name
))
- credentials = webhook.match(/(\w*).slack.com.*services\/(.*)/)
- if credentials.present?
- subdomain = credentials[1]
- token = credentials[2].split("token=").last
- notifier = Slack::Notifier.new(subdomain, token)
- notifier.ping(message.pretext, attachments: message.attachments)
- end
+ notifier = Slack::Notifier.new(webhook)
+ notifier.ping(message.pretext, attachments: message.attachments)
end
private
diff --git a/app/models/service.rb b/app/models/service.rb
index c489c1e96e1..71c8aa39e45 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -82,4 +82,8 @@ class Service < ActiveRecord::Base
}
end
end
+
+ def async_execute(data)
+ Sidekiq::Client.enqueue(ProjectServiceWorker, id, data)
+ end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 42faea0070e..7faeef1b5b0 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -79,6 +79,7 @@ class User < ActiveRecord::Base
# Profile
has_many :keys, dependent: :destroy
has_many :emails, dependent: :destroy
+ has_many :identities, dependent: :destroy
# Groups
has_many :members, dependent: :destroy
@@ -113,7 +114,6 @@ class User < ActiveRecord::Base
validates :name, presence: true
validates :email, presence: true, email: {strict_mode: true}, uniqueness: true
validates :bio, length: { maximum: 255 }, allow_blank: true
- validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
validates :username, presence: true, uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path },
@@ -124,7 +124,7 @@ class User < ActiveRecord::Base
validate :namespace_uniq, if: ->(user) { user.username_changed? }
validate :avatar_type, if: ->(user) { user.avatar_changed? }
validate :unique_email, if: ->(user) { user.email_changed? }
- validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
+ validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
before_validation :generate_password, on: :create
before_validation :sanitize_attrs
@@ -178,7 +178,6 @@ class User < ActiveRecord::Base
scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) }
scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') }
- scope :ldap, -> { where('provider LIKE ?', 'ldap%') }
scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active }
#
@@ -226,6 +225,11 @@ class User < ActiveRecord::Base
where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%")
end
+ def by_login(login)
+ where('lower(username) = :value OR lower(email) = :value',
+ value: login.to_s.downcase).first
+ end
+
def by_username_or_id(name_or_id)
where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
end
@@ -330,11 +334,7 @@ class User < ActiveRecord::Base
end
def abilities
- @abilities ||= begin
- abilities = Six.new
- abilities << Ability
- abilities
- end
+ Ability.abilities
end
def can_select_namespace?
@@ -406,7 +406,11 @@ class User < ActiveRecord::Base
end
def ldap_user?
- extern_uid && provider.start_with?('ldap')
+ identities.exists?(["provider LIKE ? AND extern_uid IS NOT NULL", "ldap%"])
+ end
+
+ def ldap_identity
+ @ldap_identity ||= identities.find_by(["provider LIKE ?", "ldap%"])
end
def accessible_deploy_keys
@@ -497,6 +501,14 @@ class User < ActiveRecord::Base
end
end
+ def hook_attrs
+ {
+ name: name,
+ username: username,
+ avatar_url: avatar_url
+ }
+ end
+
def ensure_namespace_correct
# Ensure user has namespace
self.create_namespace!(path: self.username, name: self.username) unless self.namespace
@@ -542,4 +554,14 @@ class User < ActiveRecord::Base
UsersStarProject.create!(project: project, user: self)
end
end
+
+ def manageable_namespaces
+ @manageable_namespaces ||=
+ begin
+ namespaces = []
+ namespaces << namespace
+ namespaces += owned_groups
+ namespaces += masters_groups
+ end
+ end
end
diff --git a/app/services/base_service.rb b/app/services/base_service.rb
index ed286c04095..0d46eeaa18f 100644
--- a/app/services/base_service.rb
+++ b/app/services/base_service.rb
@@ -6,11 +6,7 @@ class BaseService
end
def abilities
- @abilities ||= begin
- abilities = Six.new
- abilities << Ability
- abilities
- end
+ Ability.abilities
end
def can?(object, action, subject)
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index db6f0831f8b..bd245100955 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -10,12 +10,6 @@ module Files
private
- def success
- out = super()
- out[:error] = ''
- out
- end
-
def repository
project.repository
end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 8f2b0e347f6..529af1970f6 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -83,9 +83,14 @@ class GitPushService
# closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
# a different branch.
issues_to_close = commit.closes_issues(project)
- author = commit_user(commit)
- if !issues_to_close.empty? && is_default_branch
+ # Load commit author only if needed.
+ # For push with 1k commits it prevents 900+ requests in database
+ author = nil
+
+ if issues_to_close.present? && is_default_branch
+ author ||= commit_user(commit)
+
issues_to_close.each do |issue|
Issues::CloseService.new(project, author, {}).execute(issue, commit)
end
@@ -96,8 +101,13 @@ class GitPushService
# being pushed to a different branch).
refs = commit.references(project) - issues_to_close
refs.reject! { |r| commit.has_mentioned?(r) }
- refs.each do |r|
- Note.create_cross_reference_note(r, commit, author, project)
+
+ if refs.present?
+ author ||= commit_user(commit)
+
+ refs.each do |r|
+ Note.create_cross_reference_note(r, commit, author, project)
+ end
end
end
end
@@ -160,19 +170,19 @@ class GitPushService
ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits)
- ref_parts[1] =~ /heads/ && oldrev != "0000000000000000000000000000000000000000"
+ ref_parts[1] =~ /heads/ && oldrev != Gitlab::Git::BLANK_SHA
end
def push_to_new_branch?(ref, oldrev)
ref_parts = ref.split('/')
- ref_parts[1] =~ /heads/ && oldrev == "0000000000000000000000000000000000000000"
+ ref_parts[1] =~ /heads/ && oldrev == Gitlab::Git::BLANK_SHA
end
def push_remove_branch?(ref, newrev)
ref_parts = ref.split('/')
- ref_parts[1] =~ /heads/ && newrev == "0000000000000000000000000000000000000000"
+ ref_parts[1] =~ /heads/ && newrev == Gitlab::Git::BLANK_SHA
end
def push_to_branch?(ref)
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index 41948f226a6..755c0ef45a8 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -4,7 +4,7 @@ module Issues
private
def execute_hooks(issue, action = 'open')
- issue_data = issue.to_hook_data
+ issue_data = issue.to_hook_data(current_user)
issue_url = Gitlab::UrlBuilder.new(:issue).build(issue.id)
issue_data[:object_attributes].merge!(url: issue_url, action: action)
issue.project.execute_hooks(issue_data, :issue_hooks)
diff --git a/app/services/merge_requests/base_merge_service.rb b/app/services/merge_requests/base_merge_service.rb
index 9bc50d3d16c..700a21ca011 100644
--- a/app/services/merge_requests/base_merge_service.rb
+++ b/app/services/merge_requests/base_merge_service.rb
@@ -13,7 +13,8 @@ module MergeRequests
def execute_project_hooks(merge_request)
if merge_request.project
- merge_request.project.execute_hooks(merge_request.to_hook_data, :merge_request_hooks)
+ hook_data = merge_request.to_hook_data(current_user)
+ merge_request.project.execute_hooks(hook_data, :merge_request_hooks)
end
end
end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 694994001b0..7f3421b8e4b 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -7,7 +7,8 @@ module MergeRequests
def execute_hooks(merge_request)
if merge_request.project
- merge_request.project.execute_hooks(merge_request.to_hook_data, :merge_request_hooks)
+ hook_data = merge_request.to_hook_data(current_user)
+ merge_request.project.execute_hooks(hook_data, :merge_request_hooks)
end
end
end
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
new file mode 100644
index 00000000000..baf0936cc3d
--- /dev/null
+++ b/app/services/merge_requests/refresh_service.rb
@@ -0,0 +1,86 @@
+module MergeRequests
+ class RefreshService < MergeRequests::BaseService
+ def execute(oldrev, newrev, ref)
+ return true unless ref =~ /heads/
+
+ @oldrev, @newrev = oldrev, newrev
+ @branch_name = ref.gsub("refs/heads/", "")
+ @fork_merge_requests = @project.fork_merge_requests.opened
+ @commits = @project.repository.commits_between(oldrev, newrev)
+
+ close_merge_requests
+ reload_merge_requests
+ comment_mr_with_commits
+
+ true
+ end
+
+ private
+
+ # Collect open merge requests that target same branch we push into
+ # and close if push to master include last commit from merge request
+ # We need this to close(as merged) merge requests that were merged into
+ # target branch manually
+ def close_merge_requests
+ commit_ids = @commits.map(&:id)
+ merge_requests = @project.merge_requests.opened.where(target_branch: @branch_name).to_a
+ merge_requests = merge_requests.select(&:last_commit)
+
+ merge_requests = merge_requests.select do |merge_request|
+ commit_ids.include?(merge_request.last_commit.id)
+ end
+
+
+ merge_requests.uniq.select(&:source_project).each do |merge_request|
+ MergeRequests::MergeService.new.execute(merge_request, @current_user, nil)
+ end
+ end
+
+ def force_push?
+ Gitlab::ForcePushCheck.force_push?(@project, @oldrev, @newrev)
+ end
+
+ # Refresh merge request diff if we push to source or target branch of merge request
+ # Note: we should update merge requests from forks too
+ def reload_merge_requests
+ merge_requests = @project.merge_requests.opened.by_branch(@branch_name).to_a
+ merge_requests += @fork_merge_requests.by_branch(@branch_name).to_a
+ merge_requests = filter_merge_requests(merge_requests)
+
+ merge_requests.each do |merge_request|
+
+ if merge_request.source_branch == @branch_name || force_push?
+ merge_request.reload_code
+ merge_request.mark_as_unchecked
+ else
+ mr_commit_ids = merge_request.commits.map(&:id)
+ push_commit_ids = @commits.map(&:id)
+ matches = mr_commit_ids & push_commit_ids
+
+ if matches.any?
+ merge_request.reload_code
+ merge_request.mark_as_unchecked
+ else
+ merge_request.mark_as_unchecked
+ end
+ end
+ end
+ end
+
+ # Add comment about pushing new commits to merge requests
+ def comment_mr_with_commits
+ merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
+ merge_requests += @fork_merge_requests.where(source_branch: @branch_name).to_a
+ merge_requests = filter_merge_requests(merge_requests)
+
+ merge_requests.each do |merge_request|
+ Note.create_new_commits_note(merge_request, merge_request.project,
+ @current_user, @commits)
+ end
+ end
+
+ def filter_merge_requests(merge_requests)
+ merge_requests.uniq.select(&:source_project)
+ end
+ end
+end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index fe39f83b400..d1aadd741e1 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -107,7 +107,7 @@ class NotificationService
# Notify new user with email after creation
def new_user(user, token = nil)
# Don't email omniauth created users
- mailer.new_user_email(user.id, user.password, token) unless user.extern_uid?
+ mailer.new_user_email(user.id, token) unless user.identities.any?
end
# Notify users on new note in system
@@ -119,11 +119,12 @@ class NotificationService
# ignore gitlab service messages
return true if note.note =~ /\A_Status changed to closed_/
- return true if note.note =~ /\A_mentioned in / && note.system == true
+ return true if note.cross_reference? && note.system == true
opts = { noteable_type: note.noteable_type, project_id: note.project_id }
target = note.noteable
+
if target.respond_to?(:participants)
recipients = target.participants
else
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 12386792aab..3672b623806 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -37,35 +37,22 @@ module Projects
@project.creator = current_user
- if @project.save
- log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"")
- system_hook_service.execute_hooks_for(@project, :create)
+ Project.transaction do
+ @project.save
- unless @project.group
- @project.team << [current_user, :master]
- end
-
- @project.update_column(:last_activity_at, @project.created_at)
-
- if @project.import?
- @project.import_start
- else
- GitlabShellWorker.perform_async(
- :add_repository,
- @project.path_with_namespace
- )
+ unless @project.import?
+ unless @project.create_repository
+ raise 'Failed to create repository'
+ end
end
+ end
+ if @project.persisted?
if @project.wiki_enabled?
- begin
- # force the creation of a wiki,
- ProjectWiki.new(@project, @project.owner).wiki
- rescue ProjectWiki::CouldNotCreateWikiError => ex
- # Prevent project observer crash
- # if failed to create wiki
- nil
- end
+ @project.create_wiki
end
+
+ after_create_actions
end
@project
@@ -84,5 +71,20 @@ module Projects
namespace = Namespace.find_by(id: namespace_id)
current_user.can?(:create_projects, namespace)
end
+
+ def after_create_actions
+ log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"")
+ system_hook_service.execute_hooks_for(@project, :create)
+
+ unless @project.group
+ @project.team << [current_user, :master]
+ end
+
+ @project.update_column(:last_activity_at, @project.created_at)
+
+ if @project.import?
+ @project.import_start
+ end
+ end
end
end
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index a59311bf942..4930660055a 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -2,11 +2,9 @@ module Projects
class ForkService < BaseService
include Gitlab::ShellAdapter
- def initialize(project, user)
- @from_project, @current_user = project, user
- end
-
def execute
+ @from_project = @project
+
project_params = {
visibility_level: @from_project.visibility_level,
description: @from_project.description,
@@ -15,8 +13,18 @@ module Projects
project = Project.new(project_params)
project.name = @from_project.name
project.path = @from_project.path
- project.namespace = current_user.namespace
- project.creator = current_user
+ project.creator = @current_user
+
+ if namespace = @params[:namespace]
+ project.namespace = namespace
+ else
+ project.namespace = @current_user.namespace
+ end
+
+ unless @current_user.can?(:create_projects, project.namespace)
+ project.errors.add(:namespace, 'insufficient access rights')
+ return project
+ end
# If the project cannot save, we do not want to trigger the project destroy
# as this can have the side effect of deleting a repo attached to an existing
@@ -27,7 +35,7 @@ module Projects
#First save the DB entries as they can be rolled back if the repo fork fails
project.build_forked_project_link(forked_to_project_id: project.id, forked_from_project_id: @from_project.id)
if project.save
- project.team << [current_user, :master]
+ project.team << [@current_user, :master]
end
#Now fork the repo
unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path)
@@ -42,8 +50,8 @@ module Projects
else
project.errors.add(:base, "Invalid fork destination")
end
- project
+ project
end
end
end
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index a6b68749a71..44e494525b3 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -18,7 +18,7 @@ class SystemHooksService
def build_event_data(model, event)
data = {
event_name: build_event_name(model, event),
- created_at: model.created_at
+ created_at: model.created_at.xmlschema
}
case model
diff --git a/app/services/test_hook_service.rb b/app/services/test_hook_service.rb
index b6b1ef29b51..17d86a7a274 100644
--- a/app/services/test_hook_service.rb
+++ b/app/services/test_hook_service.rb
@@ -2,8 +2,5 @@ class TestHookService
def execute(hook, current_user)
data = GitPushService.new.sample_data(hook.project, current_user)
hook.execute(data)
- true
- rescue SocketError
- false
end
end
diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml
index 9dcf7b488ee..8db2b2a709c 100644
--- a/app/views/admin/background_jobs/show.html.haml
+++ b/app/views/admin/background_jobs/show.html.haml
@@ -25,7 +25,7 @@
- next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/)
- data = process.strip.split(' ')
%tr
- %td= Settings.gitlab.user
+ %td= gitlab_config.user
- 5.times do
%td= data.shift
%td= data.join(' ')
@@ -36,7 +36,7 @@
If '[25 of 25 busy]' is shown, restart GitLab with 'sudo service gitlab reload'.
%p
%i.fa.fa-exclamation-circle
- If more than one sidekiq process is listed, stop GitLab, kill the remaining sidekiq processes (sudo pkill -u #{Settings.gitlab.user} -f sidekiq) and restart GitLab.
+ If more than one sidekiq process is listed, stop GitLab, kill the remaining sidekiq processes (sudo pkill -u #{gitlab_config.user} -f sidekiq) and restart GitLab.
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index c56863ce274..f4d7e25fd74 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -2,39 +2,20 @@
- if @group.errors.any?
.alert.alert-danger
%span= @group.errors.full_messages.first
- .form-group.group_name_holder
- = f.label :name, class: 'control-label' do
- Group name
- .col-sm-10
- = f.text_field :name, placeholder: "Example Group", class: "form-control"
- .form-group.group-description-holder
- = f.label :description, "Details", class: 'control-label'
- .col-sm-10
- = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4
+ = render 'shared/group_form', f: f
.form-group.group-description-holder
= f.label :avatar, "Group avatar", class: 'control-label'
.col-sm-10
- %a.choose-btn.btn.btn-small.js-choose-group-avatar-button
- %i.fa.fa-paperclip
- %span Choose File ...
- &nbsp;
- %span.file_name.js-avatar-filename File name...
- = f.file_field :avatar, class: "js-group-avatar-input hidden"
- .light The maximum file size allowed is 100KB.
+ = render 'shared/choose_group_avatar_button', f: f
- if @group.new_record?
.form-group
.col-sm-2
.col-sm-10
.bs-callout.bs-callout-info
- %ul
- %li A group is a collection of several projects
- %li Groups are private by default
- %li Members of a group may only view projects they have permission to access
- %li Group project URLs are prefixed with the group namespace
- %li Existing projects may be moved into a group
+ = render 'shared/group_tips'
.form-actions
= f.submit 'Create group', class: "btn btn-create"
= link_to 'Cancel', admin_groups_path, class: "btn btn-cancel"
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 09105679bd2..1d7fef43184 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -10,7 +10,7 @@
= form_tag admin_groups_path, method: :get, class: 'form-inline' do
.form-group
= text_field_tag :name, params[:name], class: "form-control input-mn-300"
- = submit_tag "Search", class: "btn submit btn-primary"
+ = button_tag "Search", class: "btn submit btn-primary"
%hr
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index c1a9214b77a..8057de38805 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -64,7 +64,7 @@
%div.prepend-top-10
= select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2"
%hr
- = submit_tag 'Add users into group', class: "btn btn-create"
+ = button_tag 'Add users into group', class: "btn btn-create"
.panel.panel-default
.panel-heading
%h3.panel-title
@@ -74,13 +74,13 @@
%ul.well-list.group-users-list
- @members.each do |member|
- user = member.user
- %li{class: dom_class(user)}
+ %li{class: dom_class(member), id: dom_id(user)}
.list-item-name
%strong
= link_to user.name, admin_user_path(user)
%span.pull-right.light
= member.human_access
- = link_to group_group_members_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
+ = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
%i.fa.fa-minus.fa-inverse
.panel-footer
= paginate @members, param_name: 'members_page', theme: 'gitlab'
diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml
index b3f8f012f00..384c6ee9af5 100644
--- a/app/views/admin/logs/show.html.haml
+++ b/app/views/admin/logs/show.html.haml
@@ -1,68 +1,25 @@
+- loggers = [Gitlab::GitLogger, Gitlab::AppLogger,
+ Gitlab::ProductionLogger, Gitlab::SidekiqLogger]
%ul.nav.nav-tabs.log-tabs
- %li.active
- = link_to "githost.log", "#githost", 'data-toggle' => 'tab'
- %li
- = link_to "application.log", "#application", 'data-toggle' => 'tab'
- %li
- = link_to "production.log", "#production", 'data-toggle' => 'tab'
- %li
- = link_to "sidekiq.log", "#sidekiq", 'data-toggle' => 'tab'
-
+ - loggers.each do |klass|
+ %li{ class: (klass == Gitlab::GitLogger ? 'active' : '') }
+ = link_to klass::file_name, "##{klass::file_name_noext}",
+ 'data-toggle' => 'tab'
%p.light To prevent performance issues admin logs output the last 2000 lines
.tab-content
- .tab-pane.active#githost
- .file-holder#README
- .file-title
- %i.fa.fa-file
- githost.log
- .pull-right
- = link_to '#', class: 'log-bottom' do
- %i.fa.fa-arrow-down
- Scroll down
- .file-content.logs
- %ol
- - Gitlab::GitLogger.read_latest.each do |line|
- %li
- %p= line
- .tab-pane#application
- .file-holder#README
- .file-title
- %i.fa.fa-file
- application.log
- .pull-right
- = link_to '#', class: 'log-bottom' do
- %i.fa.fa-arrow-down
- Scroll down
- .file-content.logs
- %ol
- - Gitlab::AppLogger.read_latest.each do |line|
- %li
- %p= line
- .tab-pane#production
- .file-holder#README
- .file-title
- %i.fa.fa-file
- production.log
- .pull-right
- = link_to '#', class: 'log-bottom' do
- %i.fa.fa-arrow-down
- Scroll down
- .file-content.logs
- %ol
- - Gitlab::Logger.read_latest_for('production.log').each do |line|
- %li
- %p= line
- .tab-pane#sidekiq
- .file-holder#README
- .file-title
- %i.fa.fa-file
- sidekiq.log
- .pull-right
- = link_to '#', class: 'log-bottom' do
- %i.fa.fa-arrow-down
- Scroll down
- .file-content.logs
- %ol
- - Gitlab::Logger.read_latest_for('sidekiq.log').each do |line|
- %li
- %p= line
+ - loggers.each do |klass|
+ .tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''),
+ id: klass::file_name_noext }
+ .file-holder#README
+ .file-title
+ %i.fa.fa-file
+ = klass::file_name
+ .pull-right
+ = link_to '#', class: 'log-bottom' do
+ %i.fa.fa-arrow-down
+ Scroll down
+ .file-content.logs
+ %ol
+ - klass.read_latest.each do |line|
+ %li
+ %p= line
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 5ca6090f8d3..aa59f38d213 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -35,7 +35,7 @@
= label
%hr
= hidden_field_tag :sort, params[:sort]
- = submit_tag "Search", class: "btn submit btn-primary"
+ = button_tag "Search", class: "btn submit btn-primary"
= link_to "Reset", admin_projects_path, class: "btn btn-cancel"
.col-md-9
@@ -56,13 +56,13 @@
= link_to admin_projects_path(sort: nil) do
Name
= link_to admin_projects_path(sort: 'newest') do
- Newest
+ = sort_title_recently_created
= link_to admin_projects_path(sort: 'oldest') do
- Oldest
+ = sort_title_oldest_created
= link_to admin_projects_path(sort: 'recently_updated') do
- Recently updated
+ = sort_title_recently_updated
= link_to admin_projects_path(sort: 'last_updated') do
- Last updated
+ = sort_title_oldest_updated
= link_to admin_projects_path(sort: 'largest_repository') do
Largest repository
= link_to 'New Project', new_project_path, class: "btn btn-new"
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 92c619738a2..8e1ecb41a85 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -49,9 +49,10 @@
= link_to admin_users_path(sort: 'oldest_sign_in') do
Oldest sign in
= link_to admin_users_path(sort: 'recently_created') do
- Recently created
+ = sort_title_recently_created
= link_to admin_users_path(sort: 'late_created') do
- Late created
+ = sort_title_oldest_created
+
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
%ul.well-list
- @users.each do |user|
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 211d77d5185..29717aedd80 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -95,7 +95,7 @@
%li
%span.light LDAP uid:
%strong
- = @user.extern_uid
+ = @user.ldap_identity.extern_uid
- if @user.created_by
%li
diff --git a/app/views/dashboard/_zero_authorized_projects.html.haml b/app/views/dashboard/_zero_authorized_projects.html.haml
index 711e607f0bc..5d133cd8285 100644
--- a/app/views/dashboard/_zero_authorized_projects.html.haml
+++ b/app/views/dashboard/_zero_authorized_projects.html.haml
@@ -46,5 +46,5 @@
%br
Public projects are an easy way to allow everyone to have read-only access.
.link_holder
- = link_to explore_projects_path, class: "btn btn-new" do
+ = link_to trending_explore_projects_path, class: "btn btn-new" do
Browse public projects »
diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder
index f5413557783..66381310221 100644
--- a/app/views/dashboard/issues.atom.builder
+++ b/app/views/dashboard/issues.atom.builder
@@ -1,24 +1,13 @@
xml.instruct!
-xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
+xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlnsmedia" => "http://search.yahoo.com/mrss/" do
xml.title "#{current_user.name} issues"
- xml.link :href => issues_dashboard_url(:atom, :private_token => current_user.private_token), :rel => "self", :type => "application/atom+xml"
- xml.link :href => issues_dashboard_url(:private_token => current_user.private_token), :rel => "alternate", :type => "text/html"
- xml.id issues_dashboard_url(:private_token => current_user.private_token)
+ xml.link href: issues_dashboard_url(:atom, private_token: current_user.private_token), rel: "self", type: "application/atom+xml"
+ xml.link href: issues_dashboard_url(private_token: current_user.private_token), rel: "alternate", type: "text/html"
+ xml.id issues_dashboard_url(private_token: current_user.private_token)
xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
@issues.each do |issue|
- xml.entry do
- xml.id project_issue_url(issue.project, issue)
- xml.link :href => project_issue_url(issue.project, issue)
- xml.title truncate(issue.title, :length => 80)
- xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
- xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(issue.author_email)
- xml.author do |author|
- xml.name issue.author_name
- xml.email issue.author_email
- end
- xml.summary issue.title
- end
+ issue_to_atom(xml, issue)
end
end
diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml
index f124c688be1..5b7835b097b 100644
--- a/app/views/dashboard/projects.html.haml
+++ b/app/views/dashboard/projects.html.haml
@@ -14,13 +14,14 @@
= link_to projects_dashboard_filter_path(sort: nil) do
Name
= link_to projects_dashboard_filter_path(sort: 'newest') do
- Newest
+ = sort_title_recently_created
= link_to projects_dashboard_filter_path(sort: 'oldest') do
- Oldest
+ = sort_title_oldest_created
= link_to projects_dashboard_filter_path(sort: 'recently_updated') do
- Recently updated
+ = sort_title_recently_updated
= link_to projects_dashboard_filter_path(sort: 'last_updated') do
- Last updated
+ = sort_title_oldest_updated
+
%p.light
All projects you have access to are listed here. Public projects are not included here unless you are a member
%hr
diff --git a/app/views/dashboard/show.atom.builder b/app/views/dashboard/show.atom.builder
index f4cf24ccd99..70ac66f8016 100644
--- a/app/views/dashboard/show.atom.builder
+++ b/app/views/dashboard/show.atom.builder
@@ -1,29 +1,12 @@
xml.instruct!
-xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
+xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlnsmedia" => "http://search.yahoo.com/mrss/" do
xml.title "Dashboard feed#{" - #{current_user.name}" if current_user.name.present?}"
- xml.link :href => dashboard_url(:atom), :rel => "self", :type => "application/atom+xml"
- xml.link :href => dashboard_url, :rel => "alternate", :type => "text/html"
+ xml.link href: dashboard_url(:atom), rel: "self", type: "application/atom+xml"
+ xml.link href: dashboard_url, rel: "alternate", type: "text/html"
xml.id projects_url
xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
@events.each do |event|
- if event.proper?
- xml.entry do
- event_link = event_feed_url(event)
- event_title = event_feed_title(event)
- event_summary = event_feed_summary(event)
-
- xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
- xml.link :href => event_link
- xml.title truncate(event_title, :length => 80)
- xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
- xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(event.author_email)
- xml.author do |author|
- xml.name event.author_name
- xml.email event.author_email
- end
- xml.summary(:type => "xhtml") { |x| x << event_summary unless event_summary.nil? }
- end
- end
+ event_to_atom(xml, event)
end
end
diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml
index 1326cc0aac9..f6cbf9b82ba 100644
--- a/app/views/devise/passwords/edit.html.haml
+++ b/app/views/devise/passwords/edit.html.haml
@@ -6,8 +6,8 @@
.devise-errors
= devise_error_messages!
= f.hidden_field :reset_password_token
- %div
- = f.password_field :password, class: "form-control top", placeholder: "New password", required: true
+ .form-group#password-strength
+ = f.password_field :password, class: "form-control top", id: "user_password_recover", placeholder: "New password", required: true
%div
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm new password", required: true
.clearfix.append-bottom-10
diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml
index d6a952f3dc5..123de881f59 100644
--- a/app/views/devise/registrations/new.html.haml
+++ b/app/views/devise/registrations/new.html.haml
@@ -11,8 +11,8 @@
= f.text_field :username, class: "form-control middle", placeholder: "Username", required: true
%div
= f.email_field :email, class: "form-control middle", placeholder: "Email", required: true
- %div
- = f.password_field :password, class: "form-control middle", placeholder: "Password", required: true
+ .form-group#password-strength
+ = f.password_field :password, class: "form-control middle", id: "user_password_sign_up", placeholder: "Password", required: true
%div
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm password", required: true
%div
diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml
index 01584611493..bf8a593c254 100644
--- a/app/views/devise/sessions/_new_ldap.html.haml
+++ b/app/views/devise/sessions/_new_ldap.html.haml
@@ -2,4 +2,4 @@
= text_field_tag :username, nil, {class: "form-control top", placeholder: "LDAP Login", autofocus: "autofocus"}
= password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"}
%br/
- = submit_tag "LDAP Sign in", class: "btn-save btn"
+ = button_tag "LDAP Sign in", class: "btn-save btn"
diff --git a/app/views/devise/sessions/_oauth_providers.html.haml b/app/views/devise/sessions/_oauth_providers.html.haml
index 15048a78063..8d6aaefb9ff 100644
--- a/app/views/devise/sessions/_oauth_providers.html.haml
+++ b/app/views/devise/sessions/_oauth_providers.html.haml
@@ -1,4 +1,4 @@
-- providers = (enabled_oauth_providers - [:ldap])
+- providers = additional_providers
- if providers.present?
.bs-callout.bs-callout-info{:'data-no-turbolink' => 'data-no-turbolink'}
%span Sign in with: &nbsp;
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index b9832787446..ca7e9570b43 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -2,22 +2,22 @@
.login-heading
%h3 Sign in
.login-body
- - if ldap_enabled? && gitlab_config.signin_enabled
+ - if ldap_enabled?
%ul.nav.nav-tabs
- @ldap_servers.each_with_index do |server, i|
- %li{class: (:active if i==0)}
+ %li{class: (:active if i.zero?)}
= link_to server['label'], "#tab-#{server['provider_name']}", 'data-toggle' => 'tab'
- %li
- = link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab'
+ - if gitlab_config.signin_enabled
+ %li
+ = link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab'
.tab-content
- - @ldap_servers.each_with_index do |server,i|
- %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i==0)}
+ - @ldap_servers.each_with_index do |server, i|
+ %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero?)}
= render 'devise/sessions/new_ldap', provider: server['provider_name']
- %div#tab-signin.tab-pane
- = render 'devise/sessions/new_base'
+ - if gitlab_config.signin_enabled
+ %div#tab-signin.tab-pane
+ = render 'devise/sessions/new_base'
- - elsif ldap_enabled?
- = render 'devise/sessions/new_ldap', ldap_servers: @ldap_servers
- elsif gitlab_config.signin_enabled
= render 'devise/sessions/new_base'
- else
diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml
index c8243ff782c..9b1d7d0416d 100644
--- a/app/views/explore/groups/index.html.haml
+++ b/app/views/explore/groups/index.html.haml
@@ -4,7 +4,7 @@
.form-group
= search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input input-mn-300", id: "groups_search"
.form-group
- = submit_tag 'Search', class: "btn btn-primary wide"
+ = button_tag 'Search', class: "btn btn-primary wide"
.pull-right
.dropdown.inline
@@ -20,13 +20,13 @@
= link_to explore_groups_path(sort: nil) do
Name
= link_to explore_groups_path(sort: 'newest') do
- Newest
+ = sort_title_recently_created
= link_to explore_groups_path(sort: 'oldest') do
- Oldest
+ = sort_title_oldest_created
= link_to explore_groups_path(sort: 'recently_updated') do
- Recently updated
+ = sort_title_recently_updated
= link_to explore_groups_path(sort: 'last_updated') do
- Last updated
+ = sort_title_oldest_updated
%hr
diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml
index c8bf78385e8..02586077d8c 100644
--- a/app/views/explore/projects/index.html.haml
+++ b/app/views/explore/projects/index.html.haml
@@ -4,7 +4,7 @@
.form-group
= search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input input-mn-300", id: "projects_search"
.form-group
- = submit_tag 'Search', class: "btn btn-primary wide"
+ = button_tag 'Search', class: "btn btn-primary wide"
.pull-right
.dropdown.inline
@@ -20,13 +20,13 @@
= link_to explore_projects_path(sort: nil) do
Name
= link_to explore_projects_path(sort: 'newest') do
- Newest
+ = sort_title_recently_created
= link_to explore_projects_path(sort: 'oldest') do
- Oldest
+ = sort_title_oldest_created
= link_to explore_projects_path(sort: 'recently_updated') do
- Recently updated
+ = sort_title_recently_updated
= link_to explore_projects_path(sort: 'last_updated') do
- Last updated
+ = sort_title_oldest_updated
%hr
.public-projects
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 0b15affe785..eb24fd65d9e 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -11,16 +11,7 @@
- if @group.errors.any?
.alert.alert-danger
%span= @group.errors.full_messages.first
- .form-group
- = f.label :name, class: 'control-label' do
- Group name
- .col-sm-10
- = f.text_field :name, placeholder: "Ex. OpenSource", class: "form-control left"
-
- .form-group.group-description-holder
- = f.label :description, "Details", class: 'control-label'
- .col-sm-10
- = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4
+ = render 'shared/group_form', f: f
.form-group
.col-sm-2
@@ -31,13 +22,7 @@
You can change your group avatar here
- else
You can upload a group avatar here
- %a.choose-btn.btn.btn-small.js-choose-group-avatar-button
- %i.fa.fa-paperclip
- %span Choose File ...
- &nbsp;
- %span.file_name.js-avatar-filename File name...
- = f.file_field :avatar, class: "js-group-avatar-input hidden"
- .light The maximum file size allowed is 100KB.
+ = render 'shared/choose_group_avatar_button', f: f
- if @group.avatar?
%hr
= link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
diff --git a/app/views/groups/issues.atom.builder b/app/views/groups/issues.atom.builder
index f2005193f83..240001967f3 100644
--- a/app/views/groups/issues.atom.builder
+++ b/app/views/groups/issues.atom.builder
@@ -7,18 +7,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
@issues.each do |issue|
- xml.entry do
- xml.id project_issue_url(issue.project, issue)
- xml.link :href => project_issue_url(issue.project, issue)
- xml.title truncate(issue.title, :length => 80)
- xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
- xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(issue.author_email)
- xml.author do |author|
- xml.name issue.author_name
- xml.email issue.author_email
- end
- xml.summary issue.title
- end
+ issue_to_atom(xml, issue)
end
end
diff --git a/app/views/groups/members.html.haml b/app/views/groups/members.html.haml
index ba554cd5ef1..d2ebcdab7e1 100644
--- a/app/views/groups/members.html.haml
+++ b/app/views/groups/members.html.haml
@@ -13,7 +13,7 @@
= form_tag members_group_path(@group), method: :get, class: 'form-inline member-search-form' do
.form-group
= search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control search-text-input input-mn-300' }
- = submit_tag 'Search', class: 'btn'
+ = button_tag 'Search', class: 'btn'
- if current_user && current_user.can?(:manage_group, @group)
.pull-right
diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml
index 235e299343a..6e17cdaef6f 100644
--- a/app/views/groups/new.html.haml
+++ b/app/views/groups/new.html.haml
@@ -2,37 +2,18 @@
- if @group.errors.any?
.alert.alert-danger
%span= @group.errors.full_messages.first
- .form-group
- = f.label :name, class: 'control-label' do
- Group name
- .col-sm-10
- = f.text_field :name, placeholder: "Ex. OpenSource", class: "form-control", tabindex: 1, autofocus: true
- .form-group.group-description-holder
- = f.label :description, "Details", class: 'control-label'
- .col-sm-10
- = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4, tabindex: 2
+ = render 'shared/group_form', f: f, autofocus: true
.form-group.group-description-holder
= f.label :avatar, "Group avatar", class: 'control-label'
.col-sm-10
- %a.choose-btn.btn.btn-small.js-choose-group-avatar-button
- %i.fa.fa-paperclip
- %span Choose File ...
- &nbsp;
- %span.file_name.js-avatar-filename File name...
- = f.file_field :avatar, class: "js-group-avatar-input hidden"
- .light The maximum file size allowed is 100KB.
+ = render 'shared/choose_group_avatar_button', f: f
.form-group
.col-sm-2
.col-sm-10
- %ul
- %li A group is a collection of several projects
- %li Groups are private by default
- %li Members of a group may only view projects they have permission to access
- %li Group project URLs are prefixed with the group namespace
- %li Existing projects may be moved into a group
+ = render 'shared/group_tips'
.form-actions
= f.submit 'Create group', class: "btn btn-create", tabindex: 3
diff --git a/app/views/groups/show.atom.builder b/app/views/groups/show.atom.builder
index e07bb7d2fb7..e765ea8338d 100644
--- a/app/views/groups/show.atom.builder
+++ b/app/views/groups/show.atom.builder
@@ -1,28 +1,12 @@
xml.instruct!
-xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
+xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlnsmedia" => "http://search.yahoo.com/mrss/" do
xml.title "Group feed - #{@group.name}"
- xml.link :href => group_path(@group, :atom), :rel => "self", :type => "application/atom+xml"
- xml.link :href => group_path(@group), :rel => "alternate", :type => "text/html"
+ xml.link href: group_path(@group, :atom), rel: "self", type: "application/atom+xml"
+ xml.link href: group_path(@group), rel: "alternate", type: "text/html"
xml.id projects_url
xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
@events.each do |event|
- if event.proper?
- xml.entry do
- event_link = event_feed_url(event)
- event_title = event_feed_title(event)
-
- xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
- xml.link :href => event_link
- xml.title truncate(event_title, :length => 80)
- xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
- xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(event.author_email)
- xml.author do |author|
- xml.name event.author_name
- xml.email event.author_email
- end
- xml.summary event_title
- end
- end
+ event_to_atom(xml, event)
end
end
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index 5ab82122ad7..04f79846858 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -4,11 +4,20 @@
= hidden_field_tag :group_id, @group.try(:id)
- if @project && @project.persisted?
= hidden_field_tag :project_id, @project.id
- = hidden_field_tag :search_code, true
+
+ - if current_controller?(:issues)
+ = hidden_field_tag :scope, 'issues'
+ - elsif current_controller?(:merge_requests)
+ = hidden_field_tag :scope, 'merge_requests'
+ - elsif current_controller?(:wikis)
+ = hidden_field_tag :scope, 'wiki_blobs'
+ - else
+ = hidden_field_tag :search_code, true
+
- if @snippet || @snippets
= hidden_field_tag :snippets, true
= hidden_field_tag :repository_ref, @ref
- = submit_tag 'Go' if ENV['RAILS_ENV'] == 'test'
+ = button_tag 'Go' if ENV['RAILS_ENV'] == 'test'
.search-autocomplete-opts.hide{:'data-autocomplete-path' => search_autocomplete_path, :'data-autocomplete-project-id' => @project.try(:id), :'data-autocomplete-project-ref' => @ref }
:javascript
diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml
index ab421d63f1a..da451961327 100644
--- a/app/views/layouts/notify.html.haml
+++ b/app/views/layouts/notify.html.haml
@@ -28,3 +28,4 @@
You're receiving this notification because you are a member of the #{link_to_unless @target_url, @project.name_with_namespace, project_url(@project)} project team.
- if @target_url
#{link_to "View it on GitLab", @target_url}
+ = email_action @target_url
diff --git a/app/views/notify/new_ssh_key_email.html.haml b/app/views/notify/new_ssh_key_email.html.haml
index deb0822d8f2..63b0cbbd205 100644
--- a/app/views/notify/new_ssh_key_email.html.haml
+++ b/app/views/notify/new_ssh_key_email.html.haml
@@ -6,5 +6,5 @@
title:
%code= @key.title
%p
- If this key was added in error, you can remove it here:
+ If this key was added in error, you can remove it under
= link_to "SSH Keys", profile_keys_url
diff --git a/app/views/notify/new_ssh_key_email.text.erb b/app/views/notify/new_ssh_key_email.text.erb
index 5f0080c2b76..05b551c89a0 100644
--- a/app/views/notify/new_ssh_key_email.text.erb
+++ b/app/views/notify/new_ssh_key_email.text.erb
@@ -2,6 +2,6 @@ Hi <%= @user.name %>!
A new public key was added to your account:
-title.................. <%= @key.title %>
+Title: <%= @key.title %>
-If this key was added in error, you can remove it here: <%= profile_keys_url %>
+If this key was added in error, you can remove it at <%= profile_keys_url %>
diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml
index 2a7d317aa3e..425200ff523 100644
--- a/app/views/profiles/passwords/edit.html.haml
+++ b/app/views/profiles/passwords/edit.html.haml
@@ -24,7 +24,7 @@
.form-group
= f.label :password, 'New password', class: 'control-label'
.col-sm-10
- = f.password_field :password, required: true, class: 'form-control'
+ = f.password_field :password, required: true, class: 'form-control', id: 'user_password_profile'
.form-group
= f.label :password_confirmation, class: 'control-label'
.col-sm-10
diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml
index aef7348fd20..42d2d0db29c 100644
--- a/app/views/profiles/passwords/new.html.haml
+++ b/app/views/profiles/passwords/new.html.haml
@@ -16,7 +16,7 @@
.col-sm-10= f.password_field :current_password, required: true, class: 'form-control'
.form-group
= f.label :password, class: 'control-label'
- .col-sm-10= f.password_field :password, required: true, class: 'form-control'
+ .col-sm-10= f.password_field :password, required: true, class: 'form-control', id: 'user_password_profile'
.form-group
= f.label :password_confirmation, class: 'control-label'
.col-sm-10
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index d6b52f86154..640104fdad1 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -83,7 +83,7 @@
&nbsp;
%span.file_name.js-avatar-filename File name...
= f.file_field :avatar, class: "js-user-avatar-input hidden"
- .light The maximum file size allowed is 100KB.
+ .light The maximum file size allowed is 200KB.
- if @user.avatar?
%hr
= link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 672a91e0eef..30d063c7a36 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -16,11 +16,11 @@
- unless @project.empty_repo?
.fork-buttons
- if current_user && can?(current_user, :fork_project, @project) && @project.namespace != current_user.namespace
- - if current_user.already_forked?(@project)
+ - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
= link_to project_path(current_user.fork_of(@project)), title: 'Go to my fork' do
= link_to_toggle_fork
- else
- = link_to fork_project_path(@project), title: "Fork project", method: "POST" do
+ = link_to new_project_fork_path(@project), title: "Fork project" do
= link_to_toggle_fork
.star-buttons
@@ -31,7 +31,7 @@
- else
= link_to_toggle_star('You must sign in to star a project.', false, false)
- .project-home-row
+ .project-home-row.hidden-xs
- if current_user && !empty_repo
.project-home-dropdown
= render "dropdown"
diff --git a/app/views/projects/_issuable_filter.html.haml b/app/views/projects/_issuable_filter.html.haml
new file mode 100644
index 00000000000..b3e5efd938f
--- /dev/null
+++ b/app/views/projects/_issuable_filter.html.haml
@@ -0,0 +1,72 @@
+.issues-filters
+ .dropdown.inline
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.fa.fa-user
+ %span.light assignee:
+ - if @assignee.present?
+ %strong= @assignee.name
+ - elsif params[:assignee_id] == "0"
+ Unassigned
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(assignee_id: nil) do
+ Any
+ = link_to project_filter_path(assignee_id: 0) do
+ Unassigned
+ - @assignees.sort_by(&:name).each do |user|
+ %li
+ = link_to project_filter_path(assignee_id: user.id) do
+ = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
+ = user.name
+
+ .dropdown.inline.prepend-left-10
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.fa.fa-user
+ %span.light author:
+ - if @author.present?
+ %strong= @author.name
+ - elsif params[:author_id] == "0"
+ Unassigned
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(author_id: nil) do
+ Any
+ = link_to project_filter_path(author_id: 0) do
+ Unassigned
+ - @authors.sort_by(&:name).each do |user|
+ %li
+ = link_to project_filter_path(author_id: user.id) do
+ = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
+ = user.name
+
+ .dropdown.inline.prepend-left-10
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.fa.fa-clock-o
+ %span.light milestone:
+ - if @milestone.present?
+ %strong= @milestone.title
+ - elsif params[:milestone_id] == "0"
+ None (backlog)
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(milestone_id: nil) do
+ Any
+ = link_to project_filter_path(milestone_id: 0) do
+ None (backlog)
+ - project_active_milestones.each do |milestone|
+ %li
+ = link_to project_filter_path(milestone_id: milestone.id) do
+ %strong= milestone.title
+ %small.light= milestone.expires_at
+
+ .pull-right
+ = render 'shared/sort_dropdown'
diff --git a/app/views/projects/_issuable_form.html.haml b/app/views/projects/_issuable_form.html.haml
index 675b73a59cb..b02f52a5aff 100644
--- a/app/views/projects/_issuable_form.html.haml
+++ b/app/views/projects/_issuable_form.html.haml
@@ -52,7 +52,7 @@
- else
%span.light No open milestones available.
&nbsp;
- = link_to 'Create new milestone', new_project_milestone_path(issuable.project)
+ = link_to 'Create new milestone', new_project_milestone_path(issuable.project), target: :blank
.form-group
= f.label :label_ids, class: 'control-label' do
%i.icon-tag
@@ -64,7 +64,7 @@
- else
%span.light No labels yet.
&nbsp;
- = link_to 'Create new label', new_project_label_path(issuable.project)
+ = link_to 'Create new label', new_project_label_path(issuable.project), target: :blank
.form-actions
- if issuable.new_record?
diff --git a/app/views/projects/_issues_nav.html.haml b/app/views/projects/_issues_nav.html.haml
new file mode 100644
index 00000000000..18628eb6207
--- /dev/null
+++ b/app/views/projects/_issues_nav.html.haml
@@ -0,0 +1,55 @@
+%ul.nav.nav-tabs
+ - if project_nav_tab? :issues
+ = nav_link(controller: :issues) do
+ = link_to project_issues_path(@project), class: "tab" do
+ Issues
+ - if project_nav_tab? :merge_requests
+ = nav_link(controller: :merge_requests) do
+ = link_to project_merge_requests_path(@project), class: "tab" do
+ Merge Requests
+ = nav_link(controller: :milestones) do
+ = link_to 'Milestones', project_milestones_path(@project), class: "tab"
+ = nav_link(controller: :labels) do
+ = link_to 'Labels', project_labels_path(@project), class: "tab"
+
+ - if current_controller?(:milestones)
+ %li.pull-right
+ %button.btn.btn-default.sidebar-expand-button
+ %i.icon.fa.fa-list
+
+ - if current_controller?(:issues)
+ - if current_user
+ %li.hidden-xs
+ = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
+ %i.fa.fa-rss
+
+ %li.pull-right
+ .pull-right
+ %button.btn.btn-default.sidebar-expand-button
+ %i.icon.fa.fa-list
+
+ .pull-left
+ = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do
+ .append-right-10.hidden-xs.hidden-sm
+ = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' }
+ = hidden_field_tag :state, params['state']
+ = hidden_field_tag :scope, params['scope']
+ = hidden_field_tag :assignee_id, params['assignee_id']
+ = hidden_field_tag :milestone_id, params['milestone_id']
+ = hidden_field_tag :label_id, params['label_id']
+
+ - if can? current_user, :write_issue, @project
+ = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
+ %i.fa.fa-plus
+ New Issue
+
+ - if current_controller?(:merge_requests)
+ %li.pull-right
+ .pull-right
+ %button.btn.btn-default.sidebar-expand-button
+ %i.icon.fa.fa-list
+
+ - if can? current_user, :write_merge_request, @project
+ = link_to new_project_merge_request_path(@project), class: "btn btn-new pull-left", title: "New Merge Request" do
+ %i.fa.fa-plus
+ New Merge Request
diff --git a/app/views/projects/blob/_actions.html.haml b/app/views/projects/blob/_actions.html.haml
index 64c19a57803..812d88a8730 100644
--- a/app/views/projects/blob/_actions.html.haml
+++ b/app/views/projects/blob/_actions.html.haml
@@ -23,5 +23,6 @@
tree_join(@commit.sha, @path)), class: 'btn btn-small'
- if allowed_tree_edit?
- = link_to '#modal-remove-blob', class: "remove-blob btn btn-small btn-remove", "data-toggle" => "modal" do
+ = button_tag class: 'remove-blob btn btn-small btn-remove',
+ 'data-toggle' => 'modal', 'data-target' => '#modal-remove-blob' do
Remove
diff --git a/app/views/projects/blob/_remove.html.haml b/app/views/projects/blob/_remove.html.haml
index da84dc4b6cf..c5568315cb1 100644
--- a/app/views/projects/blob/_remove.html.haml
+++ b/app/views/projects/blob/_remove.html.haml
@@ -15,7 +15,7 @@
.form-group
.col-sm-2
.col-sm-10
- = submit_tag 'Remove file', class: 'btn btn-remove btn-remove-file'
+ = button_tag 'Remove file', class: 'btn btn-remove btn-remove-file'
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
:javascript
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 9f2b1b59292..d2aefd815a1 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -20,9 +20,9 @@
= link_to project_branches_path(sort: nil) do
Name
= link_to project_branches_path(sort: 'recently_updated') do
- Recently updated
+ = sort_title_recently_updated
= link_to project_branches_path(sort: 'last_updated') do
- Last updated
+ = sort_title_oldest_updated
%hr
- unless @branches.empty?
%ul.bordered-list.top-list.all-branches
diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml
index f5a530d95f2..a6623240da1 100644
--- a/app/views/projects/branches/new.html.haml
+++ b/app/views/projects/branches/new.html.haml
@@ -15,7 +15,7 @@
.col-sm-10
= text_field_tag :ref, params[:ref], placeholder: 'existing branch name, tag or commit SHA', required: true, tabindex: 2, class: 'form-control'
.form-actions
- = submit_tag 'Create branch', class: 'btn btn-create', tabindex: 3
+ = button_tag 'Create branch', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
:javascript
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index da6157cf1b6..cb0a3747f7d 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -12,7 +12,7 @@
%span.input-group-addon to
= text_field_tag :to, params[:to], class: "form-control"
&nbsp;
- = submit_tag "Compare", class: "btn btn-create commits-compare-btn"
+ = button_tag "Compare", class: "btn btn-create commits-compare-btn"
- if compare_to_mr_button?
= link_to compare_mr_path, class: 'prepend-left-10 btn' do
%strong Make a merge request
diff --git a/app/views/projects/create.js.haml b/app/views/projects/create.js.haml
deleted file mode 100644
index 89710d3a09a..00000000000
--- a/app/views/projects/create.js.haml
+++ /dev/null
@@ -1,13 +0,0 @@
-- if @project.saved?
- - if @project.import?
- :plain
- location.href = "#{import_project_path(@project)}";
- - else
- :plain
- location.href = "#{project_path(@project)}";
-- else
- :plain
- $(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
- $('.project-submit').enable();
- $('.save-project-loader').hide();
- $('.project-edit-container').show();
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index c415ae2ddc8..bf7770ceedf 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -10,7 +10,10 @@
- if @commit.parent_ids.present?
= view_file_btn(@commit.parent_id, diff_file, project)
- else
- %span= diff_file.new_path
+ - if diff_file.renamed_file
+ %span= "#{diff_file.old_path} renamed to #{diff_file.new_path}"
+ - else
+ %span= diff_file.new_path
- if diff_file.mode_changed?
%span.file-mode= "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}"
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index f48f4bb2953..b85cf7d8d37 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -13,7 +13,7 @@
= f.label :name, class: 'control-label' do
Project name
.col-sm-10
- = f.text_field :name, placeholder: "Example Project", class: "form-control"
+ = f.text_field :name, placeholder: "Example Project", class: "form-control", id: "project_name_edit"
.form-group
@@ -124,6 +124,12 @@
.errors-holder
.panel-body
= form_for(@project, html: { class: 'form-horizontal' }) do |f|
+ .form-group.project_name_holder
+ = f.label :name, class: 'control-label' do
+ Project name
+ .col-sm-9
+ .form-group
+ = f.text_field :name, placeholder: "Example Project", class: "form-control"
.form-group
= f.label :path, class: 'control-label' do
%span Path
diff --git a/app/views/projects/fork.html.haml b/app/views/projects/fork.html.haml
deleted file mode 100644
index d8f5c7b98d6..00000000000
--- a/app/views/projects/fork.html.haml
+++ /dev/null
@@ -1,19 +0,0 @@
-.alert.alert-danger.alert-block
- %h4
- %i.fa.fa-code-fork
- Fork Error!
- %p
- You tried to fork
- = link_to_project @project
- but it failed for the following reason:
-
-
- - if @forked_project && @forked_project.errors.any?
- %p
- &ndash;
- = @forked_project.errors.full_messages.first
-
- %p
- = link_to fork_project_path(@project), title: "Fork", class: "btn", method: "POST" do
- %i.fa.fa-code-fork
- Try to Fork again
diff --git a/app/views/projects/forks/error.html.haml b/app/views/projects/forks/error.html.haml
new file mode 100644
index 00000000000..76d3aa5bf00
--- /dev/null
+++ b/app/views/projects/forks/error.html.haml
@@ -0,0 +1,20 @@
+- if @forked_project && !@forked_project.saved?
+ .alert.alert-danger.alert-block
+ %h4
+ %i.fa.fa-code-fork
+ Fork Error!
+ %p
+ You tried to fork
+ = link_to_project @project
+ but it failed for the following reason:
+
+
+ - if @forked_project && @forked_project.errors.any?
+ %p
+ &ndash;
+ = @forked_project.errors.full_messages.first
+
+ %p
+ = link_to new_project_fork_path(@project), title: "Fork", class: "btn" do
+ %i.fa.fa-code-fork
+ Try to Fork again
diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml
new file mode 100644
index 00000000000..54f2cef023b
--- /dev/null
+++ b/app/views/projects/forks/new.html.haml
@@ -0,0 +1,38 @@
+%h3.page-title Fork project
+%p.lead Select namespace where to fork this project
+%hr
+
+.fork-namespaces
+ - @namespaces.in_groups_of(6, false) do |group|
+ .row
+ - group.each do |namespace|
+ .col-md-2.col-sm-3
+ - if fork = namespace.find_fork_of(@project)
+ .thumbnail.fork-exists-thumbnail
+ = link_to project_path(fork), title: "Visit project fork", class: 'has_tooltip' do
+ = image_tag namespace_icon(namespace, 200)
+ .caption
+ %h4=namespace.human_name
+ %p
+ = namespace.path
+ - else
+ .thumbnail.fork-thumbnail
+ = link_to project_fork_path(@project, namespace_id: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do
+ = image_tag namespace_icon(namespace, 200)
+ .caption
+ %h4=namespace.human_name
+ %p
+ = namespace.path
+
+ %p.light
+ Fork is a copy of a project repository.
+ %br
+ Forking a repository allows you to do changes without affecting the original project.
+
+.save-project-loader.hide
+ .center
+ %h2
+ %i.fa.fa-spinner.fa-spin
+ Forking repository
+ %p Please wait a moment, this page will automatically refresh when ready.
+
diff --git a/app/views/projects/import.html.haml b/app/views/projects/import.html.haml
deleted file mode 100644
index 4513c89e784..00000000000
--- a/app/views/projects/import.html.haml
+++ /dev/null
@@ -1,31 +0,0 @@
-- if @project.import_in_progress?
- .save-project-loader
- .center
- %h2
- %i.fa.fa-spinner.fa-spin
- Import in progress.
- %p.monospace git clone --bare #{hidden_pass_url(@project.import_url)}
- %p Please wait while we import the repository for you. Refresh at will.
- :javascript
- new ProjectImport();
-
-- elsif @project.import_failed?
- .save-project-loader
- .center
- %h2
- Import failed. Retry?
- %hr
- - if can?(current_user, :admin_project, @project)
- = form_for @project, url: retry_import_project_path(@project), method: :put, html: { class: 'form-horizontal' } do |f|
- .form-group.import-url-data
- = f.label :import_url, class: 'control-label' do
- %span Import existing git repo
- .col-sm-10
- = f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
- .bs-callout.bs-callout-info
- This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
- %br
- The import will time out after 4 minutes. For big repositories, use a clone/push combination.
- For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
- .form-actions
- = f.submit 'Retry import', class: "btn btn-create", tabindex: 4
diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml
new file mode 100644
index 00000000000..6c3083e49f5
--- /dev/null
+++ b/app/views/projects/imports/new.html.haml
@@ -0,0 +1,21 @@
+%h3.page-title
+ - if @project.import_failed?
+ Import failed. Retry?
+ - else
+ Import repository
+
+%hr
+
+= form_for @project, url: project_import_path(@project), method: :post, html: { class: 'form-horizontal' } do |f|
+ .form-group.import-url-data
+ = f.label :import_url, class: 'control-label' do
+ %span Import existing git repo
+ .col-sm-10
+ = f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
+ .bs-callout.bs-callout-info
+ This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
+ %br
+ The import will time out after 4 minutes. For big repositories, use a clone/push combination.
+ For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
+ .form-actions
+ = f.submit 'Start import', class: "btn btn-create", tabindex: 4
diff --git a/app/views/projects/imports/show.html.haml b/app/views/projects/imports/show.html.haml
new file mode 100644
index 00000000000..2d1fdafed24
--- /dev/null
+++ b/app/views/projects/imports/show.html.haml
@@ -0,0 +1,9 @@
+.save-project-loader
+ .center
+ %h2
+ %i.fa.fa-spinner.fa-spin
+ Import in progress.
+ %p.monospace git clone --bare #{hidden_pass_url(@project.import_url)}
+ %p Please wait while we import the repository for you. Refresh at will.
+ :javascript
+ new ProjectImport();
diff --git a/app/views/projects/issues/_head.html.haml b/app/views/projects/issues/_head.html.haml
deleted file mode 100644
index 1d2f3ed8118..00000000000
--- a/app/views/projects/issues/_head.html.haml
+++ /dev/null
@@ -1,36 +0,0 @@
-%ul.nav.nav-tabs
- = nav_link(controller: :issues) do
- = link_to project_issues_path(@project), class: "tab" do
- Browse Issues
- = nav_link(controller: :milestones) do
- = link_to 'Milestones', project_milestones_path(@project), class: "tab"
- = nav_link(controller: :labels) do
- = link_to 'Labels', project_labels_path(@project), class: "tab"
-
- - if current_controller?(:milestones)
- %li.pull-right
- %button.btn.btn-default.sidebar-expand-button
- %i.icon.fa.fa-list
-
- - if current_controller?(:issues)
- - if current_user
- %li
- = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
- %i.fa.fa-rss
-
- %li.pull-right
- .pull-right
- %button.btn.btn-default.sidebar-expand-button
- %i.icon.fa.fa-list
- = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do
- .append-right-10.hidden-xs.hidden-sm
- = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' }
- = hidden_field_tag :state, params['state']
- = hidden_field_tag :scope, params['scope']
- = hidden_field_tag :assignee_id, params['assignee_id']
- = hidden_field_tag :milestone_id, params['milestone_id']
- = hidden_field_tag :label_id, params['label_id']
- - if can? current_user, :write_issue, @project
- = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
- %i.fa.fa-plus
- New Issue
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index b125706781c..dc6510be858 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -4,7 +4,6 @@
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue)
.issue-title
- %span.light= "##{issue.iid}"
%span.str-truncated
= link_to_gfm issue.title, project_issue_path(issue.project, issue), class: "row_title"
- if issue.closed?
@@ -12,10 +11,9 @@
CLOSED
.issue-info
+ %span.light= "##{issue.iid}"
- if issue.assignee
assigned to #{link_to_member(@project, issue.assignee)}
- - else
- unassigned
- if issue.votes_count > 0
= render 'votes/votes_inline', votable: issue
- if issue.notes.any?
@@ -30,7 +28,7 @@
%span.task-status
= issue.task_status
- .pull-right
+ .pull-right.issue-updated-at
%small updated #{time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_update_ago')}
.issue-labels
diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml
index 8c3f0823386..648f459dc9e 100644
--- a/app/views/projects/issues/_issue_context.html.haml
+++ b/app/views/projects/issues/_issue_context.html.haml
@@ -19,6 +19,7 @@
= hidden_field_tag :issue_context
= f.submit class: 'btn'
- elsif issue.milestone
- = link_to issue.milestone.title, project_milestone_path
+ = link_to project_milestone_path(@project, @issue.milestone) do
+ = @issue.milestone.title
- else
None
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index 0bff8bdbead..15c84c7ced2 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -1,55 +1,7 @@
.append-bottom-10
.check-all-holder
= check_box_tag "check_all_issues", nil, false, class: "check_all_issues left"
- .issues-filters
- .dropdown.inline
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-user
- %span.light assignee:
- - if @assignee.present?
- %strong= @assignee.name
- - elsif params[:assignee_id] == "0"
- Unassigned
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(assignee_id: nil) do
- Any
- = link_to project_filter_path(assignee_id: 0) do
- Unassigned
- - @assignees.sort_by(&:name).each do |user|
- %li
- = link_to project_filter_path(assignee_id: user.id) do
- = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
- = user.name
-
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-clock-o
- %span.light milestone:
- - if @milestone.present?
- %strong= @milestone.title
- - elsif params[:milestone_id] == "0"
- None (backlog)
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(milestone_id: nil) do
- Any
- = link_to project_filter_path(milestone_id: 0) do
- None (backlog)
- - project_active_milestones.each do |milestone|
- %li
- = link_to project_filter_path(milestone_id: milestone.id) do
- %strong= milestone.title
- %small.light= milestone.expires_at
-
- .pull-right
- = render 'shared/sort_dropdown'
+ = render 'projects/issuable_filter'
.clearfix
.issues_bulk_update.hide
diff --git a/app/views/projects/issues/index.atom.builder b/app/views/projects/issues/index.atom.builder
index 012ba235951..61e651da932 100644
--- a/app/views/projects/issues/index.atom.builder
+++ b/app/views/projects/issues/index.atom.builder
@@ -7,17 +7,6 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
@issues.each do |issue|
- xml.entry do
- xml.id project_issue_url(@project, issue)
- xml.link :href => project_issue_url(@project, issue)
- xml.title truncate(issue.title, :length => 80)
- xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
- xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(issue.author_email)
- xml.author do |author|
- xml.name issue.author_name
- xml.email issue.author_email
- end
- xml.summary issue.title
- end
+ issue_to_atom(xml, issue)
end
end
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 4ec362b3063..8db6241f21f 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -1,4 +1,4 @@
-= render "head"
+= render "projects/issues_nav"
.row
.fixed.fixed.sidebar-expand-button.hidden-lg.hidden-md.hidden-xs
%i.fa.fa-list.fa-2x
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 71eb0d5c866..01a1fabda26 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -38,8 +38,12 @@
- else
Open
+ .cross-project-ref
+ %i.fa.fa-link.has_tooltip{:"data-original-title" => 'Cross-project reference'}
+ = cross_project_reference(@project, @issue)
+
.creator
- Created by #{link_to_member(@project, @issue.author)} #{time_ago_with_tooltip(@issue.created_at)}
+ Created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)}
%h4.title
= gfm escape_once(@issue.title)
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 06568278de8..c7c17c7797e 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -1,4 +1,4 @@
-= render "projects/issues/head"
+= render "projects/issues_nav"
- if can? current_user, :admin_label, @project
= link_to new_project_label_path(@project), class: "pull-right btn btn-new" do
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 1ee2e1bdae8..dedb060a231 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -1,13 +1,12 @@
%li{ class: mr_css_classes(merge_request) }
.merge-request-title
- %span.light= "##{merge_request.iid}"
= link_to_gfm truncate(merge_request.title, length: 80), project_merge_request_path(merge_request.target_project, merge_request), class: "row_title"
- if merge_request.merged?
%small.pull-right
%i.fa.fa-check
MERGED
- else
- %span.pull-right
+ %span.pull-right.hidden-xs
- if merge_request.for_fork?
%span.light
#{merge_request.source_project_namespace}:
@@ -15,6 +14,7 @@
%i.fa.fa-angle-right.light
= merge_request.target_branch
.merge-request-info
+ %span.light= "##{merge_request.iid}"
- if merge_request.author
authored by #{link_to_member(merge_request.source_project, merge_request.author)}
- if merge_request.votes_count > 0
@@ -31,7 +31,7 @@
%span.task-status
= merge_request.task_status
- .pull-right
+ .pull-right.hidden-xs
%small updated #{time_ago_with_tooltip(merge_request.updated_at, 'bottom', 'merge_request_updated_ago')}
.merge-request-labels
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index be638d7cac1..b93e0f9da3e 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -1,67 +1,12 @@
-- if can? current_user, :write_merge_request, @project
- = link_to new_project_merge_request_path(@project), class: "pull-right btn btn-new", title: "New Merge Request" do
- %i.fa.fa-plus
- New Merge Request
-%h3.page-title
- Merge Requests
-%hr
+= render "projects/issues_nav"
+
.row
- .fixed.sidebar-expand-button.hidden-lg.hidden-md
- %i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'shared/project_filter', project_entities_path: project_merge_requests_path(@project),
labels: true, redirect: 'merge_requests', entity: 'merge_request'
.col-md-9
- .mr-filters.append-bottom-10
- .dropdown.inline
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-user
- %span.light assignee:
- - if @assignee.present?
- %strong= @assignee.name
- - elsif params[:assignee_id] == "0"
- Unassigned
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(assignee_id: nil) do
- Any
- = link_to project_filter_path(assignee_id: 0) do
- Unassigned
- - @assignees.sort_by(&:name).each do |user|
- %li
- = link_to project_filter_path(assignee_id: user.id) do
- = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
- = user.name
-
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-clock-o
- %span.light milestone:
- - if @milestone.present?
- %strong= @milestone.title
- - elsif params[:milestone_id] == "0"
- None (backlog)
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(milestone_id: nil) do
- Any
- = link_to project_filter_path(milestone_id: 0) do
- None (backlog)
- - project_active_milestones.each do |milestone|
- %li
- = link_to project_filter_path(milestone_id: milestone.id) do
- %strong= milestone.title
- %small.light= milestone.expires_at
-
- .pull-right
- = render 'shared/sort_dropdown'
-
+ .append-bottom-10
+ = render 'projects/issuable_filter'
.panel.panel-default
%ul.well-list.mr-list
= render @merge_requests
diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
index 9540453ce3e..63db4b30968 100644
--- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml
+++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
@@ -10,11 +10,11 @@
- target_remote = @merge_request.target_project.namespace.nil? ? "target" :@merge_request.target_project.namespace.path
%p
%strong Step 1.
- Checkout the branch we are going to merge and pull in the code
+ Fetch the code and create a new branch pointing to it
%pre.dark
:preserve
- git checkout -b #{@merge_request.source_project_path}-#{@merge_request.source_branch} #{@merge_request.target_branch}
- git pull #{@merge_request.source_project.http_url_to_repo} #{@merge_request.source_branch}
+ git fetch #{@merge_request.source_project.http_url_to_repo} #{@merge_request.source_branch}
+ git checkout -b #{@merge_request.source_project_path}-#{@merge_request.source_branch} FETCH_HEAD
%p
%strong Step 2.
Merge the branch and push the changes to GitLab
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index 7e5a4eda508..866b236d827 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -8,6 +8,10 @@
- else
Open
+ .cross-project-ref
+ %i.fa.fa-link.has_tooltip{:"data-original-title" => 'Cross-project reference'}
+ = cross_project_reference(@project, @merge_request)
+
.creator
Created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)}
diff --git a/app/views/projects/merge_requests/show/_state_widget.html.haml b/app/views/projects/merge_requests/show/_state_widget.html.haml
index 87dad6140be..a4f2a890969 100644
--- a/app/views/projects/merge_requests/show/_state_widget.html.haml
+++ b/app/views/projects/merge_requests/show/_state_widget.html.haml
@@ -11,14 +11,18 @@
- if @merge_request.closed?
%h4
- Closed by #{link_to_member(@project, @merge_request.closed_event.author, avatar: false)}
- #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}
+ Closed
+ - if @merge_request.closed_event
+ by #{link_to_member(@project, @merge_request.closed_event.author, avatar: false)}
+ #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}
%p Changes were not merged into target branch
- if @merge_request.merged?
%h4
- Merged by #{link_to_member(@project, @merge_request.merge_event.author, avatar: false)}
- #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
+ Merged
+ - if @merge_request.merge_event
+ by #{link_to_member(@project, @merge_request.merge_event.author, avatar: false)}
+ #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
= render "projects/merge_requests/show/remove_source_branch"
- if @merge_request.locked?
@@ -44,4 +48,3 @@
Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'}
= succeed '.' do
!= gfm(issues_sentence(@closes_issues))
-
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 03367b7cdbf..0db0b114d63 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -1,4 +1,4 @@
-= render "projects/issues/head"
+= render "projects/issues_nav"
.milestones_content
%h3.page-title
Milestones
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 8263f7530a2..f08ccc1d570 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -1,4 +1,4 @@
-= render "projects/issues/head"
+= render "projects/issues_nav"
%h3.page-title
Milestone ##{@milestone.iid}
.pull-right
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index f5cd0f21e01..e77ef84f51c 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -3,7 +3,7 @@
= render 'projects/errors'
.project-edit-content
- = form_for @project, remote: true, html: { class: 'new_project form-horizontal' } do |f|
+ = form_for @project, html: { class: 'new_project form-horizontal' } do |f|
.form-group.project-name-holder
= f.label :name, class: 'control-label' do
%strong Project name
diff --git a/app/views/projects/new_tree/show.html.haml b/app/views/projects/new_tree/show.html.haml
index c47c0a3f642..f09d3659774 100644
--- a/app/views/projects/new_tree/show.html.haml
+++ b/app/views/projects/new_tree/show.html.haml
@@ -19,14 +19,14 @@
Encoding
.col-sm-10
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
- = render 'shared/commit_message_container', params: params,
- placeholder: 'Add new file'
.file-holder
.file-title
%i.fa.fa-file
.file-content.code
%pre#editor= params[:content]
+ = render 'shared/commit_message_container', params: params,
+ placeholder: 'Add new file'
= hidden_field_tag 'content', '', id: 'file-content'
= render 'projects/commit_button', ref: @ref,
cancel_path: project_tree_path(@project, @id)
diff --git a/app/views/projects/no_repo.html.haml b/app/views/projects/no_repo.html.haml
new file mode 100644
index 00000000000..dd576243510
--- /dev/null
+++ b/app/views/projects/no_repo.html.haml
@@ -0,0 +1,22 @@
+%h2
+ %i.fa.fa-warning
+ No repository
+
+%p.slead
+ The repository for this project does not exist.
+ %br
+ This means you can not push code until you create an empty repository or import existing one.
+%hr
+
+.no-repo-actions
+ = link_to project_repository_path(@project), method: :post, class: 'btn btn-primary' do
+ Create empty bare repository
+
+ %strong.prepend-left-10.append-right-10 or
+
+ = link_to new_project_import_path(@project), class: 'btn' do
+ Import repository
+
+- if can? current_user, :remove_project, @project
+ .prepend-top-20
+ = link_to 'Remove project', @project, data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index 05946162d3b..47ffe1fd2f3 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -19,7 +19,7 @@
= yield(:note_actions)
%a.btn.grouped.js-close-discussion-note-form Cancel
- .note-form-option
+ .note-form-option.hidden-xs
%a.choose-btn.btn.js-choose-note-attachment-button
%i.fa.fa-paperclip
%span Choose File ...
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index aa52ff35d0c..354afd3e2c9 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -18,6 +18,8 @@
%i.fa.fa-trash-o.cred
Remove
= link_to_member(@project, note.author, avatar: false)
+ %span.author-username
+ = '@' + note.author.username
%span.note-last-update
= note_timestamp(note)
@@ -60,7 +62,7 @@
- if note.attachment.image?
= link_to note.attachment.secure_url, target: '_blank' do
= image_tag note.attachment.secure_url, class: 'note-image-attach'
- .attachment.pull-right
+ .attachment
= link_to note.attachment.secure_url, target: "_blank" do
%i.fa.fa-paperclip
= note.attachment_identifier
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index 16d59d1fe9d..1151f22c7e8 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -28,7 +28,7 @@
- @service.fields.each do |field|
- name = field[:name]
- - value = @service.send(name)
+ - value = @service.send(name) unless field[:type] == 'password'
- type = field[:type]
- placeholder = field[:placeholder]
- choices = field[:choices]
@@ -45,6 +45,8 @@
= f.check_box name
- elsif type == 'select'
= f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
+ - elsif type == 'password'
+ = f.password_field name, class: 'form-control'
.form-actions
= f.submit 'Save', class: 'btn btn-save'
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
index bce105a033b..4ab102ba96c 100644
--- a/app/views/projects/tags/_tag.html.haml
+++ b/app/views/projects/tags/_tag.html.haml
@@ -4,6 +4,9 @@
= link_to project_commits_path(@project, tag.name), class: "" do
%i.fa.fa-tag
= tag.name
+ - if tag.message.present?
+ &nbsp;
+ = strip_gpg_signature(tag.message)
.pull-right
- if can? current_user, :download_code, @project
= render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-small'
diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml
index aa08b397763..ad7ff8d3db8 100644
--- a/app/views/projects/tags/new.html.haml
+++ b/app/views/projects/tags/new.html.haml
@@ -21,7 +21,7 @@
= text_field_tag :message, nil, placeholder: 'Enter message.', required: false, tabindex: 3, class: 'form-control'
.light (Optional) Entering a message will create an annotated tag.
.form-actions
- = submit_tag 'Create tag', class: 'btn btn-create', tabindex: 3
+ = button_tag 'Create tag', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel'
:javascript
diff --git a/app/views/projects/team_members/_team_member.html.haml b/app/views/projects/team_members/_team_member.html.haml
index 5f29b58de32..7a9c0939ba0 100644
--- a/app/views/projects/team_members/_team_member.html.haml
+++ b/app/views/projects/team_members/_team_member.html.haml
@@ -5,7 +5,7 @@
- unless @project.personal? && user == current_user
.pull-left
= form_for(member, as: :project_member, url: project_team_member_path(@project, member.user)) do |f|
- = f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level), {}, class: "medium project-access-select span2 trigger-submit"
+ = f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level), {}, class: "trigger-submit"
&nbsp;
= link_to project_team_member_path(@project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do
%i.fa.fa-minus.fa-inverse
diff --git a/app/views/projects/team_members/import.html.haml b/app/views/projects/team_members/import.html.haml
index 510b579fe2f..d1f46c61b2e 100644
--- a/app/views/projects/team_members/import.html.haml
+++ b/app/views/projects/team_members/import.html.haml
@@ -9,6 +9,6 @@
.col-sm-10= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "select2 lg", required: true)
.form-actions
- = submit_tag 'Import project members', class: "btn btn-create"
+ = button_tag 'Import project members', class: "btn btn-create"
= link_to "Cancel", project_team_index_path(@project), class: "btn btn-cancel"
diff --git a/app/views/search/_project_filter.html.haml b/app/views/search/_project_filter.html.haml
index c201b3d6c47..ad933502a28 100644
--- a/app/views/search/_project_filter.html.haml
+++ b/app/views/search/_project_filter.html.haml
@@ -25,6 +25,7 @@
= @search_results.notes_count
%li{class: ("active" if @scope == 'wiki_blobs')}
= link_to search_filter_path(scope: 'wiki_blobs') do
+ %i.fa.fa-book
Wiki
.pull-right
= @search_results.wiki_blobs_count
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index bae57917a4c..5b4816e4c40 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -6,7 +6,7 @@
.col-sm-6
= search_field_tag :search, params[:search], placeholder: "issue 143", class: "form-control search-text-input", id: "dashboard_search"
.col-sm-4
- = submit_tag 'Search', class: "btn btn-create"
+ = button_tag 'Search', class: "btn btn-create"
.form-group
.col-sm-2
- unless params[:snippets].eql? 'true'
diff --git a/app/views/shared/_choose_group_avatar_button.html.haml b/app/views/shared/_choose_group_avatar_button.html.haml
new file mode 100644
index 00000000000..299c0bd42a2
--- /dev/null
+++ b/app/views/shared/_choose_group_avatar_button.html.haml
@@ -0,0 +1,7 @@
+%a.choose-btn.btn.btn-small.js-choose-group-avatar-button
+ %i.fa.fa-paperclip
+ %span Choose File ...
+&nbsp;
+%span.file_name.js-avatar-filename File name...
+= f.file_field :avatar, class: 'js-group-avatar-input hidden'
+.light The maximum file size allowed is 200KB.
diff --git a/app/views/shared/_group_form.html.haml b/app/views/shared/_group_form.html.haml
new file mode 100644
index 00000000000..93294e42505
--- /dev/null
+++ b/app/views/shared/_group_form.html.haml
@@ -0,0 +1,12 @@
+.form-group
+ = f.label :name, class: 'control-label' do
+ Group name
+ .col-sm-10
+ = f.text_field :name, placeholder: 'Example Group', class: 'form-control',
+ autofocus: local_assigns[:autofocus] || false
+
+.form-group.group-description-holder
+ = f.label :description, 'Details', class: 'control-label'
+ .col-sm-10
+ = f.text_area :description, maxlength: 250,
+ class: 'form-control js-gfm-input', rows: 4
diff --git a/app/views/shared/_group_tips.html.haml b/app/views/shared/_group_tips.html.haml
new file mode 100644
index 00000000000..e5cf783beb7
--- /dev/null
+++ b/app/views/shared/_group_tips.html.haml
@@ -0,0 +1,6 @@
+%ul
+ %li A group is a collection of several projects
+ %li Groups are private by default
+ %li Members of a group may only view projects they have permission to access
+ %li Group project URLs are prefixed with the group namespace
+ %li Existing projects may be moved into a group
diff --git a/app/views/shared/_promo.html.haml b/app/views/shared/_promo.html.haml
index 3400c345c4c..3596aabe309 100644
--- a/app/views/shared/_promo.html.haml
+++ b/app/views/shared/_promo.html.haml
@@ -1,5 +1,5 @@
.gitlab-promo
= link_to 'Homepage', promo_url
= link_to "Blog", promo_url + '/blog/'
- = link_to "@gitlabhq", "https://twitter.com/gitlabhq"
+ = link_to "@gitlab", "https://twitter.com/gitlab"
= link_to "Requests", "http://feedback.gitlab.com/"
diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml
index 7b37b39780e..54f59245690 100644
--- a/app/views/shared/_sort_dropdown.html.haml
+++ b/app/views/shared/_sort_dropdown.html.haml
@@ -9,13 +9,13 @@
%ul.dropdown-menu
%li
= link_to project_filter_path(sort: 'newest') do
- Newest
+ = sort_title_recently_created
= link_to project_filter_path(sort: 'oldest') do
- Oldest
+ = sort_title_oldest_created
= link_to project_filter_path(sort: 'recently_updated') do
- Recently updated
+ = sort_title_recently_updated
= link_to project_filter_path(sort: 'last_updated') do
- Last updated
+ = sort_title_oldest_updated
= link_to project_filter_path(sort: 'milestone_due_soon') do
Milestone due soon
= link_to project_filter_path(sort: 'milestone_due_later') do
diff --git a/app/views/users/_groups.html.haml b/app/views/users/_groups.html.haml
index 09b2985d498..ea008c2dede 100644
--- a/app/views/users/_groups.html.haml
+++ b/app/views/users/_groups.html.haml
@@ -1,3 +1,3 @@
- groups.each do |group|
= link_to group, class: 'profile-groups-avatars', :title => group.name do
- = image_tag group_icon(group.path)
+ - image_tag group_icon(group.path)
diff --git a/app/views/users/show.atom.builder b/app/views/users/show.atom.builder
new file mode 100644
index 00000000000..b7216a88765
--- /dev/null
+++ b/app/views/users/show.atom.builder
@@ -0,0 +1,12 @@
+xml.instruct!
+xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlnsmedia" => "http://search.yahoo.com/mrss/" do
+ xml.title "Activity feed for #{@user.name}"
+ xml.link href: user_url(@user, :atom), rel: "self", type: "application/atom+xml"
+ xml.link href: user_url(@user), rel: "alternate", type: "text/html"
+ xml.id projects_url
+ xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
+
+ @events.each do |event|
+ event_to_atom(xml, event)
+ end
+end
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index cb49c030af2..54f2666ce5d 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -18,7 +18,15 @@
%h4 Groups:
= render 'groups', groups: @groups
%hr
- %h4 User Activity:
+ %h4
+ User Activity:
+
+ - if current_user
+ %span.rss-icon.pull-right
+ = link_to user_path(@user, :atom, { private_token: current_user.private_token }) do
+ %strong
+ %i.fa.fa-rss
+
= render @events
.col-md-4
= render 'profile', user: @user
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 2947c8e3ecd..e3f6f3a6aef 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -21,5 +21,8 @@ class EmailsOnPushWorker
recipients.split(" ").each do |recipient|
Notify.repository_push_email(project_id, recipient, author_id, branch, compare).deliver
end
+ ensure
+ compare = nil
+ GC.start
end
end
diff --git a/app/workers/project_service_worker.rb b/app/workers/project_service_worker.rb
new file mode 100644
index 00000000000..cc0a7f25664
--- /dev/null
+++ b/app/workers/project_service_worker.rb
@@ -0,0 +1,9 @@
+class ProjectServiceWorker
+ include Sidekiq::Worker
+
+ sidekiq_options queue: :project_web_hook
+
+ def perform(hook_id, data)
+ Service.find(hook_id).execute(data)
+ end
+end