Commit ce881513 authored by Sean Packham's avatar Sean Packham

Merge branch 'master' into add-university-content

parents 8e741e2b 90578f4a
Please view this file on the master branch, on stable branches it's out of date.
v 8.13.0 (unreleased)
- Use gitlab-shell v3.6.2 (GIT TRACE logging)
- Speed-up group milestones show page
- Add more tests for calendar contribution (ClemMakesApps)
- Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison)
- Revoke button in Applications Settings underlines on hover.
- Add organization field to user profile
......@@ -12,6 +14,8 @@ v 8.12.2 (unreleased)
- Fix snippets pagination
- Fix List-Unsubscribe header in emails
- Fix an issue with the "Commits" section of the cycle analytics summary. !6513
- Fix errors importing project feature and milestone models using GitLab project import
- Make JWT messages Docker-compatible
v 8.12.1
- Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST
......@@ -118,6 +122,7 @@ v 8.12.0
- Change pipeline duration to be jobs running time instead of simple wall time from start to end !6084
- Show queued time when showing a pipeline !6084
- Remove unused mixins (ClemMakesApps)
- Fix issue board label filtering appending already filtered labels
- Add search to all issue board lists
- Scroll active tab into view on mobile
- Fix groups sort dropdown alignment (ClemMakesApps)
......
......@@ -280,12 +280,12 @@
if (page === 'projects:boards:show') {
if (label.isAny) {
gl.issueBoards.BoardsStore.state.filters['label_name'] = [];
} else if (label.title) {
} else if ($el.hasClass('is-active')) {
gl.issueBoards.BoardsStore.state.filters['label_name'].push(label.title);
} else {
var filters = gl.issueBoards.BoardsStore.state.filters['label_name'];
filters = filters.filter(function (label) {
return label !== $el.text().trim();
filters = filters.filter(function (filteredLabel) {
return filteredLabel !== label.title;
});
gl.issueBoards.BoardsStore.state.filters['label_name'] = filters;
}
......
......@@ -25,7 +25,7 @@ class JwtController < ApplicationController
authenticate_with_http_basic do |login, password|
@authentication_result = Gitlab::Auth.find_for_git_client(login, password, project: nil, ip: request.ip)
render_403 unless @authentication_result.success? &&
render_unauthorized unless @authentication_result.success? &&
(@authentication_result.actor.nil? || @authentication_result.actor.is_a?(User))
end
rescue Gitlab::Auth::MissingPersonalTokenError
......@@ -33,10 +33,21 @@ class JwtController < ApplicationController
end
def render_missing_personal_token
render plain: "HTTP Basic: Access denied\n" \
"You have 2FA enabled, please use a personal access token for Git over HTTP.\n" \
"You can generate one at #{profile_personal_access_tokens_url}",
status: 401
render json: {
errors: [
{ code: 'UNAUTHORIZED',
message: "HTTP Basic: Access denied\n" \
"You have 2FA enabled, please use a personal access token for Git over HTTP.\n" \
"You can generate one at #{profile_personal_access_tokens_url}" }
] }, status: 401
end
def render_unauthorized
render json: {
errors: [
{ code: 'UNAUTHORIZED',
message: 'HTTP Basic: Access denied' }
] }, status: 401
end
def auth_params
......
......@@ -7,10 +7,10 @@ module Auth
def execute(authentication_abilities:)
@authentication_abilities = authentication_abilities
return error('not found', 404) unless registry.enabled
return error('UNAVAILABLE', status: 404, message: 'registry not enabled') unless registry.enabled
unless current_user || project
return error('forbidden', 403) unless scope
return error('DENIED', status: 403, message: 'access forbidden') unless scope
end
{ token: authorized_token(scope).encoded }
......@@ -111,5 +111,12 @@ module Auth
@authentication_abilities.include?(:create_container_image) &&
can?(current_user, :create_container_image, requested_project)
end
def error(code, status:, message: '')
{
errors: [{ code: code, message: message }],
http_status: status
}
end
end
end
# Model relationships to be included in the project import/export
project_tree:
- :labels
- milestones:
- :events
- issues:
- :events
- notes:
......@@ -39,9 +42,6 @@ project_tree:
- protected_branches:
- :merge_access_levels
- :push_access_levels
- :labels
- milestones:
- :events
- :project_feature
# Only include the following attributes for the models specified.
......
......@@ -61,11 +61,17 @@ module Gitlab
def restore_project
return @project unless @tree_hash
project_params = @tree_hash.reject { |_key, value| value.is_a?(Array) }
@project.update(project_params)
@project
end
def project_params
@tree_hash.reject do |key, value|
# return params that are not 1 to many or 1 to 1 relations
value.is_a?(Array) || key == key.singularize
end
end
# Given a relation hash containing one or more models and its relationships,
# loops through each model and each object from a model type and
# and assigns its correspondent attributes hash from +tree_hash+
......
......@@ -466,6 +466,29 @@ describe 'Issue Boards', feature: true, js: true do
end
end
it 'removes filtered labels' do
wait_for_vue_resource
page.within '.labels-filter' do
click_button('Label')
wait_for_ajax
page.within '.dropdown-menu-labels' do
click_link(testing.title)
wait_for_vue_resource(spinner: false)
end
expect(page).to have_css('input[name="label_name[]"]', visible: false)
page.within '.dropdown-menu-labels' do
click_link(testing.title)
wait_for_vue_resource(spinner: false)
end
expect(page).not_to have_css('input[name="label_name[]"]', visible: false)
end
end
it 'infinite scrolls list with label filter' do
50.times do
create(:labeled_issue, project: project, labels: [testing])
......
......@@ -5,13 +5,41 @@ feature 'Contributions Calendar', js: true, feature: true do
let(:contributed_project) { create(:project, :public) }
before do
login_as :user
date_format = '%A %b %d, %Y'
issue_title = 'Bug in old browser'
issue_params = { title: issue_title }
def get_cell_color_selector(contributions)
contribution_cell = '.user-contrib-cell'
activity_colors = Array['#ededed', '#acd5f2', '#7fa8c9', '#527ba0', '#254e77']
activity_colors_index = 0
if contributions > 0 && contributions < 10
activity_colors_index = 1
elsif contributions >= 10 && contributions < 20
activity_colors_index = 2
elsif contributions >= 20 && contributions < 30
activity_colors_index = 3
elsif contributions >= 30
activity_colors_index = 4
end
"#{contribution_cell}[fill='#{activity_colors[activity_colors_index]}']"
end
def get_cell_date_selector(contributions, date)
contribution_text = 'No contributions'
issue_params = { title: 'Bug in old browser' }
Issues::CreateService.new(contributed_project, @user, issue_params).execute
if contributions === 1
contribution_text = '1 contribution'
elsif contributions > 1
contribution_text = "#{contributions} contributions"
end
# Push code contribution
"#{get_cell_color_selector(contributions)}[data-original-title='#{contribution_text}<br />#{date}']"
end
def push_code_contribution
push_params = {
project: contributed_project,
action: Event::PUSHED,
......@@ -20,7 +48,10 @@ feature 'Contributions Calendar', js: true, feature: true do
}
Event.create(push_params)
end
before do
login_as :user
visit @user.username
wait_for_ajax
end
......@@ -29,11 +60,71 @@ feature 'Contributions Calendar', js: true, feature: true do
expect(page).to have_css('.js-contrib-calendar')
end
it 'displays calendar activity log', js: true do
expect(find('.content_list .event-note')).to have_content "Bug in old browser"
describe '1 calendar activity' do
before do
Issues::CreateService.new(contributed_project, @user, issue_params).execute
visit @user.username
wait_for_ajax
end
it 'displays calendar activity log', js: true do
expect(find('.content_list .event-note')).to have_content issue_title
end
it 'displays calendar activity square color for 1 contribution', js: true do
expect(page).to have_selector(get_cell_color_selector(1), count: 1)
end
it 'displays calendar activity square on the correct date', js: true do
today = Date.today.strftime(date_format)
expect(page).to have_selector(get_cell_date_selector(1, today), count: 1)
end
end
describe '10 calendar activities' do
before do
(0..9).each do |i|
push_code_contribution()
end
visit @user.username
wait_for_ajax
end
it 'displays calendar activity square color for 10 contributions', js: true do
expect(page).to have_selector(get_cell_color_selector(10), count: 1)
end
it 'displays calendar activity square on the correct date', js: true do
today = Date.today.strftime(date_format)
expect(page).to have_selector(get_cell_date_selector(10, today), count: 1)
end
end
it 'displays calendar activity square color', js: true do
expect(page).to have_selector('.user-contrib-cell[fill=\'#acd5f2\']', count: 1)
describe 'calendar activity on two days' do
before do
push_code_contribution()
Timecop.freeze(Date.yesterday)
Issues::CreateService.new(contributed_project, @user, issue_params).execute
Timecop.return
visit @user.username
wait_for_ajax
end
it 'displays calendar activity squares for both days', js: true do
expect(page).to have_selector(get_cell_color_selector(1), count: 2)
end
it 'displays calendar activity square for yesterday', js: true do
yesterday = Date.yesterday.strftime(date_format)
expect(page).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
end
it 'displays calendar activity square for today', js: true do
today = Date.today.strftime(date_format)
expect(page).to have_selector(get_cell_date_selector(1, today), count: 1)
end
end
end
......@@ -2231,6 +2231,31 @@
],
"milestones": [
{
"id": 1,
"title": "test milestone",
"project_id": 8,
"description": "test milestone",
"due_date": null,
"created_at": "2016-06-14T15:02:04.415Z",
"updated_at": "2016-06-14T15:02:04.415Z",
"state": "active",
"iid": 1,
"events": [
{
"id": 487,
"target_type": "Milestone",
"target_id": 1,
"title": null,
"data": null,
"project_id": 46,
"created_at": "2016-06-14T15:02:04.418Z",
"updated_at": "2016-06-14T15:02:04.418Z",
"action": 1,
"author_id": 18
}
]
},
{
"id": 20,
"title": "v4.0",
......@@ -7373,5 +7398,16 @@
}
]
}
]
],
"project_feature": {
"builds_access_level": 0,
"created_at": "2014-12-26T09:26:45.000Z",
"id": 2,
"issues_access_level": 0,
"merge_requests_access_level": 20,
"project_id": 4,
"snippets_access_level": 20,
"updated_at": "2016-09-23T11:58:28.000Z",
"wiki_access_level": 20
}
}
\ No newline at end of file
......@@ -107,6 +107,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
expect(Label.first.label_links.first.target).not_to be_nil
end
it 'has a project feature' do
restored_project_json
expect(project.project_feature).not_to be_nil
end
it 'restores the correct service' do
restored_project_json
......
......@@ -39,7 +39,7 @@ describe JwtController do
subject! { get '/jwt/auth', parameters, headers }
it { expect(response).to have_http_status(403) }
it { expect(response).to have_http_status(401) }
end
end
......@@ -77,7 +77,7 @@ describe JwtController do
subject! { get '/jwt/auth', parameters, headers }
it { expect(response).to have_http_status(403) }
it { expect(response).to have_http_status(401) }
end
end
......
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