summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/blacklist.rb1
-rw-r--r--lib/gitlab/diff/file.rb49
-rw-r--r--lib/gitlab/diff/line.rb12
-rw-r--r--lib/gitlab/diff/line_code.rb9
-rw-r--r--lib/gitlab/diff/parser.rb81
-rw-r--r--lib/gitlab/diff_parser.rb83
-rw-r--r--lib/gitlab/ldap/user.rb74
-rw-r--r--lib/gitlab/oauth/auth_hash.rb54
-rw-r--r--lib/gitlab/oauth/user.rb134
-rw-r--r--lib/gitlab/project_search_results.rb23
-rw-r--r--lib/gitlab/snippet_search_results.rb131
11 files changed, 445 insertions, 206 deletions
diff --git a/lib/gitlab/blacklist.rb b/lib/gitlab/blacklist.rb
index 65efb6e4407..43145e0ee1b 100644
--- a/lib/gitlab/blacklist.rb
+++ b/lib/gitlab/blacklist.rb
@@ -27,6 +27,7 @@ module Gitlab
notes
unsubscribes
all
+ ci
)
end
end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
new file mode 100644
index 00000000000..19a1198c68c
--- /dev/null
+++ b/lib/gitlab/diff/file.rb
@@ -0,0 +1,49 @@
+module Gitlab
+ module Diff
+ class File
+ attr_reader :diff
+
+ delegate :new_file, :deleted_file, :renamed_file,
+ :old_path, :new_path, to: :diff, prefix: false
+
+ def initialize(diff)
+ @diff = diff
+ end
+
+ # Array of Gitlab::DIff::Line objects
+ def diff_lines
+ @lines ||= parser.parse(raw_diff.lines)
+ end
+
+ def mode_changed?
+ !!(diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode)
+ end
+
+ def parser
+ Gitlab::Diff::Parser.new
+ end
+
+ def raw_diff
+ diff.diff
+ end
+
+ def next_line(index)
+ diff_lines[index + 1]
+ end
+
+ def prev_line(index)
+ if index > 0
+ diff_lines[index - 1]
+ end
+ end
+
+ def file_path
+ if diff.new_path.present?
+ diff.new_path
+ elsif diff.old_path.present?
+ diff.old_path
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb
new file mode 100644
index 00000000000..8ac1b15e88a
--- /dev/null
+++ b/lib/gitlab/diff/line.rb
@@ -0,0 +1,12 @@
+module Gitlab
+ module Diff
+ class Line
+ attr_reader :type, :text, :index, :old_pos, :new_pos
+
+ def initialize(text, type, index, old_pos, new_pos)
+ @text, @type, @index = text, type, index
+ @old_pos, @new_pos = old_pos, new_pos
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/line_code.rb b/lib/gitlab/diff/line_code.rb
new file mode 100644
index 00000000000..f3578ab3d35
--- /dev/null
+++ b/lib/gitlab/diff/line_code.rb
@@ -0,0 +1,9 @@
+module Gitlab
+ module Diff
+ class LineCode
+ def self.generate(file_path, new_line_position, old_line_position)
+ "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}"
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb
new file mode 100644
index 00000000000..9d6309954a4
--- /dev/null
+++ b/lib/gitlab/diff/parser.rb
@@ -0,0 +1,81 @@
+module Gitlab
+ module Diff
+ class Parser
+ include Enumerable
+
+ def parse(lines)
+ @lines = lines,
+ lines_obj = []
+ line_obj_index = 0
+ line_old = 1
+ line_new = 1
+ type = nil
+
+ lines_arr = ::Gitlab::InlineDiff.processing lines
+
+ lines_arr.each do |line|
+ raw_line = line.dup
+
+ next if filename?(line)
+
+ full_line = html_escape(line.gsub(/\n/, ''))
+ full_line = ::Gitlab::InlineDiff.replace_markers full_line
+
+ if line.match(/^@@ -/)
+ type = "match"
+
+ line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
+ line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
+
+ next if line_old == 1 && line_new == 1 #top of file
+ lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
+ line_obj_index += 1
+ next
+ else
+ type = identification_type(line)
+ lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
+ line_obj_index += 1
+ end
+
+
+ if line[0] == "+"
+ line_new += 1
+ elsif line[0] == "-"
+ line_old += 1
+ else
+ line_new += 1
+ line_old += 1
+ end
+ end
+
+ lines_obj
+ end
+
+ def empty?
+ @lines.empty?
+ end
+
+ private
+
+ def filename?(line)
+ line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
+ '--- /tmp/diffy', '+++ /tmp/diffy')
+ end
+
+ def identification_type(line)
+ if line[0] == "+"
+ "new"
+ elsif line[0] == "-"
+ "old"
+ else
+ nil
+ end
+ end
+
+ def html_escape str
+ replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
+ str.gsub(/[&"'><]/, replacements)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff_parser.rb b/lib/gitlab/diff_parser.rb
deleted file mode 100644
index b244295027e..00000000000
--- a/lib/gitlab/diff_parser.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-module Gitlab
- class DiffParser
- include Enumerable
-
- attr_reader :lines, :new_path
-
- def initialize(lines, new_path = '')
- @lines = lines
- @new_path = new_path
- end
-
- def each
- line_old = 1
- line_new = 1
- type = nil
-
- lines_arr = ::Gitlab::InlineDiff.processing lines
- lines_arr.each do |line|
- raw_line = line.dup
-
- next if filename?(line)
-
- full_line = html_escape(line.gsub(/\n/, ''))
- full_line = ::Gitlab::InlineDiff.replace_markers full_line
-
- if line.match(/^@@ -/)
- type = "match"
-
- line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
- line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
-
- next if line_old == 1 && line_new == 1 #top of file
- yield(full_line, type, nil, line_new, line_old)
- next
- else
- type = identification_type(line)
- line_code = generate_line_code(new_path, line_new, line_old)
- yield(full_line, type, line_code, line_new, line_old, raw_line)
- end
-
-
- if line[0] == "+"
- line_new += 1
- elsif line[0] == "-"
- line_old += 1
- else
- line_new += 1
- line_old += 1
- end
- end
- end
-
- def empty?
- @lines.empty?
- end
-
- private
-
- def filename?(line)
- line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
- '--- /tmp/diffy', '+++ /tmp/diffy')
- end
-
- def identification_type(line)
- if line[0] == "+"
- "new"
- elsif line[0] == "-"
- "old"
- else
- nil
- end
- end
-
- def generate_line_code(path, line_new, line_old)
- "#{Digest::SHA1.hexdigest(path)}_#{line_old}_#{line_new}"
- end
-
- def html_escape str
- replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
- str.gsub(/[&"'><]/, replacements)
- end
- end
-end
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index e6aa3890992..25b5a702f9a 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -10,37 +10,20 @@ module Gitlab
module LDAP
class User < Gitlab::OAuth::User
class << self
- def find_or_create(auth)
- @auth = auth
-
- if uid.blank? || email.blank? || username.blank?
- raise_error("Account must provide a dn, uid and email address")
- end
-
- user = find(auth)
+ def find_or_create(auth_hash)
+ self.auth_hash = auth_hash
+ find(auth_hash) || find_and_connect_by_email(auth_hash) || create(auth_hash)
+ end
- unless user
- # Look for user with same emails
- #
- # Possible cases:
- # * When user already has account and need to link their LDAP account.
- # * LDAP uid changed for user with same email and we need to update their uid
- #
- user = model.find_by(email: email)
+ def find_and_connect_by_email(auth_hash)
+ self.auth_hash = auth_hash
+ user = model.find_by(email: self.auth_hash.email)
- if user
- user.update_attributes(extern_uid: uid, provider: provider)
- log.info("(LDAP) Updating legacy LDAP user #{email} with extern_uid => #{uid}")
- else
- # Create a new user inside GitLab database
- # based on LDAP credentials
- #
- #
- user = create(auth)
- end
+ if user
+ user.update_attributes(extern_uid: auth_hash.uid, provider: auth_hash.provider)
+ Gitlab::AppLogger.info("(LDAP) Updating legacy LDAP user #{self.auth_hash.email} with extern_uid => #{auth_hash.uid}")
+ return user
end
-
- user
end
def authenticate(login, password)
@@ -48,17 +31,8 @@ module Gitlab
# Only check with valid login and password to prevent anonymous bind results
return nil unless ldap_conf.enabled && login.present? && password.present?
- ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf)
- filter = Net::LDAP::Filter.eq(ldap.uid, login)
-
- # Apply LDAP user filter if present
- if ldap_conf['user_filter'].present?
- user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter'])
- filter = Net::LDAP::Filter.join(filter, user_filter)
- end
-
- ldap_user = ldap.bind_as(
- filter: filter,
+ ldap_user = adapter.bind_as(
+ filter: user_filter(login),
size: 1,
password: password
)
@@ -66,10 +40,14 @@ module Gitlab
find_by_uid(ldap_user.dn) if ldap_user
end
- private
+ def adapter
+ @adapter ||= OmniAuth::LDAP::Adaptor.new(ldap_conf)
+ end
+
+ protected
def find_by_uid_and_provider
- find_by_uid(uid)
+ find_by_uid(auth_hash.uid)
end
def find_by_uid(uid)
@@ -88,6 +66,20 @@ module Gitlab
def ldap_conf
Gitlab.config.ldap
end
+
+ def user_filter(login)
+ filter = Net::LDAP::Filter.eq(adapter.uid, login)
+ # Apply LDAP user filter if present
+ if ldap_conf['user_filter'].present?
+ user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter'])
+ filter = Net::LDAP::Filter.join(filter, user_filter)
+ end
+ filter
+ end
+ end
+
+ def needs_blocking?
+ false
end
end
end
diff --git a/lib/gitlab/oauth/auth_hash.rb b/lib/gitlab/oauth/auth_hash.rb
new file mode 100644
index 00000000000..0198f61f427
--- /dev/null
+++ b/lib/gitlab/oauth/auth_hash.rb
@@ -0,0 +1,54 @@
+# Class to parse and transform the info provided by omniauth
+#
+module Gitlab
+ module OAuth
+ class AuthHash
+ attr_reader :auth_hash
+ def initialize(auth_hash)
+ @auth_hash = auth_hash
+ end
+
+ def uid
+ auth_hash.uid.to_s
+ end
+
+ def provider
+ auth_hash.provider
+ end
+
+ def info
+ auth_hash.info
+ end
+
+ def name
+ (info.name || full_name).to_s.force_encoding('utf-8')
+ end
+
+ def full_name
+ "#{info.first_name} #{info.last_name}"
+ end
+
+ def username
+ (info.try(:nickname) || generate_username).to_s.force_encoding('utf-8')
+ end
+
+ def email
+ (info.try(:email) || generate_temporarily_email).downcase
+ end
+
+ def password
+ @password ||= Devise.friendly_token[0, 8].downcase
+ end
+
+ # Get the first part of the email address (before @)
+ # In addtion in removes illegal characters
+ def generate_username
+ email.match(/^[^@]*/)[0].parameterize
+ end
+
+ def generate_temporarily_email
+ "temp-email-for-oauth-#{username}@gitlab.localhost"
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb
index 9670aad2c5d..b768eda185f 100644
--- a/lib/gitlab/oauth/user.rb
+++ b/lib/gitlab/oauth/user.rb
@@ -7,106 +7,78 @@ module Gitlab
module OAuth
class User
class << self
- attr_reader :auth
+ attr_reader :auth_hash
- def find(auth)
- @auth = auth
+ def find(auth_hash)
+ self.auth_hash = auth_hash
find_by_uid_and_provider
end
- def create(auth)
- @auth = auth
- password = Devise.friendly_token[0, 8].downcase
- opts = {
- extern_uid: uid,
- provider: provider,
- name: name,
- username: username,
- email: email,
- password: password,
- password_confirmation: password,
- }
-
- user = model.build_user(opts)
- user.skip_confirmation!
-
- # Services like twitter and github does not return email via oauth
- # In this case we generate temporary email and force user to fill it later
- if user.email.blank?
- user.generate_tmp_oauth_email
- elsif provider != "ldap"
- # Google oauth returns email but dont return nickname
- # So we use part of email as username for new user
- # For LDAP, username is already set to the user's
- # uid/userid/sAMAccountName.
- email_username = email.match(/^[^@]*/)[0]
- # Strip apostrophes since they are disallowed as part of username
- user.username = email_username.gsub("'", "")
- end
-
- begin
- user.save!
- rescue ActiveRecord::RecordInvalid => e
- log.info "(OAuth) Email #{e.record.errors[:email]}. Username #{e.record.errors[:username]}"
- return nil, e.record.errors
- end
-
- log.info "(OAuth) Creating user #{email} from login with extern_uid => #{uid}"
-
- if Gitlab.config.omniauth['block_auto_created_users'] && !ldap?
- user.block
- end
+ def create(auth_hash)
+ user = new(auth_hash)
+ user.save_and_trigger_callbacks
+ end
- user
+ def model
+ ::User
end
- private
+ def auth_hash=(auth_hash)
+ @auth_hash = AuthHash.new(auth_hash)
+ end
+ protected
def find_by_uid_and_provider
- model.where(provider: provider, extern_uid: uid).last
+ model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last
end
+ end
- def uid
- auth.uid.to_s
- end
+ # Instance methods
+ attr_accessor :auth_hash, :user
- def email
- return unless auth.info.respond_to?(:email)
- auth.info.email.downcase unless auth.info.email.nil?
- end
+ def initialize(auth_hash)
+ self.auth_hash = auth_hash
+ self.user = self.class.model.new(user_attributes)
+ user.skip_confirmation!
+ end
- def name
- if auth.info.name.nil?
- "#{auth.info.first_name} #{auth.info.last_name}".force_encoding('utf-8')
- else
- auth.info.name.to_s.force_encoding('utf-8')
- end
- end
+ def auth_hash=(auth_hash)
+ @auth_hash = AuthHash.new(auth_hash)
+ end
- def username
- return unless auth.info.respond_to?(:nickname)
- auth.info.nickname.to_s.force_encoding("utf-8")
- end
+ def save_and_trigger_callbacks
+ user.save!
+ log.info "(OAuth) Creating user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}"
+ user.block if needs_blocking?
- def provider
- auth.provider
- end
+ user
+ rescue ActiveRecord::RecordInvalid => e
+ log.info "(OAuth) Email #{e.record.errors[:email]}. Username #{e.record.errors[:username]}"
+ return nil, e.record.errors
+ end
- def log
- Gitlab::AppLogger
- end
+ def user_attributes
+ {
+ extern_uid: auth_hash.uid,
+ provider: auth_hash.provider,
+ name: auth_hash.name,
+ username: auth_hash.username,
+ email: auth_hash.email,
+ password: auth_hash.password,
+ password_confirmation: auth_hash.password,
+ }
+ end
- def model
- ::User
- end
+ def log
+ Gitlab::AppLogger
+ end
- def raise_error(message)
- raise OmniAuth::Error, "(OAuth) " + message
- end
+ def raise_error(message)
+ raise OmniAuth::Error, "(OAuth) " + message
+ end
- def ldap?
- provider == 'ldap'
- end
+ def needs_blocking?
+ Gitlab.config.omniauth['block_auto_created_users']
end
end
end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index 90511662b20..9dc8b34d9c7 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -14,13 +14,16 @@ module Gitlab
notes.page(page).per(per_page)
when 'blobs'
Kaminari.paginate_array(blobs).page(page).per(per_page)
+ when 'wiki_blobs'
+ Kaminari.paginate_array(wiki_blobs).page(page).per(per_page)
else
super
end
end
def total_count
- @total_count ||= issues_count + merge_requests_count + blobs_count + notes_count
+ @total_count ||= issues_count + merge_requests_count + blobs_count +
+ notes_count + wiki_blobs_count
end
def blobs_count
@@ -31,6 +34,10 @@ module Gitlab
@notes_count ||= notes.count
end
+ def wiki_blobs_count
+ @wiki_blobs_count ||= wiki_blobs.count
+ end
+
private
def blobs
@@ -41,6 +48,20 @@ module Gitlab
end
end
+ def wiki_blobs
+ if project.wiki_enabled?
+ wiki_repo = Repository.new(ProjectWiki.new(project).path_with_namespace)
+
+ if wiki_repo.exists?
+ wiki_repo.search_files(query)
+ else
+ []
+ end
+ else
+ []
+ end
+ end
+
def notes
Note.where(project_id: limit_project_ids).search(query).order('updated_at DESC')
end
diff --git a/lib/gitlab/snippet_search_results.rb b/lib/gitlab/snippet_search_results.rb
new file mode 100644
index 00000000000..938219efdb2
--- /dev/null
+++ b/lib/gitlab/snippet_search_results.rb
@@ -0,0 +1,131 @@
+module Gitlab
+ class SnippetSearchResults < SearchResults
+ attr_reader :limit_snippet_ids
+
+ def initialize(limit_snippet_ids, query)
+ @limit_snippet_ids = limit_snippet_ids
+ @query = query
+ end
+
+ def objects(scope, page = nil)
+ case scope
+ when 'snippet_titles'
+ Kaminari.paginate_array(snippet_titles).page(page).per(per_page)
+ when 'snippet_blobs'
+ Kaminari.paginate_array(snippet_blobs).page(page).per(per_page)
+ else
+ super
+ end
+ end
+
+ def total_count
+ @total_count ||= snippet_titles_count + snippet_blobs_count
+ end
+
+ def snippet_titles_count
+ @snippet_titles_count ||= snippet_titles.count
+ end
+
+ def snippet_blobs_count
+ @snippet_blobs_count ||= snippet_blobs.count
+ end
+
+ private
+
+ def snippet_titles
+ Snippet.where(id: limit_snippet_ids).search(query).order('updated_at DESC')
+ end
+
+ def snippet_blobs
+ search = Snippet.where(id: limit_snippet_ids).search_code(query)
+ search = search.order('updated_at DESC').to_a
+ snippets = []
+ search.each { |e| snippets << chunk_snippet(e) }
+ snippets
+ end
+
+ def default_scope
+ 'snippet_blobs'
+ end
+
+ # Get an array of line numbers surrounding a matching
+ # line, bounded by min/max.
+ #
+ # @returns Array of line numbers
+ def bounded_line_numbers(line, min, max)
+ lower = line - surrounding_lines > min ? line - surrounding_lines : min
+ upper = line + surrounding_lines < max ? line + surrounding_lines : max
+ (lower..upper).to_a
+ end
+
+ # Returns a sorted set of lines to be included in a snippet preview.
+ # This ensures matching adjacent lines do not display duplicated
+ # surrounding code.
+ #
+ # @returns Array, unique and sorted.
+ def matching_lines(lined_content)
+ used_lines = []
+ lined_content.each_with_index do |line, line_number|
+ used_lines.concat bounded_line_numbers(
+ line_number,
+ 0,
+ lined_content.size
+ ) if line.include?(query)
+ end
+
+ used_lines.uniq.sort
+ end
+
+ # 'Chunkify' entire snippet. Splits the snippet data into matching lines +
+ # surrounding_lines() worth of unmatching lines.
+ #
+ # @returns a hash with {snippet_object, snippet_chunks:{data,start_line}}
+ def chunk_snippet(snippet)
+ lined_content = snippet.content.split("\n")
+ used_lines = matching_lines(lined_content)
+
+ snippet_chunk = []
+ snippet_chunks = []
+ snippet_start_line = 0
+ last_line = -1
+
+ # Go through each used line, and add consecutive lines as a single chunk
+ # to the snippet chunk array.
+ used_lines.each do |line_number|
+ if last_line < 0
+ # Start a new chunk.
+ snippet_start_line = line_number
+ snippet_chunk << lined_content[line_number]
+ elsif last_line == line_number - 1
+ # Consecutive line, continue chunk.
+ snippet_chunk << lined_content[line_number]
+ else
+ # Non-consecutive line, add chunk to chunk array.
+ snippet_chunks << {
+ data: snippet_chunk.join("\n"),
+ start_line: snippet_start_line + 1
+ }
+
+ # Start a new chunk.
+ snippet_chunk = [lined_content[line_number]]
+ snippet_start_line = line_number
+ end
+ last_line = line_number
+ end
+ # Add final chunk to chunk array
+ snippet_chunks << {
+ data: snippet_chunk.join("\n"),
+ start_line: snippet_start_line + 1
+ }
+
+ # Return snippet with chunk array
+ { snippet_object: snippet, snippet_chunks: snippet_chunks }
+ end
+
+ # Defines how many unmatching lines should be
+ # included around the matching lines in a snippet
+ def surrounding_lines
+ 3
+ end
+ end
+end