Skip to content

Instantly share code, notes, and snippets.

@litvil
Created January 13, 2016 17:03
Show Gist options
  • Save litvil/26b1e2b6bfdbee2055b0 to your computer and use it in GitHub Desktop.
Save litvil/26b1e2b6bfdbee2055b0 to your computer and use it in GitHub Desktop.
class Neighborhood < ActiveRecord::Base
has_many :requests, :dependent => :destroy, :foreign_key => 'neighborhood_id', :class_name => "NeighborhoodRequests"
before_save :prepare_data
MAX_USERS = 30
TYPE_OPEN = 0
TYPE_REQUEST = 1
TYPE_PRIVATE = 2
JOIN_REQUESTS = 'join'
INVITE_REQUESTS = 'invite'
# params {"emblem":{"icon_image":1,"icon_color":2,"bg_image":3,"bg_color":1,"additional_image":2,"additional_color":3},"level":19,"max_users":30}
# user_roles {"6148904":{"role":3,"claims":{},"banned":0},"-fb_12354":{"role":0,"claims":{},"banned":0}}
def refresh
refresh_avg_level
refresh_activity
end
def refresh_avg_level
by_level = {}
users_hash.each { |user_id, user_hash|
user_hash['level']
by_level[user_hash['level']] ||= 0
by_level[user_hash['level']] += 1
}
max = by_level.values.max
res = Hash[by_level.select { |k, v| v == max}]
self.avg_users_level = if res.size == 1
res.keys.first.to_i
else
avg = res.keys.sum.to_f / res.keys.size.to_f
res.keys.min_by { |x| (x.to_f - avg).abs }
end
end
def emblem
@emblem ||= JSON.parse(params || '{}')['emblem'] || {}
end
def emblem=(val)
@emblem = val
end
def max_users
@max_users ||= JSON.parse(params || '{}')['max_users'].to_i
end
def max_users=(val)
@max_users = val
end
def banned_users
return @banned_users unless @banned_users.nil?
parsed = JSON.parse(data || '{}')['banned_users']
@banned_users = parsed.present? ? parsed : {}
@banned_users
end
def password
@password ||= JSON.parse(params || '{}')['password'].to_s
end
def secured_password
"#{NeighborhoodController.config['secret_room_key']}#{password}"
end
def password=(val)
@password = val
end
def users_hash
@users_hash ||= user_roles.present? ? JSON.parse(user_roles) : {}
end
def users_hash=(new_users)
@users_hash = new_users
end
def join_requests
requests.joins.map{|req| req.user_id}
end
def join_requests_obj
Hash[requests.joins.map{|req| [req.user_id.to_s, req.created_at.to_i]}]
end
def invite_requests
requests.invites.map{|req| req.user_id}
end
def invite_requests_obj
Hash[requests.invites.map{|req| [req.user_id.to_s, req.created_at.to_i]}]
end
def prepare_data
my_params = {}
my_params['emblem'] = emblem
my_params['password'] = password
my_params['max_users'] = max_users if max_users > 0
self.params = my_params.to_json
my_data = {}
my_data['banned_users'] = banned_users
self.data = my_data.to_json
self.user_roles = users_hash.to_json if @users_hash.present?
unless name.present?
self.name = Base64.strict_encode64(Locale.get_translate(NeighborhoodController.config['neighborhood_default_name'], nil, Translation.current_locale))
end
end
def change_role(user_id, new_role)
check_member(user_id)
role = get_role_by_user_id(user_id)
return false if new_role == role
set_role(user_id, new_role.to_i)
end
def check_member(user_id)
raise DZError.new('not a member of neighborhood') unless member?(user_id)
end
def add_user(user, role)
raise DZError.new('user is already in the neighborhood') if users_hash.keys.include?(user.user_id)
@users_hash[user.user_id] = {'role' => -1, 'claims' => {}, 'banned' => 0, 'level' =>user.level}
set_role(user.user_id, role.to_i)
set_level(user.user_id, user.level)
refresh_activity
refresh_invites
restore_ban(user.user_id)
end
def remove_user(user_id)
cache_ban(user_id)
@users_hash.delete(user_id)
refresh_avg_level
refresh_activity
end
def cache_ban(user_id)
if user_banned?(user_id)
banned_users[user_id] = users_hash[user_id]['banned'].to_i
end
end
def restore_ban(user_id)
time = banned_users[user_id].to_i
if time > 0
if time >= Server.current_time.to_i
ban_member(user_id, time)
else
banned_users.delete(user_id)
end
end
end
def refresh_activity
self.activity = (( (max_users.to_f/2.0) - members_count.to_f).abs*100).round
end
def refresh_invites
remove_all_invite_requests if full?
end
def add_join_request(user_id)
requests.joins.for_user(user_id).create!
end
def add_invite_request(user_id)
requests.invites.for_user(user_id).create!
end
def remove_invite_request(user_id)
invites_for_user = requests.invites.for_user(user_id)
return unless invites_for_user.size > 0
invites_for_user.first.destroy
end
def remove_join_request(user_id)
requests_joins_for_user = requests.joins.for_user(user_id)
return unless requests_joins_for_user.size > 0
requests_joins_for_user.first.destroy
end
def remove_all_join_requests
requests.joins.destroy_all
end
def remove_all_invite_requests
requests.invites.destroy_all
end
def remove_all_requests
requests.destroy_all
end
def set_role(user_id, role)
current_count = members_count_by_roles([role])
check_member(user_id)
raise DZError.new("too many users for role #{role}", "users_count = #{current_count}") if current_count >= NeighborhoodController.config['roles'][role]['max_count']
@users_hash[user_id]['role'] = role
end
def set_level(user_id, level)
check_member(user_id)
@users_hash[user_id]['level'] = level.to_i
refresh_avg_level
end
def get_role_by_user_id(user_id)
member?(user_id) ? users_hash[user_id]['role'] : -1
end
def get_first_user_by_role(role)
users_hash.each{|user_id, member|
return user_id if member['role'] == role
}
nil
end
def leader_id
get_first_user_by_role(NeighborhoodMemberRole::ROLE_CREATOR)
end
def get_all_user_by_role(role)
res = []
users_hash.each{|user_id, member|
res.push(user_id) if member['role'] == role
}
res
end
def can_delete?
users_hash.present? && members_count <= 1
end
def has_user_join_request?(user_id)
requests.joins.for_user(user_id).size > 0
end
def has_user_invite_request?(user_id)
requests.invites.for_user(user_id).size > 0
end
def members_count
users_hash.size
end
def members_count_by_roles(roles)
members_by_roles(roles).size
end
def members_by_roles(roles_array)
users_hash.select { |id, member| roles_array.include?(member['role']) }
end
def type_open?
neighborhood_type == TYPE_OPEN
end
def type_request?
neighborhood_type == TYPE_REQUEST
end
def type_private?
neighborhood_type == TYPE_PRIVATE
end
def symbol_type
case neighborhood_type
when TYPE_OPEN
return :type_open
when TYPE_PRIVATE
return :type_private
when TYPE_REQUEST
return :type_request
else
nil
end
end
def has_free_space?
members_count < max_users
end
def free_space_count
max_users - members_count
end
def full?
!has_free_space?
end
def member?(user_id)
users_hash.has_key?(user_id)
end
def has_role?(user_id, role)
users_hash[user_id].present? && users_hash[user_id]['role'] == role
end
def ban_member(user_id, time)
check_member(user_id)
users_hash[user_id]['banned'] = time.to_i
users_hash[user_id]['claims'] = {}
end
def unban_member(user_id)
check_member(user_id)
users_hash[user_id]['banned'] = 0
users_hash[user_id]['claims'] = {}
end
def user_banned?(user_id)
users_hash[user_id].present? && users_hash[user_id]['banned'].to_i >= Server.current_time.to_i
end
def has_claim?(sad_user_id, target_user_id)
users_hash[target_user_id].present? && users_hash[target_user_id]['claims'].has_key?(sad_user_id)
end
def add_claim(sad_user_id, target_user_id)
@users_hash[target_user_id]['claims'][sad_user_id] = Server.current_time.to_i
end
def delete_claim(sad_user_id, target_user_id)
@users_hash[target_user_id]['claims'].delete(sad_user_id)
end
def claims_count(target_user_id)
users_hash[target_user_id]['claims'].size rescue 0
end
def server_config
{
'active' => Chat::SFS_CONFIG['chat_active'][shard_number],
'host' => Chat::SFS_CONFIG['chat_address'][shard_number],
'zone' => Chat::SFS_CONFIG['chat_zone'][shard_number]
}
end
def shard_number
Chat.get_shard_number(id)
end
def to_client
{
'id' => id,
'name' => Base64.strict_encode64(name),
'descr' => description,
'emblem' => emblem,
'level' => level || NeighborhoodController.config['min_level'],
'max_users' => max_users,
'users' => users_hash,
'lang' => lang,
'avg_users_level' => avg_users_level,
'type' => neighborhood_type
}
end
def my_to_client
{
'id' => id,
'name' => Base64.strict_encode64(name),
'descr' => description,
'emblem' => emblem,
'level' => level || NeighborhoodController.config['min_level'],
'max_users' => max_users,
'server_config' => server_config,
'password' => password,
'users' => users_hash,
'type' => neighborhood_type,
'avg_users_level' => avg_users_level,
'activity' => activity,
'lang' => lang,
'joins' => join_requests_obj,
'invites' => invite_requests_obj
}
end
def self.from_hash(hash)
hood = Neighborhood.new
hash.each{|key, val|
hood[key]=val if hood.respond_to?(key.to_sym)
}
hood
end
end
class NeighborhoodRequests < ActiveRecord::Base
INVITE_TYPE = 0
JOIN_TYPE = 1
belongs_to :neighborhood
named_scope :for_user, lambda { |user_id| { :conditions => { :user_id => user_id.to_s } } }
named_scope :invites, {:conditions => {:request_type => INVITE_TYPE}, :order =>'created_at ASC'}
named_scope :joins, {:conditions => {:request_type => JOIN_TYPE}, :order =>'created_at ASC'}
named_scope :for_neighborhood, lambda { |hood_id| { :conditions => { :neighborhood_id => hood_id.to_i } } }
named_scope :for_neighborhoods, lambda { |hood_ids| { :conditions => { :neighborhood_id => hood_ids } } }
named_scope :for_users, lambda { |user_ids| { :conditions => { :user_id => user_ids } } }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment