Mercurial > hg > AnnotationManagerN4J
changeset 15:58357a4b86de
ASSIGNED - # 249: Annotations shared in groups
https://it-dev.mpiwg-berlin.mpg.de/tracs/mpdl-project-software/ticket/249
line wrap: on
line diff
--- a/src/main/java/de/mpiwg/itgroup/annotations/Actor.java Fri Jul 13 20:41:02 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/Actor.java Tue Aug 28 20:23:12 2012 +0200 @@ -3,6 +3,7 @@ */ package de.mpiwg.itgroup.annotations; +import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore; import de.mpiwg.itgroup.annotations.old.NS; /** @@ -21,19 +22,21 @@ public abstract boolean isGroup(); /** - * Returns if this Actor is equivalent to an Actor with this id. If this is + * Returns if this Actor is equivalent to Person person. If this is * a Group returns true when the Person is in the Group. * - * @param userId + * @param person + * @param store AnnotationStore to check group membership * @return */ - public boolean isEquivalentWith(String userId) { - if (userId == null) return false; - if (userId.equals(getIdString())) { + public boolean isEquivalentWith(Person person, AnnotationStore store) { + if (person == null) return false; + if (person.equals(getIdString())) { return true; } - if (isGroup()) { - // TODO: check if person in group + if (isGroup() && store != null) { + // check if person in group + return store.isPersonInGroup(person, (Group) this); } return false; }
--- a/src/main/java/de/mpiwg/itgroup/annotations/Annotation.java Fri Jul 13 20:41:02 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/Annotation.java Tue Aug 28 20:23:12 2012 +0200 @@ -3,6 +3,8 @@ */ package de.mpiwg.itgroup.annotations; +import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore; + /** * @author casties * @@ -85,43 +87,44 @@ * Returns if the requested action is allowed on this annotation. * * @param action - * @param userId + * @param user + * @param store AnnotationStore to check group membership * @return */ - public boolean isActionAllowed(String action, String userId) { + public boolean isActionAllowed(String action, Person user, AnnotationStore store) { if (action.equals("read")) { Actor reader = getReadPermission(); if (reader == null) { return true; } else { - return reader.isEquivalentWith(userId); + return reader.isEquivalentWith(user, store); } } else if (action.equals("update")) { // require at least an authenticated user - if (userId == null) return false; + if (user == null) return false; Actor updater = getUpdatePermission(); if (updater == null) { return true; } else { - return updater.isEquivalentWith(userId); + return updater.isEquivalentWith(user, store); } } else if (action.equals("delete")) { // require at least an authenticated user - if (userId == null) return false; + if (user == null) return false; Actor updater = getUpdatePermission(); if (updater == null) { return true; } else { - return updater.isEquivalentWith(userId); + return updater.isEquivalentWith(user, store); } } else if (action.equals("admin")) { // require at least an authenticated user - if (userId == null) return false; + if (user == null) return false; Actor admin = getAdminPermission(); if (admin == null) { return true; } else { - return admin.isEquivalentWith(userId); + return admin.isEquivalentWith(user, store); } } return false;
--- a/src/main/java/de/mpiwg/itgroup/annotations/Group.java Fri Jul 13 20:41:02 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/Group.java Tue Aug 28 20:23:12 2012 +0200 @@ -20,6 +20,14 @@ this.name = name; } + public Group(String id, String uri, String name) { + super(); + this.id = id; + this.uri = uri; + this.name = name; + } + + @Override public boolean isGroup() { return true;
--- a/src/main/java/de/mpiwg/itgroup/annotations/Person.java Fri Jul 13 20:41:02 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/Person.java Tue Aug 28 20:23:12 2012 +0200 @@ -23,6 +23,13 @@ this.name = name; } + public Person(String id, String uri, String name) { + super(); + this.id = id; + this.uri = uri; + this.name = name; + } + @Override public boolean isGroup() { return false; @@ -35,4 +42,16 @@ return id; } + /** + * Returns a Person with this id or null. + * + * @param id + * @return + */ + public static Person createPersonWithId(String id) { + if (id != null) { + return new Person(id); + } + return null; + } }
--- a/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java Fri Jul 13 20:41:02 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java Tue Aug 28 20:23:12 2012 +0200 @@ -34,13 +34,13 @@ protected GraphDatabaseService graphDb; public static enum NodeTypes { - ANNOTATION, PERSON, TARGET + ANNOTATION, PERSON, TARGET, GROUP } protected List<Index<Node>> nodeIndexes; public static enum RelationTypes implements RelationshipType { - ANNOTATES, CREATED, PERMITS_ADMIN, PERMITS_DELETE, PERMITS_UPDATE, PERMITS_READ + ANNOTATES, CREATED, PERMITS_ADMIN, PERMITS_DELETE, PERMITS_UPDATE, PERMITS_READ, MEMBER_OF } public static String ANNOTATION_URI_BASE = "http://entities.mpiwg-berlin.mpg.de/annotations/"; @@ -53,6 +53,7 @@ nodeIndexes.add(NodeTypes.ANNOTATION.ordinal(), graphDb.index().forNodes("annotations")); nodeIndexes.add(NodeTypes.PERSON.ordinal(), graphDb.index().forNodes("persons")); nodeIndexes.add(NodeTypes.TARGET.ordinal(), graphDb.index().forNodes("targets")); + nodeIndexes.add(NodeTypes.GROUP.ordinal(), graphDb.index().forNodes("groups")); } protected Index<Node> getNodeIndex(NodeTypes type) { @@ -60,6 +61,60 @@ } /** + * @param userUri + * @return + */ + public Node getPersonNodeByUri(String userUri) { + if (userUri == null) return null; + Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri).getSingle(); + return person; + } + + + /** + * Returns List of Groups the person is member of. + * + * @param person + * @return + */ + public List<Group> getGroupsForPersonNode(Node person) { + ArrayList<Group> groups = new ArrayList<Group>(); + Iterable<Relationship> rels = person.getRelationships(RelationTypes.MEMBER_OF); + for (Relationship rel : rels) { + Node groupNode = rel.getEndNode(); + Actor group = createActorFromNode(groupNode); + // make sure we're getting a group + if (!(group instanceof Group)) { + logger.error("target of MEMBER_OF is not GROUP! rel="+rel); + continue; + } + groups.add((Group) group); + } + return groups; + } + + /** + * Returns if person with uri is in Group group. + * + * @param person + * @param group + * @return + */ + public boolean isPersonInGroup(Person person, Group group) { + Node pn = getPersonNodeByUri(person.getUriString()); + if (pn == null) return false; + // optimised version of getGroupsForPersonNode + Iterable<Relationship> rels = pn.getRelationships(RelationTypes.MEMBER_OF); + for (Relationship rel : rels) { + Node gn = rel.getEndNode(); + if (gn.getProperty("uri", "").equals(group.getUriString()) || gn.getProperty("id", "").equals(group.getId())) { + return true; + } + } + return false; + } + + /** * Returns the Annotation with the given id. * * @param id @@ -142,13 +197,14 @@ * @return */ protected Actor createActorFromNode(Node actorNode) { + String id = (String) actorNode.getProperty("id", null); String uri = (String) actorNode.getProperty("uri", null); String name = (String) actorNode.getProperty("name", null); String type = (String) actorNode.getProperty("TYPE", null); if (type != null && type.equals("PERSON")) { - return new Person(uri, name); + return new Person(id, uri, name); } else if (type != null && type.equals("GROUP")) { - return new Group(uri, name); + return new Group(id, uri, name); } return null; } @@ -209,7 +265,7 @@ */ Actor creator = annot.getCreator(); if (creator != null) { - Node creatorNode = getOrCreatePersonNode(creator); + Node creatorNode = getOrCreateActorNode(creator); getOrCreateRelation(creatorNode, RelationTypes.CREATED, annotNode); } @@ -300,7 +356,7 @@ } if (userUri != null) { // there should be only one - Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri).getSingle(); + Node person = getPersonNodeByUri(userUri); if (person != null) { Iterable<Relationship> relations = person.getRelationships(RelationTypes.CREATED); for (Relationship relation : relations) { @@ -380,11 +436,17 @@ return target; } - protected Node getOrCreatePersonNode(Actor actor) { - // Person is identified by URI + protected Node getOrCreateActorNode(Actor actor) { + // Person/Group is identified by URI or id String uri = actor.getUriString(); String name = actor.getName(); - Index<Node> idx = getNodeIndex(NodeTypes.PERSON); + String id = actor.getId(); + Index<Node> idx; + if (actor.isGroup()) { + idx = getNodeIndex(NodeTypes.GROUP); + } else { + idx = getNodeIndex(NodeTypes.PERSON); + } IndexHits<Node> persons = idx.get("uri", uri); Node person = persons.getSingle(); if (person == null) { @@ -392,12 +454,19 @@ Transaction tx = graphDb.beginTx(); try { person = graphDb.createNode(); - person.setProperty("TYPE", NodeTypes.PERSON.name()); + if (actor.isGroup()) { + person.setProperty("TYPE", NodeTypes.GROUP.name()); + } else { + person.setProperty("TYPE", NodeTypes.PERSON.name()); + } person.setProperty("uri", uri); idx.add(person, "uri", uri); if (name != null) { person.setProperty("name", name); } + if (id != null) { + person.setProperty("id", id); + } tx.success(); } finally { tx.finish(); @@ -416,7 +485,7 @@ protected void setPermissionRelation(Node annotNode, RelationTypes type, Actor actor) { Node newActorNode = null; if (actor != null) { - newActorNode = getOrCreatePersonNode(actor); + newActorNode = getOrCreateActorNode(actor); } Relationship rel = getRelation(annotNode, type, null); if (rel != null) { @@ -463,6 +532,13 @@ } } + /** returns the (first) Relationship of RelationTypes type from Node start. + * + * @param start + * @param type + * @param direction + * @return + */ protected Relationship getRelation(Node start, RelationTypes type, Direction direction) { Iterable<Relationship> rels; if (direction == null) {
--- a/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java Fri Jul 13 20:41:02 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java Tue Aug 28 20:23:12 2012 +0200 @@ -6,7 +6,6 @@ import java.io.IOException; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.restlet.data.Status; @@ -18,6 +17,7 @@ import org.restlet.resource.Put; import de.mpiwg.itgroup.annotations.Annotation; +import de.mpiwg.itgroup.annotations.Person; import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore; /** @@ -51,12 +51,12 @@ // TODO: what to return without id - list of all annotations? // do authentication - String authUser = this.checkAuthToken(entity); + Person authUser = Person.createPersonWithId(this.checkAuthToken(entity)); logger.debug("request authenticated=" + authUser); Annotation annot = getAnnotationStore().getAnnotationById(id); if (annot != null) { - if (! annot.isActionAllowed("read", authUser)) { + if (! annot.isActionAllowed("read", authUser, null)) { setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); return null; } @@ -83,7 +83,7 @@ setCorsHeaders(); // do authentication TODO: who's allowed to create? - String authUser = this.checkAuthToken(entity); + Person authUser = Person.createPersonWithId(this.checkAuthToken(entity)); logger.debug("request authenticated=" + authUser); if (authUser == null) { setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); @@ -141,7 +141,7 @@ logger.debug("annotation-id=" + id); // do authentication - String authUser = this.checkAuthToken(entity); + Person authUser = Person.createPersonWithId(this.checkAuthToken(entity)); logger.debug("request authenticated=" + authUser); Annotation annot = null; @@ -159,7 +159,7 @@ setStatus(Status.CLIENT_ERROR_NOT_FOUND); return null; } - if (! storedAnnot.isActionAllowed("update", authUser)) { + if (! storedAnnot.isActionAllowed("update", authUser, null)) { setStatus(Status.CLIENT_ERROR_FORBIDDEN); return null; } @@ -204,11 +204,11 @@ logger.debug("annotation-id=" + id); // do authentication - String authUser = this.checkAuthToken(entity); + Person authUser = Person.createPersonWithId(this.checkAuthToken(entity)); logger.debug("request authenticated=" + authUser); Annotation annot = getAnnotationStore().getAnnotationById(id); if (annot != null) { - if (! annot.isActionAllowed("delete", authUser)) { + if (! annot.isActionAllowed("delete", authUser, null)) { setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); return null; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorGroups.java Tue Aug 28 20:23:12 2012 +0200 @@ -0,0 +1,84 @@ +/** + * ReST API for accessing groups in the Annotation store. + */ +package de.mpiwg.itgroup.annotations.restlet; + +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.neo4j.graphdb.Node; +import org.restlet.data.Form; +import org.restlet.data.Status; +import org.restlet.ext.json.JsonRepresentation; +import org.restlet.representation.Representation; +import org.restlet.resource.Get; + +import de.mpiwg.itgroup.annotations.Actor; +import de.mpiwg.itgroup.annotations.Group; +import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore; + + +/** + * API for accessing groups in the Annotation store. + * + * @author casties + * + */ +public class AnnotatorGroups extends AnnotatorResourceImpl { + protected String getAllowedMethodsForHeader() { + return "OPTIONS,GET"; + } + + /** + * GET with JSON content-type. + * Parameters: + * user: short user name + * uri: user uri + * + * @param entity + * @return + */ + @Get("json") + public Representation doGetJSON(Representation entity) { + logger.debug("AnnotatorGroups doGetJSON!"); + setCorsHeaders(); + Form form = getRequest().getResourceRef().getQueryAsForm(); + String user = form.getFirstValue("user"); + String uri = form.getFirstValue("uri"); + if (uri == null || uri.isEmpty()) { + // get uri from user-id + uri = Actor.getUriFromId(user, false); + } + JSONArray results = new JSONArray(); + AnnotationStore store = getAnnotationStore(); + Node person = store.getPersonNodeByUri(uri); + if (person != null) { + List<Group> groups = store.getGroupsForPersonNode(person); + for (Group group : groups) { + JSONObject jo = new JSONObject(); + try { + jo.put("id", group.getId()); + jo.put("name", group.getName()); + jo.put("uri", group.getUriString()); + } catch (JSONException e) { + } + results.put(jo); + } + } + // assemble result object + JSONObject result = new JSONObject(); + try { + result.put("rows", results); + result.put("total", results.length()); + } catch (JSONException e) { + setStatus(Status.SERVER_ERROR_INTERNAL, "JSON Error"); + return null; + } + logger.debug("sending:"); + logger.debug(result); + return new JsonRepresentation(result); + + } +}
--- a/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java Fri Jul 13 20:41:02 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java Tue Aug 28 20:23:12 2012 +0200 @@ -532,7 +532,7 @@ return annot; } - @SuppressWarnings("unused") + @SuppressWarnings("unused") // i in for loop protected Actor getActorFromPermissions(JSONArray perms) throws JSONException { Actor actor = null; for (int i = 0; i < perms.length(); ++i) {
--- a/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorSearch.java Fri Jul 13 20:41:02 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorSearch.java Tue Aug 28 20:23:12 2012 +0200 @@ -15,6 +15,8 @@ import org.restlet.resource.Get; import de.mpiwg.itgroup.annotations.Annotation; +import de.mpiwg.itgroup.annotations.Person; +import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore; /** * Implements the "search" uri of the Annotator API. see @@ -41,7 +43,7 @@ logger.debug("AnnotatorSearch doGetJSON!"); setCorsHeaders(); // do authentication - String authUser = this.checkAuthToken(entity); + Person authUser = Person.createPersonWithId(this.checkAuthToken(entity)); logger.debug("request authenticated=" + authUser); Form form = getRequest().getResourceRef().getQueryAsForm(); @@ -53,10 +55,11 @@ JSONArray results = new JSONArray(); // do search logger.debug(String.format("searching for uri=%s user=%s", uri, user)); - List<Annotation> annots = getAnnotationStore().searchByUriUser(uri, user, limit, offset); + AnnotationStore store = getAnnotationStore(); + List<Annotation> annots = store.searchByUriUser(uri, user, limit, offset); for (Annotation annot : annots) { // check permission - if (!annot.isActionAllowed("read", authUser)) continue; + if (!annot.isActionAllowed("read", authUser, store)) continue; JSONObject jo = createAnnotatorJson(annot, (authUser == null)); if (jo != null) { results.put(jo);
--- a/src/main/java/de/mpiwg/itgroup/annotations/restlet/RestServer.java Fri Jul 13 20:41:02 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/RestServer.java Tue Aug 28 20:23:12 2012 +0200 @@ -165,6 +165,7 @@ router.attach("/annotator/annotations", AnnotatorAnnotations.class); router.attach("/annotator/annotations/{id}", AnnotatorAnnotations.class); router.attach("/annotator/search", AnnotatorSearch.class); + router.attach("/annotator/groups", AnnotatorGroups.class); // router.attach("",redirector); router.attach("/annotator", // ExtendedAnnotationInput.class);