Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch edit access level for editor role #7464

Merged
merged 5 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions core/src/main/java/org/fao/geonet/util/UserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
*/
package org.fao.geonet.util;

import jeeves.server.UserSession;
import org.apache.commons.lang.StringUtils;
import org.fao.geonet.api.exception.NotAllowedException;
import org.fao.geonet.domain.Profile;
import org.fao.geonet.kernel.setting.SettingManager;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
Expand Down Expand Up @@ -55,4 +60,27 @@ public static boolean hasHierarchyRole(String role, RoleHierarchy roleHierarchy)
return false;
}

/**
* Checks if the user session's profile is allowed to do the transaction
*
* @param userSession current user session
* @param settingManager setting manager bean
* @param roleHierarchy role hierarchy bean
* @param settingConfigPath setting config path check org.fao.geonet.kernel.setting.Settings
* @param defaultProfile default configuration profile is no configuration found
* @param errorText error text to the exception
*/
public static void checkUserProfileLevel(UserSession userSession, SettingManager settingManager, RoleHierarchy roleHierarchy, String settingConfigPath, Profile defaultProfile, String errorText) {
if (userSession.getProfile() != Profile.Administrator) {
String allowedUserProfileFromConfiguration =
StringUtils.defaultIfBlank(settingManager.getValue(settingConfigPath), defaultProfile.toString());

// Is the user profile higher than the configuration profile allowed to do the transaction?
if (!UserUtil.hasHierarchyRole(allowedUserProfileFromConfiguration, roleHierarchy)) {
throw new NotAllowedException("The user has no permissions to " + errorText);
}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,9 @@
import jeeves.server.UserSession;
import jeeves.server.context.ServiceContext;
import jeeves.services.ReadWriteController;
import org.apache.commons.lang.StringUtils;
import org.fao.geonet.ApplicationContextHolder;
import org.fao.geonet.api.ApiParams;
import org.fao.geonet.api.ApiUtils;
import org.fao.geonet.api.exception.NotAllowedException;
import org.fao.geonet.api.processing.report.MetadataReplacementProcessingReport;
import org.fao.geonet.api.processing.report.XsltMetadataProcessingReport;
import org.fao.geonet.domain.AbstractMetadata;
Expand All @@ -63,7 +61,11 @@
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Expand Down Expand Up @@ -184,7 +186,7 @@ public ResponseEntity<Object> previewProcessSearchAndReplace(

try {
ServiceContext serviceContext = ApiUtils.createServiceContext(request);
checkUserProfileToBatchEditMetadata(serviceContext.getUserSession());
UserUtil.checkUserProfileLevel(serviceContext.getUserSession(), settingManager, roleHierarchy, Settings.METADATA_BATCH_EDITING_ACCESS_LEVEL, Profile.Editor, "batch edit metadata");

Set<String> records = ApiUtils.getUuidsParameterOrSelection(uuids, bucket, session);

Expand Down Expand Up @@ -319,7 +321,7 @@ public XsltMetadataProcessingReport processSearchAndReplace(

try {
ServiceContext serviceContext = ApiUtils.createServiceContext(request);
checkUserProfileToBatchEditMetadata(serviceContext.getUserSession());
UserUtil.checkUserProfileLevel(serviceContext.getUserSession(), settingManager, roleHierarchy, Settings.METADATA_BATCH_EDITING_ACCESS_LEVEL, Profile.Editor, "batch edit metadata");
Set<String> records = ApiUtils.getUuidsParameterOrSelection(uuids, bucket, session);
UserSession userSession = ApiUtils.getUserSession(httpSession);

Expand Down Expand Up @@ -416,21 +418,4 @@ public void process(String catalogueId) throws Exception {
}
}

/**
* Checks if the user profile is allowed to batch edit metadata.
*
* @param userSession
*/
private void checkUserProfileToBatchEditMetadata(UserSession userSession) {
if (userSession.getProfile() != Profile.Administrator) {
String allowedUserProfileToImportMetadata =
StringUtils.defaultIfBlank(settingManager.getValue(Settings.METADATA_BATCH_EDITING_ACCESS_LEVEL), Profile.Editor.toString());

// Is the user profile is higher than the profile allowed to import metadata?
if (!UserUtil.hasHierarchyRole(allowedUserProfileToImportMetadata, this.roleHierarchy)) {
throw new NotAllowedException("The user has no permissions to batch edit metadata.");
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,17 @@
import org.fao.geonet.api.records.attachments.StoreUtils;
import org.fao.geonet.api.tools.i18n.LanguageUtils;
import org.fao.geonet.constants.Geonet;
import org.fao.geonet.domain.*;
import org.fao.geonet.domain.AbstractMetadata;
import org.fao.geonet.domain.ISODate;
import org.fao.geonet.domain.MetadataCategory;
import org.fao.geonet.domain.MetadataDraft;
import org.fao.geonet.domain.MetadataResourceVisibility;
import org.fao.geonet.domain.MetadataType;
import org.fao.geonet.domain.Pair;
import org.fao.geonet.domain.Profile;
import org.fao.geonet.domain.ReservedGroup;
import org.fao.geonet.domain.ReservedOperation;
import org.fao.geonet.domain.UserGroup;
import org.fao.geonet.domain.utils.ObjectJSONUtils;
import org.fao.geonet.events.history.RecordCreateEvent;
import org.fao.geonet.events.history.RecordDeletedEvent;
Expand Down Expand Up @@ -91,18 +101,39 @@
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;

import static org.fao.geonet.api.ApiParams.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.UUID;

import static org.fao.geonet.api.ApiParams.API_CLASS_RECORD_OPS;
import static org.fao.geonet.api.ApiParams.API_CLASS_RECORD_TAG;
import static org.fao.geonet.api.ApiParams.API_PARAM_RECORD_UUID;
import static org.fao.geonet.api.ApiParams.API_PARAM_RECORD_UUIDS_OR_SELECTION;
import static org.springframework.data.jpa.domain.Specification.where;


Expand Down Expand Up @@ -203,7 +234,7 @@ public void deleteRecord(

UserSession userSession = ApiUtils.getUserSession(request.getSession());
if (accessMan.isVisibleToAll(String.valueOf(metadata.getId())) ) {
checkUserProfileToDeletePublishedMetadata(userSession);
UserUtil.checkUserProfileLevel(userSession, settingManager, roleHierarchy, Settings.METADATA_PUBLISHED_DELETE_USERPROFILE, Profile.Editor, "delete published metadata");
}

store.delResources(context, metadata.getUuid(), approved);
Expand Down Expand Up @@ -250,7 +281,7 @@ public SimpleMetadataProcessingReport deleteRecords(

if (accessMan.isVisibleToAll(String.valueOf(metadata.getId())) ) {
try {
checkUserProfileToDeletePublishedMetadata(userSession);
UserUtil.checkUserProfileLevel(userSession, settingManager, roleHierarchy, Settings.METADATA_PUBLISHED_DELETE_USERPROFILE, Profile.Editor, "delete published metadata");
} catch (NotAllowedException ex) {
report.addMetadataInfos(metadata, ex.getMessage());
continue;
Expand Down Expand Up @@ -320,7 +351,7 @@ SimpleMetadataProcessingReport insert(
SimpleMetadataProcessingReport report = new SimpleMetadataProcessingReport();

UserSession userSession = ApiUtils.getUserSession(request.getSession());
checkUserProfileToImportMetadata(userSession);
UserUtil.checkUserProfileLevel(userSession, settingManager, roleHierarchy, Settings.METADATA_IMPORT_USERPROFILE, Profile.Editor, "import metadata");


boolean isMdWorkflowEnable = settingManager.getValueAsBool(Settings.METADATA_WORKFLOW_ENABLE);
Expand Down Expand Up @@ -597,7 +628,7 @@ public SimpleMetadataProcessingReport insertFile(
if (file != null) {
ServiceContext context = ApiUtils.createServiceContext(request);

checkUserProfileToImportMetadata(context.getUserSession());
UserUtil.checkUserProfileLevel(context.getUserSession(), settingManager, roleHierarchy, Settings.METADATA_IMPORT_USERPROFILE, Profile.Editor, "import metadata");

for (MultipartFile f : file) {
if (MEFLib.isValidArchiveExtensionForMEF(f.getOriginalFilename())) {
Expand Down Expand Up @@ -986,39 +1017,4 @@ private Pair<Integer, String> loadRecord(MetadataType metadataType, Element xmlE
return Pair.read(Integer.valueOf(id.get(0)), uuid);
}

/**
* Checks if the user profile is allowed to import metadata.
*
* @param userSession
*/
private void checkUserProfileToImportMetadata(UserSession userSession) {
if (userSession.getProfile() != Profile.Administrator) {
String allowedUserProfileToImportMetadata =
StringUtils.defaultIfBlank(settingManager.getValue(Settings.METADATA_IMPORT_USERPROFILE), Profile.Editor.toString());

// Is the user profile is higher than the profile allowed to import metadata?
if (!UserUtil.hasHierarchyRole(allowedUserProfileToImportMetadata, this.roleHierarchy)) {
throw new NotAllowedException("The user has no permissions to import metadata.");
}
}

}

/**
* Checks if the user profile is allowed to import metadata.
*
* @param userSession
*/
private void checkUserProfileToDeletePublishedMetadata(UserSession userSession) {
if (userSession.getProfile() != Profile.Administrator) {
String allowedUserProfileToImportMetadata =
StringUtils.defaultIfBlank(settingManager.getValue(Settings.METADATA_PUBLISHED_DELETE_USERPROFILE), Profile.Editor.toString());

// Is the user profile is higher than the profile allowed to import metadata?
if (!UserUtil.hasHierarchyRole(allowedUserProfileToImportMetadata, this.roleHierarchy)) {
throw new NotAllowedException("The user has no permissions to delete published metadata.");
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ private Pair<SimpleMetadataProcessingReport, Element> applyBatchEdits(


ServiceContext serviceContext = ApiUtils.createServiceContext(request);
checkUserProfileToBatchEditMetadata(serviceContext.getUserSession());
UserUtil.checkUserProfileLevel(serviceContext.getUserSession(), settingManager, roleHierarchy, Settings.METADATA_BATCH_EDITING_ACCESS_LEVEL, Profile.Editor, "batch edit metadata");
final Set<String> setOfUuidsToEdit;
if (uuids == null) {
SelectionManager selectionManager =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,20 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jeeves.server.context.ServiceContext;
import org.apache.commons.lang.StringUtils;
import org.fao.geonet.api.API;
import org.fao.geonet.api.ApiParams;
import org.fao.geonet.api.ApiUtils;
import org.fao.geonet.api.exception.ResourceNotFoundException;
import org.fao.geonet.api.exception.WebApplicationException;
import org.fao.geonet.api.tools.i18n.LanguageUtils;
import org.fao.geonet.domain.Profile;
import org.fao.geonet.kernel.SchemaManager;
import org.fao.geonet.kernel.schema.MetadataSchema;
import org.fao.geonet.kernel.schema.editorconfig.BatchEditing;
import org.fao.geonet.kernel.schema.editorconfig.Editor;
import org.fao.geonet.kernel.schema.labels.Codelists;
import org.fao.geonet.kernel.setting.SettingManager;
import org.fao.geonet.kernel.setting.Settings;
import org.fao.geonet.util.UserUtil;
import org.fao.geonet.utils.Xml;
import org.jdom.Element;
import org.json.JSONObject;
Expand All @@ -48,13 +51,27 @@
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

/**
*
Expand All @@ -74,6 +91,12 @@ public class StandardsApi implements ApplicationContextAware {
@Autowired
LanguageUtils languageUtils;

@Autowired
SettingManager settingManager;

@Autowired
RoleHierarchy roleHierarchy;

private ApplicationContext context;

public synchronized void setApplicationContext(ApplicationContext context) {
Expand Down Expand Up @@ -135,8 +158,13 @@ Map<String, BatchEditing> getConfigurations(
required = false,
example = "iso19139")
@RequestParam(required = false)
String[] schema
String[] schema,
HttpServletRequest request
) throws Exception {

ServiceContext serviceContext = ApiUtils.createServiceContext(request);
UserUtil.checkUserProfileLevel(serviceContext.getUserSession(), settingManager, roleHierarchy, Settings.METADATA_BATCH_EDITING_ACCESS_LEVEL, Profile.Editor, "batch edit metadata");

List<String> listOfRequestedSchema = schema == null ? new ArrayList<String>() : Arrays.asList(schema);
Set<String> listOfSchemas = schemaManager.getSchemas();
Map<String, BatchEditing> schemasConfig = new HashMap<>();
Expand Down Expand Up @@ -394,4 +422,5 @@ public String getEditorAssociatedPanelConfiguration(
name, schemasProcessed.toString()));

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
href="#/batchedit"
class="btn btn-default btn-block gn-margin-bottom"
title="{{'batchEditing' | translate}}"
ng-if="user.isEditorOrMore()"
ng-if="user.canBatchEditMetadata()"
>
<i class="fa fa-fw fa-pencil" /><span
class="hidden-xs hidden-sm hidden-md"
Expand Down
Loading