Commit e5a4b269 authored by Fatih Acet's avatar Fatih Acet

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into milestone-tooltip

parents 58456e26 b4812e2e
......@@ -61,6 +61,8 @@ update-knapsack:
- scripts/merge-reports knapsack/rspec_report.json knapsack/rspec_node_*.json
- scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json
- rm -f knapsack/*_node_*.json
only:
- master
# Execute all testing suites
......
......@@ -1088,6 +1088,9 @@ Rails/TimeZone:
Rails/Validation:
Enabled: false
Rails/UniqBeforePluck:
Enabled: false
##################### RSpec ##################################
# Check that instances are not being stubbed globally.
......
......@@ -9,6 +9,7 @@ v 8.9.0 (unreleased)
- Make EmailsOnPushWorker use Sidekiq mailers queue
- Fix wiki page events' webhook to point to the wiki repository
- Fix issue todo not remove when leave project !4150 (Long Nguyen)
- Allow customisable text on the 'nearly there' page after a user signs up
- Bump recaptcha gem to 3.0.0 to remove deprecated stoken support
- Allow forking projects with restricted visibility level
- Improve note validation to prevent errors when creating invalid note via API
......@@ -18,6 +19,7 @@ v 8.9.0 (unreleased)
- Redesign navigation for project pages
- Fix groups API to list only user's accessible projects
- Redesign account and email confirmation emails
- `git clone https://host/namespace/project` now works, in addition to using the `.git` suffix
- Bump nokogiri to 1.6.8
- Use gitlab-shell v3.0.0
- Use Knapsack to evenly distribute tests across multiple nodes
......@@ -50,6 +52,8 @@ v 8.9.0 (unreleased)
- Replace Colorize with Rainbow for coloring console output in Rake tasks.
- An indicator is now displayed at the top of the comment field for confidential issues.
- RepositoryCheck::SingleRepositoryWorker public and private methods are now instrumented
- Improve issuables APIs performance when accessing notes !4471
- External links now open in a new tab
v 8.8.4 (unreleased)
- Ensure branch cleanup regardless of whether the GitHub import process succeeds
......
......@@ -142,15 +142,26 @@
}
&.btn-grouped {
margin-right: 7px;
margin-right: $btn-side-margin;
float: left;
&.inline {
float: none;
}
&:last-child {
margin-right: 0;
}
&.btn-sm {
margin-right: $btn-sm-side-margin;
}
&.btn-xs {
margin-right: 3px;
margin-right: $btn-xs-side-margin;
}
}
&.disabled {
pointer-events: auto !important;
}
......
......@@ -124,6 +124,7 @@
position: relative;
padding: 5px 10px;
color: $dropdown-link-color;
line-height: initial;
text-overflow: ellipsis;
border-radius: 2px;
white-space: nowrap;
......
......@@ -79,6 +79,9 @@ $provider-btn-not-active-color: #4688f1;
$link-underline-blue: #4a8bee;
$layout-link-gray: #7e7c7c;
$todo-alert-blue: #428bca;
$btn-side-margin: 7px;
$btn-sm-side-margin: 5px;
$btn-xs-side-margin: 5px;
/*
* Color schema
......@@ -121,7 +124,7 @@ $border-white-normal: #d6dae2;
$border-white-dark: #c6cacf;
$border-gray-light: #dcdcdc;
$border-gray-normal: rgba(0, 0, 0, 0.10);
$border-gray-normal: #d7d7d7;
$border-gray-dark: #c6cacf;
$border-green-light: #2faa60;
......
......@@ -2,13 +2,21 @@
margin-bottom: 20px;
border-bottom: 1px solid #eee;
> h1 {
> h1, h2, h3, h4, h5, h6 {
font-weight: 400;
}
.lead {
margin-bottom: 20px;
}
ul, ol {
padding-left: 0;
}
li {
list-style-type: none;
}
}
.confirmation-content {
......
......@@ -74,6 +74,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:two_factor_grace_period,
:gravatar_enabled,
:sign_in_text,
:after_sign_up_text,
:help_page_text,
:home_page_url,
:after_sign_out_path,
......
......@@ -14,6 +14,7 @@ class SessionsController < Devise::SessionsController
before_action :load_recaptcha
def new
set_minimum_password_length
if Gitlab.config.ldap.enabled
@ldap_servers = Gitlab::LDAP::Config.servers
else
......
......@@ -15,6 +15,10 @@ module ApplicationSettingsHelper
current_application_settings.sign_in_text
end
def after_sign_up_text
current_application_settings.after_sign_up_text
end
def shared_runners_text
current_application_settings.shared_runners_text
end
......
......@@ -113,7 +113,10 @@ class ApplicationSetting < ActiveRecord::Base
signup_enabled: Settings.gitlab['signup_enabled'],
signin_enabled: Settings.gitlab['signin_enabled'],
gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'],
sign_in_text: nil,
after_sign_up_text: nil,
help_page_text: nil,
shared_runners_text: nil,
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
max_attachment_size: Settings.gitlab['max_attachment_size'],
session_expire_delay: Settings.gitlab['session_expire_delay'],
......
......@@ -198,7 +198,7 @@ class Commit
end
def notes_with_associations
notes.includes(:author, :project)
notes.includes(:author)
end
def method_missing(m, *args, &block)
......
......@@ -17,7 +17,12 @@ module Issuable
belongs_to :assignee, class_name: "User"
belongs_to :updated_by, class_name: "User"
belongs_to :milestone
has_many :notes, as: :noteable, dependent: :destroy
has_many :notes, as: :noteable, dependent: :destroy do
def authors_loaded?
# We check first if we're loaded to not load unnecesarily.
loaded? && to_a.all? { |note| note.association(:author).loaded? }
end
end
has_many :label_links, as: :target, dependent: :destroy
has_many :labels, through: :label_links
has_many :todos, as: :target, dependent: :destroy
......@@ -44,6 +49,7 @@ module Issuable
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
scope :join_project, -> { joins(:project) }
scope :inc_notes_with_associations, -> { includes(notes: :author) }
scope :references_project, -> { references(:project) }
scope :non_archived, -> { join_project.where(projects: { archived: false }) }
......@@ -179,7 +185,13 @@ module Issuable
end
def user_notes_count
notes.user.count
if notes.loaded?
# Use the in-memory association to select and count to avoid hitting the db
notes.to_a.count { |note| !note.system? }
else
# do the count query
notes.user.count
end
end
def subscribed_without_subscriptions?(user)
......@@ -239,7 +251,13 @@ module Issuable
end
def notes_with_associations
notes.includes(:author, :project)
# If A has_many Bs, and B has_many Cs, and you do
# `A.includes(b: :c).each { |a| a.b.includes(:c) }`, sadly ActiveRecord
# will do the inclusion again. So, we check if all notes in the relation
# already have their authors loaded (possibly because the scope
# `inc_notes_with_associations` was used) and skip the inclusion if that's
# the case.
notes.authors_loaded? ? notes : notes.includes(:author)
end
def updated_tasks
......
......@@ -102,7 +102,7 @@ class Snippet < ActiveRecord::Base
end
def notes_with_associations
notes.includes(:author, :project)
notes.includes(:author)
end
class << self
......
......@@ -154,6 +154,11 @@
.col-sm-10
= f.text_area :sign_in_text, class: 'form-control', rows: 4
.help-block Markdown enabled
.form-group
= f.label :after_sign_up_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :after_sign_up_text, class: 'form-control', rows: 4
.help-block Markdown enabled
.form-group
= f.label :help_page_text, class: 'control-label col-sm-2'
.col-sm-10
......
......@@ -9,5 +9,4 @@
- if current_user.can_create_group?
.nav-controls
= link_to new_group_path, class: "btn btn-new" do
= icon('plus')
New Group
......@@ -18,5 +18,4 @@
= render 'shared/projects/dropdown'
- if current_user.can_create_project?
= link_to new_project_path, class: 'btn btn-new' do
= icon('plus')
New Project
......@@ -3,6 +3,9 @@
Almost there...
%p.lead
Please check your email to confirm your account
- if after_sign_up_text.present?
.well-confirmation.text-center
= markdown(after_sign_up_text)
%p.confirmation-content.text-center
No confirmation email received? Please check your spam folder or
.append-bottom-20.prepend-top-20.text-center
......
......@@ -16,7 +16,7 @@
%div
= f.email_field :email, class: "form-control middle", placeholder: "Email", required: true
.form-group.append-bottom-20#password-strength
= f.password_field :password, class: "form-control bottom", placeholder: "Password", required: true
= f.password_field :password, class: "form-control bottom", placeholder: "Password - minimum length #{@minimum_password_length} characters", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters"
%div
- if current_application_settings.recaptcha_enabled
= recaptcha_tags
......
......@@ -36,7 +36,7 @@
- if can?(current_user, :update_group_member, member)
= button_tag class: "btn-xs btn js-toggle-button",
title: 'Edit access level', type: 'button' do
%i.fa.fa-pencil-square-o
= icon('pencil')
- if can?(current_user, :destroy_group_member, member)
&nbsp;
......@@ -46,7 +46,7 @@
Leave
- else
= link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
%i.fa.fa-minus.fa-inverse
= icon('trash')
.edit-member.hide.js-toggle-content
%br
......
......@@ -35,7 +35,6 @@
= render 'shared/projects/dropdown'
- if can? current_user, :create_projects, @group
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do
= icon('plus')
New Project
.tab-content
......
......@@ -2,106 +2,102 @@
= nav_link(controller: :dashboard, html_options: {class: 'home'}) do
= link_to admin_root_path, title: 'Overview' do
= icon('dashboard fw')
%span
.nav-link-text
Overview
= nav_link(controller: [:admin, :projects]) do
= link_to admin_namespaces_projects_path, title: 'Projects' do
= icon('cube fw')
%span
.nav-link-text
Projects
= nav_link(controller: :users) do
= link_to admin_users_path, title: 'Users' do
= icon('user fw')
%span
.nav-link-text
Users
= nav_link(controller: :groups) do
= link_to admin_groups_path, title: 'Groups' do
= icon('group fw')
%span
.nav-link-text
Groups
= nav_link(controller: :deploy_keys) do
= link_to admin_deploy_keys_path, title: 'Deploy Keys' do
= icon('key fw')
%span
.nav-link-text
Deploy Keys
= nav_link path: ['runners#index', 'runners#show'] do
= link_to admin_runners_path, title: 'Runners' do
= icon('cog fw')
%span
.nav-link-text
Runners
%span.count= number_with_delimiter(Ci::Runner.count(:all))
= nav_link path: 'builds#index' do
= link_to admin_builds_path, title: 'Builds' do
= icon('link fw')
%span
.nav-link-text
Builds
%span.count= number_with_delimiter(Ci::Build.count(:all))
= nav_link(controller: :logs) do
= link_to admin_logs_path, title: 'Logs' do
= icon('file-text fw')
%span
.nav-link-text
Logs
= nav_link(controller: :health_check) do
= link_to admin_health_check_path, title: 'Health Check' do
= icon('medkit fw')
%span
.nav-link-text
Health Check
= nav_link(controller: :broadcast_messages) do
= link_to admin_broadcast_messages_path, title: 'Messages' do
= icon('bullhorn fw')
%span
.nav-link-text
Messages
= nav_link(controller: :hooks) do
= link_to admin_hooks_path, title: 'Hooks' do
= icon('external-link fw')
%span
.nav-link-text
Hooks
= nav_link(controller: :background_jobs) do
= link_to admin_background_jobs_path, title: 'Background Jobs' do
= icon('cog fw')
%span
.nav-link-text
Background Jobs
= nav_link(controller: :appearances) do
= link_to admin_appearances_path, title: 'Appearances' do
= icon('image')
%span
.nav-link-text
Appearance
= nav_link(controller: :applications) do
= link_to admin_applications_path, title: 'Applications' do
= icon('cloud fw')
%span
.nav-link-text
Applications
= nav_link(controller: :services) do
= link_to admin_application_settings_services_path, title: 'Service Templates' do
= icon('copy fw')
%span
.nav-link-text
Service Templates
= nav_link(controller: :labels) do
= link_to admin_labels_path, title: 'Labels' do
= icon('tags fw')
%span
.nav-link-text
Labels
= nav_link(controller: :abuse_reports) do
= link_to admin_abuse_reports_path, title: "Abuse Reports" do
= icon('exclamation-circle fw')
%span
.nav-link-text
Abuse Reports
%span.count= number_with_delimiter(AbuseReport.count(:all))
- if askimet_enabled?
= nav_link(controller: :spam_logs) do
= link_to admin_spam_logs_path, title: "Spam Logs" do
= icon('exclamation-triangle fw')
%span
.nav-link-text
Spam Logs
%span.count= number_with_delimiter(SpamLog.count(:all))
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to admin_application_settings_path, title: 'Settings' do
= icon('cogs fw')
%span
.nav-link-text
Settings
......@@ -2,20 +2,20 @@
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
= link_to explore_root_path, title: 'Projects' do
= icon('bookmark fw')
%span
.nav-link-text
Projects
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to explore_groups_path, title: 'Groups' do
= icon('group fw')
%span
.nav-link-text
Groups
= nav_link(controller: :snippets) do
= link_to explore_snippets_path, title: 'Snippets' do
= icon('clipboard fw')
%span
.nav-link-text
Snippets
= nav_link(controller: :help) do
= link_to help_path, title: 'Help' do
= icon('question-circle fw')
%span
.nav-link-text
Help
......@@ -21,12 +21,10 @@
.controls.hidden-xs
- if create_mr_button?(@repository.root_ref, branch.name)
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-grouped btn-xs' do
= icon('plus')
Merge Request
- if branch.name != @repository.root_ref
= link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: branch.name), class: 'btn btn-grouped btn-xs', method: :post, title: "Compare" do
= icon("exchange")
Compare
- if can_remove_branch?(@project, branch.name)
......
- if can?(current_user, :push_code, @project)
.pull-right
#new-branch{'data-path' => can_create_branch_namespace_project_issue_path(@project.namespace, @project, @issue)}
= link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid), method: :post, class: 'btn has-tooltip', title: @issue.to_branch_name, disabled: 'disabled' do
= link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid),
method: :post, class: 'btn has-tooltip', title: @issue.to_branch_name, disabled: 'disabled' do
.checking
%i.fa.fa-spinner.fa-spin
= icon('spinner spin')
Checking branches
.available(style="display: none")
%i.fa.fa-code-fork
.available.hide
New branch
.unavailable(style="display: none")
%i.fa.fa-exclamation-triangle
.unavailable.hide
= icon('exclamation-triangle')
New branch unavailable
......@@ -15,7 +15,6 @@
= render 'shared/issuable/search_form', path: namespace_project_issues_path(@project.namespace, @project)
- if can? current_user, :create_issue, @project
= link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { assignee_id: @issuable_finder.assignee.try(:id), milestone_id: @issuable_finder.milestones.try(:first).try(:id) }), class: "btn btn-new", title: "New Issue", id: "new_issue_link" do
= icon('plus')
New Issue
= render 'shared/issuable/filter', type: :issues
......
......@@ -38,14 +38,12 @@
%li
= link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue)
- if can?(current_user, :create_issue, @project)
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped new-issue-link btn-success', title: 'New issue', id: 'new_issue_link' do
= icon('plus')
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-grouped new-issue-link btn-success', title: 'New issue', id: 'new_issue_link' do
New issue
- if can?(current_user, :update_issue, @issue)
= link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
= link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
= link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit' do
= icon('pencil-square-o')
= link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
= link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
= link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-grouped issuable-edit' do
Edit
......
......@@ -7,7 +7,6 @@
.nav-controls
- if can?(current_user, :admin_label, @project)
= link_to new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new" do
= icon('plus')
New label
.labels
......
......@@ -14,13 +14,11 @@
- if @merge_request.open?
.pull-right
- if @merge_request.source_branch_exists?
= link_to "#modal_merge_info", class: "btn btn-sm", "data-toggle" => "modal" do
= icon('cloud-download fw')
= link_to "#modal_merge_info", class: "btn inline btn-grouped btn-sm", "data-toggle" => "modal" do
Check out branch
%span.dropdown
%a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} }
= icon('download')
Download as
%span.caret
%ul.dropdown-menu
......
......@@ -10,7 +10,6 @@
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- if merge_project
= link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do
= icon('plus')
New Merge Request
= render 'shared/issuable/filter', type: :merge_requests
......
......@@ -25,8 +25,7 @@
= link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request'
%li
= link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'issuable-edit'
= link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@merge_request, true)}", title: 'Close merge request'
= link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen reopen-mr-link #{issue_button_visibility(@merge_request, false)}", title: 'Reopen merge request'
= link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit" do
= icon('pencil-square-o')
= link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "hidden-xs hidden-sm btn btn-grouped btn-close #{issue_button_visibility(@merge_request, true)}", title: 'Close merge request'
= link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "hidden-xs hidden-sm btn btn-grouped btn-reopen reopen-mr-link #{issue_button_visibility(@merge_request, false)}", title: 'Reopen merge request'
= link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "hidden-xs hidden-sm btn btn-grouped issuable-edit" do
Edit
......@@ -7,7 +7,6 @@
- if can?(current_user, :admin_group_member, @group)
.controls
= link_to group_group_members_path(@group), class: 'btn' do
= icon('pencil-square-o')
Manage group members
%ul.content-list
- members.limit(20).each do |member|
......
......@@ -34,7 +34,7 @@
- if can?(current_user, :update_project_member, member)
= button_tag class: "btn-xs btn js-toggle-button",
title: 'Edit access level', type: 'button' do
%i.fa.fa-pencil-square-o
= icon('pencil')
- if can?(current_user, :destroy_project_member, member)
&nbsp;
......@@ -44,7 +44,7 @@
Leave
- else
= link_to namespace_project_project_member_path(@project.namespace, @project, member), data: { confirm: remove_from_project_team_message(@project, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from team' do
%i.fa.fa-minus.fa-inverse
= icon('trash')
.edit-member.hide.js-toggle-content
%br
......
- if @projects.any?
.prepend-left-10.project-item-select-holder
.project-item-select-holder
= project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at' }
%a.btn.btn-new.new-project-item-select-button
= icon('plus')
= local_assigns[:label]
%b.caret
......
......@@ -135,7 +135,7 @@
.title.hide-collapsed
Notifications
- subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed'
%button.btn.btn-block.btn-gray.js-subscribe-button.issuable-subscribe-button.hide-collapsed{ type: "button" }
%button.btn.btn-block.btn-default.js-subscribe-button.issuable-subscribe-button.hide-collapsed{ type: "button" }
%span= subscribed ? 'Unsubscribe' : 'Subscribe'
.subscription-status.hide-collapsed{data: {status: subscribtion_status}}
.unsubscribed{class: ( 'hidden' if subscribed )}
......
......@@ -441,6 +441,23 @@ Rails.application.routes.draw do
resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do
resources(:projects, constraints: { id: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ }, except:
[:new, :create, :index], path: "/") do
# Allow /info/refs, /info/refs?service=git-upload-pack, and
# /info/refs?service=git-receive-pack, but nothing else.
#
git_http_handshake = lambda do |request|
request.query_string.blank? ||
request.query_string.match(/\Aservice=git-(upload|receive)-pack\z/)
end
ref_redirect = redirect do |params, request|
path = "#{params[:namespace_id]}/#{params[:project_id]}.git/info/refs"
path << "?#{request.query_string}" unless request.query_string.blank?
path
end
get '/info/refs', constraints: git_http_handshake, to: ref_redirect
member do
put :transfer
delete :remove_fork
......
class RemoveDuplicatedNotificationSettings < ActiveRecord::Migration
def up
execute <<-SQL
DELETE FROM notification_settings WHERE id NOT IN ( SELECT min_id from (SELECT MIN(id) as min_id FROM notification_settings GROUP BY user_id, source_type, source_id) as dups )
SQL
duplicates = exec_query(%Q{
SELECT user_id, source_type, source_id
FROM notification_settings
GROUP BY user_id, source_type, source_id
HAVING COUNT(*) > 1
})
duplicates.each do |row|
uid = row['user_id']
stype = connection.quote(row['source_type'])
sid = row['source_id']
execute(%Q{
DELETE FROM notification_settings
WHERE user_id = #{uid}
AND source_type = #{stype}
AND source_id = #{sid}
AND id != (
SELECT id FROM (
SELECT min(id) AS id
FROM notification_settings
WHERE user_id = #{uid}
AND source_type = #{stype}
AND source_id = #{sid}
) min_ids
)
})
end
end
end
class AddAfterSignUpTextToApplicationSettings < ActiveRecord::Migration
def change
add_column :application_settings, :after_sign_up_text, :text
end
end
......@@ -11,7 +11,8 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160530150109) do
ActiveRecord::Schema.define(version: 20160608155312) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
enable_extension "pg_trgm"
......@@ -83,6 +84,7 @@ ActiveRecord::Schema.define(version: 20160530150109) do
t.string "health_check_access_token"
t.boolean "send_user_confirmation_email", default: false
t.integer "container_registry_token_expire_delay", default: 5
t.text "after_sign_up_text"
end
create_table "audit_events", force: :cascade do |t|
......@@ -676,6 +678,7 @@ ActiveRecord::Schema.define(version: 20160530150109) do
end
add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree
add_index "notification_settings", ["user_id", "source_id", "source_type"], name: "index_notifications_on_user_id_and_source_id_and_source_type", unique: true, using: :btree
add_index "notification_settings", ["user_id"], name: "index_notification_settings_on_user_id", using: :btree
create_table "oauth_access_grants", force: :cascade do |t|
......
......@@ -49,8 +49,8 @@ information from database or file system
## Buttons
* Button should contain icon or text. Exceptions should be approved by UX designer.
* Use gray button on white background or white button on gray background.
* Use red button for destructive actions (not revertable). For example removing issue.
* Use green or blue button for primary action. Primary button should be only one.
Do not use both green and blue button in one form.
* For all other cases use default white button
......@@ -120,7 +120,7 @@ will need to let gitlab-workhorse listen on a TCP port. You can do this
via [/etc/default/gitlab].
[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-8-stable/lib/support/init.d/gitlab.default.example#L37
[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-9-stable/lib/support/init.d/gitlab.default.example#L37
#### Init script
......@@ -145,7 +145,7 @@ To make sure you didn't miss anything run a more thorough check:
If all items are green, then congratulations, the upgrade is complete!
## Things went south? Revert to previous version (8.7)
## Things went south? Revert to previous version (8.8)
### 1. Revert the code to the previous version
......
......@@ -351,6 +351,7 @@ module API
expose :signin_enabled
expose :gravatar_enabled
expose :sign_in_text
expose :after_sign_up_text
expose :created_at
expose :updated_at
expose :home_page_url
......
......@@ -51,7 +51,7 @@ module API
# GET /issues?labels=foo,bar
# GET /issues?labels=foo,bar&state=opened
get do
issues = current_user.issues
issues = current_user.issues.inc_notes_with_associations
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues.reorder(issuable_order_by => issuable_sort)
......@@ -82,7 +82,7 @@ module API
# GET /projects/:id/issues?milestone=1.0.0&state=closed
# GET /issues?iid=42
get ":id/issues" do
issues = user_project.issues.visible_to_user(current_user)
issues = user_project.issues.inc_notes_with_associations.visible_to_user(current_user)
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil?
......
......@@ -41,7 +41,7 @@ module API
#
get ":id/merge_requests" do
authorize! :read_merge_request, user_project
merge_requests = user_project.merge_requests
merge_requests = user_project.merge_requests.inc_notes_with_associations
unless params[:iid].nil?
merge_requests = filter_by_iid(merge_requests, params[:iid])
......
......@@ -15,6 +15,7 @@ module Banzai
next if link.start_with?(internal_url)
node.set_attribute('rel', 'nofollow noreferrer')
node.set_attribute('target', '_blank')
end
doc
......
......@@ -26,7 +26,10 @@ module Gitlab
signup_enabled: Settings.gitlab['signup_enabled'],
signin_enabled: Settings.gitlab['signin_enabled'],
gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'],
sign_in_text: nil,
after_sign_up_text: nil,
help_page_text: nil,
shared_runners_text: nil,
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
max_attachment_size: Settings.gitlab['max_attachment_size'],
session_expire_delay: Settings.gitlab['session_expire_delay'],
......
......@@ -165,17 +165,27 @@ describe 'GitLab Markdown', feature: true do
describe 'ExternalLinkFilter' do
it 'adds nofollow to external link' do
link = doc.at_css('a:contains("Google")')
expect(link.attr('rel')).to include('nofollow')
end
it 'adds noreferrer to external link' do
link = doc.at_css('a:contains("Google")')
expect(link.attr('rel')).to include('noreferrer')
end
it 'adds _blank to target attribute for external links' do
link = doc.at_css('a:contains("Google")')
expect(link.attr('target')).to match('_blank')
end
it 'ignores internal link' do
link = doc.at_css('a:contains("GitLab Root")')
expect(link.attr('rel')).not_to match 'nofollow'
expect(link.attr('target')).not_to match '_blank'
end
end
end
......
......@@ -136,7 +136,7 @@ But it shouldn't autolink text inside certain tags:
### ExternalLinkFilter
External links get a `rel="nofollow"` attribute:
External links get a `rel="nofollow noreferrer"` and `target="_blank"` attributes:
- [Google](https://google.com/)
- [GitLab Root](<%= Gitlab.config.gitlab.url %>)
......
......@@ -10,6 +10,16 @@ describe Issue, "Issuable" do
it { is_expected.to belong_to(:assignee) }
it { is_expected.to have_many(:notes).dependent(:destroy) }
it { is_expected.to have_many(:todos).dependent(:destroy) }
context 'Notes' do
let!(:note) { create(:note, noteable: issue, project: issue.project) }
let(:scoped_issue) { Issue.includes(notes: :author).find(issue.id) }
it 'indicates if the notes have their authors loaded' do
expect(issue.notes).not_to be_authors_loaded
expect(scoped_issue.notes).to be_authors_loaded
end
end
end
describe 'Included modules' do
......@@ -245,6 +255,22 @@ describe Issue, "Issuable" do
end
end
describe '#user_notes_count' do
let(:project) { create(:project) }
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
before do
create_list(:note, 3, noteable: issue1, project: project)
create_list(:note, 6, noteable: issue2, project: project)
end
it 'counts the user notes' do
expect(issue1.user_notes_count).to be(3)
expect(issue2.user_notes_count).to be(6)
end
end
describe "votes" do
let(:project) { issue.project }
......
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