Repository: koladev32/drf-simple-apikey (language: python)

Issue:
Add an exemple project showcasing how to use the package
**Is your feature request related to a problem? Please describe.**

It will help the developers see an actual implementation of the project done by the maintainers but also can serve as a quick demo.

**Describe the solution you'd like**
A simple Django project with an API using API authentication for controlling accessing endpoint.



Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index b6e4761..6b7ea68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -127,3 +127,6 @@ dmypy.json
 
 # Pyre type checker
 .pyre/
+
+# idea files
+.idea
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67a1262..21a0aac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@ Changelog
 [Unreleased]
 ------------
 
+- Add an exemple project showcasing how to use the package (#45)
+
 [v0.1.2] - 2023-04-21
 ------------------
 - Add an example project to the package (#29)
diff --git a/README.md b/README.md
index 03686e5..d4fc5eb 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,18 @@ python manage.py generate_fernet_key
 
 ## Changelog
 
+You can find a demo in project in the `example` directory. To run the project, you can :
+
+```shell
+cd example
+pip install -r requirements.txt
+
+python manage.py migrate
+python manage.py runserver
+```
+
+## Changelog
+
 See [CHANGELOG.md](https://github.com/koladev32/djangorestframework-simple-apikey/blob/main/CHANGELOG.md).
 
 ## Contributing
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 4b0bdca..f6a6307 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,6 +1,54 @@
 Changelog
 =========
 
+[v0.1.2] - 2023-04-21
+------------------
+- Add an example project to the package (#29)
+
+- Fixed: DoesNotExist error not related to custom model (#38)
+
+[v0.1.1] - 2023-02-26
+------------------
+
+- Minor refactoring (#35)
+
+[v0.1.0] - 2023-02-06
+------------------
+- Add a script to generate a Fernet key (#21)
+- Add templates for issues and pull requests (#24)
+- Add documentation for the package (#10)
+
+[v0.0.3] - 2023-02-05
+------------------
+
+- Bug: Default settings are not loaded in the project (#25)
+
+[v0.0.2] - 2023-02-04
+------------------
+
+- Fix typo on admin `expiry_date` <- `expires_at` (#4)
+
+[v0.0.1] - 2023-02-04
+------------------Changelog
+=========
+
+[v0.1.2] - 2023-04-21
+------------------
+- Add an example project to the package (#29)
+
+- Fixed: DoesNotExist error not related to custom model (#38)
+
+[v0.1.1] - 2023-02-26
+------------------
+
+- Minor refactoring (#35)
+
+[v0.1.0] - 2023-02-06
+------------------
+- Add a script to generate a Fernet key (#21)
+- Add templates for issues and pull requests (#24)
+- Add documentation for the package (#10)
+
 [v0.0.3] - 2023-02-05
 ------------------
 
@@ -12,12 +60,35 @@ Changelog
 - Fix typo on admin `expiry_date` <- `expires_at` (#4)
 
 [v0.0.1] - 2023-02-04
+------------------Changelog
+=========
+
+[v0.1.2] - 2023-04-21
+------------------
+- Add an example project to the package (#29)
+
+- Fixed: DoesNotExist error not related to custom model (#38)
+
+[v0.1.1] - 2023-02-26
+------------------
+
+- Minor refactoring (#35)
+
+[v0.1.0] - 2023-02-06
+------------------
+- Add a script to generate a Fernet key (#21)
+- Add templates for issues and pull requests (#24)
+- Add documentation for the package (#10)
+
+[v0.0.3] - 2023-02-05
+------------------
+
+- Bug: Default settings are not loaded in the project (#25)
+
+[v0.0.2] - 2023-02-04
 ------------------
 
-- Add apikey model (#9)
-- Add Django admin to manage API keys (#11)
-- Add authentication backend (#12)
-- Add default permissions classes (#13)
-- Add creation date field on ApiKey (#14)
-- Add package for linting, coverage and syntax checker (#18)
-- Add a script to generate a Fernet key (#21)
\ No newline at end of file
+- Fix typo on admin `expiry_date` <- `expires_at` (#4)
+
+[v0.0.1] - 2023-02-04
+------------------
\ No newline at end of file
diff --git a/example/ApiKey/__init__.py b/example/ApiKey/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/example/ApiKey/asgi.py b/example/ApiKey/asgi.py
new file mode 100644
index 0000000..133d8f4
--- /dev/null
+++ b/example/ApiKey/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for ApiKey project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ApiKey.settings")
+
+application = get_asgi_application()
diff --git a/example/ApiKey/settings.py b/example/ApiKey/settings.py
new file mode 100644
index 0000000..fd9de28
--- /dev/null
+++ b/example/ApiKey/settings.py
@@ -0,0 +1,129 @@
+"""
+Django settings for ApiKey project.
+
+Generated by 'django-admin startproject' using Django 4.1.6.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.1/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/4.1/ref/settings/
+"""
+
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = "foo"
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+    "django.contrib.admin",
+    "django.contrib.auth",
+    "django.contrib.contenttypes",
+    "django.contrib.sessions",
+    "django.contrib.messages",
+    "django.contrib.staticfiles",
+    "rest_framework",
+    "rest_framework_simple_api_key",
+    "fruits",
+]
+
+MIDDLEWARE = [
+    "django.middleware.security.SecurityMiddleware",
+    "django.contrib.sessions.middleware.SessionMiddleware",
+    "django.middleware.common.CommonMiddleware",
+    "django.middleware.csrf.CsrfViewMiddleware",
+    "django.contrib.auth.middleware.AuthenticationMiddleware",
+    "django.contrib.messages.middleware.MessageMiddleware",
+    "django.middleware.clickjacking.XFrameOptionsMiddleware",
+]
+
+ROOT_URLCONF = "ApiKey.urls"
+
+TEMPLATES = [
+    {
+        "BACKEND": "django.template.backends.django.DjangoTemplates",
+        "DIRS": [],
+        "APP_DIRS": True,
+        "OPTIONS": {
+            "context_processors": [
+                "django.template.context_processors.debug",
+                "django.template.context_processors.request",
+                "django.contrib.auth.context_processors.auth",
+                "django.contrib.messages.context_processors.messages",
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = "ApiKey.wsgi.application"
+
+
+# Database
+# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
+
+DATABASES = {
+    "default": {
+        "ENGINE": "django.db.backends.sqlite3",
+        "NAME": BASE_DIR / "db.sqlite3",
+    }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
+    },
+    {
+        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
+    },
+    {
+        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
+    },
+    {
+        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/4.1/topics/i18n/
+
+LANGUAGE_CODE = "en-us"
+
+TIME_ZONE = "UTC"
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/4.1/howto/static-files/
+
+STATIC_URL = "static/"
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
+
+
+SIMPLE_API_KEY = {"FERNET_SECRET": "foo"}
diff --git a/example/ApiKey/urls.py b/example/ApiKey/urls.py
new file mode 100644
index 0000000..dd0ed93
--- /dev/null
+++ b/example/ApiKey/urls.py
@@ -0,0 +1,22 @@
+"""ApiKey URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/4.1/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path, include
+
+urlpatterns = [
+    path("admin/", admin.site.urls),
+    path("api/", include(("routers", "fruits"), namespace="fruits-api")),
+]
diff --git a/example/ApiKey/wsgi.py b/example/ApiKey/wsgi.py
new file mode 100644
index 0000000..7a49a06
--- /dev/null
+++ b/example/ApiKey/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for ApiKey project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ApiKey.settings")
+
+application = get_wsgi_application()
diff --git a/example/fruits/__init__.py b/example/fruits/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/example/fruits/admin.py b/example/fruits/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/example/fruits/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/example/fruits/apps.py b/example/fruits/apps.py
new file mode 100644
index 0000000..3ebcc0c
--- /dev/null
+++ b/example/fruits/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class FruitsConfig(AppConfig):
+    default_auto_field = "django.db.models.BigAutoField"
+    name = "fruits"
diff --git a/example/fruits/migrations/__init__.py b/example/fruits/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/example/fruits/models.py b/example/fruits/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/example/fruits/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/example/fruits/viewsets.py b/example/fruits/viewsets.py
new file mode 100644
index 0000000..61a9316
--- /dev/null
+++ b/example/fruits/viewsets.py
@@ -0,0 +1,16 @@
+from django.shortcuts import render
+
+from rest_framework import viewsets
+
+from rest_framework_simple_api_key.backends import APIKeyAuthentication
+from rest_framework_simple_api_key.permissions import IsActiveEntity
+from rest_framework.response import Response
+
+
+class FruitViewSets(viewsets.ViewSet):
+    http_method_names = ["get"]
+    authentication_classes = (APIKeyAuthentication,)
+    permission_classes = (IsActiveEntity,)
+
+    def list(self, request):
+        return Response([{"detail": True}], 200)
diff --git a/example/manage.py b/example/manage.py
new file mode 100755
index 0000000..46b6e96
--- /dev/null
+++ b/example/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+    """Run administrative tasks."""
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ApiKey.settings")
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/example/requirements.txt b/example/requirements.txt
new file mode 100644
index 0000000..83cbe3d
--- /dev/null
+++ b/example/requirements.txt
@@ -0,0 +1,3 @@
+Django==4.1.6
+djangorestframework==3.14.0
+djangorestframework-simple-apikey==0.1.2
diff --git a/example/routers.py b/example/routers.py
new file mode 100644
index 0000000..e9495b4
--- /dev/null
+++ b/example/routers.py
@@ -0,0 +1,15 @@
+from rest_framework import routers
+from fruits.viewsets import FruitViewSets
+
+router = routers.SimpleRouter()
+
+# ##################################################################### #
+# ################### Fruits                    ###################### #
+# ##################################################################### #
+
+router.register(r"fruits", FruitViewSets, basename="fruits")
+
+
+urlpatterns = [
+    *router.urls,
+]
diff --git a/setup.cfg b/setup.cfg
index 60cdf34..9cd475d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -71,3 +71,4 @@ exclude =
 	docs*
 	tests*
 	.github*
+	example*


Test patch:
diff --git a/example/fruits/tests.py b/example/fruits/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/example/fruits/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.