Commit 43a3a401 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into mention-all

parents 396c5c97 e3befaed
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.4.0 (unreleased) v 8.4.0 (unreleased)
- Fix Error 500 when doing a search in dashboard before visiting any project (Stan Hu)
- Implement new UI for group page - Implement new UI for group page
- Implement search inside emoji picker - Implement search inside emoji picker
- Add project permissions to all project API endpoints (Stan Hu) - Add project permissions to all project API endpoints (Stan Hu)
- Only allow group/project members to mention `@all` - Only allow group/project members to mention `@all`
- Expose Git's version in the admin area
- Add "Frequently used" category to emoji picker
- Add CAS support (tduehr)
- Add link to merge request on build detail page.
v 8.3.1 (unreleased) v 8.3.1
- Fix Error 500 when global milestones have slashes (Stan Hu) - Fix Error 500 when global milestones have slashes (Stan Hu)
- Fix Error 500 when doing a search in dashboard before visiting any project (Stan Hu)
- Fix LDAP identity and user retrieval when special characters are used
- Move Sidekiq-cron configuration to gitlab.yml
v 8.3.0 v 8.3.0
- Add CAS support (tduehr)
- Bump rack-attack to 4.3.1 for security fix (Stan Hu) - Bump rack-attack to 4.3.1 for security fix (Stan Hu)
- API support for starred projects for authorized user (Zeger-Jan van de Weg) - API support for starred projects for authorized user (Zeger-Jan van de Weg)
- Add link to merge request on build detail page.
- Add open_issues_count to project API (Stan Hu) - Add open_issues_count to project API (Stan Hu)
- Expand character set of usernames created by Omniauth (Corey Hinshaw) - Expand character set of usernames created by Omniauth (Corey Hinshaw)
- Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg) - Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg)
...@@ -74,7 +78,6 @@ v 8.3.0 ...@@ -74,7 +78,6 @@ v 8.3.0
- Do not show build status unless builds are enabled and `.gitlab-ci.yml` is present - Do not show build status unless builds are enabled and `.gitlab-ci.yml` is present
- Persist runners registration token in database - Persist runners registration token in database
- Fix online editor should not remove newlines at the end of the file - Fix online editor should not remove newlines at the end of the file
- Expose Git's version in the admin area
v 8.2.3 v 8.2.3
- Fix application settings cache not expiring after changes (Stan Hu) - Fix application settings cache not expiring after changes (Stan Hu)
......
...@@ -10,6 +10,7 @@ class @AwardsHandler ...@@ -10,6 +10,7 @@ class @AwardsHandler
if $(".emoji-menu").is(":visible") if $(".emoji-menu").is(":visible")
$(".emoji-menu").hide() $(".emoji-menu").hide()
@renderFrequentlyUsedBlock()
@setupSearch() @setupSearch()
addAward: (emoji) -> addAward: (emoji) ->
...@@ -20,6 +21,8 @@ class @AwardsHandler ...@@ -20,6 +21,8 @@ class @AwardsHandler
$(".emoji-menu").hide() $(".emoji-menu").hide()
addAwardToEmojiBar: (emoji) -> addAwardToEmojiBar: (emoji) ->
@addEmojiToFrequentlyUsedList(emoji)
emoji = @normilizeEmojiName(emoji) emoji = @normilizeEmojiName(emoji)
if @exist(emoji) if @exist(emoji)
if @isActive(emoji) if @isActive(emoji)
...@@ -117,6 +120,29 @@ class @AwardsHandler ...@@ -117,6 +120,29 @@ class @AwardsHandler
normilizeEmojiName: (emoji) -> normilizeEmojiName: (emoji) ->
@aliases[emoji] || emoji @aliases[emoji] || emoji
addEmojiToFrequentlyUsedList: (emoji) ->
frequently_used_emojis = @getFrequentlyUsedEmojis()
frequently_used_emojis.push(emoji)
$.cookie('frequently_used_emojis', frequently_used_emojis.join(","), { expires: 365 })
getFrequentlyUsedEmojis: ->
frequently_used_emojis = ($.cookie('frequently_used_emojis') || "").split(",")
frequently_used_emojis = ["thumbsup", "thumbsdown"].concat(frequently_used_emojis)
_.compact(_.uniq(frequently_used_emojis))
renderFrequentlyUsedBlock: ->
frequently_used_emojis = @getFrequentlyUsedEmojis()
ul = $("<ul>")
for emoji in frequently_used_emojis
do (emoji) ->
$(".emoji-menu-content [data-emoji='#{emoji}']").closest("li").clone().appendTo(ul)
$("input.emoji-search").after(ul).after($("<h5>").text("Frequently used"))
setupSearch: -> setupSearch: ->
$("input.emoji-search").keyup (ev) => $("input.emoji-search").keyup (ev) =>
term = $(ev.target).val() term = $(ev.target).val()
...@@ -125,7 +151,7 @@ class @AwardsHandler ...@@ -125,7 +151,7 @@ class @AwardsHandler
$("ul.emoji-search,h5.emoji-search").remove() $("ul.emoji-search,h5.emoji-search").remove()
if term if term
# Generate search result block # Generate a search result block
h5 = $("<h5>").text("Search results").addClass("emoji-search") h5 = $("<h5>").text("Search results").addClass("emoji-search")
found_emojis = @searchEmojis(term).show() found_emojis = @searchEmojis(term).show()
ul = $("<ul>").addClass("emoji-search").append(found_emojis) ul = $("<ul>").addClass("emoji-search").append(found_emojis)
......
class @Project class @Project
constructor: -> constructor: ->
# Git protocol switcher # Git protocol switcher
$('.js-protocol-switch').click -> $('ul.clone-options-dropdown a').click ->
return if $(@).hasClass('active') return if $(@).hasClass('active')
...@@ -10,7 +10,8 @@ class @Project ...@@ -10,7 +10,8 @@ class @Project
# Add the active class for the clicked button # Add the active class for the clicked button
$(@).toggleClass('active') $(@).toggleClass('active')
url = $(@).data('clone') url = $("#project_clone").val()
console.log("url",url)
# Update the input field # Update the input field
$('#project_clone').val(url) $('#project_clone').val(url)
......
class @Star
constructor: ->
$('.project-home-panel .toggle-star').on('ajax:success', (e, data, status, xhr) ->
$this = $(this)
$starSpan = $this.find('span')
$starIcon = $this.find('i')
toggleStar = (isStarred) ->
$this.parent().find('span.count').text data.star_count
if isStarred
$starSpan.removeClass('starred').text 'Star'
$starIcon.removeClass('fa-star').addClass 'fa-star-o'
else
$starSpan.addClass('starred').text 'Unstar'
$starIcon.removeClass('fa-star-o').addClass 'fa-star'
return
toggleStar $starSpan.hasClass('starred')
return
).on 'ajax:error', (e, xhr, status, error) ->
new Flash('Star toggle failed. Try again later.', 'alert')
return
\ No newline at end of file
...@@ -91,21 +91,83 @@ ...@@ -91,21 +91,83 @@
} }
} }
.input-group { .git-clone-holder {
display: inline-table; display: inline-table;
position: relative; position: relative;
top: 17px;
} }
.project-repo-buttons { .project-repo-buttons {
margin-top: 12px; margin-top: 12px;
margin-bottom: 0px; margin-bottom: 0px;
.count-buttons {
display: block;
margin-bottom: 12px;
}
.btn { .btn {
@include btn-gray; @include btn-gray;
text-transform: none;
}
.count-with-arrow {
display: inline-block;
position: relative;
margin-left: 4px;
.arrow {
&:before {
content: '';
display: inline-block;
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
top: 50%;
left: 0;
margin-top: -6px;
border-width: 7px 5px 7px 0;
border-right-color: #dce0e5;
}
&:after {
content: '';
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
top: 50%;
left: 1px;
margin-top: -9px;
border-width: 10px 7px 10px 0;
border-right-color: #FFF;
}
}
.count { .count {
@include btn-gray;
display: inline-block; display: inline-block;
background: white;
border-radius: 2px;
border-width: 1px;
border-style: solid;
font-size: 13px;
font-weight: 600;
line-height: 20px;
padding: 11px 16px;
letter-spacing: .4px;
padding: 10px;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
white-space: nowrap;
margin: 0 11px 0px 4px;
&:hover {
background: #FFF;
}
} }
} }
} }
...@@ -125,6 +187,13 @@ ...@@ -125,6 +187,13 @@
margin-right: 45px; margin-right: 45px;
} }
.clone-options {
display: table-cell;
a.btn {
width: 100%;
}
}
.form-control { .form-control {
cursor: auto; cursor: auto;
@extend .monospace; @extend .monospace;
......
...@@ -171,7 +171,7 @@ class ProjectsController < ApplicationController ...@@ -171,7 +171,7 @@ class ProjectsController < ApplicationController
@project.reload @project.reload
render json: { render json: {
html: view_to_html_string("projects/buttons/_star") star_count: @project.star_count
} }
end end
......
...@@ -132,14 +132,14 @@ class Ability ...@@ -132,14 +132,14 @@ class Ability
end end
def public_project_rules def public_project_rules
project_guest_rules + [ @public_project_rules ||= project_guest_rules + [
:download_code, :download_code,
:fork_project :fork_project
] ]
end end
def project_guest_rules def project_guest_rules
[ @project_guest_rules ||= [
:read_project, :read_project,
:read_wiki, :read_wiki,
:read_issue, :read_issue,
...@@ -157,7 +157,7 @@ class Ability ...@@ -157,7 +157,7 @@ class Ability
end end
def project_report_rules def project_report_rules
project_guest_rules + [ @project_report_rules ||= project_guest_rules + [
:create_commit_status, :create_commit_status,
:read_commit_statuses, :read_commit_statuses,
:download_code, :download_code,
...@@ -170,7 +170,7 @@ class Ability ...@@ -170,7 +170,7 @@ class Ability
end end
def project_dev_rules def project_dev_rules
project_report_rules + [ @project_dev_rules ||= project_report_rules + [
:admin_merge_request, :admin_merge_request,
:create_merge_request, :create_merge_request,
:create_wiki, :create_wiki,
...@@ -181,7 +181,7 @@ class Ability ...@@ -181,7 +181,7 @@ class Ability
end end
def project_archived_rules def project_archived_rules
[ @project_archived_rules ||= [
:create_merge_request, :create_merge_request,
:push_code, :push_code,
:push_code_to_protected_branches, :push_code_to_protected_branches,
...@@ -191,7 +191,7 @@ class Ability ...@@ -191,7 +191,7 @@ class Ability
end end
def project_master_rules def project_master_rules
project_dev_rules + [ @project_master_rules ||= project_dev_rules + [
:push_code_to_protected_branches, :push_code_to_protected_branches,
:update_project_snippet, :update_project_snippet,
:update_merge_request, :update_merge_request,
...@@ -206,7 +206,7 @@ class Ability ...@@ -206,7 +206,7 @@ class Ability
end end
def project_admin_rules def project_admin_rules
project_master_rules + [ @project_admin_rules ||= project_master_rules + [
:change_namespace, :change_namespace,
:change_visibility_level, :change_visibility_level,
:rename_project, :rename_project,
...@@ -332,7 +332,7 @@ class Ability ...@@ -332,7 +332,7 @@ class Ability
end end
if snippet.public? || snippet.internal? if snippet.public? || snippet.internal?
rules << :read_personal_snippet rules << :read_personal_snippet
end end
rules rules
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
class Identity < ActiveRecord::Base class Identity < ActiveRecord::Base
include Sortable include Sortable
include CaseSensitivity
belongs_to :user belongs_to :user
validates :provider, presence: true validates :provider, presence: true
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
- else - else
= render 'explore/head' = render 'explore/head'
.gray-content-block.clearfix .gray-content-block.clearfix.second-block
= render 'filter' = render 'filter'
= render 'projects', projects: @projects = render 'projects', projects: @projects
= paginate @projects, theme: "gitlab" = paginate @projects, theme: "gitlab"
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= render 'explore/head' = render 'explore/head'
.explore-trending-block .explore-trending-block
.gray-content-block .gray-content-block.second-block
.pull-right .pull-right
= render 'explore/projects/dropdown' = render 'explore/projects/dropdown'
.oneline .oneline
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= render 'explore/head' = render 'explore/head'
.explore-trending-block .explore-trending-block
.gray-content-block .gray-content-block.second-block
.pull-right .pull-right
= render 'explore/projects/dropdown' = render 'explore/projects/dropdown'
.oneline .oneline
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
= icon('rss') = icon('rss')
.project-repo-buttons .project-repo-buttons
.split-one .split-one.count-buttons
= render 'projects/buttons/star' = render 'projects/buttons/star'
= render 'projects/buttons/fork' = render 'projects/buttons/fork'
...@@ -38,3 +38,6 @@ ...@@ -38,3 +38,6 @@
= render 'projects/buttons/dropdown' = render 'projects/buttons/dropdown'
= render 'projects/buttons/notifications' = render 'projects/buttons/notifications'
:coffeescript
new Star()
\ No newline at end of file
...@@ -4,10 +4,15 @@ ...@@ -4,10 +4,15 @@
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn has_tooltip' do = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn has_tooltip' do
= icon('code-fork fw') = icon('code-fork fw')
Fork Fork
%div.count-with-arrow
%span.arrow
%span.count %span.count
= @project.forks_count = @project.forks_count
- else - else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn has_tooltip' do = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn has_tooltip' do
= icon('code-fork fw') = icon('code-fork fw')
Fork
%div.count-with-arrow
%span.arrow
%span.count %span.count
= @project.forks_count = @project.forks_count
- if current_user - if current_user
= link_to toggle_star_namespace_project_path(@project.namespace, @project), class: 'btn star-btn toggle-star has_tooltip', method: :post, remote: true, title: "Star project" do = link_to toggle_star_namespace_project_path(@project.namespace, @project), class: 'btn star-btn toggle-star has_tooltip', method: :post, remote: true, title: "Star project" do
= icon('star fw') - if current_user.starred?(@project)
%span.count = icon('star fw')
%span.starred Unstar
- else
= icon('star-o fw')
%span Star
%div.count-with-arrow
%span.arrow
%span.count.star-count
= @project.star_count = @project.star_count
:javascript
$('.project-home-panel .toggle-star').on('ajax:success', function (e, data, status, xhr) {
$(this).replaceWith(data.html);
})
.on('ajax:error', function (e, xhr, status, error) {
new Flash('Star toggle failed. Try again later.', 'alert');
});
- else - else
= link_to new_user_session_path, class: 'btn has_tooltip star-btn', title: 'You must sign in to star a project' do = link_to new_user_session_path, class: 'btn has_tooltip star-btn', title: 'You must sign in to star a project' do
= icon('star fw') = icon('star fw')
Star
%div.count-with-arrow
%span.arrow
%span.count %span.count
= @project.star_count = @project.star_count
- project = project || @project - project = project || @project
.git-clone-holder.input-group
.input-group-addon.git-protocols .git-clone-holder
.input-group-btn .btn-group.clone-options
= ssh_clone_button(project) %a#clone-dropdown.clone-dropdown-btn.btn{href: '#', 'data-toggle' => 'dropdown'}
.input-group-btn %span
= http_clone_button(project) = default_clone_protocol.upcase
= icon('angle-down')
%ul.dropdown-menu.dropdown-menu-right.clone-options-dropdown
%li
%a#ssh-selector{href: @project.ssh_url_to_repo}
SSH
%li
%a#http-selector{href: @project.http_url_to_repo}
HTTPS
= text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true = text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#project_clone') = clipboard_button(clipboard_target: '#project_clone')
:javascript
$('ul.clone-options-dropdown a').on('click',function(e){
e.preventDefault();
var $this = $(this);
$('a.clone-dropdown-btn span').text($this.text());
$('#project_clone').val($this.attr('href'));
});
@project-create
Feature: Project Create Feature: Project Create
In order to get access to project sections In order to get access to project sections
A user with ability to create a project A user with ability to create a project
......
...@@ -26,5 +26,5 @@ Feature: Award Emoji ...@@ -26,5 +26,5 @@ Feature: Award Emoji
@javascript @javascript
Scenario: I add award emoji using regular comment Scenario: I add award emoji using regular comment
Given I leave comment with a single emoji Given I leave comment with a single emoji
Then I have award added Then I have award added
@project-stars
Feature: Project Star Feature: Project Star
Scenario: New projects have 0 stars Scenario: New projects have 0 stars
Given public project "Community" Given public project "Community"
......
...@@ -26,7 +26,8 @@ class Spinach::Features::ProjectCreate < Spinach::FeatureSteps ...@@ -26,7 +26,8 @@ class Spinach::Features::ProjectCreate < Spinach::FeatureSteps
end end
step 'I click on HTTP' do step 'I click on HTTP' do
click_button 'HTTP' find('#clone-dropdown').click
find('#http-selector').click
end end
step 'Remote url should update to http link' do step 'Remote url should update to http link' do
...@@ -34,7 +35,8 @@ class Spinach::Features::ProjectCreate < Spinach::FeatureSteps ...@@ -34,7 +35,8 @@ class Spinach::Features::ProjectCreate < Spinach::FeatureSteps
end end
step 'If I click on SSH' do step 'If I click on SSH' do
click_button 'SSH' find('#clone-dropdown').click
find('#ssh-selector').click
end end
step 'Remote url should update to ssh link' do step 'Remote url should update to ssh link' do
......
...@@ -32,6 +32,6 @@ class Spinach::Features::ProjectStar < Spinach::FeatureSteps ...@@ -32,6 +32,6 @@ class Spinach::Features::ProjectStar < Spinach::FeatureSteps
protected protected
def has_n_stars(n) def has_n_stars(n)
expect(page).to have_css(".star-btn .count", text: n, visible: true) expect(page).to have_css(".star-count", text: n, visible: true)
end end
end end
...@@ -14,7 +14,7 @@ module Gitlab ...@@ -14,7 +14,7 @@ module Gitlab
# LDAP distinguished name is case-insensitive # LDAP distinguished name is case-insensitive
identity = ::Identity. identity = ::Identity.
where(provider: provider). where(provider: provider).
where('lower(extern_uid) = ?', uid.mb_chars.downcase.to_s).last iwhere(extern_uid: uid).last
identity && identity.user identity && identity.user
end end
end end
...@@ -31,7 +31,7 @@ module Gitlab ...@@ -31,7 +31,7 @@ module Gitlab
def find_by_uid_and_provider def find_by_uid_and_provider
self.class.find_by_uid_and_provider( self.class.find_by_uid_and_provider(
auth_hash.uid.downcase, auth_hash.provider) auth_hash.uid, auth_hash.provider)
end end
def find_by_email def find_by_email
...@@ -47,7 +47,7 @@ module Gitlab ...@@ -47,7 +47,7 @@ module Gitlab
# find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved. # find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved.
identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider } identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider }
identity ||= gl_user.identities.build(provider: auth_hash.provider) identity ||= gl_user.identities.build(provider: auth_hash.provider)
# For a new user set extern_uid to the LDAP DN # For a new user set extern_uid to the LDAP DN
# For an existing user with matching email but changed DN, update the DN. # For an existing user with matching email but changed DN, update the DN.
# For an existing user with no change in DN, this line changes nothing. # For an existing user with no change in DN, this line changes nothing.
......
...@@ -64,7 +64,7 @@ module Gitlab ...@@ -64,7 +64,7 @@ module Gitlab
# If a corresponding person exists with same uid in a LDAP server, # If a corresponding person exists with same uid in a LDAP server,
# set up a Gitlab user with dual LDAP and Omniauth identities. # set up a Gitlab user with dual LDAP and Omniauth identities.
if user = Gitlab::LDAP::User.find_by_uid_and_provider(ldap_person.dn.downcase, ldap_person.provider) if user = Gitlab::LDAP::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider)
# Case when a LDAP user already exists in Gitlab. Add the Omniauth identity to existing account. # Case when a LDAP user already exists in Gitlab. Add the Omniauth identity to existing account.
user.identities.build(extern_uid: auth_hash.uid, provider: auth_hash.provider) user.identities.build(extern_uid: auth_hash.uid, provider: auth_hash.provider)
else else
......
#= require jquery.ui.all #= require jquery-ui
#= require new_branch_form #= require new_branch_form
describe 'Branch', -> describe 'Branch', ->
......
...@@ -42,6 +42,21 @@ describe Gitlab::LDAP::User, lib: true do ...@@ -42,6 +42,21 @@ describe Gitlab::LDAP::User, lib: true do
end end
end end
describe '.find_by_uid_and_provider' do
it 'retrieves the correct user' do
special_info = {
name: 'John Åström',
email: 'john@example.com',
nickname: 'jastrom'
}
special_hash = OmniAuth::AuthHash.new(uid: 'CN=John Åström,CN=Users,DC=Example,DC=com', provider: 'ldapmain', info: special_info)
special_chars_user = described_class.new(special_hash)
user = special_chars_user.save
expect(described_class.find_by_uid_and_provider(special_hash.uid, special_hash.provider)).to eq user
end
end
describe :find_or_create do describe :find_or_create do
it "finds the user if already existing" do it "finds the user if already existing" do
create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain') create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment