github.com/cozy/cozy-stack@v0.0.0-20240327093429-939e4a21320e/docs/references-docs-in-vfs.md (about)

     1  [Table of contents](README.md#table-of-contents)
     2  
     3  # References of documents in the Virtual File System
     4  
     5  ## What we want?
     6  
     7  Cozy applications can use data from the Data System and files from the Virtual
     8  File System. Of course, sometimes a link between data and files can be useful.
     9  For example, the application can have an album with photos. The album will be a
    10  document in CouchDB (with a title and other fields), but il will also list the
    11  files to use as photos.
    12  
    13  A direct way to do that is storing the files IDs in the album document. It's
    14  simple and will work pretty well if the files are manipulated only from this
    15  application. But, files are often accessed from other apps, like cozy-desktop
    16  and cozy-drive. To improve the User eXperience, it should be nice to alert the
    17  user when a file in an album is modified or deleted.
    18  
    19  When a file is modified, we can offer the user the choice between keeping the
    20  original version in the album, or using the new modified file. When a file is
    21  moved to the trash, we can alert the user and let him/her restore the file.
    22  
    23  Cozy-desktop, cozy-drive, and the other apps can't scan all the documents with
    24  many different doctypes to find all the references to a file to detect such
    25  cases. The goal of this document is to offer a way to do that, and it is called
    26  _References_.
    27  
    28  The references of a file are listed in its JSON-API representation in the
    29  `references` field, within the `relationships` object of `data`.
    30  
    31  ### Example
    32  
    33  ```json
    34  {
    35      "data": {
    36          "type": "io.cozy.files",
    37          "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
    38          "meta": {
    39              "rev": "1-0e6d5b72"
    40          },
    41          "attributes": {
    42              "type": "file",
    43              "name": "hello.txt",
    44              "md5sum": "ODZmYjI2OWQxOTBkMmM4NQo=",
    45              "created_at": "2016-09-19T12:38:04Z",
    46              "updated_at": "2016-09-19T12:38:04Z",
    47              "tags": [],
    48              "size": 12,
    49              "executable": false,
    50              "class": "document",
    51              "mime": "text/plain"
    52          },
    53          "relationships": {
    54              "parent": {
    55                  "links": {
    56                      "related": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
    57                  },
    58                  "data": {
    59                      "type": "io.cozy.files",
    60                      "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
    61                  }
    62              },
    63              "referenced_by": {
    64                  "links": {
    65                      "self": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/relationships/references"
    66                  },
    67                  "data": [
    68                      {
    69                          "type": "io.cozy.playlists",
    70                          "id": "94375086-e2e2-11e6-81b9-5bc0b9dd4aa4"
    71                      }
    72                  ]
    73              }
    74          },
    75          "links": {
    76              "self": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b"
    77          }
    78      }
    79  }
    80  ```
    81  
    82  ## Routes
    83  
    84  ### POST /files/:file-id/relationships/referenced_by
    85  
    86  Add on a file one or more references to documents
    87  
    88  #### Request
    89  
    90  ```http
    91  POST /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/relationships/referenced_by HTTP/1.1
    92  Content-Type: application/vnd.api+json
    93  Accept: application/vnd.api+json
    94  ```
    95  
    96  ```json
    97  {
    98      "data": [
    99          {
   100              "type": "io.cozy.playlists",
   101              "id": "f2625cc0-e2d6-11e6-a0d5-cfbbfb141af0"
   102          }
   103      ]
   104  }
   105  ```
   106  
   107  #### Response
   108  
   109  ```http
   110  HTTP/1.1 200 OK
   111  Content-Type: application/vnd.api+json
   112  ```
   113  
   114  ```json
   115  {
   116      "meta": {
   117          "rev": "2-de8d0ba2",
   118          "count": 2
   119      },
   120      "data": [
   121          {
   122              "type": "io.cozy.playlists",
   123              "id": "94375086-e2e2-11e6-81b9-5bc0b9dd4aa4"
   124          },
   125          {
   126              "type": "io.cozy.playlists",
   127              "id": "f2625cc0-e2d6-11e6-a0d5-cfbbfb141af0"
   128          }
   129      ]
   130  }
   131  ```
   132  
   133  ### DELETE /files/:file-id/relationships/referenced_by
   134  
   135  Remove one or more references to documents on a file
   136  
   137  #### Request
   138  
   139  ```http
   140  DELETE /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/relationships/referenced_by HTTP/1.1
   141  Content-Type: application/vnd.api+json
   142  Accept: application/vnd.api+json
   143  ```
   144  
   145  ```json
   146  {
   147      "data": [
   148          {
   149              "type": "io.cozy.playlists",
   150              "id": "f2625cc0-e2d6-11e6-a0d5-cfbbfb141af0"
   151          }
   152      ]
   153  }
   154  ```
   155  
   156  #### Response
   157  
   158  ```http
   159  HTTP/1.1 200 OK
   160  Content-Type: application/vnd.api+json
   161  ```
   162  
   163  ```json
   164  {
   165      "meta": {
   166          "rev": "3-7ab812c0",
   167          "count": 1
   168      },
   169      "data": [
   170          {
   171              "type": "io.cozy.playlists",
   172              "id": "94375086-e2e2-11e6-81b9-5bc0b9dd4aa4"
   173          }
   174      ]
   175  }
   176  ```
   177  
   178  ### GET /data/:type/:doc-id/relationships/references
   179  
   180  Returns all the files id associated to an album or playlist.
   181  
   182  Contents is paginated following [jsonapi conventions](http-api.md#pagination).
   183  The default limit is 100 entries. The maximal number of entries per page is
   184  1000.
   185  
   186  It's also possible to sort the files by their datetime (for photos) with the
   187  `sort` query parameter: `?sort=datetime`.
   188  
   189  #### Request
   190  
   191  ```http
   192  GET /data/io.cozy.playlists/e9308dc2-e2e3-11e6-b685-fb88662613d4/relationships/references HTTP/1.1
   193  Content-Type: application/vnd.api+json
   194  Accept: application/vnd.api+json
   195  ```
   196  
   197  #### Response
   198  
   199  ```http
   200  HTTP/1.1 200 OK
   201  Content-Type: application/vnd.api+json
   202  ```
   203  
   204  ```json
   205  {
   206      "data": [
   207          {
   208              "type": "io.cozy.files",
   209              "id": "417c4e58-e2e4-11e6-b7dc-2b68ed7b77f4"
   210          },
   211          {
   212              "type": "io.cozy.files",
   213              "id": "4504f55c-e2e4-11e6-88f2-d77aeecab549"
   214          },
   215          {
   216              "type": "io.cozy.files",
   217              "id": "4587727a-e2e4-11e6-bfe9-ef1be7df7f26"
   218          },
   219          {
   220              "type": "io.cozy.files",
   221              "id": "45d591d0-e2e4-11e6-ab9a-ff3b218e31cc"
   222          }
   223      ]
   224  }
   225  ```
   226  
   227  ### POST /data/:type/:doc-id/relationships/references
   228  
   229  When creating an album or a playlist, it's tedious to add the references to it
   230  for each file individually. This route allows to make it in bulk.
   231  
   232  #### Request
   233  
   234  ```http
   235  POST /data/io.cozy.playlists/e9308dc2-e2e3-11e6-b685-fb88662613d4/relationships/references HTTP/1.1
   236  Content-Type: application/vnd.api+json
   237  Accept: application/vnd.api+json
   238  ```
   239  
   240  ```json
   241  {
   242      "data": [
   243          {
   244              "type": "io.cozy.files",
   245              "id": "417c4e58-e2e4-11e6-b7dc-2b68ed7b77f4"
   246          },
   247          {
   248              "type": "io.cozy.files",
   249              "id": "4504f55c-e2e4-11e6-88f2-d77aeecab549"
   250          },
   251          {
   252              "type": "io.cozy.files",
   253              "id": "4587727a-e2e4-11e6-bfe9-ef1be7df7f26"
   254          },
   255          {
   256              "type": "io.cozy.files",
   257              "id": "45d591d0-e2e4-11e6-ab9a-ff3b218e31cc"
   258          }
   259      ]
   260  }
   261  ```
   262  
   263  #### Response
   264  
   265  ```http
   266  HTTP/1.1 204 No Content
   267  Content-Type: application/vnd.api+json
   268  ```
   269  
   270  ### DELETE /data/:type/:doc-id/relationships/references
   271  
   272  This bulk deletion of references on many files can be useful when an album or
   273  playlist is deleted.
   274  
   275  #### Request
   276  
   277  ```http
   278  DELETE /data/io.cozy.playlists/e9308dc2-e2e3-11e6-b685-fb88662613d4/relationships/references HTTP/1.1
   279  Content-Type: application/vnd.api+json
   280  Accept: application/vnd.api+json
   281  ```
   282  
   283  ```json
   284  {
   285      "data": [
   286          {
   287              "type": "io.cozy.files",
   288              "id": "417c4e58-e2e4-11e6-b7dc-2b68ed7b77f4"
   289          },
   290          {
   291              "type": "io.cozy.files",
   292              "id": "4504f55c-e2e4-11e6-88f2-d77aeecab549"
   293          },
   294          {
   295              "type": "io.cozy.files",
   296              "id": "4587727a-e2e4-11e6-bfe9-ef1be7df7f26"
   297          },
   298          {
   299              "type": "io.cozy.files",
   300              "id": "45d591d0-e2e4-11e6-ab9a-ff3b218e31cc"
   301          }
   302      ]
   303  }
   304  ```
   305  
   306  #### Response
   307  
   308  ```http
   309  HTTP/1.1 204 No Content
   310  Content-Type: application/vnd.api+json
   311  ```
   312  
   313  ## Usage
   314  
   315  ### Modification of a referenced file
   316  
   317  Before an application updates a file, it can check if the file has some
   318  references. If it is the case, it may offer to the user two choices:
   319  
   320  -   update the file with the new version (the albums and playlists will use the
   321      new version)
   322  -   save the new version as a new file and preserve the old file (the old file
   323      may be moved to a `originals` directory).
   324  
   325  ### Moving a referenced file to the trash
   326  
   327  Before an application moves a file to the trash, if the file has some
   328  references, it should ask the user if they really want to trash the file. And
   329  it should also removes the references before trashing the file.
   330  
   331  ## Implementation
   332  
   333  The references are persisted in the `io.cozy.files` documents in CouchDB. A
   334  mango index is used to fetch all the files that are associated to a given
   335  document (for `GET /data/:type/:doc-id/relationships/references`).
   336  
   337  For request to update or move to trash a file, it is easy to fetch its CouchDB
   338  document to see if it has a reference. But it is more difficult when moving a
   339  folder to trash. To do that, we need two requests to fetch the number of
   340  references in a folder.
   341  
   342  1/ Get all descendant folders from a given folder, with a CouchDB View:
   343  
   344  ```js
   345  map = function(doc) {
   346      if (doc.type === "folder") emit(doc.path);
   347  };
   348  query = {
   349      startkey: parent_folder_path + "/",
   350      endkey: parent_folder_path + "/\uFFFF"
   351  };
   352  ```
   353  
   354  2/ Get the total number of "referenced" file for this folders list, with a
   355  map/reduce CouchDB view:
   356  
   357  ```js
   358  map = function(doc) { if(doc.referenced != null) emit(doc.parentID) }
   359  reduce = count
   360  query = {keys: [list from above]}
   361  ```