{"id":20287036,"url":"https://github.com/codewithsegnet/hng_backend_stage_2","last_synced_at":"2026-05-11T09:36:17.762Z","repository":{"id":247083131,"uuid":"824863987","full_name":"CodewithSegNet/HNG_backend_Stage_2","owner":"CodewithSegNet","description":"BACKEND Stage 2 Task: User Authentication \u0026 Organisation","archived":false,"fork":false,"pushed_at":"2024-07-07T22:41:43.000Z","size":12276,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-14T08:23:30.174Z","etag":null,"topics":["flask","flask-api","flask-sqlalchemy","jwt-authentication","restful-api"],"latest_commit_sha":null,"homepage":"https://hng-backend-stage-2-lumf.onrender.com","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CodewithSegNet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-06T06:48:16.000Z","updated_at":"2024-07-07T22:41:46.000Z","dependencies_parsed_at":"2024-07-06T14:24:49.917Z","dependency_job_id":"a5d22423-3729-4152-9b0b-97fdd8f93de6","html_url":"https://github.com/CodewithSegNet/HNG_backend_Stage_2","commit_stats":null,"previous_names":["codewithsegnet/hng_backend_stage_2"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodewithSegNet%2FHNG_backend_Stage_2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodewithSegNet%2FHNG_backend_Stage_2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodewithSegNet%2FHNG_backend_Stage_2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodewithSegNet%2FHNG_backend_Stage_2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CodewithSegNet","download_url":"https://codeload.github.com/CodewithSegNet/HNG_backend_Stage_2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241780497,"owners_count":20019061,"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":["flask","flask-api","flask-sqlalchemy","jwt-authentication","restful-api"],"created_at":"2024-11-14T14:37:55.492Z","updated_at":"2026-05-11T09:36:17.730Z","avatar_url":"https://github.com/CodewithSegNet.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BACKEND Stage 2 Task: User Authentication \u0026 Organisation\n\nUsing your most comfortable backend framework of your choice, adhere to the following acceptance:\n\n**READ CAREFULLY!!!**Acceptance Criteria\n\n- Connect your application to a **Postgres** database server. (optional: you can choose to use any ORM of your choice if you want or not).\n- Create a `User` model using the properties below\n- NB: user id and email must be unique\n\n```\n{\n\t\"userId\": \"string\" // must be unique\n\t\"firstName\": \"string\", // must not be null\n\t\"lastName\": \"string\" // must not be null\n\t\"email\": \"string\" // must be unique and must not be null\n\t\"password\": \"string\" // must not be null\n\t\"phone\": \"string\"\n}\n\n```\n\n- Provide validation for all fields. When there’s a validation error, return status code `422` with payload:\n\n```\n{\n  \"errors\": [\n    {\n      \"field\": \"string\",\n      \"message\": \"string\"\n    },\n  ]\n}\n\n```\n\n- Using the schema above, implement user authentication\n- User Registration:\n- Implement an endpoint for user registration\n- Hash the user’s password before storing them in the database.\n- successful response: Return the payload with a `201` success status code.\n- User Login\n- Implement an endpoint for user Login.\n- Use the JWT token returned to access PROTECTED endpoints.\n\nOrganisation\n\n- A user can belong to one or more organisations\n- An organisation can contain one or more users.\n- On every registration, an organisation must be created.\n- The `name` property of the organisation takes the user’s `firstName` and appends “Organisation” to it. For example: user’s first name is `John` , organisation name becomes `\"John's Organisation\"` because `firstName = \"John\"` .\n- Logged in users can access organisations they belong to and organisations they created.\n- Create an `organisation` model with the properties below.\n\nOrganisation Model:\n\n```\n{\n\t\"orgId\": \"string\", // Unique\n\t\"name\": \"string\", // Required and cannot be null\n\t\"description\": \"string\",\n}\n\n```\n\nEndpoints:\n\n- `[POST] /auth/register` Registers a users and creates a default organisation Register request body:\n\n```\n{\n\t\"firstName\": \"string\",\n\t\"lastName\": \"string\",\n\t\"email\": \"string\",\n\t\"password\": \"string\",\n\t\"phone\": \"string\",\n}\n\n```\n\nSuccessful response: Return the payload below with a `201` success status code.\n\n```\n{\n    \"status\": \"success\",\n    \"message\": \"Registration successful\",\n    \"data\": {\n      \"accessToken\": \"eyJh...\",\n      \"user\": {\n        \"userId\": \"string\",\n        \"firstName\": \"string\",\n        \"lastName\": \"string\",\n        \"email\": \"string\",\n        \"phone\": \"string\",\n      }\n    }\n}\n\n```\n\nUnsuccessful registration response:\n\n```\n{\n    \"status\": \"Bad request\",\n    \"message\": \"Registration unsuccessful\",\n    \"statusCode\": 400\n}\n\n```\n\n- `[POST] /auth/login` : logs in a user. When you log in, you can select an organisation to interact with\n\nLogin request body:\n\n```\n{\n\t\"email\": \"string\",\n\t\"password\": \"string\",\n}\n\n```\n\nSuccessful response: Return the payload below with a `200` success status code.\n\n```\n{\n    \"status\": \"success\",\n    \"message\": \"Login successful\",\n    \"data\": {\n      \"accessToken\": \"eyJh...\",\n      \"user\": {\n          \"userId\": \"string\",\n          \"firstName\": \"string\",\n          \"lastName\": \"string\",\n          \"email\": \"string\",\n          \"phone\": \"string\",\n      }\n    }\n}\n\n```\n\nUnsuccessful login response:\n\n```\n{\n    \"status\": \"Bad request\",\n    \"message\": \"Authentication failed\",\n    \"statusCode\": 401\n}\n\n```\n\n- `[GET] /api/users/:id` : a user gets their own record or user record in organisations they belong to or created [PROTECTED].\n\nSuccessful response: Return the payload below with a `200` success status code.\n\n```\n{\n  \"status\": \"success\",\n  \"message\": \"\u003cmessage\u003e\",\n    \"data\": {\n          \"userId\": \"string\",\n          \"firstName\": \"string\",\n          \"lastName\": \"string\",\n          \"email\": \"string\",\n          \"phone\": \"string\"\n    }\n}\n\n```\n\n- `[GET] /api/organisations` : gets all your organisations the user belongs to or created. If a user is logged in properly, they can get all their organisations. They should not get another user’s organisation [PROTECTED].\n\nSuccessful response: Return the payload below with a `200` success status code.\n\n```\n{\n    \"status\": \"success\",\n    \"message\": \"\u003cmessage\u003e\",\n    \"data\": {\n      \"organisations\": [\n      {\n        \"orgId\": \"string\",\n        \"name\": \"string\",\n        \"description\": \"string\",\n      }\n      ]\n    }\n}\n\n```\n\n- `[GET] /api/organisations/:orgId` the logged in user gets a single organisation record [PROTECTED]\n\nSuccessful response: Return the payload below with a `200` success status code.\n\n```\n{\n    \"status\": \"success\",\n    \"message\": \"\u003cmessage\u003e\",\n    \"data\": {\n          \"orgId\": \"string\", // Unique\n          \"name\": \"string\", // Required and cannot be null\n          \"description\": \"string\",\n  }\n}\n\n```\n\n- `[POST] /api/organisations` : a user can create their new organisation [PROTECTED].\n\nRequest body: request body must be validated\n\n```\n{\n\t\"name\": \"string\", // Required and cannot be null\n\t\"description\": \"string\",\n}\n\n```\n\nSuccessful response: Return the payload below with a `201` success status code.\n\n```\n{\n    \"status\": \"success\",\n    \"message\": \"Organisation created successfully\",\n    \"data\": {\n            \"orgId\": \"string\",\n            \"name\": \"string\",\n            \"description\": \"string\"\n    }\n}\n\n```\n\nUnsuccessful response:\n\n```\n{\n    \"status\": \"Bad Request\",\n    \"message\": \"Client error\",\n    \"statusCode\": 400\n}\n\n```\n\n- `[POST] /api/organisations/:orgId/users` : adds a user to a particular organisation\n\nRequest body:\n\n```\n{\n\t\"userId\": \"string\"\n}\n\n```\n\nSuccessful response: Return the payload below with a `200` success status code.\n\n```\n{\n    \"status\": \"success\",\n    \"message\": \"User added to organisation successfully\",\n}\n\n```\n\nUnit TestingWrite appropriate unit tests to cover\n\n- Token generation - Ensure token expires at the correct time and correct user details is found in token.\n- Organisation - Ensure users can’t see data from organisations they don’t have access to.\n\nEnd-to-End Test Requirements for the Register EndpointThe goal is to ensure the `POST /auth/register` endpoint works correctly by performing end-to-end tests. The tests should cover successful user registration, validation errors, and database constraints.Directory Structure:\n\n- The test file should be named `auth.spec.ext` (ext is the file extension of your chosen language) inside a folder named `tests` . For example `tests/auth.spec.ts` assuming I’m using Typescript\n\nTest Scenarios:\n\n- **It Should Register User Successfully with Default Organisation:**Ensure a user is registered successfully when no organisation details are provided.\n- Verify the default organisation name is correctly generated (e.g., \"John's Organisation\" for a user with the first name \"John\").\n- Check that the response contains the expected user details and access token.\n- **It Should Log the user in successfully:**Ensure a user is logged in successfully when a valid credential is provided and fails otherwise.\n- Check that the response contains the expected user details and access token.\n- **It Should Fail If Required Fields Are Missing:**Test cases for each required field (firstName, lastName, email, password) missing.\n- Verify the response contains a status code of 422 and appropriate error messages.\n- **It Should Fail if there’s Duplicate Email or UserID:**Attempt to register two users with the same email.\n- Verify the response contains a status code of 422 and appropriate error messages.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodewithsegnet%2Fhng_backend_stage_2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodewithsegnet%2Fhng_backend_stage_2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodewithsegnet%2Fhng_backend_stage_2/lists"}