Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
WCMS
uw_migrate
Commits
df0131cc
Commit
df0131cc
authored
Feb 10, 2022
by
Chris Shantz
Browse files
Merge branch '1.0.x' into prod/1.0.x
parents
13deb131
f1488950
Changes
23
Hide whitespace changes
Inline
Side-by-side
migrations/block_content/uw_cbl_copy_text.yml
View file @
df0131cc
...
...
@@ -43,6 +43,7 @@ process:
uw_ct_profile
:
{}
uw_ct_web_page
:
{}
uw_ct_opportunity
:
{}
uw_ct_service
:
{}
-
plugin
:
uw_dom_inline_image_handler
-
plugin
:
uw_dom_inline_file_handler
-
plugin
:
dom
...
...
@@ -66,3 +67,4 @@ migration_dependencies:
-
uw_ct_site_footer
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
migrations/block_content/uw_cbl_related_links.yml
View file @
df0131cc
...
...
@@ -44,3 +44,4 @@ migration_dependencies:
-
uw_ct_profile
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
migrations/block_content/uw_field_body_no_summary_promo_item.yml
View file @
df0131cc
...
...
@@ -31,6 +31,7 @@ process:
uw_ct_news_item
:
{}
uw_ct_profile
:
{}
uw_ct_web_page
:
{}
uw_ct_service
:
{}
-
plugin
:
uw_dom_inline_image_handler
-
plugin
:
dom
method
:
export
...
...
@@ -52,3 +53,4 @@ migration_dependencies:
-
uw_ct_sidebar_promo_item
-
uw_ct_site_footer
-
uw_ct_web_page
-
uw_ct_service
migrations/node/uw_ct_contact.yml
View file @
df0131cc
...
...
@@ -12,6 +12,9 @@ source:
batch_size
:
200
process
:
title
:
title
field_uw_ct_contact_sort_name
:
plugin
:
uw_name_sort
source
:
title
field_uw_ct_contact_watiam_id
:
-
plugin
:
skip_on_empty
method
:
process
...
...
migrations/node/uw_ct_service.yml
0 → 100644
View file @
df0131cc
id
:
uw_ct_service
label
:
Service
migration_group
:
uw
audit
:
true
migration_tags
:
-
Drupal
7
-
Content
-
Node
source
:
plugin
:
uw_node
node_type
:
uw_service
batch_size
:
200
process
:
title
:
title
field_uw_service_status
:
field_service_status
field_uw_service_popularity
:
field_service_popularity
field_uw_meta_image
:
plugin
:
migration_lookup
migration
:
uw_mt_image
source
:
field_event_image/0/fid
no_stub
:
true
field_uw_service_category
:
plugin
:
sub_process
source
:
field_service_category
process
:
target_id
:
plugin
:
migration_lookup
migration
:
uw_taxonomy_term
source
:
tid
no_stub
:
true
field_uw_service_available
:
field_service_available
field_uw_service_audience
:
plugin
:
sub_process
source
:
field_service_audience
process
:
target_id
:
plugin
:
migration_lookup
migration
:
uw_taxonomy_term
source
:
tid
no_stub
:
true
field_uw_service_request/value
:
field_service_request/0/value
field_uw_service_request/format
:
plugin
:
uw_formats
source
:
field_service_request/0/format
field_uw_service_notice
:
field_service_notice
field_uw_service_length
:
field_service_length
field_uw_service_cost/value
:
field_service_cost_new/0/value
field_uw_service_cost/format
:
plugin
:
uw_formats
source
:
field_service_cost_new/0/format
field_uw_service_support/value
:
field_service_support/0/value
field_uw_service_support/format
:
plugin
:
uw_formats
source
:
field_service_support/0/format
field_uw_service_hours
:
plugin
:
uw_office_hours
source
:
-
field_service_hours
-
field_date_closed
-
field_hours_change
field_uw_service_hours_notes
:
field_hours_notice
field_uw_service_location_coord
:
plugin
:
location_to_geofield
source
:
field_service_location
field_uw_service_location
:
plugin
:
location_to_address
source
:
field_service_location
field_uw_service_owner
:
-
plugin
:
uw_migration_lookup_path
source
:
field_service_owner
-
plugin
:
field_link
uri_scheme
:
https://
field_uw_service_contacts
:
-
plugin
:
sub_process
source
:
field_service_contact
process
:
url
:
plugin
:
uw_migration_lookup_path
source
:
url
title
:
title
attributes
:
attributes
-
plugin
:
field_link
uri_scheme
:
https://
field_uw_service_summary/value
:
plugin
:
uw_summary
source
:
field_service_summary
field_uw_service_summary/format
:
plugin
:
uw_formats
source
:
field_service_summary/0/format
field_uw_meta_description
:
plugin
:
uw_summary
trimmed
:
true
source
:
body
uid
:
-
plugin
:
migration_lookup
migration
:
uw_user
source
:
node_uid
no_stub
:
true
-
plugin
:
default_value
default_value
:
0
langcode
:
plugin
:
default_value
source
:
language
default_value
:
"
und"
status
:
status
moderation_state
:
plugin
:
static_map
source
:
status
map
:
'
0'
:
draft
'1'
:
published
default_value
:
draft
created
:
created
changed
:
changed
promote
:
promote
sticky
:
sticky
revision_uid
:
-
plugin
:
migration_lookup
migration
:
uw_user
source
:
revision_uid
no_stub
:
true
-
plugin
:
default_value
default_value
:
0
revision_log
:
log
revision_timestamp
:
timestamp
field_uw_meta_tags
:
plugin
:
d7_metatag_entities
source
:
pseudo_metatag_entities
destination
:
plugin
:
entity:node
default_bundle
:
uw_ct_service
migration_dependencies
:
required
:
-
uw_user
-
uw_taxonomy_term
optional
:
-
uw_mt_image
migrations/node/uw_ct_sidebar.yml
View file @
df0131cc
...
...
@@ -38,6 +38,7 @@ process:
plugin
:
migration_lookup
migration
:
-
uw_ct_web_page
-
uw_ct_service
source
:
nid
no_stub
:
true
langcode
:
...
...
@@ -73,3 +74,4 @@ migration_dependencies:
-
uw_user
optional
:
-
uw_ct_web_page
-
uw_ct_service
migrations/node/uw_ct_sidebar_promo_item.yml
View file @
df0131cc
...
...
@@ -74,3 +74,4 @@ migration_dependencies:
-
uw_ct_sidebar_promo
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
migrations/paragraph/uw_para_call_to_action.yml
View file @
df0131cc
...
...
@@ -76,3 +76,4 @@ migration_dependencies:
-
uw_ct_profile
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
migrations/paragraph/uw_para_image_banner.yml
View file @
df0131cc
...
...
@@ -35,3 +35,4 @@ migration_dependencies:
-
uw_ct_profile
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
migrations/paragraph/uw_para_timeline.yml
View file @
df0131cc
...
...
@@ -50,3 +50,4 @@ migration_dependencies:
-
uw_ct_profile
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
migrations/uw_menu_links.yml
View file @
df0131cc
...
...
@@ -68,3 +68,4 @@ migration_dependencies:
-
uw_ct_profile
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
migrations/uw_path_redirect.yml
View file @
df0131cc
...
...
@@ -33,6 +33,7 @@ process:
-
uw_ct_profile
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
-
plugin
:
extract
index
:
-
0
...
...
@@ -55,3 +56,4 @@ migration_dependencies:
-
uw_ct_profile
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
migrations/uw_taxonomy_term.yml
View file @
df0131cc
...
...
@@ -18,6 +18,7 @@ source:
-
uwaterloo_faculties
-
uw_event_type
-
uwaterloo_audience
-
service_categories
process
:
vid
:
plugin
:
static_map
...
...
@@ -33,6 +34,7 @@ process:
uw_catalog_catalogs
:
uw_vocab_catalogs
uwaterloo_faculties
:
uw_vocab_faculties_and_schools
uwaterloo_audience
:
uw_vocab_audience
service_categories
:
uw_vocab_service_categories
tid
:
plugin
:
uw_taxonomy_term_lookup
source
:
...
...
migrations/uw_url_alias_node.yml
View file @
df0131cc
...
...
@@ -41,6 +41,7 @@ process:
-
uw_ct_profile
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
no_stub
:
true
-
plugin
:
skip_on_empty
...
...
@@ -69,3 +70,4 @@ migration_dependencies:
-
uw_ct_profile
-
uw_ct_web_page
-
uw_ct_opportunity
-
uw_ct_service
src/Plugin/migrate/UwLayoutBuilderDeriver.php
View file @
df0131cc
...
...
@@ -49,6 +49,7 @@ class UwLayoutBuilderDeriver extends DeriverBase implements ContainerDeriverInte
'uw_ct_news_item'
,
'uw_ct_event'
,
'uw_ct_profile'
,
'uw_ct_service'
,
],
],
'field_body_no_summary'
=>
[
...
...
src/Plugin/migrate/process/UwNameSort.php
0 → 100644
View file @
df0131cc
<?php
namespace
Drupal\uw_migrate\Plugin\migrate\process
;
use
ADCI\FullNameParser\Parser
;
use
Drupal\migrate\MigrateExecutableInterface
;
use
Drupal\migrate\ProcessPluginBase
;
use
Drupal\migrate\Row
;
/**
* Transform full name to sort format (last_name, fist_name).
*
* @code
* process:
* destination_field:
* plugin: uw_name_sort
* source: source_field
* @endcode
*
* @MigrateProcessPlugin(
* id = "uw_name_sort"
* )
*/
class
UwNameSort
extends
ProcessPluginBase
{
/**
* Full name parser.
*
* @var \ADCI\FullNameParser\Parser
*/
protected
Parser
$parser
;
/**
* Default constructor.
*/
public
function
__construct
(
array
$configuration
,
string
$plugin_id
,
$plugin_definition
)
{
parent
::
__construct
(
$configuration
,
$plugin_id
,
$plugin_definition
);
$this
->
parser
=
new
Parser
([
'mandatory_first_name'
=>
FALSE
,
'mandatory_last_name'
=>
FALSE
,
'throws'
=>
FALSE
,
]);
}
/**
* {@inheritDoc}
*/
public
function
transform
(
$value
,
MigrateExecutableInterface
$migrate_executable
,
Row
$row
,
$destination_property
)
{
$name
=
$this
->
parser
->
parse
(
$value
);
if
(
$last_name
=
$name
->
getLastName
())
{
$value
=
$last_name
.
', '
.
$name
->
getFirstName
();
}
return
$value
;
}
}
src/Plugin/migrate/process/UwNodeLookup.php
View file @
df0131cc
...
...
@@ -33,7 +33,9 @@ class UwNodeLookup extends MigrationLookup {
'uw_ct_contact'
,
'uw_ct_event'
,
'uw_ct_news_item'
,
'uw_ct_opportunity'
,
'uw_ct_profile'
,
'uw_ct_service'
,
'uw_ct_site_footer'
,
'uw_ct_web_page'
,
];
...
...
src/Plugin/migrate/process/UwOfficeHours.php
0 → 100644
View file @
df0131cc
<?php
namespace
Drupal\uw_migrate\Plugin\migrate\process
;
use
Drupal\migrate\MigrateExecutableInterface
;
use
Drupal\migrate\Row
;
use
Drupal\office_hours
\
Plugin\migrate\process\OfficeHoursField
;
/**
* Custom process plugin for Office Hours field value.
*
* Appends other field values (closed dates, hours changes) as office hours
* exceptions.
*
* @MigrateProcessPlugin(
* id = "uw_office_hours"
* )
*/
class
UwOfficeHours
extends
OfficeHoursField
{
/**
* {@inheritdoc}
*/
public
function
transform
(
$value
,
MigrateExecutableInterface
$migrate_executable
,
Row
$row
,
$destination_property
)
{
$timezone
=
new
\
DateTimeZone
(
'EST'
);
// Input value consist from 3 sources fields: office hours, closed dates and
// hours change.
// Office hours is retrieved from original plugin.
[
$office_hours
,
$closed_dates
,
$changed_hours
]
=
$value
;
$aggregated_value
=
parent
::
transform
(
$office_hours
,
$migrate_executable
,
$row
,
$destination_property
);
// Append "Closed" dates to the list.
if
(
!
empty
(
$closed_dates
))
{
foreach
(
$closed_dates
as
$closed_date_range
)
{
$start_date
=
new
\
DateTime
(
$closed_date_range
[
'value'
],
$timezone
);
// If end date is missing, append a start date and move one.
if
(
empty
(
$closed_date_range
[
'value2'
]))
{
$aggregated_value
[]
=
[
'day'
=>
$start_date
->
getTimestamp
(),
'starthours'
=>
-
1
,
'endhours'
=>
-
1
,
];
}
else
{
$end_date
=
new
\
DateTime
(
$closed_date_range
[
'value2'
],
$timezone
);
// Define a period of specified dates and traverse through dates.
foreach
(
new
\
DatePeriod
(
$start_date
,
new
\
DateInterval
(
'P1D'
),
$end_date
)
as
$date
)
{
$aggregated_value
[]
=
[
'day'
=>
$date
->
getTimestamp
(),
'starthours'
=>
-
1
,
'endhours'
=>
-
1
,
];
}
// "End date" is not included in the period by default - append it
// manually.
if
(
$start_date
!=
$end_date
)
{
$aggregated_value
[]
=
[
'day'
=>
$end_date
->
getTimestamp
(),
'starthours'
=>
-
1
,
'endhours'
=>
-
1
,
];
}
}
}
}
// Append "Hours Change" to the list.
if
(
!
empty
(
$changed_hours
))
{
foreach
(
$changed_hours
as
$changed_hour
)
{
$start_date
=
new
\
DateTime
(
$changed_hour
[
'value'
],
$timezone
);
$end_date
=
new
\
DateTime
(
$changed_hour
[
'value2'
],
$timezone
);
$aggregated_value
[]
=
[
'day'
=>
$start_date
->
getTimestamp
(),
'starthours'
=>
$start_date
->
format
(
'Hi'
),
'endhours'
=>
$end_date
->
format
(
'Hi'
),
];
}
}
return
$aggregated_value
;
}
}
src/Plugin/migrate/source/UwEmbeddedContent.php
View file @
df0131cc
...
...
@@ -45,6 +45,7 @@ abstract class UwEmbeddedContent extends UwTable {
'uw_web_page'
,
'uw_opportunities'
,
'uwaterloo_custom_listing'
,
'uw_service'
,
];
$query
->
condition
(
'n.type'
,
$supported_node_types
,
'IN'
);
return
$query
;
...
...
tests/src/Kernel/UwMigrateTest.php
View file @
df0131cc
...
...
@@ -56,11 +56,12 @@ class UwMigrateTest extends MigrateDrupal7TestBase {
'webform'
,
'path_alias'
,
'webform_node'
,
'filter'
,
'editor'
,
'linkit'
,
'ckeditor'
,
'views_taxonomy_term_name_into_id'
,
'migrate_scanner'
,
'content_moderation'
,
'workflows'
,
'pathauto'
,
'ctools'
,
'comment'
,
'features'
,
'config_update'
,
'features'
,
'config_update'
,
'office_hours'
,
'office_hours_exceptions'
,
'uw_media'
,
'uw_migrate'
,
'uw_cfg_common'
,
'uw_ct_blog'
,
'uw_ct_catalog'
,
'uw_ct_contact'
,
'uw_ct_event'
,
'uw_ct_news_item'
,
'uw_ct_web_page'
,
'uw_ct_sidebar'
,
'uw_ct_site_footer'
,
'uw_custom_blocks'
,
'uw_ct_profile'
,
'uw_ct_service'
,
];
/**
...
...
@@ -104,6 +105,7 @@ class UwMigrateTest extends MigrateDrupal7TestBase {
$this
->
installConfig
([
'uw_ct_web_page'
]);
$this
->
installConfig
([
'uw_ct_sidebar'
]);
$this
->
installConfig
([
'uw_ct_site_footer'
]);
$this
->
installConfig
([
'uw_ct_service'
]);
}
/**
...
...
@@ -115,7 +117,7 @@ class UwMigrateTest extends MigrateDrupal7TestBase {
$definitions
=
$plugin_manager
->
getDefinitions
();
// Check the amount of custom migrations.
$this
->
assertCount
(
10
0
,
$definitions
);
$this
->
assertCount
(
10
1
,
$definitions
);
// Check some random migrations.
$this
->
assertArrayHasKey
(
'uw_user'
,
$definitions
);
...
...
@@ -213,7 +215,7 @@ class UwMigrateTest extends MigrateDrupal7TestBase {
// Taxonomy terms.
$this
->
executeMigration
(
'uw_taxonomy_term'
);
$this
->
assertSame
(
'5
3
'
,
$this
->
getEntityCount
(
'taxonomy_term'
));
$this
->
assertSame
(
'5
9
'
,
$this
->
getEntityCount
(
'taxonomy_term'
));
$terms
=
\
Drupal
::
entityTypeManager
()
->
getStorage
(
'taxonomy_term'
)
...
...
@@ -231,6 +233,7 @@ class UwMigrateTest extends MigrateDrupal7TestBase {
$this
->
assertTerm
(
25
,
[
'name'
=>
'Animal care provider'
]);
$this
->
assertTerm
(
16
,
[
'name'
=>
'Faculty'
]);
$this
->
assertTerm
(
53
,
[
'name'
=>
'party'
]);
$this
->
assertTerm
(
2
,
[
'name'
=>
'Current undergraduate students'
]);
$this
->
assertTerm
(
50
,
[
'name'
=>
'Coffee Listing'
,
'description'
=>
[
...
...
@@ -253,6 +256,7 @@ class UwMigrateTest extends MigrateDrupal7TestBase {
'field_uw_ct_contact_title'
=>
'Animal Care Provider'
,
'field_uw_ct_contact_location'
=>
'Zoo 222'
,
'field_uw_ct_contact_image'
=>
[[
'target_id'
=>
'3'
]],
'field_uw_ct_contact_sort_name'
=>
'Dolittel, Professor'
,
]);
// Content items of uw_ct_event type.
...
...
@@ -485,6 +489,94 @@ class UwMigrateTest extends MigrateDrupal7TestBase {
$pay_type_term
=
$node
->
get
(
'field_uw_opportunity_pay_type'
)
->
entity
;
$this
->
assertEquals
(
'Hourly'
,
$pay_type_term
->
label
());
// Content items of uw_ct_service type.
$this
->
executeMigration
(
'uw_ct_service'
);
$this
->
assertSame
(
'28'
,
$this
->
getEntityCount
(
'node'
));
$service
=
$this
->
assertNode
(
26
,
[
'title'
=>
'Test service'
,
'type'
=>
[[
'target_id'
=>
'uw_ct_service'
]],
'field_uw_service_status'
=>
'active'
,
'field_uw_service_popularity'
=>
'5'
,
'field_uw_service_summary'
=>
'<p>This service has a summary here. Additional services exist, but they are not currently active.</p>'
,
'field_uw_service_available'
=>
[
[
'value'
=>
'stuff'
],
[
'value'
=>
'more stuff'
],
],
'field_uw_service_audience'
=>
[
[
'target_id'
=>
'2'
],
[
'target_id'
=>
'1'
],
[
'target_id'
=>
'24'
],
[
'target_id'
=>
'12'
],
],
'field_uw_service_notice'
=>
'day'
,
'field_uw_service_length'
=>
'day'
,
'field_uw_service_hours'
=>
[
// @codingStandardsIgnoreStart
[
'day'
=>
'0'
,
'starthours'
=>
'100'
,
'endhours'
=>
'2300'
,
'comment'
=>
''
],
[
'day'
=>
'1'
,
'starthours'
=>
'100'
,
'endhours'
=>
'2300'
,
'comment'
=>
''
],
[
'day'
=>
'2'
,
'starthours'
=>
'100'
,
'endhours'
=>
'2300'
,
'comment'
=>
''
],
[
'day'
=>
'3'
,
'starthours'
=>
'100'
,
'endhours'
=>
'2300'
,
'comment'
=>
''
],
[
'day'
=>
'4'
,
'starthours'
=>
'100'
,
'endhours'
=>
'2300'
,
'comment'
=>
''
],
[
'day'
=>
'5'
,
'starthours'
=>
'100'
,
'endhours'
=>
'2300'
,
'comment'
=>
''
],
[
'day'
=>
'6'
,
'starthours'
=>
'100'
,
'endhours'
=>
'2300'
,
'comment'
=>
''
],
[
'day'
=>
'1643605200'
,
'starthours'
=>
'-1'
,
'endhours'
=>
'-1'
,
'comment'
=>
NULL
],
[
'day'
=>
'1643691600'
,
'starthours'
=>
'-1'
,
'endhours'
=>
'-1'
,
'comment'
=>
NULL
],
[
'day'
=>
'1642816800'
,
'starthours'
=>
'2100'
,
'endhours'
=>
'100'
,
'comment'
=>
NULL
],
// @codingStandardsIgnoreEnd
],
'field_uw_service_hours_notes'
=>
'test note'
,
'field_uw_service_location'
=>
[
[
'langcode'
=>
NULL
,
'country_code'
=>
'CA'
,
'administrative_area'
=>
'ON'
,
'locality'
=>
'Waterloo'
,
'dependent_locality'
=>
NULL
,
'postal_code'
=>
'N2L 6R5'
,
'sorting_code'
=>
''
,
'address_line1'
=>
'295 Hagey Boulevard'
,
'address_line2'
=>
''
,
'organization'
=>
'ACW - Accelerator Centre Waterloo'
,
'given_name'
=>
NULL
,
'additional_name'
=>
NULL
,
'family_name'
=>
NULL
,
],
],
'field_uw_service_owner'
=>
[
[
'uri'
=>
'https://uwaterloo.ca'
,
'title'
=>
'Test'
,
'options'
=>
[
'attributes'
=>
[],
],
],
],
'field_uw_service_contacts'
=>
[
[
'uri'
=>
'https://google.ca'
,
'title'
=>
'Contact'
,
'options'
=>
[
'attributes'
=>
[],
],
],
],
]);
$service_category
=
$service
->
get
(
'field_uw_service_category'
)
->
entity
;
$this
->
assertEquals
(
'Desktop and Portable Computing'
,
$service_category
->
label
());
// Geolocation data.
$this
->
assertSame
(
43.477310
,
$service
->
get
(
'field_uw_service_location_coord'
)
->
lat
);
$this
->
assertSame
(
-
80.548960
,
$service
->
get
(
'field_uw_service_location_coord'
)
->
lon
);
$this
->
assertNode
(
28
,
[
'title'
=>
'Retired service'
,
'type'
=>
[[
'target_id'
=>
'uw_ct_service'
]],
'field_uw_service_status'
=>
'retired'
,
'field_uw_service_category'
=>
[
[
'target_id'
=>
'57'
],
[
'target_id'
=>
'58'
],
],
]);
// Call to action paragraphs.
$this
->
executeMigration
(
'uw_para_call_to_action'
);
$this
->
assertSame
(
'2'
,
$this
->
getEntityCount
(
'paragraph'
));
...
...
@@ -781,12 +873,12 @@ class UwMigrateTest extends MigrateDrupal7TestBase {
// Copy text blocks.
$this
->
executeMigrations
([
'uw_cbl_copy_text'
]);
$this
->
assertSame
(
'8
0
'
,
$this
->
getEntityCount
(
'block_content'
));
$this
->
assertSame
(
'8
4
'
,
$this
->
getEntityCount
(
'block_content'
));
$this
->
executeMigration
(
'uw_field_body_no_summary_promo_item'
);
// We should have one more text block (promo item).
$this
->
assertSame
(
'8
1
'
,
$this
->
getEntityCount
(
'block_content'
));
$this
->
assertBlockContent
(
8
1
,
[
$this
->
assertSame
(
'8
5
'
,
$this
->
getEntityCount
(
'block_content'
));
$this
->
assertBlockContent
(
8
5
,
[
'type'
=>
[[
'target_id'
=>
'uw_cbl_copy_text'
]],
'field_uw_copy_text'
=>
[
[
...
...
Prev
1
2
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.