feature/share-libs
rb 225 lines 6.13 KB
Raw
1 class User < ApplicationRecord # rubocop:disable Metrics/ClassLength
2 # Virtual attribute to skip password validation while saving new user from
3 # a wallet connection.
4 attr_accessor :skip_password_validation
5
6 has_merit
7
8 # Include default devise modules. Others available are:
9 # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
10 devise :invitable, :database_authenticatable,
11 :registerable,
12 :confirmable,
13 :recoverable,
14 :rememberable,
15 :validatable,
16 :jwt_authenticatable,
17 jwt_revocation_strategy: JwtDenylist
18
19 before_save { email.downcase! }
20
21 VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d-]+(\.[a-z\d-]+)*\.[a-z]+\z/i
22 validates :email, presence: true,
23 length: { maximum: 255 },
24 format: { with: VALID_EMAIL_REGEX },
25 uniqueness: { case_sensitive: false }
26
27 validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
28 devise :invitable, :omniauthable, omniauth_providers: %i[facebook spotify google_oauth2 apple]
29
30 has_many :chords, dependent: :destroy
31 has_many :lyrics, dependent: :destroy
32 has_many :songs, dependent: :destroy
33 has_many :albums, dependent: :destroy
34 has_many :artists, dependent: :destroy
35 has_many :javanese_gendings, dependent: :destroy
36 has_many :comments, dependent: :delete_all
37
38 # Invitable
39 has_many :invitees, class_name: 'User', foreign_key: :invited_by_id
40
41 scope :all_public, -> { where(is_private: false).all }
42
43 has_many :active_relationships, class_name: 'Relationship',
44 foreign_key: 'follower_id',
45 dependent: :destroy
46 has_many :passive_relationships, class_name: 'Relationship',
47 foreign_key: 'followed_id',
48 dependent: :destroy
49 has_many :following, through: :active_relationships, source: :followed
50 has_many :followers, through: :passive_relationships, source: :follower
51
52 has_many :authorizations, dependent: :destroy
53
54 has_many :song_chord_pleas, dependent: :destroy
55 has_many :javanese_gending_notations, dependent: :destroy
56
57 has_one :user_setting, dependent: :destroy
58 has_many :wallets, dependent: :destroy
59
60 has_many :comments, as: :commentable
61
62 # Follows a user.
63 def follow(other_user)
64 active_relationships.create(followed_id: other_user.id)
65 end
66
67 # Unfollows a user.
68 def unfollow(other_user)
69 active_relationships.find_by(followed_id: other_user.id).destroy
70 end
71
72 # Returns true if the current user is following the other user.
73 def following?(other_user)
74 following.include?(other_user)
75 end
76
77 # Returns the hash digest of the given string.
78 def self.digest(string)
79 cost = if ActiveModel::SecurePassword.min_cost
80 BCrypt::Engine::MIN_COST
81 else
82 BCrypt::Engine.cost
83 end
84 BCrypt::Password.create(string, cost: cost)
85 end
86
87 # Returns a random token
88 def self.new_token
89 SecureRandom.urlsafe_base64
90 end
91
92 # Remembers a user in the database for use in persistent sessions
93 def remember
94 self.remember_token = User.new_token
95 update_attribute(:remember_digest, User.digest(remember_token))
96 end
97
98 # Returns true if the given token matches the digest
99 def authenticated?(remember_token)
100 return false if remember_digest.nil?
101
102 BCrypt::Password.new(remember_digest).is_password?(remember_token)
103 end
104
105 # Forgets a user
106 def forget
107 update_attribute(:remember_digest, nil)
108 end
109
110 # Omniauth helpers
111 def self.new_with_session(params, session)
112 super.tap do |user|
113 if data == session['devise.facebook_data'] && session['devise.facebook_data']['extra']['raw_info'] && user.email.blank?
114 user.email = data['email']
115 end
116 end
117 end
118
119 def self.from_omniauth(auth)
120 return_user = where(email: auth.info.email).first
121 return_user ||= create do |user|
122 user.name = auth.info.name
123 user.email = auth.info.email
124 end
125 save_or_update_provider(return_user, auth)
126 return_user
127 end
128
129 def self.from_omniauth_web3(auth, pubkey_email)
130 return_user = where(email: pubkey_email).first
131 # Throw error if we could not find user
132 raise 'User not found' if return_user.nil?
133
134 save_or_update_provider(return_user, auth)
135 return_user
136 end
137
138 def spotify
139 authorizations.find_by(user_id: id, provider: 'spotify')
140 end
141
142 def google
143 authorizations.find_by(user_id: id, provider: 'google_oauth2')
144 end
145
146 # General helpers
147
148 def email_client
149 email.split('@').last
150 end
151
152 def need_onboarding?
153 username.presence.nil? || need_onboarding_spotify? || need_onboarding_google?
154 end
155
156 def need_onboarding_spotify?
157 (spotify.nil? || spotify&.pending?)
158 end
159
160 def need_onboarding_google?
161 (google.nil? || google&.pending?)
162 end
163
164 def as_json(options = {})
165 options[:methods] = %i[gravatar_url followers_count following_count]
166 super
167 end
168
169 def as_json_packed
170 as_json(only: %i[id email username name about])
171 end
172
173 def followers_count
174 followers.size
175 end
176
177 def following_count
178 following.size
179 end
180
181 def gravatar_url
182 gravatar_id = Digest::MD5.hexdigest(email.downcase)
183 "https://secure.gravatar.com/avatar/#{gravatar_id}"
184 end
185
186 def username_or_id
187 username.presence ? username : id
188 end
189
190 def username_or_name
191 username.presence ? username : name
192 end
193
194 def splitfire_link(item)
195 "#{ENV['SF_HOST']}/@#{username_or_id}/#{item.source_file.filename.to_s.downcase.parameterize}-#{item.id}"
196 end
197
198 def splitfire_profile_link
199 "#{ENV['SF_HOST']}/@#{username_or_id}"
200 end
201
202 def verified?
203 %w[seto splitfire bonzo karokowe bass64 ahmad yovie nowhereman].include? username
204 end
205
206 def reviewer?
207 verified?
208 end
209
210 def self.save_or_update_provider(user, auth)
211 authorization = user.authorizations.find_by(provider: auth.provider, uid: auth.uid)
212 authorization ||= Authorization.new(user_id: user.id, provider: auth.provider, uid: auth.uid)
213 authorization.update_token(auth.credentials.token, auth.credentials.refresh_token)
214 end
215
216 protected
217
218 # Disable password for wallet connection
219
220 def password_required?
221 return false if skip_password_validation
222
223 super
224 end
225 end