-
Notifications
You must be signed in to change notification settings - Fork 3
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
add Sharing NG endpoints #112
Conversation
The web ui currently needs to PROPFIND all path segments to receive sharing information and look up the fileid for path segments... Some thoughts: how do we get all driveItems that between the root and a child /a/b/c/d.txt?
for that the path in the parentReference needs to have a determinable path:
https://graph.microsoft.com/v1.0/drives/C12644A14B0A7750/items better to always return the This should always work: ah no it lacks the parent reference
|
I think sharing roles are best sent as an odata instance annotation of the collection returned when listing permissions: {
"@libre.graph.permissions.roles.allowedValues": { "read", "write", "owner", "editor" },
"value": [
{
"id": "67445fde-a647-4dd4-b015-fc5dafd2821d",
"roles": [
"read"
],
"shareId": "TODO the share id?",
"link": {
"type": "view",
"webUrl": "https://cloud.example.org/TODO-URL-to-use-in-the-browser-bar"
}
},
{
"id": "81d5bad3-3eff-410a-a2ea-eda2d14d4474",
"roles": [
"write"
],
"shareId": "TODO the share id?",
"expirationDateTime": "2018-07-15T14:00:00.000Z",
"hasPassword": "false,",
"grantedTo": [
{
"user": {
"id": "4c510ada-c86b-4815-8820-42cdf82c3d51",
"displayName": "Albert Einstein"
}
}
],
"invitation": {
"email": "[email protected]",
"signInRequired": true
},
"link": {
"webUrl": "https://cloud.example.org/TODO-URL-to-use-in-the-browser-bar"
}
}
]
} The allowed values can be configured in a way, similar to other role and permission relationships are managed in microsoft graph: the The Annotations can have a qualifier separated by {
"@context": "http://host/service/$metadata#Customers",
"@com.example.customer.setkind": "VIPs",
"value": [
{
"@com.example.display.highlight": true,
"ID": "ALFKI",
"[email protected]": { "title": true, "order": 1 },
"CompanyName": "Alfreds Futterkiste",
"[email protected]#simple": { "order": 2 }
}
]
} It feels more like qualifying a CSS class. So, I think the annotation identifier is ok. Now for the value. I chose readable identiffiers, because I think that makes the api better understandable. We could use uuids then clients would have to look up the corresponding sharing roles at new the When inviting a user or updating a permission I would prefer to use the name so the api stays compatible with microsoft graph as much as possible. {
"@libre.graph.permissions.roles.allowedValues": {
{ "name":"read", "displayname":"Viewer" },
{ "name":"write", "displayname":"Editor" },
{ "name":"owner", "displayname":"Manager" },
{ "name":"foo", "displayname":"Fooer", "description":"Can foo things, but not bar them." }
},
"value": [
{
"id": "67445fde-a647-4dd4-b015-fc5dafd2821d",
"roles": [
"read"
],
... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I think we need some good examples that fit the use-cases for ocis.
It's still somewhat unclear to me how the /invite
this is supposed to work.
Is it only supposed to be used for sharing with other users and groups? Are "public" shares supposed to be created via /createLink
If that is the case we might want to remove the requireSignIn
and password
properties from the properites of the invite
body.
api/openapi-spec/v1.0.yaml
Outdated
properties: | ||
type: | ||
type: string | ||
description: Optional. The type of sharing link to create. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is optional, what kind of link is created, when no type is specified? If only a certain set of types is allowed I think we should specify those values here via enum
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICT the link type is redundant to sharing roles. I made the latter discoverable at the /roleManagement/permissions/roleDefinitions
endpoint. I think we can probably leave out link types and reuse roles for links as well ...
We need to fix the {
"value": [
{
"driveType": "grant",
"id": "storage-users-1$some-admin-user-id-0000-000000000000!c37cfa1b-f93c-407d-a2e1-ca9d102cc7df",
"name": "",
"owner": {
"user": {
"displayName": "",
"id": "some-admin-user-id-0000-000000000000"
}
},
"quota": {
"remaining": 335284809728,
"state": "normal",
"total": 0,
"used": 8
},
"root": {
"id": "storage-users-1$some-admin-user-id-0000-000000000000!c37cfa1b-f93c-407d-a2e1-ca9d102cc7df",
"webDavUrl": "https://cloud.ocis.test/dav/spaces/storage-users-1$some-admin-user-id-0000-000000000000%21c37cfa1b-f93c-407d-a2e1-ca9d102cc7df",
"permissions": [
{
"id": "81d5bad3-3eff-410a-a2ea-eda2d14d4474",
"roles": [
"write"
],
"shareId": "TODO the share id?",
"expirationDateTime": "2018-07-15T14:00:00.000Z",
"hasPassword": "false,",
"grantedTo": [
{
"user": {
"id": "4c510ada-c86b-4815-8820-42cdf82c3d51",
"displayName": "Albert Einstein"
}
}
],
"invitation": {
"email": "[email protected]",
"signInRequired": true
},
"link": {
"webUrl": "https://cloud.example.org/TODO-URL-to-use-in-the-browser-bar"
}
}
]
},
"webUrl": "https://cloud.ocis.test/f/storage-users-1$some-admin-user-id-0000-000000000000%21c37cfa1b-f93c-407d-a2e1-ca9d102cc7df"
}
]
} onedrive allows listing all received shares regardless of their mount status by creating a driveItem ... maybe on the fly ... that is wrapped around the remoteItem in the but that still does not help us because we cannot find a difference in that mountpoint driveItem before and after quicklinking it. We could leave out the On the graph api All driveItems in the sharedWithMe result set have a parentReference:
It is the same for all items, but I guess only because quicklinks will alll land in my personal space ... 🤔 They do not contain a drive item this all does not yet deal with how to 'hide' shares ... 😞 |
Removing' a folder only seems to wipe it from the lists that are queried by the web ui ... {
"HttpStatusCode": 200,
"RetryAfterHeader": null,
"error": {
"code": 3000,
"debugMessage": "Item not found or access denied.",
"isExpected": true,
"message": "This item might have been deleted, expired, or you might not have permission to access it. Contact the owner of this item for more information.",
"stackTrace": "3d3c5b6e1ebb7d041:R2FYwkV\/COoO7cMpIE1+bV4corvUIUSf\/DbVywcRQpMrXngNTWls8LjMpQTL4nxxbZWZmjy1Lnk0kDwUrchkw1VTuFxlJe3nLauY8X0S0t1i93UTr4vhEM3SWfpDKVISVEaQ9p\/TDHFoSs\/GCqWmGmmUNHNy73fGfoVGxwCCCfZV9QPj5AkzD1+sBlCWjw5UgbXJsAs6l8MXX9QbuJSm04VCFL8VWgB\/9UmIfbTiDaxI0Y9p4bdc2iAjnF\/gBdb0KdG8BY7D+AzYKnuCIycP6YeyiyU73T6GE0rgjkxnp1iAZM+9HpQ6wraecMwoaJpLLINcuJnu9ZGsO7\/bPCM1mwrz44e2yIPRy8PwdyP5LIsaKWeltI4kNfI5Yhy9WVRdNDE3FX3xhsjiEpzgoeWifHJa\/y1KNip+TY\/\/AW00HUAehHnJFTttpbm+nceUGRj01D9AtKdlz1NSZ6KWn59NaFOEIh0Y0PMUeaVhQtZWH3XqgeLSnGuWmQiVMBJ\/IQU9Wq9EIHlxKtQWX36l49ljrdckdXJ4KuTsAqj9VAyLUbYxnAFak2ePJyQISWWP546247AB0SWOut4fYl1PkcuCJynnRI8MYRRDcIDvSqh6KoFUdnrL2hm1MzZU+FQmn5mhB9PMADWdNGmtNEdeRL62kOT7f4OgPFk+Pw0fDzgIVUbz\/sJbssZ5E\/2Rh1iCvi5ZYzu0PN7\/\/7o\/yzhdO8m0d8tFXx0tXuOwvUe4I+nYxszQwGeHosJGtct4GgEd8lxY4eN0tuN4IclxzI+vw40TRAZ5sR4x9m6q1kqvuI5K2+K1tKeY9AJWv2xsmRhFr3ZMrxZ6iWx9T0SsDZJ63BKdtCh0Vyo0e\/EU87LYWkSZ+d7YGlcYz0fEX6Ft\/fE5VYw9nvisAt+J8FKlmmKBpJFvSAXwlmXiTfXdDeSkUo6hXgAcM1LaW38WQ4wUaaF14x1vSonvWLleD90WivDVHxgn8qndmMiEl3zQ0ZOZNSmfzw5zD9lxDA7j\/wrEw1kOF6dLCqMKf9umdRjSmBFKGpCXryTcCfr22xLYB4pxfjyYjKOhp90e+AJL2QfGiovn1UaqsqV8Rmk2KxPFHXiai5pjm9Nkzg\/WrOLTnWevSkGIro3dEGC6tlphDyMUAu1yjLPToSGxpMwBWqimnWtdBXme7t26cUfRalVSzmseYDg1gdYZAJ\/hS7krwAqWeZ4T0J+RtStNZ\/M9FeN+vEP737mPFdyLDhEjxSEUtNNzwTgDQ9hFrPMaS7+smb+tYxr\/LyJuRzKPRMDCtZpw0DhDX7jow240GtQlFW3b9l5\/AtqGg9g2vQ2Klrm8MVcVZR7XCMJ\/3LiKHh8PH0WNfTKn8D+e8wPqsaV3GBTUfcqPMiYk74fOY+iQHVu2yZn+zu+Bd+U3oAXY6NGzUMIYhsXzN72rTLCI\/1zuETVA7ASJGYO2aMs5un67G9Wnz+LrEcM+RMmBGcXK0oZwxPe1h0Nl9GmX\/T4uoqJoMmt3gI1NsX9JLHKORRVsraAJHha9ITg8MMCMWfC9R+e7a3XE07ooqwNbuinEI2ydtFwQPzvRMMgNMRqQUgSUaexaqOdzEO7V3tKSLjNtOeFy6vCPR8d4AqH95knVI9fTv+RIsLjGtb6VjAEZ6CD8hgMvNT7+rpzzQmtYVIyCWrN0CgRlkoSED8Dr18dl+csi05vTRSBAgzcz\/o9k5SYR9lbD81pO3NC+\/8Z\/EUtW1gOUwSHauvIHY4s1ruyRRj4AIZXuCQ12ZgzLVAgUy7J4bGrWIRnys5\/HnwKcSywtZQNmiGpHiMmmV7nETvPdJtfwGkXC0xb9OZ9nNOy5GBqDC9bjAon\/5bEP13EoeoT20pQNHASzCie1zsCdXHIZmJJz8mHz28kHhpd4iO0Wdi4NAbEM+ygxEhVJYx+yPN9gYYg+ndv40majhLPeok8vJEIAMC6d7xL6+6Tmu3Sv+xoHQECBgsZh1thOX+L83EHKkw3\/3WM3HAjndgcpoCYSFHLHYzSZPDOGnxZ0o1ObGj5C9OwILfI+9z\/rJp9zwV5saL07zeVbmNen9C+mkDRFmbgSeaK8OR3ypki2IOnXDTDgVHKQ3qNejcGsoldjCdL1zpy5455g2nPdy8\/J7EEUUNxZ3j8QZbtb5JjItnR+L49MN0iEP5d1mZHf09YKlUz9yjY54kjWBw6myHoIcopOW4hrPCs5o\/+Loo7KY\/czH3jRO5BUXJ+L\/uZr6sCMb5vO5qNCDHkbVLHL+\/bwQaff4IxyJ4Llv4fcJuumx2VXFM2Hs3\/tlyykgv479Ow9sKntR+sxwJunj4ZzGyVFmTPOAJk9D75v4Prda1JALACggnTJokgh8y2WcIRe6NUFZnhD7PdoHIoCal7haD0rcLhpE+IMNrprf5ny+DVUIpqficeAsoCBGDkzehlx6UsYp5WJTn5U+sml5xHncCa\/bEPSJS1AGw0nm\/px1CapBlLpdtZrEY+5PG9pultTjldjgZOc5E9A2iibPRpz\/vspMryzJa5AINCisPHbkVaBtqI5GU\/OjgJdnTVM5KyFCMACsf7sOY1tHkd2Ff7TVYZN\/9CSsqdk125\/wkUqdjuJ8PCq8gfhdPZ5LS\/SRiig5EBha1YpSJmFYFa1tbQjUdOrJXFsOen8fmXTPVd5RoJLDPN6yzc+BfTvrNasOB74MAt0yw4MYwS5TDUrPpV59BkQBLKDvA1APVOzYCxrEDZ4lSEq0Qk1Y13RIqwbWiA33jeXF72Rkj3T\/+phg+paYO0dlesyMJMNKEeH1iu2csjiL5WvEqZA+QYE\/Z5SFW41sp79MjKcmVOap5KEh5YzgEZgShDteMAPm4fNUkIntd6TseX5PVhGhG+aAER7wuO77cQxy6aB5Hv3Bca5zt+wQSgbz+AD38Y23e86hUKmDj+glF46TpX\/7\/OMvjHIlpeNHjpyqKRGI3qZpnhy\/DNUIx1W6x2CrD2d\/JYtuOUhemeg7hzGyf18GbT7yivvPmGBJbUutWD51sbF4e7UK4a3o1BvZNsMeIKACh5gdYnXrmJIgkho1VPQMlrMqCIJZKuNOC4BooQxd5GjrJU9WyW8BC8dlSGK9Ma9bdB+AxdUAUtYXlTBFqNw+jjqovEsdDQjgPMrep6s2mqWO8uNo4ATfVwDfciawcPz5UE5vTGX7l\/ihXaiZ+Jk\/LzAZkpsluSfyEQVg9Po9kTfhQEwO+2ppr5gxwQlTyVTN\/w9hCzIdkZFXsZOKon4mZTNWMUvI9PoLm0ZIBSkAozj\/2JoHMaetEwe2A=="
},
"transactionId": "BiV2RVnJ3kmtB9Zj5eGQLQ.0"
} |
@dschmidt we were talking about the wish of the web client to list all shares in one request because the internal data model prefers that, or did I misunderstand that? Listing /sharedWithMe returns a list of driveItems. On Ms graph it only returns all shares, regardless of their mount status ... because it does not have a mount status. The Ms graph API represents mount points as driveItems with a remoteItem that wraps the shared driveItem. This way of wrapping the share in the mount point prevents listing shares without a mount point .... hmmm ... /sharedWithMe is a list of driveItems, so we could list unmounted shares as drive items without wrapping them in a drive Item that represents the mountpoint. While the graph API does not do that I think it semantically fits the concept. I'll add an example tomorrow. Now about hiding shares... we could use a |
Yeah, from Web's POV "sharedness" is just a property of a Drive(Item). So for us it would be nice to retrieve all shares accepted or not from the same endpoint. |
@dschmidt yeah ... so .... let me clarify what the {
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(driveItem)",
"value": [
{
"id": "u-u-id-of-mountpoint",
"name": "November-December Ad Proposals.pptx",
"size": 100984,
"parentReference": {
"driveType": "personal",
"driveId": "u-u-id-of-drive-containing-the-pointpoint",
"id": "parent-u-u-id"
},
"createdBy": { ... },
"lastModifiedBy": { ... },
"remoteItem": {
"id": "u-u-id-of-shared-driveItem",
"name": "November-December Ad Proposals.pptx",
"size": 100984,
"parentReference": {
"driveType": "personal",
"driveId": "u-u-id-of-drive-containing-the-item"
// no "id" because recipient is not allowed to see parent
},
"shared": {
"scope": "users",
"sharedBy": {
"user": { ... }
}
}
}
},
{
"id": "7fd82e03-09af-4b38-8d36-c7f7ec83cd99",
"name": "Marketing Term Successes International.xlsx",
"size": 17776,
"parentReference": {
"driveType": "personal",
"driveId": "u-u-id-of-drive-containing-the-item"
// no "id" because recipient is not allowed to see parent
},
"shared": {
"scope": "users",
"sharedBy": {
"user": { ... }
}
}
}
]
} as you can see ... a mount point is not just a property ... it wraps a remoteItem ... but I think that might work, as to the end user the relevant properties are name and size. So when a driveItem in the list has a remoteItem it is a mountpoint. if it has no remoteItem it is a grant. Does that make sense?
|
with regards to a {
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(driveItem)",
"value": [
{
"@libre.graph.hidden": true,
"id": "408082ff-98ac-4b48-aa47-3ae99c4a4bb0",
...
},
{
"@libre.graph.hidden": true,
"id": "7fd82e03-09af-4b38-8d36-c7f7ec83cd99",
...
}
]
} and changing the annotation would be a PATCH request: PATCH /drives/{driveid}/items/{itemid}
{
"@libre.graph.hidden": true
} |
The remoteItem points to the origin of the share (?) - why would it be missing for a grant? I don't get that logic. Ftr: The Another reminder: we need access to the |
When navigating into a random driveItem how can we find out the path up to the driveItem the user has been granted access to? Every drilveItem has a parentReference. One of the propertios is GET /graph/v1.0/drives/{driveId}/items/{driveItemId}
{
"id": "7fd82e03-09af-4b38-8d36-c7f7ec83cd99",
"name": "Marketing Term Successes International.xlsx",
"parentReference": {
"driveType": "project",
"driveId": "marketing-space-id",
"path": "/drives/{driveId}/root:/International/Foo/Bar"
}
} This should also works for shares by using a path that 'starts' at the shared resource: GET /graph/v1.0/drives/{driveId}/items/{driveItemId}
{
"id": "7fd82e03-09af-4b38-8d36-c7f7ec83cd99",
"name": "Marketing Term Successes International.xlsx",
"parentReference": {
"driveType": "project",
"driveId": "marketing-space-id",
"path": "/drives/{driveId}/items/{driveItemId}:/International"
}
} I checked this request: A request that fetches all driveItems with name and id could be expressed as:
concrete example: We want to get all driveItems for
|
@micbar I think I have now added all needed properties. odata uses vocabularies to extend entities and properties. I am using the SAP UI vocabulary to add the |
@dschmidt @TheOneRing @dragotin something fails in the validate-cpp step. Can you take a look? |
The // ...
QList<QString> libre_graph_permissions_actions;
bool libre_graph_permissions_actions_isSet;
bool libre_graph_permissions_actions_isValid;
bool ui_hidden;
bool ui_hidden_isSet;
bool ui_hidden_isValid;
// ...
d->libre_graph_permissions_actions_isSet = false;
d->libre_graph_permissions_actions_isValid = false;
d->ui_hidden_isSet = false;
d->ui_hidden_isValid = false;
// ...
d->libre_graph_permissions_actions_isValid = ::OpenAPI::fromJsonValue(d->libre_graph_permissions_actions, json[QString("@libre.graph.permissions.actions")]);
d->libre_graph_permissions_actions_isSet = !json[QString("@libre.graph.permissions.actions")].isNull() && d->libre_graph_permissions_actions_isValid;
d->ui_hidden_isValid = ::OpenAPI::fromJsonValue(d->ui_hidden, json[QString("@UI.Hidden")]);
d->ui_hidden_isSet = !json[QString("@UI.Hidden")].isNull() && d->ui_hidden_isValid;
// ...
if (d->libre_graph_permissions_actions.size() > 0) {
obj.insert(QString("@libre.graph.permissions.actions"), ::OpenAPI::toJsonValue(d->libre_graph_permissions_actions));
}
if (d->ui_hidden_isSet) {
obj.insert(QString("@UI.Hidden"), ::OpenAPI::toJsonValue(d->ui_hidden));
}
// ...
QList<QString> OAIPermission::getLibreGraphPermissionsActions() const {
Q_D(const OAIPermission);
if(!d){
return {};
}
return d->libre_graph_permissions_actions;
}
void OAIPermission::setLibreGraphPermissionsActions(const QList<QString> &libre_graph_permissions_actions) {
Q_D(OAIPermission);
Q_ASSERT(d);
d->libre_graph_permissions_actions = libre_graph_permissions_actions;
d->libre_graph_permissions_actions_isSet = true;
}
bool OAIPermission::is_libre_graph_permissions_actions_Set() const{
Q_D(const OAIPermission);
if(!d){
return false;
}
return d->libre_graph_permissions_actions_isSet;
}
bool OAIPermission::is_libre_graph_permissions_actions_Valid() const{
Q_D(const OAIPermission);
if(!d){
return false;
}
return d->libre_graph_permissions_actions_isValid;
}
bool OAIPermission::isUiHidden() const {
Q_D(const OAIPermission);
if(!d){
return {};
}
return d->ui_hidden;
}
void OAIPermission::setUiHidden(const bool &ui_hidden) {
Q_D(OAIPermission);
Q_ASSERT(d);
d->ui_hidden = ui_hidden;
d->ui_hidden_isSet = true;
}
bool OAIPermission::is_ui_hidden_Set() const{
Q_D(const OAIPermission);
if(!d){
return false;
}
return d->ui_hidden_isSet;
}
bool OAIPermission::is_ui_hidden_Valid() const{
Q_D(const OAIPermission);
if(!d){
return false;
}
return d->ui_hidden_isValid;
}
// ... go // ...
LibreGraphPermissionsActions []string `json:"@libre.graph.permissions.actions,omitempty"`
// Properties or facets (see UI.Facet) annotated with this term will not be rendered if the annotation evaluates to true. Users can set this to hide permissons.
UIHidden *bool `json:"@UI.Hidden,omitempty"`
// ...
if !IsNil(o.LibreGraphPermissionsActions) {
toSerialize["@libre.graph.permissions.actions"] = o.LibreGraphPermissionsActions
}
if !IsNil(o.UIHidden) {
toSerialize["@UI.Hidden"] = o.UIHidden
}
// ...
// GetLibreGraphPermissionsActions returns the LibreGraphPermissionsActions field value if set, zero value otherwise.
func (o *Permission) GetLibreGraphPermissionsActions() []string {
if o == nil || IsNil(o.LibreGraphPermissionsActions) {
var ret []string
return ret
}
return o.LibreGraphPermissionsActions
}
// GetLibreGraphPermissionsActionsOk returns a tuple with the LibreGraphPermissionsActions field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Permission) GetLibreGraphPermissionsActionsOk() ([]string, bool) {
if o == nil || IsNil(o.LibreGraphPermissionsActions) {
return nil, false
}
return o.LibreGraphPermissionsActions, true
}
// HasLibreGraphPermissionsActions returns a boolean if a field has been set.
func (o *Permission) HasLibreGraphPermissionsActions() bool {
if o != nil && !IsNil(o.LibreGraphPermissionsActions) {
return true
}
return false
}
// SetLibreGraphPermissionsActions gets a reference to the given []string and assigns it to the LibreGraphPermissionsActions field.
func (o *Permission) SetLibreGraphPermissionsActions(v []string) {
o.LibreGraphPermissionsActions = v
}
// GetUIHidden returns the UIHidden field value if set, zero value otherwise.
func (o *Permission) GetUIHidden() bool {
if o == nil || IsNil(o.UIHidden) {
var ret bool
return ret
}
return *o.UIHidden
}
// GetUIHiddenOk returns a tuple with the UIHidden field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Permission) GetUIHiddenOk() (*bool, bool) {
if o == nil || IsNil(o.UIHidden) {
return nil, false
}
return o.UIHidden, true
}
// HasUIHidden returns a boolean if a field has been set.
func (o *Permission) HasUIHidden() bool {
if o != nil && !IsNil(o.UIHidden) {
return true
}
return false
}
// SetUIHidden gets a reference to the given bool and assigns it to the UIHidden field.
func (o *Permission) SetUIHidden(v bool) {
o.UIHidden = &v
}
// ... typescript // ...
/**
* Use this to create a permission with custom actions.
* @type {Array<string>}
* @memberof Permission
*/
'@libre.graph.permissions.actions'?: Array<string>;
/**
* Properties or facets (see UI.Facet) annotated with this term will not be rendered if the annotation evaluates to true. Users can set this to hide permissons.
* @type {boolean}
* @memberof Permission
*/
'@UI.Hidden'?: boolean;
// ... PHP // ...
/**
* Array of property to type mappings. Used for (de)serialization
*
* @var string[]
*/
protected static $openAPITypes = [
//...
'at_libre_graph_permissions_actions' => 'string[]',
'at_ui_hidden' => 'bool'
];
// ...
/**
* Array of property to format mappings. Used for (de)serialization
*
* @var string[]
* @phpstan-var array<string, string|null>
* @psalm-var array<string, string|null>
*/
protected static $openAPIFormats = [
//...
'at_libre_graph_permissions_actions' => null,
'at_ui_hidden' => null
];
// ...
/**
* Array of attributes where the key is the local name,
* and the value is the original name
*
* @var string[]
*/
protected static $attributeMap = [
//...
'at_libre_graph_permissions_actions' => '@libre.graph.permissions.actions',
'at_ui_hidden' => '@UI.Hidden'
];
// ...
/**
* Array of attributes to setter functions (for deserialization of responses)
*
* @var string[]
*/
protected static $setters = [
//...
'at_libre_graph_permissions_actions' => 'setAtLibreGraphPermissionsActions',
'at_ui_hidden' => 'setAtUiHidden'
];
// ...
/**
* Array of attributes to getter functions (for serialization of requests)
*
* @var string[]
*/
protected static $getters = [
//...
'at_libre_graph_permissions_actions' => 'getAtLibreGraphPermissionsActions',
'at_ui_hidden' => 'getAtUiHidden'
];
// ...
/**
* Constructor
*
* @param mixed[] $data Associated array of property values
* initializing the model
*/
public function __construct(array $data = null)
{
//...
$this->setIfExists('at_libre_graph_permissions_actions', $data ?? [], null);
$this->setIfExists('at_ui_hidden', $data ?? [], null);
}
// ...
/**
* Gets at_libre_graph_permissions_actions
*
* @return string[]|null
*/
public function getAtLibreGraphPermissionsActions()
{
return $this->container['at_libre_graph_permissions_actions'];
}
/**
* Sets at_libre_graph_permissions_actions
*
* @param string[]|null $at_libre_graph_permissions_actions Use this to create a permission with custom actions.
*
* @return self
*/
public function setAtLibreGraphPermissionsActions($at_libre_graph_permissions_actions)
{
if (is_null($at_libre_graph_permissions_actions)) {
throw new \InvalidArgumentException('non-nullable at_libre_graph_permissions_actions cannot be null');
}
$this->container['at_libre_graph_permissions_actions'] = $at_libre_graph_permissions_actions;
return $this;
}
/**
* Gets at_ui_hidden
*
* @return bool|null
*/
public function getAtUiHidden()
{
return $this->container['at_ui_hidden'];
}
/**
* Sets at_ui_hidden
*
* @param bool|null $at_ui_hidden Properties or facets (see UI.Facet) annotated with this term will not be rendered if the annotation evaluates to true. Users can set this to hide permissons.
*
* @return self
*/
public function setAtUiHidden($at_ui_hidden)
{
if (is_null($at_ui_hidden)) {
throw new \InvalidArgumentException('non-nullable at_ui_hidden cannot be null');
}
$this->container['at_ui_hidden'] = $at_ui_hidden;
return $this;
} I strongly suggest we use those annotations for our deviations from the ms graph api |
Note that I dropped the shareID from the itemReference as it is AFAICT unused: https://github.com/owncloud/libre-graph-api/pull/112/files#diff-ef34f08de0f08ec7094fc1391308521fae6824a2ad2e5b279673c98da8a60e33L2488-R3276 |
regarding the c++ build failure: I added
My guess is that maybe the code generation does not yet handle the case that |
I guess we need to patch our fork of the mustache files there are 3 to 4 errors in OAISharingLinkType.cpp |
rebased on main which now has the c++ fixes, @micbar ready to merge IMO |
Signed-off-by: Jörn Friedrich Dreyer <[email protected]> add invite endpoint Signed-off-by: Jörn Friedrich Dreyer <[email protected]> update invite, add driveRecipient, extend permissions Signed-off-by: Jörn Friedrich Dreyer <[email protected]> fix quotes Signed-off-by: Jörn Friedrich Dreyer <[email protected]> add list permissions endpoint Signed-off-by: Jörn Friedrich Dreyer <[email protected]> turn listing permissions schema into a collection Signed-off-by: Jörn Friedrich Dreyer <[email protected]> add get permission, minor fixes Signed-off-by: Jörn Friedrich Dreyer <[email protected]> update and delete permissions, allowedValues, fix parameters Signed-off-by: Jörn Friedrich Dreyer <[email protected]> add roleDefinitions Signed-off-by: Jörn Friedrich Dreyer <[email protected]> clarify Signed-off-by: Jörn Friedrich Dreyer <[email protected]> incorporate feedback Signed-off-by: Jörn Friedrich Dreyer <[email protected]> add creatLink Signed-off-by: Jörn Friedrich Dreyer <[email protected]> add sharedByMe endpoint, drop unused paremeters in sharing examples Signed-off-by: Jörn Friedrich Dreyer <[email protected]> fix examples, better description for group shares Signed-off-by: Jörn Friedrich Dreyer <[email protected]> fix indentaton of shared property Signed-off-by: Jörn Friedrich Dreyer <[email protected]> add error case Signed-off-by: Jörn Friedrich Dreyer <[email protected]> work on links and permissions Signed-off-by: Jörn Friedrich Dreyer <[email protected]>
Signed-off-by: Jörn Friedrich Dreyer <[email protected]>
Signed-off-by: Jörn Friedrich Dreyer <[email protected]>
Signed-off-by: Jörn Friedrich Dreyer <[email protected]>
Well, maybe the type just has to be changed... In XML, an enum is also not a string. |
on request from @butonic : |
top PR comment contains sharing walkthrough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking forward to use it 😄
libregraph API spec for the sharing ADR in owncloud/ocis#6995
When following a share lifecycle, the following OCS requests can be replaced with these libregraph counterparts:
List shares on a resource (includes sharing options)
OCS: web calls two endpoints:
/ocs/v1.php/apps/files_sharing/api/v1/shares?path={space-relative-path}&space_ref={space-id}&reshares=true
/ocs/v1.php/apps/files_sharing/api/v1/shares?path={space-relative-path}&space_ref={space-id}&shared_with_me=true
ms graph:
/drives/{drive-id}/items/{drive-item-id}/permissions
libre graph: for now we stick to two kinds of permissions:
grantedToV2
for internal user or group shareslink
for public link sharesjfd: roles are currently hardcoded to
read
,write
andowner
. We can make them customizable but I'll show that at the end of this descriptionSearch for recipient (not part of this PR)
OCS:
/ocs/v2.php/apps/files_sharing/api/v1/sharees?search=einst&itemType=(folder|file)&page=1&perPage=200&format=json
ms graph:
/me/people?$search="einst"
is used to interact with users that are relevant or in a working-with relationship. The returned list of person entities has apersonType
property to differentiate types of groups and users.libre graph:
/me/people?$search="einst"
is the only endpoint we need, I think. For now, a$search="einst"
parameter can be used instead of the OCS sharee call.Note: There is a difference between
$search="foo bar"
and$search=foo bar
. To mimic OCS the request has to quote the typed in string.*Create a share with user or group
OCS:
ms graph: sharing wit a user is done by posting an
invite
response:
It seems the response does not use
grantedToV2
. And whenrequireSignIn
is left out orfalse
it will happily create a linkwebUrl
that allows browsing the file.libre graph: sharing wit a user is done by posting an
invite
. While ms graph usesemail
to identify a recipient libre graph assumes internal shares are created using theobjectId
(the usersid
)response:
jfd: multiple recipients can be sent in the same request. Each will receive a dedicated permissions object with their own id. WChen an error occurs a 207 multistatus response will be returned, similar to https://learn.microsoft.com/en-us/graph/api/site-follow?view=graph-rest-1.0&tabs=http#response-1 which shows an examplo where one of the entries contains an error
request:
response:
Shared by me
List shares created by the currently logged in user
OCS: is called Shared With Others, see below
ms graph: odata query not implemented
onedrive web: can list shares by me in the web ui. maybe something is coming to ms graph as well?
libre graph:
/me/drive/sharedByMe
(only includes shares created by the current user)Shared with others (not part of this PR)
Includes shares in project spaces that can be managed by the current user because he is a manager of the space. He does not need to be the creator of the share.
OCS:
/ocs/v1.php/apps/files_sharing/api/v1/shares?reshares=true&include_tags=false&share_types=0,1,4,6
ms graph: odata query not implemented
libre graph: does not exist, but we could add a new
/me/drive/sharedWithOthers
endpointNote: the OCS
share_types
are 0 = User, 1 = Group, 3 = public link, 4 = guest, 6 = federated share, 7 = federated group / space member user (OH great we have a clash here), 8 = space member group.Hint: There is a difference in the concept of shares. In OC10 shares are tied to a user. In OCIS they are tied to a space. The Owner/All managers of a space can collaboratively manage all shares in a personal/project space.
Shared with me
As the recipient you want to get a list of all driveItems that have been shared with you.
OCS:
/ocs/v1.php/apps/files_sharing/api/v1/shares?include_tags=false&state=all&shared_with_me=true
ms graph:
/me/drive/sharedWithMe
libre graph:
/me/drive/sharedWithMe
The endpoint returns a
collection(driveItem)
that contains both: mounted and unmounted driveItems. shared driveItems are wrapped in another driveItem representing the mountpoint as on the ms graph API. But there are two deviations from the ms graph API:shared
property but expands thepermissions
relation as it contains all necessary information. This might change if we think theshared
property is enough to show the necessary indicators. It would be faster than listing all details of the permission.@UI.hidden
annotation on driveItems to indicatejfd: we cannot put the
@UI.hidden
property on the drive item directly, because it would mean the driveItem was hidden. So we put it on the permissions property. That hidden flag can be toggled.Accept/Reject a share / an invite
OCS:
POST ocs/v2.php/apps/files_sharing/api/v1/shares/pending/{share-id}
DELETE ocs/v2.php/apps/files_sharing/api/v1/shares/pending/{share-id}
ms graph: /sharedWithMe will list all shares, but
libre graph: mount shares in the share jail by creating a driveItem using a
POST /drives/{sharejailid}/items
request:This request can check if the current user has access to the given drive item and will 'mount'/ accept it with the name "Einsteins project share". In theory we could add a remoteItem anywhere in a drive like in OC10, but it is a product decision to collect them in the dedicated virtual share jail drive.
The mountpoint can be deleted/rejected by sending a
DELETE /drives/{drive-item-id}
where{drive-item-id}
is the id of the drive item representing the mount point, not the remote item.Create a public link
ms graph
response:
Update shares / links
ms graph:
jfd: same as libregraph but I tried changing the role ... we'll just not go there for now
The role does affect the ui. It now shows upload elements even for non logged in users. The link type is still view. When trying to upload a file the web ui will try to log you in before making the request. The link type cannot be changed: in the UI there is a hint "This setting can't be changed. Create a new link if you need different permissions.". I guess this is to prevent changing permissions on existing links?
libre graph:
response
For links we ignore the role and instead set the link type. ms graph has a lot predefined: https://learn.microsoft.com/en-us/graph/api/listitem-createlink?view=graph-rest-beta&tabs=http#link-types
Delete shares / links
OCS
DELETE ocs/v1.php/apps/files_sharing/api/v1/shares/{share-id}
libre graph
DELETE /drives/{drive-id}/items/{drive-item-id}/permissions/{permission-id}
older notes
/drives/{drive-id}/items/{item-id}/invite
to create shares/drives/{drive-id}/items/{item-id}/createLink
to create links/me/drive/sharedWithMe
to list shares with the current user/me/drive/sharedByMe
to list shares by the current user. This only includes shares created by the current user, not all shares he can manage, eg. in project spaces.extendwe went with a libregraph only/drives
to allow/drives?$expand=items&$filter=items/any(property:property/shared+ne+null)
, the listing of shares with others/me/drive/sharedByMe
endpoint insteadshared
facet/drives/{drive-id}/items/{item-id}/permissions
to list permissionssharing roles as app roles / appRoleAssignment for a sharing app???asharing
relationship on theroleManagement
resource seems more fitting. appRoles are supposed to show up in access token scopes ... so ... nah/drives/{drive-id}/items/{item-id}/permissions
:/drives/{drive-id}/items/{item-id}/invite
and/drives/{drive-id}/items/{item-id}/createLink
. They both add permissions to drive items and thepermission
object as a result can carry alink
or agrantedToV2
facet/property. This needs more investigation: permissioens have arole
property butlink
objects themselves have atype
... and the existing link types in ms graph pretty much cover all we need. That being said we want to have them customizeable ... so they should be discoverable, similar to the sharing roles at/roleManagement/permissions/roleDefinitions
Further reading
It follows the MS Graph API, documented here:
shares in ms graph are called permissions: https://learn.microsoft.com/en-us/graph/api/resources/permission?view=graph-rest-1.0
invite is used to add permissions and optionally send a message https://learn.microsoft.com/en-us/graph/api/driveitem-invite?view=graph-rest-1.0&tabs=http
list permissions on a driveItem: https://learn.microsoft.com/en-us/graph/api/driveitem-list-permissions?view=graph-rest-1.0&tabs=http
get permission: https://learn.microsoft.com/en-us/graph/api/permission-get?view=graph-rest-1.0&tabs=http
update permission: https://learn.microsoft.com/en-us/graph/api/permission-update?view=graph-rest-1.0&tabs=http
delete permission: https://learn.microsoft.com/en-us/graph/api/permission-delete?view=graph-rest-1.0&tabs=http
sharing roles are only read, view, owner: https://learn.microsoft.com/en-us/graph/api/resources/permission?view=graph-rest-1.0#roles-property-values
Listing shares incoming / outgoing shares:
https://graph.microsoft.com/v1.0/me/drive/items?$filter=shared ne null
. It works by matching all driveItems that have no sharing facet. However, it is not implemented in ms graph. Maybe because it is not clear that/v1.0/me/drive/items
works on ALL drives. Semantically, it should only list the shared drive items on the users personal drive. To match drive items on all drives the user has access tohttps://graph.microsoft.com/v1.0/drives?$expand=items&$filter=items/any(property:property/shared+ne+null)
could be used to get a list of all drives that have shared drive items and expand the items. This is not allowed on the ms graph api.What does work is
https://graph.microsoft.com/v1.0/me/drive/root/search(q='*')?filter=shared+ne+null
but it is slow as it relies on the search() function. I'd go with the semantically correct version.interesting sidenote
/shares/{share-id}
endpoint that can be used to directly access a shared drive item ... similar to/drives/{drive-id}
... 🤔