diff --git a/modules/weko-items-ui/weko_items_ui/static/js/weko_items_ui/app.js b/modules/weko-items-ui/weko_items_ui/static/js/weko_items_ui/app.js
index 2cf6e7b653..03be6f626a 100644
--- a/modules/weko-items-ui/weko_items_ui/static/js/weko_items_ui/app.js
+++ b/modules/weko-items-ui/weko_items_ui/static/js/weko_items_ui/app.js
@@ -2176,6 +2176,14 @@ function validateThumbnails(rootScope, scope, itemSizeCheckFlg, files) {
};
$scope.isExistingTitle = function () {
+ // The subitem key used for an item type's title varies by item
+ // type (e.g. `subitem_item_title` vs.
+ // `subitem_restricted_access_item_title`). It is resolved
+ // server-side (weko_workflow.views.get_title_subitem_keys) and
+ // passed down via these hidden inputs, falling back to the
+ // standard JPCOAR name if unresolved.
+ let titleSubKey = $("#title_subitem_key").val() || "subitem_item_title";
+ let titleLanguageKey = $("#title_language_subitem_key").val() || "subitem_item_title_language";
let model = $rootScope.recordsVM.invenioRecordsModel;
if (Object.keys(model).length === 0 && model.constructor === Object) {
return false;
@@ -2183,7 +2191,7 @@ function validateThumbnails(rootScope, scope, itemSizeCheckFlg, files) {
let isExisted = false;
for (let key in model) {
if (model.hasOwnProperty(key) && model[key].length > 0) {
- let title = model[key][0]['subitem_item_title'];
+ let title = model[key][0][titleSubKey];
if (title){
$scope.item_tile_key = key
let activity_id= title.match(/A-[0-9]{8}-[0-9]{5}/g);
@@ -2194,7 +2202,7 @@ function validateThumbnails(rootScope, scope, itemSizeCheckFlg, files) {
if (title && $("#auto_fill_title").val() !== '""') {
$scope.setFormReadOnly(key);
setTimeout(function () {
- $("input[name='subitem_item_title'], select[name='subitem_item_title_language']").attr("disabled", "disabled");
+ $("input[name='" + titleSubKey + "'], select[name='" + titleLanguageKey + "']").attr("disabled", "disabled");
}, 3000);
isExisted = true;
break;
@@ -2226,21 +2234,28 @@ function validateThumbnails(rootScope, scope, itemSizeCheckFlg, files) {
userName = JSON.parse(userInfoData).results["subitem_displayname"];
}
}
- let titleSubKey = "subitem_item_title";
- let titleLanguageKey = "subitem_item_title_language";
+ let titleSubKey = $("#title_subitem_key").val() || "subitem_item_title";
+ let titleLanguageKey = $("#title_language_subitem_key").val() || "subitem_item_title_language";
let recordsVM = $rootScope["recordsVM"];
Object.entries(recordsVM["invenioRecordsSchema"].properties).forEach(
function ([key, value]) {
if (value && value.type === "array" && value.items) {
if (value.items.properties && value.items.properties.hasOwnProperty(titleSubKey)) {
+ // Not every title property declares a language sub-key
+ // (e.g. item_1578299480500 on item type 3007/3008) --
+ // assigning an undeclared property breaks the whole
+ // array item and the record fails to save with a title.
+ let hasLanguageKey = value.items.properties.hasOwnProperty(titleLanguageKey);
$scope.item_tile_key = key;
let enTitle = {};
let jaTitle = {};
// TitleData and Username are mandatory, dataType either way
enTitle[titleSubKey] = dataType ? [dataType, titleData['en'], userName].join(" - ") : [titleData['en'], userName].join(" - ");
- enTitle[titleLanguageKey] = "en";
jaTitle[titleSubKey] = dataType ? [dataType, titleData['ja'], userName].join(" - ") : [titleData['ja'], userName].join(" - ");
- jaTitle[titleLanguageKey] = "ja";
+ if (hasLanguageKey) {
+ enTitle[titleLanguageKey] = "en";
+ jaTitle[titleLanguageKey] = "ja";
+ }
recordsVM["invenioRecordsModel"][key] = [jaTitle, enTitle];
}
}
@@ -5266,8 +5281,8 @@ function validateThumbnails(rootScope, scope, itemSizeCheckFlg, files) {
let defaultTitleEn = titleData['en'] + userName;
let defaultTitleJa = titleData['ja'] + userName;
- let titleSubKey = "subitem_item_title";
- let titleLanguageKey = "subitem_item_title_language";
+ let titleSubKey = $("#title_subitem_key").val() || "subitem_item_title";
+ let titleLanguageKey = $("#title_language_subitem_key").val() || "subitem_item_title_language";
let selectedUsageApplicationIDs = []
let model = $rootScope["recordsVM"].invenioRecordsModel;
diff --git a/modules/weko-items-ui/weko_items_ui/templates/weko_items_ui/iframe/item_edit.html b/modules/weko-items-ui/weko_items_ui/templates/weko_items_ui/iframe/item_edit.html
index 590b886464..69983f3627 100644
--- a/modules/weko-items-ui/weko_items_ui/templates/weko_items_ui/iframe/item_edit.html
+++ b/modules/weko-items-ui/weko_items_ui/templates/weko_items_ui/iframe/item_edit.html
@@ -489,6 +489,8 @@
Contributor
+
+
diff --git a/modules/weko-workflow/tests/test_views.py b/modules/weko-workflow/tests/test_views.py
index 8ab92284b0..ce7c374612 100644
--- a/modules/weko-workflow/tests/test_views.py
+++ b/modules/weko-workflow/tests/test_views.py
@@ -35,7 +35,8 @@
check_authority,
display_guest_activity,
display_guest_activity_item_application,
- render_guest_workflow)
+ render_guest_workflow,
+ get_title_subitem_keys)
from marshmallow.exceptions import ValidationError
from weko_records_ui.models import FileOnetimeDownload, FilePermission
from weko_records.models import ItemMetadata, ItemReference
@@ -4627,6 +4628,28 @@ def prepare_activity(act_id, recid, with_item=False, is_deleted=False):
assert res.status_code == 200
assert json.loads(res.data) == {"code": 200, 'for_delete': False, "is_deleted": True}
+# .tox/c1/bin/pytest --cov=weko_workflow tests/test_views.py::test_get_title_subitem_keys -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko_workflow/.tox/c1/tmp
+def test_get_title_subitem_keys(app, item_type):
+ """get_title_subitem_keys() should resolve the title subitem key names
+ from the item type's own jpcoar_mapping, not a hardcoded name -- the
+ title subitem key varies by item type (e.g. subitem_item_title vs.
+ subitem_restricted_access_item_title)."""
+ item_type_id = item_type[0]["id"]
+ # tests/data/item_type/item_type_mapping.json maps
+ # item_1617186331708.jpcoar_mapping.title to these subitem keys.
+ title_subitem_key, title_language_subitem_key = \
+ get_title_subitem_keys(item_type_id)
+ assert title_subitem_key == "subitem_1551255647225"
+ assert title_language_subitem_key == "subitem_1551255648112"
+
+
+def test_get_title_subitem_keys_no_mapping(app, db):
+ """Falls back to empty strings (never raises) when there is no
+ item_type_mapping for the given id, or no id at all."""
+ assert get_title_subitem_keys(None) == ("", "")
+ assert get_title_subitem_keys(999999) == ("", "")
+
+
# .tox/c1/bin/pytest --cov=weko_workflow tests/test_views.py::test_display_activity_nologin -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko_workflow/.tox/c1/tmp
def test_display_activity_nologin(client,db_register2,mocker):
"""Test of display activity."""
diff --git a/modules/weko-workflow/weko_workflow/views.py b/modules/weko-workflow/weko_workflow/views.py
index 8d4135ee57..fef6110c29 100644
--- a/modules/weko-workflow/weko_workflow/views.py
+++ b/modules/weko-workflow/weko_workflow/views.py
@@ -58,7 +58,7 @@
from weko_items_ui.utils import check_item_is_being_edit, get_workflow_by_item_type_id, \
get_current_user
from weko_logging.activity_logger import UserActivityLogger
-from weko_records.api import FeedbackMailList, RequestMailList, ItemLink, ItemTypes, ItemApplication
+from weko_records.api import FeedbackMailList, RequestMailList, ItemLink, ItemTypes, ItemApplication, Mapping
from weko_records.models import ItemMetadata
from weko_records.serializers.utils import get_item_type_name
from weko_records_ui.models import FilePermission
@@ -797,6 +797,37 @@ def verify_deletion(activity_id="0"):
return jsonify(res), 200
+def get_title_subitem_keys(item_type_id):
+ """Resolve the subitem key names used for an item type's title.
+
+ Different item types name their "title" subitem differently
+ (e.g. ``subitem_item_title`` for the standard JPCOAR title
+ property, ``subitem_restricted_access_item_title`` for the
+ restricted-access reference item type). Rather than hardcoding
+ one name, resolve it the same way
+ :meth:`weko_deposit.api.WekoDeposit.get_titles` does: via the
+ item type's ``jpcoar_mapping.title`` mapping entry.
+
+ :param item_type_id: ID of the item type.
+ :returns: (title_subitem_key, title_language_subitem_key), each
+ an empty string if it could not be resolved.
+ """
+ title_subitem_key = ""
+ title_language_subitem_key = ""
+ item_type_mapping = Mapping.get_record(item_type_id) if item_type_id else None
+ if item_type_mapping:
+ for mapping_value in item_type_mapping.values():
+ if not isinstance(mapping_value, dict):
+ continue
+ jpcoar_title = (mapping_value.get('jpcoar_mapping') or {}).get('title')
+ if isinstance(jpcoar_title, dict) and jpcoar_title.get('@value'):
+ title_subitem_key = jpcoar_title.get('@value')
+ title_language_subitem_key = jpcoar_title.get(
+ '@attributes', {}).get('xml:lang') or ""
+ break
+ return title_subitem_key, title_language_subitem_key
+
+
@workflow_blueprint.route('/activity/detail/',
methods=['GET', 'POST'])
@login_required_customize
@@ -955,6 +986,8 @@ def display_activity(activity_id="0", community_id=None):
step_item_login_url = None
term_and_condition_content = ''
title = ""
+ title_subitem_key = ""
+ title_language_subitem_key = ""
user_lock_key = "workflow_userlock_activity_{}".format(str(current_user.get_id()))
if action_endpoint in ['item_login',
'item_login_application',
@@ -1007,6 +1040,8 @@ def display_activity(activity_id="0", community_id=None):
title = auto_fill_title(item_type_name)
+ title_subitem_key, title_language_subitem_key = \
+ get_title_subitem_keys(workflow_detail.itemtype_id)
show_autofill_metadata = is_show_autofill_metadata(item_type_name)
is_hidden_pubdate_value = is_hidden_pubdate(item_type_name)
@@ -1209,6 +1244,8 @@ def display_activity(activity_id="0", community_id=None):
approval_preview=approval_preview,
auto_fill_data_type=data_type,
auto_fill_title=title,
+ title_subitem_key=title_subitem_key,
+ title_language_subitem_key=title_language_subitem_key,
community_id=community_id,
cur_step=cur_step,
contributors=contributors,