Newer
Older
# Copyright (c) 2010-2011, Diaspora Inc. This file is
# licensed under the Affero General Public License version 3 or later. See
Daniel Vincent Grippi
a validé
include Connecting
include Querying
include SocialActions
apply_simple_captcha :message => I18n.t('simple_captcha.message.failed'), :add_to_base => true
scope :logged_in_since, ->(time) { where('last_seen > ?', time) }
scope :monthly_actives, ->(time = Time.now) { logged_in_since(time - 1.month) }
scope :daily_actives, ->(time = Time.now) { logged_in_since(time - 1.day) }
scope :yearly_actives, ->(time = Time.now) { logged_in_since(time - 1.year) }
scope :halfyear_actives, ->(time = Time.now) { logged_in_since(time - 6.month) }
scope :active, -> { joins(:person).where(people: {closed_account: false}).where.not(username: nil) }
Devendra
a validé
devise :token_authenticatable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:lockable, :lastseenable, :lock_strategy => :none, :unlock_strategy => :none
before_validation :strip_and_downcase_username
before_validation :set_default_color_theme, on: :create
validates :username, :presence => true, :uniqueness => true
validates_format_of :username, :with => /\A[A-Za-z0-9_]+\z/
validates_length_of :username, :maximum => 32
validates_exclusion_of :username, :in => AppConfig.settings.username_blacklist
validates_inclusion_of :language, :in => AVAILABLE_LANGUAGE_CODES
validates :color_theme, inclusion: {in: AVAILABLE_COLOR_THEME_CODES}, allow_blank: true
validates_format_of :unconfirmed_email, :with => Devise.email_regexp, :allow_blank => true
validates_presence_of :person, :unless => proc {|user| user.invitation_token.present?}
validates_associated :person
Maxwell Salzberg
a validé
validate :no_person_with_same_username
serialize :hidden_shareables, Hash
has_one :person, inverse_of: :owner, foreign_key: :owner_id
has_one :profile, through: :person
delegate :guid, :public_key, :posts, :photos, :owns?, :image_url,
:diaspora_handle, :name, :atom_url, :profile_url, :profile, :url,
:first_name, :last_name, :gender, :participations, to: :person
delegate :id, :guid, to: :person, prefix: true
has_many :invitations_from_me, :class_name => 'Invitation', :foreign_key => :sender_id
has_many :invitations_to_me, :class_name => 'Invitation', :foreign_key => :recipient_id
has_many :aspects, -> { order('order_id ASC') }
belongs_to :auto_follow_back_aspect, :class_name => 'Aspect'
belongs_to :invited_by, :class_name => 'User'
has_many :aspect_memberships, :through => :aspects
Sarah Mei
a validé
has_many :contacts
has_many :contact_people, :through => :contacts, :source => :person
Sarah Mei
a validé
has_many :services
Sarah Mei
a validé
has_many :user_preferences
Sarah Mei
a validé
has_many :tag_followings
has_many :followed_tags, -> { order('tags.name') }, :through => :tag_followings, :source => :tag
Sarah Mei
a validé
Sarah Mei
a validé
has_many :ignored_people, :through => :blocks, :source => :person
has_many :conversation_visibilities, through: :person
has_many :conversations, through: :conversation_visibilities
Ilya Zhitomirskiy
a validé
has_many :pairwise_pseudonymous_identifiers, class_name: "Api::OpenidConnect::PairwisePseudonymousIdentifier"
has_many :authorizations, class_name: "Api::OpenidConnect::Authorization"
has_many :o_auth_applications, through: :authorizations, class_name: "Api::OpenidConnect::OAuthApplication"
has_many :share_visibilities
danielgrippi
a validé
def self.all_sharing_with_person(person)
User.joins(:contacts).where(:contacts => {:person_id => person.id})
end
def unread_notifications
notifications.where(:unread => true)
end
def unread_message_count
ConversationVisibility.where(person_id: self.person_id).sum(:unread)
Maxwell Salzberg
a validé
#@deprecated
def ugly_accept_invitation_code
begin
self.invitations_to_me.first.sender.invitation_code
rescue Exception => e
nil
def process_invite_acceptence(invite)
self.invited_by = invite.user
invite.use!
danielgrippi
a validé
end
InvitationCode.find_or_create_by(user_id: self.id)
121
122
123
124
125
126
127
128
129
130
131
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
158
159
160
161
162
163
164
165
166
167
168
def hidden_shareables
self[:hidden_shareables] ||= {}
end
def add_hidden_shareable(key, share_id, opts={})
if self.hidden_shareables.has_key?(key)
self.hidden_shareables[key] << share_id
else
self.hidden_shareables[key] = [share_id]
end
self.save unless opts[:batch]
self.hidden_shareables
end
def remove_hidden_shareable(key, share_id)
if self.hidden_shareables.has_key?(key)
self.hidden_shareables[key].delete(share_id)
end
end
def is_shareable_hidden?(shareable)
shareable_type = shareable.class.base_class.name
if self.hidden_shareables.has_key?(shareable_type)
self.hidden_shareables[shareable_type].include?(shareable.id.to_s)
else
false
end
end
def toggle_hidden_shareable(share)
share_id = share.id.to_s
key = share.class.base_class.to_s
if self.hidden_shareables.has_key?(key) && self.hidden_shareables[key].include?(share_id)
self.remove_hidden_shareable(key, share_id)
self.save
false
else
self.add_hidden_shareable(key, share_id)
self.save
true
end
end
def has_hidden_shareables_of_type?(t = Post)
share_type = t.base_class.to_s
self.hidden_shareables[share_type].present?
end
# Copy the method provided by Devise to be able to call it later
# from a Sidekiq job
alias_method :send_reset_password_instructions!, :send_reset_password_instructions
def send_reset_password_instructions
end
def update_user_preferences(pref_hash)
UserPreference::VALID_EMAIL_TYPES.each{|x| self.user_preferences.find_or_create_by(email_type: x)}
self.disable_mail = false
self.save
Raphael Sofaer
a validé
pref_hash.keys.each do |key|
if pref_hash[key] == 'true'
self.user_preferences.find_or_create_by(email_type: key)
else
block = self.user_preferences.where(:email_type => key).first
if block
block.destroy
end
end
end
end
def strip_and_downcase_username
if username.present?
username.strip!
username.downcase!
end
end
def disable_getting_started
self.update_attribute(:getting_started, false) if self.getting_started?
end
def set_current_language
self.language = I18n.locale.to_s if self.language.blank?
end
self.color_theme ||= AppConfig.settings.default_color_theme
# This override allows a user to enter either their email address or their username into the username field.
# @return [User] The user that matches the username/email condition.
# @return [nil] if no user matches that condition.
def self.find_for_database_authentication(conditions={})
conditions = conditions.dup
conditions[:username] = conditions[:username].downcase
if conditions[:username] =~ /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i # email regex
conditions[:email] = conditions.delete(:username)
end
where(conditions).first
def confirm_email(token)
return false if token.blank? || token != confirm_email_token
self.email = unconfirmed_email
save
end
######## Posting ########
def build_post(class_name, opts={})
model_class = class_name.to_s.camelize.constantize
model_class.diaspora_initialize(opts)
def dispatch_post(post, opts={})
logger.info "user:#{id} dispatching #{post.class}:#{post.guid}"
Diaspora::Federation::Dispatcher.defer_dispatch(self, post, opts)
def update_post(post, post_hash={})
if self.owns? post
post.update_attributes(post_hash)
self.dispatch_post(post)
end
end
def add_to_streams(post, aspects_to_insert)
aspects_to_insert.each do |aspect|
end
end
def aspects_from_ids(aspect_ids)
if aspect_ids == "all" || aspect_ids == :all
self.aspects
else
end
end
maxwell
a validé
def salmon(post)
Salmon::EncryptedSlap.create_by_user_and_activity(self, post.to_diaspora_xml)
maxwell
a validé
end
# Check whether the user has liked a post.
def liked?(target)
if target.likes.loaded?
if self.like_for(target)
Like.exists?(:author_id => self.person.id, :target_type => target.class.base_class.to_s, :target_id => target.id)
Raphael Sofaer
a validé
# Get the user's like of a post, if there is one.
def like_for(target)
if target.likes.loaded?
return target.likes.detect{ |like| like.author_id == self.person.id }
return Like.where(:author_id => self.person.id, :target_type => target.class.base_class.to_s, :target_id => target.id).first
MrZYX
a validé
end
end
######### Data export ##################
mount_uploader :export, ExportedUser
def queue_export
update exporting: true
Workers::ExportUser.perform_async(id)
end
def perform_export!
export = Tempfile.new([username, '.json.gz'], encoding: 'ascii-8bit')
export.write(compressed_export) && export.close
if export.present?
update exporting: false, export: export, exported_at: Time.zone.now
else
update exporting: false
end
end
def compressed_export
ActiveSupport::Gzip.compress Diaspora::Exporter.new(self).execute
end
######### Photos export ##################
mount_uploader :exported_photos_file, ExportedPhotos
def queue_export_photos
update exporting_photos: true
Workers::ExportPhotos.perform_async(id)
end
def perform_export_photos!
temp_zip = Tempfile.new([username, '_photos.zip'])
begin
Zip::OutputStream.open(temp_zip.path) do |zos|
photo_file = photo.unprocessed_image.file
if photo_file
photo_data = photo_file.read
zos.put_next_entry(photo.remote_photo_name)
zos.print(photo_data)
else
logger.info "Export photos error: No file for #{photo.remote_photo_name} not found"
end
rescue Errno::ENOENT
logger.info "Export photos error: #{photo.unprocessed_image.file.path} not found"
end
end
end
ensure
temp_zip.close
end
begin
update exported_photos_file: temp_zip, exported_photos_at: Time.zone.now if temp_zip.present?
ensure
restore_attributes if invalid? || temp_zip.present?
update exporting_photos: false
end
end
######### Mailer #######################
def mail(job, *args)
pref = job.to_s.gsub('Workers::Mail::', '').underscore
maxwell
a validé
if(self.disable_mail == false && !self.user_preferences.exists?(:email_type => pref))
end
end
def send_confirm_email
return if unconfirmed_email.blank?
######### Posts and Such ###############
def retract(target)
retraction = Retraction.for(target, self)
retraction.defer_dispatch(self)
end
########### Profile ######################
def update_profile(params)
if photo = params.delete(:photo)
photo.update_attributes(:pending => false) if photo.pending
params[:image_url] = photo.url(:thumb_large)
params[:image_url_medium] = photo.url(:thumb_medium)
params[:image_url_small] = photo.url(:thumb_small)
Maxwell Salzberg
a validé
params.stringify_keys!
params.slice!(*(Profile.column_names+['tag_string', 'date']))
if self.profile.update_attributes(params)
Jonne Haß
a validé
deliver_profile_update
true
else
false
end
end
def update_profile_with_omniauth( user_info )
update_profile( self.profile.from_omniauth_hash( user_info ) )
end
def deliver_profile_update(opts={})
Diaspora::Federation::Dispatcher.defer_dispatch(self, profile, opts)
Jonne Haß
a validé
end
def basic_profile_present?
tag_followings.any? || profile[:image_url]
end
###Helpers############
def self.build(opts = {})
u.setup(opts)
u
end
def setup(opts)
self.username = opts[:username]
self.language = opts[:language]
self.language ||= I18n.locale.to_s
self.color_theme ||= AppConfig.settings.default_color_theme
self.valid?
errors = self.errors
errors.delete :person
return if errors.size > 0
self.set_person(Person.new((opts[:person] || {}).except(:id)))
self
end
Maxwell Salzberg
a validé
def set_person(person)
Maxwell Salzberg
a validé
person.diaspora_handle = "#{self.username}#{User.diaspora_id_host}"
Maxwell Salzberg
a validé
self.person = person
end
Maxwell Salzberg
a validé
def self.diaspora_id_host
"@#{AppConfig.bare_pod_uri}"
end
def seed_aspects
self.aspects.create(:name => I18n.t('aspects.seed.family'))
self.aspects.create(:name => I18n.t('aspects.seed.friends'))
self.aspects.create(:name => I18n.t('aspects.seed.work'))
aq = self.aspects.create(:name => I18n.t('aspects.seed.acquaintances'))
if AppConfig.settings.autofollow_on_join?
default_account = Person.find_or_fetch_by_identifier(AppConfig.settings.autofollow_on_join_user)
self.share_with(default_account, aq) if default_account
end
def send_welcome_message
return unless AppConfig.settings.welcome_message.enabled? && AppConfig.admins.account?
sender_username = AppConfig.admins.account.get
sender = User.find_by(username: sender_username)
conversation = sender.build_conversation(
participant_ids: [sender.person.id, person.id],
subject: AppConfig.settings.welcome_message.subject.get,
message: {text: AppConfig.settings.welcome_message.text.get % {username: username}}
)
Diaspora::Federation::Dispatcher.build(sender, conversation).dispatch if conversation.save
end
def encryption_key
OpenSSL::PKey::RSA.new(serialized_private_key)
end
def admin?
Role.is_admin?(self.person)
end
def podmin_account?
username == AppConfig.admins.account
end
def mine?(target)
if target.present? && target.respond_to?(:user_id)
return self.id == target.user_id
end
false
end
# Ensure that the unconfirmed email isn't already someone's email
def unconfirmed_email_quasiuniqueness
if User.exists?(["id != ? AND email = ?", id, unconfirmed_email])
errors.add(:unconfirmed_email, I18n.t("errors.messages.taken"))
end
end
def guard_unconfirmed_email
self.unconfirmed_email = nil if unconfirmed_email.blank? || unconfirmed_email == email
Raphael Sofaer
a validé
if unconfirmed_email_changed?
self.confirm_email_token = unconfirmed_email ? SecureRandom.hex(15) : nil
# Whenever email is set, clear all unconfirmed emails which match
def remove_invalid_unconfirmed_emails
User.where(unconfirmed_email: email).update_all(unconfirmed_email: nil) if email_changed?
end
# Generate public/private keys for User and associated Person
def generate_keys
self.serialized_private_key = OpenSSL::PKey::RSA.generate(key_size).to_s if serialized_private_key.blank?
if self.person && self.person.serialized_public_key.blank?
self.person.serialized_public_key = OpenSSL::PKey::RSA.new(self.serialized_private_key).public_key.to_s
Maxwell Salzberg
a validé
def no_person_with_same_username
Maxwell Salzberg
a validé
diaspora_id = "#{self.username}#{User.diaspora_id_host}"
Maxwell Salzberg
a validé
if self.username_changed? && Person.exists?(:diaspora_handle => diaspora_id)
errors[:base] << 'That username has already been taken'
end
end
Ilya Zhitomirskiy
a validé
self.person.lock_access!
self.lock_access!
Ilya Zhitomirskiy
a validé
end
def closed_account?
self.person.closed_account
end
Ilya Zhitomirskiy
a validé
def clear_account!
clearable_fields.each do |field|
self[field] = nil
end
[:getting_started,
:show_community_spotlight_in_stream].each do |field|
self[field] = false
end
self[:email] = "deletedaccount_#{self[:id]}@example.org"
Ilya Zhitomirskiy
a validé
random_password = SecureRandom.hex(20)
Ilya Zhitomirskiy
a validé
self.password = random_password
self.password_confirmation = random_password
self.save(:validate => false)
def sign_up
if AppConfig.settings.captcha.enable?
save_with_captcha
else
save
end
end
def flag_for_removal(remove_after)
# flag inactive user for future removal
if AppConfig.settings.maintenance.remove_old_users.enable?
self.remove_after = remove_after
self.save
end
end
def after_database_authentication
# remove any possible remove_after timestamp flag set by maintenance.remove_old_users
unless self.remove_after.nil?
self.remove_after = nil
self.save
end
end
attributes.keys - %w(id username encrypted_password created_at updated_at locked_at
serialized_private_key getting_started
disable_mail show_community_spotlight_in_stream
strip_exif email remove_after export exporting exported_at
exported_photos_file exporting_photos exported_photos_at)