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

Feature workspace/Draft #1527

Closed
wants to merge 77 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
e3c0367
Introducing the new IMetadata superclass.
Delawen Dec 11, 2015
b802ae8
Splitting DataManager on lesser utility classes so it is easier to ma…
Delawen Dec 14, 2015
51a1b57
All DataManager split. Test pass. Simple testing of creating and edit…
Delawen Dec 15, 2015
cafcd25
"Removing" autowired fields and replacing it with a temporary init fu…
Delawen Dec 15, 2015
b704ccf
Still very buggy, but the Draft implementation advances.
Delawen Dec 18, 2015
b8699b3
Creation and editing of drafts finished.
Delawen Dec 22, 2015
cf67ae1
Redirect editor when trying to edit published metadata if draft is en…
Delawen Dec 22, 2015
f67bafb
Fix broken metadata view if there is a draft
Delawen Dec 22, 2015
0dc9fa5
Workspace draft improvements and bugfixing. Playing with publishing a…
Delawen Dec 23, 2015
1b32c8f
Moving draft configuration to web project
Delawen Jan 7, 2016
26bffdb
Fixing save of metadata draft on editor
Delawen Jan 7, 2016
580c206
Draft metadata has a draft flag on the index
Delawen Jan 8, 2016
4892491
Select now distinguish between draft and not drafted metadata version
Delawen Jan 8, 2016
d896bd2
Publish draft: replaces current metadata with draft and removes draft…
Delawen Jan 8, 2016
3edf8b3
New location path /draft to show drafted versions of metadata
Delawen Jan 11, 2016
de232b4
Links and actions to show drafted or published version
Delawen Jan 11, 2016
61e19af
LuceneQueryBuilder only returns one version of each metadata (draft o…
Delawen Jan 27, 2016
19a2ce9
Use draft parameter to allow see non drafted version of metadata
Delawen Jan 29, 2016
a830632
Fix metadata/draft view with draft field from index
Delawen Feb 3, 2016
5bb938c
Metadata lock
Delawen Feb 5, 2016
ab3f664
Setting for how much time the editing lock should last (if should)
Delawen Feb 5, 2016
f0028de
Throwing security exception if the user doesn't have privileges over …
Delawen Feb 5, 2016
d62c2cb
If there is no row in the settings for metadata lock, create one with…
Delawen Feb 8, 2016
5694614
Draft behaviour: general bug fixing related to selection and batch pr…
Delawen Feb 19, 2016
f05ac49
Different color on editor board for drafts
Delawen Feb 19, 2016
43442a1
Fixing some errors from last merge. Updated test. Disabled draft by d…
Delawen Apr 1, 2016
a54ddae
Merge branch 'develop' of github.com:geonetwork/core-geonetwork into …
Delawen Apr 14, 2016
187c8b2
Commenting tests that fail not related to the changes done
Delawen Apr 14, 2016
5346e2b
Merge branch 'develop' into feature_workspace
Delawen May 6, 2016
dce021e
Fixing tests
Delawen May 9, 2016
3a76569
Fixing duplicated getLabelsTranslation on domain beans
Delawen May 20, 2016
9bdf1a2
Do not allow a user to lock the same metadata more than once
Delawen May 20, 2016
5687ad0
Restoring error message for metadataLocked
Delawen May 20, 2016
33c6dca
Restoring "reserved" attribute on group xml display
Delawen May 20, 2016
88a5b6c
Removed useless labeltranslatioins attribute
Delawen May 20, 2016
3057510
Restore Metadata not found error
Delawen May 20, 2016
365cff8
Merge branch 'develop' of github.com:geonetwork/core-geonetwork into …
Delawen Jul 14, 2016
0941605
Merge branch 'develop' of github.com:geonetwork/core-geonetwork into …
Delawen Jul 14, 2016
a9215e4
Move lock service to API
Delawen Jul 15, 2016
34a9753
Fixing duplicated List for categories.
Delawen Jul 15, 2016
20326d8
Adding lock editor screen to admin.console
Delawen Jul 21, 2016
b9eab55
MetadataApi using MetadataManager instead of mdRepository directly
Delawen Jul 22, 2016
1908081
Disabling edit button if locked
Delawen Jul 22, 2016
2d0c5dd
Filtering drafts on csw results
Delawen Sep 6, 2016
1077fad
Make sure the metadata record is correctly indexed and displayed on t…
Delawen Sep 13, 2016
ed65881
Using events for publishing/unpublishing, so they work on all cases
Delawen Sep 14, 2016
0e60e7a
Merge branch 'develop' of github.com:geonetwork/core-geonetwork into …
Delawen Sep 14, 2016
e9a3195
Merge branch 'develop' of github.com:geonetwork/core-geonetwork into …
Delawen Sep 19, 2016
2314997
Merge branch 'develop' of github.com:geonetwork/core-geonetwork into …
Delawen Sep 26, 2016
d5d2c25
Merge branch '3.2.x' of github.com:geonetwork/core-geonetwork into fe…
Delawen Oct 18, 2016
09583b7
Fixing API to use either ID or UUID when retrieving a record
Delawen Oct 18, 2016
4958afb
Fixing lock loop on editing a new draft
Delawen Oct 21, 2016
579cd75
Checking not only null but also empty string
Delawen Oct 28, 2016
d5a28b0
Merge branch '3.2.x' of github.com:geonetwork/core-geonetwork into fe…
Delawen Nov 17, 2016
a4bd939
Merge branch '3.2.x' of github.com:geonetwork/core-geonetwork into fe…
Delawen Nov 18, 2016
6ad3035
Merge branch '3.2.x' of github.com:geonetwork/core-geonetwork into fe…
Delawen Nov 18, 2016
a18be5c
Refresh search after publishing. Update icons
Delawen Nov 18, 2016
b34fb89
Warn about what happens when a draft gets removed
Delawen Nov 18, 2016
0765155
Merge branch 'develop' of github.com:geonetwork/core-geonetwork into …
Delawen Jan 12, 2017
a55ecdb
Make draft and metadata privileges sync
Delawen Jan 20, 2017
c972c04
Now an editor, reviewer and useradmin can see drafts from other users
Delawen Jan 26, 2017
eceee52
Fixing queries on search: editors saw both published and draft
Delawen Jan 27, 2017
93a6260
Updating tests of queries
Delawen Jan 30, 2017
61cfcb6
Restoring "smart" useful functions when indexing metadata
Delawen Feb 1, 2017
3f3e803
Fixing test: now there is no empty "()" group for admins
Delawen Feb 1, 2017
45fbad3
Update docs
Delawen Feb 1, 2017
d4d3f26
Fixing problem with null context on metadata indexing
Delawen Apr 4, 2017
c60514c
Fixing Lucene queries. Now simpler and easier to debug
Delawen May 5, 2017
7b6e385
Missing concurrent connections accessing the same database on the tes…
Delawen Jun 13, 2017
7eae304
Update tests to adapt to draft
Delawen Jun 13, 2017
7246e02
Fixing more bugs related to draft. This should be history rewritten
Delawen Jun 13, 2017
8d5ca1f
Some tests were failing
Delawen Jun 15, 2017
eab0d00
Workflow didn't have the right metadata repository classes
Delawen Jun 27, 2017
055ef9d
Missing anotation that made the service call an inexistent xslt trans…
Delawen Jun 27, 2017
55925f1
Merge branch 'develop' into feature_workspace
Delawen Jun 27, 2017
0239e51
Merge remote-tracking branch 'origin/develop' into feature_workspace
Delawen Jun 29, 2017
c9ed0c1
Merge branch 'develop' of github.com:geonetwork/core-geonetwork into …
Delawen Jul 10, 2017
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
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,6 @@ public ServiceContext createServiceContext(String name, String lang, HttpServlet
final HttpSession httpSession = request.getSession(false);
UserSession session = (UserSession) httpSession.getAttribute(Jeeves.Elem.SESSION);
if (session != null) {

context.setUserSession(session);
}

Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/fao/geonet/constants/Edit.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public static final class Elem {
public static final String BASEURL = "baseUrl";
public static final String LOCSERV = "locService";
public static final String IS_PUBLISHED_TO_ALL = "isPublishedToAll";
public static final String IS_LOCKED = "lock";

//--- privileges

Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/fao/geonet/constants/Geonet.java
Original file line number Diff line number Diff line change
Expand Up @@ -668,5 +668,6 @@ public static class IndexFieldNames {
public static final String ID = "_id";
public static final String ANY = "any";
public static final String LOCALE = "locale";
public static final String DRAFT = "draft";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//=============================================================================
//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the
//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
//=== and United Nations Environment Programme (UNEP)
//===
//=== This program is free software; you can redistribute it and/or modify
//=== it under the terms of the GNU General Public License as published by
//=== the Free Software Foundation; either version 2 of the License, or (at
//=== your option) any later version.
//===
//=== This program is distributed in the hope that it will be useful, but
//=== WITHOUT ANY WARRANTY; without even the implied warranty of
//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//=== General Public License for more details.
//===
//=== You should have received a copy of the GNU General Public License
//=== along with this program; if not, write to the Free Software
//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
//===
//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
//=== Rome - Italy. email: geonetwork@osgeo.org
//==============================================================================

package org.fao.geonet.exceptions;

public class MetadataLockedException extends RuntimeException {

private static final long serialVersionUID = -110149283987412689L;

public MetadataLockedException(String id) {
super("You can't edit the metadata with id " + id
+ " because it is locked by another editor.");
}

}
197 changes: 169 additions & 28 deletions core/src/main/java/org/fao/geonet/kernel/AccessManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,22 @@

package org.fao.geonet.kernel;

import jeeves.server.UserSession;
import jeeves.server.context.ServiceContext;
import static org.fao.geonet.repository.specification.OperationAllowedSpecs.hasMetadataId;
import static org.fao.geonet.repository.specification.OperationAllowedSpecs.hasOperation;
import static org.springframework.data.jpa.domain.Specifications.where;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringUtils;
import org.fao.geonet.ApplicationContextHolder;
import org.fao.geonet.constants.Geonet;
import org.fao.geonet.domain.Group;
import org.fao.geonet.domain.Metadata;
import org.fao.geonet.domain.IMetadata;
import org.fao.geonet.domain.MetadataSourceInfo;
import org.fao.geonet.domain.Operation;
import org.fao.geonet.domain.OperationAllowed;
Expand All @@ -41,32 +50,30 @@
import org.fao.geonet.domain.User;
import org.fao.geonet.domain.UserGroup;
import org.fao.geonet.domain.User_;
import org.fao.geonet.kernel.metadata.IMetadataManager;
import org.fao.geonet.kernel.setting.Settings;
import org.fao.geonet.repository.GroupRepository;
import org.fao.geonet.repository.GroupRepositoryCustom;
import org.fao.geonet.repository.MetadataRepository;
import org.fao.geonet.repository.OperationAllowedRepository;
import org.fao.geonet.repository.OperationRepository;
import org.fao.geonet.repository.SettingRepository;
import org.fao.geonet.repository.SortUtils;
import org.fao.geonet.repository.UserGroupRepository;
import org.fao.geonet.repository.UserRepository;
import org.fao.geonet.repository.specification.UserGroupSpecs;
import org.fao.geonet.utils.Log;
import org.jdom.Element;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.Specifications;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import static org.fao.geonet.repository.specification.OperationAllowedSpecs.hasMetadataId;
import static org.fao.geonet.repository.specification.OperationAllowedSpecs.hasOperation;
import static org.springframework.data.jpa.domain.Specifications.where;
import jeeves.server.UserSession;
import jeeves.server.context.ServiceContext;

/**
* Handles the access to a metadata depending on the metadata/group.
Expand Down Expand Up @@ -180,6 +187,24 @@ public Set<Integer> getUserGroups(UserSession usrSess, String ip, boolean editin
}
return hs;
}


public Set<Integer> getReviewerGroups(User user) throws Exception {
Set<Integer> hs = new HashSet<Integer>();
UserGroupRepository _userGroupRepository = ApplicationContextHolder.get().getBean(UserGroupRepository.class);

// get other groups
Specification<UserGroup> spec =
UserGroupSpecs.hasUserId(user.getId());
spec = Specifications
.where(spec)
.and(UserGroupSpecs.hasProfile(Profile.Reviewer));

hs.addAll(_userGroupRepository.findGroupIds(spec));

return hs;
}


public Set<Integer> getReviewerGroups(UserSession usrSess) throws Exception {
Set<Integer> hs = new HashSet<Integer>();
Expand Down Expand Up @@ -240,6 +265,16 @@ public Set<Integer> getVisibleGroups(final int userId) throws Exception {
public boolean canEdit(final ServiceContext context, final String id) throws Exception {
return isOwner(context, id) || hasEditPermission(context, id);
}

/**
* Returns true if, and only if, at least one of these conditions is satisfied: <ul> <li>the
* user is owner (@see #isOwner)</li> <li>the user has edit rights over the metadata</li> </ul>
*
* @param id The metadata internal identifier
*/
public boolean canEdit(final String id) throws Exception {
return isOwner(id) || hasEditPermission(id);
}

/**
* Return true if the current user is: <ul> <li>administrator</li> <li>the metadata owner (the
Expand All @@ -254,13 +289,47 @@ public boolean canEdit(final ServiceContext context, final String id) throws Exc
*/
public boolean isOwner(final ServiceContext context, final String id) throws Exception {

if(id == null) {
Log.error(Geonet.ACCESS_MANAGER, "id parameter on AccessManager.isOwner is null. This shouldn't be happening.");
return false;
}

if(context == null) {
Log.error(Geonet.ACCESS_MANAGER, "context parameter on AccessManager.isOwner is null. This shouldn't be happening.");
return false;
}

//--- retrieve metadata info
IMetadata info = context.getBean(IMetadataManager.class)
.getMetadataObjectNoPriv(Integer.valueOf(id));

if (info == null)
return false;
final MetadataSourceInfo sourceInfo = info.getSourceInfo();
return isOwner(context, sourceInfo);
}

/**
* Return true if the current user is: <ul> <li>administrator</li> <li>the metadata owner (the
* user who created the record)</li> <li>reviewer in the group the metadata was created</li>
* </ul>
*
* Note: old GeoNetwork was also restricting editing on harvested record. This is not restricted
* on the server side anymore. If a record is harvested it could be edited by default but the
* client application may restrict this condition.
*
* @param id The metadata internal identifier
*/
public boolean isOwner(final String id) throws Exception {

//--- retrieve metadata info
Metadata info = context.getBean(MetadataRepository.class).findOne(id);
IMetadata info = ApplicationContextHolder.get().getBean(IMetadataManager.class)
.getMetadataObjectNoPriv(Integer.valueOf(id));

if (info == null)
return false;
final MetadataSourceInfo sourceInfo = info.getSourceInfo();
return isOwner(context, sourceInfo);
return isOwner(sourceInfo);
}

/**
Expand Down Expand Up @@ -308,17 +377,52 @@ public boolean isOwner(ServiceContext context, MetadataSourceInfo sourceInfo) th
}

/**
* TODO javadoc.
* Return true if the current user is: <ul> <li>administrator</li> <li>the metadata owner (the
* user who created the record)</li> <li>reviewer in the group the metadata was created</li>
* </ul>
*
* Note: old GeoNetwork was also restricting editing on harvested record. This is not restricted
* on the server side anymore. If a record is harvested it could be edited by default but the
* client application may restrict this condition.
*
* @param sourceInfo The metadata source/owner information
*/
private String join(Set<Integer> set, String delim) {
StringBuilder sb = new StringBuilder();
String loopDelim = "";
for (Integer s : set) {
sb.append(loopDelim);
sb.append(s + "");
loopDelim = delim;
public boolean isOwner(MetadataSourceInfo sourceInfo) throws Exception {

final SecurityContext context = SecurityContextHolder.getContext();
Authentication auth = context.getAuthentication();
if (auth == null || !auth.isAuthenticated()) {
return false;
}

UserRepository userRepo = ApplicationContextHolder.get().getBean(UserRepository.class);

//--- check if the user is an administrator
UserDetails userDetails = (UserDetails) auth.getPrincipal();
User us = userRepo.findOneByUsername(userDetails.getUsername());
final Profile profile = us.getProfile();
if (profile == Profile.Administrator)
return true;

//--- check if the user is the metadata owner
//
if (sourceInfo.getOwner().equals(us.getId()))
return true;

//--- check if the user is a reviewer or useradmin
if (profile != Profile.Reviewer && profile != Profile.UserAdmin)
return false;

//--- if there is no group owner then the reviewer cannot review and the useradmin cannot administer
final Integer groupOwner = sourceInfo.getGroupOwner();
if (groupOwner == null) {
return false;
}
return sb.toString();
for (Integer userGroup : getReviewerGroups(us)) {
if (userGroup == groupOwner.intValue())
return true;
}
return false;
}

/**
Expand Down Expand Up @@ -347,7 +451,9 @@ public Element getContentReviewers(ServiceContext context, final Set<Integer> me
* @param metadataId the id of the metadata
*/
public boolean isVisibleToAll(final String metadataId) throws Exception {
Metadata metadata = ApplicationContextHolder.get().getBean(MetadataRepository.class).findOne(metadataId);
IMetadata metadata = ApplicationContextHolder.get().getBean(IMetadataManager.class)
.getMetadataObjectNoPriv(Integer.valueOf(metadataId));

if (metadata == null) {
return false;
} else {
Expand Down Expand Up @@ -396,7 +502,7 @@ public boolean canDynamic(final ServiceContext context, final String id) throws
* @param group the group to check
* @param opId the id of the operation to check for
*/
public boolean hasPermission(final Metadata metadata, final Group group, final int opId) {
public boolean hasPermission(final IMetadata metadata, final Group group, final int opId) {
OperationAllowedRepository opAllowedRepository = ApplicationContextHolder.get().getBean(OperationAllowedRepository.class);
return opAllowedRepository.findOneById_GroupIdAndId_MetadataIdAndId_OperationId(group.getId(), metadata.getId(), opId) != null;
}
Expand Down Expand Up @@ -432,6 +538,41 @@ public boolean hasEditPermission(final ServiceContext context, final String id)
return (!userGroupRepository.findAll(spec).isEmpty());
}


/**
* Check if current user can edit the metadata according to the groups where the metadata is
* editable.
*
* @param id The metadata internal identifier
*/
public boolean hasEditPermission(final String id) throws Exception {
ApplicationContext context = ApplicationContextHolder.get();
Authentication us = SecurityContextHolder.getContext().getAuthentication();
if (us == null || !us.isAuthenticated())
return false;


OperationAllowedRepository opAllowedRepository = context.getBean(OperationAllowedRepository.class);
UserGroupRepository userGroupRepository = context.getBean(UserGroupRepository.class);
List<OperationAllowed> allOpAlloweds = opAllowedRepository.findAll(where(hasMetadataId(id)).and(hasOperation(ReservedOperation
.editing)));
if (allOpAlloweds.isEmpty()) {
return false;
}

Specifications spec = where(UserGroupSpecs.hasProfile(Profile.Editor))
.and(UserGroupSpecs.hasUserId(context.getBean(UserRepository.class)
.findOneByUsername(us.getName()).getId()));

List<Integer> opAlloweds = new ArrayList<Integer>();
for (OperationAllowed opAllowed : allOpAlloweds) {
opAlloweds.add(opAllowed.getId().getGroupId());
}
spec = spec.and(UserGroupSpecs.hasGroupIds(opAlloweds));

return (!userGroupRepository.findAll(spec).isEmpty());
}

/**
* TODO javadoc.
*/
Expand Down Expand Up @@ -524,4 +665,4 @@ private long getAddress(String ip) {
return a1 << 24 | a2 << 16 | a3 << 8 | a4;
}
}
}
}
Loading