diff --git a/common/src/pandas/collection/Permission.java b/common/src/pandas/collection/Permission.java index d2fdb739..937d3a63 100644 --- a/common/src/pandas/collection/Permission.java +++ b/common/src/pandas/collection/Permission.java @@ -4,6 +4,7 @@ import pandas.core.Individual; import java.time.Instant; +import java.util.Objects; /** * Information about whether the publisher of a title has granted or denied access to archived versions of that title, @@ -212,4 +213,19 @@ public boolean isDenied() { public boolean isUnknown() { return hasState(PermissionState.UNKNOWN); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Permission that = (Permission) o; + + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } } diff --git a/common/src/pandas/collection/TitleEditForm.java b/common/src/pandas/collection/TitleEditForm.java index bf770ba2..01b3b0a6 100644 --- a/common/src/pandas/collection/TitleEditForm.java +++ b/common/src/pandas/collection/TitleEditForm.java @@ -6,11 +6,7 @@ import pandas.gather.*; import java.time.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; +import java.util.*; import static pandas.util.Strings.emptyToNull; @@ -42,7 +38,6 @@ public class TitleEditForm { private String filters; private Status status; private Reason reason; - private boolean legalDeposit = true; private boolean unableToArchive; private boolean disappeared; @@ -55,6 +50,16 @@ public class TitleEditForm { private Title continues; private Set continuesTitles = new TreeSet<>(Title.COMPARE_BY_NAME); private Set<Title> continuedByTitles = new TreeSet<>(Title.COMPARE_BY_NAME); + private PermissionTypeRadio permissionType; + private String permissionState; + private String permissionLocalReference; + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + private LocalDate permissionStatusSetDate; + private String permissionNote; + + enum PermissionTypeRadio { + LEGAL_DEPOSIT, TITLE, PUBLISHER + } public TitleEditForm() {} @@ -67,7 +72,6 @@ public TitleEditForm(Title title) { setDisappeared(title.isDisappeared()); setFormat(title.getFormat()); setId(title.getId()); - setLegalDeposit(title.getLegalDeposit()); setLocalDatabaseNo(title.getLocalDatabaseNo()); setLocalReference(title.getLocalReference()); setName(title.getName()); @@ -104,6 +108,23 @@ public TitleEditForm(Title title) { setSeedUrls(getSeedUrls() + "\n" + gather.getAdditionalUrls()); } } + + if (title.getLegalDeposit()) { + permissionType = PermissionTypeRadio.LEGAL_DEPOSIT; + } else if (Objects.equals(title.getPermission(), title.getDefaultPermission())) { + permissionType = PermissionTypeRadio.TITLE; + } else { + permissionType = PermissionTypeRadio.PUBLISHER; + } + + Permission permission = title.getDefaultPermission(); + if (permission != null) { + permissionState = permission.getStateName(); + permissionLocalReference = permission.getLocalReference(); + permissionStatusSetDate = permission.getStatusSetDate().atZone(ZoneId.systemDefault()).toLocalDate(); + permissionNote = permission.getNote(); + } + if (permissionState == null) permissionState = "Unknown"; } public Instant getScheduledInstant() { @@ -253,14 +274,6 @@ public void setOneoffDates(List<Instant> oneoffDates) { this.oneoffDates = oneoffDates; } - public Boolean getLegalDeposit() { - return legalDeposit; - } - - public void setLegalDeposit(Boolean legalDeposit) { - this.legalDeposit = legalDeposit; - } - public Publisher getPublisher() { return publisher; } @@ -382,4 +395,53 @@ public void setContinuedByTitles(Set<Title> continuedByTitles) { this.continuedByTitles.clear(); this.continuedByTitles.addAll(continuedByTitles); } + + public String getPermissionState() { + return permissionState; + } + + public TitleEditForm setPermissionState(String permissionState) { + this.permissionState = permissionState; + return this; + } + + public LocalDate getPermissionStatusSetDate() { + return permissionStatusSetDate; + } + public Instant getPermissionStatusSetInstant() { + if (permissionStatusSetDate == null) return null; + return permissionStatusSetDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); + } + + public TitleEditForm setPermissionStatusSetDate(LocalDate permissionStatusSetDate) { + this.permissionStatusSetDate = permissionStatusSetDate; + return this; + } + + public String getPermissionLocalReference() { + return permissionLocalReference; + } + + public TitleEditForm setPermissionLocalReference(String permissionLocalReference) { + this.permissionLocalReference = permissionLocalReference; + return this; + } + + public String getPermissionNote() { + return permissionNote; + } + + public TitleEditForm setPermissionNote(String permissionNote) { + this.permissionNote = permissionNote; + return this; + } + + public PermissionTypeRadio getPermissionType() { + return permissionType; + } + + public TitleEditForm setPermissionType(PermissionTypeRadio permissionType) { + this.permissionType = permissionType; + return this; + } } diff --git a/common/src/pandas/collection/TitleService.java b/common/src/pandas/collection/TitleService.java index 6790b94a..290d3f8e 100644 --- a/common/src/pandas/collection/TitleService.java +++ b/common/src/pandas/collection/TitleService.java @@ -87,7 +87,7 @@ public TitleEditForm newTitleForm(Set<Collection> collections, Set<Subject> subj form.setScope(scopeRepository.findById(Scope.DEFAULT_ID).orElse(null)); form.setStatus(statusRepository.findById(Status.SELECTED_ID).orElseThrow()); form.setSubjects(subjects); - form.setLegalDeposit(true); + form.setPermissionType(TitleEditForm.PermissionTypeRadio.LEGAL_DEPOSIT); form.setCataloguingNotRequired(true); return form; } @@ -107,7 +107,7 @@ public Title save(TitleEditForm form, User user) { title.setContinuesTitles(form.getContinuesTitles()); title.setDisappeared(form.isDisappeared()); title.setFormat(form.getFormat() == null ? formatRepository.findById(Format.DEFAULT_ID).orElseThrow() : form.getFormat()); - title.setLegalDeposit(form.getLegalDeposit()); + title.setLegalDeposit(form.getPermissionType() == TitleEditForm.PermissionTypeRadio.LEGAL_DEPOSIT); title.setLocalDatabaseNo(Strings.emptyToNull(form.getLocalDatabaseNo())); title.setLocalReference(Strings.emptyToNull(form.getLocalReference())); title.setName(form.getName().trim()); @@ -188,6 +188,15 @@ public Title save(TitleEditForm form, User user) { title.setPermission(permission); } + if (form.getPermissionType() == TitleEditForm.PermissionTypeRadio.TITLE) { + Permission permission = title.getDefaultPermission(); + permission.setStateName(form.getPermissionState()); + permission.setNote(form.getPermissionNote()); + permission.setLocalReference(form.getPermissionLocalReference()); + permission.setStatusSetDate(form.getPermissionStatusSetInstant()); + title.setPermission(permission); + } + // create or update publisher Publisher publisher = form.getPublisher(); if (publisher == null && form.getPublisherName() != null) { // create new diff --git a/ui/resources/templates/TitleEdit.html b/ui/resources/templates/TitleEdit.html index 18ffdfdd..ace04ee2 100644 --- a/ui/resources/templates/TitleEdit.html +++ b/ui/resources/templates/TitleEdit.html @@ -195,10 +195,6 @@ <h2 style="margin-top: 0; margin-bottom: var(--gutter)">Archive an Australian We Title URL (optional) <input th:field="*{titleUrl}"> </label> - <div> - <label sec:authorize="hasRole('stduser')"><input type=checkbox th:field="*{legalDeposit}"> Collect under - legal deposit</label> - </div> <div> <label sec:authorize="hasRole('stduser')"><input type=checkbox th:field="*{unableToArchive}"> Was unable to be archived</label> @@ -235,6 +231,66 @@ <h2 style="margin-top: 0; margin-bottom: var(--gutter)">Archive an Australian We </details> </fieldset> + <fieldset sec:authorize="hasRole('stduser')"> + <legend>Permission</legend> + <label> + Collect under + <div style="margin-top: 4px; display: flex; gap: 16px; align-items: end"> + <label><input type="radio" th:field="*{permissionType}" value="LEGAL_DEPOSIT"> Legal deposit</label> + <label><input type="radio" th:field="*{permissionType}" value="TITLE"> Title permission</label> + <label><input type="radio" th:field="*{permissionType}" value="PUBLISHER"> Publisher permission</label> + </div> + </label> + + <fieldset id="titlePermissionFieldset" style="border: 1px solid #ccc; background: #f3f3f3"> + <div style="gap: 16px"> + <div> + Permission status + <div style="margin-top: 4px; display: flex; gap: 16px"> + <label style="text-wrap: none"><input type="radio" th:field="*{permissionState}" value="Unknown"> Unknown</label> + <label><input type="radio" th:field="*{permissionState}" value="Granted"> Granted</label> + <label><input type="radio" th:field="*{permissionState}" value="Denied"> Denied</label> + <label><input type="radio" th:field="*{permissionState}" value="Impossible"> Impossible</label> + </div> + </div> + <label> + On date<br> + <input th:field="*{permissionStatusSetDate}" type="date"> + </label> + <label style="width: 160px; flex-grow: 1"> + Local reference + <input th:field="*{permissionLocalReference}"> + </label> + <script> + // set the permission status date to today if it's empty when permissionState is changed + document.querySelectorAll("input[name=permissionState]:not([value=Unknown])").forEach(el => + el.addEventListener("change", function () { + if (document.getElementById("permissionStatusSetDate").value === "") { + document.getElementById("permissionStatusSetDate").valueAsDate = new Date(); + } + })); + </script> + </div> + + <label> + Conditions + <textarea th:field="*{permissionNote}" rows="4"></textarea> + </label> + </fieldset> + + <fieldset id="publisherPermissionFieldset" class="alert-info"> + Publisher permissions can currently only be edited via PANDAS 3. + </fieldset> + + <script> + document.querySelectorAll("input[name=permissionType]").forEach(el => el.addEventListener("change", function() { + document.getElementById("titlePermissionFieldset").style.display = this.value === "TITLE" ? "block" : "none"; + document.getElementById("publisherPermissionFieldset").style.display = this.value === "PUBLISHER" ? "block" : "none"; + })); + document.querySelectorAll("input[name=permissionType]:checked").forEach(el => el.dispatchEvent(new Event("change"))); + </script> + </fieldset> + <fieldset> <legend>Gather</legend> diff --git a/ui/resources/templates/TitleView.html b/ui/resources/templates/TitleView.html index b7d773f9..eb0698c7 100644 --- a/ui/resources/templates/TitleView.html +++ b/ui/resources/templates/TitleView.html @@ -141,6 +141,19 @@ <h4>Status</h4> <div th:if="${title.statusReason != null}" th:text="${title.statusReason.name}" style="color: #777"></div> <div th:if="${title.disappeared}" style="color: #f77">No longer online</div> <p></p> + + <div id="permissionStatus" th:if="${title.permission != null}"> + <span th:text="${title.permission.stateName}">granted</span> + <time th:if="${title.permission.statusSetDate != null}" + th:text="${@dateFormats.shortDate.format(title.permission.statusSetDate)}" + th:datetime="${title.permission.statusSetDate}">30/8/2003</time> + <span th:if="${title.permission.contactPerson != null}"> + by <span th:text="${title.permission.contactPerson.fullName}">John Smith</span> + </span> + <blockquote th:if="${!#strings.isEmpty(title.permission.domain)}" + th:text="${title.permission.domain}"></blockquote> + </div> + <details> <summary>Schedule: <span th:text="${title?.gather?.schedule?.name}">Weekly</span> <span th:text="${title?.gather?.method?.name}">Heritrix</span> gather