diff --git a/CHANGELOG b/CHANGELOG
index 6ceb9509bc..850c0578d8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,10 @@
Please view this file on the master branch, on stable branches it's out of date.
v 7.9.0 (unreleased)
+ - Add HipChat integration documentation (Stan Hu)
+ - Update documentation for object_kind field in Webhook push and tag push Webhooks (Stan Hu)
+ - Fix broken email images (Hannes Rosenögger)
+ - Automatically config git if user forgot, where possible (Zeger-Jan van de Weg)
- Fix mass SQL statements on initial push (Hannes Rosenögger)
- Add tag push notifications and normalize HipChat and Slack messages to be consistent (Stan Hu)
- Add comment notification events to HipChat and Slack services (Stan Hu)
@@ -13,6 +17,8 @@ v 7.9.0 (unreleased)
- Improve error messages for file edit failures
- Improve UI for commits, issues and merge request lists
- Fix commit comments on first line of diff not rendering in Merge Request Discussion view.
+ - Allow admins to override restricted project visibility settings.
+ - Move restricted visibility settings from gitlab.yml into the web UI.
- Improve trigger merge request hook when source project branch has been updated (Kirill Zaitsev)
- Save web edit in new branch
- Fix ordering of imported but unchanged projects (Marco Wessel)
@@ -21,11 +27,13 @@ v 7.9.0 (unreleased)
- Fix checkbox alignment on the application settings page.
- Generalize image upload in drag and drop in markdown to all files (Hannes Rosenögger)
- Fix mass-unassignment of issues (Robert Speicher)
+ - Fix hidden diff comments in merge request discussion view
- Allow user confirmation to be skipped for new users via API
- Add a service to send updates to an Irker gateway (Romain Coltel)
- Ignore case of LDAP user DN when checking group membership.
- Add brakeman (security scanner for Ruby on Rails)
- Slack username and channel options
+ - Restrict permissions on backup files
- Add grouped milestones from all projects to dashboard.
- Web hook sends pusher email as well as commiter
- Add Bitbucket omniauth provider.
@@ -35,16 +43,16 @@ v 7.9.0 (unreleased)
- Send notifications and leave system comments when bulk updating issues.
- Automatically link commit ranges to compare page: sha1...sha4 or sha1..sha4 (includes sha1 in comparison)
- Move groups page from profile to dashboard
- - Starred projects page at dashboard
+ - Starred projects page at dashboard
- Blocking user does not remove him/her from project/groups but show blocked label
- Change subject of EmailsOnPush emails to include namespace, project and branch.
- Change subject of EmailsOnPush emails to include first commit message when multiple were pushed.
- Remove confusing footer from EmailsOnPush mail body.
- - Add list of changed files to EmailsOnPush emails.
- - Add option to send EmailsOnPush emails from committer email if domain matches.
+ - Add list of changed files to EmailsOnPush emails.
+ - Add option to send EmailsOnPush emails from committer email if domain matches.
- Add option to disable code diffs in EmailOnPush emails.
- Wrap commit message in EmailsOnPush email.
- - Send EmailsOnPush emails when deleting commits using force push.
+ - Send EmailsOnPush emails when deleting commits using force push.
- Fix EmailsOnPush email comparison link to include first commit.
- Fix highliht of selected lines in file
- Reject access to group/project avatar if the user doesn't have access.
@@ -54,6 +62,20 @@ v 7.9.0 (unreleased)
- Make email display name configurable
- Improve json validation in hook data
- Use Emoji One
+ - Updated emoji help documentation to properly reference EmojiOne.
+ - Fix missing GitHub organisation repositories on import page.
+ - Added blue theme
+ - Remove annoying notice messages when create/update merge request
+ - Allow smb:// links in Markdown text.
+ - Filter merge request by title or description at Merge Requests page
+ - Block user if he/she was blocked in Active Directory
+ - Fix import pages not working after first load.
+ - Use custom LDAP label in LDAP signin form.
+ - Execute hooks and services when branch or tag is created or deleted through web interface.
+ - Block and unblock user if he/she was blocked/unblocked in Active Directory
+ - Raise recommended number of unicorn workers from 2 to 3
+ - Use same layout and interactivity for project members as group members.
+ - Prevent gitlab-shell character encoding issues by receiving its changes as raw data.
v 7.8.4
- Fix issue_tracker_id substitution in custom issue trackers
@@ -61,7 +83,6 @@ v 7.8.4
v 7.8.3
- Bump version of gitlab_git fixing annotated tags without message
- - Allow smb:// links in Markdown text.
v 7.8.2
- Fix service migration issue when upgrading from versions prior to 7.3
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index fe16b348d9..e70b4523ae 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-2.5.4
+2.6.0
diff --git a/Gemfile b/Gemfile
index 61316ee730..ebbd641e44 100644
--- a/Gemfile
+++ b/Gemfile
@@ -39,7 +39,7 @@ gem "browser"
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", '7.1.0'
+gem "gitlab_git", '~> 7.1.0'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.0.rc2', require: 'grack'
@@ -179,6 +179,9 @@ gem 'ace-rails-ap'
# Keyboard shortcuts
gem 'mousetrap-rails'
+# Detect and convert string character encoding
+gem 'charlock_holmes'
+
# Shutting down requests that take too long
gem "slowpoke"
@@ -270,7 +273,6 @@ end
group :production do
gem "gitlab_meta", '7.0'
- gem "therubyracer"
end
gem "newrelic_rpm"
diff --git a/Gemfile.lock b/Gemfile.lock
index 70f239c666..d9da09ac91 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -321,7 +321,6 @@ GEM
addressable (~> 2.3)
letter_opener (1.1.2)
launchy (~> 2.2)
- libv8 (3.16.14.3)
listen (2.3.1)
celluloid (>= 0.15.2)
rb-fsevent (>= 0.9.3)
@@ -480,7 +479,6 @@ GEM
redis-store (~> 1.1.0)
redis-store (1.1.4)
redis (>= 2.2)
- ref (1.0.5)
request_store (1.0.5)
rest-client (1.6.7)
mime-types (>= 1.16)
@@ -605,9 +603,6 @@ GEM
tins (~> 0.8)
terminal-table (1.4.5)
test_after_commit (0.2.2)
- therubyracer (0.12.0)
- libv8 (~> 3.16.14.0)
- ref
thin (1.6.1)
daemons (>= 1.0.9)
eventmachine (>= 1.0.0)
@@ -689,6 +684,7 @@ DEPENDENCIES
cal-heatmap-rails (~> 0.0.1)
capybara (~> 2.2.1)
carrierwave
+ charlock_holmes
coffee-rails
colored
coveralls
@@ -714,7 +710,7 @@ DEPENDENCIES
gitlab-grack (~> 2.0.0.rc2)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1)
- gitlab_git (= 7.1.0)
+ gitlab_git (~> 7.1.0)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.0)
gollum-lib (~> 4.0.0)
@@ -795,7 +791,6 @@ DEPENDENCIES
stamp
state_machine
test_after_commit
- therubyracer
thin
tinder (~> 1.9.2)
turbolinks
diff --git a/MAINTENANCE.md b/MAINTENANCE.md
index 19200fef38..d3d3667069 100644
--- a/MAINTENANCE.md
+++ b/MAINTENANCE.md
@@ -2,7 +2,7 @@
GitLab is a fast moving and evolving project. We currently don't have the resources to support many releases concurrently. We support exactly one stable release at any given time.
-GitLab follows the [Semantic Versioning](http://semver.org/) for its releases: `(Major).(Minor).(Patch)`.
+GitLab follows the [Semantic Versioning](http://semver.org/) for its releases: `(Major).(Minor).(Patch)` in a [pragmatic way](https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e).
- **Major version**: Whenever there is something significant or any backwards incompatible changes are introduced to the public API.
- **Minor version**: When new, backwards compatible functionality is introduced to the public API or a minor feature is introduced, or when a set of smaller features is rolled out.
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index bd61025116..4305b6144e 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -52,6 +52,7 @@ class Dispatcher
new ZenMode()
when 'projects:merge_requests:index'
shortcut_handler = new ShortcutsNavigation()
+ MergeRequests.init()
when 'dashboard:show'
new Dashboard()
new Activities()
@@ -72,9 +73,12 @@ class Dispatcher
new Activities()
shortcut_handler = new ShortcutsNavigation()
new ProjectsList()
- when 'groups:members'
+ when 'groups:group_members:index'
new GroupMembers()
new UsersSelect()
+ when 'projects:project_members:index'
+ new ProjectMembers()
+ new UsersSelect()
when 'groups:new', 'groups:edit', 'admin:groups:edit'
new GroupAvatar()
when 'projects:tree:show'
@@ -130,9 +134,8 @@ class Dispatcher
new DropzoneInput($('.wiki-form'))
when 'snippets', 'labels', 'graphs'
shortcut_handler = new ShortcutsNavigation()
- when 'team_members', 'deploy_keys', 'hooks', 'services', 'protected_branches'
+ when 'project_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/importer_status.js.coffee b/app/assets/javascripts/importer_status.js.coffee
index e0e7771ab2..be8d225e73 100644
--- a/app/assets/javascripts/importer_status.js.coffee
+++ b/app/assets/javascripts/importer_status.js.coffee
@@ -16,20 +16,20 @@ class @ImporterStatus
$(".js-import-all").click (event) =>
$(".js-add-to-import").each ->
$(this).click()
-
+
setAutoUpdate: ->
setInterval (=>
$.get @jobs_url, (data) =>
$.each data, (i, job) =>
job_item = $("#project_" + job.id)
status_field = job_item.find(".job-status")
-
+
if job.import_status == 'finished'
job_item.removeClass("active").addClass("success")
- status_field.html(' done')
+ status_field.html(' done')
else if job.import_status == 'started'
status_field.html(" started")
else
status_field.html(job.import_status)
-
- ), 4000
\ No newline at end of file
+
+ ), 4000
diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee
index 6513f4bcef..40bb9e9cb0 100644
--- a/app/assets/javascripts/issues.js.coffee
+++ b/app/assets/javascripts/issues.js.coffee
@@ -47,7 +47,7 @@
initSearch: ->
@timer = null
$("#issue_search").keyup ->
- clearTimeout(@timer);
+ clearTimeout(@timer)
@timer = setTimeout(Issues.filterResults, 500)
filterResults: =>
diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee
index 9201c84c5e..83434c1b9b 100644
--- a/app/assets/javascripts/merge_requests.js.coffee
+++ b/app/assets/javascripts/merge_requests.js.coffee
@@ -1,8 +1,35 @@
#
# * Filter merge requests
#
-@merge_requestsPage = ->
- $('#assignee_id').select2()
- $('#milestone_id').select2()
- $('#milestone_id, #assignee_id').on 'change', ->
- $(this).closest('form').submit()
+@MergeRequests =
+ init: ->
+ MergeRequests.initSearch()
+
+ # Make sure we trigger ajax request only after user stop typing
+ initSearch: ->
+ @timer = null
+ $("#issue_search").keyup ->
+ clearTimeout(@timer)
+ @timer = setTimeout(MergeRequests.filterResults, 500)
+
+ filterResults: =>
+ form = $("#issue_search_form")
+ search = $("#issue_search").val()
+ $('.merge-requests-holder').css("opacity", '0.5')
+ issues_url = form.attr('action') + '? '+ form.serialize()
+
+ $.ajax
+ type: "GET"
+ url: form.attr('action')
+ data: form.serialize()
+ complete: ->
+ $('.merge-requests-holder').css("opacity", '1.0')
+ success: (data) ->
+ $('.merge-requests-holder').html(data.html)
+ # Change url so if user reload a page - search results are saved
+ History.replaceState {page: issues_url}, document.title, issues_url
+ MergeRequests.reload()
+ dataType: "json"
+
+ reload: ->
+ $('#filter_issue_search').val($('#issue_search').val())
diff --git a/app/assets/javascripts/project_members.js.coffee b/app/assets/javascripts/project_members.js.coffee
new file mode 100644
index 0000000000..896ba7e53e
--- /dev/null
+++ b/app/assets/javascripts/project_members.js.coffee
@@ -0,0 +1,4 @@
+class @ProjectMembers
+ constructor: ->
+ $('li.project_member').bind 'ajax:success', ->
+ $(this).fadeOut()
diff --git a/app/assets/stylesheets/base/gl_bootstrap.scss b/app/assets/stylesheets/base/gl_bootstrap.scss
index 0775c17181..be1ee90c18 100644
--- a/app/assets/stylesheets/base/gl_bootstrap.scss
+++ b/app/assets/stylesheets/base/gl_bootstrap.scss
@@ -152,12 +152,9 @@
*/
.panel {
.panel-heading {
- font-size: 14px;
- line-height: 18px;
-
.panel-head-actions {
position: relative;
- top: -6px;
+ top: -5px;
float: right;
}
}
@@ -190,6 +187,11 @@
}
}
+.panel-succes .panel-heading,
+.panel-info .panel-heading,
+.panel-danger .panel-heading,
+.panel-warning .panel-heading,
+.panel-primary .panel-heading,
.alert {
a {
@extend .alert-link;
@@ -197,3 +199,50 @@
text-decoration: underline;
}
}
+
+// Typography =================================================================
+
+.text-primary,
+.text-primary:hover {
+ color: $brand-primary;
+}
+
+.text-success,
+.text-success:hover {
+ color: $brand-success;
+}
+
+.text-danger,
+.text-danger:hover {
+ color: $brand-danger;
+}
+
+.text-warning,
+.text-warning:hover {
+ color: $brand-warning;
+}
+
+.text-info,
+.text-info:hover {
+ color: $brand-info;
+}
+
+// Tables =====================================================================
+
+table.table {
+ .dropdown-menu a {
+ text-decoration: none;
+ }
+
+ .success,
+ .warning,
+ .danger,
+ .info {
+ color: #fff;
+
+ a:not(.btn) {
+ text-decoration: underline;
+ color: #fff;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
index ea230646a8..ce82ad8031 100644
--- a/app/assets/stylesheets/base/gl_variables.scss
+++ b/app/assets/stylesheets/base/gl_variables.scss
@@ -716,8 +716,8 @@ $panel-border-radius: 0;
// $panel-footer-bg: #f5f5f5
$panel-default-text: $text-color;
-// $panel-default-border: #ddd
-// $panel-default-heading-bg: #f5f5f5
+$panel-default-border: $border-color;
+$panel-default-heading-bg: $background-color;
// $panel-primary-text: #fff
// $panel-primary-border: $brand-primary
diff --git a/app/assets/stylesheets/base/variables.scss b/app/assets/stylesheets/base/variables.scss
index 54af78ee08..4e2c64aa13 100644
--- a/app/assets/stylesheets/base/variables.scss
+++ b/app/assets/stylesheets/base/variables.scss
@@ -1,6 +1,5 @@
$style_color: #474D57;
$hover: #FFF3EB;
-$box_bg: #F9F9F9;
$gl-link-color: #446e9b;
$nprogress-color: #c0392b;
$gl-font-size: 14px;
@@ -9,6 +8,8 @@ $sidebar_width: 230px;
$avatar_radius: 50%;
$code_font_size: 13px;
$code_line_height: 1.5;
+$border-color: #dce4ec;
+$background-color: #ECF0F1;
/*
* State colors:
diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss
index 0224484d82..cd6bf64c0a 100644
--- a/app/assets/stylesheets/generic/buttons.scss
+++ b/app/assets/stylesheets/generic/buttons.scss
@@ -21,18 +21,6 @@
float: right;
}
- &.btn-small {
- padding: 2px 10px;
- font-size: 12px;
- }
-
- &.btn-tiny {
- font-size: 11px;
- padding: 2px 6px;
- line-height: 16px;
- margin: 2px;
- }
-
&.btn-close {
color: $gl-danger;
border-color: $gl-danger;
@@ -84,6 +72,3 @@
}
}
}
-
-.btn-group-small > .btn { @extend .btn.btn-small; }
-.btn-group-tiny > .btn { @extend .btn.btn-tiny; }
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index df0f150f40..b890149fd7 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -167,7 +167,7 @@ li.note {
background-color: inherit;
}
-.team_member_show {
+.project_member_show {
td:first-child {
color: #aaa;
}
diff --git a/app/assets/stylesheets/generic/files.scss b/app/assets/stylesheets/generic/files.scss
index 1ed41272ac..91220a856a 100644
--- a/app/assets/stylesheets/generic/files.scss
+++ b/app/assets/stylesheets/generic/files.scss
@@ -3,7 +3,7 @@
*
*/
.file-holder {
- border: 1px solid #CCC;
+ border: 1px solid $border-color;
margin-bottom: 1em;
table {
@@ -11,34 +11,30 @@
}
.file-title {
- background: #EEE;
- border-bottom: 1px solid #CCC;
+ position: relative;
+ background: $background-color;
+ border-bottom: 1px solid $border-color;
text-shadow: 0 1px 1px #fff;
margin: 0;
text-align: left;
padding: 10px 15px;
- .options {
+ .file-actions {
float: right;
- margin-top: -3px;
+ position: absolute;
+ top: 5px;
+ right: 15px;
+
+ .btn {
+ padding: 0px 10px;
+ font-size: 13px;
+ line-height: 28px;
+ }
}
.left-options {
margin-top: -3px;
}
-
- .file_name {
- font-weight: bold;
- padding-left: 3px;
- font-size: 14px;
-
- small {
- color: #888;
- font-size: 13px;
- font-weight: normal;
- padding-left: 10px;
- }
- }
}
.file-content {
background: #fff;
@@ -119,7 +115,7 @@
ol {
margin-left: 40px;
padding: 10px 0;
- border-left: 1px solid #CCC;
+ border-left: 1px solid $border-color;
margin-bottom: 0;
background: white;
li {
diff --git a/app/assets/stylesheets/generic/highlight.scss b/app/assets/stylesheets/generic/highlight.scss
index 0f8225d682..2e13ee842e 100644
--- a/app/assets/stylesheets/generic/highlight.scss
+++ b/app/assets/stylesheets/generic/highlight.scss
@@ -57,7 +57,7 @@
.note-text .code {
border: none;
box-shadow: none;
- background: $box_bg;
+ background: $background-color;
padding: 1em;
overflow-x: auto;
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss
index ff08641263..7a262c4589 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/generic/selects.scss
@@ -2,7 +2,7 @@
.select2-container, .select2-container.select2-drop-above {
.select2-choice {
background: #FFF;
- border-color: #BBB;
+ border-color: #CCC;
padding: 6px 14px;
line-height: 1.42857143;
height: auto;
diff --git a/app/assets/stylesheets/generic/tables.scss b/app/assets/stylesheets/generic/tables.scss
index 71a7d4abae..a66e45577d 100644
--- a/app/assets/stylesheets/generic/tables.scss
+++ b/app/assets/stylesheets/generic/tables.scss
@@ -9,7 +9,7 @@ table {
th {
font-weight: normal;
font-size: 15px;
- border-bottom: 1px solid #CCC !important;
+ border-bottom: 1px solid $border-color !important;
}
td {
border-color: #F1F1F1 !important;
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index f46d6542c0..e7125c0399 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -30,7 +30,8 @@
color: #666;
font-size: 14px;
font-weight: normal;
- padding: 10px 0;
+ padding: 3px 0;
+ margin-bottom: 10px;
}
.commit-info-row {
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index e167d044e4..84361e1548 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -1,17 +1,11 @@
.commits-compare-switch{
+ @extend .btn;
background: image-url("switch_icon.png") no-repeat center center;
- width: 32px;
- height: 32px;
text-indent: -9999px;
float: left;
margin-right: 9px;
- border: 1px solid #DDD;
- @include border-radius(4px);
- padding: 4px;
- background-color: #EEE;
}
-
.lists-separator {
margin: 10px 0;
border-color: #DDD;
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 54311a6885..5a9f93dc03 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -1,25 +1,30 @@
.diff-file {
- border: 1px solid #CCC;
+ border: 1px solid $border-color;
margin-bottom: 1em;
.diff-header {
- @extend .clearfix;
- background: #EEE;
- border-bottom: 1px solid #CCC;
- padding: 5px 5px 5px 10px;
+ position: relative;
+ background: $background-color;
+ border-bottom: 1px solid $border-color;
+ padding: 10px 15px;
color: #555;
z-index: 10;
> span {
+ @include str-truncated(65%);
font-family: $monospace_font;
- line-height: 2;
}
.diff-btn-group {
float: right;
+ position: absolute;
+ top: 5px;
+ right: 15px;
.btn {
- background-color: #FFF;
+ padding: 0px 10px;
+ font-size: 13px;
+ line-height: 28px;
}
}
@@ -87,7 +92,7 @@
background: #F5F5F5;
color: rgba(0,0,0,0.3);
padding: 0px 5px;
- border-right: 1px solid #ccc;
+ border-right: 1px solid $border-color;
text-align: right;
min-width: 35px;
max-width: 50px;
@@ -136,7 +141,7 @@
background: #ffecec;
}
&.matched {
- color: #ccc;
+ color: $border-color;
background: #fafafa;
}
&.parallel {
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 88aa256e56..851f126318 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -16,8 +16,6 @@
}
}
.commit-button-annotation {
- @extend .alert;
- @extend .alert-info;
display: inline-block;
margin: 0;
padding: 2px;
diff --git a/app/assets/stylesheets/pages/graph.scss b/app/assets/stylesheets/pages/graph.scss
index 3d878d1e52..c3b10d144e 100644
--- a/app/assets/stylesheets/pages/graph.scss
+++ b/app/assets/stylesheets/pages/graph.scss
@@ -1,11 +1,11 @@
.project-network {
- border: 1px solid #CCC;
+ border: 1px solid $border-color;
.controls {
color: #888;
font-size: 14px;
padding: 5px;
- border-bottom: 1px solid #bbb;
+ border-bottom: 1px solid $border-color;
background: #EEE;
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 9bd34b7376..d41e34caba 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -12,14 +12,8 @@
}
.accept-merge-holder {
- margin-top: 5px;
-
.accept-action {
display: inline-block;
-
- .accept_merge_request {
- padding: 10px 20px;
- }
}
.accept-control {
@@ -123,7 +117,8 @@
}
.mr-state-widget {
- background: $box_bg;
+ font-size: 13px;
+ background: #F9F9F9;
margin-bottom: 20px;
color: #666;
border: 1px solid #EEE;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 384ff6d740..70505dc430 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -89,6 +89,11 @@ ul.notes {
}
}
+// Diff code in discussion view
+.discussion-body .diff-file .line_content {
+ white-space: pre-wrap;
+}
+
.diff-file .notes_holder {
font-size: 13px;
line-height: 18px;
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 0ab62b7ae4..81afe05162 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -80,6 +80,10 @@
&.violet {
background: #548;
}
+
+ &.blue {
+ background: #2980b9;
+ }
}
}
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index bfd05973d7..7475595167 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -156,7 +156,7 @@ ul.nav.nav-projects-tabs {
}
}
-.team_member_row form {
+.project_member_row form {
margin: 0px;
}
@@ -301,3 +301,8 @@ table.table.protected-branches-list tr.no-border {
border: 0;
}
}
+
+.project-import .btn {
+ float: left;
+ margin-right: 10px;
+}
diff --git a/app/assets/stylesheets/themes/ui_blue.scss b/app/assets/stylesheets/themes/ui_blue.scss
new file mode 100644
index 0000000000..cb7980b5a0
--- /dev/null
+++ b/app/assets/stylesheets/themes/ui_blue.scss
@@ -0,0 +1,6 @@
+/**
+ * Modern GitLab UI theme
+ */
+.ui_blue {
+ @include dark-theme(#BECDE9, #2980b9, #1970a9, #096099);
+}
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 3cbe409257..72bb09153b 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -20,6 +20,15 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end
def application_setting_params
+ restricted_levels = params[:application_setting][:restricted_visibility_levels]
+ if restricted_levels.nil?
+ params[:application_setting][:restricted_visibility_levels] = []
+ else
+ restricted_levels.map! do |level|
+ level.to_i
+ end
+ end
+
params.require(:application_setting).permit(
:default_projects_limit,
:default_branch_protection,
@@ -29,7 +38,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:twitter_sharing_enabled,
:sign_in_text,
:home_page_url,
- :help_text
+ :help_text,
+ restricted_visibility_levels: []
)
end
end
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 65dc027c8e..9d9adaa467 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -1,16 +1,16 @@
class Admin::GroupsController < Admin::ApplicationController
- before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :project_teams_update]
+ before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :members_update]
def index
@groups = Group.all
@groups = @groups.sort(@sort = params[:sort])
@groups = @groups.search(params[:name]) if params[:name].present?
- @groups = @groups.page(params[:page]).per(20)
+ @groups = @groups.page(params[:page]).per(PER_PAGE)
end
def show
- @members = @group.members.order("access_level DESC").page(params[:members_page]).per(30)
- @projects = @group.projects.page(params[:projects_page]).per(30)
+ @members = @group.members.order("access_level DESC").page(params[:members_page]).per(PER_PAGE)
+ @projects = @group.projects.page(params[:projects_page]).per(PER_PAGE)
end
def new
@@ -40,7 +40,7 @@ class Admin::GroupsController < Admin::ApplicationController
end
end
- def project_teams_update
+ def members_update
@group.add_users(params[:user_ids].split(','), params[:access_level])
redirect_to [:admin, @group], notice: 'Users were successfully added.'
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 2b1fc862b7..5176a8399a 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -11,15 +11,15 @@ class Admin::ProjectsController < Admin::ApplicationController
@projects = @projects.abandoned if params[:abandoned].present?
@projects = @projects.search(params[:name]) if params[:name].present?
@projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
+ @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(PER_PAGE)
end
def show
if @group
- @group_members = @group.members.order("access_level DESC").page(params[:group_members_page]).per(30)
+ @group_members = @group.members.order("access_level DESC").page(params[:group_members_page]).per(PER_PAGE)
end
- @project_members = @project.project_members.page(params[:project_members_page]).per(30)
+ @project_members = @project.project_members.page(params[:project_members_page]).per(PER_PAGE)
end
def transfer
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 82458aa258..18bc1801a8 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -4,6 +4,8 @@ class ApplicationController < ActionController::Base
include Gitlab::CurrentSettings
include GitlabRoutingHelper
+ PER_PAGE = 20
+
before_filter :authenticate_user_from_token!
before_filter :authenticate_user!
before_filter :reject_blocked!
diff --git a/app/controllers/dashboard/groups_controller.rb b/app/controllers/dashboard/groups_controller.rb
index 61d691e636..ed14f4e1f3 100644
--- a/app/controllers/dashboard/groups_controller.rb
+++ b/app/controllers/dashboard/groups_controller.rb
@@ -1,21 +1,5 @@
class Dashboard::GroupsController < ApplicationController
def index
- @user_groups = current_user.group_members.page(params[:page]).per(20)
- end
-
- def leave
- @users_group = group.group_members.where(user_id: current_user.id).first
- if can?(current_user, :destroy, @users_group)
- @users_group.destroy
- redirect_to(dashboard_groups_path, info: "You left #{group.name} group.")
- else
- return render_403
- end
- end
-
- private
-
- def group
- @group ||= Group.find_by(path: params[:id])
+ @group_members = current_user.group_members.page(params[:page]).per(PER_PAGE)
end
end
diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb
index 386e283f3a..cb51792df1 100644
--- a/app/controllers/dashboard/milestones_controller.rb
+++ b/app/controllers/dashboard/milestones_controller.rb
@@ -8,7 +8,7 @@ class Dashboard::MilestonesController < ApplicationController
else state('active')
end
@dashboard_milestones = Milestones::GroupService.new(project_milestones).execute
- @dashboard_milestones = Kaminari.paginate_array(@dashboard_milestones).page(params[:page]).per(30)
+ @dashboard_milestones = Kaminari.paginate_array(@dashboard_milestones).page(params[:page]).per(PER_PAGE)
end
def show
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 0500619909..9bd853ed5c 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -25,13 +25,13 @@ class DashboardController < ApplicationController
def merge_requests
@merge_requests = get_merge_requests_collection
- @merge_requests = @merge_requests.page(params[:page]).per(20)
+ @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
@merge_requests = @merge_requests.preload(:author, :target_project)
end
def issues
@issues = get_issues_collection
- @issues = @issues.page(params[:page]).per(20)
+ @issues = @issues.page(params[:page]).per(PER_PAGE)
@issues = @issues.preload(:author, :project)
respond_to do |format|
diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb
index ada7031fea..c51a4a211a 100644
--- a/app/controllers/explore/groups_controller.rb
+++ b/app/controllers/explore/groups_controller.rb
@@ -8,6 +8,6 @@ class Explore::GroupsController < ApplicationController
@groups = GroupsFinder.new.execute(current_user)
@groups = @groups.search(params[:search]) if params[:search].present?
@groups = @groups.sort(@sort = params[:sort])
- @groups = @groups.page(params[:page]).per(20)
+ @groups = @groups.page(params[:page]).per(PER_PAGE)
end
end
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index d664624fa6..b295f295bb 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -11,17 +11,17 @@ class Explore::ProjectsController < ApplicationController
@projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
@projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.includes(:namespace).page(params[:page]).per(20)
+ @projects = @projects.includes(:namespace).page(params[:page]).per(PER_PAGE)
end
def trending
@trending_projects = TrendingProjectsFinder.new.execute(current_user)
- @trending_projects = @trending_projects.page(params[:page]).per(10)
+ @trending_projects = @trending_projects.page(params[:page]).per(PER_PAGE)
end
def starred
@starred_projects = ProjectsFinder.new.execute(current_user)
@starred_projects = @starred_projects.reorder('star_count DESC')
- @starred_projects = @starred_projects.page(params[:page]).per(10)
+ @starred_projects = @starred_projects.page(params[:page]).per(PER_PAGE)
end
end
diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb
index 04c47275b9..56c427a9de 100644
--- a/app/controllers/groups/application_controller.rb
+++ b/app/controllers/groups/application_controller.rb
@@ -1,7 +1,17 @@
class Groups::ApplicationController < ApplicationController
private
-
+
+ def authorize_read_group!
+ unless @group and can?(current_user, :read_group, @group)
+ if current_user.nil?
+ return authenticate_user!
+ else
+ return render_404
+ end
+ end
+ end
+
def authorize_admin_group!
unless can?(current_user, :manage_group, group)
return render_404
@@ -11,4 +21,12 @@ class Groups::ApplicationController < ApplicationController
def group
@group ||= Group.find_by(path: params[:group_id])
end
+
+ def determine_layout
+ if current_user
+ 'group'
+ else
+ 'public_group'
+ end
+ end
end
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 4c84e1a419..ae9291f178 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -1,30 +1,38 @@
class Groups::GroupMembersController < Groups::ApplicationController
+ skip_before_filter :authenticate_user!, only: [:index]
before_filter :group
# Authorize
- before_filter :authorize_admin_group!
+ before_filter :authorize_read_group!
+ before_filter :authorize_admin_group!, except: [:index, :leave]
- layout 'group'
+ layout :determine_layout
+
+ def index
+ @project = @group.projects.find(params[:project_id]) if params[:project_id]
+ @members = @group.group_members
+
+ if params[:search].present?
+ users = @group.users.search(params[:search]).to_a
+ @members = @members.where(user_id: users)
+ end
+
+ @members = @members.order('access_level DESC').page(params[:page]).per(50)
+ @group_member = GroupMember.new
+ end
def create
access_level = params[:access_level]
user_ids = params[:user_ids].split(',')
@group.add_users(user_ids, access_level)
+ group_members = @group.group_members.where(user_id: user_ids)
- users = User.where(id: user_ids).pluck(:id, :name)
- users.each do |user|
- details = {
- add: "user_access",
- as: Gitlab::Access.options_with_owner.key(access_level.to_i),
- target_id: user[0],
- target_type: "User",
- target_details: user[1],
- }
- AuditEventService.new(current_user, @group, details).security_event
+ group_members.each do |group_member|
+ log_audit_event(group_member, action: :create)
end
- redirect_to members_group_path(@group), notice: 'Users were successfully added.'
+ redirect_to group_group_members_path(@group), notice: 'Users were successfully added.'
end
def update
@@ -32,36 +40,19 @@ class Groups::GroupMembersController < Groups::ApplicationController
old_access_level = @member.human_access
if @member.update_attributes(member_params)
- details = {
- change: "access_level",
- from: old_access_level,
- to: @member.human_access,
- target_id: @member.user_id,
- target_type: "User",
- target_details: @member.user.name,
- }
- AuditEventService.new(current_user, @group, details).security_event
+ log_audit_event(@member, action: :update, old_access_level: old_access_level)
end
end
def destroy
- @users_group = @group.group_members.find(params[:id])
+ @group_member = @group.group_members.find(params[:id])
- if can?(current_user, :destroy, @users_group) # May fail if last owner.
- user_id = @users_group.id
- user_name = @users_group.user.name
- if @users_group.destroy
- details = {
- remove: "user_access",
- target_id: user_id,
- target_type: "User",
- target_details: user_name,
- }
- AuditEventService.new(current_user, @group, details).security_event
- end
+ if can?(current_user, :destroy_group_member, @group_member) # May fail if last owner.
+ @group_member.destroy
+ log_audit_event(@group_member, action: :destroy)
respond_to do |format|
- format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
+ format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
format.js { render nothing: true }
end
else
@@ -69,9 +60,27 @@ class Groups::GroupMembersController < Groups::ApplicationController
end
end
+ def leave
+ @group_member = @group.group_members.where(user_id: current_user.id).first
+
+ if can?(current_user, :destroy_group_member, @group_member)
+ @group_member.destroy
+ log_audit_event(@group_member, action: :destroy)
+
+ redirect_to(dashboard_groups_path, info: "You left #{group.name} group.")
+ else
+ return render_403
+ end
+ end
+
protected
def member_params
params.require(:group_member).permit(:access_level, :user_id)
end
+
+ def log_audit_event(member, options = {})
+ AuditEventService.new(current_user, @group, options).
+ for_member(member).security_event
+ end
end
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 6802e529b5..c46b8fff88 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -10,7 +10,7 @@ class Groups::MilestonesController < ApplicationController
else state('active')
end
@group_milestones = Milestones::GroupService.new(project_milestones).execute
- @group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(30)
+ @group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(PER_PAGE)
end
def show
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index c36ac2c712..7e819b5cd2 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -1,5 +1,5 @@
class GroupsController < Groups::ApplicationController
- skip_before_filter :authenticate_user!, only: [:show, :issues, :members, :merge_requests]
+ skip_before_filter :authenticate_user!, only: [:show, :issues, :merge_requests]
respond_to :html
before_filter :group, except: [:new, :create]
@@ -54,13 +54,13 @@ class GroupsController < Groups::ApplicationController
def merge_requests
@merge_requests = get_merge_requests_collection
- @merge_requests = @merge_requests.page(params[:page]).per(20)
+ @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
@merge_requests = @merge_requests.preload(:author, :target_project)
end
def issues
@issues = get_issues_collection
- @issues = @issues.page(params[:page]).per(20)
+ @issues = @issues.page(params[:page]).per(PER_PAGE)
@issues = @issues.preload(:author, :project)
respond_to do |format|
@@ -69,19 +69,6 @@ class GroupsController < Groups::ApplicationController
end
end
- def members
- @project = group.projects.find(params[:project_id]) if params[:project_id]
- @members = group.group_members
-
- if params[:search].present?
- users = group.users.search(params[:search]).to_a
- @members = @members.where(user_id: users)
- end
-
- @members = @members.order('access_level DESC').page(params[:page]).per(50)
- @users_group = GroupMember.new
- end
-
def edit
end
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index dc7668ee6f..8650b6464d 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -14,7 +14,7 @@ class Import::GithubController < Import::BaseController
def status
@repos = client.repos
client.orgs.each do |org|
- @repos += client.repos(org.login)
+ @repos += client.org_repos(org.login)
end
@already_added_projects = current_user.created_projects.where(import_type: "github")
diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb
index 433c19189a..3fdcbbab61 100644
--- a/app/controllers/profiles/notifications_controller.rb
+++ b/app/controllers/profiles/notifications_controller.rb
@@ -14,9 +14,9 @@ class Profiles::NotificationsController < ApplicationController
@saved = if type == 'global'
current_user.update_attributes(user_params)
elsif type == 'group'
- users_group = current_user.group_members.find(params[:notification_id])
- users_group.notification_level = params[:notification_level]
- users_group.save
+ group_member = current_user.group_members.find(params[:notification_id])
+ group_member.notification_level = params[:notification_level]
+ group_member.save
else
project_member = current_user.project_members.find(params[:notification_id])
project_member.notification_level = params[:notification_level]
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index a7863aba75..1b9a86ee42 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -43,7 +43,7 @@ class ProfilesController < ApplicationController
end
def history
- @events = current_user.recent_events.page(params[:page]).per(20)
+ @events = current_user.recent_events.page(params[:page]).per(PER_PAGE)
end
def update_username
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index 489a6ae566..a87b8270a2 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -7,7 +7,7 @@ class Projects::BlameController < Projects::ApplicationController
before_filter :authorize_download_code!
def show
- @blob = @repository.blob_at(@commit.id, @path)
- @blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path)
+ @blame = Gitlab::Git::Blame.new(@repository, @commit.id, @path)
+ @blob = @blame.blob
end
end
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 690501f306..f049e96e61 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -8,7 +8,7 @@ class Projects::BranchesController < Projects::ApplicationController
def index
@sort = params[:sort] || 'name'
@branches = @repository.branches_sorted_by(@sort)
- @branches = Kaminari.paginate_array(@branches).page(params[:page]).per(30)
+ @branches = Kaminari.paginate_array(@branches).page(params[:page]).per(PER_PAGE)
end
def recent
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 752474b4a4..6e54af356e 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -28,8 +28,8 @@ class Projects::GraphsController < Projects::ApplicationController
@commits.each do |commit|
@log << {
- author_name: commit.author_name.force_encoding('UTF-8'),
- author_email: commit.author_email.force_encoding('UTF-8'),
+ author_name: commit.author_name,
+ author_email: commit.author_email,
date: commit.committed_date.strftime("%Y-%m-%d")
}
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 1f1a9b4d43..4266bcaef1 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -20,7 +20,7 @@ class Projects::IssuesController < Projects::ApplicationController
terms = params['issue_search']
@issues = get_issues_collection
@issues = @issues.full_search(terms) if terms.present?
- @issues = @issues.page(params[:page]).per(20)
+ @issues = @issues.page(params[:page]).per(PER_PAGE)
respond_to do |format|
format.html
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 5e31fce4b0..207a01ed3b 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -7,7 +7,7 @@ class Projects::LabelsController < Projects::ApplicationController
respond_to :js, :html
def index
- @labels = @project.labels.page(params[:page]).per(20)
+ @labels = @project.labels.page(params[:page]).per(PER_PAGE)
end
def new
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 57c017e799..93d79d8166 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -17,8 +17,19 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
def index
+ terms = params['issue_search']
@merge_requests = get_merge_requests_collection
- @merge_requests = @merge_requests.page(params[:page]).per(20)
+ @merge_requests = @merge_requests.full_search(terms) if terms.present?
+ @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
+
+ respond_to do |format|
+ format.html
+ format.json do
+ render json: {
+ html: view_to_html_string("projects/merge_requests/_merge_requests")
+ }
+ end
+ end
end
def show
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index afdb560e73..b49b549547 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -18,7 +18,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end
@milestones = @milestones.includes(:project)
- @milestones = @milestones.page(params[:page]).per(20)
+ @milestones = @milestones.page(params[:page]).per(PER_PAGE)
end
def new
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
new file mode 100644
index 0000000000..a68ab91d87
--- /dev/null
+++ b/app/controllers/projects/project_members_controller.rb
@@ -0,0 +1,106 @@
+class Projects::ProjectMembersController < Projects::ApplicationController
+ # Authorize
+ before_filter :authorize_admin_project!, except: :leave
+
+ layout "project_settings"
+
+ def index
+ @project_members = @project.project_members
+
+ if params[:search].present?
+ users = @project.users.search(params[:search]).to_a
+ @project_members = @project_members.where(user_id: users)
+ end
+
+ @project_members = @project_members.order('access_level DESC')
+
+ @group = @project.group
+ if @group
+ @group_members = @group.group_members
+
+ if params[:search].present?
+ users = @group.users.search(params[:search]).to_a
+ @group_members = @group_members.where(user_id: users)
+ end
+
+ @group_members = @group_members.order('access_level DESC').limit(20)
+ end
+
+ @project_member = @project.project_members.new
+ @project_group_links = @project.project_group_links
+ end
+
+ def new
+ @project_member = @project.project_members.new
+ end
+
+ def create
+ users = User.where(id: params[:user_ids].split(','))
+ @project.team << [users, params[:access_level]]
+ members = @project.project_members.where(user_id: user_ids)
+
+ members.each do |member|
+ log_audit_event(member, action: :create)
+ end
+
+ redirect_to namespace_project_project_members_path(@project.namespace, @project)
+ end
+
+ def update
+ @project_member = @project.project_members.find_by(user_id: member)
+ old_access_level = @project_member.human_access
+
+ if @project_member.update_attributes(member_params)
+ log_audit_event(@project_member, action: :update, old_access_level: old_access_level)
+ end
+ end
+
+ def destroy
+ @project_member = @project.project_members.find_by(user_id: member)
+ @project_member.destroy
+ log_audit_event(@project_member, action: :destroy)
+
+ respond_to do |format|
+ format.html do
+ redirect_to namespace_project_project_members_path(@project.namespace,
+ @project)
+ end
+ format.js { render nothing: true }
+ end
+ end
+
+ def leave
+ @project_member = @project.project_members.find_by(user_id: current_user)
+ @project_member.destroy
+ log_audit_event(@project_member, action: :destroy)
+
+ respond_to do |format|
+ format.html { redirect_to :back }
+ format.js { render nothing: true }
+ end
+ end
+
+ def apply_import
+ giver = Project.find(params[:source_project_id])
+ status = @project.team.import(giver)
+ notice = status ? "Successfully imported" : "Import failed"
+
+ redirect_to(namespace_project_project_members_path(project.namespace, project),
+ notice: notice)
+ end
+
+ protected
+
+ def member
+ @member ||= User.find_by(username: params[:id])
+ end
+
+ def member_params
+ params.require(:project_member).permit(:user_id, :access_level)
+ end
+
+ def log_audit_event(member, options = {})
+ AuditEventService.new(current_user, @project, options).
+ for_member(member).security_event
+ end
+end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 6c250e4ffe..ed26840037 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -28,26 +28,22 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def create
- @snippet = @project.snippets.build(snippet_params)
- @snippet.author = current_user
-
- if @snippet.save
- redirect_to namespace_project_snippet_path(@project.namespace, @project,
- @snippet)
- else
- respond_with(@snippet)
- end
+ @snippet = CreateSnippetService.new(@project, current_user,
+ snippet_params).execute
+ respond_with(@snippet,
+ location: namespace_project_snippet_path(@project.namespace,
+ @project, @snippet))
end
def edit
end
def update
- if @snippet.update_attributes(snippet_params)
- redirect_to namespace_project_snippet_path(@project.namespace, @project, @snippet)
- else
- respond_with(@snippet)
- end
+ UpdateSnippetService.new(project, current_user, @snippet,
+ snippet_params).execute
+ respond_with(@snippet,
+ location: namespace_project_snippet_path(@project.namespace,
+ @project, @snippet))
end
def show
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 03fface2d2..83f4937bce 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -7,7 +7,7 @@ class Projects::TagsController < Projects::ApplicationController
def index
sorted = VersionSorter.rsort(@repository.tag_names)
- @tags = Kaminari.paginate_array(sorted).page(params[:page]).per(30)
+ @tags = Kaminari.paginate_array(sorted).page(params[:page]).per(PER_PAGE)
end
def create
@@ -24,14 +24,13 @@ class Projects::TagsController < Projects::ApplicationController
end
def destroy
- tag = @repository.find_tag(params[:id])
-
- if tag && @repository.rm_tag(tag.name)
- EventCreateService.new.push_ref(@project, current_user, tag, 'rm', Gitlab::Git::TAG_REF_PREFIX)
- end
+ DeleteTagService.new(project, current_user).execute(params[:id])
respond_to do |format|
- format.html { redirect_to namespace_project_tags_path }
+ format.html do
+ redirect_to namespace_project_tags_path(@project.namespace,
+ @project)
+ end
format.js
end
end
diff --git a/app/controllers/projects/team_members_controller.rb b/app/controllers/projects/team_members_controller.rb
deleted file mode 100644
index e28fa25c74..0000000000
--- a/app/controllers/projects/team_members_controller.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-class Projects::TeamMembersController < Projects::ApplicationController
- # Authorize
- before_filter :authorize_admin_project!, except: :leave
-
- layout "project_settings"
-
- def index
- @group = @project.group
- @project_members = @project.project_members.order('access_level DESC')
- @project_group_links = @project.project_group_links
- end
-
- def new
- @user_project_relation = @project.project_members.new
- end
-
- def create
- users = User.where(id: params[:user_ids].split(','))
- access_level = params[:access_level]
- @project.team << [users, access_level]
-
- users.each do |user|
- details = {
- add: "user_access",
- as: Gitlab::Access.options_with_owner.key(access_level.to_i),
- target_id: user.id,
- target_type: "User",
- target_details: user.name,
- }
- AuditEventService.new(current_user, @project, details).security_event
- end
-
- redirect_to namespace_project_team_index_path(@project.namespace, @project)
- end
-
- def update
- @user_project_relation = @project.project_members.find_by(user_id: member)
- old_access_level = @user_project_relation.human_access
-
- if @user_project_relation.update_attributes(member_params)
- details = {
- change: "access_level",
- from: old_access_level,
- to: @user_project_relation.human_access,
- target_id: @user_project_relation.user_id,
- target_type: "User",
- target_details: @user_project_relation.user.name,
- }
- AuditEventService.new(current_user, @project, details).security_event
- end
-
- unless @user_project_relation.valid?
- flash[:alert] = "User should have at least one role"
- end
- redirect_to namespace_project_team_index_path(@project.namespace, @project)
- end
-
- def destroy
- @user_project_relation = @project.project_members.find_by(user_id: member)
- user_id = @user_project_relation.user_id
- user_name = @user_project_relation.user.name
-
- if @user_project_relation.destroy
- details = {
- remove: "user_access",
- target_id: user_id,
- target_type: "User",
- target_details: user_name,
- }
- AuditEventService.new(current_user, @project, details).security_event
- end
-
- respond_to do |format|
- format.html do
- redirect_to namespace_project_team_index_path(@project.namespace,
- @project)
- end
- format.js { render nothing: true }
- end
- end
-
- def leave
- @project.project_members.find_by(user_id: current_user).destroy
-
- respond_to do |format|
- format.html { redirect_to :back }
- format.js { render nothing: true }
- end
- end
-
- def apply_import
- giver = Project.find(params[:source_project_id])
- status = @project.team.import(giver)
- notice = status ? "Successfully imported" : "Import failed"
-
- redirect_to(namespace_project_team_index_path(project.namespace, project),
- notice: notice)
- end
-
- protected
-
- def member
- @member ||= User.find_by(username: params[:id])
- end
-
- def member_params
- params.require(:project_member).permit(:user_id, :access_level)
- end
-end
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 3392fbca91..643167947b 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -7,7 +7,7 @@ class Projects::WikisController < Projects::ApplicationController
before_filter :load_project_wiki
def pages
- @wiki_pages = Kaminari.paginate_array(@project_wiki.pages).page(params[:page]).per(30)
+ @wiki_pages = Kaminari.paginate_array(@project_wiki.pages).page(params[:page]).per(PER_PAGE)
end
def show
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 6ac048e4b8..cd52556b20 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -16,7 +16,7 @@ class SnippetsController < ApplicationController
layout :determine_layout
def index
- @snippets = SnippetsFinder.new.execute(current_user, filter: :all).page(params[:page]).per(20)
+ @snippets = SnippetsFinder.new.execute(current_user, filter: :all).page(params[:page]).per(PER_PAGE)
end
def user_index
@@ -28,7 +28,7 @@ class SnippetsController < ApplicationController
filter: :by_user,
user: @user,
scope: params[:scope] }).
- page(params[:page]).per(20)
+ page(params[:page]).per(PER_PAGE)
if @user == current_user
render 'current_user_index'
@@ -42,25 +42,19 @@ class SnippetsController < ApplicationController
end
def create
- @snippet = PersonalSnippet.new(snippet_params)
- @snippet.author = current_user
+ @snippet = CreateSnippetService.new(nil, current_user,
+ snippet_params).execute
- if @snippet.save
- redirect_to snippet_path(@snippet)
- else
- respond_with @snippet
- end
+ respond_with @snippet.becomes(Snippet)
end
def edit
end
def update
- if @snippet.update_attributes(snippet_params)
- redirect_to snippet_path(@snippet)
- else
- respond_with @snippet
- end
+ UpdateSnippetService.new(nil, current_user, @snippet,
+ snippet_params).execute
+ respond_with @snippet.becomes(Snippet)
end
def show
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index a81e41819b..8ed6d59c20 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -86,15 +86,6 @@ module ApplicationHelper
end
end
- def group_icon(group_path)
- group = Group.find_by(path: group_path)
- if group && group.avatar.present?
- group.avatar.url
- else
- image_path('no_group_avatar.png')
- end
- end
-
def avatar_icon(user_email = '', size = nil)
user = User.find_by(email: user_email)
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 4c37b73dd8..002e0d0e5b 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -22,4 +22,21 @@ module ApplicationSettingsHelper
def help_text
current_application_settings.help_text
end
+
+ # Return a group of checkboxes that use Bootstrap's button plugin for a
+ # toggle button effect.
+ def restricted_level_checkboxes(help_block_id)
+ Gitlab::VisibilityLevel.options.map do |name, level|
+ checked = restricted_visibility_levels(true).include?(level)
+ css_class = 'btn btn-primary'
+ css_class += ' active' if checked
+ checkbox_name = 'application_setting[restricted_visibility_levels][]'
+
+ label_tag(checkbox_name, class: css_class) do
+ check_box_tag(checkbox_name, level, checked,
+ autocomplete: 'off',
+ 'aria-describedby' => help_block_id) + name
+ end
+ end
+ end
end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 8c921cba54..f81504991d 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -122,7 +122,7 @@ module DiffHelper
params_copy = params.dup
params_copy[:view] = 'inline'
- link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] != 'parallel' ? 'btn active' : 'btn') do
+ link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] != 'parallel' ? 'btn btn-sm active' : 'btn btn-sm') do
'Inline'
end
end
@@ -131,7 +131,7 @@ module DiffHelper
params_copy = params.dup
params_copy[:view] = 'parallel'
- link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] == 'parallel' ? 'btn active' : 'btn') do
+ link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] == 'parallel' ? 'btn active btn-sm' : 'btn btn-sm') do
'Side-by-side'
end
end
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index 92cc9c426b..08476f8516 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -1,3 +1,6 @@
+require 'html/pipeline'
+require 'html/pipeline/gitlab'
+
module EmailsHelper
# Google Actions
@@ -39,4 +42,26 @@ module EmailsHelper
lexer = Rugments::Lexers::Diff.new
raw formatter.format(lexer.lex(diffcontent))
end
+
+ def replace_image_links_with_base64(text, project)
+ # Used pipelines in GitLab:
+ # GitlabEmailImageFilter - replaces images that have been uploaded as attachments with inline images in emails.
+ #
+ # see https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters
+ filters = [
+ HTML::Pipeline::Gitlab::GitlabEmailImageFilter
+ ]
+
+ context = {
+ base_url: File.join(Gitlab.config.gitlab.url, project.path_with_namespace, 'uploads'),
+ upload_path: File.join(Rails.root, 'public', 'uploads', project.path_with_namespace),
+ }
+
+ pipeline = HTML::Pipeline::Gitlab.new(filters).pipeline
+
+ result = pipeline.call(text, context)
+ text = result[:output].to_html(save_with: 0)
+
+ text.html_safe
+ end
end
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index 8518a47a3a..b005cb8e41 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -45,7 +45,8 @@ module GitlabRoutingHelper
namespace_project_merge_request_url(entity.project.namespace, entity.project, entity, *args)
end
- def snippet_url(entity, *args)
+ def project_snippet_url(entity, *args)
namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args)
+
end
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 0fdb1e82a1..e7694bc580 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -42,4 +42,16 @@ module GroupsHelper
false
end
end
+
+ def group_icon(group)
+ if group.is_a?(String)
+ group = Group.find_by(path: group)
+ end
+
+ if group && group.avatar.present?
+ group.avatar.url
+ else
+ image_path('no_group_avatar.png')
+ end
+ end
end
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
index 2bcfde6283..b3132a1f3b 100644
--- a/app/helpers/namespaces_helper.rb
+++ b/app/helpers/namespaces_helper.rb
@@ -28,7 +28,7 @@ module NamespacesHelper
def namespace_icon(namespace, size = 40)
if namespace.kind_of?(Group)
- group_icon(namespace.path)
+ group_icon(namespace)
else
avatar_icon(namespace.owner.email, size)
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index cb82903769..7d3fcfa703 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -60,7 +60,7 @@ module SearchHelper
{ label: "#{prefix} - Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) },
{ label: "#{prefix} - Milestones", url: namespace_project_milestones_path(@project.namespace, @project) },
{ label: "#{prefix} - Snippets", url: namespace_project_snippets_path(@project.namespace, @project) },
- { label: "#{prefix} - Team", url: namespace_project_team_index_path(@project.namespace, @project) },
+ { label: "#{prefix} - Members", url: namespace_project_project_members_path(@project.namespace, @project) },
{ label: "#{prefix} - Wiki", url: namespace_project_wikis_path(@project.namespace, @project) },
]
else
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index 32872b6053..bbb37259d6 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -89,7 +89,7 @@ module TabHelper
def project_tab_class
return "active" if current_page?(controller: "/projects", action: :edit, id: @project)
- if ['services', 'git_hooks', 'hooks', 'deploy_keys', 'team_members', 'protected_branches'].include? controller.controller_name
+ if ['services', 'git_hooks', 'hooks', 'deploy_keys', 'project_members', 'protected_branches'].include? controller.controller_name
"active"
end
end
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index deb9c8b4d4..0d573e72a8 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -60,7 +60,8 @@ module VisibilityLevelHelper
Project.visibility_levels.key(level)
end
- def restricted_visibility_levels
- current_user.is_admin? ? [] : gitlab_config.restricted_visibility_levels
+ def restricted_visibility_levels(show_all = false)
+ return [] if current_user.is_admin? && !show_all
+ current_application_settings.restricted_visibility_levels || []
end
end
diff --git a/app/mailers/emails/groups.rb b/app/mailers/emails/groups.rb
index 8c09389985..26f43bf955 100644
--- a/app/mailers/emails/groups.rb
+++ b/app/mailers/emails/groups.rb
@@ -1,10 +1,10 @@
module Emails
module Groups
- def group_access_granted_email(user_group_id)
- @membership = GroupMember.find(user_group_id)
- @group = @membership.group
+ def group_access_granted_email(group_member_id)
+ @group_member = GroupMember.find(group_member_id)
+ @group = @group_member.group
@target_url = group_url(@group)
- mail(to: @membership.user.email,
+ mail(to: @group_member.user.email,
subject: subject("Access to group was granted"))
end
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 890417e780..d2b39f667f 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -14,7 +14,7 @@ class Ability
when "MergeRequest" then merge_request_abilities(user, subject)
when "Group" then group_abilities(user, subject)
when "Namespace" then namespace_abilities(user, subject)
- when "GroupMember" then users_group_abilities(user, subject)
+ when "GroupMember" then group_member_abilities(user, subject)
else []
end.concat(global_abilities(user))
end
@@ -37,7 +37,7 @@ class Ability
:read_issue,
:read_milestone,
:read_project_snippet,
- :read_team_member,
+ :read_project_member,
:read_merge_request,
:read_note,
:download_code
@@ -119,7 +119,7 @@ class Ability
:read_issue,
:read_milestone,
:read_project_snippet,
- :read_team_member,
+ :read_project_member,
:read_merge_request,
:read_note,
:write_project,
@@ -166,7 +166,7 @@ class Ability
:admin_issue,
:admin_milestone,
:admin_project_snippet,
- :admin_team_member,
+ :admin_project_member,
:admin_merge_request,
:admin_note,
:admin_wiki,
@@ -225,13 +225,15 @@ class Ability
[:issue, :note, :project_snippet, :personal_snippet, :merge_request].each do |name|
define_method "#{name}_abilities" do |user, subject|
- if subject.author == user
- [
+ if subject.author == user || user.is_admin?
+ rules = [
:"read_#{name}",
:"write_#{name}",
:"modify_#{name}",
:"admin_#{name}"
]
+ rules.push(:change_visibility_level) if subject.is_a?(Snippet)
+ rules
elsif subject.respond_to?(:assignee) && subject.assignee == user
[
:"read_#{name}",
@@ -248,17 +250,17 @@ class Ability
end
end
- def users_group_abilities(user, subject)
+ def group_member_abilities(user, subject)
rules = []
target_user = subject.user
group = subject.group
can_manage = group_abilities(user, group).include?(:manage_group)
if can_manage && (user != target_user)
- rules << :modify
- rules << :destroy
+ rules << :modify_group_member
+ rules << :destroy_group_member
end
if !group.last_owner?(user) && (can_manage || (user == target_user))
- rules << :destroy
+ rules << :destroy_group_member
end
rules
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 676111053d..f097e66e96 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -2,28 +2,41 @@
#
# Table name: application_settings
#
-# id :integer not null, primary key
-# default_projects_limit :integer
-# default_branch_protection :integer
-# signup_enabled :boolean
-# signin_enabled :boolean
-# gravatar_enabled :boolean
-# twitter_sharing_enabled :boolean
-# sign_in_text :text
-# created_at :datetime
-# updated_at :datetime
-# home_page_url :string(255)
-# default_branch_protection :integer default(2)
-# twitter_sharing_enabled :boolean default(TRUE)
-# help_text :text
+# id :integer not null, primary key
+# default_projects_limit :integer
+# default_branch_protection :integer
+# signup_enabled :boolean
+# signin_enabled :boolean
+# gravatar_enabled :boolean
+# twitter_sharing_enabled :boolean
+# sign_in_text :text
+# created_at :datetime
+# updated_at :datetime
+# home_page_url :string(255)
+# default_branch_protection :integer default(2)
+# twitter_sharing_enabled :boolean default(TRUE)
+# help_text :text
+# restricted_visibility_levels :text
#
class ApplicationSetting < ActiveRecord::Base
+ serialize :restricted_visibility_levels
+
validates :home_page_url,
allow_blank: true,
format: { with: URI::regexp(%w(http https)), message: "should be a valid url" },
if: :home_page_url_column_exist
+ validates_each :restricted_visibility_levels do |record, attr, value|
+ unless value.nil?
+ value.each do |level|
+ unless Gitlab::VisibilityLevel.options.has_value?(level)
+ record.errors.add(attr, "'#{level}' is not a valid visibility level")
+ end
+ end
+ end
+ end
+
def self.current
ApplicationSetting.last
end
@@ -37,6 +50,7 @@ class ApplicationSetting < ActiveRecord::Base
twitter_sharing_enabled: Settings.gitlab['twitter_sharing_enabled'],
gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'],
+ restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels']
)
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 19e43ebd78..6e10205138 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -32,7 +32,6 @@ class Issue < ActiveRecord::Base
validates :project, presence: true
scope :of_group, ->(group) { where(project_id: group.project_ids) }
- scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) }
scope :cared, ->(user) { where(assignee_id: user) }
scope :open_for, ->(user) { opened.assigned_to(user) }
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index e4791d0f0a..6b13e0ff30 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -116,14 +116,14 @@ class ProjectMember < Member
def post_create_hook
unless owner?
event_service.join_project(self.project, self.user)
- notification_service.new_team_member(self)
+ notification_service.new_project_member(self)
end
system_hook_service.execute_hooks_for(self, :create)
end
def post_update_hook
- notification_service.update_team_member(self) if self.access_level_changed?
+ notification_service.update_project_member(self) if self.access_level_changed?
end
def post_destroy_hook
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index ec7a97d4f4..e72d791889 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -118,7 +118,6 @@ class MergeRequest < ActiveRecord::Base
validate :validate_fork
scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)", group_project_ids: group.project_ids) }
- scope :of_user_team, ->(team) { where("(source_project_id in (:team_project_ids) OR target_project_id in (:team_project_ids) AND assignee_id in (:team_member_ids))", team_project_ids: team.project_ids, team_member_ids: team.member_ids) }
scope :merged, -> { with_state(:merged) }
scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) }
scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
diff --git a/app/models/project.rb b/app/models/project.rb
index a887b6cd3c..0ac56f645e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -137,9 +137,6 @@ class Project < ActiveRecord::Base
message: Gitlab::Regex.path_regex_message }
validates :issues_enabled, :merge_requests_enabled,
:wiki_enabled, inclusion: { in: [true, false] }
- validates :visibility_level,
- exclusion: { in: gitlab_config.restricted_visibility_levels },
- if: -> { gitlab_config.restricted_visibility_levels.any? }
validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true
validates :namespace, presence: true
validates_uniqueness_of :name, scope: :namespace_id
@@ -163,7 +160,6 @@ class Project < ActiveRecord::Base
scope :without_user, ->(user) { where('projects.id NOT IN (:ids)', ids: user.authorized_projects.map(&:id) ) }
scope :without_team, ->(team) { team.projects.present? ? where('projects.id NOT IN (:ids)', ids: team.projects.map(&:id)) : scoped }
scope :not_in_group, ->(group) { where('projects.id NOT IN (:ids)', ids: group.project_ids ) }
- scope :in_team, ->(team) { where('projects.id IN (:ids)', ids: team.projects.map(&:id)) }
scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) }
scope :in_group_namespace, -> { joins(:group) }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
@@ -459,13 +455,13 @@ class Project < ActiveRecord::Base
end
end
- def team_member_by_name_or_email(name = nil, email = nil)
+ def project_member_by_name_or_email(name = nil, email = nil)
user = users.where('name like ? or email like ?', name, email).first
project_members.where(user: user) if user
end
# Get Team Member record by user id
- def team_member_by_id(user_id)
+ def project_member_by_id(user_id)
project_members.find_by(user_id: user_id)
end
diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb
index deb210c61e..2bddb7b881 100644
--- a/app/models/project_services/irker_service.rb
+++ b/app/models/project_services/irker_service.rb
@@ -68,9 +68,15 @@ class IrkerService < Service
'irker'
end
- def execute(push_data)
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
IrkerWorker.perform_async(project_id, channels,
- colorize_messages, push_data, @settings)
+ colorize_messages, data, @settings)
end
def fields
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 1d1fd68c26..9755fb779d 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -31,16 +31,16 @@ class ProjectTeam
user
end
- def find_tm(user_id)
- tm = project.project_members.find_by(user_id: user_id)
+ def find_member(user_id)
+ member = project.project_members.find_by(user_id: user_id)
# If user is not in project members
# we should check for group membership
- if group && !tm
- tm = group.group_members.find_by(user_id: user_id)
+ if group && !member
+ member = group.group_members.find_by(user_id: user_id)
end
- tm
+ member
end
def add_user(user, access)
@@ -92,24 +92,24 @@ class ProjectTeam
def import(source_project)
target_project = project
- source_team = source_project.project_members.to_a
+ source_members = source_project.project_members.to_a
target_user_ids = target_project.project_members.pluck(:user_id)
- source_team.reject! do |tm|
+ source_members.reject! do |member|
# Skip if user already present in team
- target_user_ids.include?(tm.user_id)
+ target_user_ids.include?(member.user_id)
end
- source_team.map! do |tm|
- new_tm = tm.dup
- new_tm.id = nil
- new_tm.source = target_project
- new_tm
+ source_members.map! do |member|
+ new_member = member.dup
+ new_member.id = nil
+ new_member.source = target_project
+ new_member
end
ProjectMember.transaction do
- source_team.each do |tm|
- tm.save
+ source_members.each do |member|
+ member.save
end
end
@@ -119,26 +119,26 @@ class ProjectTeam
end
def guest?(user)
- max_tm_access(user.id) == Gitlab::Access::GUEST
+ max_member_access(user.id) == Gitlab::Access::GUEST
end
def reporter?(user)
- max_tm_access(user.id) == Gitlab::Access::REPORTER
+ max_member_access(user.id) == Gitlab::Access::REPORTER
end
def developer?(user)
- max_tm_access(user.id) == Gitlab::Access::DEVELOPER
+ max_member_access(user.id) == Gitlab::Access::DEVELOPER
end
def master?(user)
- max_tm_access(user.id) == Gitlab::Access::MASTER
+ max_member_access(user.id) == Gitlab::Access::MASTER
end
def member?(user_id)
- !!find_tm(user_id)
+ !!find_member(user_id)
end
- def max_tm_access(user_id)
+ def max_member_access(user_id)
access = []
access << project.project_members.find_by(user_id: user_id).try(:access_field)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 6117db418a..47758b8ad6 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -136,8 +136,8 @@ class Repository
commit = Gitlab::Git::Commit.new(rugged_commit)
{
- author_name: commit.author_name.force_encoding('UTF-8'),
- author_email: commit.author_email.force_encoding('UTF-8'),
+ author_name: commit.author_name,
+ author_email: commit.author_email,
additions: commit.stats.additions,
deletions: commit.stats.deletions,
}
diff --git a/app/models/user.rb b/app/models/user.rb
index a92095e582..d74dc9f013 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -169,13 +169,10 @@ class User < ActiveRecord::Base
scope :admins, -> { where(admin: true) }
scope :blocked, -> { with_state(:blocked) }
scope :active, -> { with_state(:active) }
- scope :in_team, ->(team){ where(id: team.member_ids) }
- 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 :subscribed_for_admin_email, -> { where(admin_email_unsubscribed_at: nil) }
scope :ldap, -> { joins(:identities).where('identities.provider LIKE ?', 'ldap%') }
- scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active }
#
# Class methods
@@ -419,7 +416,7 @@ class User < ActiveRecord::Base
end
def tm_of(project)
- project.team_member_by_id(self.id)
+ project.project_member_by_id(self.id)
end
def already_forked?(project)
diff --git a/app/services/audit_event_service.rb b/app/services/audit_event_service.rb
index 96e8d08917..e59268afd2 100644
--- a/app/services/audit_event_service.rb
+++ b/app/services/audit_event_service.rb
@@ -1,9 +1,43 @@
class AuditEventService
-
def initialize(author, entity, details = {})
@author, @entity, @details = author, entity, details
end
+ def for_member(member)
+ action = @details[:action]
+ old_access_level = @details[:old_access_level]
+ user_id = member.id
+ user_name = member.user.name
+
+ @details =
+ case action
+ when :destroy
+ {
+ remove: "user_access",
+ target_id: user_id,
+ target_type: "User",
+ target_details: user_name,
+ }
+ when :create
+ {
+ add: "user_access",
+ as: Gitlab::Access.options_with_owner.key(member.access_level.to_i),
+ target_id: user_id,
+ target_type: "User",
+ target_details: user_name,
+ }
+ when :update
+ {
+ change: "access_level",
+ from: old_access_level,
+ to: member.human_access,
+ target_id: user_id,
+ target_type: "User",
+ target_details: user_name,
+ }
+ end
+ end
+
def security_event
SecurityEvent.create(
author_id: @author.id,
diff --git a/app/services/base_service.rb b/app/services/base_service.rb
index 52ab29f149..6d9ed34591 100644
--- a/app/services/base_service.rb
+++ b/app/services/base_service.rb
@@ -31,8 +31,19 @@ class BaseService
SystemHooksService.new
end
- def current_application_settings
- ApplicationSetting.current
+ # Add an error to the specified model for restricted visibility levels
+ def deny_visibility_level(model, denied_visibility_level = nil)
+ denied_visibility_level ||= model.visibility_level
+
+ level_name = 'Unknown'
+ Gitlab::VisibilityLevel.options.each do |name, level|
+ level_name = name if level == denied_visibility_level
+ end
+
+ model.errors.add(
+ :visibility_level,
+ "#{level_name} visibility has been restricted by your GitLab administrator"
+ )
end
private
diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb
index 5e971c7891..cf7ae4345f 100644
--- a/app/services/create_branch_service.rb
+++ b/app/services/create_branch_service.rb
@@ -17,10 +17,15 @@ class CreateBranchService < BaseService
new_branch = repository.find_branch(branch_name)
if new_branch
- EventCreateService.new.push_ref(project, current_user, new_branch, 'add')
- return success(new_branch)
+ push_data = build_push_data(project, current_user, new_branch)
+
+ EventCreateService.new.push(project, current_user, push_data)
+ project.execute_hooks(push_data.dup, :push_hooks)
+ project.execute_services(push_data.dup, :push_hooks)
+
+ success(new_branch)
else
- return error('Invalid reference name')
+ error('Invalid reference name')
end
end
@@ -29,4 +34,9 @@ class CreateBranchService < BaseService
out[:branch] = branch
out
end
+
+ def build_push_data(project, user, branch)
+ Gitlab::PushDataBuilder.
+ build(project, user, Gitlab::Git::BLANK_SHA, branch.target, "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch.name}", [])
+ end
end
diff --git a/app/services/create_snippet_service.rb b/app/services/create_snippet_service.rb
new file mode 100644
index 0000000000..101a3df5ee
--- /dev/null
+++ b/app/services/create_snippet_service.rb
@@ -0,0 +1,20 @@
+class CreateSnippetService < BaseService
+ def execute
+ if project.nil?
+ snippet = PersonalSnippet.new(params)
+ else
+ snippet = project.snippets.build(params)
+ end
+
+ unless Gitlab::VisibilityLevel.allowed_for?(current_user,
+ params[:visibility_level])
+ deny_visibility_level(snippet)
+ return snippet
+ end
+
+ snippet.author = current_user
+
+ snippet.save
+ snippet
+ end
+end
diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb
index dfc5677c9d..af4b537cb9 100644
--- a/app/services/create_tag_service.rb
+++ b/app/services/create_tag_service.rb
@@ -21,9 +21,9 @@ class CreateTagService < BaseService
new_tag = repository.find_tag(tag_name)
if new_tag
- EventCreateService.new.push_ref(project, current_user, new_tag, 'add', Gitlab::Git::TAG_REF_PREFIX)
-
push_data = create_push_data(project, current_user, new_tag)
+
+ EventCreateService.new.push(project, current_user, push_data)
project.execute_hooks(push_data.dup, :tag_push_hooks)
project.execute_services(push_data.dup, :tag_push_hooks)
@@ -40,9 +40,7 @@ class CreateTagService < BaseService
end
def create_push_data(project, user, tag)
- data = Gitlab::PushDataBuilder.
+ Gitlab::PushDataBuilder.
build(project, user, Gitlab::Git::BLANK_SHA, tag.target, "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", [])
- data[:object_kind] = "tag_push"
- data
end
end
diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb
index c26aee2b0a..b19b112a0c 100644
--- a/app/services/delete_branch_service.rb
+++ b/app/services/delete_branch_service.rb
@@ -25,10 +25,15 @@ class DeleteBranchService < BaseService
end
if repository.rm_branch(branch_name)
- EventCreateService.new.push_ref(project, current_user, branch, 'rm')
+ push_data = build_push_data(branch)
+
+ EventCreateService.new.push(project, current_user, push_data)
+ project.execute_hooks(push_data.dup, :push_hooks)
+ project.execute_services(push_data.dup, :push_hooks)
+
success('Branch was removed')
else
- return error('Failed to remove branch')
+ error('Failed to remove branch')
end
end
@@ -43,4 +48,9 @@ class DeleteBranchService < BaseService
out[:message] = message
out
end
+
+ def build_push_data(branch)
+ Gitlab::PushDataBuilder
+ .build(project, current_user, branch.target, Gitlab::Git::BLANK_SHA, "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch.name}", [])
+ end
end
diff --git a/app/services/delete_tag_service.rb b/app/services/delete_tag_service.rb
new file mode 100644
index 0000000000..0c83640113
--- /dev/null
+++ b/app/services/delete_tag_service.rb
@@ -0,0 +1,42 @@
+require_relative 'base_service'
+
+class DeleteTagService < BaseService
+ def execute(tag_name)
+ repository = project.repository
+ tag = repository.find_tag(tag_name)
+
+ # No such tag
+ unless tag
+ return error('No such tag', 404)
+ end
+
+ if repository.rm_tag(tag_name)
+ push_data = build_push_data(tag)
+
+ EventCreateService.new.push(project, current_user, push_data)
+ project.execute_hooks(push_data.dup, :tag_push_hooks)
+ project.execute_services(push_data.dup, :tag_push_hooks)
+
+ success('Tag was removed')
+ else
+ error('Failed to remove tag')
+ end
+ end
+
+ def error(message, return_code = 400)
+ out = super(message)
+ out[:return_code] = return_code
+ out
+ end
+
+ def success(message)
+ out = super()
+ out[:message] = message
+ out
+ end
+
+ def build_push_data(tag)
+ Gitlab::PushDataBuilder
+ .build(project, current_user, tag.target, Gitlab::Git::BLANK_SHA, "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", [])
+ end
+end
diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb
index dc52d6d89d..103d6b0a08 100644
--- a/app/services/event_create_service.rb
+++ b/app/services/event_create_service.rb
@@ -62,26 +62,6 @@ class EventCreateService
create_event(project, current_user, Event::CREATED)
end
- def push_ref(project, current_user, ref, action = 'add', prefix = Gitlab::Git::BRANCH_REF_PREFIX)
- commit = project.repository.commit(ref.target)
-
- if action.to_s == 'add'
- before = Gitlab::Git::BLANK_SHA
- after = commit.id
- else
- before = commit.id
- after = Gitlab::Git::BLANK_SHA
- end
-
- data = {
- ref: "#{prefix}#{ref.name}",
- before: before,
- after: after
- }
-
- push(project, current_user, data)
- end
-
def push(project, current_user, push_data)
create_event(project, current_user, Event::PUSHED, data: push_data)
end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 742781f631..3358403cf2 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -53,7 +53,8 @@ class GitPushService
process_commit_messages(ref)
end
- @push_data = post_receive_data(oldrev, newrev, ref)
+ @push_data = build_push_data(oldrev, newrev, ref)
+
EventCreateService.new.push(project, user, @push_data)
project.execute_hooks(@push_data.dup, :push_hooks)
project.execute_services(@push_data.dup, :push_hooks)
@@ -105,7 +106,7 @@ class GitPushService
end
end
- def post_receive_data(oldrev, newrev, ref)
+ def build_push_data(oldrev, newrev, ref)
Gitlab::PushDataBuilder.
build(project, user, oldrev, newrev, ref, push_commits)
end
diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb
index cd92f50b02..0d8e6e85e4 100644
--- a/app/services/git_tag_push_service.rb
+++ b/app/services/git_tag_push_service.rb
@@ -3,21 +3,21 @@ class GitTagPushService
def execute(project, user, oldrev, newrev, ref)
@project, @user = project, user
- @push_data = create_push_data(oldrev, newrev, ref)
+
+ @push_data = build_push_data(oldrev, newrev, ref)
EventCreateService.new.push(project, user, @push_data)
- project.repository.expire_cache
project.execute_hooks(@push_data.dup, :tag_push_hooks)
project.execute_services(@push_data.dup, :tag_push_hooks)
+ project.repository.expire_cache
+
true
end
private
- def create_push_data(oldrev, newrev, ref)
- data = Gitlab::PushDataBuilder.build(project, user, oldrev, newrev, ref, [])
- data[:object_kind] = "tag_push"
- data
+ def build_push_data(oldrev, newrev, ref)
+ Gitlab::PushDataBuilder.build(project, user, oldrev, newrev, ref, [])
end
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 0063b7ce40..fb411c3e23 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -162,20 +162,20 @@ class NotificationService
end
end
- def new_team_member(project_member)
+ def new_project_member(project_member)
mailer.project_access_granted_email(project_member.id)
end
- def update_team_member(project_member)
+ def update_project_member(project_member)
mailer.project_access_granted_email(project_member.id)
end
- def new_group_member(users_group)
- mailer.group_access_granted_email(users_group.id)
+ def new_group_member(group_member)
+ mailer.group_access_granted_email(group_member.id)
end
- def update_group_member(users_group)
- mailer.group_access_granted_email(users_group.id)
+ def update_group_member(group_member)
+ mailer.group_access_granted_email(group_member.id)
end
def project_was_moved(project)
@@ -194,11 +194,11 @@ class NotificationService
project_members = project_member_notification(project)
users_with_project_level_global = project_member_notification(project, Notification::N_GLOBAL)
- users_with_group_level_global = users_group_notification(project, Notification::N_GLOBAL)
+ users_with_group_level_global = group_member_notification(project, Notification::N_GLOBAL)
users = users_with_global_level_watch([users_with_project_level_global, users_with_group_level_global].flatten.uniq)
users_with_project_setting = select_project_member_setting(project, users_with_project_level_global, users)
- users_with_group_setting = select_users_group_setting(project, project_members, users_with_group_level_global, users)
+ users_with_group_setting = select_group_member_setting(project, project_members, users_with_group_level_global, users)
User.where(id: users_with_project_setting.concat(users_with_group_setting).uniq).to_a
end
@@ -213,7 +213,7 @@ class NotificationService
end
end
- def users_group_notification(project, notification_level)
+ def group_member_notification(project, notification_level)
if project.group
project.group.group_members.where(notification_level: notification_level).pluck(:user_id)
else
@@ -243,8 +243,8 @@ class NotificationService
end
# Build a list of users based on group notification settings
- def select_users_group_setting(project, project_members, global_setting, users_global_level_watch)
- uids = users_group_notification(project, Notification::N_WATCH)
+ def select_group_member_setting(project, project_members, global_setting, users_global_level_watch)
+ uids = group_member_notification(project, Notification::N_WATCH)
# Group setting is watch, add to users list if user is not project member
users = []
@@ -273,20 +273,20 @@ class NotificationService
users.reject do |user|
next user.notification.disabled? unless project
- tm = project.project_members.find_by(user_id: user.id)
+ member = project.project_members.find_by(user_id: user.id)
- if !tm && project.group
- tm = project.group.group_members.find_by(user_id: user.id)
+ if !member && project.group
+ member = project.group.group_members.find_by(user_id: user.id)
end
# reject users who globally disabled notification and has no membership
- next user.notification.disabled? unless tm
+ next user.notification.disabled? unless member
# reject users who disabled notification in project
- next true if tm.notification.disabled?
+ next true if member.notification.disabled?
# reject users who have N_GLOBAL in project and disabled in global settings
- tm.notification.global? && user.notification.disabled?
+ member.notification.global? && user.notification.disabled?
end
end
@@ -297,20 +297,20 @@ class NotificationService
users.reject do |user|
next user.notification.mention? unless project
- tm = project.project_members.find_by(user_id: user.id)
+ member = project.project_members.find_by(user_id: user.id)
- if !tm && project.group
- tm = project.group.group_members.find_by(user_id: user.id)
+ if !member && project.group
+ member = project.group.group_members.find_by(user_id: user.id)
end
# reject users who globally set mention notification and has no membership
- next user.notification.mention? unless tm
+ next user.notification.mention? unless member
# reject users who set mention notification in project
- next true if tm.notification.mention?
+ next true if member.notification.mention?
# reject users who have N_MENTION in project and disabled in global settings
- tm.notification.global? && user.notification.mention?
+ member.notification.global? && user.notification.mention?
end
end
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 4fe790b98f..7ffd0b3882 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -7,9 +7,12 @@ module Projects
def execute
@project = Project.new(params)
- # Reset visibility level if is not allowed to set it
- unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
- @project.visibility_level = default_features.visibility_level
+ # Make sure that the user is allowed to use the specified visibility
+ # level
+ unless Gitlab::VisibilityLevel.allowed_for?(current_user,
+ params[:visibility_level])
+ deny_visibility_level(@project)
+ return @project
end
# Set project name from path
diff --git a/app/services/projects/participants_service.rb b/app/services/projects/participants_service.rb
index f6f9aceef9..bcbacbff56 100644
--- a/app/services/projects/participants_service.rb
+++ b/app/services/projects/participants_service.rb
@@ -12,8 +12,8 @@ module Projects
else
[]
end
- team_members = sorted(@project.team.members)
- participants = all_members + groups + team_members + participating
+ project_members = sorted(@project.team.members)
+ participants = all_members + groups + project_members + participating
participants.uniq
end
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 36877a6167..69bdd045dd 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -2,8 +2,13 @@ module Projects
class UpdateService < BaseService
def execute
# check that user is allowed to set specified visibility_level
- unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
- params[:visibility_level] = project.visibility_level
+ new_visibility = params[:visibility_level]
+ if new_visibility && new_visibility.to_i != project.visibility_level
+ unless can?(current_user, :change_visibility_level, project) &&
+ Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
+ deny_visibility_level(project, new_visibility)
+ return project
+ end
end
new_branch = params[:default_branch]
diff --git a/app/services/update_snippet_service.rb b/app/services/update_snippet_service.rb
new file mode 100644
index 0000000000..9d181c2d2a
--- /dev/null
+++ b/app/services/update_snippet_service.rb
@@ -0,0 +1,22 @@
+class UpdateSnippetService < BaseService
+ attr_accessor :snippet
+
+ def initialize(project, user, snippet, params)
+ super(project, user, params)
+ @snippet = snippet
+ end
+
+ def execute
+ # check that user is allowed to set specified visibility_level
+ new_visibility = params[:visibility_level]
+ if new_visibility && new_visibility.to_i != snippet.visibility_level
+ unless can?(current_user, :change_visibility_level, snippet) &&
+ Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
+ deny_visibility_level(snippet, new_visibility)
+ return snippet
+ end
+ end
+
+ snippet.update_attributes(params)
+ end
+end
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 46c5908f1b..827e555c14 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -42,6 +42,14 @@
= f.label :default_branch_protection, class: 'control-label col-sm-2'
.col-sm-10
= f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
+ .form-group
+ = f.label :restricted_visibility_levels, class: 'control-label col-sm-2'
+ .col-sm-10
+ - data_attrs = { toggle: 'buttons' }
+ .btn-group{ data: data_attrs }
+ - restricted_level_checkboxes('restricted-visibility-help').each do |level|
+ = level
+ %span.help-block#restricted-visibility-help Selected levels cannot be used by non-admin users for projects or snippets
.form-group
= f.label :home_page_url, class: 'control-label col-sm-2'
.col-sm-10
diff --git a/app/views/admin/applications/_delete_form.html.haml b/app/views/admin/applications/_delete_form.html.haml
index 371ac55209..3147cbd659 100644
--- a/app/views/admin/applications/_delete_form.html.haml
+++ b/app/views/admin/applications/_delete_form.html.haml
@@ -1,4 +1,4 @@
-- submit_btn_css ||= 'btn btn-link btn-remove btn-small'
+- submit_btn_css ||= 'btn btn-link btn-remove btn-sm'
= form_tag admin_application_path(application) do
%input{:name => "_method", :type => "hidden", :value => "delete"}/
= submit_tag 'Destroy', onclick: "return confirm('Are you sure?')", class: submit_btn_css
\ No newline at end of file
diff --git a/app/views/admin/broadcast_messages/index.html.haml b/app/views/admin/broadcast_messages/index.html.haml
index 7b483ee655..c0afaf16d8 100644
--- a/app/views/admin/broadcast_messages/index.html.haml
+++ b/app/views/admin/broadcast_messages/index.html.haml
@@ -52,7 +52,7 @@
%strong
#{broadcast_message.ends_at.to_s(:short)}
- = link_to [:admin, broadcast_message], method: :delete, remote: true, class: 'remove-row btn btn-tiny' do
+ = link_to [:admin, broadcast_message], method: :delete, remote: true, class: 'remove-row btn btn-xs' do
%i.fa.fa-times.cred
.message= broadcast_message.message
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 8ae9a1edea..4c53ff5570 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -40,8 +40,8 @@
%li
.clearfix
.pull-right.prepend-top-10
- = link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small"
- = link_to 'Destroy', [:admin, group], data: {confirm: "REMOVE #{group.name}? Are you sure?"}, method: :delete, class: "btn btn-small btn-remove"
+ = link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-sm"
+ = link_to 'Destroy', [:admin, group], data: {confirm: "REMOVE #{group.name}? Are you sure?"}, method: :delete, class: "btn btn-sm btn-remove"
%h4
= link_to [:admin, group] do
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 7a36036519..8e4a31053d 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -12,7 +12,7 @@
Group info:
%ul.well-list
%li
- = image_tag group_icon(@group.path), class: "avatar s60"
+ = image_tag group_icon(@group), class: "avatar s60"
%li
%span.light Name:
%strong= @group.name
@@ -85,7 +85,7 @@
Read more about project permissions
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
- = form_tag project_teams_update_admin_group_path(@group), id: "new_team_member", class: "bulk_import", method: :put do
+ = form_tag members_update_admin_group_path(@group), id: "new_project_member", class: "bulk_import", method: :put do
%div
= users_select_tag(:user_ids, { multiple: true, skip_ldap: @group.ldap_synced? })
%div.prepend-top-10
@@ -107,7 +107,7 @@
= link_to user.name, admin_user_path(user)
%span.pull-right.light
= member.human_access
- = 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
+ = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-xs 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/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml
index 0c5db0805f..7a9dc113f2 100644
--- a/app/views/admin/hooks/index.html.haml
+++ b/app/views/admin/hooks/index.html.haml
@@ -33,5 +33,5 @@
%strong= hook.url
.pull-right
- = link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-small"
- = link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-remove btn-small"
+ = link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-sm"
+ = link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm"
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 3a1e61d5d8..3bbe10bc27 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -74,8 +74,8 @@
.pull-right
%span.label.label-gray
= repository_size(project)
- = link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
- = link_to 'Destroy', [project.namespace.becomes(Namespace), project], data: { confirm: remove_project_message(project) }, method: :delete, class: "btn btn-small btn-remove"
+ = link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm"
+ = link_to 'Destroy', [project.namespace.becomes(Namespace), project], data: { confirm: remove_project_message(project) }, method: :delete, class: "btn btn-sm btn-remove"
- if @projects.blank?
.nothing-here-block 0 projects matches
= paginate @projects, theme: "gitlab"
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 1421c2ea90..077ee56908 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -97,7 +97,7 @@
%strong #{@group.name}
group members (#{@group.group_members.count})
.pull-right
- = link_to admin_group_path(@group), class: 'btn btn-small' do
+ = link_to admin_group_path(@group), class: 'btn btn-sm' do
%i.fa.fa-pencil-square-o
%ul.well-list
- @group_members.each do |member|
@@ -111,10 +111,10 @@
%small
(#{@project.users.count})
.pull-right
- = link_to namespace_project_team_index_path(@project.namespace, @project), class: "btn btn-tiny" do
+ = link_to namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-xs" do
%i.fa.fa-pencil-square-o
Manage Access
- %ul.well-list.team_members
+ %ul.well-list.project_members
- @project_members.each do |project_member|
- user = project_member.user
%li.project_member
@@ -126,7 +126,7 @@
%span.light Owner
- else
%span.light= project_member.human_access
- = link_to namespace_project_team_member_path(@project.namespace, @project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, remote: true, class: "btn btn-small btn-remove" do
+ = link_to namespace_project_project_member_path(@project.namespace, @project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, remote: true, class: "btn btn-sm btn-remove" do
%i.fa.fa-times
.panel-footer
= paginate @project_members, param_name: 'project_members_page', theme: 'gitlab'
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 680bd9ceb9..3c201c3a9a 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -79,11 +79,11 @@
%i.fa.fa-envelope
= mail_to user.email, user.email, class: 'light'
- = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small"
+ = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-sm"
- unless user == current_user
- if user.blocked?
- = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-small success"
+ = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-sm success"
- else
- = link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-small btn-remove"
- = link_to 'Destroy', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! All tickets linked to this user will also be removed! Maybe block the user instead? Are you sure?" }, method: :delete, class: "btn btn-small btn-remove"
+ = link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-sm btn-remove"
+ = link_to 'Destroy', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! All tickets linked to this user will also be removed! Maybe block the user instead? Are you sure?" }, method: :delete, class: "btn btn-sm btn-remove"
= paginate @users, theme: "gitlab"
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 90c9f8c2f9..0a2934d3bd 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -46,7 +46,7 @@
%li
%span.light Secondary email:
%strong= email.email
- = link_to remove_email_admin_user_path(@user, email), data: { confirm: "Are you sure you want to remove #{email.email}?" }, method: :delete, class: "btn-tiny btn btn-remove pull-right", title: 'Remove secondary email', id: "remove_email_#{email.id}" do
+ = link_to remove_email_admin_user_path(@user, email), data: { confirm: "Are you sure you want to remove #{email.email}?" }, method: :delete, class: "btn-xs btn btn-remove pull-right", title: 'Remove secondary email', id: "remove_email_#{email.id}" do
%i.fa.fa-times
%li
@@ -174,15 +174,15 @@
.panel.panel-default
.panel-heading Groups:
%ul.well-list
- - @user.group_members.each do |user_group|
- - group = user_group.group
+ - @user.group_members.each do |group_member|
+ - group = group_member.group
%li.group_member
- %span{class: ("list-item-name" unless user_group.owner?)}
+ %span{class: ("list-item-name" unless group_member.owner?)}
%strong= link_to group.name, admin_group_path(group)
.pull-right
- %span.light= user_group.human_access
- - unless user_group.owner?
- = link_to group_group_member_path(group, user_group), 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
+ %span.light= group_member.human_access
+ - unless group_member.owner?
+ = link_to group_group_member_path(group, group_member), data: { confirm: remove_user_from_group_message(group, @user) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
%i.fa.fa-times.fa-inverse
- else
.nothing-here-block This user has no groups.
@@ -207,21 +207,21 @@
.panel-heading Joined projects (#{@joined_projects.count})
%ul.well-list
- @joined_projects.sort_by(&:name_with_namespace).each do |project|
- - tm = project.team.find_tm(@user.id)
+ - member = project.team.find_member(@user.id)
%li.project_member
.list-item-name
= link_to admin_namespace_project_path(project.namespace, project), class: dom_class(project) do
= project.name_with_namespace
- - if tm
+ - if member
.pull-right
- - if tm.owner?
+ - if member.owner?
%span.light Owner
- else
- %span.light= tm.human_access
+ %span.light= member.human_access
- - if tm.respond_to? :project
- = link_to namespace_project_team_member_path(project.namespace, project, @user), data: { confirm: remove_from_project_team_message(project, @user) }, remote: true, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from project' do
+ - if member.respond_to? :project
+ = link_to namespace_project_project_member_path(project.namespace, project, @user), data: { confirm: remove_from_project_team_message(project, @user) }, remote: true, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from project' do
%i.fa.fa-times
#ssh-keys.tab-pane
= render 'profiles/keys/key_table', admin: true
diff --git a/app/views/dashboard/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml
index 50e90b1c17..165db214d7 100644
--- a/app/views/dashboard/groups/index.html.haml
+++ b/app/views/dashboard/groups/index.html.haml
@@ -11,30 +11,30 @@
.panel.panel-default
.panel-heading
%strong Groups
- (#{@user_groups.count})
+ (#{@group_members.count})
%ul.well-list
- - @user_groups.each do |user_group|
- - group = user_group.group
+ - @group_members.each do |group_member|
+ - group = group_member.group
%li
.pull-right
- if can?(current_user, :manage_group, group)
- = link_to edit_group_path(group), class: "btn-small btn btn-grouped" do
+ = link_to edit_group_path(group), class: "btn-sm btn btn-grouped" do
%i.fa.fa-cogs
Settings
- - if can?(current_user, :destroy, user_group)
- = link_to leave_dashboard_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn btn-grouped", title: 'Remove user from group' do
+ - if can?(current_user, :destroy_group_member, group_member)
+ = link_to leave_group_group_members_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-sm btn btn-grouped", title: 'Remove user from group' do
%i.fa.fa-sign-out
Leave
- = image_tag group_icon(group.path), class: "avatar s40 avatar-tile"
+ = image_tag group_icon(group), class: "avatar s40 avatar-tile"
= link_to group, class: 'group-name' do
%strong= group.name
as
- %strong #{user_group.human_access}
+ %strong #{group_member.human_access}
%div.light
#{pluralize(group.projects.count, "project")}, #{pluralize(group.users.count, "user")}
-= paginate @user_groups
+= paginate @group_members
diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml
index e986989a72..812e22373a 100644
--- a/app/views/devise/sessions/_new_ldap.html.haml
+++ b/app/views/devise/sessions/_new_ldap.html.haml
@@ -1,4 +1,4 @@
-= form_tag(user_omniauth_callback_path(provider), id: 'new_ldap_user' ) do
- = text_field_tag :username, nil, {class: "form-control top", placeholder: "LDAP Login", autofocus: "autofocus"}
+= form_tag(user_omniauth_callback_path(server['provider_name']), id: 'new_ldap_user' ) do
+ = text_field_tag :username, nil, {class: "form-control top", placeholder: "#{server['label']} Login", autofocus: "autofocus"}
= password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"}
- = button_tag "LDAP Sign in", class: "btn-save btn"
+ = button_tag "#{server['label']} Sign in", class: "btn-save btn"
diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml
index 1fb65c3937..7900995dc4 100644
--- a/app/views/devise/shared/_signin_box.html.haml
+++ b/app/views/devise/shared/_signin_box.html.haml
@@ -20,7 +20,7 @@
.tab-content
- @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']
+ = render 'devise/sessions/new_ldap', server: server
- if kerberos_enabled?
%div#tab-kerberos.tab-pane{class: (:active unless ldap_enabled?)}
= render 'devise/sessions/new_kerberos', provider: :kerberos
diff --git a/app/views/doorkeeper/applications/_delete_form.html.haml b/app/views/doorkeeper/applications/_delete_form.html.haml
index bf8098f38d..6a5c917049 100644
--- a/app/views/doorkeeper/applications/_delete_form.html.haml
+++ b/app/views/doorkeeper/applications/_delete_form.html.haml
@@ -1,4 +1,4 @@
-- submit_btn_css ||= 'btn btn-link btn-remove btn-small'
+- submit_btn_css ||= 'btn btn-link btn-remove btn-sm'
= form_tag oauth_application_path(application) do
%input{:name => "_method", :type => "hidden", :value => "delete"}/
= submit_tag 'Destroy', onclick: "return confirm('Are you sure?')", class: submit_btn_css
\ No newline at end of file
diff --git a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
index 5cbb4a70c1..4bba72167e 100644
--- a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
+++ b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
@@ -1,4 +1,4 @@
- submit_btn_css ||= 'btn btn-link btn-remove'
= form_tag oauth_authorized_application_path(application) do
%input{:name => "_method", :type => "hidden", :value => "delete"}/
- = submit_tag 'Revoke', onclick: "return confirm('Are you sure?')", class: 'btn btn-link btn-remove btn-small'
\ No newline at end of file
+ = submit_tag 'Revoke', onclick: "return confirm('Are you sure?')", class: 'btn btn-link btn-remove btn-sm'
\ No newline at end of file
diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml
index cb40aa9970..d2f0005142 100644
--- a/app/views/events/_event_last_push.html.haml
+++ b/app/views/events/_event_last_push.html.haml
@@ -9,6 +9,6 @@
#{time_ago_with_tooltip(event.created_at)}
.pull-right
- = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-create btn-small" do
+ = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-create btn-sm" do
Create Merge Request
%hr
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 36950a4166..30d8a5c951 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -12,7 +12,7 @@
.form-group
.col-sm-2
.col-sm-10
- = image_tag group_icon(@group.to_param), alt: '', class: 'avatar group-avatar s160'
+ = image_tag group_icon(@group), alt: '', class: 'avatar group-avatar s160'
%p.light
- if @group.avatar?
You can change your group avatar here
@@ -21,7 +21,7 @@
= 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"
+ = 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-sm remove-avatar"
.form-group
%hr
diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml
index 6267006f63..003025221b 100644
--- a/app/views/groups/group_members/_group_member.html.haml
+++ b/app/views/groups/group_members/_group_member.html.haml
@@ -1,6 +1,7 @@
- user = member.user
- return unless user
- show_roles = true if show_roles.nil?
+
%li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
%span{class: ("list-item-name" if show_controls)}
= image_tag avatar_icon(user.email, 16), class: "avatar s16"
@@ -16,20 +17,21 @@
%span.pull-right
%strong= member.human_access
- if show_controls
- - if can?(current_user, :modify, member)
- = button_tag class: "btn-tiny btn js-toggle-button",
+ - if can?(current_user, :modify_group_member, member)
+ = button_tag class: "btn-xs btn js-toggle-button",
title: 'Edit access level', type: 'button' do
%i.fa.fa-pencil-square-o
- - if can?(current_user, :destroy, member)
- - if current_user == member.user
- = link_to leave_dashboard_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
+ - if can?(current_user, :destroy_group_member, member)
+
+ - if current_user == user
+ = link_to leave_group_group_members_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
%i.fa.fa-minus.fa-inverse
- else
- = 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
+ = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
%i.fa.fa-minus.fa-inverse
.edit-member.hide.js-toggle-content
= form_for [@group, member], remote: true do |f|
.alert.prepend-top-20
= f.select :access_level, options_for_select(GroupMember.access_level_roles, member.access_level)
- = f.submit 'Save', class: 'btn btn-save btn-small'
+ = f.submit 'Save', class: 'btn btn-save btn-sm'
diff --git a/app/views/groups/_new_group_member.html.haml b/app/views/groups/group_members/_new_group_member.html.haml
similarity index 73%
rename from app/views/groups/_new_group_member.html.haml
rename to app/views/groups/group_members/_new_group_member.html.haml
index 9123b3b94f..13e4e2fae1 100644
--- a/app/views/groups/_new_group_member.html.haml
+++ b/app/views/groups/group_members/_new_group_member.html.haml
@@ -1,4 +1,4 @@
-= form_for @users_group, url: group_group_members_path(@group), html: { class: 'form-horizontal users-group-form' } do |f|
+= form_for @group_member, url: group_group_members_path(@group), html: { class: 'form-horizontal users-group-form' } do |f|
.form-group
= f.label :user_ids, "People", class: 'control-label'
.col-sm-10= users_select_tag(:user_ids, { multiple: true, skip_ldap: @group.ldap_synced? , class: 'input-large' })
@@ -6,7 +6,7 @@
.form-group
= f.label :access_level, "Group Access", class: 'control-label'
.col-sm-10
- = select_tag :access_level, options_for_select(GroupMember.access_level_roles, @users_group.access_level), class: "project-access-select select2"
+ = select_tag :access_level, options_for_select(GroupMember.access_level_roles, @group_member.access_level), class: "project-access-select select2"
.help-block
Read more about role permissions
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
diff --git a/app/views/groups/members.html.haml b/app/views/groups/group_members/index.html.haml
similarity index 95%
rename from app/views/groups/members.html.haml
rename to app/views/groups/group_members/index.html.haml
index b59c6ed9ef..40893df282 100644
--- a/app/views/groups/members.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -1,4 +1,5 @@
- show_roles = should_user_see_group_roles?(current_user, @group)
+
%h3.page-title
Group members
- if show_roles
@@ -10,7 +11,7 @@
%hr
.clearfix.js-toggle-container
- = form_tag members_group_path(@group), method: :get, class: 'form-inline member-search-form' do
+ = form_tag group_group_members_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' }
= button_tag 'Search', class: 'btn'
@@ -50,6 +51,7 @@
%ul.well-list
- @members.each do |member|
= render 'groups/group_members/group_member', member: member, show_roles: show_roles, show_controls: true
+
= paginate @members, theme: 'gitlab'
:coffeescript
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index 9febaab04a..57dc235f5b 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -22,9 +22,9 @@
.pull-right
- if can?(current_user, :manage_group, @group)
- if milestone.closed?
- = link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped btn-reopen"
+ = link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen"
- else
- = link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-close"
+ = link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-sm btn-close"
%h4
= link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, milestone.safe_title, title: milestone.title)
%div
diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml
index dd2d84499b..fea70f5cbc 100644
--- a/app/views/groups/milestones/show.html.haml
+++ b/app/views/groups/milestones/show.html.haml
@@ -8,9 +8,9 @@
.pull-right
- if can?(current_user, :manage_group, @group)
- if @group_milestone.active?
- = link_to 'Close Milestone', group_milestone_path(@group, @group_milestone.safe_title, title: @group_milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-close"
+ = link_to 'Close Milestone', group_milestone_path(@group, @group_milestone.safe_title, title: @group_milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-sm btn-close"
- else
- = link_to 'Reopen Milestone', group_milestone_path(@group, @group_milestone.safe_title, title: @group_milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped btn-reopen"
+ = link_to 'Reopen Milestone', group_milestone_path(@group, @group_milestone.safe_title, title: @group_milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen"
%hr
- if (@group_milestone.total_items_count == @group_milestone.closed_items_count) && @group_milestone.active?
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index 976868ec8f..d825215bcd 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -16,9 +16,9 @@
%span.label.label-gray
= repository_size(project)
.pull-right
- = link_to 'Members', namespace_project_team_index_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
- = link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
- = link_to 'Remove', namespace_project_path(project.namespace, project), data: { confirm: remove_project_message(project)}, method: :delete, class: "btn btn-small btn-remove"
+ = link_to 'Members', namespace_project_project_members_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm"
+ = link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm"
+ = link_to 'Remove', project, data: { confirm: remove_project_message(project)}, method: :delete, class: "btn btn-sm btn-remove"
- if @projects.blank?
.nothing-here-block This group has no projects yet
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 9706e4bc90..8d2a6322d2 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -1,6 +1,6 @@
.dashboard
%div
- = image_tag group_icon(@group.path), class: "avatar group-avatar s90"
+ = image_tag group_icon(@group), class: "avatar group-avatar s90"
.clearfix
%h2
= @group.name
diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml
index 58de5b7c86..ed03f885dc 100644
--- a/app/views/help/ui.html.haml
+++ b/app/views/help/ui.html.haml
@@ -21,6 +21,8 @@
= link_to 'Alerts', '#alerts'
%li
= link_to 'Forms', '#forms'
+ %li
+ = link_to 'Files', '#file'
%li
= link_to 'Markdown', '#markdown'
@@ -193,6 +195,23 @@
Remember me
%button.btn.btn-default{:type => "submit"} Sign in
+ %h2#file File
+ %h3
+ %code .file-holder
+
+ - blob = Snippet.new(content: "Wow\nSuch\nFile")
+ .example
+ .file-holder
+ .file-title
+ Awesome file
+ .file-actions
+ .btn-group
+ %a.btn Edit
+ %a.btn Remove
+ .file-contenta.code
+ = render 'shared/file_highlight', blob: blob
+
+
%h2#markdown Markdown
%h3
%code .md or .wiki and others
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index bcbbaadf3e..9da3c920c6 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -23,7 +23,7 @@
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
- %span.cgreen
+ %span
%i.fa.fa-check
done
- elsif project.import_status == 'started'
diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml
index 883090a302..9c4d91013e 100644
--- a/app/views/import/github/status.html.haml
+++ b/app/views/import/github/status.html.haml
@@ -23,7 +23,7 @@
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
- %span.cgreen
+ %span
%i.fa.fa-check
done
- elsif project.import_status == 'started'
diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml
index 41ac073eae..e809643d8d 100644
--- a/app/views/import/gitlab/status.html.haml
+++ b/app/views/import/gitlab/status.html.haml
@@ -23,7 +23,7 @@
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
- %span.cgreen
+ %span
%i.fa.fa-check
done
- elsif project.import_status == 'started'
diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml
index ebe24747a0..645241a6c6 100644
--- a/app/views/import/gitorious/status.html.haml
+++ b/app/views/import/gitorious/status.html.haml
@@ -23,7 +23,7 @@
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
- %span.cgreen
+ %span
%i.fa.fa-check
done
- elsif project.import_status == 'started'
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index ddd3df19ee..32fe0e37df 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -24,8 +24,8 @@
Merge Requests
- if current_user
%span.count= MergeRequest.opened.of_group(@group).count
- = nav_link(path: 'groups#members') do
- = link_to members_group_path(@group), title: 'Members' do
+ = nav_link(controller: [:group_members]) do
+ = link_to group_group_members_path(@group), title: 'Members' do
%i.fa.fa-users
%span
Members
diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml
index 5272dfa0ed..778a78acf5 100644
--- a/app/views/notify/_note_message.html.haml
+++ b/app/views/notify/_note_message.html.haml
@@ -1,2 +1,2 @@
%div
- = markdown(@note.note)
+ = replace_image_links_with_base64(markdown(@note.note), @note.project)
diff --git a/app/views/notify/group_access_granted_email.html.haml b/app/views/notify/group_access_granted_email.html.haml
index 823ebf7734..f1916d624b 100644
--- a/app/views/notify/group_access_granted_email.html.haml
+++ b/app/views/notify/group_access_granted_email.html.haml
@@ -1,4 +1,4 @@
%p
- = "You have been granted #{@membership.human_access} access to group"
+ = "You have been granted #{@group_member.human_access} access to group"
= link_to group_url(@group) do
= @group.name
diff --git a/app/views/notify/group_access_granted_email.text.erb b/app/views/notify/group_access_granted_email.text.erb
index 331bb98d5c..ef9617bfc1 100644
--- a/app/views/notify/group_access_granted_email.text.erb
+++ b/app/views/notify/group_access_granted_email.text.erb
@@ -1,4 +1,4 @@
-You have been granted <%= @membership.human_access %> access to group <%= @group.name %>
+You have been granted <%= @group_member.human_access %> access to group <%= @group.name %>
<%= url_for(group_url(@group)) %>
diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml
index f2f8eee18c..03cbee9460 100644
--- a/app/views/notify/new_issue_email.html.haml
+++ b/app/views/notify/new_issue_email.html.haml
@@ -1,5 +1,5 @@
-if @issue.description
- = markdown(@issue.description)
+ = replace_image_links_with_base64(markdown(@issue.description), @issue.project)
- if @issue.assignee_id.present?
%p
diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml
index f02d5111b2..729a7bb505 100644
--- a/app/views/notify/new_merge_request_email.html.haml
+++ b/app/views/notify/new_merge_request_email.html.haml
@@ -6,4 +6,4 @@
Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name}
-if @merge_request.description
- = markdown(@merge_request.description)
+ = replace_image_links_with_base64(markdown(@merge_request.description), @merge_request.project)
diff --git a/app/views/profiles/applications.html.haml b/app/views/profiles/applications.html.haml
index c8c522e981..97e98948f3 100644
--- a/app/views/profiles/applications.html.haml
+++ b/app/views/profiles/applications.html.haml
@@ -23,7 +23,7 @@
- application.redirect_uri.split.each do |uri|
%div= uri
%td= application.access_tokens.count
- %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link btn-small'
+ %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link btn-sm'
%td= render 'doorkeeper/applications/delete_form', application: application
%fieldset.oauth-authorized-applications.prepend-top-20
diff --git a/app/views/profiles/design.html.haml b/app/views/profiles/design.html.haml
index 8d09595fd4..cc00d08d03 100644
--- a/app/views/profiles/design.html.haml
+++ b/app/views/profiles/design.html.haml
@@ -33,6 +33,11 @@
.prev.violet
= f.radio_button :theme_id, 5
Violet
+
+ = label_tag do
+ .prev.blue
+ = f.radio_button :theme_id, 6
+ Blue
%br
.clearfix
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
index 3bbad6fdf7..9d8f33cbba 100644
--- a/app/views/profiles/emails/index.html.haml
+++ b/app/views/profiles/emails/index.html.haml
@@ -25,7 +25,7 @@
%strong= email.email
%span.cgray
added #{time_ago_with_tooltip(email.created_at)}
- = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-small btn-remove pull-right'
+ = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-remove pull-right'
%h4 Add email address
= form_for 'email', url: profile_emails_path, html: { class: 'form-horizontal' } do |f|
diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml
index 141e18e45e..a7a2de94f4 100644
--- a/app/views/profiles/keys/_key.html.haml
+++ b/app/views/profiles/keys/_key.html.haml
@@ -10,4 +10,4 @@
added #{time_ago_with_tooltip(key.created_at)}
%td
- unless key.is_a? LDAPKey
- = link_to 'Remove', path_to_key(key, is_admin), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-small btn-remove delete-key pull-right"
+ = link_to 'Remove', path_to_key(key, is_admin), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-sm btn-remove delete-key pull-right"
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index 6cf5c81c19..273e72f8a4 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -62,9 +62,9 @@
By default, all projects and groups will use the notification level set above.
%h4 Groups:
%ul.bordered-list
- - @group_members.each do |users_group|
- - notification = Notification.new(users_group)
- = render 'settings', type: 'group', membership: users_group, notification: notification
+ - @group_members.each do |group_member|
+ - notification = Notification.new(group_member)
+ = render 'settings', type: 'group', membership: group_member, notification: notification
.col-md-6
%p
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 1a7bc353bf..e6b204451c 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -77,7 +77,7 @@
%br
or change it at #{link_to "gravatar.com", "http://gravatar.com"}
%hr
- %a.choose-btn.btn.btn-small.js-choose-user-avatar-button
+ %a.choose-btn.btn.btn-sm.js-choose-user-avatar-button
%i.fa.fa-paperclip
%span Choose File ...
@@ -86,7 +86,7 @@
.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"
+ = link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
- if @user.public_profile?
.alert.alert-info
diff --git a/app/views/projects/_dropdown.html.haml b/app/views/projects/_dropdown.html.haml
index 2d5120f283..f4f4c2662c 100644
--- a/app/views/projects/_dropdown.html.haml
+++ b/app/views/projects/_dropdown.html.haml
@@ -15,9 +15,9 @@
%li
= link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
New snippet
- - if can?(current_user, :admin_team_member, @project)
+ - if can?(current_user, :admin_project_member, @project)
%li
- = link_to new_namespace_project_team_member_path(@project.namespace, @project), title: "New project member" do
+ = link_to namespace_project_project_members_path(@project.namespace, @project), title: "New project member" do
New project member
- if can? current_user, :push_code, @project
%li.divider
diff --git a/app/views/projects/_settings_nav.html.haml b/app/views/projects/_settings_nav.html.haml
index 411e6ca354..b45af073a7 100644
--- a/app/views/projects/_settings_nav.html.haml
+++ b/app/views/projects/_settings_nav.html.haml
@@ -4,8 +4,8 @@
%i.fa.fa-pencil-square-o
%span
Project
- = nav_link(controller: [:team_members, :teams]) do
- = link_to namespace_project_team_index_path(@project.namespace, @project), title: 'Members', class: "team-tab tab" do
+ = nav_link(controller: [:project_members, :teams]) do
+ = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: "team-tab tab" do
%i.fa.fa-users
%span
Members
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index 5a33d18e63..e6a859fea8 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -4,10 +4,11 @@
.file-holder
.file-title
%i.fa.fa-file
- %span.file_name
+ %strong
= @path
- %small= number_to_human_size @blob.size
- %span.options= render "projects/blob/actions"
+ %small= number_to_human_size @blob.size
+ .file-actions
+ = render "projects/blob/actions"
.file-content.blame.highlight
%table
- @blame.each do |commit, lines, since|
@@ -30,5 +31,5 @@
%code
:erb
<% lines.each do |line| %>
- <%= highlight(@blob.name, line.force_encoding("utf-8"), true).html_safe %>
+ <%= highlight(@blob.name, line, true).html_safe %>
<% end %>
diff --git a/app/views/projects/blob/_actions.html.haml b/app/views/projects/blob/_actions.html.haml
index b5b29540bb..13f8271b97 100644
--- a/app/views/projects/blob/_actions.html.haml
+++ b/app/views/projects/blob/_actions.html.haml
@@ -1,22 +1,22 @@
.btn-group.tree-btn-group
= edit_blob_link(@project, @ref, @path)
= link_to 'Raw', namespace_project_raw_path(@project.namespace, @project, @id),
- class: 'btn btn-small', target: '_blank'
+ class: 'btn btn-sm', target: '_blank'
-# only show normal/blame view links for text files
- if @blob.text?
- if current_page? namespace_project_blame_path(@project.namespace, @project, @id)
= link_to 'Normal View', namespace_project_blob_path(@project.namespace, @project, @id),
- class: 'btn btn-small'
+ class: 'btn btn-sm'
- else
= link_to 'Blame', namespace_project_blame_path(@project.namespace, @project, @id),
- class: 'btn btn-small' unless @blob.empty?
+ class: 'btn btn-sm' unless @blob.empty?
= link_to 'History', namespace_project_commits_path(@project.namespace, @project, @id),
- class: 'btn btn-small'
+ class: 'btn btn-sm'
- if @ref != @commit.sha
= link_to 'Permalink', namespace_project_blob_path(@project.namespace, @project,
- tree_join(@commit.sha, @path)), class: 'btn btn-small'
+ tree_join(@commit.sha, @path)), class: 'btn btn-sm'
- if allowed_tree_edit?
- = button_tag class: 'remove-blob btn btn-small btn-remove',
+ = button_tag class: 'remove-blob btn btn-sm btn-remove',
'data-toggle' => 'modal', 'data-target' => '#modal-remove-blob' do
Remove
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index 9ff61f3887..ba60bd9286 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -21,12 +21,14 @@
%div#tree-content-holder.tree-content-holder
%article.file-holder
- .file-title.clearfix
+ .file-title
%i.fa.fa-file
- %span.file_name
+ %strong
= blob.name
- %small= number_to_human_size blob.size
- %span.options.hidden-xs= render "actions"
+ %small
+ = number_to_human_size(blob.size)
+ .file-actions.hidden-xs
+ = render "actions"
- if blob.text?
= render "text", blob: blob
- elsif blob.image?
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 8de629b03e..0de8c509f2 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -11,14 +11,14 @@
protected
.pull-right
- if can?(current_user, :download_code, @project)
- = render 'projects/repositories/download_archive', ref: branch.name, btn_class: 'btn-grouped btn-group-small'
+ = render 'projects/repositories/download_archive', ref: branch.name, btn_class: 'btn-grouped btn-group-sm'
- if branch.name != @repository.root_ref
- = link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: branch.name), class: 'btn btn-grouped btn-small', method: :post, title: "Compare" do
+ = link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: branch.name), class: 'btn btn-grouped btn-sm', method: :post, title: "Compare" do
%i.fa.fa-files-o
Compare
- if can_remove_branch?(@project, branch.name)
- = link_to namespace_project_branch_path(@project.namespace, @project, branch.name), class: 'btn btn-grouped btn-small btn-remove remove-row', method: :delete, data: { confirm: 'Removed branch cannot be restored. Are you sure?'}, remote: true do
+ = link_to namespace_project_branch_path(@project.namespace, @project, branch.name), class: 'btn btn-grouped btn-sm btn-remove remove-row', method: :delete, data: { confirm: 'Removed branch cannot be restored. Are you sure?'}, remote: true do
%i.fa.fa-trash-o
- if commit
diff --git a/app/views/projects/deploy_keys/_deploy_key.html.haml b/app/views/projects/deploy_keys/_deploy_key.html.haml
index 230e164f24..a2faa9d5e2 100644
--- a/app/views/projects/deploy_keys/_deploy_key.html.haml
+++ b/app/views/projects/deploy_keys/_deploy_key.html.haml
@@ -1,16 +1,16 @@
%li
.pull-right
- if @available_keys.include?(deploy_key)
- = link_to enable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-small', method: :put do
+ = link_to enable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-sm', method: :put do
%i.fa.fa-plus
Enable
- else
- if deploy_key.projects.count > 1
- = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-small', method: :put do
+ = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-sm', method: :put do
%i.fa.fa-power-off
Disable
- else
- = link_to 'Remove', namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :delete, class: "btn btn-remove delete-key btn-small pull-right"
+ = link_to 'Remove', namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :delete, class: "btn btn-remove delete-key btn-sm pull-right"
- key_project = deploy_key.projects.include?(@project) ? @project : deploy_key.projects.first
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 2569e91ccf..36d98b2671 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -27,7 +27,7 @@
= check_box_tag nil, 1, false, class: 'js-toggle-diff-line-wrap'
Wrap text
- = link_to '#', class: 'js-toggle-diff-comments btn btn-small' do
+ = link_to '#', class: 'js-toggle-diff-comments btn btn-sm' do
%i.fa.fa-chevron-down
Show/Hide comments
diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml
index 9b5eb84a86..d387ec2f75 100644
--- a/app/views/projects/diffs/_stats.html.haml
+++ b/app/views/projects/diffs/_stats.html.haml
@@ -9,7 +9,7 @@
and
%strong.cred #{@commit.stats.deletions} deletions
- = link_to '#', class: 'btn btn-small js-toggle-button' do
+ = link_to '#', class: 'btn btn-sm js-toggle-button' do
Show diff stats
%i.fa.fa-chevron-down
.file-stats.js-toggle-content.hide
diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml
index af1f342afb..47abbba2eb 100644
--- a/app/views/projects/diffs/_warning.html.haml
+++ b/app/views/projects/diffs/_warning.html.haml
@@ -3,15 +3,15 @@
Too many changes.
.pull-right
- unless diff_hard_limit_enabled?
- = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true)), class: "btn btn-small btn-warning"
+ = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true)), class: "btn btn-sm btn-warning"
- if current_controller?(:commit) or current_controller?(:merge_requests)
- if current_controller?(:commit)
- = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-warning btn-small"
- = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-warning btn-small"
+ = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-warning btn-sm"
+ = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-warning btn-sm"
- elsif @merge_request && @merge_request.persisted?
- = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-warning btn-small"
- = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-warning btn-small"
+ = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-warning btn-sm"
+ = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-warning btn-sm"
%p
To preserve performance only
%strong #{allowed_diff_size} of #{diffs.size}
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index bf66022975..f6de698256 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -107,7 +107,7 @@
You can change your project avatar here
- else
You can upload a project avatar here
- %a.choose-btn.btn.btn-small.js-choose-project-avatar-button
+ %a.choose-btn.btn.btn-sm.js-choose-project-avatar-button
%i.icon-paper-clip
%span Choose File ...
@@ -116,7 +116,7 @@
.light The maximum file size allowed is 200KB.
- if @project.avatar?
%hr
- = link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
+ = link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
.form-actions
= f.submit 'Save changes', class: "btn btn-save"
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index e70cf5c388..bbaddba31b 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -58,8 +58,8 @@
- @hooks.each do |hook|
%li
.pull-right
- = link_to 'Test Hook', test_namespace_project_hook_path(@project.namespace, @project, hook), class: "btn btn-small btn-grouped"
- = link_to 'Remove', namespace_project_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-small btn-grouped"
+ = link_to 'Test Hook', test_namespace_project_hook_path(@project.namespace, @project, hook), class: "btn btn-sm btn-grouped"
+ = link_to 'Remove', namespace_project_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
.clearfix
%span.monospace= hook.url
%p
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 01e2133e28..3b50ce0135 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -41,10 +41,10 @@
.issue-actions
- if can? current_user, :modify_issue, issue
- if issue.closed?
- = link_to 'Reopen', issue_path(issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small btn-grouped reopen_issue btn-reopen", remote: true
+ = link_to 'Reopen', issue_path(issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-sm btn-grouped reopen_issue btn-reopen", remote: true
- else
- = link_to 'Close', issue_path(issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small btn-grouped close_issue btn-close", remote: true
- = link_to edit_namespace_project_issue_path(issue.project.namespace, issue.project, issue), class: "btn btn-small edit-issue-link btn-grouped" do
+ = link_to 'Close', issue_path(issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-sm btn-grouped close_issue btn-close", remote: true
+ = link_to edit_namespace_project_issue_path(issue.project.namespace, issue.project, issue), class: "btn btn-sm edit-issue-link btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index cbbcb1d06c..2cb94d10b6 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -6,14 +6,7 @@
= link_to namespace_project_issues_path(@project.namespace, @project, :atom, { private_token: current_user.private_token }), class: 'btn append-right-10' do
%i.fa.fa-rss
- = form_tag namespace_project_issues_path(@project.namespace, @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']
+ = render 'shared/issuable_search_form', path: namespace_project_issues_path(@project.namespace, @project)
- if can? current_user, :write_issue, @project
= link_to new_namespace_project_issue_path(@project.namespace, @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
diff --git a/app/views/projects/merge_requests/_merge_requests.html.haml b/app/views/projects/merge_requests/_merge_requests.html.haml
new file mode 100644
index 0000000000..b8a0ca9a42
--- /dev/null
+++ b/app/views/projects/merge_requests/_merge_requests.html.haml
@@ -0,0 +1,13 @@
+.panel.panel-default
+ %ul.well-list.mr-list
+ = render @merge_requests
+ - if @merge_requests.blank?
+ %li
+ .nothing-here-block No merge requests to show
+
+- if @merge_requests.present?
+ .pull-right
+ %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
+
+ = paginate @merge_requests, theme: "gitlab"
+
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index e3b9a28033..d7992bdd19 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -1,22 +1,11 @@
+.append-bottom-10
+ .pull-right
+ = render 'shared/issuable_search_form', path: namespace_project_merge_requests_path(@project.namespace, @project)
+
+ - if can? current_user, :write_merge_request, @project
+ = link_to new_namespace_project_merge_request_path(@project.namespace, @project), class: "btn btn-new pull-left", title: "New Merge Request" do
+ %i.fa.fa-plus
+ New Merge Request
+ = render 'shared/issuable_filter'
.merge-requests-holder
- .append-bottom-10
- .pull-right
- - if can? current_user, :write_merge_request, @project
- = link_to new_namespace_project_merge_request_path(@project.namespace, @project), class: "btn btn-new pull-left", title: "New Merge Request" do
- %i.fa.fa-plus
- New Merge Request
- = render 'shared/issuable_filter'
- .panel.panel-default
- %ul.well-list.mr-list
- = render @merge_requests
- - if @merge_requests.blank?
- %li
- .nothing-here-block No merge requests to show
- - if @merge_requests.present?
- .pull-right
- %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
-
- = paginate @merge_requests, theme: "gitlab"
-
-:javascript
- $(merge_requestsPage);
+ = render 'merge_requests'
diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml
index c8a1bffb4d..ae15eb902c 100644
--- a/app/views/projects/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -35,7 +35,7 @@
text: @merge_request.merge_commit_message,
rows: 14, hint: true
- %hr
+ %br
.light
If you still want to merge this request manually - use
%strong
diff --git a/app/views/projects/merge_requests/show/_remove_source_branch.html.haml b/app/views/projects/merge_requests/show/_remove_source_branch.html.haml
index 0a642b7e6d..59cb85edfc 100644
--- a/app/views/projects/merge_requests/show/_remove_source_branch.html.haml
+++ b/app/views/projects/merge_requests/show/_remove_source_branch.html.haml
@@ -4,7 +4,7 @@
- elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && @merge_request.merged?
.remove_source_branch_widget
%p Changes merged into #{@merge_request.target_branch}. You can remove source branch now
- = link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @source_branch), remote: true, method: :delete, class: "btn btn-primary btn-small remove_source_branch" do
+ = link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @source_branch), remote: true, method: :delete, class: "btn btn-primary btn-sm remove_source_branch" do
%i.fa.fa-times
Remove Source Branch
diff --git a/app/views/projects/milestones/_milestone.html.haml b/app/views/projects/milestones/_milestone.html.haml
index dcf56541db..7039c85bb2 100644
--- a/app/views/projects/milestones/_milestone.html.haml
+++ b/app/views/projects/milestones/_milestone.html.haml
@@ -1,10 +1,10 @@
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone) }
.pull-right
- if can?(current_user, :admin_milestone, milestone.project) and milestone.active?
- = link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-small edit-milestone-link btn-grouped" do
+ = link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-sm edit-milestone-link btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
- = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-close"
+ = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-sm btn-close"
%h4
= link_to_gfm truncate(milestone.title, length: 100), namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
- if milestone.expired? and not milestone.closed?
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 00b912742b..7fc612c0c7 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -40,52 +40,45 @@
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"}
+
.project-import.form-group
- .col-sm-2
+ %label.control-label Import projects from
.col-sm-10
- if github_import_enabled?
- = link_to status_import_github_path do
+ = link_to status_import_github_path, class: 'btn' do
%i.fa.fa-github
- Import projects from GitHub
+ GitHub
- else
- = link_to '#', class: 'how_to_import_link light' do
+ = link_to '#', class: 'how_to_import_link light btn' do
%i.fa.fa-github
- Import projects from GitHub
+ GitHub
= render 'github_import_modal'
- .project-import.form-group
- .col-sm-2
- .col-sm-10
+
- if bitbucket_import_enabled?
- = link_to status_import_bitbucket_path do
+ = link_to status_import_bitbucket_path, class: 'btn' do
%i.fa.fa-bitbucket
- Import projects from Bitbucket
+ Bitbucket
- else
- = link_to '#', class: 'how_to_import_link light' do
+ = link_to '#', class: 'how_to_import_link light btn' do
%i.fa.fa-bitbucket
- Import projects from Bitbucket
+ Bitbucket
= render 'bitbucket_import_modal'
- - unless request.host == 'gitlab.com'
- .project-import.form-group
- .col-sm-2
- .col-sm-10
+ - unless request.host == 'gitlab.com'
- if gitlab_import_enabled?
- = link_to status_import_gitlab_path do
+ = link_to status_import_gitlab_path, class: 'btn' do
%i.fa.fa-heart
- Import projects from GitLab.com
+ GitLab.com
- else
- = link_to '#', class: 'how_to_import_link light' do
+ = link_to '#', class: 'how_to_import_link light btn' do
%i.fa.fa-heart
- Import projects from GitLab.com
+ GitLab.com
= render 'gitlab_import_modal'
- .project-import.form-group
- .col-sm-2
- .col-sm-10
- = link_to new_import_gitorious_path do
+ = link_to new_import_gitorious_path, class: 'btn' do
%i.icon-gitorious.icon-gitorious-small
- Import projects from Gitorious.org
+ Gitorious.org
%hr.prepend-botton-10
@@ -104,7 +97,7 @@
.pull-right
.light
Need a group for several dependent projects?
- = link_to new_group_path, class: "btn btn-tiny" do
+ = link_to new_group_path, class: "btn btn-xs" do
Create a group
.save-project-loader.hide
diff --git a/app/views/projects/project_members/_group_members.html.haml b/app/views/projects/project_members/_group_members.html.haml
new file mode 100644
index 0000000000..43e92437cf
--- /dev/null
+++ b/app/views/projects/project_members/_group_members.html.haml
@@ -0,0 +1,16 @@
+.panel.panel-default
+ .panel-heading
+ %strong #{@group.name}
+ group members
+ %small
+ (#{members.count})
+ .panel-head-actions
+ = link_to group_group_members_path(@group), class: 'btn btn-sm' do
+ %i.fa.fa-pencil-square-o
+ Edit group members
+ %ul.well-list
+ - members.each do |member|
+ = render 'groups/group_members/group_member', member: member, show_controls: false
+ - if members.count > 20
+ %li
+ and #{members.count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(@group)}
diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml
new file mode 100644
index 0000000000..0f824bdabf
--- /dev/null
+++ b/app/views/projects/project_members/_new_project_member.html.haml
@@ -0,0 +1,15 @@
+= form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project), html: { class: 'form-horizontal users-project-form' } do |f|
+ .form-group
+ = f.label :user_ids, "People", class: 'control-label'
+ .col-sm-10= users_select_tag(:user_ids, multiple: true, class: 'input-large')
+
+ .form-group
+ = f.label :access_level, "Project Access", class: 'control-label'
+ .col-sm-10
+ = select_tag :access_level, options_for_select(ProjectMember.access_roles, @project_member.access_level), class: "project-access-select select2"
+ .help-block
+ Read more about role permissions
+ %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
+
+ .form-actions
+ = f.submit 'Add users to project', class: "btn btn-create"
diff --git a/app/views/projects/project_members/_project_member.html.haml b/app/views/projects/project_members/_project_member.html.haml
new file mode 100644
index 0000000000..1f31d84dd1
--- /dev/null
+++ b/app/views/projects/project_members/_project_member.html.haml
@@ -0,0 +1,35 @@
+- user = member.user
+- return unless user
+
+%li{class: "#{dom_class(member)} js-toggle-container project_member_row access-#{member.human_access.downcase}", id: dom_id(member)}
+ %span.list-item-name
+ = image_tag avatar_icon(user.email, 16), class: "avatar s16"
+ %strong= user.name
+ %span.cgray= user.username
+ - if user == current_user
+ %span.label.label-success It's you
+ - if user.blocked?
+ %label.label.label-danger
+ %strong Blocked
+
+ - if current_user_can_admin_project
+ - unless @project.personal? && user == current_user
+ .pull-right
+ %strong= member.human_access
+ = button_tag class: "btn-xs btn js-toggle-button",
+ title: 'Edit access level', type: 'button' do
+ %i.fa.fa-pencil-square-o
+
+
+ - if current_user == user
+ = link_to leave_namespace_project_project_members_path(@project.namespace, @project), data: { confirm: "Leave project?"}, method: :delete, class: "btn-xs btn btn-remove", title: 'Leave project' do
+ %i.fa.fa-minus.fa-inverse
+ - else
+ = link_to namespace_project_project_member_path(@project.namespace, @project, user), data: { confirm: remove_from_project_team_message(@project, user) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from team' do
+ %i.fa.fa-minus.fa-inverse
+
+ .edit-member.hide.js-toggle-content
+ = form_for member, as: :project_member, url: namespace_project_project_member_path(@project.namespace, @project, member.user), remote: true do |f|
+ .alert.prepend-top-20
+ = f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level)
+ = f.submit 'Save', class: 'btn btn-save btn-sm'
diff --git a/app/views/projects/team_members/_shared_group_members.html.haml b/app/views/projects/project_members/_shared_group_members.html.haml
similarity index 100%
rename from app/views/projects/team_members/_shared_group_members.html.haml
rename to app/views/projects/project_members/_shared_group_members.html.haml
diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml
new file mode 100644
index 0000000000..615c425e59
--- /dev/null
+++ b/app/views/projects/project_members/_team.html.haml
@@ -0,0 +1,11 @@
+- can_admin_project = can?(current_user, :admin_project, @project)
+
+.panel.panel-default.prepend-top-20
+ .panel-heading
+ %strong #{@project.name}
+ project members
+ %small
+ (#{members.count})
+ %ul.well-list
+ - members.each do |project_member|
+ = render 'project_member', member: project_member, current_user_can_admin_project: can_admin_project
diff --git a/app/views/projects/team_members/import.html.haml b/app/views/projects/project_members/import.html.haml
similarity index 66%
rename from app/views/projects/team_members/import.html.haml
rename to app/views/projects/project_members/import.html.haml
index 9e31d47117..293754cd0c 100644
--- a/app/views/projects/team_members/import.html.haml
+++ b/app/views/projects/project_members/import.html.haml
@@ -3,12 +3,12 @@
%p.light
Only project members will be imported. Group members will be skipped.
%hr
-= form_tag apply_import_namespace_project_team_members_path(@project.namespace, @project), method: 'post', class: 'form-horizontal' do
+= form_tag apply_import_namespace_project_project_members_path(@project.namespace, @project), method: 'post', class: 'form-horizontal' do
.form-group
= label_tag :source_project_id, "Project", class: 'control-label'
.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
= button_tag 'Import project members', class: "btn btn-create"
- = link_to "Cancel", namespace_project_team_index_path(@project.namespace, @project), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-cancel"
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
new file mode 100644
index 0000000000..36a6f6a155
--- /dev/null
+++ b/app/views/projects/project_members/index.html.haml
@@ -0,0 +1,35 @@
+%h3.page-title
+ Users with access to this project
+
+%p.light
+ Read more about project permissions
+ %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
+
+%hr
+
+.clearfix.js-toggle-container
+ = form_tag namespace_project_project_members_path(@project.namespace, @project), 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' }
+ = button_tag 'Search', class: 'btn'
+
+ - if can?(current_user, :admin_project_member, @project)
+ %span.pull-right
+ = button_tag class: 'btn btn-new btn-grouped js-toggle-button', type: 'button' do
+ Add members
+ %i.fa.fa-chevron-down
+ = link_to import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-grouped", title: "Import members from another project" do
+ Import members
+
+ .js-toggle-content.hide.new-group-member-holder
+ = render "new_project_member"
+
+= render "team", members: @project_members
+
+- if @group
+ = render "group_members", members: @group_members
+
+:coffeescript
+ $('form.member-search-form').on 'submit', (event) ->
+ event.preventDefault()
+ Turbolinks.visit @.action + '?' + $(@).serialize()
diff --git a/app/views/projects/project_members/update.js.haml b/app/views/projects/project_members/update.js.haml
new file mode 100644
index 0000000000..811b185882
--- /dev/null
+++ b/app/views/projects/project_members/update.js.haml
@@ -0,0 +1,3 @@
+- can_admin_project = can?(current_user, :admin_project, @project)
+:plain
+ $("##{dom_id(@project_member)}").replaceWith('#{escape_javascript(render("project_member", member: @project_member, current_user_can_admin_project: can_admin_project))}');
diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml
index 5406b80dc1..bb49f4de87 100644
--- a/app/views/projects/protected_branches/_branches_list.html.haml
+++ b/app/views/projects/protected_branches/_branches_list.html.haml
@@ -31,4 +31,4 @@
%td
.pull-right
- if can? current_user, :admin_project, @project
- = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-small"
+ = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm"
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index 345848fa6d..d19689a105 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -23,15 +23,15 @@
.file-holder
.file-title
%i.fa.fa-file
- %span.file_name
+ %strong
= @snippet.file_name
- .options
+ .file-actions
.btn-group
- if can?(current_user, :modify_project_snippet, @snippet)
- = link_to "edit", edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-small", title: 'Edit Snippet'
- = link_to "raw", raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-small", target: "_blank"
+ = link_to "edit", edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", title: 'Edit Snippet'
+ = link_to "raw", raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
- if can?(current_user, :admin_project_snippet, @snippet)
- = link_to "remove", namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-small btn-remove", title: 'Delete Snippet'
+ = link_to "remove", namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-sm btn-remove", title: 'Delete Snippet'
= render 'shared/snippets/blob'
%div#notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
index 8da07222cb..f22308e54b 100644
--- a/app/views/projects/tags/_tag.html.haml
+++ b/app/views/projects/tags/_tag.html.haml
@@ -9,9 +9,9 @@
= 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'
+ = render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-sm'
- if can?(current_user, :admin_project, @project)
- = link_to namespace_project_tag_path(@project.namespace, @project, tag.name), class: 'btn btn-small btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do
+ = link_to namespace_project_tag_path(@project.namespace, @project, tag.name), class: 'btn btn-sm btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do
%i.fa.fa-trash-o
- if commit
diff --git a/app/views/projects/team_members/_form.html.haml b/app/views/projects/team_members/_form.html.haml
deleted file mode 100644
index f1ae2b5f23..0000000000
--- a/app/views/projects/team_members/_form.html.haml
+++ /dev/null
@@ -1,29 +0,0 @@
-%h3.page-title
- New project member(s)
-
-= form_for @user_project_relation, as: :project_member, url: namespace_project_team_members_path(@project.namespace, @project), html: { class: "form-horizontal users-project-form" } do |f|
- -if @user_project_relation.errors.any?
- .alert.alert-danger
- %ul
- - @user_project_relation.errors.full_messages.each do |msg|
- %li= msg
-
- %p 1. Choose people you want in the project
- .form-group
- = f.label :user_ids, "People", class: 'control-label'
- .col-sm-10
- = users_select_tag(:user_ids, { multiple: true })
-
- %p 2. Set access level for them
- .form-group
- = f.label :access_level, "Project Access", class: 'control-label'
- .col-sm-10
- = select_tag :access_level, options_for_select(Gitlab::Access.options, @user_project_relation.access_level), class: "project-access-select select2"
- .help-block
- Read more about role permissions
- %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
-
-
- .form-actions
- = f.submit 'Add users', class: "btn btn-create"
- = link_to "Cancel", namespace_project_team_index_path(@project.namespace, @project), class: "btn btn-cancel"
diff --git a/app/views/projects/team_members/_group_members.html.haml b/app/views/projects/team_members/_group_members.html.haml
deleted file mode 100644
index df3c914fde..0000000000
--- a/app/views/projects/team_members/_group_members.html.haml
+++ /dev/null
@@ -1,14 +0,0 @@
-- group_users_count = @group.group_members.count
-.panel.panel-default
- .panel-heading
- %strong #{@group.name}
- group members (#{group_users_count})
- .pull-right
- = link_to members_group_path(@group), class: 'btn btn-small' do
- %i.fa.fa-pencil-square-o
- %ul.well-list
- - @group.group_members.order('access_level DESC').limit(20).each do |member|
- = render 'groups/group_members/group_member', member: member, show_controls: false
- - if group_users_count > 20
- %li
- and #{group_users_count - 20} more. For full list visit #{link_to 'group members page', members_group_path(@group)}
diff --git a/app/views/projects/team_members/_team.html.haml b/app/views/projects/team_members/_team.html.haml
deleted file mode 100644
index 0e5b817613..0000000000
--- a/app/views/projects/team_members/_team.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
-.team-table
- - can_admin_project = (can? current_user, :admin_project, @project)
- .panel.panel-default
- .panel-heading
- %strong #{@project.name}
- project members (#{members.count})
- %ul.well-list
- - members.each do |team_member|
- = render 'team_member', member: team_member, current_user_can_admin_project: can_admin_project
diff --git a/app/views/projects/team_members/_team_member.html.haml b/app/views/projects/team_members/_team_member.html.haml
deleted file mode 100644
index eb81544740..0000000000
--- a/app/views/projects/team_members/_team_member.html.haml
+++ /dev/null
@@ -1,18 +0,0 @@
-- user = member.user
-%li{id: dom_id(user), class: "team_member_row access-#{member.human_access.downcase}"}
- .pull-right
- - if current_user_can_admin_project
- - unless @project.personal? && user == current_user
- .pull-left
- = form_for(member, as: :project_member, url: namespace_project_team_member_path(@project.namespace, @project, member.user)) do |f|
- = f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level), {}, class: "trigger-submit"
-
- = link_to namespace_project_team_member_path(@project.namespace, @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
- = image_tag avatar_icon(user.email, 32), class: "avatar s32"
- %p
- %strong= user.name
- - if user.blocked?
- %label.label.label-danger
- %strong Blocked
- %span.cgray= user.username
diff --git a/app/views/projects/team_members/index.html.haml b/app/views/projects/team_members/index.html.haml
deleted file mode 100644
index 0cbba021b9..0000000000
--- a/app/views/projects/team_members/index.html.haml
+++ /dev/null
@@ -1,22 +0,0 @@
-%h3.page-title
- Users with access to this project
-
- - if !membership_locked? && can?(current_user, :admin_team_member, @project)
- %span.pull-right
- = link_to new_namespace_project_team_member_path(@project.namespace, @project), class: "btn btn-new btn-grouped", title: "New project member" do
- New project member
- = link_to import_namespace_project_team_members_path(@project.namespace, @project), class: "btn btn-grouped", title: "Import members from another project" do
- Import members
-
-%p.light
- Read more about project permissions
- %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
- - if membership_locked?
- %span.pull-right
- Adding new users is disabled at group level
-
-= render "team", members: @project_members
-- if @group
- = render "group_members"
-- if @project_group_links.any?
- = render "shared_group_members"
diff --git a/app/views/projects/team_members/new.html.haml b/app/views/projects/team_members/new.html.haml
deleted file mode 100644
index b1bc3ba0eb..0000000000
--- a/app/views/projects/team_members/new.html.haml
+++ /dev/null
@@ -1 +0,0 @@
-= render "form"
diff --git a/app/views/projects/team_members/update.js.haml b/app/views/projects/team_members/update.js.haml
deleted file mode 100644
index c68fe9574a..0000000000
--- a/app/views/projects/team_members/update.js.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- if @user_project_relation.valid?
- :plain
- $("##{dom_id(@user_project_relation)}").effect("highlight", {color: "#529214"}, 1000);;
-- else
- :plain
- $("##{dom_id(@user_project_relation)}").effect("highlight", {color: "#D12F19"}, 1000);;
diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml
index fc4616da6e..feca145369 100644
--- a/app/views/projects/tree/show.html.haml
+++ b/app/views/projects/tree/show.html.haml
@@ -3,7 +3,7 @@
- if can? current_user, :download_code, @project
.tree-download-holder
- = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group-small pull-right hidden-xs hidden-sm', split_button: true
+ = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group-sm pull-right hidden-xs hidden-sm', split_button: true
#tree-holder.tree-holder.clearfix
= render "tree", tree: @tree
diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml
index 5567f1af22..566850cb78 100644
--- a/app/views/projects/wikis/edit.html.haml
+++ b/app/views/projects/wikis/edit.html.haml
@@ -9,5 +9,5 @@
.pull-right
- if @page.persisted? && can?(current_user, :admin_wiki, @project)
- = link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-small btn-remove" do
+ = link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-sm btn-remove" do
Delete this page
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index c635c04fb8..ffc145497a 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -1,5 +1,5 @@
.dropdown.inline
- %button.dropdown-toggle.btn.btn-small{type: 'button', 'data-toggle' => 'dropdown'}
+ %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
%i.fa.fa-tags
%span.light Group:
- if @group.present?
@@ -17,7 +17,7 @@
= group.name
.dropdown.inline.prepend-left-10.project-filter
- %button.dropdown-toggle.btn.btn-small{type: 'button', 'data-toggle' => 'dropdown'}
+ %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
%i.fa.fa-tags
%span.light Project:
- if @project.present?
diff --git a/app/views/search/results/_snippet_blob.html.haml b/app/views/search/results/_snippet_blob.html.haml
index 6fc2cdf636..8af393777f 100644
--- a/app/views/search/results/_snippet_blob.html.haml
+++ b/app/views/search/results/_snippet_blob.html.haml
@@ -13,12 +13,6 @@
.file-title
%i.fa.fa-file
%strong= snippet_blob[:snippet_object].file_name
- %span.options
- .btn-group.tree-btn-group.pull-right
- - if snippet_blob[:snippet_object].author == current_user
- = link_to "Edit", edit_snippet_path(snippet_blob[:snippet_object]), class: "btn btn-tiny", title: 'Edit Snippet'
- = link_to "Delete", snippet_path(snippet_blob[:snippet_object]), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-tiny", title: 'Delete Snippet'
- = link_to "Raw", raw_snippet_path(snippet_blob[:snippet_object]), class: "btn btn-tiny", target: "_blank"
- if gitlab_markdown?(snippet_blob[:snippet_object].file_name)
.file-content.wiki
- snippet_blob[:snippet_chunks].each do |snippet|
diff --git a/app/views/shared/_choose_group_avatar_button.html.haml b/app/views/shared/_choose_group_avatar_button.html.haml
index 299c0bd42a..000532b1c9 100644
--- a/app/views/shared/_choose_group_avatar_button.html.haml
+++ b/app/views/shared/_choose_group_avatar_button.html.haml
@@ -1,4 +1,4 @@
-%a.choose-btn.btn.btn-small.js-choose-group-avatar-button
+%a.choose-btn.btn.btn-sm.js-choose-group-avatar-button
%i.fa.fa-paperclip
%span Choose File ...
diff --git a/app/views/shared/_issuable_search_form.html.haml b/app/views/shared/_issuable_search_form.html.haml
new file mode 100644
index 0000000000..639d203dcd
--- /dev/null
+++ b/app/views/shared/_issuable_search_form.html.haml
@@ -0,0 +1,9 @@
+= form_tag(path, 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 :author_id, params['author_id']
+ = hidden_field_tag :milestone_id, params['milestone_id']
+ = hidden_field_tag :label_id, params['label_id']
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index f5bc543de1..edfa2092df 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -31,13 +31,13 @@
.file-holder
.file-title
%i.fa.fa-file
- %span.file_name
+ %strong
= @snippet.file_name
- .options
+ .file-actions
.btn-group
- if can?(current_user, :modify_personal_snippet, @snippet)
- = link_to "edit", edit_snippet_path(@snippet), class: "btn btn-small", title: 'Edit Snippet'
- = link_to "raw", raw_snippet_path(@snippet), class: "btn btn-small", target: "_blank"
+ = link_to "edit", edit_snippet_path(@snippet), class: "btn btn-sm", title: 'Edit Snippet'
+ = link_to "raw", raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
- if can?(current_user, :admin_personal_snippet, @snippet)
- = link_to "remove", snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-small btn-remove", title: 'Delete Snippet'
+ = link_to "remove", snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-sm btn-remove", title: 'Delete Snippet'
= render 'shared/snippets/blob'
diff --git a/app/views/snippets/user_index.html.haml b/app/views/snippets/user_index.html.haml
index 67f3a68aa2..df524cd18b 100644
--- a/app/views/snippets/user_index.html.haml
+++ b/app/views/snippets/user_index.html.haml
@@ -5,7 +5,7 @@
\/
Snippets
- if current_user
- = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do
+ = link_to new_snippet_path, class: "btn btn-sm add_new pull-right", title: "New Snippet" do
Add new snippet
%hr
diff --git a/app/views/users/_groups.html.haml b/app/views/users/_groups.html.haml
index cb84570a6d..f360fbb3d5 100644
--- a/app/views/users/_groups.html.haml
+++ b/app/views/users/_groups.html.haml
@@ -1,4 +1,4 @@
.clearfix
- groups.each do |group|
= link_to group, class: 'profile-groups-avatars inline', title: group.name do
- = image_tag group_icon(group.path), class: 'avatar group-avatar s40'
+ = image_tag group_icon(group), class: 'avatar group-avatar s40'
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index ecc6c8e53a..0c3ee6ba4f 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -21,7 +21,9 @@ class PostReceive
return false
end
- changes = changes.lines if changes.kind_of?(String)
+ changes = Base64.decode64(changes) unless changes.include?(" ")
+ changes = utf8_encode_changes(changes)
+ changes = changes.lines
changes.each do |change|
oldrev, newrev, ref = change.strip.split(' ')
@@ -41,6 +43,19 @@ class PostReceive
end
end
+ def utf8_encode_changes(changes)
+ changes = changes.dup
+
+ changes.force_encoding("UTF-8")
+ return changes if changes.valid_encoding?
+
+ # Convert non-UTF-8 branch/tag names to UTF-8 so they can be dumped as JSON.
+ detection = CharlockHolmes::EncodingDetector.detect(changes)
+ return changes unless detection && detection[:encoding]
+
+ CharlockHolmes::Converter.convert(changes, detection[:encoding], 'UTF-8')
+ end
+
def log(message)
Gitlab::GitLogger.error("POST-RECEIVE: #{message}")
end
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 2806239d4c..ea39b7083a 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -57,10 +57,6 @@ production: &base
## COLOR = 5
# default_theme: 2 # default: 2
- # Restrict setting visibility levels for non-admin users.
- # The default is to allow all levels.
- # restricted_visibility_levels: [ "public" ]
-
## Automatic issue closing
# If a commit message matches this regular expression, all issues referenced from the matched text will be closed.
# This happens when the commit is pushed or merged into the default branch of a project.
diff --git a/config/routes.rb b/config/routes.rb
index 511b981f7e..9e3e687b03 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -142,7 +142,7 @@ Gitlab::Application.routes.draw do
resources :groups, constraints: { id: /[^\/]+/ } do
member do
- put :project_teams_update
+ put :members_update
end
end
@@ -230,11 +230,7 @@ Gitlab::Application.routes.draw do
scope module: :dashboard do
resources :milestones, only: [:index, :show]
- resources :groups, only: [:index] do
- member do
- delete :leave
- end
- end
+ resources :groups, only: [:index]
resources :projects, only: [] do
collection do
@@ -251,7 +247,6 @@ Gitlab::Application.routes.draw do
member do
get :issues
get :merge_requests
- get :members
get :projects
end
@@ -261,11 +256,12 @@ Gitlab::Application.routes.draw do
put :reset_access
end
end
- end
- scope module: :groups do
resources :ldap_group_links, only: [:index, :create, :destroy]
- resources :group_members, only: [:create, :update, :destroy]
+ resources :group_members, only: [:index, :create, :update, :destroy] do
+ delete :leave, on: :collection
+ end
+
resource :avatar, only: [:destroy]
resources :milestones, only: [:index, :show, :update]
end
@@ -459,7 +455,6 @@ Gitlab::Application.routes.draw do
end
end
- resources :team, controller: 'team_members', only: [:index]
resources :milestones, except: [:destroy], constraints: { id: /\d+/ } do
member do
put :sort_issues
@@ -479,7 +474,7 @@ Gitlab::Application.routes.draw do
end
end
- resources :team_members, except: [:index, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ } do
+ resources :project_members, except: [:new, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ } do
collection do
delete :leave
diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example
index 29253b71f4..3aee718097 100644
--- a/config/unicorn.rb.example
+++ b/config/unicorn.rb.example
@@ -16,7 +16,7 @@
# Read about unicorn workers here:
# http://doc.gitlab.com/ee/install/requirements.html#unicorn-workers
#
-worker_processes 2
+worker_processes 3
# Since Unicorn is never exposed to outside clients, it does not need to
# run on the standard HTTP port (80), there is no reason to start Unicorn
diff --git a/db/migrate/20150301014758_add_restricted_visibility_levels_to_application_settings.rb b/db/migrate/20150301014758_add_restricted_visibility_levels_to_application_settings.rb
new file mode 100644
index 0000000000..494c3033bf
--- /dev/null
+++ b/db/migrate/20150301014758_add_restricted_visibility_levels_to_application_settings.rb
@@ -0,0 +1,5 @@
+class AddRestrictedVisibilityLevelsToApplicationSettings < ActiveRecord::Migration
+ def change
+ add_column :application_settings, :restricted_visibility_levels, :text
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 72f0139f34..11204b4f65 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -36,9 +36,10 @@ ActiveRecord::Schema.define(version: 20150312000132) do
t.datetime "created_at"
t.datetime "updated_at"
t.string "home_page_url"
- t.integer "default_branch_protection", default: 2
- t.boolean "twitter_sharing_enabled", default: true
+ t.integer "default_branch_protection", default: 2
+ t.boolean "twitter_sharing_enabled", default: true
t.text "help_text"
+ t.text "restricted_visibility_levels"
end
create_table "audit_events", force: true do |t|
diff --git a/doc/install/installation.md b/doc/install/installation.md
index eb0b2c2359..12cbd771c0 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -56,7 +56,7 @@ up-to-date and install it.
Install the required packages (needed to compile Ruby and native extensions to Ruby gems):
- sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake libkrb5-dev
+ sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake libkrb5-dev nodejs
Make sure you have the right version of Git installed
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 5bdb9caa2b..f42af65796 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -76,15 +76,18 @@ Notice: The 25 workers of Sidekiq will show up as separate processes in your pro
## Unicorn Workers
-It's possible to increase the amount of unicorn workers and tis will usually help for to reduce the response time of the applications.
+It's possible to increase the amount of unicorn workers and tis will usually help for to reduce the response time of the applications and increase the ability to handle parallel requests.
+
For most instances we recommend using: CPU cores + 1 = unicorn workers.
So for a machine with 2 cores, 3 unicorn workers is ideal.
-For all machines that have 1GB and up we recommend a minimum of two unicorn workers.
+For all machines that have 1GB and up we recommend a minimum of three unicorn workers.
If you have a 512MB machine with a magnetic (non-SSD) swap drive we recommend to configure only one Unicorn worker to prevent excessive swapping.
With one Unicorn worker only git over ssh access will work because the git over HTTP access requires two running workers (one worker to receive the user request and one worker for the authorization check).
If you have a 512MB machine with a SSD drive you can use two Unicorn workers, this will allow HTTP access although it will be slow due to swapping.
+To change the Unicorn workers when you have the Omnibus package please see [the Unicorn settings in the Omnibus GitLab documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/unicorn.md#unicorn-settings).
+
## Database
If you want to run the database separately, the **recommended** database size is **1 MB per user**.
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index 1096ea9656..64f28d4645 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -140,25 +140,25 @@ But let's throw in a tag.
## Emoji
- Sometimes you want to be a :ninja: and add some :glowing_star: to your :speech_balloon:. Well we have a gift for you:
+ Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
- :high_voltage_sign: You can use emoji anywhere GFM is supported. :victory_hand:
+ :zap: You can use emoji anywhere GFM is supported. :v:
- You can use it to point out a :bug: or warn about :speak_no_evil_monkey: patches. And if someone improves your really :snail: code, send them some :cake:. People will :heart: you for that.
+ You can use it to point out a :bug: or warn about :speak_no_evil: patches. And if someone improves your really :snail: code, send them some :birthday:. People will :heart: you for that.
- If you are new to this, don't be :fearful_face:. You can easily join the emoji :family:. All you need to do is to look up on the supported codes.
+ If you are new to this, don't be :fearful:. You can easily join the emoji :family:. All you need to do is to look up on the supported codes.
- Consult the [Emoji Cheat Sheet](https://s3.amazonaws.com/emoji-cheatsheet/cheat_sheet.pdf) for a list of all supported emoji codes. :thumbsup:
+ Consult the [Emoji Cheat Sheet](http://emoji.codes) for a list of all supported emoji codes. :thumbsup:
-Sometimes you want to be a :ninja: and add some :glowing_star: to your :speech_balloon:. Well we have a gift for you:
+Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
-:high_voltage_sign: You can use emoji anywhere GFM is supported. :victory_hand:
+:zap: You can use emoji anywhere GFM is supported. :v:
-You can use it to point out a :bug: or warn about :speak_no_evil_monkey: patches. And if someone improves your really :snail: code, send them some :cake:. People will :heart: you for that.
+You can use it to point out a :bug: or warn about :speak_no_evil: patches. And if someone improves your really :snail: code, send them some :birthday:. People will :heart: you for that.
-If you are new to this, don't be :fearful_face:. You can easily join the emoji :family:. All you need to do is to look up on the supported codes.
+If you are new to this, don't be :fearful:. You can easily join the emoji :family:. All you need to do is to look up on the supported codes.
-Consult the [Emoji Cheat Sheet](https://s3.amazonaws.com/emoji-cheatsheet/cheat_sheet.pdf) for a list of all supported emoji codes. :thumbsup:
+Consult the [Emoji Cheat Sheet](http://emoji.codes) for a list of all supported emoji codes. :thumbsup:
## Special GitLab References
@@ -485,6 +485,10 @@ This line is separated from the one above by two newlines, so it will be a *sepa
This line is also a separate paragraph, but...
This line is only separated by a single newline, so it's a separate line in the *same paragraph*.
+
+This line is also a separate paragraph, and...
+This line is on its own line, because the previous line ends with two
+spaces.
```
Here's a line for us to start with.
@@ -494,6 +498,10 @@ This line is separated from the one above by two newlines, so it will be a *sepa
This line is also begins a separate paragraph, but...
This line is only separated by a single newline, so it's a separate line in the *same paragraph*.
+This line is also a separate paragraph, and...
+This line is on its own line, because the previous line ends with two
+spaces.
+
## Tables
Tables aren't part of the core Markdown spec, but they are part of GFM and Markdown Here supports them.
diff --git a/doc/project_services/hipchat.md b/doc/project_services/hipchat.md
new file mode 100644
index 0000000000..021a93a288
--- /dev/null
+++ b/doc/project_services/hipchat.md
@@ -0,0 +1,54 @@
+# Atlassian HipChat
+
+GitLab provides a way to send HipChat notifications upon a number of events,
+such as when a user pushes code, creates a branch or tag, adds a comment, and
+creates a merge request.
+
+## Setup
+
+GitLab requires the use of a HipChat v2 API token to work. v1 tokens are
+not supported at this time. Note the differences between v1 and v2 tokens:
+
+HipChat v1 API (legacy) supports "API Auth Tokens" in the Group API menu. A v1
+token is allowed to send messages to *any* room.
+
+HipChat v2 API has tokens that are can be created using the Integrations tab
+in the Group or Room admin page. By design, these are lightweight tokens that
+allow GitLab to send messages only to *one* room.
+
+### Complete these steps in HipChat:
+
+1. Go to: https://admin.hipchat.com/admin
+1. Click on "Group Admin" -> "Integrations".
+1. Find "Build Your Own!" and click "Create".
+1. Select the desired room, name the integration "GitLab", and click "Create".
+1. In the "Send messages to this room by posting this URL" column, you should
+see a URL in the format:
+
+```
+ https://api.hipchat.com/v2/room//notification?auth_token=
+```
+
+HipChat is now ready to accept messages from GitLab. Next, set up the HipChat
+service in GitLab.
+
+### Complete these steps in GitLab:
+
+1. Navigate to the project you want to configure for notifications.
+1. Select "Settings" in the top navigation.
+1. Select "Services" in the left navigation.
+1. Click "HipChat".
+1. Select the "Active" checkbox.
+1. Insert the `token` field from the URL into the `Token` field on the Web page.
+1. Insert the `room` field from the URL into the `Room` field on the Web page.
+1. Save or optionally click "Test Settings".
+
+## Troubleshooting
+
+If you do not see notifications, make sure you are using a HipChat v2 API
+token, not a v1 token.
+
+Note that the v2 token is tied to a specific room. If you want to be able to
+specify arbitrary rooms, you can create an API token for a specific user in
+HipChat under "Account settings" and "API access". Use the `XXX` value under
+`auth_token=XXX`.
diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md
index 86eda341d6..03937d2072 100644
--- a/doc/project_services/project_services.md
+++ b/doc/project_services/project_services.md
@@ -12,7 +12,7 @@ __Project integrations with external services for continuous integration and mor
- Flowdock
- Gemnasium
- GitLab CI
-- HipChat
+- [HipChat](hipchat.md) An Atlassian product for private group chat and instant messaging.
- [Irker](irker.md) An IRC gateway to receive messages on repository updates.
- Pivotal Tracker
- Pushover
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index 4712c38702..7c5a6c0463 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -41,4 +41,4 @@ When visiting the public page of an user, you will only see listed projects whic
## Restricting the use of public or internal projects
-In [gitlab.yml](https://gitlab.com/gitlab-org/gitlab-ce/blob/dbd88d453b8e6c78a423fa7e692004b1db6ea069/config/gitlab.yml.example#L64) you can disable public projects or public and internal projects for the entire GitLab installation to prevent people making code public by accident.
+In [gitlab.yml](https://gitlab.com/gitlab-org/gitlab-ce/blob/dbd88d453b8e6c78a423fa7e692004b1db6ea069/config/gitlab.yml.example#L64) you can disable public projects or public and internal projects for the entire GitLab installation to prevent people making code public by accident. The restricted visibility settings do not apply to admin users.
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index ec96be27f3..cfe01896d8 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -178,6 +178,10 @@ Update [installation.md](/doc/install/installation.md) to the newest version in
Follow the [release doc in the Omnibus repository](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md).
This can happen before tagging because Omnibus uses tags in its own repo and SHA1's to refer to the GitLab codebase.
+## Update GitLab.com with the stable version
+
+- Deploy the package (should not need downtime because of the small difference with RC1)
+- Deploy the package for ci.gitlab.com
## Release CE, EE and CI
@@ -199,10 +203,10 @@ Proposed tweet "Release of GitLab X.X & CI Y.Y! FEATURE, FEATURE and FEATURE <
Consider creating a post on Hacker News.
-## Update GitLab.com with the stable version
-
-- Deploy the package (should not need downtime because of the small difference with RC1)
-
## Release new AMIs
[Follow this guide](https://dev.gitlab.org/gitlab/AMI/blob/master/README.md)
+
+## Create a WIP blogpost for the next release
+
+Create a WIP blogpost using [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md).
diff --git a/doc/update/7.8-to-7.9.md b/doc/update/7.8-to-7.9.md
new file mode 100644
index 0000000000..28fd433e1c
--- /dev/null
+++ b/doc/update/7.8-to-7.9.md
@@ -0,0 +1,120 @@
+# From 7.8 to 7.9
+
+### 0. Stop server
+
+ sudo service gitlab stop
+
+### 1. Backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 2. Get latest code
+
+```bash
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+```
+
+For GitLab Community Edition:
+
+```bash
+sudo -u git -H git checkout 7-9-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 7-9-stable-ee
+```
+
+### 3. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+sudo -u git -H git fetch
+sudo -u git -H git checkout v2.6.0
+```
+
+### 4. Install libs, migrations, etc.
+
+```bash
+sudo apt-get install nodejs
+
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without ... postgres')
+sudo -u git -H bundle install --without development test postgres --deployment
+
+# PostgreSQL installations (note: the line below states '--without ... mysql')
+sudo -u git -H bundle install --without development test mysql --deployment
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Clean up assets and cache
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+# Update init.d script
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+### 5. Update config files
+
+#### New configuration options for `gitlab.yml`
+
+There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them to your current `gitlab.yml`.
+
+```
+git diff origin/7-8-stable:config/gitlab.yml.example origin/7-9-stable:config/gitlab.yml.example
+```
+
+#### Change Nginx settings
+
+* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as [`lib/support/nginx/gitlab`](/lib/support/nginx/gitlab) but with your settings.
+* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`](/lib/support/nginx/gitlab-ssl) but with your settings.
+* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
+
+#### Setup time zone (optional)
+
+Consider setting the time zone in `gitlab.yml` otherwise GitLab will default to UTC. If you set a time zone previously in [`application.rb`](config/application.rb) (unlikely), unset it.
+
+### 6. Start application
+
+ sudo service gitlab start
+ sudo service nginx restart
+
+### 7. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+ sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check with:
+
+ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations upgrade is complete!
+
+### 8. GitHub settings (if applicable)
+
+If you are using GitHub as an OAuth provider for authentication, you should change the callback URL so that it
+only contains a root URL (ex. `https://gitlab.example.com/`)
+
+## Things went south? Revert to previous version (7.8)
+
+### 1. Revert the code to the previous version
+Follow the [upgrade guide from 7.7 to 7.8](7.7-to-7.8.md), except for the database migration
+(The backup is already migrated to the previous version)
+
+### 2. Restore from the backup:
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above.
diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md
index 4ed35b2b56..d8476fb345 100644
--- a/doc/update/upgrader.md
+++ b/doc/update/upgrader.md
@@ -24,7 +24,7 @@ If you have local changes to your GitLab repository the script will stash them a
## 2. Run GitLab upgrade tool
-Note: GitLab 7.6 adds `libkrb5-dev` as a dependency (installed by default on Ubuntu and OSX) while 7.2 adds `pkg-config` and `cmake` as dependency. Please check the dependencies in the [installation guide.](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
+Note: GitLab 7.9 adds nodejs as a dependency. GitLab 7.6 adds `libkrb5-dev` as a dependency (installed by default on Ubuntu and OSX). GitLab 7.2 adds `pkg-config` and `cmake` as dependency. Please check the dependencies in the [installation guide.](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
# Starting with GitLab version 7.0 upgrader script has been moved to bin directory
cd /home/git/gitlab
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index 3cccd84b06..851f50f5e9 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -16,6 +16,7 @@ Triggered when you push to the repository except when pushing tags.
```json
{
+ "object_kind": "push",
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"ref": "refs/heads/master",
@@ -66,6 +67,7 @@ Triggered when you create (or delete) tags to the repository.
```json
{
+ "object_kind": "tag_push",
"ref": "refs/tags/v1.0.0",
"before": "0000000000000000000000000000000000000000",
"after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7",
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index d02b8b053a..eae37a9ea6 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -223,3 +223,10 @@ Feature: Project Merge Requests
And I click link "Edit" for the merge request
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown write tab
+
+ @javascript
+ Scenario: I search merge request
+ Given I click link "All"
+ When I fill in merge request search with "Fe"
+ Then I should see "Feature NS-03" in merge requests
+ And I should not see "Bug NS-04" in merge requests
diff --git a/features/project/team_management.feature b/features/project/team_management.feature
index e8ee0f9525..9d2359a3a7 100644
--- a/features/project/team_management.feature
+++ b/features/project/team_management.feature
@@ -13,7 +13,7 @@ Feature: Project Team Management
@javascript
Scenario: Add user to project
- Given I click link "New Team Member"
+ Given I click link "Add members"
And I select "Mike" as "Reporter"
Then I should see "Mike" in team list as "Reporter"
diff --git a/features/steps/admin/groups.rb b/features/steps/admin/groups.rb
index 8d3fdc078a..c4b05f5620 100644
--- a/features/steps/admin/groups.rb
+++ b/features/steps/admin/groups.rb
@@ -38,7 +38,7 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps
When 'I select user "John Doe" from user list as "Reporter"' do
select2(user_john.id, from: "#user_ids", multiple: true)
- within "#new_team_member" do
+ within "#new_project_member" do
select "Reporter", from: "access_level"
end
click_button "Add users to group"
diff --git a/features/steps/explore/groups.rb b/features/steps/explore/groups.rb
index ccbf6cda07..0c2127d4c4 100644
--- a/features/steps/explore/groups.rb
+++ b/features/steps/explore/groups.rb
@@ -35,7 +35,7 @@ class Spinach::Features::ExploreGroups < Spinach::FeatureSteps
end
step 'I visit group "TestGroup" members page' do
- visit members_group_path(Group.find_by(name: "TestGroup"))
+ visit group_group_members_path(Group.find_by(name: "TestGroup"))
end
step 'I should not see project "Enterprise" items' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 7fff00ad2f..e3f5c38363 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -286,6 +286,10 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
end
+ step 'I fill in merge request search with "Fe"' do
+ fill_in 'issue_search', with: "Fe"
+ end
+
def merge_request
@merge_request ||= MergeRequest.find_by!(title: "Bug NS-05")
end
diff --git a/features/steps/project/team_management.rb b/features/steps/project/team_management.rb
index 6763f74ff3..aca99d3f92 100644
--- a/features/steps/project/team_management.rb
+++ b/features/steps/project/team_management.rb
@@ -15,18 +15,18 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps
page.should have_content(user.username)
end
- step 'I click link "New Team Member"' do
- click_link "New project member"
+ step 'I click link "Add members"' do
+ find(:css, 'button.btn-new').click
end
step 'I select "Mike" as "Reporter"' do
user = User.find_by(name: "Mike")
- select2(user.id, from: "#user_ids", multiple: true)
- within "#new_project_member" do
+ within ".users-project-form" do
+ select2(user.id, from: "#user_ids", multiple: true)
select "Reporter", from: "access_level"
end
- click_button "Add users"
+ click_button "Add users to project"
end
step 'I should see "Mike" in team list as "Reporter"' do
@@ -42,9 +42,13 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps
end
step 'I change "Sam" role to "Reporter"' do
- user = User.find_by(name: "Sam")
- within "#user_#{user.id}" do
+ project = Project.find_by(name: "Shop")
+ user = User.find_by(name: 'Sam')
+ project_member = project.project_members.find_by(user_id: user.id)
+ within "#project_member_#{project_member.id}" do
+ click_button "Edit access level"
select "Reporter", from: "project_member_access_level"
+ click_button "Save"
end
end
@@ -100,7 +104,10 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps
end
step 'I click cancel link for "Sam"' do
- within "#user_#{User.find_by(name: 'Sam').id}" do
+ project = Project.find_by(name: "Shop")
+ user = User.find_by(name: 'Sam')
+ project_member = project.project_members.find_by(user_id: user.id)
+ within "#project_member_#{project_member.id}" do
click_link('Remove user from team')
end
end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index cc9de0c92f..0ea73eb6f7 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -36,7 +36,7 @@ module SharedPaths
end
step 'I visit group "Owned" members page' do
- visit members_group_path(Group.find_by(name:"Owned"))
+ visit group_group_members_path(Group.find_by(name:"Owned"))
end
step 'I visit group "Owned" settings page' do
@@ -60,7 +60,7 @@ module SharedPaths
end
step 'I visit group "Guest" members page' do
- visit members_group_path(Group.find_by(name:"Guest"))
+ visit group_group_members_path(Group.find_by(name:"Guest"))
end
step 'I visit group "Guest" settings page' do
@@ -410,7 +410,7 @@ module SharedPaths
end
step 'I visit project "Shop" team page' do
- visit namespace_project_team_index_path(project.namespace, project)
+ visit namespace_project_project_members_path(project.namespace, project)
end
step 'I visit project wiki page' do
diff --git a/lib/api/group_members.rb b/lib/api/group_members.rb
index c9c9ccbcb2..ed54c7f6ff 100644
--- a/lib/api/group_members.rb
+++ b/lib/api/group_members.rb
@@ -53,14 +53,14 @@ module API
authorize! :manage_group, group
required_attributes! [:access_level]
- team_member = group.group_members.find_by(user_id: params[:user_id])
- not_found!('User can not be found') if team_member.nil?
+ group_member = group.group_members.find_by(user_id: params[:user_id])
+ not_found!('User can not be found') if group_member.nil?
- if team_member.update_attributes(access_level: params[:access_level])
- @member = team_member.user
+ if group_member.update_attributes(access_level: params[:access_level])
+ @member = group_member.user
present @member, with: Entities::GroupMember, group: group
else
- handle_member_errors team_member.errors
+ handle_member_errors group_member.errors
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index ee678d84c8..a6e77002a0 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -207,7 +207,7 @@ module API
end
def render_validation_error!(model)
- unless model.valid?
+ if model.errors.any?
render_api_error!(model.errors.messages || '400 Bad Request', 400)
end
end
diff --git a/lib/api/project_members.rb b/lib/api/project_members.rb
index 2c56a0bedc..b88f13887d 100644
--- a/lib/api/project_members.rb
+++ b/lib/api/project_members.rb
@@ -50,19 +50,19 @@ module API
end
# either the user is already a team member or a new one
- team_member = user_project.team_member_by_id(params[:user_id])
- if team_member.nil?
- team_member = user_project.project_members.new(
+ project_member = user_project.project_member_by_id(params[:user_id])
+ if project_member.nil?
+ project_member = user_project.project_members.new(
user_id: params[:user_id],
access_level: params[:access_level]
)
end
- if team_member.save
- @member = team_member.user
+ if project_member.save
+ @member = project_member.user
present @member, with: Entities::ProjectMember, project: user_project
else
- handle_member_errors team_member.errors
+ handle_member_errors project_member.errors
end
end
@@ -78,14 +78,14 @@ module API
authorize! :admin_project, user_project
required_attributes! [:access_level]
- team_member = user_project.project_members.find_by(user_id: params[:user_id])
- not_found!("User can not be found") if team_member.nil?
+ project_member = user_project.project_members.find_by(user_id: params[:user_id])
+ not_found!("User can not be found") if project_member.nil?
- if team_member.update_attributes(access_level: params[:access_level])
- @member = team_member.user
+ if project_member.update_attributes(access_level: params[:access_level])
+ @member = project_member.user
present @member, with: Entities::ProjectMember, project: user_project
else
- handle_member_errors team_member.errors
+ handle_member_errors project_member.errors
end
end
@@ -98,9 +98,9 @@ module API
# DELETE /projects/:id/members/:user_id
delete ":id/members/:user_id" do
authorize! :admin_project, user_project
- team_member = user_project.project_members.find_by(user_id: params[:user_id])
- unless team_member.nil?
- team_member.destroy
+ project_member = user_project.project_members.find_by(user_id: params[:user_id])
+ unless project_member.nil?
+ project_member.destroy
else
{ message: "Access revoked", id: params[:user_id].to_i }
end
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index 0c2d282f78..54f2555903 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -42,21 +42,22 @@ module API
# title (required) - The title of a snippet
# file_name (required) - The name of a snippet file
# code (required) - The content of a snippet
+ # visibility_level (required) - The snippet's visibility
# Example Request:
# POST /projects/:id/snippets
post ":id/snippets" do
authorize! :write_project_snippet, user_project
- required_attributes! [:title, :file_name, :code]
+ required_attributes! [:title, :file_name, :code, :visibility_level]
- attrs = attributes_for_keys [:title, :file_name]
+ attrs = attributes_for_keys [:title, :file_name, :visibility_level]
attrs[:content] = params[:code] if params[:code].present?
- @snippet = user_project.snippets.new attrs
- @snippet.author = current_user
+ @snippet = CreateSnippetService.new(user_project, current_user,
+ attrs).execute
- if @snippet.save
- present @snippet, with: Entities::ProjectSnippet
- else
+ if @snippet.errors.any?
render_validation_error!(@snippet)
+ else
+ present @snippet, with: Entities::ProjectSnippet
end
end
@@ -68,19 +69,22 @@ module API
# title (optional) - The title of a snippet
# file_name (optional) - The name of a snippet file
# code (optional) - The content of a snippet
+ # visibility_level (optional) - The snippet's visibility
# Example Request:
# PUT /projects/:id/snippets/:snippet_id
put ":id/snippets/:snippet_id" do
@snippet = user_project.snippets.find(params[:snippet_id])
authorize! :modify_project_snippet, @snippet
- attrs = attributes_for_keys [:title, :file_name]
+ attrs = attributes_for_keys [:title, :file_name, :visibility_level]
attrs[:content] = params[:code] if params[:code].present?
- if @snippet.update_attributes attrs
- present @snippet, with: Entities::ProjectSnippet
- else
+ UpdateSnippetService.new(user_project, current_user, @snippet,
+ attrs).execute
+ if @snippet.errors.any?
render_validation_error!(@snippet)
+ else
+ present @snippet, with: Entities::ProjectSnippet
end
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 2972c59fc2..293dc6427d 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -233,10 +233,10 @@ module API
::Projects::UpdateService.new(user_project,
current_user, attrs).execute
- if user_project.valid?
- present user_project, with: Entities::Project
- else
+ if user_project.errors.any?
render_validation_error!(user_project)
+ else
+ present user_project, with: Entities::Project
end
end
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index ab8db4e983..b499e5755b 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -17,14 +17,18 @@ module Backup
file << s.to_yaml.gsub(/^---\n/,'')
end
+ FileUtils.chmod_R(0700, %w{db uploads repositories})
+
# create archive
$progress.print "Creating backup archive: #{tar_file} ... "
+ orig_umask = File.umask(0077)
if Kernel.system('tar', '-cf', tar_file, *BACKUP_CONTENTS)
$progress.puts "done".green
else
puts "creating archive #{tar_file} failed".red
abort 'Backup failed'
end
+ File.umask(orig_umask)
upload(tar_file)
end
diff --git a/lib/gitlab/bitbucket_import/client.rb b/lib/gitlab/bitbucket_import/client.rb
index c907bebaef..1e4906c9e3 100644
--- a/lib/gitlab/bitbucket_import/client.rb
+++ b/lib/gitlab/bitbucket_import/client.rb
@@ -92,7 +92,7 @@ module Gitlab
end
def bitbucket_options
- OmniAuth::Strategies::Bitbucket.default_options[:client_options]
+ OmniAuth::Strategies::Bitbucket.default_options[:client_options].dup
end
end
end
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 1a25eebe7d..0ebebfa09c 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -5,8 +5,7 @@ module Gitlab
RequestStore.store[key] ||= begin
if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings')
- RequestStore.store[:current_application_settings] =
- (ApplicationSetting.current || ApplicationSetting.create_from_defaults)
+ ApplicationSetting.current || ApplicationSetting.create_from_defaults
else
fake_application_settings
end
@@ -21,6 +20,7 @@ module Gitlab
signin_enabled: Settings.gitlab['signin_enabled'],
gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'],
+ restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels']
)
end
end
diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb
index 7e6e1e61ae..f202b42e5c 100644
--- a/lib/gitlab/github_import/client.rb
+++ b/lib/gitlab/github_import/client.rb
@@ -46,7 +46,7 @@ module Gitlab
end
def github_options
- OmniAuth::Strategies::GitHub.default_options[:client_options]
+ OmniAuth::Strategies::GitHub.default_options[:client_options].dup
end
end
end
diff --git a/lib/gitlab/gitlab_import/client.rb b/lib/gitlab/gitlab_import/client.rb
index ecf4ff94e3..2236439c6c 100644
--- a/lib/gitlab/gitlab_import/client.rb
+++ b/lib/gitlab/gitlab_import/client.rb
@@ -71,7 +71,7 @@ module Gitlab
end
def gitlab_options
- OmniAuth::Strategies::GitLab.default_options[:client_options]
+ OmniAuth::Strategies::GitLab.default_options[:client_options].dup
end
end
end
diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb
index ae89ba21c1..007955733b 100644
--- a/lib/gitlab/ldap/access.rb
+++ b/lib/gitlab/ldap/access.rb
@@ -37,7 +37,15 @@ module Gitlab
def allowed?
if Gitlab::LDAP::Person.find_by_dn(user.ldap_identity.extern_uid, adapter)
return true unless ldap_config.active_directory
- !Gitlab::LDAP::Person.disabled_via_active_directory?(user.ldap_identity.extern_uid, adapter)
+
+ # Block user in GitLab if he/she was blocked in AD
+ if Gitlab::LDAP::Person.disabled_via_active_directory?(user.ldap_identity.extern_uid, adapter)
+ user.block unless user.blocked?
+ false
+ else
+ user.activate if user.blocked?
+ true
+ end
else
false
end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 2dfa18da48..c3a8d90ef5 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -200,7 +200,7 @@ module Gitlab
def reference_user(identifier, project = @project, _ = nil)
options = html_options.merge(
- class: "gfm gfm-team_member #{html_options[:class]}"
+ class: "gfm gfm-project_member #{html_options[:class]}"
)
if identifier == "all"
diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb
index 0cc6b0ac69..ea9012b884 100644
--- a/lib/gitlab/push_data_builder.rb
+++ b/lib/gitlab/push_data_builder.rb
@@ -28,9 +28,10 @@ module Gitlab
# Get latest 20 commits ASC
commits_limited = commits.last(20)
+ type = Gitlab::Git.tag_ref?(ref) ? "tag_push" : "push"
# Hash to be passed as post_receive_data
data = {
- object_kind: "push",
+ object_kind: type,
before: oldrev,
after: newrev,
ref: ref,
diff --git a/lib/gitlab/theme.rb b/lib/gitlab/theme.rb
index a7c83a880f..9799e54de5 100644
--- a/lib/gitlab/theme.rb
+++ b/lib/gitlab/theme.rb
@@ -5,6 +5,7 @@ module Gitlab
MODERN = 3 unless const_defined?(:MODERN)
GRAY = 4 unless const_defined?(:GRAY)
COLOR = 5 unless const_defined?(:COLOR)
+ BLUE = 6 unless const_defined?(:BLUE)
def self.css_class_by_id(id)
themes = {
@@ -12,7 +13,8 @@ module Gitlab
MARS => "ui_mars",
MODERN => "ui_modern",
GRAY => "ui_gray",
- COLOR => "ui_color"
+ COLOR => "ui_color",
+ BLUE => "ui_blue"
}
id ||= Gitlab.config.gitlab.default_theme
diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb
index 6830d15875..11b0d44f34 100644
--- a/lib/gitlab/url_builder.rb
+++ b/lib/gitlab/url_builder.rb
@@ -51,9 +51,9 @@ module Gitlab
anchor: "note_#{note.id}")
elsif note.for_project_snippet?
snippet = Snippet.find(note.noteable_id)
- snippet_url(snippet,
- host: Gitlab.config.gitlab['url'],
- anchor: "note_#{note.id}")
+ project_snippet_url(snippet,
+ host: Gitlab.config.gitlab['url'],
+ anchor: "note_#{note.id}")
end
end
end
diff --git a/lib/gitlab/visibility_level.rb b/lib/gitlab/visibility_level.rb
index d0b6cde3c7..1851e76067 100644
--- a/lib/gitlab/visibility_level.rb
+++ b/lib/gitlab/visibility_level.rb
@@ -5,6 +5,8 @@
#
module Gitlab
module VisibilityLevel
+ extend CurrentSettings
+
PRIVATE = 0 unless const_defined?(:PRIVATE)
INTERNAL = 10 unless const_defined?(:INTERNAL)
PUBLIC = 20 unless const_defined?(:PUBLIC)
@@ -23,21 +25,21 @@ module Gitlab
end
def allowed_for?(user, level)
- user.is_admin? || allowed_level?(level)
+ user.is_admin? || allowed_level?(level.to_i)
end
- # Level can be a string `"public"` or a value `20`, first check if valid,
- # then check if the corresponding string appears in the config
+ # Return true if the specified level is allowed for the current user.
+ # Level should be a numeric value, e.g. `20`.
def allowed_level?(level)
- if options.has_key?(level.to_s)
- non_restricted_level?(level)
- elsif options.has_value?(level.to_i)
- non_restricted_level?(options.key(level.to_i).downcase)
- end
+ valid_level?(level) && non_restricted_level?(level)
end
def non_restricted_level?(level)
- ! Gitlab.config.gitlab.restricted_visibility_levels.include?(level)
+ ! current_application_settings.restricted_visibility_levels.include?(level)
+ end
+
+ def valid_level?(level)
+ options.has_value?(level)
end
end
diff --git a/lib/support/deploy/deploy.sh b/lib/support/deploy/deploy.sh
index 4684957233..adea4c7a74 100755
--- a/lib/support/deploy/deploy.sh
+++ b/lib/support/deploy/deploy.sh
@@ -4,7 +4,7 @@
# If any command return non-zero status - stop deploy
set -e
-echo 'Deploy: Stoping sidekiq..'
+echo 'Deploy: Stopping sidekiq..'
cd /home/git/gitlab/ && sudo -u git -H bundle exec rake sidekiq:stop RAILS_ENV=production
echo 'Deploy: Show deploy index page'
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 976c4b5f22..d791b7155f 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -329,16 +329,20 @@ namespace :gitlab do
if correct_options.all?
puts "yes".green
else
- puts "no".red
- try_fixing_it(
- sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global user.name \"#{options["user.name"]}\""),
- sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global user.email \"#{options["user.email"]}\""),
- sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global core.autocrlf \"#{options["core.autocrlf"]}\"")
- )
- for_more_information(
- see_installation_guide_section "GitLab"
- )
- fix_and_rerun
+ print "Trying to fix Git error automatically. ..."
+ if auto_fix_git_config(options)
+ puts "Success".green
+ else
+ puts "Failed".red
+ try_fixing_it(
+ sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global user.name \"#{options["user.name"]}\""),
+ sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global user.email \"#{options["user.email"]}\""),
+ sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global core.autocrlf \"#{options["core.autocrlf"]}\"")
+ )
+ for_more_information(
+ see_installation_guide_section "GitLab"
+ )
+ end
end
end
end
@@ -806,3 +810,4 @@ namespace :gitlab do
end
end
end
+
diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake
index da61c6e007..14a130be2c 100644
--- a/lib/tasks/gitlab/task_helpers.rake
+++ b/lib/tasks/gitlab/task_helpers.rake
@@ -112,4 +112,20 @@ namespace :gitlab do
@warned_user_not_gitlab = true
end
end
+
+ # Tries to configure git itself
+ #
+ # Returns true if all subcommands were successfull (according to their exit code)
+ # Returns false if any or all subcommands failed.
+ def auto_fix_git_config(options)
+ if !@warned_user_not_gitlab && options['user.email'] != 'example@example.com' # default email should be overridden?
+ command_success = options.map do |name, value|
+ system(%W(#{Gitlab.config.git.bin_path} config --global #{name} #{value}))
+ end
+
+ command_success.all?
+ else
+ false
+ end
+ end
end
diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb
index b3affdb2ce..2f524712ed 100644
--- a/spec/controllers/import/github_controller_spec.rb
+++ b/spec/controllers/import/github_controller_spec.rb
@@ -28,17 +28,20 @@ describe Import::GithubController do
describe "GET status" do
before do
@repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim')
+ @org = OpenStruct.new(login: 'company')
+ @org_repo = OpenStruct.new(login: 'company', full_name: 'company/repo')
end
it "assigns variables" do
@project = create(:project, import_type: 'github', creator_id: user.id)
controller.stub_chain(:client, :repos).and_return([@repo])
- controller.stub_chain(:client, :orgs).and_return([])
+ controller.stub_chain(:client, :orgs).and_return([@org])
+ controller.stub_chain(:client, :org_repos).with(@org.login).and_return([@org_repo])
get :status
expect(assigns(:already_added_projects)).to eq([@project])
- expect(assigns(:repos)).to eq([@repo])
+ expect(assigns(:repos)).to eq([@repo, @org_repo])
end
it "does not show already added project" do
diff --git a/spec/features/security/group/group_access_spec.rb b/spec/features/security/group/group_access_spec.rb
index e0c5cbf4d3..6379314945 100644
--- a/spec/features/security/group/group_access_spec.rb
+++ b/spec/features/security/group/group_access_spec.rb
@@ -59,8 +59,8 @@ describe "Group access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
- describe "GET /groups/:path/members" do
- subject { members_group_path(group) }
+ describe "GET /groups/:path/group_members" do
+ subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
diff --git a/spec/features/security/group/internal_group_access_spec.rb b/spec/features/security/group/internal_group_access_spec.rb
index 5279a1bc13..d17a7412e4 100644
--- a/spec/features/security/group/internal_group_access_spec.rb
+++ b/spec/features/security/group/internal_group_access_spec.rb
@@ -55,8 +55,8 @@ describe "Group with internal project access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
- describe "GET /groups/:path/members" do
- subject { members_group_path(group) }
+ describe "GET /groups/:path/group_members" do
+ subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
diff --git a/spec/features/security/group/mixed_group_access_spec.rb b/spec/features/security/group/mixed_group_access_spec.rb
index efd14858b9..b3db7b5dea 100644
--- a/spec/features/security/group/mixed_group_access_spec.rb
+++ b/spec/features/security/group/mixed_group_access_spec.rb
@@ -56,8 +56,8 @@ describe "Group access", feature: true do
it { is_expected.to be_allowed_for :visitor }
end
- describe "GET /groups/:path/members" do
- subject { members_group_path(group) }
+ describe "GET /groups/:path/group_members" do
+ subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
diff --git a/spec/features/security/group/public_group_access_spec.rb b/spec/features/security/group/public_group_access_spec.rb
index c7e3d0a8a4..c16f0c0d1e 100644
--- a/spec/features/security/group/public_group_access_spec.rb
+++ b/spec/features/security/group/public_group_access_spec.rb
@@ -55,8 +55,8 @@ describe "Group with public project access", feature: true do
it { is_expected.to be_allowed_for :visitor }
end
- describe "GET /groups/:path/members" do
- subject { members_group_path(group) }
+ describe "GET /groups/:path/group_members" do
+ subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index 322697bced..8d1bfd2522 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -79,8 +79,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
- describe "GET /:project_path/team" do
- subject { namespace_project_team_index_path(project.namespace, project) }
+ describe "GET /:project_path/project_members" do
+ subject { namespace_project_project_members_path(project.namespace, project) }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_denied_for reporter }
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index ea146c3f0e..9021ff3318 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -79,8 +79,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
- describe "GET /:project_path/team" do
- subject { namespace_project_team_index_path(project.namespace, project) }
+ describe "GET /:project_path/project_members" do
+ subject { namespace_project_project_members_path(project.namespace, project) }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_denied_for reporter }
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 8ee9199ff2..6ec190ed77 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -84,8 +84,8 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :visitor }
end
- describe "GET /:project_path/team" do
- subject { namespace_project_team_index_path(project.namespace, project) }
+ describe "GET /:project_path/project_members" do
+ subject { namespace_project_project_members_path(project.namespace, project) }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_denied_for reporter }
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 99ff8a32ea..4c11709ed6 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -39,24 +39,6 @@ describe ApplicationHelper do
end
end
- describe 'group_icon' do
- avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
-
- it 'should return an url for the avatar' do
- group = create(:group)
- group.avatar = File.open(avatar_file_path)
- group.save!
- expect(group_icon(group.path).to_s).
- to match("/uploads/group/avatar/#{ group.id }/gitlab_logo.png")
- end
-
- it 'should give default avatar_icon when no avatar is present' do
- group = create(:group)
- group.save!
- expect(group_icon(group.path)).to match('group_avatar.png')
- end
- end
-
describe 'project_icon' do
avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 58b0dceab8..7ab1a65557 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -180,7 +180,7 @@ describe GitlabMarkdownHelper do
end
it "should include standard gfm classes" do
- expect(gfm(actual)).to match(/class="\s?gfm gfm-team_member\s?"/)
+ expect(gfm(actual)).to match(/class="\s?gfm gfm-project_member\s?"/)
end
end
diff --git a/spec/helpers/groups_helper.rb b/spec/helpers/groups_helper.rb
new file mode 100644
index 0000000000..3e99ab84ec
--- /dev/null
+++ b/spec/helpers/groups_helper.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe GroupsHelper do
+ describe 'group_icon' do
+ avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
+
+ it 'should return an url for the avatar' do
+ group = create(:group)
+ group.avatar = File.open(avatar_file_path)
+ group.save!
+ expect(group_icon(group.path).to_s).
+ to match("/uploads/group/avatar/#{ group.id }/gitlab_logo.png")
+ end
+
+ it 'should give default avatar_icon when no avatar is present' do
+ group = create(:group)
+ group.save!
+ expect(group_icon(group.path)).to match('group_avatar.png')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb
index d72b047ba8..8366bcc055 100644
--- a/spec/lib/gitlab/ldap/access_spec.rb
+++ b/spec/lib/gitlab/ldap/access_spec.rb
@@ -20,12 +20,26 @@ describe Gitlab::LDAP::Access do
before { Gitlab::LDAP::Person.stub(disabled_via_active_directory?: true) }
it { is_expected.to be_falsey }
+
+ it "should block user in GitLab" do
+ access.allowed?
+ user.should be_blocked
+ end
end
context 'and has no disabled flag in active diretory' do
- before { Gitlab::LDAP::Person.stub(disabled_via_active_directory?: false) }
+ before do
+ user.block
+
+ Gitlab::LDAP::Person.stub(disabled_via_active_directory?: false)
+ end
it { is_expected.to be_truthy }
+
+ it "should unblock user in GitLab" do
+ access.allowed?
+ user.should_not be_blocked
+ end
end
context 'withoud ActiveDirectory enabled' do
@@ -331,4 +345,3 @@ objectclass: posixGroup
end
end
end
-
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index d53f6e2793..538020b693 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -183,6 +183,13 @@ describe Notify do
context 'for issues' do
let(:issue) { create(:issue, author: current_user, assignee: assignee, project: project) }
let(:issue_with_description) { create(:issue, author: current_user, assignee: assignee, project: project, description: Faker::Lorem.sentence) }
+ let(:issue_with_image) do
+ create(:issue,
+ author: current_user,
+ assignee: assignee,
+ project: project,
+ description: "")
+ end
describe 'that are new' do
subject { Notify.new_issue_email(issue.assignee_id, issue.id) }
@@ -207,6 +214,22 @@ describe Notify do
end
end
+ describe 'that contain images' do
+ let(:png) { File.read("#{Rails.root}/spec/fixtures/dk.png") }
+ let(:png_encoded) { Base64::encode64(png) }
+
+ before :each do
+ file_path = File.join(Rails.root, 'public', 'uploads', issue_with_image.project.path_with_namespace, '12345/test.jpg')
+ allow(File).to receive(:file?).with(file_path).and_return(true)
+ allow(File).to receive(:read).with(file_path).and_return(png)
+ end
+
+ subject { Notify.new_issue_email(issue_with_image.assignee_id, issue_with_image.id) }
+ it 'replaces attached images with inline images' do
+ is_expected.to have_body_text URI.encode(png_encoded)
+ end
+ end
+
describe 'that have been reassigned' do
subject { Notify.reassigned_issue_email(recipient.id, issue.id, previous_assignee.id, current_user) }
@@ -271,6 +294,14 @@ describe Notify do
let(:merge_author) { create(:user) }
let(:merge_request) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project) }
let(:merge_request_with_description) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project, description: Faker::Lorem.sentence) }
+ let(:merge_request_with_image) do
+ create(:merge_request,
+ author: current_user,
+ assignee: assignee,
+ source_project: project,
+ target_project: project,
+ description: "")
+ end
describe 'that are new' do
subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) }
@@ -307,6 +338,22 @@ describe Notify do
end
end
+ describe 'that are new and contain contain images in the description' do
+ let(:png) {File.read("#{Rails.root}/spec/fixtures/dk.png")}
+ let(:png_encoded) { Base64::encode64(png) }
+
+ before :each do
+ file_path = File.join(Rails.root, 'public', 'uploads', merge_request_with_image.project.path_with_namespace, '/12345/test.jpg')
+ allow(File).to receive(:file?).with(file_path).and_return(true)
+ allow(File).to receive(:read).with(file_path).and_return(png)
+ end
+
+ subject { Notify.new_merge_request_email(merge_request_with_image.assignee_id, merge_request_with_image.id) }
+ it 'replaces attached images with inline images' do
+ is_expected.to have_body_text URI.encode(png_encoded)
+ end
+ end
+
describe 'that are reassigned' do
subject { Notify.reassigned_merge_request_email(recipient.id, merge_request.id, previous_assignee.id, current_user.id) }
@@ -415,9 +462,12 @@ describe Notify do
describe 'project access changed' do
let(:project) { create(:project) }
let(:user) { create(:user) }
- let(:project_member) { create(:project_member,
- project: project,
- user: user) }
+ let(:project_member) do
+ create(:project_member,
+ project: project,
+ user: user)
+ end
+
subject { Notify.project_access_granted_email(project_member.id) }
it_behaves_like 'an email sent from GitLab'
@@ -457,6 +507,32 @@ describe Notify do
end
end
+ describe 'on a commit that contains an image' do
+ let(:commit) { project.repository.commit }
+ let(:note_with_image) do
+ create(:note,
+ project: project,
+ author: note_author,
+ note: "")
+ end
+
+ let(:png) {File.read("#{Rails.root}/spec/fixtures/dk.png")}
+ let(:png_encoded) { Base64::encode64(png) }
+
+ before :each do
+ file_path = File.join(Rails.root, 'public', 'uploads', note_with_image.project.path_with_namespace, '12345/test.jpg')
+ allow(File).to receive(:file?).with(file_path).and_return(true)
+ allow(File).to receive(:read).with(file_path).and_return(png)
+ allow(Note).to receive(:find).with(note_with_image.id).and_return(note_with_image)
+ allow(note_with_image).to receive(:noteable).and_return(commit)
+ end
+
+ subject { Notify.note_commit_email(recipient.id, note_with_image.id) }
+ it 'replaces attached images with inline images' do
+ is_expected.to have_body_text URI.encode(png_encoded)
+ end
+ end
+
describe 'on a commit' do
let(:commit) { project.repository.commit }
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index d1027f64d1..b4f0b2c201 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -2,17 +2,19 @@
#
# Table name: application_settings
#
-# id :integer not null, primary key
-# default_projects_limit :integer
-# signup_enabled :boolean
-# signin_enabled :boolean
-# gravatar_enabled :boolean
-# sign_in_text :text
-# created_at :datetime
-# updated_at :datetime
-# home_page_url :string(255)
-# default_branch_protection :integer default(2)
-# twitter_sharing_enabled :boolean default(TRUE)
+# id :integer not null, primary key
+# default_projects_limit :integer
+# default_branch_protection :integer
+# signup_enabled :boolean
+# signin_enabled :boolean
+# gravatar_enabled :boolean
+# sign_in_text :text
+# created_at :datetime
+# updated_at :datetime
+# home_page_url :string(255)
+# default_branch_protection :integer default(2)
+# twitter_sharing_enabled :boolean default(TRUE)
+# restricted_visibility_levels :text
#
require 'spec_helper'
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index e04f1741b2..e206c11f33 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -28,18 +28,18 @@ describe GroupMember do
describe "#after_update" do
before do
- @membership = create :group_member
- @membership.stub(notification_service: double('NotificationService').as_null_object)
+ @group_member = create :group_member
+ @group_member.stub(notification_service: double('NotificationService').as_null_object)
end
it "should send email to user" do
- expect(@membership).to receive(:notification_service)
- @membership.update_attribute(:access_level, GroupMember::MASTER)
+ expect(@group_member).to receive(:notification_service)
+ @group_member.update_attribute(:access_level, GroupMember::MASTER)
end
it "does not send an email when the access level has not changed" do
- expect(@membership).not_to receive(:notification_service)
- @membership.update_attribute(:access_level, GroupMember::OWNER)
+ expect(@group_member).not_to receive(:notification_service)
+ @group_member.update_attribute(:access_level, GroupMember::OWNER)
end
end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index ccdaeff992..9fb76b751c 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
+ include Gitlab::CurrentSettings
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
@@ -202,6 +203,31 @@ describe API::API, api: true do
expect(json_response['public']).to be_falsey
expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
end
+
+ context 'when a visibility level is restricted' do
+ before do
+ @project = attributes_for(:project, { public: true })
+ allow_any_instance_of(ApplicationSetting).to(
+ receive(:restricted_visibility_levels).and_return([20])
+ )
+ end
+
+ it 'should not allow a non-admin to use a restricted visibility level' do
+ post api('/projects', user), @project
+ expect(response.status).to eq(400)
+ expect(json_response['message']['visibility_level'].first).to(
+ match('restricted by your GitLab administrator')
+ )
+ end
+
+ it 'should allow an admin to override restricted visibility settings' do
+ post api('/projects', admin), @project
+ expect(json_response['public']).to be_truthy
+ expect(json_response['visibility_level']).to(
+ eq(Gitlab::VisibilityLevel::PUBLIC)
+ )
+ end
+ end
end
describe 'POST /projects/user/:id' do
@@ -399,7 +425,8 @@ describe API::API, api: true do
describe 'POST /projects/:id/snippets' do
it 'should create a new project snippet' do
post api("/projects/#{project.id}/snippets", user),
- title: 'api test', file_name: 'sample.rb', code: 'test'
+ title: 'api test', file_name: 'sample.rb', code: 'test',
+ visibility_level: '0'
expect(response.status).to eq(201)
expect(json_response['title']).to eq('api test')
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 4308a765b5..d9bd91f599 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -338,17 +338,14 @@ describe Projects::CommitsController, 'routing' do
end
end
-# project_team_members GET /:project_id/team_members(.:format) team_members#index
-# POST /:project_id/team_members(.:format) team_members#create
-# new_project_team_member GET /:project_id/team_members/new(.:format) team_members#new
-# edit_project_team_member GET /:project_id/team_members/:id/edit(.:format) team_members#edit
-# project_team_member GET /:project_id/team_members/:id(.:format) team_members#show
-# PUT /:project_id/team_members/:id(.:format) team_members#update
-# DELETE /:project_id/team_members/:id(.:format) team_members#destroy
-describe Projects::TeamMembersController, 'routing' do
+# project_project_members GET /:project_id/project_members(.:format) project_members#index
+# POST /:project_id/project_members(.:format) project_members#create
+# PUT /:project_id/project_members/:id(.:format) project_members#update
+# DELETE /:project_id/project_members/:id(.:format) project_members#destroy
+describe Projects::ProjectMembersController, 'routing' do
it_behaves_like 'RESTful project resources' do
- let(:actions) { [:new, :create, :update, :destroy] }
- let(:controller) { 'team_members' }
+ let(:actions) { [:index, :create, :update, :destroy] }
+ let(:controller) { 'project_members' }
end
end
diff --git a/spec/services/create_snippet_service_spec.rb b/spec/services/create_snippet_service_spec.rb
new file mode 100644
index 0000000000..08689c15ca
--- /dev/null
+++ b/spec/services/create_snippet_service_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe CreateSnippetService do
+ before do
+ @user = create :user
+ @admin = create :user, admin: true
+ @opts = {
+ title: 'Test snippet',
+ file_name: 'snippet.rb',
+ content: 'puts "hello world"',
+ visibility_level: Gitlab::VisibilityLevel::PRIVATE
+ }
+ end
+
+ context 'When public visibility is restricted' do
+ before do
+ allow_any_instance_of(ApplicationSetting).to(
+ receive(:restricted_visibility_levels).and_return(
+ [Gitlab::VisibilityLevel::PUBLIC]
+ )
+ )
+
+ @opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ it 'non-admins should not be able to create a public snippet' do
+ snippet = create_snippet(nil, @user, @opts)
+ expect(snippet.errors.messages).to have_key(:visibility_level)
+ expect(snippet.errors.messages[:visibility_level].first).to(
+ match('Public visibility has been restricted')
+ )
+ end
+
+ it 'admins should be able to create a public snippet' do
+ snippet = create_snippet(nil, @admin, @opts)
+ expect(snippet.errors.any?).to be_falsey
+ expect(snippet.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
+ end
+ end
+
+ def create_snippet(project, user, opts)
+ CreateSnippetService.new(project, user, opts).execute
+ end
+end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 2074f8e7f7..34737348d4 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -69,9 +69,9 @@ describe NotificationService do
user_project = note.project.project_members.find_by_user_id(@u_watcher.id)
user_project.notification_level = Notification::N_PARTICIPATING
user_project.save
- user_group = note.project.group.group_members.find_by_user_id(@u_watcher.id)
- user_group.notification_level = Notification::N_GLOBAL
- user_group.save
+ group_member = note.project.group.group_members.find_by_user_id(@u_watcher.id)
+ group_member.notification_level = Notification::N_GLOBAL
+ group_member.save
end
it do
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 8bb4834620..337dae592d 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -55,6 +55,33 @@ describe Projects::CreateService do
it { expect(File.exists?(@path)).to be_falsey }
end
end
+
+ context 'restricted visibility level' do
+ before do
+ allow_any_instance_of(ApplicationSetting).to(
+ receive(:restricted_visibility_levels).and_return([20])
+ )
+
+ @opts.merge!(
+ visibility_level: Gitlab::VisibilityLevel.options['Public']
+ )
+ end
+
+ it 'should not allow a restricted visibility level for non-admins' do
+ project = create_project(@user, @opts)
+ expect(project).to respond_to(:errors)
+ expect(project.errors.messages).to have_key(:visibility_level)
+ expect(project.errors.messages[:visibility_level].first).to(
+ match('restricted by your GitLab administrator')
+ )
+ end
+
+ it 'should allow a restricted visibility level for admins' do
+ project = create_project(@admin, @opts)
+ expect(project.errors.any?).to be(false)
+ expect(project.saved?).to be(true)
+ end
+ end
end
def create_project(user, opts)
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 10dbc548e8..ea5b881310 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -47,9 +47,9 @@ describe Projects::UpdateService do
context 'respect configured visibility restrictions setting' do
before(:each) do
- @restrictions = double("restrictions")
- allow(@restrictions).to receive(:restricted_visibility_levels) { [ "public" ] }
- Settings.stub_chain(:gitlab).and_return(@restrictions)
+ allow_any_instance_of(ApplicationSetting).to(
+ receive(:restricted_visibility_levels).and_return([20])
+ )
end
context 'should be private when updated to private' do
diff --git a/spec/services/update_snippet_service_spec.rb b/spec/services/update_snippet_service_spec.rb
new file mode 100644
index 0000000000..841ef9bfed
--- /dev/null
+++ b/spec/services/update_snippet_service_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe UpdateSnippetService do
+ before do
+ @user = create :user
+ @admin = create :user, admin: true
+ @opts = {
+ title: 'Test snippet',
+ file_name: 'snippet.rb',
+ content: 'puts "hello world"',
+ visibility_level: Gitlab::VisibilityLevel::PRIVATE
+ }
+ end
+
+ context 'When public visibility is restricted' do
+ before do
+ allow_any_instance_of(ApplicationSetting).to(
+ receive(:restricted_visibility_levels).and_return(
+ [Gitlab::VisibilityLevel::PUBLIC]
+ )
+ )
+
+ @snippet = create_snippet(@project, @user, @opts)
+ @opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ it 'non-admins should not be able to update to public visibility' do
+ old_visibility = @snippet.visibility_level
+ update_snippet(@project, @user, @snippet, @opts)
+ expect(@snippet.errors.messages).to have_key(:visibility_level)
+ expect(@snippet.errors.messages[:visibility_level].first).to(
+ match('Public visibility has been restricted')
+ )
+ expect(@snippet.visibility_level).to eq(old_visibility)
+ end
+
+ it 'admins should be able to update to pubic visibility' do
+ old_visibility = @snippet.visibility_level
+ update_snippet(@project, @admin, @snippet, @opts)
+ expect(@snippet.visibility_level).not_to eq(old_visibility)
+ expect(@snippet.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
+ end
+ end
+
+ def create_snippet(project, user, opts)
+ CreateSnippetService.new(project, user, opts).execute
+ end
+
+ def update_snippet(project = nil, user, snippet, opts)
+ UpdateSnippetService.new(project, user, snippet, opts).execute
+ end
+end
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 60942cc95f..e6763be7b8 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -10,17 +10,17 @@ describe 'gitlab:app namespace rake task' do
Rake::Task.define_task :environment
end
+ def run_rake_task(task_name)
+ Rake::Task[task_name].reenable
+ Rake.application.invoke_task task_name
+ end
+
describe 'backup_restore' do
before do
# avoid writing task output to spec progress
allow($stdout).to receive :write
end
- let :run_rake_task do
- Rake::Task["gitlab:backup:restore"].reenable
- Rake.application.invoke_task "gitlab:backup:restore"
- end
-
context 'gitlab version' do
before do
Dir.stub glob: []
@@ -36,7 +36,9 @@ describe 'gitlab:app namespace rake task' do
it 'should fail on mismatch' do
YAML.stub load_file: {gitlab_version: "not #{gitlab_version}" }
- expect { run_rake_task }.to raise_error SystemExit
+ expect { run_rake_task('gitlab:backup:restore') }.to(
+ raise_error SystemExit
+ )
end
it 'should invoke restoration on mach' do
@@ -44,9 +46,43 @@ describe 'gitlab:app namespace rake task' do
expect(Rake::Task["gitlab:backup:db:restore"]).to receive :invoke
expect(Rake::Task["gitlab:backup:repo:restore"]).to receive :invoke
expect(Rake::Task["gitlab:shell:setup"]).to receive :invoke
- expect { run_rake_task }.to_not raise_error
+ expect { run_rake_task('gitlab:backup:restore') }.to_not raise_error
end
end
end # backup_restore task
+
+ describe 'backup_create' do
+ def tars_glob
+ Dir.glob(File.join(Gitlab.config.backup.path, '*_gitlab_backup.tar'))
+ end
+
+ before :all do
+ FileUtils.rm(tars_glob)
+ orig_stdout = $stdout
+ $stdout = StringIO.new
+ run_rake_task('gitlab:backup:create')
+ $stdout = orig_stdout
+
+ @backup_tar = tars_glob.first
+ end
+
+ before do
+ backup_path = File.join(Gitlab.config.backup.path, 'test')
+ allow(Gitlab.config.backup).to receive(:path).and_return(backup_path)
+ end
+
+ it 'should set correct permissions on the tar file' do
+ expect(File.exist?(@backup_tar)).to be_truthy
+ expect(File::Stat.new(@backup_tar).mode.to_s(8)).to eq('100600')
+ end
+
+ it 'should set correct permissions on the tar contents' do
+ tar_contents, exit_status = Gitlab::Popen.popen(
+ %W{tar -tvf #{@backup_tar} db uploads repositories}
+ )
+ expect(exit_status).to eq(0)
+ expect(tar_contents).not_to match(/^.{4,9}[rwx]/)
+ end
+ end # backup_create task
end # gitlab:app namespace
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 8eabc46112..df1a2b84a5 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -1,6 +1,10 @@
require 'spec_helper'
describe PostReceive do
+ let(:changes) { "123456 789012 refs/heads/tést\n654321 210987 refs/tags/tag" }
+ let(:wrongly_encoded_changes) { changes.encode("ISO-8859-1").force_encoding("UTF-8") }
+ let(:base64_changes) { Base64.encode64(wrongly_encoded_changes) }
+
context "as a resque worker" do
it "reponds to #perform" do
expect(PostReceive.new).to respond_to(:perform)
@@ -14,7 +18,7 @@ describe PostReceive do
it "fetches the correct project" do
expect(Project).to receive(:find_with_namespace).with(project.path_with_namespace).and_return(project)
- PostReceive.new.perform(pwd(project), key_id, changes)
+ PostReceive.new.perform(pwd(project), key_id, base64_changes)
end
it "does not run if the author is not in the project" do
@@ -22,24 +26,20 @@ describe PostReceive do
expect(project).not_to receive(:execute_hooks)
- expect(PostReceive.new.perform(pwd(project), key_id, changes)).to be_falsey
+ expect(PostReceive.new.perform(pwd(project), key_id, base64_changes)).to be_falsey
end
it "asks the project to trigger all hooks" do
Project.stub(find_with_namespace: project)
- expect(project).to receive(:execute_hooks)
- expect(project).to receive(:execute_services)
+ expect(project).to receive(:execute_hooks).twice
+ expect(project).to receive(:execute_services).twice
expect(project).to receive(:update_merge_requests)
- PostReceive.new.perform(pwd(project), key_id, changes)
+ PostReceive.new.perform(pwd(project), key_id, base64_changes)
end
end
def pwd(project)
File.join(Gitlab.config.gitlab_shell.repos_path, project.path_with_namespace)
end
-
- def changes
- 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master'
- end
end