mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
Add xml writer
This commit is contained in:
@@ -204,6 +204,9 @@ group :test do
|
||||
gem 'retriable', '~> 3.1.1'
|
||||
gem 'rspec-retry', '~> 0.6.1'
|
||||
|
||||
# XML comparison tests
|
||||
gem 'compare-xml', '~> 0.66', require: false
|
||||
|
||||
gem 'rspec-example_disabler', git: 'https://github.com/finnlabs/rspec-example_disabler.git'
|
||||
|
||||
# brings back testing for 'assigns' and 'assert_template' extracted in rails 5
|
||||
|
||||
@@ -397,6 +397,8 @@ GEM
|
||||
colored2 (3.1.2)
|
||||
commonmarker (0.20.1)
|
||||
ruby-enum (~> 0.5)
|
||||
compare-xml (0.66)
|
||||
nokogiri (~> 1.8)
|
||||
concurrent-ruby (1.1.5)
|
||||
cork (0.3.0)
|
||||
colored2 (~> 3.1)
|
||||
@@ -969,6 +971,7 @@ DEPENDENCIES
|
||||
cells-erb (~> 0.1.0)
|
||||
cells-rails (~> 0.0.9)
|
||||
commonmarker (~> 0.20.1)
|
||||
compare-xml (~> 0.66)
|
||||
cucumber (~> 3.1.0)
|
||||
cucumber-rails (~> 1.8.0)
|
||||
daemons
|
||||
|
||||
@@ -19,6 +19,10 @@ module Bcf
|
||||
end
|
||||
end
|
||||
|
||||
def imported_title
|
||||
markup_doc.xpath('//Topic/Title').text
|
||||
end
|
||||
|
||||
def markup_doc
|
||||
@markup_doc ||= Nokogiri::XML markup, nil, 'UTF-8'
|
||||
end
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
<% highlighting_class << ' -failed' if issue.errors.present? %>
|
||||
<div class="<%= highlighting_class %>">
|
||||
<p>
|
||||
<strong><%= issue.title %></strong>
|
||||
<br/>
|
||||
<% if issue.work_package %>
|
||||
<%= link_to_work_package(issue.work_package) %>
|
||||
<br/>
|
||||
<% else %>
|
||||
<%= issue.imported_title %>
|
||||
<% end %>
|
||||
</p>
|
||||
<% if issue.errors.present? %>
|
||||
|
||||
@@ -8,7 +8,7 @@ class MigrateXmlViewpointToJson < ActiveRecord::Migration[6.0]
|
||||
# Convert viewpoints
|
||||
::Bcf::Viewpoint.reset_column_information
|
||||
::Bcf::Viewpoint.find_each do |resource|
|
||||
mapper = ::OpenProject::Bcf::BcfJson::ViewpointMapper
|
||||
mapper = ::OpenProject::Bcf::BcfJson::ViewpointReader
|
||||
.new(resource.uuid, resource.viewpoint)
|
||||
|
||||
resource.update_column(:json_viewpoint, mapper.result)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
module OpenProject::Bcf
|
||||
module BcfJson
|
||||
class ViewpointMapper
|
||||
class ViewpointReader
|
||||
ROOT_NODE ||= 'VisualizationInfo'.freeze
|
||||
|
||||
attr_reader :uuid, :xml
|
||||
@@ -0,0 +1,67 @@
|
||||
##
|
||||
# Creates or updates a BCF issue and markup from a work package
|
||||
module OpenProject::Bcf::BcfXml
|
||||
class BaseWriter
|
||||
attr_reader :markup_doc
|
||||
|
||||
def initialize
|
||||
@markup_doc = build_markup_document
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def root_node
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def root_node_attributes
|
||||
{}
|
||||
end
|
||||
|
||||
##
|
||||
# Initial markup file as basic BCF compliant xml
|
||||
def build_markup_document
|
||||
Nokogiri::XML::Builder
|
||||
.new(:encoding => 'UTF-8') do |xml|
|
||||
xml.comment created_by_comment
|
||||
xml.send(root_node,
|
||||
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
||||
"xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
|
||||
**root_node_attributes)
|
||||
end
|
||||
.doc
|
||||
end
|
||||
|
||||
def prepend_into_or_insert(parent_node, node)
|
||||
if first_child = parent_node.children.select(&:element?)&.first
|
||||
first_child.previous = node
|
||||
else
|
||||
node.parent = parent_node
|
||||
end
|
||||
end
|
||||
|
||||
def fetch(parent_node, name)
|
||||
node = parent_node.at(name) || Nokogiri::XML::Node.new(name, markup_doc)
|
||||
node.parent = parent_node unless node.parent.present?
|
||||
node
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
def created_by_comment
|
||||
" Created by #{Setting.app_title} #{OpenProject::VERSION} at #{Time.now} "
|
||||
end
|
||||
|
||||
def to_bcf_datetime(date_time)
|
||||
date_time.utc.iso8601
|
||||
end
|
||||
|
||||
def to_bcf_date(date)
|
||||
date.iso8601
|
||||
end
|
||||
|
||||
def url_helpers
|
||||
@url_helpers ||= OpenProject::StaticRouting::StaticUrlHelpers.new
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -131,7 +131,7 @@ module OpenProject::Bcf::BcfXml
|
||||
snapshot_file = File.join(issue_dir, vp.snapshot.filename)
|
||||
|
||||
# Copy the files
|
||||
dump_file vp_file, vp.viewpoint
|
||||
dump_file vp_file, ViewpointWriter.new(vp).to_xml
|
||||
FileUtils.cp vp.snapshot.local_path, snapshot_file
|
||||
|
||||
files << vp_file << snapshot_file
|
||||
|
||||
@@ -193,7 +193,7 @@ module OpenProject::Bcf::BcfXml
|
||||
uuid: vp[:uuid],
|
||||
|
||||
# Save the viewpoint as json
|
||||
viewpoint: viewpoint_as_json(vp[:uuid], vp[:viewpoint]),
|
||||
json_viewpoint: viewpoint_as_json(vp[:uuid], read_entry(vp[:viewpoint])),
|
||||
viewpoint_name: vp[:viewpoint],
|
||||
|
||||
# Save the snapshot as file attachment
|
||||
@@ -238,9 +238,9 @@ module OpenProject::Bcf::BcfXml
|
||||
##
|
||||
# Map the xml viewpoint as json
|
||||
def viewpoint_as_json(uuid, xml)
|
||||
::OpenProject::Bcf::BcfJson::ViewpointMapper
|
||||
::OpenProject::Bcf::BcfJson::ViewpointReader
|
||||
.new(uuid, xml)
|
||||
.to_json
|
||||
.result
|
||||
end
|
||||
|
||||
def new_comment(comment_data)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
##
|
||||
# Creates or updates a BCF issue and markup from a work package
|
||||
module OpenProject::Bcf::BcfXml
|
||||
class IssueWriter
|
||||
class IssueWriter < BaseWriter
|
||||
attr_reader :work_package, :issue, :markup_doc, :markup_node
|
||||
|
||||
TOPIC_SEQUENCE = [
|
||||
@@ -34,11 +34,11 @@ module OpenProject::Bcf::BcfXml
|
||||
@work_package = work_package
|
||||
@issue = find_or_initialize_issue
|
||||
|
||||
# Read the existing markup XML or build an empty one
|
||||
@markup_doc = build_markup_document
|
||||
# Create markup document
|
||||
super()
|
||||
|
||||
# Remember root markup node for easier access
|
||||
@markup_node = @markup_doc.at_xpath('/Markup')
|
||||
@markup_node = markup_doc.at_xpath('/Markup')
|
||||
end
|
||||
|
||||
def update
|
||||
@@ -58,7 +58,11 @@ module OpenProject::Bcf::BcfXml
|
||||
issue.save!
|
||||
end
|
||||
|
||||
private
|
||||
protected
|
||||
|
||||
def root_node
|
||||
:Markup
|
||||
end
|
||||
|
||||
##
|
||||
# Get the nokogiri document from the markup xml
|
||||
@@ -66,16 +70,7 @@ module OpenProject::Bcf::BcfXml
|
||||
if issue.markup
|
||||
Nokogiri::XML issue.markup, &:noblanks
|
||||
else
|
||||
build_initial_markup_xml.doc
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Initial markup file as basic BCF compliant xml
|
||||
def build_initial_markup_xml
|
||||
Nokogiri::XML::Builder.new do |xml|
|
||||
xml.comment created_by_comment
|
||||
xml.Markup "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema"
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
@@ -124,12 +119,6 @@ module OpenProject::Bcf::BcfXml
|
||||
end
|
||||
end
|
||||
|
||||
def fetch(parent_node, name)
|
||||
node = parent_node.at(name) || Nokogiri::XML::Node.new(name, markup_doc)
|
||||
node.parent = parent_node unless node.parent.present?
|
||||
node
|
||||
end
|
||||
|
||||
def topic_attributes(topic_node)
|
||||
topic_node['Guid'] = issue.uuid
|
||||
topic_node['TopicType'] = work_package.type.name # TODO: Looks wrong to me. Probably better to use original TopicType?
|
||||
@@ -239,28 +228,10 @@ module OpenProject::Bcf::BcfXml
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
def created_by_comment
|
||||
" Created by #{Setting.app_title} #{OpenProject::VERSION} at #{Time.now} "
|
||||
end
|
||||
|
||||
##
|
||||
# Find existing issue or create new
|
||||
def find_or_initialize_issue
|
||||
::Bcf::Issue.find_or_initialize_by(work_package: work_package)
|
||||
end
|
||||
|
||||
def to_bcf_datetime(date_time)
|
||||
date_time.utc.iso8601
|
||||
end
|
||||
|
||||
def to_bcf_date(date)
|
||||
date.iso8601
|
||||
end
|
||||
|
||||
def url_helpers
|
||||
@url_helpers ||= OpenProject::StaticRouting::StaticUrlHelpers.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
##
|
||||
# Creates or updates a BCF issue and markup from a work package
|
||||
module OpenProject::Bcf::BcfXml
|
||||
class ViewpointWriter < BaseWriter
|
||||
attr_reader :viewpoint
|
||||
|
||||
def initialize(viewpoint)
|
||||
@viewpoint = viewpoint
|
||||
super()
|
||||
end
|
||||
|
||||
def to_xml
|
||||
doc.to_xml(indent: 2)
|
||||
end
|
||||
|
||||
def doc
|
||||
@doc ||= begin
|
||||
viewpoint_node = fetch(markup_doc, root_node.to_s)
|
||||
|
||||
Nokogiri::XML::Builder.with(viewpoint_node) do |xml|
|
||||
components xml
|
||||
|
||||
camera('orthogonal_camera', xml)
|
||||
camera('perspective_camera', xml)
|
||||
|
||||
lines xml
|
||||
clipping_planes xml
|
||||
bitmaps xml
|
||||
end
|
||||
|
||||
markup_doc
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def root_node
|
||||
:VisualizationInfo
|
||||
end
|
||||
|
||||
def root_node_attributes
|
||||
{ Guid: viewpoint.uuid }
|
||||
end
|
||||
|
||||
def dig_json(*args)
|
||||
viewpoint.json_viewpoint.dig(*args)
|
||||
end
|
||||
|
||||
def components(xml)
|
||||
return unless dig_json('components')
|
||||
|
||||
xml.Components do
|
||||
view_setup_hints xml
|
||||
selected_components xml
|
||||
visibility xml
|
||||
coloring xml
|
||||
end
|
||||
end
|
||||
|
||||
def view_setup_hints(xml)
|
||||
return unless (setup_hash = dig_json('components', 'visibility', 'view_setup_hints'))
|
||||
|
||||
xml.ViewSetupHints(camelized(setup_hash))
|
||||
end
|
||||
|
||||
def selected_components(xml)
|
||||
return unless (selected = dig_json('components', 'selection'))
|
||||
|
||||
xml.Selection do
|
||||
selected.each do |comp_hash|
|
||||
xml.Component camelized(comp_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def visibility(xml)
|
||||
return unless (visibility_hash = dig_json 'components', 'visibility')
|
||||
|
||||
xml.Visibility(DefaultVisibility: visibility_hash['default_visibility']) do
|
||||
exceptions = visibility_hash['exceptions']
|
||||
next unless exceptions
|
||||
|
||||
xml.Exceptions do
|
||||
Array.wrap(exceptions).each do |comp_hash|
|
||||
xml.Component camelized(comp_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def coloring(xml)
|
||||
return unless (colors = dig_json 'components', 'coloring')
|
||||
|
||||
xml.Coloring do
|
||||
Array.wrap(colors).each do |color|
|
||||
xml.Color Color: color['color'].delete_prefix('#') do
|
||||
Array.wrap(color['components']).each do |comp_hash|
|
||||
xml.Component camelized(comp_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def camera(type, xml)
|
||||
return unless (camera = dig_json(type))
|
||||
|
||||
xml.send(type.camelize) do
|
||||
%w[CameraViewPoint CameraDirection CameraUpVector].each do |entry|
|
||||
xml.send(entry) do
|
||||
coords = camera[entry.underscore]
|
||||
to_xml_coords(coords, xml)
|
||||
end
|
||||
end
|
||||
xml.FieldOfView convert_float(camera['field_of_view'])
|
||||
end
|
||||
end
|
||||
|
||||
def lines(xml)
|
||||
return unless (lines = dig_json 'lines')
|
||||
|
||||
xml.Lines do
|
||||
Array.wrap(lines).each do |line|
|
||||
xml.Line do
|
||||
xml.StartPoint { to_xml_coords(line['start_point'], xml) }
|
||||
xml.EndPoint { to_xml_coords(line['end_point'], xml) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def clipping_planes(xml)
|
||||
return unless (planes = dig_json 'clipping_planes')
|
||||
|
||||
xml.ClippingPlanes do
|
||||
Array.wrap(planes).each do |plane|
|
||||
xml.ClippingPlane do
|
||||
xml.Location { to_xml_coords(plane['location'], xml) }
|
||||
xml.Direction { to_xml_coords(plane['direction'], xml) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def bitmaps(xml)
|
||||
return unless (entries = dig_json 'bitmaps')
|
||||
|
||||
# Bitmaps are rendered flat, whyever that is
|
||||
entries.each do |bitmap|
|
||||
xml.Bitmaps do
|
||||
xml.Bitmap bitmap['bitmap_type'].upcase
|
||||
xml.Reference bitmap['bitmap_data']
|
||||
xml.Location { to_xml_coords bitmap['location'], xml }
|
||||
xml.Normal { to_xml_coords bitmap['normal'], xml }
|
||||
xml.Up { to_xml_coords bitmap['up'], xml }
|
||||
xml.Height convert_float(bitmap['height'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Helper to transform a hash into camelized keys
|
||||
def camelized(hash)
|
||||
hash.transform_keys(&:camelize)
|
||||
end
|
||||
|
||||
##
|
||||
# Convert a float to BCF format that strips
|
||||
# insignificant zeros
|
||||
def convert_float(val)
|
||||
val.to_s.gsub(/(\.)0+$/, '')
|
||||
end
|
||||
|
||||
##
|
||||
# Helper to render X,Y,Z hash as set of nodes
|
||||
def to_xml_coords(hash, xml)
|
||||
hash.each do |key, val|
|
||||
xml.send(key.to_s.upcase, convert_float(val))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -38,10 +38,10 @@ FactoryBot.define do
|
||||
new_uuid = SecureRandom.uuid
|
||||
uuid { new_uuid }
|
||||
viewpoint_name { "full_viewpoint.bcfv" }
|
||||
viewpoint do
|
||||
file = OpenProject::Bcf::Engine.root.join("spec/fixtures/viewpoints/#{viewpoint_name}.xml")
|
||||
json_viewpoint do
|
||||
file = OpenProject::Bcf::Engine.root.join("spec/fixtures/viewpoints/#{viewpoint_name}.json")
|
||||
if file.readable?
|
||||
file.read
|
||||
JSON.parse(file.read)
|
||||
else
|
||||
warn "Viewpoint name #{viewpoint_name} doesnt map to a viewpoint fixture"
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--Created with the iabi.BCF library, V1.1.0 at 22.05.2017 09:51. Visit http://iabi.eu to find out more.-->
|
||||
<VisualizationInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Guid="8dc86298-9737-40b4-a448-98a9e953293a">
|
||||
<VisualizationInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Guid="{{UUID}}">
|
||||
<Components>
|
||||
<ViewSetupHints SpacesVisible="true" SpaceBoundariesVisible="true" OpeningsVisible="true" />
|
||||
<Selection>
|
||||
@@ -120,13 +120,13 @@
|
||||
</Location>
|
||||
<Normal>
|
||||
<X>-0.9999999999999999</X>
|
||||
<Y>1.253656364893038E-16</Y>
|
||||
<Z>0.0</Z>
|
||||
<Y>1.253656364893038e-16</Y>
|
||||
<Z>0</Z>
|
||||
</Normal>
|
||||
<Up>
|
||||
<X>-5.43903050550883E-34</X>
|
||||
<Y>-4.338533794284917E-18</Y>
|
||||
<Z>1.0</Z>
|
||||
<X>-5.43903050550883e-34</X>
|
||||
<Y>-4.338533794284917e-18</Y>
|
||||
<Z>1</Z>
|
||||
</Up>
|
||||
<Height>1666.1814563907683</Height>
|
||||
</Bitmaps>
|
||||
@@ -140,13 +140,13 @@
|
||||
</Location>
|
||||
<Normal>
|
||||
<X>-3</X>
|
||||
<Y>1.253656364893038E-16</Y>
|
||||
<Z>0.0</Z>
|
||||
<Y>1.253656364893038e-16</Y>
|
||||
<Z>0</Z>
|
||||
</Normal>
|
||||
<Up>
|
||||
<X>30.1234</X>
|
||||
<Y>-9000</Y>
|
||||
<Z>1.0</Z>
|
||||
<Z>1</Z>
|
||||
</Up>
|
||||
<Height>10</Height>
|
||||
</Bitmaps>
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<VisualizationInfo Guid="08a379aa-43d0-5160-3d92-1d16a24ed182">
|
||||
<VisualizationInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Guid="{{UUID}}">
|
||||
<OrthogonalCamera>
|
||||
<CameraViewPoint>
|
||||
<X>12.3456789</X>
|
||||
@@ -7,8 +7,8 @@
|
||||
<Z>-1234.1234</Z>
|
||||
</CameraViewPoint>
|
||||
<CameraDirection>
|
||||
<X>-1.0</X>
|
||||
<Y>-2.0</Y>
|
||||
<X>-1</X>
|
||||
<Y>-2</Y>
|
||||
<Z>-3</Z>
|
||||
</CameraDirection>
|
||||
<CameraUpVector>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<VisualizationInfo Guid="08a379aa-43d0-5160-3d92-1d16a24ed182">
|
||||
<VisualizationInfo Guid="{{UUID}}">
|
||||
<Components>
|
||||
<Selection>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc$"/>
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<VisualizationInfo Guid="{{UUID}}">
|
||||
<Components>
|
||||
<Selection>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc$"/>
|
||||
<Component IfcGuid="2IzdhaXk1DxQeoZSeKbhcz"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyCk"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyCj"/>
|
||||
<Component IfcGuid="2VwVShDiz0gAl$BsweUrbl"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDZ"/>
|
||||
<Component IfcGuid="30Vi1xXgzEtA72FJfoLgwc"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyCe"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDR"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBr"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkb$"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDP"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBn"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDM"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkb_"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcN"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDK"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDJ"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcM"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcL"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcK"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkbZ"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkbY"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcF"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDB"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcD"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcC"/>
|
||||
<Component IfcGuid="13osNZG6b1HvGnEwG5IBDr"/>
|
||||
<Component IfcGuid="3W4DSy3pb33QWyGgzgo0pw"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc8"/>
|
||||
<Component IfcGuid="0E1Yt2xX98svHrdrMFg9cE"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc7"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc6"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc5"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc4"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc2"/>
|
||||
<Component IfcGuid="30Vi1xXgzEtA72FJfoLgxk"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc1"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkc0"/>
|
||||
<Component IfcGuid="2PzCZPHLj8bQL_hp3fERU1"/>
|
||||
<Component IfcGuid="1s$t1FRQf40wjxOyV1OVTV"/>
|
||||
<Component IfcGuid="13osNZG6b1HvGnEwG5IBE9"/>
|
||||
<Component IfcGuid="1pc0TFRcjAywrRV3HgpmMS"/>
|
||||
<Component IfcGuid="0wh07UsgP8mf3ADo8LWq7U"/>
|
||||
<Component IfcGuid="2VwVShDiz0gAl$BsweUrbX"/>
|
||||
<Component IfcGuid="0wh07UsgP8mf3ADo8LWq6X"/>
|
||||
<Component IfcGuid="3LnOhZYmz8UQwRTZK9roX$"/>
|
||||
<Component IfcGuid="3W4DSy3pb33QWyGgzgo0mc"/>
|
||||
<Component IfcGuid="2MXBDcWRP02P5tfnBdrHNU"/>
|
||||
<Component IfcGuid="2MXBDcWRP02P5tfnBdrHNT"/>
|
||||
<Component IfcGuid="3W4DSy3pb33QWyGgzgo0o9"/>
|
||||
<Component IfcGuid="3W4DSy3pb33QWyGgzgo0mW"/>
|
||||
<Component IfcGuid="2MXBDcWRP02P5tfnBdrHNJ"/>
|
||||
<Component IfcGuid="3bII83hyD6Yu$Mpez2jNcv"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWOJ"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWOI"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWVj"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWVi"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWO6"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWO5"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWO4"/>
|
||||
<Component IfcGuid="2UWgTxbmTEourPAlYFxD8x"/>
|
||||
<Component IfcGuid="2UWgTxbmTEourPAlYFxD8v"/>
|
||||
<Component IfcGuid="2UWgTxbmTEourPAlYFxD8u"/>
|
||||
<Component IfcGuid="1mLIVAU39AxPo7CJmxmiBM"/>
|
||||
<Component IfcGuid="1gOilIRmfEGwb7$SzUoanJ"/>
|
||||
<Component IfcGuid="2OyfaLLJzADAvG7yl7qlqI"/>
|
||||
<Component IfcGuid="2OyfaLLJzADAvG7yl7qlnw"/>
|
||||
<Component IfcGuid="0e0$1G54f40AFFxJYqAOJk"/>
|
||||
<Component IfcGuid="2OyfaLLJzADAvG7yl7qlnr"/>
|
||||
<Component IfcGuid="2UWgTxbmTEourPAlYFxD8d"/>
|
||||
<Component IfcGuid="0e0$1G54f40AFFxJYqAOJi"/>
|
||||
<Component IfcGuid="2UWgTxbmTEourPAlYFxD8c"/>
|
||||
<Component IfcGuid="2UWgTxbmTEourPAlYFxD8a"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWOz"/>
|
||||
<Component IfcGuid="1nQPsl2Nv5Uvj6quEKe7LN"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWO_"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWQN"/>
|
||||
<Component IfcGuid="1qQCUVUprErw_MLQ7DcWPL"/>
|
||||
<Component IfcGuid="2OyfaLLJzADAvG7yl7qln3"/>
|
||||
<Component IfcGuid="2OyfaLLJzADAvG7yl7qln0"/>
|
||||
<Component IfcGuid="0mQ6Us0RbAEwcMtmD0TDm6"/>
|
||||
<Component IfcGuid="2OyfaLLJzADAvG7yl7qlm1"/>
|
||||
<Component IfcGuid="1pc0TFRcjAywrRV3HgppMl"/>
|
||||
<Component IfcGuid="1pc0TFRcjAywrRV3HgppMh"/>
|
||||
<Component IfcGuid="1pc0TFRcjAywrRV3HgppMf"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjh"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjg"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkiv"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjf"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkja"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkj7"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhV"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkj6"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhU"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhT"/>
|
||||
<Component IfcGuid="0zsqKw7957Bh4NNjGz39d0"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhS"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkj3"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkj2"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhR"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhQ"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkj1"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkj0"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhP"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhO"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhM"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhL"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhK"/>
|
||||
<Component IfcGuid="1gOilIRmfEGwb7$SzUohOS"/>
|
||||
<Component IfcGuid="1azD0$4TTC1hgVDVWx5ITK"/>
|
||||
<Component IfcGuid="1azD0$4TTC1hgVDVWx5ITI"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjX"/>
|
||||
<Component IfcGuid="0LHXUGtOLEzvvIxaK5XMWV"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjW"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjT"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjS"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjR"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyAn"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyAl"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjN"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyAk"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjM"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjL"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyAi"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyD9"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjK"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyD8"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjJ"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkhi"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjI"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBV"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyAf"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjH"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkjG"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBR"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyAb"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyD2"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBQ"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBO"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBL"/>
|
||||
<Component IfcGuid="2Cc$KVYf55mfjggfx$IIb9"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBK"/>
|
||||
<Component IfcGuid="2Cc$KVYf55mfjggfx$IIb7"/>
|
||||
<Component IfcGuid="2Cc$KVYf55mfjggfx$IIb6"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkbz"/>
|
||||
<Component IfcGuid="0LHXUGtOLEzvvIxaK5XMW8"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBG"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkby"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBF"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkch"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBE"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBC"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcf"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkbu"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkbt"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyBA"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkca"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkbp"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkbo"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkbn"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkbm"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyB3"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkdD"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyB0"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcR"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcQ"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcP"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkh2"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkh1"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDt"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcv"/>
|
||||
<Component IfcGuid="39_n9ZMhPAQBWcKbXoFkcu"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDq"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDk"/>
|
||||
<Component IfcGuid="1Uhsb9oeb77OoM87lbwyDf"/>
|
||||
</Selection>
|
||||
</Components>
|
||||
<PerspectiveCamera>
|
||||
<CameraViewPoint>
|
||||
<X>58.1038</X>
|
||||
<Y>16.5493</Y>
|
||||
<Z>24.7329</Z>
|
||||
</CameraViewPoint>
|
||||
<CameraDirection>
|
||||
<X>1.28974</X>
|
||||
<Y>1.2105</Y>
|
||||
<Z>-0.569962</Z>
|
||||
</CameraDirection>
|
||||
<CameraUpVector>
|
||||
<X>0.223629</X>
|
||||
<Y>0.209889</Y>
|
||||
<Z>0.951807</Z>
|
||||
</CameraUpVector>
|
||||
<FieldOfView>60</FieldOfView>
|
||||
</PerspectiveCamera>
|
||||
</VisualizationInfo>
|
||||
+2
-2
@@ -27,9 +27,9 @@
|
||||
#++
|
||||
|
||||
require 'spec_helper'
|
||||
require_relative './viewpoint_mapper_shared_examples.rb'
|
||||
require_relative './viewpoint_reader_shared_examples.rb'
|
||||
|
||||
describe OpenProject::Bcf::BcfJson::ViewpointMapper do
|
||||
describe OpenProject::Bcf::BcfJson::ViewpointReader do
|
||||
let(:instance) { described_class.new xml_viewpoint.uuid, xml_viewpoint.viewpoint }
|
||||
subject { instance.result }
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#-- copyright
|
||||
# OpenProject is a project management system.
|
||||
# Copyright (C) 2012-2019 the OpenProject Foundation (OPF)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See docs/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
require 'spec_helper'
|
||||
require 'compare-xml'
|
||||
|
||||
describe OpenProject::Bcf::BcfXml::ViewpointWriter do
|
||||
let(:writer_instance) { described_class.new json_resource }
|
||||
let(:reader_instance) { ::OpenProject::Bcf::BcfJson::ViewpointReader.new xml_resource.uuid, subject.to_xml }
|
||||
let(:xml_comparison) { Nokogiri::XML(xml_resource.viewpoint) }
|
||||
let(:json_comparison) { json_resource.raw_json_viewpoint }
|
||||
|
||||
subject { writer_instance.doc }
|
||||
|
||||
shared_examples 'converts back to xml' do
|
||||
it 'the output of writer is XML-equal to the provided XML viewpoint' do
|
||||
results = CompareXML.equivalent?(
|
||||
subject,
|
||||
xml_comparison,
|
||||
collapse_whitespace: false,
|
||||
verbose: true
|
||||
)
|
||||
|
||||
if results.length > 0
|
||||
puts subject.to_xml
|
||||
raise "Expected documents to be equal. Found diffs:\n#{results.join("\n")}"
|
||||
end
|
||||
end
|
||||
|
||||
it 'contains the root node' do
|
||||
expect(writer_instance.doc.at('VisualizationInfo')).to be_present
|
||||
end
|
||||
|
||||
it 'goes full circle comparing back to JSON' do
|
||||
expect(reader_instance.to_json).to be_json_eql json_comparison
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with minimal example' do
|
||||
let_it_be(:json_resource) do
|
||||
FactoryBot.build_stubbed :bcf_viewpoint, uuid: '{{UUID}}', viewpoint_name: 'minimal.bcfv'
|
||||
end
|
||||
let_it_be(:xml_resource) do
|
||||
FactoryBot.build_stubbed :xml_viewpoint, uuid: '{{UUID}}', viewpoint_name: 'minimal.bcfv'
|
||||
end
|
||||
|
||||
it_behaves_like 'converts back to xml'
|
||||
end
|
||||
|
||||
describe 'with full viewpoint' do
|
||||
let_it_be(:json_resource) do
|
||||
FactoryBot.build_stubbed :bcf_viewpoint, uuid: '{{UUID}}', viewpoint_name: 'full_viewpoint.bcfv'
|
||||
end
|
||||
let_it_be(:xml_resource) do
|
||||
FactoryBot.build_stubbed :xml_viewpoint, uuid: '{{UUID}}', viewpoint_name: 'full_viewpoint.bcfv'
|
||||
end
|
||||
|
||||
it_behaves_like 'converts back to xml'
|
||||
end
|
||||
|
||||
describe 'with real-world neuhaus_sc_1 example' do
|
||||
let_it_be(:json_resource) do
|
||||
FactoryBot.build_stubbed :bcf_viewpoint, uuid: '{{UUID}}', viewpoint_name: 'neubau_sc_1.bcfv'
|
||||
end
|
||||
let_it_be(:xml_resource) do
|
||||
FactoryBot.build_stubbed :xml_viewpoint, uuid: '{{UUID}}', viewpoint_name: 'neubau_sc_1_fixed.bcfv'
|
||||
end
|
||||
|
||||
it_behaves_like 'converts back to xml'
|
||||
end
|
||||
end
|
||||
@@ -54,7 +54,7 @@ describe 'BCF 2.1 viewpoints resource', type: :request, content_type: :json, wit
|
||||
shared_let(:bcf_issue) { FactoryBot.create(:bcf_issue_with_viewpoint, work_package: work_package) }
|
||||
|
||||
let(:viewpoint) { bcf_issue.viewpoints.first }
|
||||
let(:viewpoint_json) { ::OpenProject::Bcf::BcfJson::ViewpointMapper.new(viewpoint).result }
|
||||
let(:viewpoint_json) { ::OpenProject::Bcf::BcfJson::ViewpointReader.new(viewpoint).result }
|
||||
subject(:response) { last_response }
|
||||
|
||||
describe 'GET /api/bcf/2.1/projects/:project_id/topics/:topic/viewpoints' do
|
||||
|
||||
Reference in New Issue
Block a user