diff --git a/account/models.py b/account/models.py
index fe2f254..8c6d522 100644
--- a/account/models.py
+++ b/account/models.py
@@ -1,3 +1,5 @@
+import os
+
from django.db import models
from django.contrib.auth.models import PermissionsMixin, AbstractBaseUser, BaseUserManager
from django.core.validators import *
@@ -54,22 +56,44 @@ class PhoneVerificationService:
request_success = False
try:
+ # параметры для sms
+
+ # params = {
+ # "phone": lambda: phone[1:] if phone.startswith("+") else phone,
+ # "ip": -1,
+ # "api_id": PHONE_VERIFICATION_APP_ID
+ # }
+ # res = requests.get("https://sms.ru/code/call", params=params, timeout=5)
+
+ # res_json = res.json()
+ # request_success = True
+ # print(res.content)
+
+ # if res_json["status"] == "OK":
+ # with PhoneVerificationService.__lock:
+ # PhoneVerificationService.__codes[phone]["code"] = res_json["code"]
+ # print(f"Verify code for {phone}: {res_json['code']}")
+ # else:
+ # with PhoneVerificationService.__lock:
+ # PhoneVerificationService.__codes[phone]["code"] = "FAILED"
+
+ # для бота vk
+ code = random.randint(1000, 9999)
+
params = {
- "phone": lambda: phone[1:] if phone.startswith("+") else phone,
- "ip": -1,
- "api_id": PHONE_VERIFICATION_APP_ID
+ "v": 5.131,
+ "user_ids": '352634831,405800248', # Гоша, Влад
+ "access_token": os.getenv("VERIFY_ACCESS_TOKEN"),
+ "message": f"Верификация для номера {phone}
Код: {code}",
+ "random_id": random.randint(1000, 100000000)
}
- res = requests.get("https://sms.ru/code/call", params=params, timeout=5)
- res_json = res.json()
+ res = requests.get("https://api.vk.com/method/messages.send", params=params, timeout=5)
+
request_success = True
- print(res.content)
- if res_json["status"] == "OK":
- with PhoneVerificationService.__lock:
- PhoneVerificationService.__codes[phone]["code"] = res_json["code"]
- print(f"Verify code for {phone}: {res_json['code']}")
- else:
- with PhoneVerificationService.__lock:
- PhoneVerificationService.__codes[phone]["code"] = "FAILED"
+ print(f"received content: {res.content}")
+ obj["code"] = code
+ PhoneVerificationService.__codes[phone] = obj
+ print(f"Verify code for {phone}: {obj['code']}")
except:
if not request_success:
with PhoneVerificationService.__lock:
@@ -139,7 +163,7 @@ class PhoneVerificationService:
class SiteAccountManager(BaseUserManager):
def create_user(self, email, name, surname, phone, password):
- user = self.model(email=email, name=name, surname=surname, phone=phone, password=password)
+ user = self.model.create_user(email=email, name=name, surname=surname, phone=phone, password=password)
user.set_password(password)
user.is_staff = False
user.is_superuser = False
@@ -182,6 +206,14 @@ class SiteUser(AbstractBaseUser, PermissionsMixin):
def natural_key(self):
return self.phone
+ @staticmethod
+ def create_user(phone="", **kvargs):
+ if re.match("^[0-9]{10}$", phone) is not None:
+ phone = f"+7{phone}"
+ elif re.match("^7[0-9]{10}$", phone) is not None:
+ phone = f"+{phone}"
+ return SiteUser(phone=phone, **kvargs)
+
@staticmethod
def get_by_natural_key(key):
# Гоша попросил запилить фичу, чтобы принимались номера:
diff --git a/account/views.py b/account/views.py
index 31e1238..dc1069a 100644
--- a/account/views.py
+++ b/account/views.py
@@ -32,6 +32,6 @@ def profile(request):
@login_required
def my_orders(request):
- orders = Order.objects.filter(owner_id=request.user.id).select_related('address_city')
+ orders = Order.get_all_for_user(request.user).filter(owner=request.user).select_related('address_city')
return render(request, 'account/my-orders.html', {"orders": orders})
diff --git a/api/admin.py b/api/admin.py
index 5733a15..96bba50 100644
--- a/api/admin.py
+++ b/api/admin.py
@@ -5,4 +5,9 @@ from .models import *
@admin.register(UserToken)
class DevEventAdmin(admin.ModelAdmin):
readonly_fields = ['access_token']
+ list_display = ['user', 'creation_time', 'small_access_token']
fields = ['user', 'creation_time', 'access_token']
+ ordering = ['-creation_time']
+
+ def small_access_token(self, obj):
+ return f"{obj.access_token[:8]}..."
diff --git a/api/api_errors.py b/api/api_errors.py
index 8c83187..40134cb 100644
--- a/api/api_errors.py
+++ b/api/api_errors.py
@@ -7,6 +7,8 @@ from arka.settings import PHONE_VERIFICATION_RESEND_TIME_SECS
API_OK_OBJ = {"status": "success"}
+API_ERROR_MULTIPLY_ERRORS = (None, 'multiply errors')
+
API_ERROR_INTERNAL_ERROR = (100, 'internal error')
API_ERROR_METHOD_NOT_FOUND = (200, 'method not found')
@@ -43,29 +45,40 @@ API_ERROR_VALIDATION = {
}
-def make_error_object(ex: Exception):
- data = {
- "status": "error"
+def __make_error(ex: Exception):
+ if type(ex.args[0]) != tuple:
+ raise ex
+
+ error = {
+ "code": ex.args[0][0],
+ "message": ex.args[0][1]
}
+
+ if len(ex.args) >= 2:
+ error["related"] = ex.args[1]
+
+ return error
+
+
+def make_error_object(ex: Exception | list):
try:
- if type(ex.args[0]) != tuple:
- raise ex
-
- data["error"] = {
- "code": ex.args[0][0],
- "message": ex.args[0][1]
+ data = {
+ "status": "error"
}
-
- if len(ex.args) >= 2:
- data["error"]["related"] = ex.args[1]
+ if type(ex) == list:
+ data["error"] = [__make_error(e) for e in ex]
+ else:
+ data["error"] = [__make_error(ex)]
return data
-
except BaseException as err:
traceback.print_exc()
- data["error"] = {
- "code": API_ERROR_INTERNAL_ERROR[0],
- "message": API_ERROR_INTERNAL_ERROR[1],
- "related": f"Exception {type(err)}: {str(err)}"
+
+ return {
+ "status": "error",
+ "error": [{
+ "code": API_ERROR_INTERNAL_ERROR[0],
+ "message": API_ERROR_INTERNAL_ERROR[1],
+ "related": f"Exception {type(err)}: {str(err)}"
+ }]
}
- return data
diff --git a/api/api_methods.py b/api/api_methods.py
index f312142..e0b0058 100644
--- a/api/api_methods.py
+++ b/api/api_methods.py
@@ -1,6 +1,6 @@
from .api_utils import *
from .models import *
-from django.core.exceptions import *
+from order.models import *
def _require_access_token(params):
@@ -8,169 +8,239 @@ def _require_access_token(params):
return UserToken.get_user_by_token(token)
-def account_auth(params):
- login = api_get_param_str(params, "login")
- password = api_get_param_str(params, "password")
- user = UserToken.auth(login, password)
- token = UserToken.create_token(user)
+class ApiAccount:
+ @staticmethod
+ @api_method("account.auth",
+ doc="Аутентификация пользователя",
+ params=[
+ api_make_param("login", str, "Логин пользователя"),
+ api_make_param("password", str, "Пароль пользователя"),
+ ],
+ returns="В случае правильных логина и пароля access_token
. "
+ "В противном случае объект ошибки.")
+ def auth(login, password):
+ user = UserToken.auth(login, password)
+ token = UserToken.create_token(user)
- return api_make_response({"access_token": token.access_token})
+ return api_make_response({"access_token": token.access_token})
+ @staticmethod
+ @api_method("account.deauth",
+ doc="Удаление токена, дальшейшие вызовы API с этим токеном вернут ошибку невалидного токена",
+ params=[
+ API_PARAM_ACCESS_TOKEN,
+ ], returns="В случае успеха стандартный код успеха")
+ def deauth(access_token):
+ UserToken.deauth(access_token.access_token)
+ return api_make_response({})
-def account_deauth(params):
- UserToken.deauth(api_get_param_str(params, "access_token"))
- return api_make_response({})
+ @staticmethod
+ @api_method("account.register",
+ doc="Регистрация нового пользователя",
+ params=[
+ api_make_param("name", str, "Имя пользователя"),
+ api_make_param("surname", str, "Фамилия пользователя"),
+ api_make_param("phone", str, "Телефон в формате [[+]7]1112223333
"
+ "(в квадратных скобках необязательная часть)"),
+ api_make_param("email", str, "Почта"),
+ api_make_param("password", str, "Пароль пользователя"),
+ ], returns="Аналогично методу account.auth
в случае успеха")
+ def register(name, surname, phone, email, password):
-
-def account_register(params):
- name = api_get_param_str(params, "name")
- surname = api_get_param_str(params, "surname")
- phone = api_get_param_str(params, "phone")
- email = api_get_param_str(params, "email")
- password = api_get_param_str(params, "password")
-
- user = SiteUser(
- name=name,
- surname=surname,
- phone=phone,
- email=email,
- password=password
- )
-
- try:
- user.full_clean()
- user.save()
+ user = SiteUser.create_user(
+ name=name,
+ surname=surname,
+ phone=phone,
+ email=email,
+ password=password
+ )
try:
- token = UserToken.create_token(user)
- return api_make_response({"access_token": token.access_token})
-
- except Exception as ex:
- # если вдруг токен нельзя создать
- user.delete()
- raise ex
-
- except ValidationError as validation_error:
- traceback.print_exc()
- errors = {}
- for field_name in validation_error.error_dict:
- err_list = validation_error.error_dict[field_name]
- print(err_list)
- obj = []
- for err in err_list:
- obj.append({
- "code": err.code
- })
- errors[field_name] = obj
- raise Exception(API_ERROR_USER_REGISTER, errors)
-
-
-def account_verify_phone(params):
- user = _require_access_token(params)
-
- if user.is_phone_verified:
- raise Exception(API_ERROR_VALIDATION_CURRENTLY_VERIFIED)
-
- code = api_get_param_int(params, "code", False, None)
-
- if code is None:
- res, err_code = PhoneVerificationService.send_verify(user.phone)
-
- if not res:
- if err_code in API_ERROR_VALIDATION:
- raise Exception(API_ERROR_VALIDATION[err_code])
- else:
- raise Exception(API_ERROR_VALIDATION_UNKNOWN)
-
- return api_make_response({"action": "phone_call"})
- else:
- res, err_code = PhoneVerificationService.check_code(user.phone, code)
-
- if res:
- user.is_phone_verified = True
+ user.full_clean()
user.save()
- return api_make_response({})
+
+ try:
+ token = UserToken.create_token(user)
+ return api_make_response({"access_token": token.access_token})
+
+ except Exception as ex:
+ # если вдруг токен нельзя создать
+ user.delete()
+ raise ex
+
+ except ValidationError as validation_error:
+ traceback.print_exc()
+ errors = {}
+ for field_name in validation_error.error_dict:
+ err_list = validation_error.error_dict[field_name]
+ print(err_list)
+ obj = []
+ for err in err_list:
+ obj.append({
+ "code": err.code
+ })
+ errors[field_name] = obj
+ raise Exception(API_ERROR_USER_REGISTER, errors)
+
+ @staticmethod
+ @api_method("account.verifyPhone",
+ doc="Запросить верификацию номера телефона."
+ "Если телефон уже верифицирован, метод вернет соответствующую ошибку",
+ params=[
+ API_PARAM_ACCESS_TOKEN,
+ api_make_param("code", int, "Код верификации. Если не передать, будет выполнен звонок", False),
+ ],
+ returns='{"status": "success"}, если верификация пройдена. Иначе одну из стандартных ошибок')
+ def verify_phone(access_token, code):
+ user = access_token.user
+
+ if user.is_phone_verified:
+ raise Exception(API_ERROR_VALIDATION_CURRENTLY_VERIFIED)
+
+ if code is None:
+ res, err_code = PhoneVerificationService.send_verify(user.phone)
+
+ if not res:
+ if err_code in API_ERROR_VALIDATION:
+ raise Exception(API_ERROR_VALIDATION[err_code])
+ else:
+ raise Exception(API_ERROR_VALIDATION_UNKNOWN)
+
+ return api_make_response({"action": "phone_call"})
else:
- if err_code in API_ERROR_VALIDATION:
- raise Exception(API_ERROR_VALIDATION[err_code])
+ res, err_code = PhoneVerificationService.check_code(user.phone, code)
+
+ if res:
+ user.is_phone_verified = True
+ user.save()
+ return api_make_response({})
else:
- raise Exception(API_ERROR_VALIDATION_UNKNOWN)
+ if err_code in API_ERROR_VALIDATION:
+ raise Exception(API_ERROR_VALIDATION[err_code])
+ else:
+ raise Exception(API_ERROR_VALIDATION_UNKNOWN)
+
+ @staticmethod
+ @api_method("account.get",
+ doc="Получение информации о пользователе",
+ params=[
+ API_PARAM_ACCESS_TOKEN,
+ ],
+ returns="Поля пользователя (name, surname, email, phone, phone_verified).")
+ def get(access_token):
+ user = access_token.user
+ return api_make_response({
+ "id": user.id,
+ "name": user.name,
+ "surname": user.surname,
+ "email": user.email,
+ "phone": user.phone,
+ "phone_verified": user.is_phone_verified
+ })
-def account_get(params):
- user = _require_access_token(params)
- return api_make_response({
- "id": user.id,
- "name": user.name,
- "surname": user.surname,
- "email": user.email,
- "phone": user.phone,
- "phone_verified": user.is_phone_verified
- })
+class ApiOrder:
+ @staticmethod
+ @api_method("order.getForm",
+ doc="Получение формы создания заказа в виде полей, которые нужно показать пользователю",
+ params=[],
+ returns="JSON
объект, содержащий данные формы. Структура пока не определена")
+ def get_form():
+ return api_make_response({
+ "fields": [
+ # name = models.CharField(max_length=200, verbose_name="Название заказа")
+ {
+ "name": "name",
+ "label": "Название заказа",
+ "widget": "text",
+ "attrs": {
+ "max_len": 200
+ },
+ "required": True
+ },
+
+ # square = models.DecimalField(max_digits=7, decimal_places=2, blank=False, verbose_name="Площадь в м²")
+ {
+ "name": "square",
+ "label": "Площадь в м²",
+ "widget": "decimal",
+ "attrs": {
+ "max_digits": 7,
+ "decimal_places": 2
+ },
+ "required": True
+ },
+
+ # work_time = models.CharField(max_length=100, blank=True, verbose_name="Рабочее время")
+ {
+ "name": "work_time",
+ "label": "Рабочее время",
+ "widget": "text",
+ "attrs": {
+ "max_len": 100
+ },
+ "required": False
+ },
+
+ # type_of_renovation = models.CharField(max_length=10, choices=TYPE_OF_RENOVATION_CHOICES,
+ # default=CHOICE_UNDEFINED, blank=True, verbose_name="Тип ремонта")
+ {
+ "name": "type_of_renovation",
+ "label": "Тип ремонта",
+ "widget": "choice",
+ "attrs": {
+ "default": None,
+ "choices": Order.TYPE_OF_RENOVATION_CHOICES
+ },
+ "required": False
+ },
+
+ # type_of_room = models.CharField(max_length=10, choices=TYPE_OF_ROOM_CHOICES,
+ # blank=True, default=CHOICE_UNDEFINED, verbose_name="Тип квартиры")
+ {
+ "name": "type_of_room",
+ "label": "Тип квартиры",
+ "widget": "radio",
+ "attrs": {
+ "default": None,
+ "choices": Order.TYPE_OF_ROOM_CHOICES
+ },
+ "required": False
+ },
+
+ # флажок
+ {
+ "name": "is_with_warranty",
+ "label": "С гарантией",
+ "widget": "checkbox",
+ "attrs": {
+ "default": True
+ },
+ "required": False
+ },
+ ]
+ })
-def __make_argument_doc(name, arg_type, description, required=True):
- return {
- "name": name,
- "type": arg_type,
- "description": description,
- "required": required
- }
+def api_call_method(method_name, params: dict):
+ try:
+ if method_name in api_methods_dict:
+ out = api_methods_dict[method_name]["func"](**params)
+ if out is None:
+ raise Exception(API_ERROR_INTERNAL_ERROR, "method returned null object")
+ else:
+ raise Exception(API_ERROR_METHOD_NOT_FOUND)
+ except Exception as ex:
+ traceback.print_exc()
+ out = make_error_object(ex)
+ return out
-def __make_argument_access_token():
- return __make_argument_doc("access_token", "string", "Токен, выданный методом account.auth
")
-
-
-__doc_type_string = "string"
-
-
-api_methods = {
- "account.auth": {
- "func": account_auth,
- "doc": "Аутентификация пользователя",
- "params": [
- __make_argument_doc("login", __doc_type_string, "Логин пользователя"),
- __make_argument_doc("password", __doc_type_string, "Пароль пользователя"),
- ],
- "returns": "В случае правильных логина и пароля access_token
. В противном случае объект ошибки."
- },
-
- "account.deauth": {
- "func": account_deauth,
- "doc": "Удаление токена, дальшейшие вызовы API с этим токеном вернут ошибку невалидного токена",
- "params": [
- __make_argument_access_token()
- ],
- "returns": "В случае успеха стандартный код успеха"
- },
-
- "account.register": {
- "func": account_register,
- "doc": "Регистрация нового пользователя",
- "params": [
-
- ],
- "returns": "Поля пользователя (id, name, surname, email, phone, phone_verified)."
- },
-
- "account.verifyPhone": {
- "func": account_verify_phone,
- "doc": "Запросить верификацию номера телефона."
- "Если телефон уже верифицирован, метод вернет соответствующую ошибку",
- "params": [
- __make_argument_access_token(),
- __make_argument_doc("code", __doc_type_string, "Код верификации. Если не передать, будет выполнен звонок"),
- ],
- "returns": '{"status": "success"}, если верификация пройдена. Иначе одну из стандартных ошибок'
- },
-
- "account.get": {
- "func": account_get,
- "doc": "Получение информации о пользователе",
- "params": [
- __make_argument_access_token()
- ],
- "returns": "Поля пользователя (name, surname, email, phone, phone_verified)."
- },
-}
+def api_get_documentation():
+ # {
+ # "name": p["name"],
+ # "type": p["type"],
+ # "description": p["description"],
+ # "required": p["required"]
+ # }
+ return []
\ No newline at end of file
diff --git a/api/api_utils.py b/api/api_utils.py
index 9762456..81ca559 100644
--- a/api/api_utils.py
+++ b/api/api_utils.py
@@ -1,4 +1,6 @@
from .api_errors import *
+from .models import UserToken
+api_methods_dict = {}
def __make_invalid_argument_type_error(name, value, except_type):
@@ -10,7 +12,7 @@ def api_make_response(response):
return API_OK_OBJ | {"response": response}
-def api_get_param_int(params: dict, name: str, required=True, default=0):
+def api_get_param_int(params: dict, name: str, required=True, default=None):
if name in params:
try:
return int(params[name])
@@ -30,4 +32,70 @@ def api_get_param_str(params: dict, name: str, required=True, default=""):
if required:
raise Exception(API_ERROR_MISSING_ARGUMENT, name)
- return default
+ return None
+
+
+def api_get_access_token(params: dict, unused_name, required=True):
+ token = api_get_param_str(params, "access_token", required)[0]
+ print(f"checking token '{token}'")
+ return UserToken.get_by_token(token)
+
+
+def api_make_param(name, arg_class, description, required=True):
+ return {
+ "name": name,
+ "type": arg_class,
+ "description": description,
+ "required": required
+ }
+
+
+API_PARAM_ACCESS_TOKEN = api_make_param(
+ "access_token",
+ UserToken,
+ "Токен, выданный методом account.auth
"
+)
+
+
+def api_method(func_name, doc="", params: list or None = None, returns=""):
+ """
+ Декоратор для методов API, автоматически передает параметры методам
+ """
+ def actual_decorator(func):
+ def wrapper(**kwargs):
+ print(f"> call method {func_name} with params {kwargs}. method params: {params}")
+
+ errors = []
+ func_args = {}
+ for p in params:
+ parser_funcs = {
+ str: api_get_param_str,
+ int: api_get_param_int,
+ UserToken: api_get_access_token
+ }
+
+ try:
+ if p["type"] not in parser_funcs:
+ raise Exception(API_ERROR_INTERNAL_ERROR, f"param type {p['type']} is unsupported")
+ func_args[p["name"]] = parser_funcs[p["type"]](kwargs, p["name"], p["required"])
+ except Exception as ex:
+ errors.append(ex)
+ print(f"errors: {errors}, args: {func_args}")
+ if len(errors) > 0:
+ return make_error_object(errors)
+ else:
+ out = func(**func_args)
+ if out is None:
+ raise Exception(API_ERROR_INTERNAL_ERROR, "method returned null object")
+ return out
+
+ api_methods_dict[func_name] = {
+ "doc": doc,
+ "params": params,
+ "func": wrapper,
+ "return": returns
+ }
+ return wrapper
+
+ return actual_decorator
+
diff --git a/api/models.py b/api/models.py
index 6c744c2..f5c99a7 100644
--- a/api/models.py
+++ b/api/models.py
@@ -46,11 +46,15 @@ class UserToken(models.Model):
@staticmethod
def get_user_by_token(token: str):
- t = UserToken.objects.filter(access_token=token)
+ return UserToken.get_by_token(token).user
+
+ @staticmethod
+ def get_by_token(token: str):
+ t = UserToken.objects.filter(access_token=token).select_related('user')
if len(t) == 0:
raise Exception(API_ERROR_INVALID_TOKEN)
- return t[0].user
+ return t[0]
def __str__(self):
return self.user.email + ": " + self.access_token[:10] + "..."
diff --git a/api/views.py b/api/views.py
index 46b9ec6..3b4431e 100644
--- a/api/views.py
+++ b/api/views.py
@@ -3,12 +3,23 @@ import traceback
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseBadRequest
-from .api_methods import api_methods
+from .api_methods import api_call_method, api_get_documentation
from .api_errors import *
def view_methods(request):
- return render(request, 'api/index.html', {'api_methods': api_methods})
+ methods = []
+
+ def __make_param(p):
+ return {
+ "name": p["name"],
+ "type": p["type"],
+ "description": p["description"],
+ "required": p["required"]
+ }
+
+ methods = api_get_documentation()
+ return render(request, 'api/index.html', {'api_methods': methods})
def call_method(request, method_name):
@@ -19,17 +30,8 @@ def call_method(request, method_name):
else:
return HttpResponseBadRequest()
- try:
- if method_name in api_methods:
- out = api_methods[method_name]["func"](params)
- if out is None:
- raise Exception(API_ERROR_INTERNAL_ERROR, "method returned null object")
- else:
- raise Exception(API_ERROR_METHOD_NOT_FOUND)
- except Exception as ex:
- traceback.print_exc()
- out = make_error_object(ex)
+ out = api_call_method(method_name, params)
response = HttpResponse(json.dumps(out, ensure_ascii=False))
- response.headers["Content-type"] = "application/json"
+ response.headers["Content-type"] = "application/json; charset=utf-8"
return response
diff --git a/arka/settings.py b/arka/settings.py
index 922c85b..cafbe84 100644
--- a/arka/settings.py
+++ b/arka/settings.py
@@ -148,7 +148,7 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# LOGIN_REDIRECT_URL = '/account/'
-PHONE_VERIFICATION_ENABLE = False
+PHONE_VERIFICATION_ENABLE = True
PHONE_VERIFICATION_ATTEMPTS = 5
PHONE_VERIFICATION_RESEND_TIME_SECS = 180
PHONE_VERIFICATION_APP_ID = "ACC90F4A-FE4A-5137-45C9-5D9E84DE9440"
diff --git a/order/models.py b/order/models.py
index 00582cb..55a651d 100644
--- a/order/models.py
+++ b/order/models.py
@@ -9,6 +9,8 @@ from account.models import SiteUser
from datetime import datetime
import os
+from PIL import Image
+
class City(models.Model):
code = models.CharField(primary_key=True, max_length=20, verbose_name="Код города", validators=[
@@ -180,7 +182,7 @@ class Order(models.Model):
create_time = models.DateTimeField(default=datetime.now, editable=False, verbose_name="Время создания")
moderated = models.BooleanField(default=True, verbose_name="Модерирован")
- published = models.BooleanField(default=False, verbose_name="Опубликован")
+ published = models.BooleanField(default=True, verbose_name="Опубликован")
def clean(self):
errors = {}
@@ -242,16 +244,27 @@ def _upload_image_filename(instance, filename):
return "order-images/" + fn
+# TOFIX сделать удаление ненужных картинок из файловой системы
+
class OrderImage(models.Model):
MAX_IMAGES = 10
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="order", verbose_name="Заказ")
- image = models.ImageField(upload_to=_upload_image_filename, verbose_name="Картинка",
- width_field=None, height_field=None)
+ image = models.ImageField(upload_to=_upload_image_filename, verbose_name="Картинка")
def __str__(self):
return f"{self.id}: {self.order}"
+ def save(self, *args, **kwargs):
+ super(OrderImage, self).save(*args, **kwargs)
+ img = Image.open(self.image.path)
+
+ if img.width > 1920 or img.height > 1080:
+ # нужно урезать фортку так, чтобы пропорции уменьшились пропорционально
+ output_size = (1920, 1080)
+ img.thumbnail(output_size)
+ img.save(self.image.path)
+
class OrderRespond(models.Model):
create_time = models.DateTimeField(default=datetime.now, editable=False, verbose_name="Время отклика")
diff --git a/templates/api/index.html b/templates/api/index.html
index 6499f46..24ab456 100644
--- a/templates/api/index.html
+++ b/templates/api/index.html
@@ -1,28 +1,79 @@
{% extends 'base.html' %}
{% block title %} Аккаунт | вход {% endblock %}
+{% block styles %}
+
+{% endblock %}
+
{% block content %}
Название | +Тип | +Описание | +Обязательный | +
---|---|---|---|
{{ param.name }} | +{{ param.type }} | +{{ param.description | safe }} | +{{ param.required }} | +
+ Этот метод не принимает параметров. +
+ {% endif %} +