Class: Gitlab::GithubImport::UserFinder
- Inherits:
-
Object
- Object
- Gitlab::GithubImport::UserFinder
- Defined in:
- lib/gitlab/github_import/user_finder.rb
Overview
Class that can be used for finding a GitLab user ID based on a GitHub user ID or username.
Any found user IDs are cached in Redis to reduce the number of SQL queries executed over time. Valid keys are refreshed upon access so frequently used keys stick around.
Lookups are cached even if no ID was found to remove the need for querying the database when most queries are not going to return results anyway.
Constant Summary collapse
- ID_CACHE_KEY =
The base cache key to use for caching user IDs for a given GitHub user ID.
'github-import/user-finder/user-id/%s'
- ID_FOR_EMAIL_CACHE_KEY =
The base cache key to use for caching user IDs for a given GitHub email address.
'github-import/user-finder/id-for-email/%s'
- EMAIL_FOR_USERNAME_CACHE_KEY =
The base cache key to use for caching the Email addresses of GitHub usernames.
'github-import/user-finder/email-for-username/%s'
- USERNAME_ETAG_CACHE_KEY =
The base cache key to use for caching the user ETAG response headers
'github-import/user-finder/user-etag/%s'
- EMAIL_FETCHED_FOR_PROJECT_CACHE_KEY =
The base cache key to store whether an email has been fetched for a project
'github-import/user-finder/%{project}/email-fetched/%{username}'
- EMAIL_API_CALL_LOGGING_MESSAGE =
{ true => 'Fetching email from GitHub with ETAG header', false => 'Fetching email from GitHub' }.freeze
Instance Attribute Summary collapse
-
#client ⇒ Object
readonly
Returns the value of attribute client.
-
#project ⇒ Object
readonly
Returns the value of attribute project.
Instance Method Summary collapse
-
#assignee_id_for(issuable) ⇒ Object
Returns the GitLab user ID of an issuable’s assignee.
-
#author_id_for(object, author_key: :author) ⇒ Object
Returns the GitLab user ID of an object’s author.
- #cached_id_for_github_email(email) ⇒ Object
- #cached_id_for_github_id(id) ⇒ Object
- #email_for_github_username(username) ⇒ String, Nil
-
#find(id, username) ⇒ Object
Returns the GitLab ID for the given GitHub ID or username.
-
#find_from_cache(id, email = nil) ⇒ Object
Finds a user ID from the cache for a given GitHub ID or Email.
-
#find_id_from_database(id, email) ⇒ Object
Finds a GitLab user ID from the database for a given GitHub user ID or Email.
-
#id_for_github_email(email) ⇒ Object
Queries and caches the GitLab user ID for a GitHub email, if one was found.
-
#id_for_github_id(id) ⇒ Object
If importing from github.com, queries and caches the GitLab user ID for a GitHub user ID, if one was found.
-
#initialize(project, client) ⇒ UserFinder
constructor
project - An instance of ‘Project` client - An instance of `Gitlab::GithubImport::Client`.
-
#query_id_for_github_email(email) ⇒ Object
rubocop: disable CodeReuse/ActiveRecord.
-
#query_id_for_github_id(id) ⇒ Object
rubocop: disable CodeReuse/ActiveRecord.
-
#read_id_from_cache(key) ⇒ Object
Reads an ID from the cache.
-
#user_id_for(user) ⇒ Object
Returns the GitLab user ID for a GitHub user.
Constructor Details
#initialize(project, client) ⇒ UserFinder
project - An instance of ‘Project` client - An instance of `Gitlab::GithubImport::Client`
44 45 46 47 |
# File 'lib/gitlab/github_import/user_finder.rb', line 44 def initialize(project, client) @project = project @client = client end |
Instance Attribute Details
#client ⇒ Object (readonly)
Returns the value of attribute client.
15 16 17 |
# File 'lib/gitlab/github_import/user_finder.rb', line 15 def client @client end |
#project ⇒ Object (readonly)
Returns the value of attribute project.
15 16 17 |
# File 'lib/gitlab/github_import/user_finder.rb', line 15 def project @project end |
Instance Method Details
#assignee_id_for(issuable) ⇒ Object
Returns the GitLab user ID of an issuable’s assignee.
78 79 80 |
# File 'lib/gitlab/github_import/user_finder.rb', line 78 def assignee_id_for(issuable) user_id_for(issuable[:assignee]) if issuable[:assignee] end |
#author_id_for(object, author_key: :author) ⇒ Object
Returns the GitLab user ID of an object’s author.
If the object has no author ID we’ll use the ID of the GitLab ghost user. object - An instance of ‘Hash` or a `Github::Representer`
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/gitlab/github_import/user_finder.rb', line 54 def (object, author_key: :author) user_info = case when :actor object[:actor] when :assignee object[:assignee] when :requested_reviewer object[:requested_reviewer] when :review_requester object[:review_requester] else object ? object[:author] : nil end id = user_info ? user_id_for(user_info) : GithubImport.ghost_user_id if id [id, true] else [project.creator_id, false] end end |
#cached_id_for_github_email(email) ⇒ Object
163 164 165 |
# File 'lib/gitlab/github_import/user_finder.rb', line 163 def cached_id_for_github_email(email) read_id_from_cache(ID_FOR_EMAIL_CACHE_KEY % email) end |
#cached_id_for_github_id(id) ⇒ Object
159 160 161 |
# File 'lib/gitlab/github_import/user_finder.rb', line 159 def cached_id_for_github_id(id) read_id_from_cache(ID_CACHE_KEY % id) end |
#email_for_github_username(username) ⇒ String, Nil
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/gitlab/github_import/user_finder.rb', line 132 def email_for_github_username(username) email = read_email_from_cache(username) if email.blank? && !email_fetched_for_project?(username) # If an ETAG is available, make an API call with the ETAG. # Only make a rate-limited API call if the ETAG is not available and the email is nil. etag = read_etag_from_cache(username) email = fetch_email_from_github(username, etag: etag) || email cache_email!(username, email) cache_etag!(username) if email.blank? && etag.nil? # If a non-blank email is cached, we don't need the ETAG or project check caches. # Otherwise, indicate that the project has been checked. if email.present? clear_caches!(username) else set_project_as_checked!(username) end end email.presence rescue ::Octokit::NotFound cache_email!(username, '') nil end |
#find(id, username) ⇒ Object
Returns the GitLab ID for the given GitHub ID or username.
id - The ID of the GitHub user. username - The username of the GitHub user.
93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/gitlab/github_import/user_finder.rb', line 93 def find(id, username) email = email_for_github_username(username) cached, found_id = find_from_cache(id, email) return found_id if found_id # We only want to query the database if necessary. If previous lookups # didn't yield a user ID we won't query the database again until the # keys expire. find_id_from_database(id, email) unless cached end |
#find_from_cache(id, email = nil) ⇒ Object
Finds a user ID from the cache for a given GitHub ID or Email.
106 107 108 109 110 111 112 113 114 115 |
# File 'lib/gitlab/github_import/user_finder.rb', line 106 def find_from_cache(id, email = nil) id_exists, id_for_github_id = cached_id_for_github_id(id) return [id_exists, id_for_github_id] if id_for_github_id # Just in case no Email address could be retrieved (for whatever reason) return [false] unless email cached_id_for_github_email(email) end |
#find_id_from_database(id, email) ⇒ Object
Finds a GitLab user ID from the database for a given GitHub user ID or Email.
119 120 121 |
# File 'lib/gitlab/github_import/user_finder.rb', line 119 def find_id_from_database(id, email) id_for_github_id(id) || id_for_github_email(email) end |
#id_for_github_email(email) ⇒ Object
Queries and caches the GitLab user ID for a GitHub email, if one was found.
185 186 187 188 189 |
# File 'lib/gitlab/github_import/user_finder.rb', line 185 def id_for_github_email(email) gitlab_id = query_id_for_github_email(email) || nil Gitlab::Cache::Import::Caching.write(ID_FOR_EMAIL_CACHE_KEY % email, gitlab_id) end |
#id_for_github_id(id) ⇒ Object
If importing from github.com, queries and caches the GitLab user ID for a GitHub user ID, if one was found.
When importing from Github Enterprise, do not query user by Github ID since we only have users’ Github ID from github.com.
172 173 174 175 176 177 178 179 180 181 |
# File 'lib/gitlab/github_import/user_finder.rb', line 172 def id_for_github_id(id) gitlab_id = if project.github_enterprise_import? nil else query_id_for_github_id(id) end Gitlab::Cache::Import::Caching.write(ID_CACHE_KEY % id, gitlab_id) end |
#query_id_for_github_email(email) ⇒ Object
rubocop: disable CodeReuse/ActiveRecord
198 199 200 |
# File 'lib/gitlab/github_import/user_finder.rb', line 198 def query_id_for_github_email(email) User.by_any_email(email).pick(:id) end |
#query_id_for_github_id(id) ⇒ Object
rubocop: disable CodeReuse/ActiveRecord
192 193 194 |
# File 'lib/gitlab/github_import/user_finder.rb', line 192 def query_id_for_github_id(id) User.by_provider_and_extern_uid(:github, id).select(:id).first&.id end |
#read_id_from_cache(key) ⇒ Object
Reads an ID from the cache.
The return value is an Array with two values:
-
A boolean indicating if the key was present or not.
-
The ID as an Integer, or nil in case no ID could be found.
209 210 211 212 213 214 215 216 217 |
# File 'lib/gitlab/github_import/user_finder.rb', line 209 def read_id_from_cache(key) value = Gitlab::Cache::Import::Caching.read(key) exists = !value.nil? number = value.to_i # The cache key may be empty to indicate a previously looked up user for # which we couldn't find an ID. [exists, number > 0 ? number : nil] end |
#user_id_for(user) ⇒ Object
Returns the GitLab user ID for a GitHub user.
user - An instance of ‘Gitlab::GithubImport::Representation::User` or `Hash`.
85 86 87 |
# File 'lib/gitlab/github_import/user_finder.rb', line 85 def user_id_for(user) find(user[:id], user[:login]) if user.present? end |