Allow Creating dataset with default license via API regardless of allow custom terms setting - #12551
Conversation
pdurbin
left a comment
There was a problem hiding this comment.
I say we make the improved behavior opt-out instead.
| - When set to `true`, the default license will be automatically assigned if no license and no terms are provided in the input JSON. | ||
| - When set to `false`, no license (and no terms) will be assigned if none are provided. | ||
| - When not set (the default), the system maintains backward compatibility: the default license is assigned if custom terms are not allowed; if custom terms are allowed, no license is assigned. |
There was a problem hiding this comment.
I think the default should be the new behavior: give the dataset the default license.
And sure, have a setting for opt-ing out of the new, better behavior, if we feel like it's valuable.
There was a problem hiding this comment.
Not sure what that would be called if it stays binary true/false. The two states when the new setting is set would then be:
- don't assume default license if custom terms are allowed
- never assume the default license
with always assume the default license being the new default. Any suggestions?
There was a problem hiding this comment.
You could reverse the logic and call it dataverse.api.allow-no-license
There was a problem hiding this comment.
~nevermind - the problem is only if we need to handle three states, but since any given instance either does/doesn't allow custom terms, there's no one who needs the current capability. I'll reactor...
…cense # Conflicts: # doc/sphinx-guides/source/installation/config.rst
There was a problem hiding this comment.
I'm happy with the direction. I like the new default of not letting a dataset be created without a license (not that I've tested it). I did find a few items to address that I'm putting in this review. I'm happy to do a call about them.
Update, I did some light testing and the feature flag seems to work well. I pushed a commit to my fork: pdurbin@03cd5fb
| TermsOfUseAndAccess copy2 = terms.copyTermsOfUseAndAccess(); | ||
| assertNull(copy2.getLicense()); | ||
| assertEquals("Some terms", copy2.getTermsOfUse()); | ||
| } |
There was a problem hiding this comment.
The following two tests are failing, according to https://github.com/IQSS/dataverse/actions/runs/29957008615/job/89048490424?pr=12551
[ERROR] DatasetVersionDifferenceTest.testDifferencing:192->compareResults:274 expected: <1> but was: <2>[ERROR] FileUtilTest$FileUtilNoParamTest.testIsDownloadPopupRequiredHasTermsOfUseAndCc0License:113 expected: <false> but was: <true>
Please fix.
There was a problem hiding this comment.
One test was creating an illegal version (with termsOfUse and a license), so I adjusted the test to account for the license or custom terms restriction (~ the reason for putting the restriction in the class itself, so we can't have code/tests creating illegal objects). The other test was to explicitly test whether a popup appears when you have both a license and termsOfUse. Since that is no longer allowed, I deleted that test.
| if (termsOfUse != null) { | ||
| this.license = null; | ||
| } |
There was a problem hiding this comment.
I find it a little odd, a bit of a code smell perhaps, that this logic is in the setter. (Not just this setter, but all the setters below too.)
And if we add a new item (setFoobarRestrictions), we have to remember to add the logic there too?
Should we at least add some javadoc somewhere to explain the need for this logic in all the setters?
There was a problem hiding this comment.
AI calls this "Encapsulated Setter Logic" and says it's a reasonable approach. We were already using it in setLicense (where we clearCustomTermsVariables()), this PR adds the restriction in the other direction. I've gone ahead and added a note on setLicense and the setters for the terms that affect the license.
There was a problem hiding this comment.
Thanks. I asked a follow up question here: https://github.com/IQSS/dataverse/pull/12551/changes#r3683535892
Another reasonable approach is to have POJOs. 😄 If we move to records some day, there are no setters!
Co-authored-by: Philip Durbin <philip_durbin@harvard.edu>
| assertNull(copy2.getLicense()); | ||
| assertEquals("Some terms", copy2.getTermsOfUse()); | ||
| } | ||
| } |
There was a problem hiding this comment.
I'm seeing this error:
@qqmyers should we have you set up SONAR_TOKEN and friends in your fork?
There was a problem hiding this comment.
@poikilotherm would be the person to ask - doesn't seem scalable to ask that of all forks, but it could probably be done for this one or for ones for core team members, etc.
There was a problem hiding this comment.
Ok, I added it to the agenda for tech hours: https://docs.google.com/document/d/1xVD_Xi5OYlJnU1scEDQv5jjEIovu1GZDuilxwpgorpo/edit?usp=sharing
I also pinged him here: https://iqss.slack.com/archives/C010LA04BCG/p1785427834898959?thread_ts=1784727464.778779&cid=C010LA04BCG
There was a problem hiding this comment.
The underlying issue is well known: PRs from forks have no access to secrets.
I'm not sure why the coveralls coverage submission job is failing silently, but oh well...
From here, we have two options:
A) Only run the Sonar job on branches and PRs originating from IQSS
B) Run the Sonar job in a special environment, so we can have access to secrets and have Sonarcloud analysis on community (fork) PRs.
WDYT?
There was a problem hiding this comment.
@poikilotherm can you please say more about option B? Sound great! Is it simple to set up? Is it free? 😅
There was a problem hiding this comment.
Yeah, it's all free, but it's not simple. The hardest part: while we run any of this, we need to collect the results from the different test that ran. This is easy to do if within the flow, but harder when we have to figure out which runs may have something to report.
Aside from that, there is an option to use a comment-command (see also how we do preview images from forks), we could use the pull_request_target trigger (kind of endangering secrets when running unmoderated) or some other clever trigger around "workflow_run" (example).
If you query a search engine for "Sonarcloud", "fork" and "PR", you will find quite a bunch of people stuck with the same problem and not a lot of solutions. Unfortunately, neither of them being "easy" or "simple".
BTW - The official way to solve this is "Automatic Analysis", where scanning happens on the Sonarcloud side of things. Unfortunately, our codebase is way past their limits - we must use the CI method.
There was a problem hiding this comment.
Ok, should we just go for option A for now? So contributors aren't confused by the failing check?
There was a problem hiding this comment.
Thanks, @poikilotherm!
@qqmyers I just merged this PR from Oliver:
Do you mind if I rebase PR or merge develop? Or you're welcome to. That should make the failing Sonar check go away.
There was a problem hiding this comment.
Jim merged the latest and the Sonar check is no longer failing because it is now skipped for forks.
| terms.setTermsOfUse(obj.getString("termsOfUse", null)); | ||
| terms.setConfidentialityDeclaration(obj.getString("confidentialityDeclaration", null)); | ||
| terms.setSpecialPermissions(obj.getString("specialPermissions", null)); | ||
| terms.setRestrictions(obj.getString("restrictions", null)); | ||
| terms.setCitationRequirements(obj.getString("citationRequirements", null)); | ||
| terms.setDepositorRequirements(obj.getString("depositorRequirements", null)); | ||
| terms.setConditions(obj.getString("conditions", null)); | ||
| terms.setDisclaimer(obj.getString("disclaimer", null)); |
There was a problem hiding this comment.
Am I right in guessing that it's important to set the license (or at least attempt to) BEFORE calling these lines?
That's my read of what's going on in the setters anyway: https://github.com/IQSS/dataverse/pull/12551/changes#r3677713314
If so, if the order is important, when to call setLicense and when to call setTerms and friends, should we have a comment about this?
There was a problem hiding this comment.
I don't think so - both the license and terms fields all do a null check so they don't affect the other field(s) unless you send in a non-null value. As far as I can tell, in both this and the original code, if you send both a license and terms, the license wins silently - might be good to fail with a 400 instead, but perhaps not related to this PR.
| datasetVersion2.getTermsOfUseAndAccess().setTermsOfAccess("Terms o' Access"); | ||
| String[] termField = new String[] { | ||
| BundleUtil.getStringFromBundle("file.dataFilesTab.terms.list.termsOfUse.header"), "", "Terms o' Use" }; | ||
| BundleUtil.getStringFromBundle("file.dataFilesTab.terms.list.termsOfAccess.termsOfsAccess"), "", "Terms o' Access" }; |
There was a problem hiding this comment.
Is "termsOfsAccess" a typo? It seems like it. 🤔 Pre-existing, I guess.
There was a problem hiding this comment.
I assume. It's only used about 15 places :-)
pdurbin
left a comment
There was a problem hiding this comment.
I'm approving this. I only did some light testing with some IT tests I wrote on the side.
It's a known issue that the new SonarQube check is failing. We're discussing it.

What this PR does / why we need it: Dataverse currently creates an incomplete/invalid dataset with no license and no terms of use when a dataset is created by API, the user doesn't specify a license or terms, and the :AllowCustomTerms setting is true.
This PR adds a new Feature Flag
dataverse.feature.do-not-assume-default-licensethat allows forcing such a dataset to not get the default license, regardless of whether custom terms are allowed, with a new default that the default license is assigned regardless of whether custom terms are allowed or not.This serves two use cases:
Which issue(s) this PR closes:
Special notes for your reviewer: This PR also tightens/object-orients the constraint that a dataset can't have a license and terms of use (or other similar fields). Before that was constrained only by the callers when setting terms of use but was handled in the TofUandA class itself when a license was set. Now both directions are constrained in the class.
Suggestions on how to test this: The basic logic is tested in the new JSON parser test. A Harvard use case for this is to use the default and assure that the HEAL bridge creates datasets with the default license when Dataverse is configured to allow custom terms. See #368. Setting the FeatureFlag true should restore the current default behavior and also leave the license unassigned when custom terms are not allowed. It would also be good to test that when custom terms aren't allowed, the UIs don't break when a dataset has no license (nominally we show a warning that a license or terms are needed when custom terms are allowed, it's possible that we don't handle this case).
Does this PR introduce a user interface change? If mockups are available, please link/include them here:
Is there a release notes update needed for this change?: included
Additional documentation:
Preview docs: