{"id":18783431,"url":"https://github.com/futuresea-dev/lms_backend","last_synced_at":"2026-04-15T18:32:01.556Z","repository":{"id":157980020,"uuid":"593063331","full_name":"futuresea-dev/LMS_Backend","owner":"futuresea-dev","description":"LMS Backend","archived":false,"fork":false,"pushed_at":"2023-02-01T15:31:31.000Z","size":1186,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-01T13:03:46.113Z","etag":null,"topics":["api","css","django","django-rest-framework","javascript","python"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/futuresea-dev.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":"2023-01-25T06:10:56.000Z","updated_at":"2025-07-31T14:13:34.000Z","dependencies_parsed_at":null,"dependency_job_id":"967eb373-7414-4eee-85b4-abd316815b1d","html_url":"https://github.com/futuresea-dev/LMS_Backend","commit_stats":null,"previous_names":["futurelife365/lms_backend","futuresea-dev/lms_backend"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/futuresea-dev/LMS_Backend","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futuresea-dev%2FLMS_Backend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futuresea-dev%2FLMS_Backend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futuresea-dev%2FLMS_Backend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futuresea-dev%2FLMS_Backend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/futuresea-dev","download_url":"https://codeload.github.com/futuresea-dev/LMS_Backend/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futuresea-dev%2FLMS_Backend/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31854717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"ssl_error","status_checked_at":"2026-04-15T15:24:39.138Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["api","css","django","django-rest-framework","javascript","python"],"created_at":"2024-11-07T20:39:18.863Z","updated_at":"2026-04-15T18:32:01.527Z","avatar_url":"https://github.com/futuresea-dev.png","language":"JavaScript","readme":"# User Authentication and BOOK API\n\nUser Authentication and BOOK API written in django rest framework + JWT\n\n### Installing\n\nI keep the database updated with the newest additions and data, so it should be just cloning the repository and installing the requirements and you're good to go\n\nCreate venv\n\n```bash\npy -m venv env\n# after activation the env\npip install -r requirements.txt\n```\n\n##### Start it using docker-compose\n\n```bash\ndocker-compose up\n```\n\n### Deployment\n\nBe sure set DEBUG = False, is_test_data in BaseModel (which every model is derived from) is dependent on this setting, if you set DEBUG False, is_test_data will be False and the API won't show up data with is_test_data = False, so the initial data from this repository's database won't show up.\n\nFor Rest:\n[Django Deployment Checklist](https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/)\n\n### Features\n- User login and register with Email , Password. \n  return JWT token\n- book, author, publisher, category endpoints return the appropriate serialized models,\n- book endpoint has url parameter that makes it easy to filter\n  - you can filter books by author, publisher,category, as well as order them via price, or search books via their names\n- These endpoints are all paginated (Max 50 results per page) and will return a data in this structure:\n  - for instance /api/author endpoint gives this json\n  - ```json\n    {\n      \"count\": 15,\n      \"next\": null,\n      \"previous\": null,\n      \"results\": [\n        {\n          \"id\": 3,\n          \"name\": \"Cornell Crowcombe\",\n          \"about\": \"Nullam porttitor lacus at turpis. Donec posuere metus vitae ipsum. Aliquam non mauris.\\r\\n\\r\\nMorbi non lectus. Aliquam sit amet diam in magna bibendum imperdiet. Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis.\\r\\n\\r\\nFusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.\\r\\n\\r\\nSed sagittis. Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci. Nullam molestie nibh in lectus.\",\n          \"birth_date\": null,\n          \"death_date\": null,\n          \"author_image\": \"http://localhost:5000/media/placeholder_author.png\"\n        },\n        {\n          \"id\": 4,\n          \"name\": \"Yorgo Mebius\",\n          \"about\": \"Fusce consequat. Nulla nisl. Nunc nisl.\\r\\n\\r\\nDuis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum.\\r\\n\\r\\nIn hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.\\r\\n\\r\\nAliquam quis turpis eget elit sodales scelerisque. Mauris sit amet eros. Suspendisse accumsan tortor quis turpis.\\r\\n\\r\\nSed ante. Vivamus tortor. Duis mattis egestas metus.\",\n          \"birth_date\": null,\n          \"death_date\": null,\n          \"author_image\": \"http://localhost:5000/media/placeholder_author.png\"\n        }\n      ]\n    }\n    ```\n  ```\n\n  ```\n- These endpoints also can be accessed via their ids in the route,\n  - /api/author/3/ would return a data like this:\n    - ```json\n      {\n        \"id\": 3,\n        \"name\": \"Cornell Crowcombe\",\n        \"about\": \"Nullam porttitor lacus at turpis. Donec posuere metus vitae ipsum. Aliquam non mauris.\\r\\n\\r\\nMorbi non lectus. Aliquam sit amet diam in magna bibendum imperdiet. Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis.\\r\\n\\r\\nFusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.\\r\\n\\r\\nSed sagittis. Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci. Nullam molestie nibh in lectus.\",\n        \"birth_date\": null,\n        \"death_date\": null,\n        \"author_image\": \"http://localhost:5000/media/placeholder_author.png\"\n      }\n      ```\n    ```\n\n    ```\n\n#### JWT Token Authorization\n\n- Every POST/GET requests listed in here must have a header (except of course login):\n  ```json\n      \"Authorization\" : \"JWT token\"\n  ```\n- User Login/Registration\n\n  - Login at : POST /login\n  - Register at : POST /api/user\n\n- Users can add/remove books to/from their Favorite\n  - POST to Cart endpoint (/api/favorite/) with a book id in the database:\n    ```py\n    class FavoritesModel(BaseModel):\n        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)\n        book = models.ForeignKey(BookModel, on_delete=models.CASCADE)\n\n        @property\n\n        def __str__(self):\n            return f\"Cart {self.user}'s Book {self.id} (Book {self.book})\"\n    ```\n  - DELETE to Favorite endpoint:\n\n### Models\n\nEvery model is derived from the same BaseModel (declared in LibraryManagementSystem/library/models.py)\n\n```py\nclass BaseQuerySet(models.QuerySet):\n    def delete(self):\n        return super(BaseQuerySet, self).update(deleted_at=now())\n\n    def hard_delete(self):\n        return super(BaseQuerySet, self).delete()\n\n\nclass BaseManager(models.Manager):\n    def __init__(self, *args, **kwargs):\n        self.get_deleted = kwargs.pop('get_deleted', False)\n        super(BaseManager, self).__init__(*args, **kwargs)\n\n    def get_queryset(self):\n        if self.get_deleted:\n            return BaseQuerySet(self.model).filter(is_test_data=settings.DEBUG)\n        else:\n            return BaseQuerySet(self.model).filter(deleted_at=None, is_test_data=settings.DEBUG)\n\n    def hard_delete(self):\n        return self.get_queryset().hard_delete()\n\n\nclass BaseModel(models.Model):\n\n    objects = BaseManager()\n    all_objects = BaseManager(get_deleted=True)\n\n    is_test_data = models.BooleanField(default=settings.DEBUG)\n    created_at = models.DateTimeField(default=now)\n    modified_at = models.DateTimeField(null=True, blank=True)\n    deleted_at = models.DateTimeField(null=True, blank=True)\n\n    created_by = models.ForeignKey(User, related_name='%(class)s_createdby',\n                                   null=True, blank=True, on_delete=models.SET_NULL)\n    modified_by = models.ForeignKey(User,\n                            related_name='%(class)s_modifiedby', null=True, blank=True, on_delete=models.SET_NULL)\n    deleted_by = models.ForeignKey(User,\n                            related_name='%(class)s_deletedby', null=True, blank=True, on_delete=models.SET_NULL)\n    class Meta:\n        abstract = True\n\n    def delete(self, deleted_by_user=None):\n        self.deleted_by = deleted_by_user\n        self.deleted_at = now()\n        self.save()\n\n    def hard_delete(self):\n        super(BaseModel, self).delete()\n```\n\n- Models with attributes is_test_data = 1 or deleted_at = 'some date' doesn't show up in the api views\n\n  - Unless django settings.DEBUG is True, then the is_test_data = 1 shows up in the API views, this is here to make sure test datas don't show up in production\n  - deleted_at flag is there to make sure no data is lost in the database\n\n- With this implementation (Soft Deleting) you can call delete() method from anywhere without a worry of losing your data\n\n#### Models for Frontend\n\n##### Author\n\n```py\nclass AuthorModel(BaseModel):\n    name = models.CharField(max_length=100)\n    about = models.TextField(null=True, blank=True)\n    birth_date = models.DateField(null=True, blank=True)\n    death_date = models.DateField(null=True, blank=True)\n    author_image = models.ImageField(default=\"placeholder_author.png\")\n\n    def __str__(self):\n        return self.name\n```\n\n##### Publisher/Category\n\n```py\nclass PublisherModel(BaseModel):\n    name = models.CharField(max_length=100)\n    descripton = models.TextField(null=True, blank=True)\n\n    def __str__(self):\n        return self.name\n\nclass CategoryModel(BaseModel):\n    name = models.CharField(max_length=50)\n    description = models.TextField(null=True, blank=True)\n\n    def __str__(self):\n        return self.name\n```\n\n##### Book\n\n```py\nclass BookModel(BaseModel):\n    name = models.CharField(max_length=100)\n    published_date = models.DateField(null=True, blank=True)\n    book_cover = models.ImageField(default=\"placeholder_cover.png\")\n    description = models.TextField()\n    # how many books that are currently in storage\n    store_amount = models.IntegerField(default=1)\n    # page count of the book, no need to specify it\n    pages = models.IntegerField(null=True, blank=True)\n    #ISBN doesn't exist for books that have been published before 1970\n    ISBN = models.IntegerField(null=True, blank=True)\n    price = models.DecimalField(max_digits=10, decimal_places=2)\n    author = models.ForeignKey(AuthorModel, on_delete=models.SET_NULL, null=True, blank=True)\n    category = models.ForeignKey(CategoryModel, on_delete=models.SET_NULL, null=True, blank=True)\n    publisher = models.ForeignKey(PublisherModel, on_delete=models.SET_NULL, null=True, blank=True)\n\n    def __str__(self):\n        return self.name\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuturesea-dev%2Flms_backend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffuturesea-dev%2Flms_backend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuturesea-dev%2Flms_backend/lists"}