-
Notifications
You must be signed in to change notification settings - Fork 29
Zarr private links #6367
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
Merged
Merged
Zarr private links #6367
Changes from all commits
Commits
Show all changes
74 commits
Select commit
Hold shift + click to select a range
68ab52b
change schema
leowe 554259c
add first version
leowe 5130ed3
reformat
leowe e067bc5
adding debugging
leowe 10f35e2
remove printlns
leowe 7c3493e
add evolution
leowe a4b80ad
fix evolution
leowe 1c77305
add tokens to dsremotetracingstore requests
leowe e5ab0f5
reformat
2b74b92
add CRUD for privatelinks
c17a875
add variable changes
fda0f57
newer evolution version
bf06570
Merge branch 'master' into zarr-private-links
6a30899
use fromString
de3ee17
remove s from uninterpolated string
30707bf
Merge branch 'master' into zarr-private-links
leowe cc218e3
change table name to fit standard
784f332
implement rudimentary list route for annotation private links
philippotto 2a37459
Update CHANGELOG.unreleased.md
leowe 7d3a8fd
implement rudimentary create/list/delete frontend for private links i…
philippotto f75ca1f
Merge branch 'zarr-private-links' of github.com:scalableminds/webknos…
philippotto 7629128
add pr feedback
61d2b49
add update access query
3c1ff8d
reformat
e9d06b6
convert id to string
1f9a369
Merge branch 'master' into zarr-private-links
d3026bf
re-add NOT FOUND messages
9993006
fix changelog
c70eb13
using NOT_FOUND correctly
1a87e17
fix delete route usage and adapt to new routes
philippotto 6cf327a
remove _ in public writes and use JsonOk
9115ff6
Merge branch 'zarr-private-links' of github.com:scalableminds/webknos…
philippotto c1d132f
add readaccessquery
cfb08da
add expiry date UI, use antd List, refactor query hooks etc
philippotto 8b1f1ce
Merge branch 'zarr-private-links' of github.com:scalableminds/webknos…
philippotto 80629da
update update route
ea78bc0
complete expiration date editing; improve error messages; use loading…
philippotto e98bf11
clean up UI
philippotto 5174c0e
dont hardcode annotation id; extract into own modal
philippotto e2add06
highlight expired links
philippotto cf0f04c
fix linting
philippotto 38f3f92
Update frontend/javascripts/oxalis/view/action-bar/private_links_view…
philippotto df88da1
format
philippotto ab23355
use correct url schema
philippotto 76ab744
rename endpoints to links
philippotto 2d3713b
copy layer-specific urls via dropdown
philippotto dcf91a0
use correct names for volume tracings when copying zarr links
philippotto 11b67ac
Update frontend/javascripts/oxalis/view/action-bar/tracing_actions_vi…
philippotto 035d9ce
Merge branch 'master' into zarr-private-links
a0e7ced
incorporate pr feedback
0cde222
re-add messagesprovider
b996307
reformat
a221a0f
default 30 day expiration period; show loading spinner when links are…
philippotto e33939f
Merge branch 'zarr-private-links' of github.com:scalableminds/webknos…
philippotto 937fedb
add /data to zarr links
philippotto 51228a9
update changelog
philippotto 823b21f
incorporate pr feedback
philippotto b04764c
center the 'Reloading webknossos...' message horizontally and vertically
philippotto e3a6fc7
add target=_blank for zarr doc link
philippotto 58ea063
also add rel='noreferrer'
philippotto 5ec3eb7
also show zarr link in dataset share modal
philippotto 1b6885a
clarify that skeletons are not shared via zarr
philippotto 2d86333
use momentjs for expiration calculation
philippotto f0edfc9
Merge branch 'master' of github.com:scalableminds/webknossos into zar…
philippotto dbbdc55
add missing evolution (got lost during merge)
philippotto 54e260e
fix schema version in migration
philippotto 7fbd48e
fix linting
philippotto 2e64f07
add reversion
75458f3
rename reversion
d3ceec8
add swagger annotations
3cb74f6
change NOT_FOUND in swagger annotation to status codes
3d4c7cc
Merge branch 'master' into zarr-private-links
e00b064
finish merge
4425899
pretty
fm3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
package controllers | ||
|
||
import com.mohiva.play.silhouette.api.Silhouette | ||
import com.scalableminds.util.accesscontext.GlobalAccessContext | ||
import com.scalableminds.util.tools.Fox | ||
import com.scalableminds.util.tools.FoxImplicits | ||
import io.swagger.annotations._ | ||
import play.api.libs.json._ | ||
|
||
import javax.inject.Inject | ||
import models.annotation._ | ||
import oxalis.security.WkEnv | ||
import play.api.mvc.{Action, AnyContent, PlayBodyParsers} | ||
import utils.ObjectId | ||
|
||
import scala.concurrent.ExecutionContext | ||
@Api | ||
class AnnotationPrivateLinkController @Inject()( | ||
annotationDAO: AnnotationDAO, | ||
annotationService: AnnotationService, | ||
annotationPrivateLinkDAO: AnnotationPrivateLinkDAO, | ||
annotationPrivateLinkService: AnnotationPrivateLinkService, | ||
sil: Silhouette[WkEnv])(implicit ec: ExecutionContext, val bodyParsers: PlayBodyParsers) | ||
extends Controller | ||
with FoxImplicits { | ||
|
||
@ApiOperation(hidden = true, value = "") | ||
def lookupPrivateLink(accessToken: String): Action[AnyContent] = Action.async { implicit request => | ||
for { | ||
annotationPrivateLink <- annotationPrivateLinkDAO.findOneByAccessToken(accessToken) | ||
_ <- bool2Fox(annotationPrivateLink.expirationDateTime.forall(_ > System.currentTimeMillis())) ?~> "Token expired" ~> 404 | ||
annotation: Annotation <- annotationDAO.findOne(annotationPrivateLink._annotation)(GlobalAccessContext) | ||
writtenAnnotation <- annotationService.writesAsAnnotationSource(annotation) | ||
} yield Ok(writtenAnnotation) | ||
} | ||
|
||
@ApiOperation(value = "List all existing private zarr links for a user", nickname = "listPrivateLinks") | ||
@ApiResponses( | ||
Array(new ApiResponse(code = 200, message = "JSON object containing string that private link was deleted."), | ||
new ApiResponse(code = 400, message = badRequestLabel))) | ||
def list: Action[AnyContent] = sil.SecuredAction.async { implicit request => | ||
for { | ||
links <- annotationPrivateLinkDAO.findAll | ||
linksJsonList <- Fox.serialCombined(links)(annotationPrivateLinkService.publicWrites) | ||
} yield Ok(Json.toJson(linksJsonList)) | ||
} | ||
|
||
@ApiOperation(value = "List all existing private zarr links for a user for a given annotation", | ||
nickname = "listPrivateLinksByAnnotation") | ||
@ApiResponses( | ||
Array(new ApiResponse(code = 200, message = "JSON object containing string that private link was deleted."), | ||
new ApiResponse(code = 400, message = badRequestLabel))) | ||
def listByAnnotation(@ApiParam(value = "The id of the annotation") annotationId: String): Action[AnyContent] = | ||
sil.SecuredAction.async { implicit request => | ||
for { | ||
annotationIdValidated <- ObjectId.fromString(annotationId) | ||
links <- annotationPrivateLinkDAO.findAllByAnnotation(annotationIdValidated) | ||
linksJsonList <- Fox.serialCombined(links)(annotationPrivateLinkService.publicWrites) | ||
} yield Ok(Json.toJson(linksJsonList)) | ||
} | ||
|
||
@ApiOperation(value = "Get the private zarr link for a user for a given id if it exists", nickname = "getPrivateLink") | ||
@ApiResponses( | ||
Array( | ||
new ApiResponse(code = 200, message = "JSON object containing string that private link was deleted."), | ||
new ApiResponse(code = 400, message = badRequestLabel), | ||
new ApiResponse(code = 404, message = badRequestLabel) | ||
)) | ||
def get(@ApiParam(value = "The id of the private link") id: String): Action[AnyContent] = sil.SecuredAction.async { | ||
implicit request => | ||
for { | ||
idValidated <- ObjectId.fromString(id) | ||
|
||
annotationPrivateLink <- annotationPrivateLinkDAO.findOne(idValidated) | ||
_ <- bool2Fox(annotationPrivateLink.expirationDateTime.forall(_ > System.currentTimeMillis())) ?~> "Token expired" ~> NOT_FOUND | ||
_ <- annotationDAO.findOne(annotationPrivateLink._annotation) ?~> "annotation.notFound" ~> NOT_FOUND | ||
|
||
annotationPrivateLinkJs <- annotationPrivateLinkService.publicWrites(annotationPrivateLink) | ||
} yield Ok(annotationPrivateLinkJs) | ||
} | ||
|
||
@ApiOperation( | ||
value = """Creates a given private link for an annotation for zarr streaming | ||
Expects: | ||
- As JSON object body with keys: | ||
- annotation (string): annotation id to create private link for | ||
- expirationDateTime (Optional[bool]): optional UNIX timestamp, expiration date and time for the link | ||
""", | ||
nickname = "createPrivateLink" | ||
) | ||
@ApiImplicitParams( | ||
Array( | ||
new ApiImplicitParam(name = "annotationPrivateLinkParams", | ||
required = true, | ||
dataTypeClass = classOf[AnnotationPrivateLinkParams], | ||
paramType = "body"))) | ||
@ApiResponses( | ||
Array( | ||
new ApiResponse(code = 200, message = "JSON object containing string that private link was deleted."), | ||
new ApiResponse(code = 400, message = badRequestLabel), | ||
new ApiResponse(code = 404, message = badRequestLabel), | ||
new ApiResponse(code = 403, message = badRequestLabel) | ||
)) | ||
def create: Action[AnnotationPrivateLinkParams] = sil.SecuredAction.async(validateJson[AnnotationPrivateLinkParams]) { | ||
implicit request => | ||
val params = request.body | ||
val _id = ObjectId.generate | ||
val accessToken = annotationPrivateLinkService.generateToken | ||
for { | ||
annotationId <- ObjectId.fromString(params.annotation) | ||
_ <- annotationDAO.assertUpdateAccess(annotationId) ?~> "notAllowed" ~> FORBIDDEN | ||
_ <- annotationPrivateLinkDAO.insertOne( | ||
AnnotationPrivateLink(_id, annotationId, accessToken, params.expirationDateTime)) ?~> "create.failed" | ||
inserted <- annotationPrivateLinkDAO.findOne(_id) | ||
js <- annotationPrivateLinkService.publicWrites(inserted) | ||
} yield Ok(js) | ||
} | ||
|
||
@ApiOperation( | ||
value = """Updates a given private link for an annotation for zarr streaming | ||
Expects: | ||
- As JSON object body with keys: | ||
- annotation (string): annotation id to create private link for | ||
- expirationDateTime (Optional[bool]): optional UNIX timestamp, expiration date and time for the link | ||
""", | ||
nickname = "updatePrivateLink" | ||
) | ||
@ApiImplicitParams( | ||
Array( | ||
new ApiImplicitParam(name = "annotationPrivateLinkParams", | ||
required = true, | ||
dataTypeClass = classOf[AnnotationPrivateLinkParams], | ||
paramType = "body"))) | ||
@ApiResponses( | ||
Array( | ||
new ApiResponse(code = 200, message = "JSON object containing string that private link was deleted."), | ||
new ApiResponse(code = 400, message = badRequestLabel), | ||
new ApiResponse(code = 404, message = badRequestLabel), | ||
new ApiResponse(code = 403, message = badRequestLabel) | ||
)) | ||
def update(@ApiParam(value = "The id of the private link") id: String): Action[AnnotationPrivateLinkParams] = | ||
sil.SecuredAction.async(validateJson[AnnotationPrivateLinkParams]) { implicit request => | ||
val params = request.body | ||
for { | ||
annotationId <- ObjectId.fromString(params.annotation) | ||
idValidated <- ObjectId.fromString(id) | ||
aPLInfo <- annotationPrivateLinkDAO.findOne(idValidated) ?~> "annotation private link not found" ~> NOT_FOUND | ||
_ <- annotationDAO.assertUpdateAccess(aPLInfo._annotation) ?~> "notAllowed" ~> FORBIDDEN | ||
_ <- annotationDAO.assertUpdateAccess(annotationId) ?~> "notAllowed" ~> FORBIDDEN | ||
_ <- annotationPrivateLinkDAO.updateOne(idValidated, annotationId, params.expirationDateTime) ?~> "update.failed" | ||
updated <- annotationPrivateLinkDAO.findOne(idValidated) ?~> "not Found" | ||
js <- annotationPrivateLinkService.publicWrites(updated) ?~> "write failed" | ||
} yield Ok(js) | ||
} | ||
|
||
@ApiOperation(value = "Deletes a given private link for an annotation for zarr streaming", | ||
nickname = "deletePrivateLink") | ||
@ApiResponses( | ||
Array( | ||
new ApiResponse(code = 200, message = "JSON object containing string that private link was deleted."), | ||
new ApiResponse(code = 400, message = badRequestLabel), | ||
new ApiResponse(code = 404, message = badRequestLabel), | ||
new ApiResponse(code = 403, message = badRequestLabel) | ||
)) | ||
def delete(@ApiParam(value = "The id of the private link") id: String): Action[AnyContent] = sil.SecuredAction.async { | ||
implicit request => | ||
for { | ||
idValidated <- ObjectId.fromString(id) | ||
aPLInfo <- annotationPrivateLinkDAO.findOne(idValidated) ?~> "notFound" ~> NOT_FOUND | ||
_ <- annotationDAO.assertUpdateAccess(aPLInfo._annotation) ?~> "notAllowed" ~> FORBIDDEN | ||
_ <- annotationPrivateLinkDAO.deleteOne(idValidated) ?~> "delete failed" | ||
} yield JsonOk("privateLink deleted") | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.