{"id":21755404,"url":"https://github.com/pericles001/alx-files_manager","last_synced_at":"2026-04-02T02:49:52.984Z","repository":{"id":57960140,"uuid":"526396527","full_name":"Pericles001/alx-files_manager","owner":"Pericles001","description":"This project is a summary of this back-end trimester: authentication, NodeJS, MongoDB, Redis, pagination and background processing.","archived":false,"fork":false,"pushed_at":"2022-08-31T09:07:42.000Z","size":46,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-21T03:17:12.428Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Pericles001.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-08-18T22:55:41.000Z","updated_at":"2023-08-09T17:35:12.000Z","dependencies_parsed_at":"2023-01-16T17:30:39.360Z","dependency_job_id":null,"html_url":"https://github.com/Pericles001/alx-files_manager","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Pericles001/alx-files_manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pericles001%2Falx-files_manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pericles001%2Falx-files_manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pericles001%2Falx-files_manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pericles001%2Falx-files_manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Pericles001","download_url":"https://codeload.github.com/Pericles001/alx-files_manager/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pericles001%2Falx-files_manager/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259368018,"owners_count":22846822,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-26T09:17:56.607Z","updated_at":"2025-12-30T19:57:30.427Z","avatar_url":"https://github.com/Pericles001.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"0x04. Files manager\n===================\n\nBack-end JavaScript ES6 NoSQL MongoDB Redis NodeJS ExpressJS Kue\n\n-   By: Guillaume, CTO at Holberton School\n-   Weight: 1\n\n\nThis project is a summary of this back-end trimester: authentication, NodeJS, MongoDB, Redis, pagination and background processing.\n\nThe objective is to build a simple platform to upload and view files:\n\n-   User authentication via a token\n-   List all files\n-   Upload a new file\n-   Change permission of a file\n-   View a file\n-   Generate thumbnails for images\n\nYou will be guided step by step for building it, but you have some freedoms of implementation, split in more files etc... (`utils` folder will be your friend)\n\nOf course, this kind of service already exists in the real life - it's a learning purpose to assemble each piece and build a full product.\n\nEnjoy!\n\nResources\n---------\n\n**Read or watch**:\n\n-   [Node JS getting started](https://alx-intranet.hbtn.io/rltoken/kZHDWCu20EsKxKzi51yWeg \"Node JS getting started\")\n-   [Process API doc](https://alx-intranet.hbtn.io/rltoken/uYPplj2cPK8pcP0LtV6RuA \"Process API doc\")\n-   [Express getting started](https://alx-intranet.hbtn.io/rltoken/SujfeWKCWmUMomfETjETEg \"Express getting started\")\n-   [Mocha documentation](https://alx-intranet.hbtn.io/rltoken/FzEwplmoZiyGvkgKllZNJw \"Mocha documentation\")\n-   [Nodemon documentation](https://alx-intranet.hbtn.io/rltoken/pdNNTX0OLugbhxvP3sLgOw \"Nodemon documentation\")\n-   [MongoDB](https://alx-intranet.hbtn.io/rltoken/g1x7y_3GskzVAJBTXcSjmA \"MongoDB\")\n-   [Bull](https://alx-intranet.hbtn.io/rltoken/NkHBpGrxnd0sK_fDPMbihg \"Bull\")\n-   [Image thumbnail](https://alx-intranet.hbtn.io/rltoken/KX6cck2nyLpQOTDMLcwxLg \"Image thumbnail\")\n-   [Mime-Types](https://alx-intranet.hbtn.io/rltoken/j9B0Kc-4HDKLUe88ShbOjQ \"Mime-Types\")\n-   [Redis](https://alx-intranet.hbtn.io/rltoken/nqwKRszO8Tkj_ZWW1EFwGw \"Redis\")\n\nLearning Objectives\n-------------------\n\nAt the end of this project, you are expected to be able to [explain to anyone](https://alx-intranet.hbtn.io/rltoken/88vbnogJmkEoxqu-6wAXEw \"explain to anyone\"), **without the help of Google**:\n\n-   how to create an API with Express\n-   how to authenticate a user\n-   how to store data in MongoDB\n-   how to store temporary data in Redis\n-   how to setup and use a background worker\n\nRequirements\n------------\n\n-   Allowed editors: `vi`, `vim`, `emacs`, `Visual Studio Code`\n-   All your files will be interpreted/compiled on Ubuntu 18.04 LTS using `node` (version 12.x.x)\n-   All your files should end with a new line\n-   A `README.md` file, at the root of the folder of the project, is mandatory\n-   Your code should use the `js` extension\n-   Your code will be verified against lint using ESLint\n\nProvided files\n--------------\n\n### `package.json`\n\nClick to show/hide file contents\n\n### `.eslintrc.js`\n\nClick to show/hide file contents\n\n### `babel.config.js`\n\nClick to show/hide file contents\n\n### and...\n\nDon't forget to run `$ npm install` when you have the `package.json`\n\nTasks\n-----\n\n### 0\\. Redis utils\n\nmandatory\n\nInside the folder `utils`, create a file `redis.js` that contains the class `RedisClient`.\n\n`RedisClient` should have:\n\n-   the constructor that creates a client to Redis:\n    -   any error of the redis client must be displayed in the console (you should use `on('error')` of the redis client)\n-   a function `isAlive` that returns `true` when the connection to Redis is a success otherwise, `false`\n-   an asynchronous function `get` that takes a string key as argument and returns the Redis value stored for this key\n-   an asynchronous function `set` that takes a string key, a value and a duration in second as arguments to store it in Redis (with an expiration set by the duration argument)\n-   an asynchronous function `del` that takes a string key as argument and remove the value in Redis for this key\n\nAfter the class definition, create and export an instance of `RedisClient` called `redisClient`.\n\n```\nbob@dylan:~$ cat main.js\nimport redisClient from './utils/redis';\n\n(async () =\u003e {\n    console.log(redisClient.isAlive());\n    console.log(await redisClient.get('myKey'));\n    await redisClient.set('myKey', 12, 5);\n    console.log(await redisClient.get('myKey'));\n\n    setTimeout(async () =\u003e {\n        console.log(await redisClient.get('myKey'));\n    }, 1000*10)\n})();\n\nbob@dylan:~$ npm run dev main.js\ntrue\nnull\n12\nnull\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `utils/redis.js`\n\n Done? Help Get a sandbox\n\n### 1\\. MongoDB utils\n\nmandatory\n\nInside the folder `utils`, create a file `db.js` that contains the class `DBClient`.\n\n`DBClient` should have:\n\n-   the constructor that creates a client to MongoDB:\n    -   host: from the environment variable `DB_HOST` or default: `localhost`\n    -   port: from the environment variable `DB_PORT` or default: `27017`\n    -   database: from the environment variable `DB_DATABASE` or default: `files_manager`\n-   a function `isAlive` that returns `true` when the connection to MongoDB is a success otherwise, `false`\n-   an asynchronous function `nbUsers` that returns the number of documents in the collection `users`\n-   an asynchronous function `nbFiles` that returns the number of documents in the collection `files`\n\nAfter the class definition, create and export an instance of `DBClient` called `dbClient`.\n\n```\nbob@dylan:~$ cat main.js\nimport dbClient from './utils/db';\n\nconst waitConnection = () =\u003e {\n    return new Promise((resolve, reject) =\u003e {\n        let i = 0;\n        const repeatFct = async () =\u003e {\n            await setTimeout(() =\u003e {\n                i += 1;\n                if (i \u003e= 10) {\n                    reject()\n                }\n                else if(!dbClient.isAlive()) {\n                    repeatFct()\n                }\n                else {\n                    resolve()\n                }\n            }, 1000);\n        };\n        repeatFct();\n    })\n};\n\n(async () =\u003e {\n    console.log(dbClient.isAlive());\n    await waitConnection();\n    console.log(dbClient.isAlive());\n    console.log(await dbClient.nbUsers());\n    console.log(await dbClient.nbFiles());\n})();\n\nbob@dylan:~$ npm run dev main.js\nfalse\ntrue\n4\n30\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `utils/db.js`\n\n Done? Help Get a sandbox\n\n### 2\\. First API\n\nmandatory\n\nInside `server.js`, create the Express server:\n\n-   it should listen on the port set by the environment variable `PORT` or by default 5000\n-   it should load all routes from the file `routes/index.js`\n\nInside the folder `routes`, create a file `index.js` that contains all endpoints of our API:\n\n-   `GET /status` =\u003e `AppController.getStatus`\n-   `GET /stats` =\u003e `AppController.getStats`\n\nInside the folder `controllers`, create a file `AppController.js` that contains the definition of the 2 endpoints:\n\n-   `GET /status` should return if Redis is alive and if the DB is alive too by using the 2 utils created previously: `{ \"redis\": true, \"db\": true }` with a status code 200\n-   `GET /stats` should return the number of users and files in DB: `{ \"users\": 12, \"files\": 1231 }` with a status code 200\n    -   `users` collection must be used for counting all users\n    -   `files` collection must be used for counting all files\n\n**Terminal 1:**\n\n```\nbob@dylan:~$ npm run start-server\nServer running on port 5000\n...\n\n```\n\n**Terminal 2:**\n\n```\nbob@dylan:~$ curl 0.0.0.0:5000/status ; echo \"\"\n{\"redis\":true,\"db\":true}\nbob@dylan:~$\nbob@dylan:~$ curl 0.0.0.0:5000/stats ; echo \"\"\n{\"users\":4,\"files\":30}\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `server.js, routes/index.js, controllers/AppController.js`\n\n Done? Help Get a sandbox\n\n### 3\\. Create a new user\n\nmandatory\n\nNow that we have a simple API, it's time to add users to our database.\n\nIn the file `routes/index.js`, add a new endpoint:\n\n-   `POST /users` =\u003e `UsersController.postNew`\n\nInside `controllers`, add a file `UsersController.js` that contains the new endpoint:\n\n`POST /users` should create a new user in DB:\n\n-   To create a user, you must specify an `email` and a `password`\n-   If the `email` is missing, return an error `Missing email` with a status code 400\n-   If the `password` is missing, return an error `Missing password` with a status code 400\n-   If the `email` already exists in DB, return an error `Already exist` with a status code 400\n-   The `password` must be stored after being hashed in `SHA1`\n-   The endpoint is returning the new user with only the `email` and the `id` (auto generated by MongoDB) with a status code 201\n-   The new user must be saved in the collection `users`:\n    -   `email`: same as the value received\n    -   `password`: `SHA1` value of the value received\n\n```\nbob@dylan:~$ curl 0.0.0.0:5000/users -XPOST -H \"Content-Type: application/json\" -d '{ \"email\": \"bob@dylan.com\", \"password\": \"toto1234!\" }' ; echo \"\"\n{\"id\":\"5f1e7d35c7ba06511e683b21\",\"email\":\"bob@dylan.com\"}\nbob@dylan:~$\nbob@dylan:~$ echo 'db.users.find()' | mongo files_manager\n{ \"_id\" : ObjectId(\"5f1e7d35c7ba06511e683b21\"), \"email\" : \"bob@dylan.com\", \"password\" : \"89cad29e3ebc1035b29b1478a8e70854f25fa2b2\" }\nbob@dylan:~$\nbob@dylan:~$\nbob@dylan:~$ curl 0.0.0.0:5000/users -XPOST -H \"Content-Type: application/json\" -d '{ \"email\": \"bob@dylan.com\", \"password\": \"toto1234!\" }' ; echo \"\"\n{\"error\":\"Already exist\"}\nbob@dylan:~$\nbob@dylan:~$ curl 0.0.0.0:5000/users -XPOST -H \"Content-Type: application/json\" -d '{ \"email\": \"bob@dylan.com\" }' ; echo \"\"\n{\"error\":\"Missing password\"}\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `utils/, routes/index.js, controllers/UsersController.js`\n\n Done? Help Get a sandbox\n\n### 4\\. Authenticate a user\n\nmandatory\n\nIn the file `routes/index.js`, add 3 new endpoints:\n\n-   `GET /connect` =\u003e `AuthController.getConnect`\n-   `GET /disconnect` =\u003e `AuthController.getDisconnect`\n-   `GET /users/me` =\u003e `UserController.getMe`\n\nInside `controllers`, add a file `AuthController.js` that contains new endpoints:\n\n`GET /connect` should sign-in the user by generating a new authentication token:\n\n-   By using the header `Authorization` and the technique of the Basic auth (Base64 of the `\u003cemail\u003e:\u003cpassword\u003e`), find the user associate to this email and with this password (reminder: we are storing the SHA1 of the password)\n-   If no user has been found, return an error `Unauthorized` with a status code 401\n-   Otherwise:\n    -   Generate a random string (using `uuidv4`) as token\n    -   Create a key: `auth_\u003ctoken\u003e`\n    -   Use this key for storing in Redis (by using the `redisClient` create previously) the user ID for 24 hours\n    -   Return this token: `{ \"token\": \"155342df-2399-41da-9e8c-458b6ac52a0c\" }` with a status code 200\n\nNow, we have a way to identify a user, create a token (= avoid to store the password on any front-end) and use this token for 24h to access to the API!\n\nEvery authenticated endpoints of our API will look at this token inside the header `X-Token`.\n\n`GET /disconnect` should sign-out the user based on the token:\n\n-   Retrieve the user based on the token:\n    -   If not found, return an error `Unauthorized` with a status code 401\n    -   Otherwise, delete the token in Redis and return nothing with a status code 204\n\nInside the file `controllers/UsersController.js` add a new endpoint:\n\n`GET /users/me` should retrieve the user base on the token used:\n\n-   Retrieve the user based on the token:\n    -   If not found, return an error `Unauthorized` with a status code 401\n    -   Otherwise, return the user object (`email` and `id` only)\n\n```\nbob@dylan:~$ curl 0.0.0.0:5000/connect -H \"Authorization: Basic Ym9iQGR5bGFuLmNvbTp0b3RvMTIzNCE=\" ; echo \"\"\n{\"token\":\"031bffac-3edc-4e51-aaae-1c121317da8a\"}\nbob@dylan:~$\nbob@dylan:~$ curl 0.0.0.0:5000/users/me -H \"X-Token: 031bffac-3edc-4e51-aaae-1c121317da8a\" ; echo \"\"\n{\"id\":\"5f1e7cda04a394508232559d\",\"email\":\"bob@dylan.com\"}\nbob@dylan:~$\nbob@dylan:~$ curl 0.0.0.0:5000/disconnect -H \"X-Token: 031bffac-3edc-4e51-aaae-1c121317da8a\" ; echo \"\"\n\nbob@dylan:~$ curl 0.0.0.0:5000/users/me -H \"X-Token: 031bffac-3edc-4e51-aaae-1c121317da8a\" ; echo \"\"\n{\"error\":\"Unauthorized\"}\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `utils/, routes/index.js, controllers/UsersController.js, controllers/AuthController.js`\n\n Done? Help Get a sandbox\n\n### 5\\. First file\n\nmandatory\n\nIn the file `routes/index.js`, add a new endpoint:\n\n-   `POST /files` =\u003e `FilesController.postUpload`\n\nInside `controllers`, add a file `FilesController.js` that contains the new endpoint:\n\n`POST /files` should create a new file in DB and in disk:\n\n-   Retrieve the user based on the token:\n    -   If not found, return an error `Unauthorized` with a status code 401\n-   To create a file, you must specify:\n    -   `name`: as filename\n    -   `type`: either `folder`, `file` or `image`\n    -   `parentId`: (optional) as ID of the parent (default: 0 -\u003e the root)\n    -   `isPublic`: (optional) as boolean to define if the file is public or not (default: false)\n    -   `data`: (only for `type=file|image`) as Base64 of the file content\n-   If the `name` is missing, return an error `Missing name` with a status code 400\n-   If the `type` is missing or not part of the list of accepted type, return an error `Missing type` with a status code 400\n-   If the `data` is missing and `type != folder`, return an error `Missing data` with a status code 400\n-   If the `parentId` is set:\n    -   If no file is present in DB for this `parentId`, return an error `Parent not found` with a status code 400\n    -   If the file present in DB for this `parentId` is not of type `folder`, return an error `Parent is not a folder` with a status code 400\n-   The user ID should be added to the document saved in DB - as owner of a file\n-   If the type is `folder`, add the new file document in the DB and return the new file with a status code 201\n-   Otherwise:\n    -   All file will be stored locally in a folder (to create automatically if not present):\n        -   The relative path of this folder is given by the environment variable `FOLDER_PATH`\n        -   If this variable is not present or empty, use `/tmp/files_manager` as storing folder path\n    -   Create a local path in the storing folder with filename a UUID\n    -   Store the file in clear (reminder: `data` contains the Base64 of the file) in this local path\n    -   Add the new file document in the collection `files` with these attributes:\n        -   `userId`: ID of the owner document (owner from the authentication)\n        -   `name`: same as the value received\n        -   `type`: same as the value received\n        -   `isPublic`: same as the value received\n        -   `parentId`: same as the value received - if not present: 0\n        -   `localPath`: for a `type=file|image`, the absolute path to the file save in local\n    -   Return the new file with a status code 201\n\n```\nbob@dylan:~$ curl 0.0.0.0:5000/connect -H \"Authorization: Basic Ym9iQGR5bGFuLmNvbTp0b3RvMTIzNCE=\" ; echo \"\"\n{\"token\":\"f21fb953-16f9-46ed-8d9c-84c6450ec80f\"}\nbob@dylan:~$\nbob@dylan:~$ curl -XPOST 0.0.0.0:5000/files -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" -H \"Content-Type: application/json\" -d '{ \"name\": \"myText.txt\", \"type\": \"file\", \"data\": \"SGVsbG8gV2Vic3RhY2shCg==\" }' ; echo \"\"\n{\"id\":\"5f1e879ec7ba06511e683b22\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"myText.txt\",\"type\":\"file\",\"isPublic\":false,\"parentId\":0}\nbob@dylan:~$\nbob@dylan:~$ ls /tmp/files_manager/\n2a1f4fc3-687b-491a-a3d2-5808a02942c9\nbob@dylan:~$\nbob@dylan:~$ cat /tmp/files_manager/2a1f4fc3-687b-491a-a3d2-5808a02942c9\nHello Webstack!\nbob@dylan:~$\nbob@dylan:~$ curl -XPOST 0.0.0.0:5000/files -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" -H \"Content-Type: application/json\" -d '{ \"name\": \"images\", \"type\": \"folder\" }' ; echo \"\"\n{\"id\":\"5f1e881cc7ba06511e683b23\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"images\",\"type\":\"folder\",\"isPublic\":false,\"parentId\":0}\nbob@dylan:~$\nbob@dylan:~$ cat image_upload.py\nimport base64\nimport requests\nimport sys\n\nfile_path = sys.argv[1]\nfile_name = file_path.split('/')[-1]\n\nfile_encoded = None\nwith open(file_path, \"rb\") as image_file:\n    file_encoded = base64.b64encode(image_file.read()).decode('utf-8')\n\nr_json = { 'name': file_name, 'type': 'image', 'isPublic': True, 'data': file_encoded, 'parentId': sys.argv[3] }\nr_headers = { 'X-Token': sys.argv[2] }\n\nr = requests.post(\"http://0.0.0.0:5000/files\", json=r_json, headers=r_headers)\nprint(r.json())\n\nbob@dylan:~$\nbob@dylan:~$ python image_upload.py image.png f21fb953-16f9-46ed-8d9c-84c6450ec80f 5f1e881cc7ba06511e683b23\n{'id': '5f1e8896c7ba06511e683b25', 'userId': '5f1e7cda04a394508232559d', 'name': 'image.png', 'type': 'image', 'isPublic': True, 'parentId': '5f1e881cc7ba06511e683b23'}\nbob@dylan:~$\nbob@dylan:~$ echo 'db.files.find()' | mongo files_manager\n{ \"_id\" : ObjectId(\"5f1e881cc7ba06511e683b23\"), \"userId\" : ObjectId(\"5f1e7cda04a394508232559d\"), \"name\" : \"images\", \"type\" : \"folder\", \"parentId\" : \"0\" }\n{ \"_id\" : ObjectId(\"5f1e879ec7ba06511e683b22\"), \"userId\" : ObjectId(\"5f1e7cda04a394508232559d\"), \"name\" : \"myText.txt\", \"type\" : \"file\", \"parentId\" : \"0\", \"isPublic\" : false, \"localPath\" : \"/tmp/files_manager/2a1f4fc3-687b-491a-a3d2-5808a02942c9\" }\n{ \"_id\" : ObjectId(\"5f1e8896c7ba06511e683b25\"), \"userId\" : ObjectId(\"5f1e7cda04a394508232559d\"), \"name\" : \"image.png\", \"type\" : \"image\", \"parentId\" : ObjectId(\"5f1e881cc7ba06511e683b23\"), \"isPublic\" : true, \"localPath\" : \"/tmp/files_manager/51997b88-5c42-42c2-901e-e7f4e71bdc47\" }\nbob@dylan:~$\nbob@dylan:~$ ls /tmp/files_manager/\n2a1f4fc3-687b-491a-a3d2-5808a02942c9   51997b88-5c42-42c2-901e-e7f4e71bdc47\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `utils/, routes/index.js, controllers/FilesController.js`\n\n Done? Help Get a sandbox\n\n### 6\\. Get and list file\n\nmandatory\n\nIn the file `routes/index.js`, add 2 new endpoints:\n\n-   `GET /files/:id` =\u003e `FilesController.getShow`\n-   `GET /files` =\u003e `FilesController.getIndex`\n\nIn the file `controllers/FilesController.js`, add the 2 new endpoints:\n\n`GET /files/:id` should retrieve the file document based on the ID:\n\n-   Retrieve the user based on the token:\n    -   If not found, return an error `Unauthorized` with a status code 401\n-   If no file document is linked to the user and the ID passed as parameter, return an error `Not found` with a status code 404\n-   Otherwise, return the file document\n\n`GET /files` should retrieve all users file documents for a specific `parentId` and with pagination:\n\n-   Retrieve the user based on the token:\n    -   If not found, return an error `Unauthorized` with a status code 401\n-   Based on the query parameters `parentId` and `page`, return the list of file document\n    -   `parentId`:\n        -   No validation of `parentId` needed - if the `parentId` is not linked to any user folder, returns an empty list\n        -   By default, `parentId` is equal to 0 = the root\n    -   Pagination:\n        -   Each page should be 20 items max\n        -   `page` query parameter starts at 0 for the first page. If equals to 1, it means it's the second page (form the 20th to the 40th), etc...\n        -   Pagination can be done directly by the `aggregate` of MongoDB\n\n```\nbob@dylan:~$ curl 0.0.0.0:5000/connect -H \"Authorization: Basic Ym9iQGR5bGFuLmNvbTp0b3RvMTIzNCE=\" ; echo \"\"\n{\"token\":\"f21fb953-16f9-46ed-8d9c-84c6450ec80f\"}\nbob@dylan:~$\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" ; echo \"\"\n[{\"id\":\"5f1e879ec7ba06511e683b22\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"myText.txt\",\"type\":\"file\",\"isPublic\":false,\"parentId\":0},{\"id\":\"5f1e881cc7ba06511e683b23\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"images\",\"type\":\"folder\",\"isPublic\":false,\"parentId\":0},{\"id\":\"5f1e8896c7ba06511e683b25\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"image.png\",\"type\":\"image\",\"isPublic\":true,\"parentId\":\"5f1e881cc7ba06511e683b23\"}]\nbob@dylan:~$\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files?parentId=5f1e881cc7ba06511e683b23 -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" ; echo \"\"\n[{\"id\":\"5f1e8896c7ba06511e683b25\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"image.png\",\"type\":\"image\",\"isPublic\":true,\"parentId\":\"5f1e881cc7ba06511e683b23\"}]\nbob@dylan:~$\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files/5f1e8896c7ba06511e683b25 -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" ; echo \"\"\n{\"id\":\"5f1e8896c7ba06511e683b25\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"image.png\",\"type\":\"image\",\"isPublic\":true,\"parentId\":\"5f1e881cc7ba06511e683b23\"}\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `utils/, routes/index.js, controllers/FilesController.js`\n\n Done? Help Get a sandbox\n\n### 7\\. File publish/unpublish\n\nmandatory\n\nIn the file `routes/index.js`, add 2 new endpoints:\n\n-   `PUT /files/:id/publish` =\u003e `FilesController.putPublish`\n-   `PUT /files/:id/publish` =\u003e `FilesController.putUnpublish`\n\nIn the file `controllers/FilesController.js`, add the 2 new endpoints:\n\n`PUT /files/:id/publish` should set `isPublic` to `true` on the file document based on the ID:\n\n-   Retrieve the user based on the token:\n    -   If not found, return an error `Unauthorized` with a status code 401\n-   If no file document is linked to the user and the ID passed as parameter, return an error `Not found` with a status code 404\n-   Otherwise:\n    -   Update the value of `isPublic` to `true`\n    -   And return the file document with a status code 200\n\n`PUT /files/:id/unpublish` should set `isPublic` to `false` on the file document based on the ID:\n\n-   Retrieve the user based on the token:\n    -   If not found, return an error `Unauthorized` with a status code 401\n-   If no file document is linked to the user and the ID passed as parameter, return an error `Not found` with a status code 404\n-   Otherwise:\n    -   Update the value of `isPublic` to `false`\n    -   And return the file document with a status code 200\n\n```\nbob@dylan:~$ curl 0.0.0.0:5000/connect -H \"Authorization: Basic Ym9iQGR5bGFuLmNvbTp0b3RvMTIzNCE=\" ; echo \"\"\n{\"token\":\"f21fb953-16f9-46ed-8d9c-84c6450ec80f\"}\nbob@dylan:~$\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files/5f1e8896c7ba06511e683b25 -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" ; echo \"\"\n{\"id\":\"5f1e8896c7ba06511e683b25\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"image.png\",\"type\":\"image\",\"isPublic\":false,\"parentId\":\"5f1e881cc7ba06511e683b23\"}\nbob@dylan:~$\nbob@dylan:~$ curl -XPUT 0.0.0.0:5000/files/5f1e8896c7ba06511e683b25/publish -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" ; echo \"\"\n{\"id\":\"5f1e8896c7ba06511e683b25\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"image.png\",\"type\":\"image\",\"isPublic\":true,\"parentId\":\"5f1e881cc7ba06511e683b23\"}\nbob@dylan:~$\nbob@dylan:~$ curl -XPUT 0.0.0.0:5000/files/5f1e8896c7ba06511e683b25/unpublish -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" ; echo \"\"\n{\"id\":\"5f1e8896c7ba06511e683b25\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"image.png\",\"type\":\"image\",\"isPublic\":false,\"parentId\":\"5f1e881cc7ba06511e683b23\"}\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `utils/, routes/index.js, controllers/FilesController.js`\n\n Done? Help Get a sandbox\n\n### 8\\. File data\n\nmandatory\n\nIn the file `routes/index.js`, add one new endpoint:\n\n-   `GET /files/:id/data` =\u003e `FilesController.getFile`\n\nIn the file `controllers/FilesController.js`, add the new endpoint:\n\n`GET /files/:id/data` should return the content of the file document based on the ID:\n\n-   If no file document is linked to the ID passed as parameter, return an error `Not found` with a status code 404\n-   If the file document (folder or file) is not public (`isPublic: false`) and no user authenticate or not the owner of the file, return an error `Not found` with a status code 404\n-   If the type of the file document is `folder`, return an error `A folder doesn't have content` with a status code 400\n-   If the file is not locally present, return an error `Not found` with a status code 404\n-   Otherwise:\n    -   By using the module `mime-types`, get the [MIME-type](https://alx-intranet.hbtn.io/rltoken/buV7HGNuNMB5ZCUH0LdECw \"MIME-type\") based on the `name` of the file\n    -   Return the content of the file with the correct MIME-type\n\n```\nbob@dylan:~$ curl 0.0.0.0:5000/connect -H \"Authorization: Basic Ym9iQGR5bGFuLmNvbTp0b3RvMTIzNCE=\" ; echo \"\"\n{\"token\":\"f21fb953-16f9-46ed-8d9c-84c6450ec80f\"}\nbob@dylan:~$\nbob@dylan:~$ curl -XPUT 0.0.0.0:5000/files/5f1e879ec7ba06511e683b22/unpublish -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" ; echo \"\"\n{\"id\":\"5f1e879ec7ba06511e683b22\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"myText.txt\",\"type\":\"file\",\"isPublic\":false,\"parentId\":0}\nbob@dylan:~$\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files/5f1e879ec7ba06511e683b22/data -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" ; echo \"\"\nHello Webstack!\n\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files/5f1e879ec7ba06511e683b22/data ; echo \"\"\n{\"error\":\"Not found\"}\nbob@dylan:~$\nbob@dylan:~$ curl -XPUT 0.0.0.0:5000/files/5f1e879ec7ba06511e683b22/publish -H \"X-Token: f21fb953-16f9-46ed-8d9c-84c6450ec80f\" ; echo \"\"\n{\"id\":\"5f1e879ec7ba06511e683b22\",\"userId\":\"5f1e7cda04a394508232559d\",\"name\":\"myText.txt\",\"type\":\"file\",\"isPublic\":true,\"parentId\":0}\nbob@dylan:~$\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files/5f1e879ec7ba06511e683b22/data ; echo \"\"\nHello Webstack!\n\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `utils/, routes/index.js, controllers/FilesController.js`\n\n Done? Help\n\n### 9\\. Image Thumbnails\n\nmandatory\n\nUpdate the endpoint `POST /files` endpoint to start a background processing for generating thumbnails for a file of type `image`:\n\n-   Create a `Bull` queue `fileQueue`\n-   When a new image is stored (in local and in DB), add a job to this queue with the `userId` and `fileId`\n\nCreate a file `worker.js`:\n\n-   By using the module `Bull`, create a queue `fileQueue`\n-   Process this queue:\n    -   If `fileId` is not present in the job, raise an error `Missing fileId`\n    -   If `userId` is not present in the job, raise an error `Missing userId`\n    -   If no document is found in DB based on the `fileId` and `userId`, raise an error `File not found`\n    -   By using the module `image-thumbnail`, generate 3 thumbnails with `width` = 500, 250 and 100 - store each result on the same location of the original file by appending `_\u003cwidth size\u003e`\n\nUpdate the endpoint `GET /files/:id/data` to accept a query parameter `size`:\n\n-   `size` can be `500`, `250` or `100`\n-   Based on `size`, return the correct local file\n-   If the local file doesn't exist, return an error `Not found` with a status code 404\n\n**Terminal 3:** (start the worker)\n\n```\nbob@dylan:~$ npm run start-worker\n...\n\n```\n\n**Terminal 2:**\n\n```\nbob@dylan:~$ curl 0.0.0.0:5000/connect -H \"Authorization: Basic Ym9iQGR5bGFuLmNvbTp0b3RvMTIzNCE=\" ; echo \"\"\n{\"token\":\"f21fb953-16f9-46ed-8d9c-84c6450ec80f\"}\nbob@dylan:~$\nbob@dylan:~$ python image_upload.py image.png f21fb953-16f9-46ed-8d9c-84c6450ec80f 5f1e881cc7ba06511e683b23\n{'id': '5f1e8896c7ba06511e683b25', 'userId': '5f1e7cda04a394508232559d', 'name': 'image.png', 'type': 'image', 'isPublic': True, 'parentId': '5f1e881cc7ba06511e683b23'}\nbob@dylan:~$ ls /tmp/files_manager/\n2a1f4fc3-687b-491a-a3d2-5808a02942c9   51997b88-5c42-42c2-901e-e7f4e71bdc47   6dc53397-8491-4b7c-8273-f748b1a031cb   6dc53397-8491-4b7c-8273-f748b1a031cb_100   6dc53397-8491-4b7c-8273-f748b1a031cb_250    6dc53397-8491-4b7c-8273-f748b1a031cb_500\nbob@dylan:~$\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files/5f1e8896c7ba06511e683b25/data -so new_image.png ; file new_image.png\nnew_image.png: PNG image data, 471 x 512, 8-bit/color RGBA, non-interlaced\nbob@dylan:~$\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files/5f1e8896c7ba06511e683b25/data?size=100 -so new_image.png ; file new_image.png\nnew_image.png: PNG image data, 100 x 109, 8-bit/color RGBA, non-interlaced\nbob@dylan:~$\nbob@dylan:~$ curl -XGET 0.0.0.0:5000/files/5f1e8896c7ba06511e683b25/data?size=250 -so new_image.png ; file new_image.png\nnew_image.png: PNG image data, 250 x 272, 8-bit/color RGBA, non-interlaced\nbob@dylan:~$\n\n```\n\n**Repo:**\n\n-   GitHub repository: `alx-files_manager`\n-   File: `utils/, controllers/FilesController.js, worker.js`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpericles001%2Falx-files_manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpericles001%2Falx-files_manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpericles001%2Falx-files_manager/lists"}