Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Paul Graydon
erp5
Commits
43f9550d
Commit
43f9550d
authored
Sep 14, 2020
by
Arnaud Fontaine
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ZODB Components: erp5_{ods,odt}_style: Migrate Unit Tests.
parent
8e647a5f
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
773 additions
and
348 deletions
+773
-348
bt5/erp5_ods_style/TestTemplateItem/portal_components/test.erp5.testOdsStyle.py
...tTemplateItem/portal_components/test.erp5.testOdsStyle.py
+49
-0
bt5/erp5_ods_style/TestTemplateItem/portal_components/test.erp5.testOdsStyle.xml
...TemplateItem/portal_components/test.erp5.testOdsStyle.xml
+106
-0
bt5/erp5_ods_style/bt/template_test_id_list
bt5/erp5_ods_style/bt/template_test_id_list
+1
-0
bt5/erp5_ods_style/bt/test_dependency_list
bt5/erp5_ods_style/bt/test_dependency_list
+7
-0
bt5/erp5_odt_style/TestTemplateItem/portal_components/test.erp5.testOdtStyle.py
...tTemplateItem/portal_components/test.erp5.testOdtStyle.py
+49
-0
bt5/erp5_odt_style/TestTemplateItem/portal_components/test.erp5.testOdtStyle.xml
...TemplateItem/portal_components/test.erp5.testOdtStyle.xml
+106
-0
bt5/erp5_odt_style/bt/template_test_id_list
bt5/erp5_odt_style/bt/template_test_id_list
+1
-0
bt5/erp5_odt_style/bt/test_dependency_list
bt5/erp5_odt_style/bt/test_dependency_list
+7
-0
bt5/erp5_web/TestTemplateItem/portal_components/test.erp5.testOOoChart.py
...tTemplateItem/portal_components/test.erp5.testOOoChart.py
+313
-0
bt5/erp5_web/TestTemplateItem/portal_components/test.erp5.testOOoChart.xml
...TemplateItem/portal_components/test.erp5.testOOoChart.xml
+131
-0
bt5/erp5_web/bt/template_test_id_list
bt5/erp5_web/bt/template_test_id_list
+1
-0
bt5/erp5_web/bt/test_dependency_list
bt5/erp5_web/bt/test_dependency_list
+2
-1
product/ERP5Form/tests/__init__.py
product/ERP5Form/tests/__init__.py
+0
-0
product/ERP5Form/tests/testOOoChart.py
product/ERP5Form/tests/testOOoChart.py
+0
-347
No files found.
bt5/erp5_ods_style/TestTemplateItem/portal_components/test.erp5.testOdsStyle.py
0 → 100644
View file @
43f9550d
# -*- coding: utf-8 -*-
##############################################################################
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
# Deheunynck Thibaut <thibaut@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import
unittest
from
erp5.component.test.testOOoChart
import
(
TestOOoChartMixin
,
HTTP_OK
)
class
TestOdsStyle
(
TestOOoChartMixin
):
def
test_ods_style
(
self
):
# simple rendering of a chart in ods style
self
.
portal
.
changeSkin
(
'ODS'
)
response
=
self
.
publish
(
'/%s/%s'
%
(
self
.
portal
.
getId
(),
self
.
form_id
),
self
.
auth
,
handle_errors
=
False
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
body
=
response
.
getBody
()
self
.
_validate
(
body
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
TestOdsStyle
))
return
suite
\ No newline at end of file
bt5/erp5_ods_style/TestTemplateItem/portal_components/test.erp5.testOdsStyle.xml
0 → 100644
View file @
43f9550d
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"Test Component"
module=
"erp5.portal_type"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
default_reference
</string>
</key>
<value>
<string>
testOdsStyle
</string>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
test.erp5.testOdsStyle
</string>
</value>
</item>
<item>
<key>
<string>
portal_type
</string>
</key>
<value>
<string>
Test Component
</string>
</value>
</item>
<item>
<key>
<string>
sid
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
text_content_error_message
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
text_content_warning_message
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
version
</string>
</key>
<value>
<string>
erp5
</string>
</value>
</item>
<item>
<key>
<string>
workflow_history
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAI=
</string>
</persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"2"
aka=
"AAAAAAAAAAI="
>
<pickle>
<global
name=
"PersistentMapping"
module=
"Persistence.mapping"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
data
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
component_validation_workflow
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAM=
</string>
</persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"3"
aka=
"AAAAAAAAAAM="
>
<pickle>
<global
name=
"WorkflowHistoryList"
module=
"Products.ERP5Type.Workflow"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_log
</string>
</key>
<value>
<list>
<dictionary>
<item>
<key>
<string>
action
</string>
</key>
<value>
<string>
validate
</string>
</value>
</item>
<item>
<key>
<string>
validation_state
</string>
</key>
<value>
<string>
validated
</string>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_ods_style/bt/template_test_id_list
0 → 100644
View file @
43f9550d
test.erp5.testOdsStyle
\ No newline at end of file
bt5/erp5_ods_style/bt/test_dependency_list
0 → 100644
View file @
43f9550d
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy
erp5_base
erp5_ingestion
erp5_web
erp5_dms
erp5_ui_test
\ No newline at end of file
bt5/erp5_odt_style/TestTemplateItem/portal_components/test.erp5.testOdtStyle.py
0 → 100644
View file @
43f9550d
# -*- coding: utf-8 -*-
##############################################################################
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
# Deheunynck Thibaut <thibaut@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import
unittest
from
erp5.component.test.testOOoChart
import
(
TestOOoChartMixin
,
HTTP_OK
)
class
TestOdtStyle
(
TestOOoChartMixin
):
def
test_odt_style
(
self
):
# simple rendering of a chart in odt style
self
.
portal
.
changeSkin
(
'ODT'
)
response
=
self
.
publish
(
'/%s/%s'
%
(
self
.
portal
.
getId
(),
self
.
form_id
),
self
.
auth
,
handle_errors
=
False
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
body
=
response
.
getBody
()
self
.
_validate
(
body
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
TestOdtStyle
))
return
suite
\ No newline at end of file
bt5/erp5_odt_style/TestTemplateItem/portal_components/test.erp5.testOdtStyle.xml
0 → 100644
View file @
43f9550d
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"Test Component"
module=
"erp5.portal_type"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
default_reference
</string>
</key>
<value>
<string>
testOdtStyle
</string>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
test.erp5.testOdtStyle
</string>
</value>
</item>
<item>
<key>
<string>
portal_type
</string>
</key>
<value>
<string>
Test Component
</string>
</value>
</item>
<item>
<key>
<string>
sid
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
text_content_error_message
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
text_content_warning_message
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
version
</string>
</key>
<value>
<string>
erp5
</string>
</value>
</item>
<item>
<key>
<string>
workflow_history
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAI=
</string>
</persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"2"
aka=
"AAAAAAAAAAI="
>
<pickle>
<global
name=
"PersistentMapping"
module=
"Persistence.mapping"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
data
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
component_validation_workflow
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAM=
</string>
</persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"3"
aka=
"AAAAAAAAAAM="
>
<pickle>
<global
name=
"WorkflowHistoryList"
module=
"Products.ERP5Type.Workflow"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_log
</string>
</key>
<value>
<list>
<dictionary>
<item>
<key>
<string>
action
</string>
</key>
<value>
<string>
validate
</string>
</value>
</item>
<item>
<key>
<string>
validation_state
</string>
</key>
<value>
<string>
validated
</string>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_odt_style/bt/template_test_id_list
0 → 100644
View file @
43f9550d
test.erp5.testOdtStyle
\ No newline at end of file
bt5/erp5_odt_style/bt/test_dependency_list
0 → 100644
View file @
43f9550d
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy
erp5_base
erp5_ingestion
erp5_web
erp5_dms
erp5_ui_test
\ No newline at end of file
bt5/erp5_web/TestTemplateItem/portal_components/test.erp5.testOOoChart.py
0 → 100644
View file @
43f9550d
# -*- coding: utf-8 -*-
##############################################################################
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
# Deheunynck Thibaut <thibaut@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import
unittest
from
DocumentTemplate
import
String
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
from
Testing
import
ZopeTestCase
from
Products.ERP5OOo.tests.utils
import
Validator
from
Acquisition
import
aq_base
from
Products.ERP5Type.Globals
import
get_request
from
lxml
import
etree
HTTP_OK
=
200
debug
=
0
class
TestOOoChartMixin
(
ERP5TypeTestCase
,
ZopeTestCase
.
Functional
):
"""Tests OOoChart a and this render for ERP5."""
form_id
=
'TestOOochart_viewForm'
ooo_chart_id
=
'my_ooochart'
nb_persons
=
10
content_type
=
'application/vnd.oasis.opendocument.graphics'
def
afterSetUp
(
self
):
self
.
auth
=
'ERP5TypeTestCase:'
portal
=
self
.
getPortal
()
container
=
portal
.
portal_skins
.
custom
if
self
.
form_id
not
in
container
.
objectIds
():
container
.
manage_addProduct
[
'ERP5Form'
].
addERP5Form
(
self
.
form_id
,
'View'
)
form
=
getattr
(
container
,
self
.
form_id
)
# create some persons in person_module
self
.
createPersons
()
# add a ListBox field
form
.
manage_addField
(
'listbox'
,
'listbox'
,
'ListBox'
)
form
.
listbox
.
ListBox_setPropertyList
(
field_list_method
=
'zCountDocumentPerOwner'
,
field_count_method
=
''
,
field_columns
=
[
'owner | Owner'
,
'owner_count | Owner Count'
,
'number_count | Reference Count'
],
)
# create a Field OOoChart
form
.
manage_addField
(
self
.
ooo_chart_id
,
self
.
ooo_chart_id
,
'OOoChart'
)
# create a Field OOoChart
form
.
manage_addField
(
'your_ooochart'
,
'your_ooochart'
,
'OOoChart'
)
# create a ZSQL Method
sql
=
"""SELECT owner, count(uid) AS owner_count,
count(reference) AS number_count
FROM catalog
WHERE portal_type = 'Person'
GROUP BY owner ORDER BY owner_count DESC"""
template
=
String
(
source_string
=
sql
)
container
.
manage_addProduct
[
'ZSQLMethods'
].
manage_addZSQLMethod
(
'zCountDocumentPerOwner'
,
'zCountDocumentPerOwner'
,
'erp5_sql_connection'
,
''
,
template
)
# enable preference
preference
=
self
.
getPortal
().
portal_preferences
.
default_site_preference
preference
.
setPriority
(
1
)
if
preference
.
getPreferenceState
()
==
'disabled'
:
self
.
getWorkflowTool
().
doActionFor
(
ob
=
preference
,
action
=
'enable_action'
,
wf_id
=
'preference_workflow'
)
self
.
validator
=
Validator
()
self
.
tic
()
def
createPersons
(
self
):
""" Create 10 persons in person_module """
module
=
self
.
getPersonModule
()
if
len
(
module
.
objectIds
())
==
0
:
for
i
in
range
(
self
.
nb_persons
):
module
.
newContent
(
portal_type
=
'Person'
,
id
=
'person%s'
%
i
)
def
_validate
(
self
,
odf_file_data
):
error_list
=
self
.
validator
.
validate
(
odf_file_data
)
if
error_list
:
self
.
fail
(
''
.
join
(
error_list
))
class
TestOOoChart
(
TestOOoChartMixin
):
def
getTitle
(
self
):
return
'Test OOoChart'
def
test_ooo_chart
(
self
):
portal
=
self
.
getPortal
()
# Does the form exist ?
self
.
assertTrue
(
self
.
form_id
in
portal
.
portal_skins
.
custom
.
objectIds
())
getattr
(
aq_base
(
portal
.
portal_skins
.
custom
),
self
.
form_id
)
form
=
getattr
(
portal
.
portal_skins
.
custom
,
self
.
form_id
)
#listbox = form.listbox
listbox
=
getattr
(
form
,
'listbox'
)
self
.
assertEqual
(
listbox
.
meta_type
,
'ListBox'
)
request
=
get_request
()
request
[
'here'
]
=
portal
.
portal_skins
.
custom
line_list
=
[
l
for
l
in
listbox
.
get_value
(
'default'
,
render_format
=
'list'
,
REQUEST
=
request
)
]
# listbox is empty?
self
.
assertEqual
(
2
,
len
(
line_list
))
# Does the field OOoChart exist ?
ooochart
=
getattr
(
form
,
self
.
ooo_chart_id
)
self
.
assertEqual
(
ooochart
.
meta_type
,
'OOoChart'
)
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# test render raw
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
content_type
=
response
.
getHeader
(
'content-type'
)
# test content type : application/vnd.oasis.opendocument.graphics
self
.
assertTrue
(
content_type
.
startswith
(
self
.
content_type
),
content_type
)
content_disposition
=
response
.
getHeader
(
'content-disposition'
)
self
.
assertEqual
(
'attachment'
,
content_disposition
.
split
(
';'
)[
0
])
# Test ODG (zip)
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
from
Products.ERP5OOo.OOoUtils
import
OOoParser
parser
=
OOoParser
()
parser
.
openFromString
(
body
)
content_xml_view
=
parser
.
oo_files
[
'content.xml'
]
doc_view
=
etree
.
fromstring
(
content_xml_view
)
xpath
=
'//@*[name() = "xlink:href"]'
num_object
=
doc_view
.
xpath
(
xpath
)[
0
][
2
:]
content_xml_build
=
parser
.
oo_files
[
'%s/content.xml'
%
num_object
]
doc_build
=
etree
.
fromstring
(
content_xml_build
)
xpath
=
'//@*[name() = "office:value"]'
value_list
=
doc_build
.
xpath
(
xpath
)
# Test the data presence in the file XML
self
.
assertNotEquals
(
0
,
len
(
value_list
))
# 2 values because there are - 10 document created by a owner
# - 0 Reference count
self
.
assertEqual
(
2
,
len
(
value_list
))
# Test the differents render
# render image
from
erp5.component.document.Document
import
VALID_IMAGE_FORMAT_LIST
for
image_format
in
VALID_IMAGE_FORMAT_LIST
:
response
=
self
.
publish
(
'/%s/%s/%s?render_format=%s&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
,
image_format
),
self
.
auth
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
(),
'%s rendering failed: %s'
%
(
image_format
,
response
.
getStatus
()))
# render pdf
response
=
self
.
publish
(
'/%s/%s/%s?render_format=pdf&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
# Change some params and restart (circle, bar, ...)
# chart type : circle
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:circle'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
# chart type : line
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:line'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
#chart type : scatter
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:scatter'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
def
test_proxy_ooo_chart
(
self
):
portal
=
self
.
getPortal
()
# Does the form exist ?
self
.
assertTrue
(
self
.
form_id
in
portal
.
portal_skins
.
custom
.
objectIds
())
getattr
(
aq_base
(
portal
.
portal_skins
.
custom
),
self
.
form_id
)
form
=
getattr
(
portal
.
portal_skins
.
custom
,
self
.
form_id
)
#Proxify the Field my_ooochart
form
.
proxifyField
({
self
.
ooo_chart_id
:
'TestOOochart_viewForm.your_ooochart'
})
# Does the field OOoChart exist ?
ooochart
=
getattr
(
form
,
self
.
ooo_chart_id
)
self
.
assertEqual
(
ooochart
.
meta_type
,
'ProxyField'
)
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# test render raw
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
content_type
=
response
.
getHeader
(
'content-type'
)
# test content type : application/vnd.oasis.opendocument.graphics
self
.
assertTrue
(
content_type
.
startswith
(
self
.
content_type
),
content_type
)
content_disposition
=
response
.
getHeader
(
'content-disposition'
)
self
.
assertEqual
(
'attachment'
,
content_disposition
.
split
(
';'
)[
0
])
# Test ODG (zip)
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
from
Products.ERP5OOo.OOoUtils
import
OOoParser
parser
=
OOoParser
()
parser
.
openFromString
(
body
)
content_xml_view
=
parser
.
oo_files
[
'content.xml'
]
doc_view
=
etree
.
fromstring
(
content_xml_view
)
xpath
=
'//@*[name() = "xlink:href"]'
num_object
=
doc_view
.
xpath
(
xpath
)[
0
][
2
:]
content_xml_build
=
parser
.
oo_files
[
'%s/content.xml'
%
num_object
]
doc_build
=
etree
.
fromstring
(
content_xml_build
)
xpath
=
'//@*[name() = "office:value"]'
value_list
=
doc_build
.
xpath
(
xpath
)
# Test the data presence in the file XML
self
.
assertNotEquals
(
0
,
len
(
value_list
))
# 2 values because there are - 10 document created by a owner
# - 0 Reference count
self
.
assertEqual
(
2
,
len
(
value_list
))
# Test the differents render
# render image
from
erp5.component.document.Document
import
VALID_IMAGE_FORMAT_LIST
for
image_format
in
VALID_IMAGE_FORMAT_LIST
:
response
=
self
.
publish
(
'/%s/%s/%s?render_format=%s&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
,
image_format
),
self
.
auth
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
(),
'%s rendering failed: %s'
%
(
image_format
,
response
.
getStatus
()))
# render pdf
response
=
self
.
publish
(
'/%s/%s/%s?render_format=pdf&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
# Change some params and restart (circle, bar, ...)
# chart type : circle
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:circle'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
# chart type : line
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:line'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
#chart type : scatter
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:scatter'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
TestOOoChart
))
return
suite
\ No newline at end of file
bt5/erp5_web/TestTemplateItem/portal_components/test.erp5.testOOoChart.xml
0 → 100644
View file @
43f9550d
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"Test Component"
module=
"erp5.portal_type"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_recorded_property_dict
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAI=
</string>
</persistent>
</value>
</item>
<item>
<key>
<string>
default_reference
</string>
</key>
<value>
<string>
testOOoChart
</string>
</value>
</item>
<item>
<key>
<string>
default_source_reference
</string>
</key>
<value>
<string>
Products.ERP5Form.tests.testOOoChart
</string>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
test.erp5.testOOoChart
</string>
</value>
</item>
<item>
<key>
<string>
portal_type
</string>
</key>
<value>
<string>
Test Component
</string>
</value>
</item>
<item>
<key>
<string>
sid
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
text_content_error_message
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
text_content_warning_message
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
version
</string>
</key>
<value>
<string>
erp5
</string>
</value>
</item>
<item>
<key>
<string>
workflow_history
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAM=
</string>
</persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"2"
aka=
"AAAAAAAAAAI="
>
<pickle>
<global
name=
"PersistentMapping"
module=
"Persistence.mapping"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
data
</string>
</key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"3"
aka=
"AAAAAAAAAAM="
>
<pickle>
<global
name=
"PersistentMapping"
module=
"Persistence.mapping"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
data
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
component_validation_workflow
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAQ=
</string>
</persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"4"
aka=
"AAAAAAAAAAQ="
>
<pickle>
<global
name=
"WorkflowHistoryList"
module=
"Products.ERP5Type.Workflow"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_log
</string>
</key>
<value>
<list>
<dictionary>
<item>
<key>
<string>
action
</string>
</key>
<value>
<string>
validate
</string>
</value>
</item>
<item>
<key>
<string>
validation_state
</string>
</key>
<value>
<string>
validated
</string>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_web/bt/template_test_id_list
View file @
43f9550d
test.erp5.testERP5Web
test.erp5.testERP5Web
test.erp5.testOOoChart
test.erp5.testWebPageConvert
test.erp5.testWebPageConvert
test.erp5.testWebSiteLanguage
test.erp5.testWebSiteLanguage
\ No newline at end of file
bt5/erp5_web/bt/test_dependency_list
View file @
43f9550d
...
@@ -3,3 +3,4 @@ erp5_ui_test_core
...
@@ -3,3 +3,4 @@ erp5_ui_test_core
erp5_ui_test
erp5_ui_test
erp5_l10n_fr
erp5_l10n_fr
erp5_project
erp5_project
erp5_ingestion
\ No newline at end of file
product/ERP5Form/tests/__init__.py
deleted
100644 → 0
View file @
8e647a5f
product/ERP5Form/tests/testOOoChart.py
deleted
100644 → 0
View file @
8e647a5f
# -*- coding: utf-8 -*-
##############################################################################
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
# Deheunynck Thibaut <thibaut@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import
unittest
from
DocumentTemplate
import
String
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
from
Testing
import
ZopeTestCase
from
Products.ERP5OOo.tests.utils
import
Validator
from
Acquisition
import
aq_base
from
Products.ERP5Type.Globals
import
get_request
from
lxml
import
etree
HTTP_OK
=
200
debug
=
0
class
TestOOoChart
(
ERP5TypeTestCase
,
ZopeTestCase
.
Functional
):
"""Tests OOoChart a and this render for ERP5."""
form_id
=
'TestOOochart_viewForm'
ooo_chart_id
=
'my_ooochart'
nb_persons
=
10
content_type
=
'application/vnd.oasis.opendocument.graphics'
def
getTitle
(
self
):
return
'Test OOoChart'
def
getBusinessTemplateList
(
self
):
return
(
'erp5_core_proxy_field_legacy'
,
'erp5_base'
,
'erp5_ingestion'
,
'erp5_web'
,
'erp5_dms'
,
'erp5_ui_test'
,
'erp5_odt_style'
,
'erp5_ods_style'
)
def
afterSetUp
(
self
):
self
.
auth
=
'ERP5TypeTestCase:'
portal
=
self
.
getPortal
()
container
=
portal
.
portal_skins
.
custom
if
self
.
form_id
not
in
container
.
objectIds
():
container
.
manage_addProduct
[
'ERP5Form'
].
addERP5Form
(
self
.
form_id
,
'View'
)
form
=
getattr
(
container
,
self
.
form_id
)
# create some persons in person_module
self
.
createPersons
()
# add a ListBox field
form
.
manage_addField
(
'listbox'
,
'listbox'
,
'ListBox'
)
form
.
listbox
.
ListBox_setPropertyList
(
field_list_method
=
'zCountDocumentPerOwner'
,
field_count_method
=
''
,
field_columns
=
[
'owner | Owner'
,
'owner_count | Owner Count'
,
'number_count | Reference Count'
],
)
# create a Field OOoChart
form
.
manage_addField
(
self
.
ooo_chart_id
,
self
.
ooo_chart_id
,
'OOoChart'
)
# create a Field OOoChart
form
.
manage_addField
(
'your_ooochart'
,
'your_ooochart'
,
'OOoChart'
)
# create a ZSQL Method
sql
=
"""SELECT owner, count(uid) AS owner_count,
count(reference) AS number_count
FROM catalog
WHERE portal_type = 'Person'
GROUP BY owner ORDER BY owner_count DESC"""
template
=
String
(
source_string
=
sql
)
container
.
manage_addProduct
[
'ZSQLMethods'
].
manage_addZSQLMethod
(
'zCountDocumentPerOwner'
,
'zCountDocumentPerOwner'
,
'erp5_sql_connection'
,
''
,
template
)
# enable preference
preference
=
self
.
getPortal
().
portal_preferences
.
default_site_preference
preference
.
setPriority
(
1
)
if
preference
.
getPreferenceState
()
==
'disabled'
:
self
.
getWorkflowTool
().
doActionFor
(
ob
=
preference
,
action
=
'enable_action'
,
wf_id
=
'preference_workflow'
)
self
.
validator
=
Validator
()
self
.
tic
()
def
createPersons
(
self
):
""" Create 10 persons in person_module """
module
=
self
.
getPersonModule
()
if
len
(
module
.
objectIds
())
==
0
:
for
i
in
range
(
self
.
nb_persons
):
module
.
newContent
(
portal_type
=
'Person'
,
id
=
'person%s'
%
i
)
def
_validate
(
self
,
odf_file_data
):
error_list
=
self
.
validator
.
validate
(
odf_file_data
)
if
error_list
:
self
.
fail
(
''
.
join
(
error_list
))
def
test_ooo_chart
(
self
):
portal
=
self
.
getPortal
()
# Does the form exist ?
self
.
assertTrue
(
self
.
form_id
in
portal
.
portal_skins
.
custom
.
objectIds
())
getattr
(
aq_base
(
portal
.
portal_skins
.
custom
),
self
.
form_id
)
form
=
getattr
(
portal
.
portal_skins
.
custom
,
self
.
form_id
)
#listbox = form.listbox
listbox
=
getattr
(
form
,
'listbox'
)
self
.
assertEqual
(
listbox
.
meta_type
,
'ListBox'
)
request
=
get_request
()
request
[
'here'
]
=
portal
.
portal_skins
.
custom
line_list
=
[
l
for
l
in
listbox
.
get_value
(
'default'
,
render_format
=
'list'
,
REQUEST
=
request
)
]
# listbox is empty?
self
.
assertEqual
(
2
,
len
(
line_list
))
# Does the field OOoChart exist ?
ooochart
=
getattr
(
form
,
self
.
ooo_chart_id
)
self
.
assertEqual
(
ooochart
.
meta_type
,
'OOoChart'
)
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# test render raw
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
content_type
=
response
.
getHeader
(
'content-type'
)
# test content type : application/vnd.oasis.opendocument.graphics
self
.
assertTrue
(
content_type
.
startswith
(
self
.
content_type
),
content_type
)
content_disposition
=
response
.
getHeader
(
'content-disposition'
)
self
.
assertEqual
(
'attachment'
,
content_disposition
.
split
(
';'
)[
0
])
# Test ODG (zip)
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
from
Products.ERP5OOo.OOoUtils
import
OOoParser
parser
=
OOoParser
()
parser
.
openFromString
(
body
)
content_xml_view
=
parser
.
oo_files
[
'content.xml'
]
doc_view
=
etree
.
fromstring
(
content_xml_view
)
xpath
=
'//@*[name() = "xlink:href"]'
num_object
=
doc_view
.
xpath
(
xpath
)[
0
][
2
:]
content_xml_build
=
parser
.
oo_files
[
'%s/content.xml'
%
num_object
]
doc_build
=
etree
.
fromstring
(
content_xml_build
)
xpath
=
'//@*[name() = "office:value"]'
value_list
=
doc_build
.
xpath
(
xpath
)
# Test the data presence in the file XML
self
.
assertNotEquals
(
0
,
len
(
value_list
))
# 2 values because there are - 10 document created by a owner
# - 0 Reference count
self
.
assertEqual
(
2
,
len
(
value_list
))
# Test the differents render
# render image
from
erp5.component.document.Document
import
VALID_IMAGE_FORMAT_LIST
for
image_format
in
VALID_IMAGE_FORMAT_LIST
:
response
=
self
.
publish
(
'/%s/%s/%s?render_format=%s&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
,
image_format
),
self
.
auth
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
(),
'%s rendering failed: %s'
%
(
image_format
,
response
.
getStatus
()))
# render pdf
response
=
self
.
publish
(
'/%s/%s/%s?render_format=pdf&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
# Change some params and restart (circle, bar, ...)
# chart type : circle
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:circle'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
# chart type : line
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:line'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
#chart type : scatter
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:scatter'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
def
test_proxy_ooo_chart
(
self
):
portal
=
self
.
getPortal
()
# Does the form exist ?
self
.
assertTrue
(
self
.
form_id
in
portal
.
portal_skins
.
custom
.
objectIds
())
getattr
(
aq_base
(
portal
.
portal_skins
.
custom
),
self
.
form_id
)
form
=
getattr
(
portal
.
portal_skins
.
custom
,
self
.
form_id
)
#Proxify the Field my_ooochart
form
.
proxifyField
({
self
.
ooo_chart_id
:
'TestOOochart_viewForm.your_ooochart'
})
# Does the field OOoChart exist ?
ooochart
=
getattr
(
form
,
self
.
ooo_chart_id
)
self
.
assertEqual
(
ooochart
.
meta_type
,
'ProxyField'
)
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# test render raw
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
content_type
=
response
.
getHeader
(
'content-type'
)
# test content type : application/vnd.oasis.opendocument.graphics
self
.
assertTrue
(
content_type
.
startswith
(
self
.
content_type
),
content_type
)
content_disposition
=
response
.
getHeader
(
'content-disposition'
)
self
.
assertEqual
(
'attachment'
,
content_disposition
.
split
(
';'
)[
0
])
# Test ODG (zip)
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
from
Products.ERP5OOo.OOoUtils
import
OOoParser
parser
=
OOoParser
()
parser
.
openFromString
(
body
)
content_xml_view
=
parser
.
oo_files
[
'content.xml'
]
doc_view
=
etree
.
fromstring
(
content_xml_view
)
xpath
=
'//@*[name() = "xlink:href"]'
num_object
=
doc_view
.
xpath
(
xpath
)[
0
][
2
:]
content_xml_build
=
parser
.
oo_files
[
'%s/content.xml'
%
num_object
]
doc_build
=
etree
.
fromstring
(
content_xml_build
)
xpath
=
'//@*[name() = "office:value"]'
value_list
=
doc_build
.
xpath
(
xpath
)
# Test the data presence in the file XML
self
.
assertNotEquals
(
0
,
len
(
value_list
))
# 2 values because there are - 10 document created by a owner
# - 0 Reference count
self
.
assertEqual
(
2
,
len
(
value_list
))
# Test the differents render
# render image
from
erp5.component.document.Document
import
VALID_IMAGE_FORMAT_LIST
for
image_format
in
VALID_IMAGE_FORMAT_LIST
:
response
=
self
.
publish
(
'/%s/%s/%s?render_format=%s&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
,
image_format
),
self
.
auth
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
(),
'%s rendering failed: %s'
%
(
image_format
,
response
.
getStatus
()))
# render pdf
response
=
self
.
publish
(
'/%s/%s/%s?render_format=pdf&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
# Change some params and restart (circle, bar, ...)
# chart type : circle
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:circle'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
# chart type : line
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:line'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
#chart type : scatter
form
.
my_ooochart
.
manage_edit_xmlrpc
(
dict
(
chart_type
=
'chart:scatter'
))
response
=
self
.
publish
(
'/%s/%s/%s?render_format=&display=medium'
%
(
self
.
portal
.
getId
(),
self
.
form_id
,
self
.
ooo_chart_id
),
self
.
auth
)
# Test ODG (zip) with other params
body
=
response
.
getBody
()
# Test Validation Relax NG
self
.
_validate
(
body
)
def
test_ods_style
(
self
):
# simple rendering of a chart in ods style
self
.
portal
.
changeSkin
(
'ODS'
)
response
=
self
.
publish
(
'/%s/%s'
%
(
self
.
portal
.
getId
(),
self
.
form_id
),
self
.
auth
,
handle_errors
=
False
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
body
=
response
.
getBody
()
self
.
_validate
(
body
)
def
test_odt_style
(
self
):
# simple rendering of a chart in odt style
self
.
portal
.
changeSkin
(
'ODT'
)
response
=
self
.
publish
(
'/%s/%s'
%
(
self
.
portal
.
getId
(),
self
.
form_id
),
self
.
auth
,
handle_errors
=
False
)
self
.
assertEqual
(
HTTP_OK
,
response
.
getStatus
())
body
=
response
.
getBody
()
self
.
_validate
(
body
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
TestOOoChart
))
return
suite
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment