self.abstract_class = true
include CurrentApiClient # current_user, current_api_client, etc.
+ include DbCurrentTime
attr_protected :created_at
attr_protected :modified_by_user_uuid
"#{current_api_base}/#{self.class.to_s.pluralize.underscore}/#{self.uuid}"
end
+ def self.selectable_attributes(template=:user)
+ # Return an array of attribute name strings that can be selected
+ # in the given template.
+ api_accessible_attributes(template).map { |attr_spec| attr_spec.first.to_s }
+ end
+
def self.searchable_columns operator
textonly_operator = !operator.match(/[<=>]/)
self.columns.select do |col|
api_column_map
end
+ def self.default_orders
+ ["#{table_name}.modified_at desc", "#{table_name}.uuid"]
+ end
+
# If current user can manage the object, return an array of uuids of
# users and groups that have permission to write the object. The
# first two elements are always [self.owner_uuid, current user's
# If current user cannot write this object, just return
# [self.owner_uuid].
def writable_by
+ return [owner_uuid] if not current_user
unless (owner_uuid == current_user.uuid or
current_user.is_admin or
(current_user.groups_i_can(:manage) & [uuid, owner_uuid]).any?)
- if current_user.groups_i_can(:write).index(uuid)
+ if ((current_user.groups_i_can(:write) + [current_user.uuid]) &
+ [uuid, owner_uuid]).any?
return [owner_uuid, current_user.uuid]
else
return [owner_uuid]
attributes
end
+ def self.full_text_searchable_columns
+ self.columns.select do |col|
+ if col.type == :string or col.type == :text
+ true
+ end
+ end.map(&:name)
+ end
+
+ def self.full_text_tsvector
+ tsvector_str = "to_tsvector('english', "
+ first = true
+ self.full_text_searchable_columns.each do |column|
+ tsvector_str += " || ' ' || " if not first
+ tsvector_str += "coalesce(#{column},'')"
+ first = false
+ end
+ tsvector_str += ")"
+ end
+
protected
def ensure_ownership_path_leads_to_user
end
def update_modified_by_fields
- self.updated_at = Time.now
+ current_time = db_current_time
+ self.updated_at = current_time
self.owner_uuid ||= current_default_owner if self.respond_to? :owner_uuid=
- self.modified_at = Time.now
+ self.modified_at = current_time
self.modified_by_user_uuid = current_user ? current_user.uuid : nil
self.modified_by_client_uuid = current_api_client ? current_api_client.uuid : nil
true
def self.uuid_prefixes
unless @@prefixes_hash
@@prefixes_hash = {}
+ Rails.application.eager_load!
ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |k|
if k.respond_to?(:uuid_prefix)
@@prefixes_hash[k.uuid_prefix] = k
"_____-#{uuid_prefix}-_______________"
end
+ def self.uuid_regex
+ %r/[a-z0-9]{5}-#{uuid_prefix}-[a-z0-9]{15}/
+ end
+
def ensure_valid_uuids
specials = [system_user_uuid]
end
resource_class = nil
- Rails.application.eager_load!
uuid.match HasUuid::UUID_REGEX do |re|
return uuid_prefixes[re[1]] if uuid_prefixes[re[1]]
end
end
def log_start_state
- @old_etag = etag
- @old_attributes = logged_attributes
+ @old_attributes = Marshal.load(Marshal.dump(attributes))
+ @old_logged_attributes = Marshal.load(Marshal.dump(logged_attributes))
end
def log_change(event_type)
log = Log.new(event_type: event_type).fill_object(self)
yield log
log.save!
- connection.execute "NOTIFY logs, '#{log.id}'"
log_start_state
end
def log_update
log_change('update') do |log|
- log.fill_properties('old', @old_etag, @old_attributes)
+ log.fill_properties('old', etag(@old_attributes), @old_logged_attributes)
log.update_to self
end
end
def log_destroy
log_change('destroy') do |log|
- log.fill_properties('old', @old_etag, @old_attributes)
+ log.fill_properties('old', etag(@old_attributes), @old_logged_attributes)
log.update_to nil
end
end