src/api/app/models/concerns/has_attributes.rb
# a model that has attributes - e.g. a project and a package
module HasAttributes
extend ActiveSupport::Concern
class AttributeSaveError < APIError
end
def write_attributes
return unless CONFIG['global_write_through']
project_name = is_a?(Project) ? name : project.name
if is_a?(Package)
Backend::Api::Sources::Package.write_attributes(project_name, name, User.session!.login, render_attribute_axml)
else
Backend::Api::Sources::Project.write_attributes(project_name, User.session!.login, render_attribute_axml)
end
rescue Backend::Error => e
raise AttributeSaveError, e.summary
end
def store_attribute_xml(attrib, binary = nil)
values = []
attrib.elements('value') do |val|
values << val
end
issues = []
attrib.elements('issue') do |i|
issues << Issue.find_or_create_by_name_and_tracker(i['name'], i['tracker'])
end
store_attribute(attrib['namespace'], attrib['name'], values, issues, binary)
end
def store_attribute(namespace, name, values, issues, binary = nil)
# get attrib_type
attrib_type = AttribType.find_by_namespace_and_name!(namespace, name)
# update or create attribute entry
a = find_attribute(namespace, name, binary)
unless a
# create the new attribute
a = Attrib.create(attrib_type: attrib_type, binary: binary)
a.project = self if is_a?(Project)
a.package = self if is_a?(Package)
end
# write values
a.update_with_associations(values, issues)
return unless a.saved_changes?
write_attributes
end
def find_attribute(namespace, name, binary = nil)
raise AttributeFindError, 'Namespace must be given' unless namespace
raise AttributeFindError, 'Name must be given' unless name
raise AttributeFindError, 'binary packages are not allowed in project attributes' if is_a?(Project) && binary
query = attribs.joins(attrib_type: :attrib_namespace)
query = query.where(attrib_types: { name: name },
binary: binary,
attrib_namespaces: { name: namespace })
query.readonly(false).first
end
def render_attribute_axml(opts = {})
builder = Nokogiri::XML::Builder.new
builder.attributes do |xml|
render_main_attributes(xml, opts)
# show project values as fallback ?
project.render_main_attributes(xml, opts) if opts[:with_project]
end
builder.doc.to_xml(indent: 2, encoding: 'UTF-8',
save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION |
Nokogiri::XML::Node::SaveOptions::FORMAT)
end
def render_main_attributes(builder, opts)
attribs.each do |attr|
next unless render?(attr, opts[:attrib_type], opts[:binary])
p = {}
p[:name] = attr.attrib_type.name
p[:namespace] = attr.attrib_type.attrib_namespace.name
p[:binary] = attr.binary if attr.binary
builder.attribute(p) do
if attr.issues.present?
attr.issues.each do |ai|
builder.issue(name: ai.name, tracker: ai.issue_tracker.name)
end
end
render_single_attribute(attr, opts[:with_default], builder)
end
end
end
private
def matches_binary_filter?(filter, binary)
return true unless filter
return false if binary != filter
# switch between all and NULL binary
filter != '' || binary == ''
end
def render?(attr, filter_attrib_type, filter_binary)
return false if filter_attrib_type && !(attr.attrib_type == filter_attrib_type)
matches_binary_filter?(filter_binary, attr.binary)
end
def render_single_attribute(attr, with_default, builder)
if attr.values.empty?
if with_default
attr.attrib_type.default_values.each do |val|
builder.value(val.value)
end
end
else
attr.values.each do |val|
builder.value(val.value)
end
end
end
end