Class: Libertree::Model::Account
- Inherits:
-
Object
- Object
- Libertree::Model::Account
- Defined in:
- lib/libertree/model/account.rb
Defined Under Namespace
Classes: KeyError
Class Method Summary collapse
-
.authenticate(creds) ⇒ Account
Used by Ramaze::Helper::UserHelper.
- .authenticate_db(creds) ⇒ Object
-
.authenticate_ldap(username, password, settings) ⇒ Object
Authenticates against LDAP.
- .create(*args) ⇒ Object
- .set_auth_settings(type, settings) ⇒ Object
-
.set_up_password_reset_for(email) ⇒ Boolean
True iff password reset was successfully set up.
Instance Method Summary collapse
- #admin? ⇒ Boolean
-
#api_last_used_more_recently_than(time) ⇒ Boolean
Whether or not the API was last used by this account more recently than the given Time.
- #chat_messages_unseen ⇒ Object
- #chat_partners_current ⇒ Object
- #contact_lists ⇒ Object
-
#contacts ⇒ Object
All contacts, from all contact lists TODO: Can we collect this in SQL instead of mapping, etc.
- #contacts_mutual ⇒ Object
- #data_hash ⇒ Object
- #delete_cascade ⇒ Object
-
#dirty ⇒ Object
Clears some memoized data.
- #files ⇒ Object
- #generate_api_token ⇒ Object
- #has_contact_list_by_name_containing_member?(contact_list_name, member) ⇒ Boolean
- #home_river ⇒ Object
- #home_river=(river) ⇒ Object
- #ignore_member(member) ⇒ Object
- #ignored_members ⇒ Object
- #ignoring?(member) ⇒ Boolean
- #invitations_not_accepted ⇒ Object
- #member ⇒ Object
- #messages(opts = {}) ⇒ Object
- #new_invitation ⇒ Object
- #notifications(limit = 128) ⇒ Object
- #notifications_unseen ⇒ Object
-
#notifications_unseen_grouped(max_groups = 5, limit = 200) ⇒ Object
TODO: Is this no longer used?.
- #notify_about(data) ⇒ Object
- #num_chat_unseen ⇒ Object
- #num_chat_unseen_from_partner(member) ⇒ Object
- #num_notifications_unseen ⇒ Object
- #online? ⇒ Boolean
-
#password ⇒ Object
These two password methods provide a seamless interface to the BCrypted password.
- #password=(new_password) ⇒ Object
- #remote_storage_connection ⇒ Object
- #rivers ⇒ Object
- #rivers_appended ⇒ Object
- #rivers_not_appended ⇒ Object
- #settings ⇒ Object
- #subscribe_to(post) ⇒ Object
- #subscribed_to?(post) ⇒ Boolean
- #unignore_member(member) ⇒ Object
- #unsubscribe_from(post) ⇒ Object
-
#validate_and_set_pubkey(key) ⇒ Object
NOTE: this method does not save the account record.
Class Method Details
.authenticate(creds) ⇒ Account
Used by Ramaze::Helper::UserHelper.
31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/libertree/model/account.rb', line 31 def self.authenticate(creds) if @@auth_type && @@auth_type == :ldap return if creds['username'].nil? || creds['password'].nil? self.authenticate_ldap(creds['username'].to_s, creds['password'].to_s, @@auth_settings) else return if creds['password_reset_code'].nil? && (creds['username'].nil? || creds['password'].nil?) self.authenticate_db(creds) end end |
.authenticate_db(creds) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/libertree/model/account.rb', line 43 def self.authenticate_db(creds) if creds['password_reset_code'].to_s account = Account.where( Sequel.lit( %{password_reset_code = ? AND NOW() <= password_reset_expiry}, creds['password_reset_code'].to_s ) ).first if account return account end end account = Account[ username: creds['username'].to_s ] if account && account.password == creds['password'].to_s account end end |
.authenticate_ldap(username, password, settings) ⇒ Object
Authenticates against LDAP. On success returns the matching Libertree account or creates a new one. TODO: override email= and password= methods when LDAP is used
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/libertree/model/account.rb', line 66 def self.authenticate_ldap(username, password, settings) ldap_connection_settings = { :host => settings['connection']['host'], :port => settings['connection']['port'], :base => settings['connection']['base'], :auth => { :method => :simple, :username => settings['connection']['bind_dn'], :password => settings['connection']['password'] } } @ldap ||= Net::LDAP.new(ldap_connection_settings) mapping = settings['mapping'] || { 'username' => 'uid', 'email' => 'mail', 'display_name' => 'displayName' } username.downcase! result = @ldap.bind_as(:filter => "(#{mapping['username']}=#{username})", :password => password) if result account = self[ username: username ] if account # update email address and password account.email = result.first[mapping['email']].first account.password_encrypted = BCrypt::Password.create( password ) account.save else # No Libertree account exists for this authenticated LDAP # user; create a new one. We will set up the password even # though it won't be used while LDAP authentication is # enabled to make sure that the account will be protected if # LDAP authentication is ever disabled. account = self.create( username: username, password_encrypted: BCrypt::Password.create( password ), email: result.first[mapping['email']].first ) end account.member.profile.name_display = result.first[mapping['display_name']].first account.member.profile.save account end end |
.create(*args) ⇒ Object
277 278 279 280 281 282 283 |
# File 'lib/libertree/model/account.rb', line 277 def self.create(*args) account = super member = Member.create( account_id: account.id ) AccountSettings.create( account_id: account.id ) River.create( label: "All posts", query: ":forest", account_id: account.id, home: true ) account end |
.set_auth_settings(type, settings) ⇒ Object
12 13 14 15 |
# File 'lib/libertree/model/account.rb', line 12 def self.set_auth_settings(type, settings) @@auth_type = type @@auth_settings = settings end |
.set_up_password_reset_for(email) ⇒ Boolean
Returns true iff password reset was successfully set up.
370 371 372 373 374 375 376 377 378 379 380 381 382 |
# File 'lib/libertree/model/account.rb', line 370 def self.set_up_password_reset_for(email) # TODO: Don't allow registration of accounts with the same email but different case account = self.where( Sequel.lit('LOWER(email) = ?', email.downcase) ).first if account account.password_reset_code = SecureRandom.hex(16) account.password_reset_expiry = Time.now + 60 * 60 account.save account end end |
Instance Method Details
#admin? ⇒ Boolean
327 328 329 |
# File 'lib/libertree/model/account.rb', line 327 def admin? self.admin end |
#api_last_used_more_recently_than(time) ⇒ Boolean
Returns whether or not the API was last used by this account more recently than the given Time.
313 314 315 |
# File 'lib/libertree/model/account.rb', line 313 def api_last_used_more_recently_than(time) self.api_time_last && self.api_time_last.to_time > time end |
#chat_messages_unseen ⇒ Object
197 198 199 200 201 202 203 204 |
# File 'lib/libertree/model/account.rb', line 197 def ChatMessage.where( to_member_id: self.member.id, seen: false ).exclude( from_member_id: self.ignored_members.map(&:id) ).all end |
#chat_partners_current ⇒ Object
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/libertree/model/account.rb', line 206 def chat_partners_current Member.s_wrap( %{ ( SELECT DISTINCT m.* , EXISTS( SELECT 1 FROM chat_messages cm2 WHERE cm2.from_member_id = cm.from_member_id AND cm2.to_member_id = cm.to_member_id AND cm2.seen = FALSE ) AS has_unseen_from_other FROM chat_messages cm , members m WHERE cm.to_member_id = ? AND ( cm.seen = FALSE OR cm.time_created > NOW() - '1 hour'::INTERVAL ) AND m.id = cm.from_member_id AND NOT EXISTS( SELECT 1 FROM ignored_members im WHERE im.member_id = cm.from_member_id ) ) UNION ( SELECT DISTINCT m.* , EXISTS( SELECT 1 FROM chat_messages cm2 WHERE cm2.from_member_id = cm.to_member_id AND cm2.to_member_id = cm.from_member_id AND cm2.seen = FALSE ) AS has_unseen_from_other FROM chat_messages cm , members m WHERE cm.from_member_id = ? AND cm.time_created > NOW() - '1 hour'::INTERVAL AND m.id = cm.to_member_id AND NOT EXISTS( SELECT 1 FROM ignored_members im WHERE im.member_id = cm.to_member_id ) ) }, self.member.id, self.member.id ) end |
#contact_lists ⇒ Object
436 437 438 |
# File 'lib/libertree/model/account.rb', line 436 def contact_lists ContactList.where(account_id: self.id).all end |
#contacts ⇒ Object
All contacts, from all contact lists TODO: Can we collect this in SQL instead of mapping, etc. in Ruby?
442 443 444 |
# File 'lib/libertree/model/account.rb', line 442 def contacts contact_lists.map { |list| list.members }.flatten.uniq end |
#contacts_mutual ⇒ Object
446 447 448 449 450 |
# File 'lib/libertree/model/account.rb', line 446 def contacts_mutual self.contacts.find_all { |c| c.account && c.account.contacts.include?(self.member) } end |
#data_hash ⇒ Object
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'lib/libertree/model/account.rb', line 408 def data_hash { 'account' => { 'username' => self.username, 'time_created' => self.time_created, 'email' => self.email, 'custom_css' => self.settings.custom_css, 'custom_js' => self.settings.custom_js, 'custom_link' => self.settings.custom_link, 'font_css' => self.font_css, 'excerpt_max_height' => self.settings.excerpt_max_height, 'profile' => { 'name_display' => self.member.profile.name_display, 'description' => self.member.profile.description, }, 'rivers' => self.rivers.map(&:to_hash), 'posts' => self.member.posts(limit: 9999999).map(&:to_hash), 'comments' => self.member.comments(9999999).map(&:to_hash), 'messages' => self.(limit: 9999999).map(&:to_hash), } } end |
#delete_cascade ⇒ Object
457 458 459 460 461 462 463 464 465 466 467 468 |
# File 'lib/libertree/model/account.rb', line 457 def delete_cascade handle = self.username DB.dbh[ "SELECT delete_cascade_account(?)", self.id ].get # distribute deletion of member record Libertree::Model::Job.create_for_forests( { task: 'request:MEMBER-DELETE', params: { 'username' => handle, } } ) end |
#dirty ⇒ Object
Clears some memoized data
318 319 320 321 322 323 324 325 |
# File 'lib/libertree/model/account.rb', line 318 def dirty @notifications = nil @notifications_unseen = nil @num_notifications_unseen = nil @rivers_appended = nil @remote_storage_connection = nil @settings = nil end |
#files ⇒ Object
474 475 476 |
# File 'lib/libertree/model/account.rb', line 474 def files Libertree::Model::File.s("SELECT * FROM files WHERE account_id = ? ORDER BY id DESC", self.id) end |
#generate_api_token ⇒ Object
305 306 307 308 |
# File 'lib/libertree/model/account.rb', line 305 def generate_api_token self.api_token = SecureRandom.hex(16) self.save end |
#has_contact_list_by_name_containing_member?(contact_list_name, member) ⇒ Boolean
452 453 454 455 |
# File 'lib/libertree/model/account.rb', line 452 def has_contact_list_by_name_containing_member?(contact_list_name, member) DB.dbh[ "SELECT account_has_contact_list_by_name_containing_member( ?, ?, ? )", self.id, contact_list_name, member.id ].single_value end |
#home_river ⇒ Object
285 286 287 |
# File 'lib/libertree/model/account.rb', line 285 def home_river River.where(account_id: self.id, home: true).first end |
#home_river=(river) ⇒ Object
289 290 291 |
# File 'lib/libertree/model/account.rb', line 289 def home_river=(river) DB.dbh[ "SELECT account_set_home_river(?,?)", self.id, river.id ].get end |
#ignore_member(member) ⇒ Object
486 487 488 489 |
# File 'lib/libertree/model/account.rb', line 486 def ignore_member(member) return if member.nil? Libertree::Model::IgnoredMember.create(account_id: self.id, member_id: member.id) end |
#ignored_members ⇒ Object
478 479 480 |
# File 'lib/libertree/model/account.rb', line 478 def ignored_members Libertree::Model::IgnoredMember.where(account_id: self.id).map(&:member) end |
#ignoring?(member) ⇒ Boolean
482 483 484 |
# File 'lib/libertree/model/account.rb', line 482 def ignoring?(member) self.ignored_members.include? member end |
#invitations_not_accepted ⇒ Object
293 294 295 296 297 |
# File 'lib/libertree/model/account.rb', line 293 def invitations_not_accepted Invitation.where( Sequel.lit("inviter_account_id = ? AND account_id IS NULL", self.id) ).order(:id).all end |
#member ⇒ Object
114 115 116 |
# File 'lib/libertree/model/account.rb', line 114 def member @member ||= Member[ account_id: self.id ] end |
#messages(opts = {}) ⇒ Object
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/libertree/model/account.rb', line 343 def ( opts = {} ) limit = opts.fetch(:limit, 30) if opts[:newer] time_comparator = '>' else time_comparator = '<' end time = Time.at( opts.fetch(:time, Time.now.to_f) ).strftime("%Y-%m-%d %H:%M:%S.%6N%z") ignored_member_ids = self.ignored_members.map(&:id) Message.s_wrap( %{ SELECT * FROM view__messages_sent_and_received WHERE member_id = ? AND time_created #{time_comparator} ? ORDER BY time_created DESC LIMIT #{limit} }, self.member.id, time ).reject { || ignored_member_ids.include?(.sender_member_id) } end |
#new_invitation ⇒ Object
299 300 301 302 303 |
# File 'lib/libertree/model/account.rb', line 299 def new_invitation if invitations_not_accepted.count < 5 Invitation.create( inviter_account_id: self.id ) end end |
#notifications(limit = 128) ⇒ Object
129 130 131 |
# File 'lib/libertree/model/account.rb', line 129 def notifications( limit = 128 ) @notifications ||= Notification.where(account_id: self.id).reverse_order(:id).limit(limit.to_i).all end |
#notifications_unseen ⇒ Object
133 134 135 |
# File 'lib/libertree/model/account.rb', line 133 def notifications_unseen @notifications_unseen ||= Notification.where(account_id: self.id, seen: false).order(:id) end |
#notifications_unseen_grouped(max_groups = 5, limit = 200) ⇒ Object
TODO: Is this no longer used?
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/libertree/model/account.rb', line 138 def notifications_unseen_grouped(max_groups=5, limit=200) grouped = {} keys = [] # so we have a display order notifs = self.notifications_unseen.reverse_order(:id).limit(limit) notifs.each do |n| next if n.subject.nil? target = case n.subject when Libertree::Model::Comment, Libertree::Model::PostLike n.subject.post when Libertree::Model::CommentLike n.subject.comment when Libertree::Model::Post # mention or group post post = n.subject post.group || post else n.subject end # collect by target and type; we don't want to put comment # and post like notifs in the same bin key = [target, n.subject.class] if grouped[key] grouped[key] << n else grouped[key] = [n] keys << key end end # get the groups in order of keys keys.take(max_groups).map {|k| grouped[k] } end |
#notify_about(data) ⇒ Object
122 123 124 125 126 127 |
# File 'lib/libertree/model/account.rb', line 122 def notify_about(data) Notification.create( account_id: self.id, data: data.to_json ) end |
#num_chat_unseen ⇒ Object
178 179 180 181 182 183 184 185 |
# File 'lib/libertree/model/account.rb', line 178 def num_chat_unseen ChatMessage.where( to_member_id: self.member.id, seen: false ).exclude( from_member_id: self.ignored_members.map(&:id) ).count end |
#num_chat_unseen_from_partner(member) ⇒ Object
187 188 189 190 191 192 193 194 195 |
# File 'lib/libertree/model/account.rb', line 187 def num_chat_unseen_from_partner(member) ChatMessage.where( from_member_id: member.id, to_member_id: self.member.id, seen: false ).exclude( from_member_id: self.ignored_members.map(&:id) ).count end |
#num_notifications_unseen ⇒ Object
174 175 176 |
# File 'lib/libertree/model/account.rb', line 174 def num_notifications_unseen @num_notifications_unseen ||= Notification.where(account_id: self.id, seen: false).count end |
#online? ⇒ Boolean
432 433 434 |
# File 'lib/libertree/model/account.rb', line 432 def online? Time.now - time_heartbeat.to_time < 5.01 * 60 end |
#password ⇒ Object
These two password methods provide a seamless interface to the BCrypted password. The pseudo-field “password” can be treated like a normal String field for reading and writing.
20 21 22 |
# File 'lib/libertree/model/account.rb', line 20 def password @password ||= BCrypt::Password.new(password_encrypted) end |
#password=(new_password) ⇒ Object
24 25 26 27 |
# File 'lib/libertree/model/account.rb', line 24 def password=( new_password ) @password = BCrypt::Password.create(new_password) self.password_encrypted = @password end |
#remote_storage_connection ⇒ Object
470 471 472 |
# File 'lib/libertree/model/account.rb', line 470 def remote_storage_connection @remote_storage_connection ||= RemoteStorageConnection[ account_id: self.id ] end |
#rivers ⇒ Object
265 266 267 |
# File 'lib/libertree/model/account.rb', line 265 def rivers River.s("SELECT * FROM rivers WHERE account_id = ? ORDER BY position ASC, id DESC", self.id) end |
#rivers_appended ⇒ Object
273 274 275 |
# File 'lib/libertree/model/account.rb', line 273 def rivers_appended @rivers_appended ||= rivers.find_all(&:appended_to_all) end |
#rivers_not_appended ⇒ Object
269 270 271 |
# File 'lib/libertree/model/account.rb', line 269 def rivers_not_appended rivers.reject(&:appended_to_all) end |
#settings ⇒ Object
118 119 120 |
# File 'lib/libertree/model/account.rb', line 118 def settings @settings ||= AccountSettings[ account_id: self.id ] end |
#subscribe_to(post) ⇒ Object
331 332 333 |
# File 'lib/libertree/model/account.rb', line 331 def subscribe_to(post) DB.dbh[ %{SELECT subscribe_account_to_post(?,?)}, self.id, post.id ].get end |
#subscribed_to?(post) ⇒ Boolean
339 340 341 |
# File 'lib/libertree/model/account.rb', line 339 def subscribed_to?(post) DB.dbh[ "SELECT account_subscribed_to_post( ?, ? )", self.id, post.id ].single_value end |
#unignore_member(member) ⇒ Object
491 492 493 494 |
# File 'lib/libertree/model/account.rb', line 491 def unignore_member(member) return if member.nil? Libertree::Model::IgnoredMember.where(account_id: self.id, member_id: member.id).delete end |
#unsubscribe_from(post) ⇒ Object
335 336 337 |
# File 'lib/libertree/model/account.rb', line 335 def unsubscribe_from(post) DB.dbh[ "DELETE FROM post_subscriptions WHERE account_id = ? AND post_id = ?", self.id, post.id ].get end |
#validate_and_set_pubkey(key) ⇒ Object
NOTE: this method does not save the account record
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 |
# File 'lib/libertree/model/account.rb', line 385 def validate_and_set_pubkey(key) # import pubkey into temporary keyring to verify it GPGME::Engine.home_dir = Dir.tmpdir result = GPGME::Key.import key.to_s if result.considered == 1 && result.secret_read == 1 # Delete the key immediately from the keyring and # alert the user in case a secret key was uploaded keys = GPGME::Key.find(:secret, result.imports.first.fpr) keys.first.delete!(true) # force deletion of secret key keys = nil; result = nil raise KeyError, 'secret key imported' elsif result.considered == 1 && (result.imported == 1 || result.unchanged == 1) # We do not check whether the key matches the given email address. # This is not necessary, because we don't search the keyring to get # the encryption key when sending emails. Instead, we just take # whatever key the user provided. self.pubkey = key.to_s else raise KeyError, 'invalid key' end end |