mirror of
				https://github.com/Alexander-D-Karpov/akarpov
				synced 2025-10-31 12:17:26 +03:00 
			
		
		
		
	added promocodes, senetry
This commit is contained in:
		
							parent
							
								
									a9937fc88a
								
							
						
					
					
						commit
						1aa39d1d20
					
				|  | @ -5,3 +5,4 @@ REDIS_CACHE=rediscache://localhost:6379/1 | ||||||
| USE_DOCKER=no | USE_DOCKER=no | ||||||
| EMAIL_HOST=127.0.0.1 | EMAIL_HOST=127.0.0.1 | ||||||
| EMAIL_PORT=1025 | EMAIL_PORT=1025 | ||||||
|  | SENTRY_DSN= | ||||||
|  |  | ||||||
|  | @ -4,6 +4,15 @@ My collection of apps and tools | ||||||
| 
 | 
 | ||||||
| Writen in Python 3.11 and Django 4.2 | Writen in Python 3.11 and Django 4.2 | ||||||
| 
 | 
 | ||||||
|  | ### local run via docker | ||||||
|  | 
 | ||||||
|  | ```shell | ||||||
|  | $ python3 manage.py migrate | ||||||
|  | $ python3 manage.py runserver | ||||||
|  | $ celery -A config.celery_app worker --loglevel=info | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ### local run via docker | ### local run via docker | ||||||
| 
 | 
 | ||||||
| ```shell | ```shell | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
|     TopFolderView, |     TopFolderView, | ||||||
|     delete_file_view, |     delete_file_view, | ||||||
|     delete_folder_view, |     delete_folder_view, | ||||||
|  |     file_download_view, | ||||||
|     file_report_list, |     file_report_list, | ||||||
|     file_table, |     file_table, | ||||||
|     file_update, |     file_update, | ||||||
|  | @ -34,6 +35,7 @@ | ||||||
|     path("api/chunked_upload/", ChunkedUploadView.as_view(), name="api_chunked_upload"), |     path("api/chunked_upload/", ChunkedUploadView.as_view(), name="api_chunked_upload"), | ||||||
|     path("api/folder/create/", folder_create, name="folder_create"), |     path("api/folder/create/", folder_create, name="folder_create"), | ||||||
|     path("api/file/report/<str:slug>", report_file, name="file_report"), |     path("api/file/report/<str:slug>", report_file, name="file_report"), | ||||||
|  |     path("api/file/download/<str:slug>", file_download_view, name="file_download"), | ||||||
|     path("api/file/delete/<str:slug>", delete_file_view, name="delete"), |     path("api/file/delete/<str:slug>", delete_file_view, name="delete"), | ||||||
|     path("api/folder/create/<str:slug>", folder_create, name="sub_folder_create"), |     path("api/folder/create/<str:slug>", folder_create, name="sub_folder_create"), | ||||||
|     path("api/folder/delete/<str:slug>", delete_folder_view, name="folder_delete"), |     path("api/folder/delete/<str:slug>", delete_folder_view, name="folder_delete"), | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| from django.http import HttpResponseRedirect | from django.http import HttpResponseRedirect | ||||||
| from django.shortcuts import get_object_or_404 | from django.shortcuts import get_object_or_404 | ||||||
| from django.urls import reverse | from django.urls import reverse | ||||||
|  | from django.views import View | ||||||
| from django.views.generic import ( | from django.views.generic import ( | ||||||
|     CreateView, |     CreateView, | ||||||
|     DetailView, |     DetailView, | ||||||
|  | @ -342,3 +343,14 @@ def get_redirect_url(self, *args, **kwargs): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| delete_folder_view = DeleteFolderView.as_view() | delete_folder_view = DeleteFolderView.as_view() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class FileDownloadView(View): | ||||||
|  |     def get(self, request, slug): | ||||||
|  |         file = get_object_or_404(File, slug=slug) | ||||||
|  |         file.downloads += 1 | ||||||
|  |         file.save(update_fields=["downloads"]) | ||||||
|  |         return HttpResponseRedirect(file.file.url) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | file_download_view = FileDownloadView.as_view() | ||||||
|  |  | ||||||
|  | @ -84,6 +84,7 @@ | ||||||
|                         <ul class="dropdown-menu dropdown-menu-dark text-small shadow" aria-labelledby="dropdownUser1"> |                         <ul class="dropdown-menu dropdown-menu-dark text-small shadow" aria-labelledby="dropdownUser1"> | ||||||
|                             <li><a class="dropdown-item {% active_link 'users:update' %}" href="{% url 'users:update'  %}">Settings</a></li> |                             <li><a class="dropdown-item {% active_link 'users:update' %}" href="{% url 'users:update'  %}">Settings</a></li> | ||||||
|                             <li><a class="dropdown-item {% active_link 'users:detail' request.user.username %}" href="{% url 'users:detail' request.user.username  %}">Profile</a></li> |                             <li><a class="dropdown-item {% active_link 'users:detail' request.user.username %}" href="{% url 'users:detail' request.user.username  %}">Profile</a></li> | ||||||
|  |                             <li><a class="dropdown-item {% active_link 'tools:qr:create' %}" href="{% url 'tools:promocodes:activate' %}">Activate promocode</a></li> | ||||||
|                             <li> |                             <li> | ||||||
|                                 <hr class="dropdown-divider"> |                                 <hr class="dropdown-divider"> | ||||||
|                             </li> |                             </li> | ||||||
|  |  | ||||||
|  | @ -58,7 +58,7 @@ | ||||||
|     {% endif %} |     {% endif %} | ||||||
|     <a class="text-danger mt-2" style="text-decoration: none" href="{% url 'files:file_report' slug=file.slug %}"><i class="bi bi-flag-fill"></i>report file</a> |     <a class="text-danger mt-2" style="text-decoration: none" href="{% url 'files:file_report' slug=file.slug %}"><i class="bi bi-flag-fill"></i>report file</a> | ||||||
|     <div class="mt-4 text-center justify-content-sm-evenly justify-content-md-start gap-3 align-items-md-start align-items-sm-center d-flex"> |     <div class="mt-4 text-center justify-content-sm-evenly justify-content-md-start gap-3 align-items-md-start align-items-sm-center d-flex"> | ||||||
|       <a class="btn btn-success fs-6" href="{{ file.file.url }}" download><i class="bi bi-download"></i> Download</a> |       <a class="btn btn-success fs-6" href="{% url 'files:file_download' slug=file.slug %}" download><i class="bi bi-download"></i> Download</a> | ||||||
|       {% if has_perm %} |       {% if has_perm %} | ||||||
|       <a class="btn btn-danger fs-6" href="{% url 'files:delete' slug=file.slug %}"><i class="bi bi-trash"></i> Delete</a> |       <a class="btn btn-danger fs-6" href="{% url 'files:delete' slug=file.slug %}"><i class="bi bi-trash"></i> Delete</a> | ||||||
|       {% endif %} |       {% endif %} | ||||||
|  |  | ||||||
							
								
								
									
										32
									
								
								akarpov/templates/tools/promocodes/activate.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								akarpov/templates/tools/promocodes/activate.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | {% extends "base.html" %} | ||||||
|  | {% load static %} | ||||||
|  | {% load crispy_forms_tags %} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |   {% if message %} | ||||||
|  |   {% if status %} | ||||||
|  |   <div class="alert alert-dismissible alert-success"> | ||||||
|  |     {{ message }} | ||||||
|  |     <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> | ||||||
|  |   </div> | ||||||
|  |   {% else %} | ||||||
|  |   <div class="alert alert-dismissible alert-error"> | ||||||
|  |     {{ message }} | ||||||
|  |     <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> | ||||||
|  |   </div> | ||||||
|  |   {% endif %} | ||||||
|  |   {% endif %} | ||||||
|  | <form class="pt-2" enctype="multipart/form-data" method="POST" id="designer-form"> | ||||||
|  |     {% csrf_token %} | ||||||
|  |     {{ form.media }} | ||||||
|  |     {% for field in form %} | ||||||
|  |         {{ field|as_crispy_field }} | ||||||
|  |     {% endfor %} | ||||||
|  |     <div class="mt-4 flex justify-end space-x-4"> | ||||||
|  |         <button class="btn btn-secondary" type="submit" id="submit"> | ||||||
|  |             Activate | ||||||
|  |         </button> | ||||||
|  |     </div> | ||||||
|  | </form> | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										0
									
								
								akarpov/tools/promocodes/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								akarpov/tools/promocodes/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										6
									
								
								akarpov/tools/promocodes/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								akarpov/tools/promocodes/admin.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | from django.contrib import admin | ||||||
|  | 
 | ||||||
|  | from akarpov.tools.promocodes.models import PromoCode, PromoCodeActivation | ||||||
|  | 
 | ||||||
|  | admin.site.register(PromoCode) | ||||||
|  | admin.site.register(PromoCodeActivation) | ||||||
							
								
								
									
										6
									
								
								akarpov/tools/promocodes/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								akarpov/tools/promocodes/apps.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | from django.apps import AppConfig | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class PromocodesConfig(AppConfig): | ||||||
|  |     default_auto_field = "django.db.models.BigAutoField" | ||||||
|  |     name = "akarpov.tools.promocodes" | ||||||
							
								
								
									
										5
									
								
								akarpov/tools/promocodes/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								akarpov/tools/promocodes/forms.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | from django import forms | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class PromoCodeForm(forms.Form): | ||||||
|  |     promocode = forms.CharField(max_length=250, required=True) | ||||||
							
								
								
									
										103
									
								
								akarpov/tools/promocodes/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								akarpov/tools/promocodes/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,103 @@ | ||||||
|  | # Generated by Django 4.2.1 on 2023-06-21 13:36 | ||||||
|  | 
 | ||||||
|  | from django.conf import settings | ||||||
|  | from django.db import migrations, models | ||||||
|  | import django.db.models.deletion | ||||||
|  | import django.utils.timezone | ||||||
|  | import model_utils.fields | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     initial = True | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name="PromoCode", | ||||||
|  |             fields=[ | ||||||
|  |                 ( | ||||||
|  |                     "id", | ||||||
|  |                     models.BigAutoField( | ||||||
|  |                         auto_created=True, | ||||||
|  |                         primary_key=True, | ||||||
|  |                         serialize=False, | ||||||
|  |                         verbose_name="ID", | ||||||
|  |                     ), | ||||||
|  |                 ), | ||||||
|  |                 ( | ||||||
|  |                     "created", | ||||||
|  |                     model_utils.fields.AutoCreatedField( | ||||||
|  |                         default=django.utils.timezone.now, | ||||||
|  |                         editable=False, | ||||||
|  |                         verbose_name="created", | ||||||
|  |                     ), | ||||||
|  |                 ), | ||||||
|  |                 ( | ||||||
|  |                     "modified", | ||||||
|  |                     model_utils.fields.AutoLastModifiedField( | ||||||
|  |                         default=django.utils.timezone.now, | ||||||
|  |                         editable=False, | ||||||
|  |                         verbose_name="modified", | ||||||
|  |                     ), | ||||||
|  |                 ), | ||||||
|  |                 ("promo", models.CharField(max_length=250, unique=True)), | ||||||
|  |                 ( | ||||||
|  |                     "type", | ||||||
|  |                     models.CharField( | ||||||
|  |                         choices=[ | ||||||
|  |                             ("single", "can be activated only one time, by one user"), | ||||||
|  |                             ( | ||||||
|  |                                 "multiuser", | ||||||
|  |                                 "can be activated many times, but only one time for one user", | ||||||
|  |                             ), | ||||||
|  |                             ("multiple", "can be activated multiple times"), | ||||||
|  |                         ] | ||||||
|  |                     ), | ||||||
|  |                 ), | ||||||
|  |                 ("name", models.CharField(max_length=250)), | ||||||
|  |                 ("app_name", models.CharField(max_length=250)), | ||||||
|  |                 ("model", models.CharField(max_length=250)), | ||||||
|  |                 ("field", models.CharField(max_length=250)), | ||||||
|  |                 ("value", models.IntegerField()), | ||||||
|  |                 ("message", models.CharField(max_length=250)), | ||||||
|  |             ], | ||||||
|  |             options={ | ||||||
|  |                 "abstract": False, | ||||||
|  |             }, | ||||||
|  |         ), | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name="PromoCodeActivation", | ||||||
|  |             fields=[ | ||||||
|  |                 ( | ||||||
|  |                     "id", | ||||||
|  |                     models.BigAutoField( | ||||||
|  |                         auto_created=True, | ||||||
|  |                         primary_key=True, | ||||||
|  |                         serialize=False, | ||||||
|  |                         verbose_name="ID", | ||||||
|  |                     ), | ||||||
|  |                 ), | ||||||
|  |                 ("activated", models.DateTimeField(auto_now_add=True)), | ||||||
|  |                 ( | ||||||
|  |                     "promocode", | ||||||
|  |                     models.ForeignKey( | ||||||
|  |                         on_delete=django.db.models.deletion.CASCADE, | ||||||
|  |                         related_name="activations", | ||||||
|  |                         to="promocodes.promocode", | ||||||
|  |                     ), | ||||||
|  |                 ), | ||||||
|  |                 ( | ||||||
|  |                     "user", | ||||||
|  |                     models.ForeignKey( | ||||||
|  |                         on_delete=django.db.models.deletion.CASCADE, | ||||||
|  |                         related_name="promocode_activations", | ||||||
|  |                         to=settings.AUTH_USER_MODEL, | ||||||
|  |                     ), | ||||||
|  |                 ), | ||||||
|  |             ], | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										0
									
								
								akarpov/tools/promocodes/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								akarpov/tools/promocodes/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										37
									
								
								akarpov/tools/promocodes/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								akarpov/tools/promocodes/models.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | ||||||
|  | from django.db import models | ||||||
|  | from model_utils.models import TimeStampedModel | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class PromoCode(TimeStampedModel): | ||||||
|  |     class PromoCodeType(models.TextChoices): | ||||||
|  |         single = "single", "can be activated only one time, by one user" | ||||||
|  |         multiuser = ( | ||||||
|  |             "multiuser", | ||||||
|  |             "can be activated many times, but only one time for one user", | ||||||
|  |         ) | ||||||
|  |         multiple = "multiple", "can be activated multiple times" | ||||||
|  | 
 | ||||||
|  |     promo = models.CharField(max_length=250, unique=True) | ||||||
|  |     type = models.CharField(choices=PromoCodeType.choices) | ||||||
|  |     name = models.CharField(max_length=250) | ||||||
|  |     app_name = models.CharField(max_length=250) | ||||||
|  |     model = models.CharField(max_length=250) | ||||||
|  |     field = models.CharField(max_length=250) | ||||||
|  |     value = models.IntegerField() | ||||||
|  |     message = models.CharField(max_length=250) | ||||||
|  | 
 | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.name | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class PromoCodeActivation(models.Model): | ||||||
|  |     activated = models.DateTimeField(auto_now_add=True) | ||||||
|  |     promocode = models.ForeignKey( | ||||||
|  |         "PromoCode", related_name="activations", on_delete=models.CASCADE | ||||||
|  |     ) | ||||||
|  |     user = models.ForeignKey( | ||||||
|  |         "users.User", related_name="promocode_activations", on_delete=models.CASCADE | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     def __str__(self): | ||||||
|  |         return f"{self.promocode} activation by {self.user}" | ||||||
							
								
								
									
										64
									
								
								akarpov/tools/promocodes/services.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								akarpov/tools/promocodes/services.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | ||||||
|  | import structlog | ||||||
|  | from django.apps import apps | ||||||
|  | 
 | ||||||
|  | from akarpov.tools.promocodes.models import PromoCode, PromoCodeActivation | ||||||
|  | from akarpov.users.models import User | ||||||
|  | 
 | ||||||
|  | logger = structlog.get_logger(__name__) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def activate_promocode(code: str, user: User) -> (str, bool): | ||||||
|  |     try: | ||||||
|  |         promo = PromoCode.objects.get(promo=code) | ||||||
|  |     except PromoCode.DoesNotExist: | ||||||
|  |         return "Promocode doesn't exist", False | ||||||
|  | 
 | ||||||
|  |     if promo.type == PromoCode.PromoCodeType.single: | ||||||
|  |         if PromoCodeActivation.objects.filter(promocode=promo).exists(): | ||||||
|  |             return "Promocode is already activated", False | ||||||
|  |     elif promo.type == PromoCode.PromoCodeType.multiuser: | ||||||
|  |         if PromoCodeActivation.objects.filter(promocode=promo, user=user).exists(): | ||||||
|  |             return "Promocode is already activated", False | ||||||
|  |     try: | ||||||
|  |         model = apps.get_model(app_label=promo.app_name, model_name=promo.model) | ||||||
|  |     except LookupError: | ||||||
|  |         logger.error( | ||||||
|  |             f"can't activate promocode {code} for {promo.model} {promo.app_name} {promo.field}" | ||||||
|  |         ) | ||||||
|  |         return "Somthing went wrong, we are already working on it", False | ||||||
|  | 
 | ||||||
|  |     if not hasattr(model, promo.field): | ||||||
|  |         logger.error( | ||||||
|  |             f"can't activate promocode {code} for {promo.model} {promo.app_name} {promo.field}" | ||||||
|  |         ) | ||||||
|  |         return "Somthing went wrong, we are already working on it", False | ||||||
|  |     if model is User: | ||||||
|  |         try: | ||||||
|  |             setattr(user, promo.field, getattr(user, promo.field) + promo.value) | ||||||
|  |             user.save() | ||||||
|  |             PromoCodeActivation.objects.create(promocode=promo, user=user) | ||||||
|  |             return promo.message, True | ||||||
|  |         except Exception as e: | ||||||
|  |             logger.error( | ||||||
|  |                 f"can't activate promocode {code} for {promo.model} {promo.app_name} {promo.field}, {e}" | ||||||
|  |             ) | ||||||
|  |             return "Somthing went wrong, we are already working on it", False | ||||||
|  |     else: | ||||||
|  |         try: | ||||||
|  |             usr_field = "" | ||||||
|  |             if hasattr(model, "user"): | ||||||
|  |                 usr_field = "user" | ||||||
|  |             elif hasattr(model, "creator"): | ||||||
|  |                 usr_field = "creator" | ||||||
|  |             elif hasattr(model, "owner"): | ||||||
|  |                 usr_field = "owner" | ||||||
|  |             obj = model.objects.filter({usr_field: user}).last() | ||||||
|  |             setattr(obj, promo.field, getattr(obj, promo.field) + promo.value) | ||||||
|  |             obj.save() | ||||||
|  |             PromoCodeActivation.objects.create(promocode=promo, user=user) | ||||||
|  |             return promo.message, True | ||||||
|  |         except Exception as e: | ||||||
|  |             logger.error( | ||||||
|  |                 f"can't activate promocode {code} for {promo.model} {promo.app_name} {promo.field}, {e}" | ||||||
|  |             ) | ||||||
|  |             return "Somthing went wrong, we are already working on it", False | ||||||
							
								
								
									
										9
									
								
								akarpov/tools/promocodes/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								akarpov/tools/promocodes/urls.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | from django.urls import path | ||||||
|  | 
 | ||||||
|  | from akarpov.tools.promocodes.views import activate_promo_code | ||||||
|  | 
 | ||||||
|  | app_name = "promocodes" | ||||||
|  | 
 | ||||||
|  | urlpatterns = [ | ||||||
|  |     path("", activate_promo_code, name="activate"), | ||||||
|  | ] | ||||||
							
								
								
									
										26
									
								
								akarpov/tools/promocodes/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								akarpov/tools/promocodes/views.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | from django.contrib.auth.mixins import LoginRequiredMixin | ||||||
|  | from django.views import generic | ||||||
|  | 
 | ||||||
|  | from akarpov.tools.promocodes.forms import PromoCodeForm | ||||||
|  | from akarpov.tools.promocodes.services import activate_promocode | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ActivatePromoCodeView(LoginRequiredMixin, generic.FormView): | ||||||
|  |     form_class = PromoCodeForm | ||||||
|  |     template_name = "tools/promocodes/activate.html" | ||||||
|  | 
 | ||||||
|  |     def get_context_data(self, **kwargs): | ||||||
|  |         context = super().get_context_data(**kwargs) | ||||||
|  |         context["message"] = "" | ||||||
|  |         context["status"] = False | ||||||
|  |         return context | ||||||
|  | 
 | ||||||
|  |     def form_valid(self, form): | ||||||
|  |         msg, status = activate_promocode(form.data["promocode"], self.request.user) | ||||||
|  |         context = self.get_context_data(form=form) | ||||||
|  |         context["message"] = msg | ||||||
|  |         context["status"] = status | ||||||
|  |         return self.render_to_response(context=context) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | activate_promo_code = ActivatePromoCodeView.as_view() | ||||||
|  | @ -3,5 +3,8 @@ | ||||||
| app_name = "tools" | app_name = "tools" | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|     path("qr/", include("akarpov.tools.qr.urls", namespace="qr")), |     path("qr/", include("akarpov.tools.qr.urls", namespace="qr")), | ||||||
|  |     path( | ||||||
|  |         "promocodes/", include("akarpov.tools.promocodes.urls", namespace="promocodes") | ||||||
|  |     ), | ||||||
|     path("shortener/", include("akarpov.tools.shortener.urls", namespace="shortener")), |     path("shortener/", include("akarpov.tools.shortener.urls", namespace="shortener")), | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | @ -149,6 +149,7 @@ | ||||||
|     "akarpov.test_platform", |     "akarpov.test_platform", | ||||||
|     "akarpov.tools.shortener", |     "akarpov.tools.shortener", | ||||||
|     "akarpov.tools.qr", |     "akarpov.tools.qr", | ||||||
|  |     "akarpov.tools.promocodes", | ||||||
| ] | ] | ||||||
| # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps | # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps | ||||||
| INSTALLED_APPS = ( | INSTALLED_APPS = ( | ||||||
|  | @ -441,7 +442,6 @@ | ||||||
| 
 | 
 | ||||||
| # django-rest-framework | # django-rest-framework | ||||||
| # ------------------------------------------------------------------------------- | # ------------------------------------------------------------------------------- | ||||||
| # django-rest-framework - https://www.django-rest-framework.org/api-guide/settings/ |  | ||||||
| REST_FRAMEWORK = { | REST_FRAMEWORK = { | ||||||
|     "DEFAULT_AUTHENTICATION_CLASSES": ( |     "DEFAULT_AUTHENTICATION_CLASSES": ( | ||||||
|         "rest_framework.authentication.SessionAuthentication", |         "rest_framework.authentication.SessionAuthentication", | ||||||
|  | @ -450,12 +450,8 @@ | ||||||
|     "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",), |     "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",), | ||||||
|     "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", |     "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", | ||||||
| } | } | ||||||
| 
 |  | ||||||
| # django-cors-headers - https://github.com/adamchainz/django-cors-headers#setup |  | ||||||
| CORS_URLS_REGEX = r"^/api/.*$" | CORS_URLS_REGEX = r"^/api/.*$" | ||||||
| 
 | 
 | ||||||
| # By Default swagger ui is available only to admin user(s). You can change permission classes to change that |  | ||||||
| # See more configuration options at https://drf-spectacular.readthedocs.io/en/latest/settings.html#settings |  | ||||||
| SPECTACULAR_SETTINGS = { | SPECTACULAR_SETTINGS = { | ||||||
|     "TITLE": "akarpov API", |     "TITLE": "akarpov API", | ||||||
|     "SCHEMA_PATH_PREFIX": "/api/v[0-9]", |     "SCHEMA_PATH_PREFIX": "/api/v[0-9]", | ||||||
|  | @ -467,6 +463,7 @@ | ||||||
|         {"url": "https://akarpov.ru", "description": "Production server"}, |         {"url": "https://akarpov.ru", "description": "Production server"}, | ||||||
|     ], |     ], | ||||||
| } | } | ||||||
|  | 
 | ||||||
| # CKEDITOR | # CKEDITOR | ||||||
| # ------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------ | ||||||
| CKEDITOR_UPLOAD_PATH = "uploads/" | CKEDITOR_UPLOAD_PATH = "uploads/" | ||||||
|  | @ -546,3 +543,23 @@ | ||||||
|     "map.provider": "openstreetmap", |     "map.provider": "openstreetmap", | ||||||
|     "search.provider": "nominatim", |     "search.provider": "nominatim", | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | # SENTRY | ||||||
|  | # ------------------------------------------------------------------------------ | ||||||
|  | dsn = env("SENTRY_DSN", default="") | ||||||
|  | if dsn: | ||||||
|  |     import sentry_sdk | ||||||
|  |     from sentry_sdk.integrations.django import DjangoIntegration | ||||||
|  | 
 | ||||||
|  |     sentry_sdk.init( | ||||||
|  |         dsn=dsn, | ||||||
|  |         traces_sample_rate=1.0, | ||||||
|  |         integrations=[ | ||||||
|  |             DjangoIntegration( | ||||||
|  |                 transaction_style="url", | ||||||
|  |                 middleware_spans=True, | ||||||
|  |                 signals_spans=True, | ||||||
|  |                 cache_spans=True, | ||||||
|  |             ), | ||||||
|  |         ], | ||||||
|  |     ) | ||||||
|  |  | ||||||
							
								
								
									
										1095
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1095
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user