654 lines
32 KiB
Python
Executable File
654 lines
32 KiB
Python
Executable File
from django.core.exceptions import ValidationError
|
||
from .api_utils import *
|
||
from .api_params import *
|
||
from .models import *
|
||
import time
|
||
|
||
|
||
def _make_model_validation_errors(validation_error: ValidationError, api_err=API_ERROR_OBJECT_VALIDATION):
|
||
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(str(err.code))
|
||
errors[field_name] = obj
|
||
return make_error_object(Exception(api_err, errors))
|
||
|
||
|
||
class ApiAccount:
|
||
@staticmethod
|
||
def __check_phone_code(phone, code):
|
||
if code is None:
|
||
res, err_code = PhoneVerificationService.send_verify(phone)
|
||
if not res:
|
||
if err_code in API_ERROR_VERIFICATION:
|
||
raise Exception(API_ERROR_VERIFICATION[err_code])
|
||
else:
|
||
raise Exception(API_ERROR_VERIFY_UNKNOWN)
|
||
|
||
raise Exception(API_ERROR_NEED_VERIFY)
|
||
else:
|
||
res, err_code = PhoneVerificationService.check_code(phone, code)
|
||
if not res:
|
||
if err_code in API_ERROR_VERIFICATION:
|
||
raise Exception(API_ERROR_VERIFICATION[err_code])
|
||
else:
|
||
raise Exception(API_ERROR_VERIFY_UNKNOWN)
|
||
|
||
return True
|
||
|
||
@staticmethod
|
||
def __make_user_json(user: Account):
|
||
obj = {
|
||
"id": user.id,
|
||
"name": user.name,
|
||
"surname": user.surname,
|
||
"phone": user.phone,
|
||
"email": user.email,
|
||
"about": user.about,
|
||
"city": {"code": user.city.code, "name": user.city.name} if user.city is not None else None,
|
||
"register_datetime": int(time.mktime(user.register_datetime.timetuple())),
|
||
"role": user.role,
|
||
}
|
||
if user.role == Account.ROLE_EXECUTOR:
|
||
obj |= {
|
||
"executor_type": user.executoraccount.executor_type,
|
||
"executor_inn": user.executoraccount.inn,
|
||
"executor_info": user.executoraccount.additional_info
|
||
}
|
||
|
||
return obj
|
||
|
||
@staticmethod
|
||
@api_method("account.register",
|
||
doc="Регистрация нового пользователя",
|
||
params=[
|
||
ApiParamEnum(name="role", choices=Account.ROLE_CHOICES, description="Роль пользователя: {choices}"),
|
||
ApiParamPhone(),
|
||
ApiParamVerifyCode(),
|
||
ApiParamPassword(required=False,
|
||
description=f"Пароль пользователя, требуется для завершения регистрации. "
|
||
f"Если код верификации будет принят, но пароль не передан"
|
||
f"метод вернет ошибку {API_ERROR_MISSING_ARGUMENT}"),
|
||
], returns="Аналогично методу <code>account.auth</code> в случае успеха")
|
||
async def register(role, phone, password, code):
|
||
user = Account.create_user(
|
||
phone=phone,
|
||
password=(password if password is not None else ""),
|
||
role=role
|
||
)
|
||
|
||
try:
|
||
await sync_to_async(user.full_clean)()
|
||
except ValidationError as validation_error:
|
||
# traceback.print_exc()
|
||
return _make_model_validation_errors(validation_error, API_ERROR_USER_REGISTER)
|
||
|
||
if ApiAccount.__check_phone_code(user.phone, code):
|
||
if password is None:
|
||
raise Exception(API_ERROR_MISSING_ARGUMENT, "password")
|
||
|
||
user = await Account.objects.acreate(phone=phone, password=password, role=role)
|
||
if role == Account.ROLE_EXECUTOR:
|
||
await ExecutorAccount.objects.acreate(account=user)
|
||
|
||
# удаляем код, типа завершение транзакции
|
||
PhoneVerificationService.check_code(phone, code, auto_pop=True)
|
||
|
||
try:
|
||
token = await AccessToken.create_token(user)
|
||
return api_make_response({"access_token": token.access_token})
|
||
except Exception as ex:
|
||
# если вдруг токен нельзя создать
|
||
user.delete()
|
||
raise ex
|
||
|
||
@staticmethod
|
||
@api_method("account.auth",
|
||
doc="Аутентификация пользователя",
|
||
params=[
|
||
ApiParamPhone(name="login", description="Логин пользователя"),
|
||
ApiParamPassword(),
|
||
],
|
||
returns="В случае правильных логина и пароля <code>access_token</code>. "
|
||
"В противном случае объект ошибки.")
|
||
async def auth(login, password):
|
||
return api_make_response({"access_token": (await AccessToken.auth(login, password)).access_token})
|
||
|
||
@staticmethod
|
||
@api_method("account.deauth",
|
||
doc="Удаление токена, дальшейшие вызовы API с этим токеном вернут ошибку невалидного токена",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
], returns="В случае успеха стандартный код успеха")
|
||
async def deauth(access_token):
|
||
await AccessToken.deauth(access_token.access_token)
|
||
return api_make_response({})
|
||
|
||
@staticmethod
|
||
@api_method("account.delete",
|
||
doc='Удаление аккаунта пользователя <bold style="color:red">БЕЗ ВОЗМОЖНОСТИ ВОССТАНОВЛЕНИЯ</bold>. '
|
||
'Так же будут удалены <bold style="color:red">ВСЕ</bold> связанные с аккаунтом данные.',
|
||
params=[ApiParamAccessToken()],
|
||
returns="Стандартный ответ успеха, в случае успеха")
|
||
async def delete(access_token):
|
||
user = access_token.user
|
||
await sync_to_async(user.delete)()
|
||
return api_make_response({})
|
||
|
||
@staticmethod
|
||
@api_method("account.get",
|
||
doc="Получение информации о пользователе",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamInt(name="user_id", required=False, value_min=0,
|
||
description="ID пользователя, аккаунт которого нужно вернуть. "
|
||
"Если не указывать, вернет аккаунт владельца.")
|
||
],
|
||
returns="Поля пользователя (name, surname, email, phone и прочие).")
|
||
async def get(access_token, user_id):
|
||
if user_id is None:
|
||
user = access_token.user
|
||
else:
|
||
user = await access_token.user.get_by_id(user_id)
|
||
if user is None:
|
||
return make_error_object(Exception(API_ERROR_NOT_FOUND, {"user": user_id}))
|
||
|
||
return api_make_response(ApiAccount.__make_user_json(user))
|
||
|
||
@staticmethod
|
||
@api_method("account.edit",
|
||
doc="Редактирование основной информации о пользователе. "
|
||
"Будут изменены только те данные, которые будут переданы в запросе, остальные не будут изменены.",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamStr(name="name", description="Имя пользователя",
|
||
min_length=2, max_length=60, required=False),
|
||
ApiParamStr(name="surname", description="Фамилия пользователя",
|
||
min_length=2, max_length=60, required=False),
|
||
ApiParamStr(name="about", description="Текст о себе. максимум - 1000 символов",
|
||
max_length=1000, required=False),
|
||
ApiParamEnum(name="executor_type", choices=ExecutorAccount.EXECUTOR_TYPE_CHOICES, required=False,
|
||
description="Тип исполнителя (только для роли исполнитель): {choices}"),
|
||
ApiParamStr(name="executor_inn", required=False, regex="^(\\d{12}|\\d{10})$",
|
||
description="ИНН исполнителя (только для роли исполнитель): "
|
||
"12 цифр если исполнитель - физ.лицо и 10 цифр если это юр. лицо"),
|
||
ApiParamEnum(name="city", description="Город, в котором находится ползователь: {choices}",
|
||
required=False, choices=City.to_choices)
|
||
],
|
||
returns="Вернет основную информацию о пользователе, иначе ошибки")
|
||
async def edit(access_token, name, surname, about, executor_type, executor_inn, city):
|
||
user = access_token.user
|
||
executor_need_save, need_save = False, False
|
||
|
||
if name is not None:
|
||
user.name = name
|
||
need_save = True
|
||
|
||
if surname is not None:
|
||
user.surname = surname
|
||
need_save = True
|
||
|
||
if about is not None:
|
||
user.about = about
|
||
need_save = True
|
||
|
||
if city is not None:
|
||
user.city = city
|
||
need_save = True
|
||
|
||
if user.role == Account.ROLE_EXECUTOR:
|
||
print("Executor account detected")
|
||
if executor_type is not None:
|
||
print("Executor account type detected")
|
||
user.executoraccount.executor_type = executor_type
|
||
executor_need_save = True
|
||
|
||
if executor_inn is not None:
|
||
print("Executor account inn detected")
|
||
t = executor_type
|
||
if t is None:
|
||
t = user.executoraccount.executor_type
|
||
|
||
if t is None:
|
||
raise Exception(API_ERROR_MISSING_ARGUMENT, "executor_type")
|
||
|
||
if t == ExecutorAccount.EXECUTOR_TYPE_SELF_EMPLOYED:
|
||
if re.match("^\\d{12}$", executor_inn) is None:
|
||
raise Exception(API_ERROR_INVALID_ARGUMENT_VALUE, "executor_inn must be defined as 12 digits")
|
||
|
||
if t == ExecutorAccount.EXECUTOR_TYPE_LEGAL_ENTITY:
|
||
if re.match("^\\d{10}$", executor_inn) is None:
|
||
raise Exception(API_ERROR_INVALID_ARGUMENT_VALUE, "executor_inn must be defined as 10 digits")
|
||
|
||
user.executoraccount.inn = executor_inn
|
||
executor_need_save = True
|
||
|
||
if need_save:
|
||
try:
|
||
await sync_to_async(user.full_clean)()
|
||
except ValidationError as ve:
|
||
return _make_model_validation_errors(ve, API_ERROR_USER_MODIFY)
|
||
|
||
await sync_to_async(user.save)()
|
||
|
||
if executor_need_save:
|
||
try:
|
||
await sync_to_async(user.executoraccount.full_clean)()
|
||
except ValidationError as ve:
|
||
return _make_model_validation_errors(ve, API_ERROR_USER_MODIFY)
|
||
|
||
await sync_to_async(user.executoraccount.save)()
|
||
|
||
return api_make_response(ApiAccount.__make_user_json(user))
|
||
|
||
@staticmethod
|
||
@api_method("account.changePhone",
|
||
doc="Смена пароля. Для подтверждения требуется старый пароль.",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamPassword(description="Пароль пользователя, нужен для подтверждения владельца аккаунта"),
|
||
ApiParamPhone(description="Новый телефон пользователя"),
|
||
ApiParamVerifyCode(description="Код подтверждения операции, придет на новый телефон")
|
||
],
|
||
returns="Вернет стандартный объект успеха")
|
||
async def change_phone(access_token, password, phone, code):
|
||
user = access_token.user
|
||
|
||
if not user.check_password(password):
|
||
raise Exception(API_ERROR_INVALID_PASSWORD)
|
||
|
||
# чекаем телефон
|
||
user.phone = phone
|
||
try:
|
||
await sync_to_async(user.full_clean)()
|
||
except ValidationError as ve:
|
||
return _make_model_validation_errors(ve, API_ERROR_USER_MODIFY)
|
||
|
||
if ApiAccount.__check_phone_code(user.phone, code):
|
||
await Account.objects.filter(id=user.id).aupdate(phone=phone)
|
||
PhoneVerificationService.check_code(user.phone, code, auto_pop=True)
|
||
|
||
return api_make_response({})
|
||
|
||
@staticmethod
|
||
@api_method("account.resetPassword",
|
||
doc="Смена пароля. Для подтверждения действия требуется код с телефона. Так же в случае успешного "
|
||
"восстановления удалит все существующие сессии пользователя.",
|
||
params=[
|
||
ApiParamPhone(description="Телефон, для которого нужно сделать восстановление"),
|
||
ApiParamPassword(name="new_password", required=False,
|
||
description="Новый пароль, нужен после того, как будет отправлен код ("
|
||
"можно передать раньше, тогда он будет проверен сразу)"),
|
||
ApiParamVerifyCode(description="Код подтверждения операции, придет на телефон")
|
||
],
|
||
returns="Вернет стандартный объект успеха")
|
||
async def reset_password(new_password, phone, code):
|
||
user = await Account.get_by_natural_key(phone)
|
||
if new_password is not None:
|
||
user.password = new_password
|
||
try:
|
||
await sync_to_async(user.full_clean)()
|
||
except:
|
||
traceback.print_exc()
|
||
raise Exception(API_ERROR_INVALID_PASSWORD)
|
||
|
||
if ApiAccount.__check_phone_code(phone, code):
|
||
if code is not None and new_password is None:
|
||
raise Exception(API_ERROR_MISSING_ARGUMENT, "new_password")
|
||
|
||
await sync_to_async(user.save)()
|
||
await AccessToken.delete_sessions(user)
|
||
PhoneVerificationService.check_code(phone, code, auto_pop=True)
|
||
|
||
return api_make_response({})
|
||
|
||
|
||
class ApiSecurity:
|
||
@staticmethod
|
||
@api_method("security.listSessions",
|
||
doc="Получение сиписка сессий (кроме текущей)",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamPassword(description="Пароль пользователя, нужен для подтверждения личности")
|
||
],
|
||
returns="Вернет sessions: [{id: int, name: str, created: unix_timestamp}]")
|
||
async def list_sessions(access_token, password):
|
||
sessions = await access_token.list_sessions()
|
||
|
||
if not access_token.user.check_password(password):
|
||
raise Exception(API_ERROR_INVALID_PASSWORD)
|
||
|
||
return api_make_response({
|
||
"current": {
|
||
"id": access_token.id,
|
||
"created": int(time.mktime(access_token.creation_time.timetuple())),
|
||
},
|
||
"sessions": [
|
||
{
|
||
"id": s.id,
|
||
"name": f"{s.access_token[:8]}...",
|
||
"created": int(time.mktime(s.creation_time.timetuple())),
|
||
} for s in sessions
|
||
]
|
||
})
|
||
|
||
@staticmethod
|
||
@api_method("security.removeOtherSessions",
|
||
doc="Получение сиписка сессий (кроме текущей)",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamPassword(description="Пароль пользователя, нужен для подтверждения личности")
|
||
],
|
||
returns="Вернет sessions: [{id: int, name: str, created: unix_timestamp}]")
|
||
async def remove_other_sessions(access_token, password):
|
||
if not access_token.user.check_password(password):
|
||
raise Exception(API_ERROR_INVALID_PASSWORD)
|
||
|
||
sessions = await access_token.list_sessions()
|
||
response = {
|
||
"current": {
|
||
"id": access_token.id,
|
||
"created": int(time.mktime(access_token.creation_time.timetuple())),
|
||
},
|
||
"removed": [
|
||
{
|
||
"id": s.id,
|
||
"name": f"{s.access_token[:8]}...",
|
||
"created": int(time.mktime(s.creation_time.timetuple())),
|
||
} for s in sessions
|
||
]
|
||
}
|
||
await access_token.delete_sessions_without_current()
|
||
|
||
return api_make_response(response)
|
||
|
||
@staticmethod
|
||
@api_method("security.removeSession",
|
||
doc="Удалит сессию с указанным id. Не удаляет текущую сессию, даже если указан ее ID "
|
||
"(будет возвращена ошибка NOT FOUND)",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamPassword(description="Пароль пользователя, нужен для подтверждения личности"),
|
||
ApiParamInt(name="session", description="ID сессии, которую надо деактивировать", value_min=0)
|
||
],
|
||
returns="Вернет стандартный отъект в случае успеха")
|
||
async def remove_session(access_token, password, session):
|
||
if not access_token.user.check_password(password):
|
||
raise Exception(API_ERROR_INVALID_PASSWORD)
|
||
|
||
await access_token.delete_session(session)
|
||
|
||
return api_make_response({})
|
||
|
||
@staticmethod
|
||
@api_method("security.changePassword",
|
||
doc="Смена пароля. Для подтверждения требуется старый пароль.",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamPassword(name="old_password", description="Старый пароль пользователя"),
|
||
ApiParamPassword(description="Новый пароль пользователя"),
|
||
],
|
||
returns="Вернет стандартный объект успеха")
|
||
async def change_password(access_token, old_password, password):
|
||
user = access_token.user
|
||
|
||
if not user.check_password(old_password):
|
||
raise Exception(API_ERROR_INVALID_PASSWORD, "old_password")
|
||
|
||
user.password = password
|
||
|
||
await sync_to_async(user.save)()
|
||
|
||
return api_make_response({})
|
||
|
||
|
||
class ApiOrder:
|
||
@staticmethod
|
||
@api_method("order.getForm",
|
||
doc="Получение формы создания заказа в виде полей, которые нужно показать пользователю",
|
||
params=[],
|
||
returns="<code>JSON</code> объект, содержащий данные формы. Структура пока не определена")
|
||
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
|
||
},
|
||
]
|
||
})
|
||
|
||
@staticmethod
|
||
@api_method("order.create",
|
||
doc="Создание заказа",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamStr(name='name', max_length=200, description="Название заказа"),
|
||
ApiParamStr(name='description', max_length=1000, description="Описание заказа",
|
||
required=False, default=""),
|
||
ApiParamFloat(name='square', value_max=99999.99, value_min=1.0,
|
||
description='Площадь в м²'),
|
||
ApiParamStr(name='work_time', max_length=100, description="Рабочее время",
|
||
required=False, default=""),
|
||
|
||
ApiParamEnum(name='type_of_renovation', choices=Order.TYPE_OF_RENOVATION_CHOICES, required=False,
|
||
default=Order.CHOICE_UNDEFINED,
|
||
description="Тип ремонта: {choices}"),
|
||
ApiParamEnum(name='type_of_house', choices=Order.TYPE_OF_HOUSE_CHOICES, required=False,
|
||
default=Order.CHOICE_UNDEFINED,
|
||
description="Тип дома: {choices}"),
|
||
ApiParamEnum(name='type_of_room', choices=Order.TYPE_OF_ROOM_CHOICES, required=False,
|
||
default=Order.CHOICE_UNDEFINED,
|
||
description="Тип квартиры: {choices}"),
|
||
ApiParamEnum(name='purchase_of_material', choices=Order.PURCHASE_OF_MATERIAL_CHOICES,
|
||
required=False, default=Order.CHOICE_UNDEFINED,
|
||
description="Закуп материала: {choices}"),
|
||
ApiParamEnum(name='type_of_executor', choices=Order.TYPE_OF_EXECUTOR_CHOICES,
|
||
required=False, default=Order.CHOICE_UNDEFINED,
|
||
description="Тип исполнителя: {choices}"),
|
||
|
||
# дальше отдельные флаги
|
||
ApiParamBoolean(name="is_with_warranty", required=False, default=True,
|
||
description="С гарантией"),
|
||
ApiParamBoolean(name="is_with_contract", required=False, default=False,
|
||
description="Работа по договору"),
|
||
ApiParamBoolean(name="is_with_trade", required=False, default=False,
|
||
description="Возможен торг"),
|
||
ApiParamBoolean(name="is_with_cleaning", required=False, default=False,
|
||
description="С уборкой"),
|
||
ApiParamBoolean(name="is_with_garbage_removal", required=False, default=False,
|
||
description="С вывозом мусора"),
|
||
ApiParamBoolean(name="is_require_design", required=False, default=False,
|
||
description="Требуется дизайн проект"),
|
||
|
||
# примерная цена
|
||
ApiParamFloat(name='approximate_price', value_max=9999999999.99, value_min=1.0,
|
||
description='Примерная цена'),
|
||
|
||
# date_start = models.DateField(null=True, blank=True, default=None, verbose_name="Дата начала")
|
||
# date_end = models.DateField(null=True, blank=True, default=None, verbose_name="Дата окончания")
|
||
|
||
ApiParamEnum(name="address_city", description="Город: {choices}", choices=City.to_choices),
|
||
|
||
ApiParamStr(name='address_text', max_length=70, description="Улица, дом",
|
||
required=False, default="")
|
||
# email = models.EmailField(null=True, blank=True, verbose_name="Email")
|
||
# phone = models.CharField(null=True, blank=True, max_length=16, verbose_name="Телефон")
|
||
],
|
||
returns="ID созданного заказа, иначе одну из ошибок")
|
||
async def create(**kwargs):
|
||
access_token = kwargs.pop('access_token')
|
||
ApiOrder._check_modify_permissions(access_token)
|
||
|
||
city = await City.get_by_code(kwargs.pop('address_city'))
|
||
|
||
try:
|
||
order = await Order.objects.acreate(owner=access_token.user, address_city=city, **kwargs)
|
||
except ValidationError as ve:
|
||
return _make_model_validation_errors(ve, API_ERROR_USER_MODIFY)
|
||
return api_make_response({"order_id": order.id})
|
||
|
||
@staticmethod
|
||
@api_method("order.setPublished",
|
||
doc="Установка статуса публикации заказа",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamInt(name='order_id', value_min=0, description='ID заказа'),
|
||
ApiParamBoolean(name='value', description='Значение поля "опубликован"')
|
||
],
|
||
returns="Обновленный объект заказа")
|
||
async def set_published(access_token, order_id, value):
|
||
ApiOrder._check_modify_permissions(access_token)
|
||
query = Order.objects.filter(id=order_id)
|
||
order = await query.afirst()
|
||
if order.owner_id != access_token.user.id:
|
||
raise Exception(API_ERROR_ACCESS_DENIED, 'edit operation allowed only for owner')
|
||
|
||
await query.aupdate(published=value)
|
||
|
||
# вернем в зад обновленный объект
|
||
order.published = value
|
||
return api_make_response(ApiOrder._order_to_json(order))
|
||
|
||
ORDER_GET_ORDERING = [
|
||
('create_time', 'время создания, сначала новые записи'),
|
||
('-create_time', 'время создания, сначала старые записи'),
|
||
]
|
||
|
||
@staticmethod
|
||
def _order_to_json(order):
|
||
return order.__dict__
|
||
|
||
@staticmethod
|
||
@api_method("order.get",
|
||
doc="Получение объектов заказа, применит все фильтры",
|
||
params=[
|
||
ApiParamAccessToken(),
|
||
ApiParamInt(name='order_id', required=False, value_min=0,
|
||
description='ID заказа, который нужно вернуть, вернет один заказ, является фильтром'),
|
||
ApiParamInt(name='user_id', required=False, value_min=0,
|
||
description='Показать заказы для конкретного пользователя'),
|
||
ApiParamEnum(name='ordering', choices=ORDER_GET_ORDERING, required=False,
|
||
description='Сортировка заказов. Возможные значения: {choices} '
|
||
'Не имеет эффекта если ответ состоит из одного заказа.'),
|
||
|
||
],
|
||
returns="Массив заказов, соответсвующий всем указанным фильтрам.")
|
||
async def get(access_token, order_id, user_id, ordering):
|
||
query = Order.objects
|
||
if order_id is not None:
|
||
res = await query.aget(id=order_id)
|
||
if user_id is not None:
|
||
if access_token.user.id == res.owner_id or (res.published and res.moderated):
|
||
return api_make_response([ApiOrder._order_to_json(res)])
|
||
else:
|
||
raise Exception(API_ERROR_NOT_ALLOWED, 'attempt access to closed order')
|
||
|
||
if user_id is not None:
|
||
user = await access_token.user.get_by_id(user_id)
|
||
if user is None:
|
||
raise Exception(API_ERROR_NOT_FOUND, 'user')
|
||
if user.role != Account.ROLE_CUSTOMER:
|
||
raise Exception(API_ERROR_NOT_ALLOWED, 'target user is not customer')
|
||
query = query.filter(owner_id=user_id)
|
||
|
||
if ordering is not None:
|
||
query = query.order_by(ordering)
|
||
|
||
return api_make_response([ApiOrder._order_to_json(item) async for item in query.all()])
|
||
|
||
@staticmethod
|
||
def _check_modify_permissions(access_token):
|
||
if not access_token.user.is_completed():
|
||
raise Exception(API_ERROR_NEED_COMPLETED_ACCOUNT)
|
||
if access_token.user.role != Account.ROLE_CUSTOMER:
|
||
raise Exception(API_ERROR_NOT_ALLOWED, 'you must be a customer')
|
||
|
||
|
||
async def api_call_method(method_name, params: dict):
|
||
if method_name in api_methods_dict:
|
||
return await api_methods_dict[method_name]["func"](**params)
|
||
else:
|
||
return make_error_object(Exception(API_ERROR_METHOD_NOT_FOUND))
|
||
|
||
|
||
def api_get_documentation():
|
||
out = []
|
||
for m in api_methods_dict:
|
||
out.append({
|
||
"name": m,
|
||
"doc": api_methods_dict[m]["doc"],
|
||
"returns": api_methods_dict[m]["returns"],
|
||
"params": [p.to_json() for p in api_methods_dict[m]["params"]]
|
||
})
|
||
return out
|