-
Notifications
You must be signed in to change notification settings - Fork 111
Description
It it worth noting that I am working from a Zenodo fork based on invenio-app-rdm v14 dev4. I also opened a similar ticket in their repository in case this is something specific to Zenodo that changes the behavior of community submissions but there is nothing obvious that indicates this with the dependency tree. The extension version is invenio-rdm-records v22.7.1.
Describe the bug
A brief description of this bug is that my curation checks, which were created using an invenio shell script that I wrote to create them. It doesn't feel like this code would cause the issues I am seeing, but perhaps you may see something there that does have something to do with it. I will provide that in the "Additional Context" section. But essentially, there seems to be a problem with curations checks and submitting to communities. When a curation check is not fulfilled (as you will see in the steps), saving a draft results in a white screen with a React error.
Steps to Reproduce
- When I go to edit the record for an already submitted record:
- And I re-save as so with one of the curation checks purposely unfulfilled (in this case it is checking if the description contains WORD, so we exclude it as a test). This seems to intermittently be the case when I start a new record in that community and click the "Save Draft" button, I suspect because I might have to something from the form validation and the subsequent likewise can be treated as alternative step 2 to replicate this:
- I get this blank screen with just the header and footer, and the header of the community. There is nothing below it when normally the form would be there, or the tabbed interface that shows curation checks but in my case nothing shows once I click "Save Draft".
The browser console shows Error: Minified React error #31 which contains Objects are not valid as a React child (found: object with keys {message, severity, description}). If you meant to render a collection of children, use an array instead.
- When I make sure the condition is met and I re-save the draft, it proceeds without that error and shows the checks view as expected.
- Likewise, you can repeat this, even when the previous save attempt fulfilled the curation check conditions.
Expected behavior
For drafts to save on communities submissions without the screen going blank (and showing a React error) regardless of whether checks are fulfilled.
Screenshots
I have screenshots in my "Steps to Reproduce" section.
Additional context (What I've Tried)
Specifically, the message, severity, description that the React error is indicating.
I have done some debugging and modified the deposit.js in a fork of invenio-rdm-records (/assets/semantic-ui/js/invenio_rdm_records/src/deposit/actions/deposit.js). I am not completely sure what the originating cause may be but I followed this approach:
Sanitizing the Data
These changes are what seemingly "fixed" the behavior that I described. I am still wrapping my head around about the reason for the behavior in the first place.
The full differential on my fork
I can open a pull request to your repository if you think there's anything worth merging, although I would be interested in addressing it in another way if you think there's a better one.
const clean = (obj) => {
if (!obj || typeof obj !== "object") return obj;
for (const key in obj) {
const v = obj[key];
// If we find the {message, severity, description} object:
if (v?.message && typeof v === "object") {
obj[key] = v.message;
} else if (typeof v === "object") {
clean(v); // Search deeper
}
}
return obj;
};
// Clean both the direct errors and any errors embedded in data
response.errors = clean(response.errors);
if (response.data?.errors) {
response.data.errors = clean(response.data.errors);
}
Set Up Debugging
You will notice I hooked in a variable getState for some of the functions to attempt to identify differences in that data, which is difficult to compare with how much is in the structure. I could write a comparison function but I took a chance on my cleaner function which surprisingly "fixed" the problem.
Validation Messages in UI
Interestingly, the validation on my curation check enabled fields always showed an amiguous message at the top of the page that didn't explain to the user what they had to change. With my changes, the detailed validation message shows when saving the draft, which is more desirable behavior.
The Curation Code
Like I mentioned, I wrote my own custom code to insert my curation checks into my communities. This may provide some context on whether something I did here is the cause and not the invenio-rdm-records handling of payload data. It does a little bit more than just setup my curation code, but that isn't relevant to what is described here.
setup-curation-checks.py
I run this using invenio shell
import sys
import time
from invenio_communities.communities.records.models import CommunityFeatured
from invenio_communities.communities.records.api import Community
from invenio_communities.proxies import current_communities
from invenio_checks.models import CheckConfig, Severity
from invenio_db import db
# For the rr team working on this, it seems invenio-checks uses this logic for metadata check levels that don't line up with the documentation
# Refer to https://github.com/inveniosoftware/invenio-checks/blob/master/invenio_checks/templates/semantic-ui/invenio_checks/requests/metadata_tab.html
TARGET_SLUGS = [
"astrophysics",
"biophys-science",
"earth-science",
"heliophysics",
"planetary-science"
]
METADATA_PARAMS = {
"title": "Required Metadata",
"description": "Metadata requirements.",
"rules": [
{
"id": "check-title",
"title": "Title Required",
"message": "Title is required.",
"description": "Title is required.",
"level": "error",
"checks": [
{
"type": "field",
"path": "metadata.title",
"operator": "exists"
}
]
},
{
"id": "require-description",
"title": "Description Missing",
"message": "A description is required for this record.",
"level": "error",
"checks": [
{
"type": "field",
"path": "metadata.description",
"operator": "exists"
}
]
},
{
"id": "check-in-description",
"title": "WORD in Description",
"message": "The word WORD is required in the description field for this record.",
"description": "The word WORD is required in the description field for this record.",
"level": "info",
"checks": [
{
"type": "comparison",
"left": {
"type": "field",
"path": "metadata.description"
},
"operator": "~=",
"right": "WORD"
}
]
}
]
}
def resolve_uuid(slug, max_retries=30, delay=5):
"""
Tries to resolve the community UUID.
If not found, waits 'delay' seconds and tries again.
"""
for attempt in range(1, max_retries + 1):
try:
community = Community.pid.resolve(slug)
return community.id
except Exception:
print(f" ⏳ Attempt {attempt}/{max_retries}: '{slug}' not ready yet... waiting {delay}s")
time.sleep(delay)
return None
def configure_community(slug):
print(f"\n--- PROCESSING: {slug} ---")
# 1. RESOLVE UUID
uuid = resolve_uuid(slug)
if not uuid:
print(f" ❌ TIMEOUT: Could not find '{slug}'. Skipping.")
return
print(f" ✅ Found UUID: {uuid}")
# 2. FEATURE COMMUNITY LOGIC
try:
is_featured = CommunityFeatured.query.filter_by(community_id=uuid).first()
if not is_featured:
featured_entry = CommunityFeatured(
community_id=uuid,
start_date=None
)
db.session.add(featured_entry)
print(" -> Community marked as Featured in DB.")
else:
print(" -> Already featured in DB. Skipping.")
except Exception as e:
print(f" ❌ ERROR during featuring: {e}")
# 3. APPLY CURATION CHECKS
try:
# Metadata Check
existing_meta = CheckConfig.query.filter_by(community_id=uuid, check_id="metadata").first()
if not existing_meta:
config_meta = CheckConfig(
community_id=uuid,
check_id="metadata",
params=METADATA_PARAMS,
severity=Severity.WARN,
enabled=True,
)
db.session.add(config_meta)
print(" -> Metadata check staged.")
else:
# UPDATE EXISTING
# We explicitly re-assign the params to ensure DB picks up changes to the JSON
existing_meta.params = METADATA_PARAMS
existing_meta.severity = Severity.WARN
existing_meta.enabled = True
print(" -> Metadata check updated.")
# File Formats Check
existing_files = CheckConfig.query.filter_by(community_id=uuid, check_id="file_formats").first()
if not existing_files:
config_files = CheckConfig(
community_id=uuid,
check_id="file_formats",
params={},
severity=Severity.WARN,
enabled=True,
)
db.session.add(config_files)
print(" -> File check staged.")
else:
# UPDATE EXISTING
existing_files.params = {}
existing_files.severity = Severity.WARN
existing_files.enabled = True
print(" -> File check updated.")
# Commit DB changes
db.session.commit()
# 4. TRIGGER SEARCH INDEX REFRESH
# Essential for the community to appear in the homepage slider
current_communities.service.indexer.index_by_id(uuid)
print(" -> Search index updated.")
except Exception as e:
db.session.rollback()
print(f" ❌ ERROR configuring curation for '{slug}': {e}")
def run():
print("Starting Community Configuration...")
for slug in TARGET_SLUGS:
configure_community(slug)
print("\n--- DONE ---")
if __name__ == "__main__":
run()