prune_captcha 1.12.1__tar.gz → 1.13.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/PKG-INFO +14 -10
  2. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/README.md +13 -9
  3. prune_captcha-1.13.0/captcha_prune/utils.py +52 -0
  4. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/prune_captcha.egg-info/PKG-INFO +14 -10
  5. prune_captcha-1.13.0/prune_captcha.egg-info/SOURCES.txt +10 -0
  6. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/prune_captcha.egg-info/top_level.txt +0 -2
  7. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/pyproject.toml +1 -1
  8. prune_captcha-1.12.1/captcha_prune/asgi.py +0 -16
  9. prune_captcha-1.12.1/captcha_prune/migrations/0001_initial.py +0 -29
  10. prune_captcha-1.12.1/captcha_prune/migrations/0002_remove_captcha_created_at_remove_captcha_pos_x_and_more.py +0 -73
  11. prune_captcha-1.12.1/captcha_prune/migrations/0003_captcha_created_at_captcha_updated_at.py +0 -25
  12. prune_captcha-1.12.1/captcha_prune/migrations/__init__.py +0 -0
  13. prune_captcha-1.12.1/captcha_prune/models.py +0 -34
  14. prune_captcha-1.12.1/captcha_prune/payloads.py +0 -6
  15. prune_captcha-1.12.1/captcha_prune/settings.py +0 -130
  16. prune_captcha-1.12.1/captcha_prune/utils.py +0 -44
  17. prune_captcha-1.12.1/captcha_prune/wsgi.py +0 -16
  18. prune_captcha-1.12.1/commons/base_model.py +0 -9
  19. prune_captcha-1.12.1/prune_captcha.egg-info/SOURCES.txt +0 -23
  20. prune_captcha-1.12.1/tests/__init__.py +0 -0
  21. prune_captcha-1.12.1/tests/captcha_prune/__init__.py +0 -0
  22. prune_captcha-1.12.1/tests/captcha_prune/test_views.py +0 -67
  23. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/captcha_prune/__init__.py +0 -0
  24. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/captcha_prune/apps.py +0 -0
  25. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/prune_captcha.egg-info/dependency_links.txt +0 -0
  26. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/prune_captcha.egg-info/requires.txt +0 -0
  27. {prune_captcha-1.12.1 → prune_captcha-1.13.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prune_captcha
3
- Version: 1.12.1
3
+ Version: 1.13.0
4
4
  Summary: A tool to protect formulaire from spam.
5
5
  Author-email: Arnout <bastien@prune.sh>
6
6
  Project-URL: Made_by, https://prune.sh/
@@ -64,6 +64,8 @@ In `settings.py`, set the path to the images used for the puzzle:
64
64
  PUZZLE_IMAGE_STATIC_PATH = "website/static/website/images/puzzles/"
65
65
  ```
66
66
 
67
+ Important: You must import the static files (css, js) present in "captcha_prune/static/".
68
+
67
69
  ### Utilisation
68
70
 
69
71
  - GET request (form display)
@@ -96,24 +98,26 @@ PUZZLE_IMAGE_STATIC_PATH = "website/static/website/images/puzzles/"
96
98
 
97
99
  - POST request (form submission)
98
100
 
99
- - Use verify_captcha to validate the captcha:
101
+ - Use verify_captcha to validate the captcha:
100
102
 
101
- ```python
102
- from captcha_prune.utils import verify_captcha
103
- ```
103
+ ```python
104
+ from captcha_prune.utils import verify_captcha
105
+ ```
104
106
 
105
- ```python
106
- response = verify_captcha(request)
107
- ```
107
+ ```python
108
+ response = verify_captcha(request)
109
+ ```
108
110
 
109
- - True if the captcha is correct, else False.
111
+ - True if the captcha is correct, else False.
110
112
 
111
- - Redirects in case of incorrect captcha.
113
+ - Redirects in case of incorrect captcha.
112
114
 
113
115
  # Available Versions
114
116
 
115
117
  | Version | Date | Notes |
116
118
  | ------- | ---------- | ---------------------------------- |
119
+ | 1.13.0 | 2025-05-21 | use session, add static |
120
+ | 1.12.2 | 2025-05-21 | doc fixed |
117
121
  | 1.12.1 | 2025-05-21 | doc fixed |
118
122
  | 1.12.0 | 2025-05-21 | removed views, added utils, ... |
119
123
  | 1.11.0 | 2025-05-21 | removed utils |
@@ -46,6 +46,8 @@ In `settings.py`, set the path to the images used for the puzzle:
46
46
  PUZZLE_IMAGE_STATIC_PATH = "website/static/website/images/puzzles/"
47
47
  ```
48
48
 
49
+ Important: You must import the static files (css, js) present in "captcha_prune/static/".
50
+
49
51
  ### Utilisation
50
52
 
51
53
  - GET request (form display)
@@ -78,24 +80,26 @@ PUZZLE_IMAGE_STATIC_PATH = "website/static/website/images/puzzles/"
78
80
 
79
81
  - POST request (form submission)
80
82
 
81
- - Use verify_captcha to validate the captcha:
83
+ - Use verify_captcha to validate the captcha:
82
84
 
83
- ```python
84
- from captcha_prune.utils import verify_captcha
85
- ```
85
+ ```python
86
+ from captcha_prune.utils import verify_captcha
87
+ ```
86
88
 
87
- ```python
88
- response = verify_captcha(request)
89
- ```
89
+ ```python
90
+ response = verify_captcha(request)
91
+ ```
90
92
 
91
- - True if the captcha is correct, else False.
93
+ - True if the captcha is correct, else False.
92
94
 
93
- - Redirects in case of incorrect captcha.
95
+ - Redirects in case of incorrect captcha.
94
96
 
95
97
  # Available Versions
96
98
 
97
99
  | Version | Date | Notes |
98
100
  | ------- | ---------- | ---------------------------------- |
101
+ | 1.13.0 | 2025-05-21 | use session, add static |
102
+ | 1.12.2 | 2025-05-21 | doc fixed |
99
103
  | 1.12.1 | 2025-05-21 | doc fixed |
100
104
  | 1.12.0 | 2025-05-21 | removed views, added utils, ... |
101
105
  | 1.11.0 | 2025-05-21 | removed utils |
@@ -0,0 +1,52 @@
1
+ import os
2
+ import random
3
+
4
+ from django.conf import settings
5
+ from django.http import HttpRequest
6
+
7
+
8
+ def create_and_get_captcha(
9
+ request, *, width=350, height=200, piece_width=80, piece_height=50, precision=2
10
+ ) -> dict:
11
+ pos_x_solution = random.randint(0, width - piece_width)
12
+ pos_y_solution = random.randint(0, height - piece_height)
13
+ piece_pos_x = random.randint(0, width - piece_width)
14
+ piece_pos_y = random.randint(0, height - piece_height)
15
+ _, _, puzzle_images_path = settings.PUZZLE_IMAGE_STATIC_PATH.rpartition("static/")
16
+ puzzle_images = [
17
+ f
18
+ for f in os.listdir(settings.PUZZLE_IMAGE_STATIC_PATH)
19
+ if f.lower().endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
20
+ ]
21
+ selected_image = random.choice(puzzle_images)
22
+ request.session["pos_x_solution"] = pos_x_solution
23
+ request.session["pos_y_solution"] = pos_y_solution
24
+ request.session["precision"] = precision
25
+ return {
26
+ "width": width,
27
+ "height": height,
28
+ "piece_width": piece_width,
29
+ "piece_height": piece_height,
30
+ "pos_x_solution": pos_x_solution,
31
+ "pos_y_solution": pos_y_solution,
32
+ "piece_pos_x": piece_pos_x,
33
+ "piece_pos_y": piece_pos_y,
34
+ "image": f"{puzzle_images_path}{selected_image}",
35
+ }
36
+
37
+
38
+ def verify_captcha(request: HttpRequest) -> bool:
39
+ pos_x_answer = request.POST.get("pos_x_answer")
40
+ pos_y_answer = request.POST.get("pos_Y_answer")
41
+ if pos_x_answer is None or pos_y_answer is None:
42
+ return False
43
+ pos_x_solution = request.session.get("pos_x_solution")
44
+ pos_y_solution = request.session.get("pos_y_solution")
45
+ precision = request.session.get("precision")
46
+ if (
47
+ abs(pos_x_solution - pos_x_answer) <= precision
48
+ and abs(pos_y_solution - pos_y_answer) <= precision
49
+ ):
50
+ return True
51
+ else:
52
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prune_captcha
3
- Version: 1.12.1
3
+ Version: 1.13.0
4
4
  Summary: A tool to protect formulaire from spam.
5
5
  Author-email: Arnout <bastien@prune.sh>
6
6
  Project-URL: Made_by, https://prune.sh/
@@ -64,6 +64,8 @@ In `settings.py`, set the path to the images used for the puzzle:
64
64
  PUZZLE_IMAGE_STATIC_PATH = "website/static/website/images/puzzles/"
65
65
  ```
66
66
 
67
+ Important: You must import the static files (css, js) present in "captcha_prune/static/".
68
+
67
69
  ### Utilisation
68
70
 
69
71
  - GET request (form display)
@@ -96,24 +98,26 @@ PUZZLE_IMAGE_STATIC_PATH = "website/static/website/images/puzzles/"
96
98
 
97
99
  - POST request (form submission)
98
100
 
99
- - Use verify_captcha to validate the captcha:
101
+ - Use verify_captcha to validate the captcha:
100
102
 
101
- ```python
102
- from captcha_prune.utils import verify_captcha
103
- ```
103
+ ```python
104
+ from captcha_prune.utils import verify_captcha
105
+ ```
104
106
 
105
- ```python
106
- response = verify_captcha(request)
107
- ```
107
+ ```python
108
+ response = verify_captcha(request)
109
+ ```
108
110
 
109
- - True if the captcha is correct, else False.
111
+ - True if the captcha is correct, else False.
110
112
 
111
- - Redirects in case of incorrect captcha.
113
+ - Redirects in case of incorrect captcha.
112
114
 
113
115
  # Available Versions
114
116
 
115
117
  | Version | Date | Notes |
116
118
  | ------- | ---------- | ---------------------------------- |
119
+ | 1.13.0 | 2025-05-21 | use session, add static |
120
+ | 1.12.2 | 2025-05-21 | doc fixed |
117
121
  | 1.12.1 | 2025-05-21 | doc fixed |
118
122
  | 1.12.0 | 2025-05-21 | removed views, added utils, ... |
119
123
  | 1.11.0 | 2025-05-21 | removed utils |
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ captcha_prune/__init__.py
4
+ captcha_prune/apps.py
5
+ captcha_prune/utils.py
6
+ prune_captcha.egg-info/PKG-INFO
7
+ prune_captcha.egg-info/SOURCES.txt
8
+ prune_captcha.egg-info/dependency_links.txt
9
+ prune_captcha.egg-info/requires.txt
10
+ prune_captcha.egg-info/top_level.txt
@@ -1,4 +1,2 @@
1
1
  captcha_prune
2
- commons
3
2
  dist
4
- tests
@@ -20,7 +20,7 @@ classifiers = [
20
20
  keywords = ["captcha", "django", "code-quality"]
21
21
  urls = {Made_by = "https://prune.sh/"}
22
22
  name = "prune_captcha"
23
- version = "1.12.1"
23
+ version = "1.13.0"
24
24
  description = "A tool to protect formulaire from spam."
25
25
  readme = "README.md"
26
26
  dependencies = [
@@ -1,16 +0,0 @@
1
- """
2
- ASGI config for captcha_prune project.
3
-
4
- It exposes the ASGI callable as a module-level variable named ``application``.
5
-
6
- For more information on this file, see
7
- https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
8
- """
9
-
10
- import os
11
-
12
- from django.core.asgi import get_asgi_application
13
-
14
- os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'captcha_prune.settings')
15
-
16
- application = get_asgi_application()
@@ -1,29 +0,0 @@
1
- # Generated by Django 5.2 on 2025-04-28 10:19
2
-
3
- import uuid
4
- from django.db import migrations, models
5
-
6
-
7
- class Migration(migrations.Migration):
8
-
9
- initial = True
10
-
11
- dependencies = [
12
- ]
13
-
14
- operations = [
15
- migrations.CreateModel(
16
- name='Captcha',
17
- fields=[
18
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19
- ('created_at', models.DateTimeField(auto_now_add=True)),
20
- ('updated_at', models.DateTimeField(auto_now=True)),
21
- ('uuid', models.UUIDField(default=uuid.uuid4, unique=True)),
22
- ('pos_x', models.IntegerField()),
23
- ('pos_y', models.IntegerField()),
24
- ],
25
- options={
26
- 'abstract': False,
27
- },
28
- ),
29
- ]
@@ -1,73 +0,0 @@
1
- # Generated by Django 5.2 on 2025-04-29 07:55
2
-
3
- from django.db import migrations, models
4
-
5
-
6
- class Migration(migrations.Migration):
7
- dependencies = [
8
- ("captcha_prune", "0001_initial"),
9
- ]
10
-
11
- operations = [
12
- migrations.RemoveField(
13
- model_name="captcha",
14
- name="created_at",
15
- ),
16
- migrations.RemoveField(
17
- model_name="captcha",
18
- name="pos_x",
19
- ),
20
- migrations.RemoveField(
21
- model_name="captcha",
22
- name="pos_y",
23
- ),
24
- migrations.RemoveField(
25
- model_name="captcha",
26
- name="updated_at",
27
- ),
28
- migrations.AddField(
29
- model_name="captcha",
30
- name="height",
31
- field=models.IntegerField(default=200),
32
- ),
33
- migrations.AddField(
34
- model_name="captcha",
35
- name="piece_height",
36
- field=models.IntegerField(default=50),
37
- ),
38
- migrations.AddField(
39
- model_name="captcha",
40
- name="piece_pos_x",
41
- field=models.IntegerField(blank=True, null=True),
42
- ),
43
- migrations.AddField(
44
- model_name="captcha",
45
- name="piece_pos_y",
46
- field=models.IntegerField(blank=True, null=True),
47
- ),
48
- migrations.AddField(
49
- model_name="captcha",
50
- name="piece_width",
51
- field=models.IntegerField(default=80),
52
- ),
53
- migrations.AddField(
54
- model_name="captcha",
55
- name="pos_x_solution",
56
- field=models.IntegerField(blank=True, null=True),
57
- ),
58
- migrations.AddField(
59
- model_name="captcha",
60
- name="pos_y_solution",
61
- field=models.IntegerField(blank=True, null=True),
62
- ),
63
- migrations.AddField(
64
- model_name="captcha",
65
- name="precision",
66
- field=models.IntegerField(default=2),
67
- ),
68
- migrations.AddField(
69
- model_name="captcha",
70
- name="width",
71
- field=models.IntegerField(default=350),
72
- ),
73
- ]
@@ -1,25 +0,0 @@
1
- # Generated by Django 5.2 on 2025-05-20 09:12
2
-
3
- import django.utils.timezone
4
- from django.db import migrations, models
5
-
6
-
7
- class Migration(migrations.Migration):
8
-
9
- dependencies = [
10
- ('captcha_prune', '0002_remove_captcha_created_at_remove_captcha_pos_x_and_more'),
11
- ]
12
-
13
- operations = [
14
- migrations.AddField(
15
- model_name='captcha',
16
- name='created_at',
17
- field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
18
- preserve_default=False,
19
- ),
20
- migrations.AddField(
21
- model_name='captcha',
22
- name='updated_at',
23
- field=models.DateTimeField(auto_now=True),
24
- ),
25
- ]
File without changes
@@ -1,34 +0,0 @@
1
- import random
2
- import uuid
3
-
4
- from django.db import models
5
-
6
- from commons.base_model import BaseModel
7
-
8
-
9
- class Captcha(BaseModel):
10
- uuid = models.UUIDField(default=uuid.uuid4, unique=True)
11
- width = models.IntegerField(default=350)
12
- height = models.IntegerField(default=200)
13
- pos_x_solution = models.IntegerField(null=True, blank=True)
14
- pos_y_solution = models.IntegerField(null=True, blank=True)
15
- piece_pos_x = models.IntegerField(null=True, blank=True)
16
- piece_pos_y = models.IntegerField(null=True, blank=True)
17
- piece_width = models.IntegerField(default=80)
18
- piece_height = models.IntegerField(default=50)
19
- precision = models.IntegerField(default=2)
20
-
21
- def save(self, *args, **kwargs):
22
- if self.pos_x_solution is None:
23
- self.pos_x_solution = random.randint(0, self.width - self.piece_width)
24
-
25
- if self.pos_y_solution is None:
26
- self.pos_y_solution = random.randint(0, self.height - self.piece_height)
27
-
28
- if self.piece_pos_x is None:
29
- self.piece_pos_x = random.randint(0, self.width - self.piece_width)
30
-
31
- if self.piece_pos_y is None:
32
- self.piece_pos_y = random.randint(0, self.height - self.piece_height)
33
-
34
- super().save(*args, **kwargs)
@@ -1,6 +0,0 @@
1
- from pydantic import BaseModel
2
-
3
-
4
- class PuzzleAnswerPayload(BaseModel):
5
- pos_x_answer: int
6
- pos_y_answer: int
@@ -1,130 +0,0 @@
1
- from pathlib import Path
2
-
3
- from pydantic_settings import BaseSettings, SettingsConfigDict
4
-
5
-
6
- class EnvSettings(BaseSettings):
7
- model_config = SettingsConfigDict(env_file=".env", extra="allow")
8
-
9
- postgres_db: str
10
- postgres_user: str
11
- postgres_password: str
12
- postgres_host: str
13
- postgres_port: str
14
-
15
-
16
- env_settings = EnvSettings()
17
-
18
- # Build paths inside the project like this: BASE_DIR / 'subdir'.
19
- BASE_DIR = Path(__file__).resolve().parent.parent
20
-
21
-
22
- # Quick-start development settings - unsuitable for production
23
- # See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
24
-
25
- # SECURITY WARNING: keep the secret key used in production secret!
26
- SECRET_KEY = "django-insecure-dj-w%-kno*r5w=e_&l1sl3)9kl%m25(3ikoc=z_%p5-0d5472%"
27
-
28
- # SECURITY WARNING: don't run with debug turned on in production!
29
- DEBUG = True
30
-
31
- ALLOWED_HOSTS = []
32
-
33
-
34
- # Application definition
35
-
36
- INSTALLED_APPS = [
37
- "django.contrib.admin",
38
- "django.contrib.auth",
39
- "django.contrib.contenttypes",
40
- "django.contrib.sessions",
41
- "django.contrib.messages",
42
- "django.contrib.staticfiles",
43
- "captcha_prune",
44
- ]
45
-
46
- MIDDLEWARE = [
47
- "django.middleware.security.SecurityMiddleware",
48
- "django.contrib.sessions.middleware.SessionMiddleware",
49
- "django.middleware.common.CommonMiddleware",
50
- "django.middleware.csrf.CsrfViewMiddleware",
51
- "django.contrib.auth.middleware.AuthenticationMiddleware",
52
- "django.contrib.messages.middleware.MessageMiddleware",
53
- "django.middleware.clickjacking.XFrameOptionsMiddleware",
54
- ]
55
-
56
- ROOT_URLCONF = "captcha_prune.urls"
57
-
58
- TEMPLATES = [
59
- {
60
- "BACKEND": "django.template.backends.django.DjangoTemplates",
61
- "DIRS": [],
62
- "APP_DIRS": True,
63
- "OPTIONS": {
64
- "context_processors": [
65
- "django.template.context_processors.request",
66
- "django.contrib.auth.context_processors.auth",
67
- "django.contrib.messages.context_processors.messages",
68
- ],
69
- },
70
- },
71
- ]
72
-
73
- WSGI_APPLICATION = "captcha_prune.wsgi.application"
74
-
75
-
76
- # Database
77
- # https://docs.djangoproject.com/en/5.2/ref/settings/#databases
78
-
79
- DATABASES = {
80
- "default": {
81
- "ENGINE": "django.db.backends.postgresql",
82
- "NAME": env_settings.postgres_db,
83
- "USER": env_settings.postgres_user,
84
- "PASSWORD": env_settings.postgres_password,
85
- "HOST": env_settings.postgres_host,
86
- "PORT": env_settings.postgres_port,
87
- }
88
- }
89
-
90
-
91
- # Password validation
92
- # https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
93
-
94
- AUTH_PASSWORD_VALIDATORS = [
95
- {
96
- "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
97
- },
98
- {
99
- "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
100
- },
101
- {
102
- "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
103
- },
104
- {
105
- "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
106
- },
107
- ]
108
-
109
-
110
- # Internationalization
111
- # https://docs.djangoproject.com/en/5.2/topics/i18n/
112
-
113
- LANGUAGE_CODE = "en-us"
114
-
115
- TIME_ZONE = "UTC"
116
-
117
- USE_I18N = True
118
-
119
- USE_TZ = True
120
-
121
-
122
- # Static files (CSS, JavaScript, Images)
123
- # https://docs.djangoproject.com/en/5.2/howto/static-files/
124
-
125
- STATIC_URL = "static/"
126
-
127
- # Default primary key field type
128
- # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
129
-
130
- DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
@@ -1,44 +0,0 @@
1
- import os
2
- import random
3
-
4
- from django.conf import settings
5
- from django.shortcuts import get_object_or_404
6
-
7
- from captcha_prune.models import Captcha
8
-
9
-
10
- def create_and_get_captcha() -> dict:
11
- captcha = Captcha.objects.create()
12
-
13
- _, _, puzzle_images_path = settings.PUZZLE_IMAGE_STATIC_PATH.rpartition("static/")
14
- puzzle_images = [
15
- f
16
- for f in os.listdir(settings.PUZZLE_IMAGE_STATIC_PATH)
17
- if f.lower().endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
18
- ]
19
- selected_image = random.choice(puzzle_images)
20
-
21
- return {
22
- "uuid": captcha.uuid,
23
- "width": captcha.width,
24
- "height": captcha.height,
25
- "piece_width": captcha.piece_width,
26
- "piece_height": captcha.piece_height,
27
- "pos_x_solution": captcha.pos_x_solution,
28
- "pos_y_solution": captcha.pos_y_solution,
29
- "piece_pos_x": captcha.piece_pos_x,
30
- "piece_pos_y": captcha.piece_pos_y,
31
- "image": f"{puzzle_images_path}{selected_image}",
32
- }
33
-
34
-
35
- def verify_captcha(puzzle_uuid: str, pos_x_answer: int, pos_y_answer: int) -> bool:
36
- captcha = get_object_or_404(Captcha, uuid=puzzle_uuid)
37
-
38
- if (
39
- abs(captcha.pos_x_solution - pos_x_answer) <= captcha.precision
40
- and abs(captcha.pos_y_solution - pos_y_answer) <= captcha.precision
41
- ):
42
- return True
43
- else:
44
- return False
@@ -1,16 +0,0 @@
1
- """
2
- WSGI config for captcha_prune project.
3
-
4
- It exposes the WSGI callable as a module-level variable named ``application``.
5
-
6
- For more information on this file, see
7
- https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
8
- """
9
-
10
- import os
11
-
12
- from django.core.wsgi import get_wsgi_application
13
-
14
- os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'captcha_prune.settings')
15
-
16
- application = get_wsgi_application()
@@ -1,9 +0,0 @@
1
- from django.db import models
2
-
3
-
4
- class BaseModel(models.Model):
5
- created_at = models.DateTimeField(auto_now_add=True)
6
- updated_at = models.DateTimeField(auto_now=True)
7
-
8
- class Meta:
9
- abstract = True
@@ -1,23 +0,0 @@
1
- README.md
2
- pyproject.toml
3
- captcha_prune/__init__.py
4
- captcha_prune/apps.py
5
- captcha_prune/asgi.py
6
- captcha_prune/models.py
7
- captcha_prune/payloads.py
8
- captcha_prune/settings.py
9
- captcha_prune/utils.py
10
- captcha_prune/wsgi.py
11
- captcha_prune/migrations/0001_initial.py
12
- captcha_prune/migrations/0002_remove_captcha_created_at_remove_captcha_pos_x_and_more.py
13
- captcha_prune/migrations/0003_captcha_created_at_captcha_updated_at.py
14
- captcha_prune/migrations/__init__.py
15
- commons/base_model.py
16
- prune_captcha.egg-info/PKG-INFO
17
- prune_captcha.egg-info/SOURCES.txt
18
- prune_captcha.egg-info/dependency_links.txt
19
- prune_captcha.egg-info/requires.txt
20
- prune_captcha.egg-info/top_level.txt
21
- tests/__init__.py
22
- tests/captcha_prune/__init__.py
23
- tests/captcha_prune/test_views.py
File without changes
File without changes
@@ -1,67 +0,0 @@
1
- import uuid
2
-
3
- from django.test import TestCase
4
- from django.urls import reverse
5
-
6
- from captcha_prune.models import Captcha
7
-
8
-
9
- class CreateCaptchaViewTestCase(TestCase):
10
- def test_create_captcha_with_GET_method(self):
11
- response = self.client.get(reverse("create-captcha"))
12
- self.assertEqual(response.status_code, 405)
13
-
14
- def test_create_captcha_with_POST_method(self):
15
- response = self.client.post(reverse("create-captcha"))
16
- self.assertEqual(response.status_code, 201)
17
-
18
- data = response.json()
19
- captcha = Captcha.objects.get(uuid=data["uuid"])
20
- self.assertIsNotNone(captcha)
21
-
22
-
23
- class VerifyCaptchaViewTestCase(TestCase):
24
- def setUp(self):
25
- self.captcha = Captcha.objects.create()
26
- self.pos_x_solution = self.captcha.pos_x_solution
27
- self.pos_y_solution = self.captcha.pos_y_solution
28
-
29
- def test_verify_captcha_with_POST_method(self):
30
- response = self.client.post(
31
- reverse("verify-captcha", kwargs={"uuid": str(uuid.uuid4())}),
32
- data={
33
- "pos_x_answer": self.pos_x_solution,
34
- "pos_y_answer": self.pos_y_solution,
35
- },
36
- )
37
- self.assertEqual(response.status_code, 405)
38
-
39
- def test_verify_captcha_with_bad_uuid(self):
40
- response = self.client.get(
41
- reverse("verify-captcha", kwargs={"uuid": str(uuid.uuid4())}),
42
- data={
43
- "pos_x_answer": self.pos_x_solution,
44
- "pos_y_answer": self.pos_y_solution,
45
- },
46
- )
47
- self.assertEqual(response.status_code, 404)
48
-
49
- def test_verify_captcha_with_good_uuid_but_bad_answer(self):
50
- response = self.client.get(
51
- reverse("verify-captcha", kwargs={"uuid": str(self.captcha.uuid)}),
52
- data={
53
- "pos_x_answer": self.pos_x_solution - 20,
54
- "pos_y_answer": self.pos_y_solution - 20,
55
- },
56
- )
57
- self.assertEqual(response.status_code, 401)
58
-
59
- def test_verify_captcha_with_good_uuid_and_good_answer(self):
60
- response = self.client.get(
61
- reverse("verify-captcha", kwargs={"uuid": str(self.captcha.uuid)}),
62
- data={
63
- "pos_x_answer": self.pos_x_solution,
64
- "pos_y_answer": self.pos_y_solution,
65
- },
66
- )
67
- self.assertEqual(response.status_code, 304)
File without changes