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

Mark resources and values as deleted, and check permissions on links #186

Merged
merged 30 commits into from
Aug 10, 2016

Conversation

benjamingeer
Copy link

@benjamingeer benjamingeer commented Jul 12, 2016

The code for marking resources and values as deleted was incomplete and incorrect, so this is a reimplementation.

Previously, we had to make a new version of a value to mark it as deleted. Now this is necessary only for LinkValue (because its reference count has to be decremented to 0 first).

All resources and values that are marked as deleted now have a deleteDate as well as isDeleted true.

I implemented permission-checking on link values in the resources responder and the search responder.

Permissions are now stored in a single string literal as per #196, using the datatype property knora-base:hasPermissions. The format of this literal is documented in knora-base.tex.

I've also refactored some things in the resources responder, the values responder, and the routes and tests, and added comments.

Closes #53: When a TextValue containing standoff links is deleted, decrement the links' reference counts.

Closes #88: What permissions should a LinkValue for a standoff link have?

Closes #89: Permissions on links are not checked correctly.

Closes #132: Delete a resource.

Closes #182: Handle Permissions on Properties correctly when searching.

Closes #196: Store permissions in a single triple for more efficient queries.

Benjamin Geer added 3 commits July 11, 2016 15:44
@benjamingeer benjamingeer added the enhancement improve existing code or new feature label Jul 12, 2016
@benjamingeer benjamingeer added this to the August 2016 Release milestone Jul 12, 2016
Benjamin Geer added 4 commits July 12, 2016 12:36
@tobiasschweizer
Copy link
Contributor

Great, you fixed the bug that on value deletion some strange value IRI was written back in the response. Now it is the same as the one that was sent in the original request.

Hpwever, I do not fully understand the documention for the parameter id for DeleteValueResponseV1:

  • @param id the IRI of the value that was marked as deleted. This may be the same value IRI that was given in
    •             the [[DeleteValueRequestV1]], or it may be the IRI of a new version of that value.
      

How can there be a new version of that value be returned when it has been deleted just now? Concurrency?

@tobiasschweizer
Copy link
Contributor

I have just found a bug in ExtendedSearch: We forgot to the statement:

?resource knora-base:isDeleted false .

@tobiasschweizer
Copy link
Contributor

I added a fix to correctly URL encode IRIs for the delete request

@benjamingeer
Copy link
Author

How can there be a new version of that value be returned when it has been deleted just now?

This is explained in the design documentation:

https://github.com/dhlab-basel/Knora/blob/wip/delete-values/docs/rst/knora-api-server/design-documentation/triplestore-updates.rst

Normally, a value is marked as deleted without creating a new version of it. However, link values must be treated as a special case. Before a LinkValue can be marked as deleted, its reference count must be decremented to 0. Therefore, a new version of the LinkValue is made, with a reference count of 0, and it is this new version that is marked as deleted.

@benjamingeer
Copy link
Author

you fixed the bug that on value deletion some strange value IRI was written back in the response. Now it is the same as the one that was sent in the original request.

This wasn't a bug. Please read the description of this pull request above, paying special attention to this sentence:

Previously, we had to make a new version of a value to mark it as deleted. Now this is necessary only for LinkValue (because its reference count has to be decremented to 0 first).

@benjamingeer
Copy link
Author

The old behaviour was also documented:

https://github.com/dhlab-basel/Knora/blob/develop/docs/rst/knora-api-server/design-documentation/triplestore-updates.rst

'Deleting' a value means creating a new version, marked with knora-base:isDeleted and pointing to the previous version.

@tobiasschweizer
Copy link
Contributor

Ok, now I understand why in the case of a link a new version has to be created.

Could you please add a sentence to the documentation for case class DeleteValueResponseV1 referring to the documentation you have mentioned?

@@ -972,9 +972,7 @@

rdfs:subPropertyOf :systemProperty ;

rdfs:comment "Indicates when a resource was deleted"@en ;

:subjectClassConstraint :Resource ;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you remove the constraint because this can apply to a resource and/or a value?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

@tobiasschweizer
Copy link
Contributor

I do have a problem of understanding regarding the deletion of LinkValues. The following code ist from ValuesResponderV1.scala:

case linkValue: LinkValueV1 =>
                    // It's a LinkValue. Make a new version of it with a reference count of 0, and mark the new
                    // version as deleted.

                    val linkPropertyIri = knoraIriUtil.linkValuePropertyIri2LinkPropertyIri(findResourceWithValueResult.propertyIri)

                    for {
                        sparqlTemplateLinkUpdate <- decrementLinkValue(
                            sourceResourceIri = findResourceWithValueResult.resourceIri,
                            linkPropertyIri = linkPropertyIri,
                            removedTargetResourceIri = linkValue.objectIri,
                            userProfile = deleteValueRequest.userProfile
                        )

                        sparqlUpdate = queries.sparql.v1.txt.deleteLink(
                            dataNamedGraph = settings.projectNamedGraphs(findResourceWithValueResult.projectIri).data,
                            triplestore = settings.triplestoreType,
                            linkSourceIri = findResourceWithValueResult.resourceIri,
                            linkUpdate = sparqlTemplateLinkUpdate,
                            maybeComment = deleteValueRequest.deleteComment
                        ).toString()

                    } yield (sparqlUpdate, sparqlTemplateLinkUpdate.newLinkValueIri)

What happens if the direct link has a reference count of 2? Then it only should be decremented to 1, but the direct link should not be deleted, right?

This is how I understand this line: val deleteDirectLink = linkValueQueryResult.directLinkExists && newReferenceCount == 0

But in the template deleteLink, there is the following check taking place:

@* Delete the direct link. *@
        @if(linkUpdate.deleteDirectLink) {
            ?linkSource ?linkProperty ?linkTarget .
        } else {
            @{throw SparqlGenerationException(s"linkUpdate.deleteDirectLink must be true in this SPARQL template"); ()}
        }

So in our example that would be false since the reference count would be 1.

@benjamingeer
Copy link
Author

What happens if the direct link has a reference count of 2?

This, too, is explained in triplestore-updates.rst:

For consistency, every LinkValue contains a reference count. If the link property
is not knora-base:hasStandoffLinkTo, the reference count will always be either 1
(if the link exists) or 0 (if it has been deleted, in which case the link value will also be
marked with knora-base:isDeleted).

@benjamingeer
Copy link
Author

See also the documentation in knora-base.pdf:

valueHasRefCount (1) The reference count of the link. This is meaningful when the LinkValue describes resource references in Standoff text markup (see Section 4.1.3). Otherwise, the reference count will always be 1 (if the link exists) or 0 (if it has been deleted).

@tobiasschweizer
Copy link
Contributor

ok, so only a TextValue's standofflinks could create a ref count > 1.

in decrementLinkValue, I found the following comment:

// There's already a LinkValue for links between these two resources. Decrement its
                    // reference count.

Isn't this misleading? Of course there is "already a link". It is the one that you attempt to delete.

@benjamingeer
Copy link
Author

That's in a match-case expression that looks at the result of a SPARQL query to get the details of the link. The link should exist, but if it doesn't, the query result will be None. Look at the comment under case None.

@tobiasschweizer
Copy link
Contributor

Wouldn't it be better to say that you found what you expected in the first case?

@tobiasschweizer
Copy link
Contributor

Ok, I see now what decrementLinkValue does in case of a standoff link: the direct link will only be deleted if the ref count reached 0.

@benjamingeer
Copy link
Author

I'm going to keep working on #182. It also just occurred to me that the resource context query doesn't check permissions on isPartOf links, either.

@benjamingeer benjamingeer changed the title Mark resources and values as deleted Mark resources and values as deleted, and check permissions on links Jul 27, 2016
@tobiasschweizer
Copy link
Contributor

Ok, I will try to finish the review of this pull request by tomorrow.

If you have time could you have a look at #101 (comment)? Thx.

@benjamingeer
Copy link
Author

No need to review this again yet, because #182 is going to take a lot more work.

@benjamingeer
Copy link
Author

benjamingeer commented Jul 29, 2016

The main things that have changed since this pull request was last reviewed:

  • The resources responder checks permissions on link values for incoming and outgoing links in response to ResourceFullGetRequestV1, as described in What permissions should a LinkValue for a standoff link have? #88 (comment).
  • Link values for standoff links now always belong to knora-base:SystemUser.
  • I redesigned full-text and extended search to check permissions on values (including link values), as described in Handle Permissions on Properties correctly when searching #182 (comment).
  • knora-base:valueHasString is required on knora-base:Value again, because it's needed in search results.
  • I refactored some things in the resources responder, values responder, routes, and tests, for clarity and consistency, and added comments.
  • I added tests in ValuesResponderV1Spec, ResourcesResponderV1Spec, and SearchResponderV1Spec.
  • I updated knora-base.txt and the RST docs.
  • I reformatted all the code.

The resources responder still doesn't check permissions on link values for ResourceContextGetRequestV1. I tried implementing that, but it was much too slow (the query took over a minute). I think for now we can live without this check. Since the context query is actually just a specialised search, and since I don't think it can be implemented efficiently anyway, I think we should aim to eliminate it in API v2.

So I think this pull request is ready for review again.

@benjamingeer
Copy link
Author

I've implemented #196: the permissions of each resource or value are now stored in a single triple, using the datatype property knora-base:hasPermissions. The format of the literal object of this property is documented in knora-base.tex.

@benjamingeer
Copy link
Author

Since permission checking is now much faster, I added permission checking on link values for ResourceContextGetRequestV1.

@tobiasschweizer
Copy link
Contributor

I have a question regarding permission checking of incoming links. In ResourcesResponderV1 when incoming links are queried, it is checked if the user has the permission to see the referring resource and if he has permissions to see the link (by looking at the reification).

However, in case of a standoff link, the owner is the SystemUser (hasStandoffLinkToValue). So what would happen in that case? Would that case have to treated specially here?

When querying links (whether outgoing or incoming), ensure that the user has permission to see the source resource and the target resource. Also ensure that the user has permission to see the LinkValue, unless the link property is hasStandoffLinkTo. We're justified in making this property a special case because it's system-maintained as a side effect of standoff.

If I get this right, standoff links should always be displayed. However, the user might not be able to see the underlying TextValue that gives the link semantics.

@tobiasschweizer
Copy link
Contributor

The new way of representing permissions required the test data to be changed. I will have to do that for the BEOL test server. What would be the easiest way to do that? I can make a dump, change the data and load it back in.

@benjamingeer
Copy link
Author

However, in case of a standoff link, the owner is the SystemUser (hasStandoffLinkToValue). So what would happen in that case? Would that case have to treated specially here?

Yes, it's treated specially. To see a standoff link, the user only needs permission to see the source and target resources. This is documented in knora-base.tex section 5.2 (Permissions):

"To view a link between resources, a user needs permission to view the source and target resources. He also needs permission to view the LinkValue representing the link, unless the link property is hasStandoffLinkTo."

And in section 4.1.3 (StandoffLink):

"Link values created automatically for resource references in standoff are automatically visible to all users, as long as they have permission to see the source and target resources."

This special case is implemented in PermissionUtilV1.getUserPermissionOnLinkValueV1.

The new way of representing permissions required the test data to be changed.

I wrote a program to change the test data. The test data on the wip/delete-values branch has already been changed. To update the permissions in any Turtle file, you can use this command in SBT:

org.knora.webapi.util.TransformTestData permissions input-file output-file

The first argument currently has to be permissions, but this is intended to be a general-purpose framework for transforming test data in different ways.

@tobiasschweizer
Copy link
Contributor

got it: if (predicateIri == OntologyConstants.KnoraBase.HasStandoffLinkTo) { Some(permissionsToV1PermissionCodes(OntologyConstants.KnoraBase.ViewPermission)) }

Regrading permissions: Great, I will try to run the program with he beol data

@tobiasschweizer
Copy link
Contributor

You refactored search so only one query is done (before, we had separate queries for paging and the actual results).

Now, search results may be filtered out if the user has no permissions to see them (changing the number of search results).

Does this get us into trouble somehow? I do not remember the reason, but we designed the query so we could do the counting directly on the basis of the results returned by the triplestore.

@benjamingeer
Copy link
Author

The previous design relied on the triplestore to do counting and paging. The SPARQL had to count and return one row per matching resource so the OFFSET and LIMIT would be correct for paging. The revised design does all the counting and paging in Scala, so it's fine if the SPARQL returns more than one row per matching resource.

@benjamingeer benjamingeer merged commit 7153fba into develop Aug 10, 2016
@benjamingeer benjamingeer deleted the wip/delete-values branch August 10, 2016 20:03
benjamingeer pushed a commit that referenced this pull request Sep 5, 2016
* feature (consistency): Simplify consistency checking rules.

- Allow a required property to have only a value marked as deleted.

- Rename properties used in knora-base for consistency checking to make them clearer.

- Add comments.

* feature (store): Add consistency check optimisations suggested by Ontotext.

- Update GraphdBConsistencyCheckingSpec to test the new consistency checking rules.

- Add missing cardinalities for hasStandoffLinkTo and hasStandoffLinkToValue to knora-base:Resource,
  and update test data accordingly.

* docs: Add documentation for optimised GraphDB consistency rules.

* feature (store): Adjust scripts and configuration for GraphDB 7.0.3.

* test: Add test for property with no cardinality.

* fix (webapi): Redesign value deletion as per #63.

* feature (webapi): Implement resource deletion.

- Refactor some code for the context query in the resources responder.

* feature (webapi): Add test for resource deletion (#132).

- Fix link deletion.

* docs: Update docs about deletion.

* feature (webapi): Add an E2E test for deleting a resource.

- Rename all 'rapierPath' to 'knoraApiPath.

* test: Add E2E tests for creating and deleting values.

- Distinguish between the 'anything' test user and the root user.

* test: Add E2E tests for changing and deleting more value types.

* fix (exclude deleted resources from extended search): check for deleted flag

* fix (URL encode IRIs): URL encode IRIs for delete request

* feature (webapi): WIP for pull request #186.

* feature (webapi): WIP for pull request #186.

* fix (webapi): Check permissions on LinkValues for incoming links (issue #88).

- Always grant view permission on LinkValues for hasStandoffLinkTo.
- Refactor link querying in ValuesResponderV1.
- Use ?prop and ?obj in SPARQL rather than ?p and ?o, for consistency and code reuse.

* doc: Update various things in knora-base.tex.

- Describe the new deleting design.
- Describe the SystemUser.
- Remove ideas about future standoff development that are obsolete in the new standoff design.
- Make the \issue{} command point to GitHub issues.

* docs: Clarify permissions on standoff links in knora-base.tex.

* style (webapi): Add comments to clarify value creation in a new resource.

* test: Add test for deleting two text values containing the same standoff resource reference.

* test: Add tests of permission-checking on incoming and outgoing links (issues #88 and #89).

* fix (webapi): Fix permission checking on outgoing links.

* style (webapi): Correct comments and variable names.

* fix (webapi): Check permissions on values in results of extended search.

- Require valueHasString on knora-base:Value.

* test: Remove incorrect test data (issue #17).

* fix (webapi): Check permissions on values in results of full-text search.

* style (webapi): Use IRI instead of String.

* style (webapi): Reformat code.

* feature (store): Update config and scripts for GraphDB 7 running as a stand-alone server.

* test: Fix some test data.

* docs: Update knora-base.tex.

* docs: Update consistency checking doc.

* fix (ontologies): Add missing rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted for consistency checking.

* feature (webapi): Add check for missing cardinalities in values.

* test: Fix typo.

* test: Add an extended search test with three criteria to check performance.

* feature (webapi): Store permissions in a single triple for more efficent queries (#196)

* feature (webapi): Check permissions in context query.

* feature (webapi): Check permissions in context query.

* docs: Clarify requirements regarding use of subjectClassConstraint and objectClassConstraint.

* docs (typos)

- it is an honour for me to fix your typos

* docs: Clarify the syntax of inference and consistency rules.
@benjamingeer benjamingeer mentioned this pull request Jul 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement improve existing code or new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants