Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq into ce-to-ee

Conflicts:
	Gemfile.lock
	app/controllers/admin/application_settings_controller.rb
	app/controllers/groups/application_controller.rb
	app/controllers/groups/group_members_controller.rb
	app/controllers/projects/team_members_controller.rb
	app/helpers/application_settings_helper.rb
	app/helpers/projects_helper.rb
	app/helpers/tab_helper.rb
	app/models/application_setting.rb
	app/models/user.rb
	app/views/devise/shared/_signin_box.html.haml
	app/views/groups/projects.html.haml
	app/views/profiles/keys/_key.html.haml
	app/views/projects/team_members/_form.html.haml
	app/views/projects/team_members/index.html.haml
	config/routes.rb
	db/schema.rb
	spec/lib/gitlab/ldap/access_spec.rb
This commit is contained in:
Dmitriy Zaporozhets
2015-03-16 21:25:00 -07:00
248 changed files with 1914 additions and 1026 deletions
+26 -5
View File
@@ -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
+1 -1
View File
@@ -1 +1 @@
2.5.4
2.6.0
+4 -2
View File
@@ -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"
+2 -7
View File
@@ -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
+1 -1
View File
@@ -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.
+6 -3
View File
@@ -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
@@ -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('<span class="cgreen"><i class="fa fa-check"></i> done</span>')
status_field.html('<span><i class="fa fa-check"></i> done</span>')
else if job.import_status == 'started'
status_field.html("<i class='fa fa-spinner fa-spin'></i> started")
else
status_field.html(job.import_status)
), 4000
), 4000
+1 -1
View File
@@ -47,7 +47,7 @@
initSearch: ->
@timer = null
$("#issue_search").keyup ->
clearTimeout(@timer);
clearTimeout(@timer)
@timer = setTimeout(Issues.filterResults, 500)
filterResults: =>
@@ -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())
@@ -0,0 +1,4 @@
class @ProjectMembers
constructor: ->
$('li.project_member').bind 'ajax:success', ->
$(this).fadeOut()
+53 -4
View File
@@ -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;
}
}
}
@@ -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
+2 -1
View File
@@ -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:
@@ -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; }
+1 -1
View File
@@ -167,7 +167,7 @@ li.note {
background-color: inherit;
}
.team_member_show {
.project_member_show {
td:first-child {
color: #aaa;
}
+15 -19
View File
@@ -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 {
@@ -57,7 +57,7 @@
.note-text .code {
border: none;
box-shadow: none;
background: $box_bg;
background: $background-color;
padding: 1em;
overflow-x: auto;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+2 -1
View File
@@ -30,7 +30,8 @@
color: #666;
font-size: 14px;
font-weight: normal;
padding: 10px 0;
padding: 3px 0;
margin-bottom: 10px;
}
.commit-info-row {
+1 -7
View File
@@ -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;
+14 -9
View File
@@ -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 {
-2
View File
@@ -16,8 +16,6 @@
}
}
.commit-button-annotation {
@extend .alert;
@extend .alert-info;
display: inline-block;
margin: 0;
padding: 2px;
+2 -2
View File
@@ -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;
}
@@ -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;
+5
View File
@@ -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;
@@ -80,6 +80,10 @@
&.violet {
background: #548;
}
&.blue {
background: #2980b9;
}
}
}
}
+6 -1
View File
@@ -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;
}
@@ -0,0 +1,6 @@
/**
* Modern GitLab UI theme
*/
.ui_blue {
@include dark-theme(#BECDE9, #2980b9, #1970a9, #096099);
}
@@ -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
+5 -5
View File
@@ -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.'
+3 -3
View File
@@ -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
@@ -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!
+1 -17
View File
@@ -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
@@ -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
+2 -2
View File
@@ -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|
+1 -1
View File
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
+3 -16
View File
@@ -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
+1 -1
View File
@@ -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")
@@ -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]
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
+10 -14
View File
@@ -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
+6 -7
View File
@@ -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
@@ -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
+1 -1
View File
@@ -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
+8 -14
View File
@@ -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
-9
View File
@@ -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)
@@ -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
+2 -2
View File
@@ -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
+25
View File
@@ -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
+2 -1
View File
@@ -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
+12
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+3 -2
View File
@@ -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
+4 -4
View File
@@ -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
+12 -10
View File
@@ -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
+28 -14
View File
@@ -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
-1
View File
@@ -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) }
+2 -2
View File
@@ -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
-1
View File
@@ -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) }
+2 -6
View File
@@ -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
+8 -2
View File
@@ -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
+21 -21
View File
@@ -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)
+2 -2
View File
@@ -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,
}
+1 -4
View File
@@ -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)
+35 -1
View File
@@ -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,
+13 -2
View File
@@ -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
+13 -3
View File
@@ -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
+20
View File
@@ -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
+3 -5
View File
@@ -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
+12 -2
View File
@@ -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
+42
View File
@@ -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
-20
View File
@@ -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
+3 -2
View File
@@ -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
+6 -6
View File
@@ -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
+23 -23
View File
@@ -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
+6 -3
View File
@@ -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
@@ -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
+7 -2
View File
@@ -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]
+22
View File
@@ -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
@@ -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
@@ -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
@@ -52,7 +52,7 @@
%strong
#{broadcast_message.ends_at.to_s(:short)}
&nbsp;
= 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
+2 -2
View File
@@ -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
+3 -3
View File
@@ -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'
+2 -2
View File
@@ -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"

Some files were not shown because too many files have changed in this diff Show More