From bd9f255a661cdcf52329de31309b88eb4b507476 Mon Sep 17 00:00:00 2001 From: Elo-No Date: Tue, 20 Sep 2022 14:17:50 +0430 Subject: [PATCH 1/7] initial config --- DJANGO-CRYPTOREADER/.gitignore | 140 ++++++++++++++++++ .../DjangoCryptoReader/__init__.py | 0 .../DjangoCryptoReader/asgi.py | 16 ++ .../DjangoCryptoReader/settings.py | 125 ++++++++++++++++ .../DjangoCryptoReader/urls.py | 21 +++ .../DjangoCryptoReader/wsgi.py | 16 ++ DJANGO-CRYPTOREADER/README.md | 30 ++++ DJANGO-CRYPTOREADER/account/__init__.py | 0 DJANGO-CRYPTOREADER/account/admin.py | 3 + DJANGO-CRYPTOREADER/account/apps.py | 6 + .../account/migrations/__init__.py | 0 DJANGO-CRYPTOREADER/account/models.py | 3 + DJANGO-CRYPTOREADER/account/serializers.py | 0 DJANGO-CRYPTOREADER/account/tests.py | 3 + DJANGO-CRYPTOREADER/account/urls.py | 0 DJANGO-CRYPTOREADER/account/views.py | 3 + DJANGO-CRYPTOREADER/manage.py | 22 +++ DJANGO-CRYPTOREADER/requirements.txt | Bin 0 -> 318 bytes 18 files changed, 388 insertions(+) create mode 100644 DJANGO-CRYPTOREADER/.gitignore create mode 100644 DJANGO-CRYPTOREADER/DjangoCryptoReader/__init__.py create mode 100644 DJANGO-CRYPTOREADER/DjangoCryptoReader/asgi.py create mode 100644 DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py create mode 100644 DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py create mode 100644 DJANGO-CRYPTOREADER/DjangoCryptoReader/wsgi.py create mode 100644 DJANGO-CRYPTOREADER/README.md create mode 100644 DJANGO-CRYPTOREADER/account/__init__.py create mode 100644 DJANGO-CRYPTOREADER/account/admin.py create mode 100644 DJANGO-CRYPTOREADER/account/apps.py create mode 100644 DJANGO-CRYPTOREADER/account/migrations/__init__.py create mode 100644 DJANGO-CRYPTOREADER/account/models.py create mode 100644 DJANGO-CRYPTOREADER/account/serializers.py create mode 100644 DJANGO-CRYPTOREADER/account/tests.py create mode 100644 DJANGO-CRYPTOREADER/account/urls.py create mode 100644 DJANGO-CRYPTOREADER/account/views.py create mode 100644 DJANGO-CRYPTOREADER/manage.py create mode 100644 DJANGO-CRYPTOREADER/requirements.txt diff --git a/DJANGO-CRYPTOREADER/.gitignore b/DJANGO-CRYPTOREADER/.gitignore new file mode 100644 index 0000000..b7b620e --- /dev/null +++ b/DJANGO-CRYPTOREADER/.gitignore @@ -0,0 +1,140 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST +.idea +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +/static +/media +/Encryptor/SecurityAuthenticator.py +/Encryptor/sym.py +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.venv +venv/ +ENV/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + + +#celery beat +celerybeat-schedule.dir +celerybeat-schedule.dat +celerybeat-schedule.bak + +/db +supervisor/supervisord.pid +supervisor/* \ No newline at end of file diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/__init__.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/asgi.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/asgi.py new file mode 100644 index 0000000..b366cba --- /dev/null +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for DjangoCryptoReader project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoCryptoReader.settings') + +application = get_asgi_application() diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py new file mode 100644 index 0000000..dd26363 --- /dev/null +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py @@ -0,0 +1,125 @@ +""" +Django settings for DjangoCryptoReader project. + +Generated by 'django-admin startproject' using Django 4.1.1. + +For more information on this file, see +https://docs.djangoproject.com/en/4.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.1/ref/settings/ +""" + +from pathlib import Path +from decouple import config + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = config('SECRET_KEY') + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'DjangoCryptoReader.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'DjangoCryptoReader.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.1/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.1/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py new file mode 100644 index 0000000..7ed3213 --- /dev/null +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py @@ -0,0 +1,21 @@ +"""DjangoCryptoReader URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path + +urlpatterns = [ + path('admin/', admin.site.urls), +] diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/wsgi.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/wsgi.py new file mode 100644 index 0000000..eccbe6e --- /dev/null +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for DjangoCryptoReader project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoCryptoReader.settings') + +application = get_wsgi_application() diff --git a/DJANGO-CRYPTOREADER/README.md b/DJANGO-CRYPTOREADER/README.md new file mode 100644 index 0000000..1fb5bf9 --- /dev/null +++ b/DJANGO-CRYPTOREADER/README.md @@ -0,0 +1,30 @@ +# In name of Allah + +## Introduction +We want to develop a REST based django application to read signed in user's KuCoin open positions for them. For this to happen, you must be able to read user's positions (if requested from user) every 30 seconds. + +The application you develop must have these features: +- Users should be able to **sign up** (provide name, username & kucoin details). +- Users should be able to **sign in**. +- Users should be able to **request position tracking**. +- Users should be able to **see list** of current open positions. +- Application should be able to track user's positions every 30 seconds. +- Application should be able to handle multi users. +- Application must be able to resume its job after restart. + +You can use [this api](https://docs.kucoin.com/#list-accounts) from KuCoin to handle this. You should create KuCoin account if you do not have already & get api key & secret to test your implementation. Note we do not need your api key, that is only for your own usage. + +### Note +- We do **NOT want any kind of UI** from you +- KuCoin api key & secrets should not be stored in raw format + + +## Expectations: +We want a clean, readable and maintainable code with meaningful comments and docstrings. Also you need to provide postman API doc for web app. + +## Task +1. Fork this repository +2. Develop the challenge with Django 3 or higher +3. Push your code to your repository +4. Send us a pull request, we will review and get back to you +5. Enjoy diff --git a/DJANGO-CRYPTOREADER/account/__init__.py b/DJANGO-CRYPTOREADER/account/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/DJANGO-CRYPTOREADER/account/admin.py b/DJANGO-CRYPTOREADER/account/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/DJANGO-CRYPTOREADER/account/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/DJANGO-CRYPTOREADER/account/apps.py b/DJANGO-CRYPTOREADER/account/apps.py new file mode 100644 index 0000000..2b08f1a --- /dev/null +++ b/DJANGO-CRYPTOREADER/account/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AccountConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'account' diff --git a/DJANGO-CRYPTOREADER/account/migrations/__init__.py b/DJANGO-CRYPTOREADER/account/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/DJANGO-CRYPTOREADER/account/models.py b/DJANGO-CRYPTOREADER/account/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/DJANGO-CRYPTOREADER/account/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/DJANGO-CRYPTOREADER/account/serializers.py b/DJANGO-CRYPTOREADER/account/serializers.py new file mode 100644 index 0000000..e69de29 diff --git a/DJANGO-CRYPTOREADER/account/tests.py b/DJANGO-CRYPTOREADER/account/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/DJANGO-CRYPTOREADER/account/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/DJANGO-CRYPTOREADER/account/urls.py b/DJANGO-CRYPTOREADER/account/urls.py new file mode 100644 index 0000000..e69de29 diff --git a/DJANGO-CRYPTOREADER/account/views.py b/DJANGO-CRYPTOREADER/account/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/DJANGO-CRYPTOREADER/account/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/DJANGO-CRYPTOREADER/manage.py b/DJANGO-CRYPTOREADER/manage.py new file mode 100644 index 0000000..7be8b6e --- /dev/null +++ b/DJANGO-CRYPTOREADER/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoCryptoReader.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/DJANGO-CRYPTOREADER/requirements.txt b/DJANGO-CRYPTOREADER/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6e35fe201e2b12fdc8beaa39463a6e5c3a7fee5 GIT binary patch literal 318 zcmYk1%?^S<420)w;-g3ee{SA<5fo5F0Rdy=;nlC*V9chQ?sjH6^LeN0byBHLxeDz# zD@EE+iRPN=pj1ayYSn-lKt~$sYw#s^L2s<3Ga|*#+Uo+ZMmbE^Ok*$8%>Jgfw@0@? zJ=KlZ(>GN=FR?ocx~*Pd&%S?wPL8)m58PepC-+kg}BYlnlt UwiM Date: Wed, 21 Sep 2022 16:52:37 +0430 Subject: [PATCH 2/7] Add auth api --- .../DjangoCryptoReader/settings.py | 1 + .../DjangoCryptoReader/urls.py | 3 +- .../account/migrations/0001_initial.py | 35 +++++++++ DJANGO-CRYPTOREADER/account/models.py | 68 +++++++++++++++++- DJANGO-CRYPTOREADER/account/serializers.py | 50 +++++++++++++ DJANGO-CRYPTOREADER/account/urls.py | 7 ++ .../account/utils/cryptography.py | 42 +++++++++++ .../account/utils/random-key.txt | 0 DJANGO-CRYPTOREADER/account/views.py | 38 +++++++++- DJANGO-CRYPTOREADER/requirements.txt | Bin 318 -> 424 bytes 10 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 DJANGO-CRYPTOREADER/account/migrations/0001_initial.py create mode 100644 DJANGO-CRYPTOREADER/account/utils/cryptography.py create mode 100644 DJANGO-CRYPTOREADER/account/utils/random-key.txt diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py index dd26363..2b03ffc 100644 --- a/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py @@ -39,6 +39,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', + 'account', ] MIDDLEWARE = [ diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py index 7ed3213..a077d7b 100644 --- a/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py @@ -14,8 +14,9 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), + path('account/', include('account.urls')), ] diff --git a/DJANGO-CRYPTOREADER/account/migrations/0001_initial.py b/DJANGO-CRYPTOREADER/account/migrations/0001_initial.py new file mode 100644 index 0000000..6a8d2e9 --- /dev/null +++ b/DJANGO-CRYPTOREADER/account/migrations/0001_initial.py @@ -0,0 +1,35 @@ +# Generated by Django 4.1.1 on 2022-09-21 06:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('username', models.CharField(max_length=64, unique=True, verbose_name='user name')), + ('name', models.CharField(blank=True, max_length=64, null=True, verbose_name='name')), + ('last_login', models.DateTimeField(auto_now=True, verbose_name='update at')), + ('joined_at', models.DateTimeField(auto_now_add=True, verbose_name='joined at')), + ('is_active', models.BooleanField(default=True)), + ('is_superuser', models.BooleanField(default=False)), + ('is_staff', models.BooleanField(default=False)), + ('kucoin_pass_pharese', models.CharField(max_length=256, verbose_name='pass phrase')), + ('kucoin_api_key', models.CharField(max_length=256, verbose_name='api key')), + ('kucoin_api_secret', models.CharField(max_length=256, verbose_name='api secret')), + ], + options={ + 'verbose_name': 'User', + 'verbose_name_plural': 'Users', + }, + ), + ] diff --git a/DJANGO-CRYPTOREADER/account/models.py b/DJANGO-CRYPTOREADER/account/models.py index 71a8362..a9b6a60 100644 --- a/DJANGO-CRYPTOREADER/account/models.py +++ b/DJANGO-CRYPTOREADER/account/models.py @@ -1,3 +1,69 @@ from django.db import models +from django.contrib.auth.models import AbstractBaseUser, BaseUserManager +from .utils.cryptography import encrypt_message,decrypt_message -# Create your models here. + +class CustomManager(BaseUserManager): + def create_user(self, username, kucoin_pass_pharese, kucoin_api_key, kucoin_api_secret, password=None): + if not username: + raise ValueError("Username is Required.") + user = self.model( + username=username, + ) + user.save(using=self._db) + user.set_password(password) + user.kucoin_pass_pharese = encrypt_message(kucoin_pass_pharese) + user.kucoin_api_key = encrypt_message(kucoin_api_key) + user.kucoin_api_secret = encrypt_message(kucoin_api_secret) + user.save() + return user + + def create_superuser(self, username, kucoin_pass_pharese, kucoin_api_key, kucoin_api_secret, password=None): + if not username: + raise ValueError("Username is required.") + user = self.model( + username=username, + ) + user.save(using=self._db) + user.set_password(password) + user.kucoin_pass_pharese = Cipher.encrypt_message(kucoin_pass_pharese) + user.kucoin_api_key = Cipher.encrypt_message(kucoin_api_key) + user.kucoin_api_secret = Cipher.encrypt_message(kucoin_api_secret) + user.is_staff = True + user.is_superuser = True + user.save() + return user + + +class User(AbstractBaseUser): + # base information + username = models.CharField( + max_length=64, unique=True, verbose_name='user name') + name = models.CharField(max_length=64, null=True, + blank=True, verbose_name='name') + + # extra information + last_login = models.DateTimeField(auto_now=True, verbose_name='update at') + joined_at = models.DateTimeField( + auto_now_add=True, verbose_name='joined at') + is_active = models.BooleanField(default=True) + is_superuser = models.BooleanField(default=False) + is_staff = models.BooleanField(default=False) + + # kucoin details + kucoin_pass_pharese = models.CharField( + max_length=256, verbose_name='pass phrase') + kucoin_api_key = models.CharField(max_length=256, verbose_name='api key') + kucoin_api_secret = models.CharField( + max_length=256, verbose_name='api secret') + + USERNAME_FIELD = 'username' + + objects = CustomManager() + + def __str__(self) -> str: + return f'user name = {self.username}' + + class Meta: + verbose_name = 'User' + verbose_name_plural = 'Users' diff --git a/DJANGO-CRYPTOREADER/account/serializers.py b/DJANGO-CRYPTOREADER/account/serializers.py index e69de29..65e41c1 100644 --- a/DJANGO-CRYPTOREADER/account/serializers.py +++ b/DJANGO-CRYPTOREADER/account/serializers.py @@ -0,0 +1,50 @@ +from .utils.cryptography import encrypt_message, decrypt_message +from rest_framework.serializers import ModelSerializer +from django.contrib.auth import authenticate +from rest_framework.exceptions import ValidationError +from .models import User + + +class RegisterSerializer(ModelSerializer): + + class Meta: + model = User + fields = ('username', 'password', 'kucoin_api_secret', + 'kucoin_api_key', 'kucoin_pass_pharese') + + # def save(self): + # username = self.validated_data['username'] + # password = encrypt_message(str(self.validated_data['password'])) + # kucoin_api_secret = decrypt_message( + # self.validated_data['password']) + # return super().save(**self.validated_data) + + def validate(self, attrs): + if not attrs.get('username'): + raise ValueError('username is required') + if not attrs.get('password'): + raise ValueError('password is required') + if not attrs.get('kucoin_api_secret'): + raise ValueError('kucoin_api_secret is required') + if not attrs.get('kucoin_api_key'): + raise ValueError('kucoin_api_key is required') + if not attrs.get('kucoin_pass_pharese'): + raise ValueError('kucoin_pass_pharese is required') + + return super().validate(attrs) + + +class LoginSerializer(ModelSerializer): + class Meta: + model = User + fields = ('username',) + + def validate(self, attrs): + username = attrs.get('username') + password = attrs.get('password') + if not User.objects.filter(username=username): + raise ValueError("you dont register with this user name") + + user = authenticate(username=username, password=password) + if user: + return user.tokens diff --git a/DJANGO-CRYPTOREADER/account/urls.py b/DJANGO-CRYPTOREADER/account/urls.py index e69de29..9aee171 100644 --- a/DJANGO-CRYPTOREADER/account/urls.py +++ b/DJANGO-CRYPTOREADER/account/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from .views import RegisterView, LoginView + +urlpatterns = [ + path('sign-up/', RegisterView.as_view()), + path('sign-in/', LoginView.as_view()), +] diff --git a/DJANGO-CRYPTOREADER/account/utils/cryptography.py b/DJANGO-CRYPTOREADER/account/utils/cryptography.py new file mode 100644 index 0000000..1014e88 --- /dev/null +++ b/DJANGO-CRYPTOREADER/account/utils/cryptography.py @@ -0,0 +1,42 @@ +import re +from cryptography.fernet import Fernet + + +def generate_key(): + """ + Generates a key and save it into a file + """ + + key = Fernet.generate_key() + with open("random-key.txt", "wb") as key_file: + key_file.write(key) + + +def load_key(): + """ + Load the previously generated key + """ + return open("random-key.txt", "rb").read() + + +def encrypt_message(message): + """ + Encrypts a message + """ + key = load_key() + encoded_message = message.encode() + f = Fernet(key) + encrypted_message = f.encrypt(encoded_message) + + print(encrypted_message) + return encrypted_message + + +def decrypt_message(encrypted_message): + """ + Decrypts an encrypted message + """ + key = load_key() + f = Fernet(key) + decrypted_message = f.decrypt(encrypted_message) + return decrypted_message diff --git a/DJANGO-CRYPTOREADER/account/utils/random-key.txt b/DJANGO-CRYPTOREADER/account/utils/random-key.txt new file mode 100644 index 0000000..e69de29 diff --git a/DJANGO-CRYPTOREADER/account/views.py b/DJANGO-CRYPTOREADER/account/views.py index 91ea44a..ec9a0dd 100644 --- a/DJANGO-CRYPTOREADER/account/views.py +++ b/DJANGO-CRYPTOREADER/account/views.py @@ -1,3 +1,39 @@ from django.shortcuts import render +from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED +from rest_framework.response import Response +from rest_framework.generics import CreateAPIView +from rest_framework.views import APIView +from .models import User +from .serializers import RegisterSerializer, LoginSerializer -# Create your views here. + +class RegisterView(CreateAPIView): + serializer_class = RegisterSerializer + + def create(self, request, *args, **kwargs): + serializer = self.serializer_class(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save() + return Response( + data='registeration done successfully.', + status=HTTP_201_CREATED + ) + + +class LoginView(APIView): + # def get_serializer_context(self): + # """ + # Extra context provided to the serializer class. + # """ + # return { + # 'username': self.request.data['username'], + # 'password': self.request.data['password'], + # } + + def post(self, request, *args, **kwargs): + serializer = LoginSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + return Response( + data='login done successfully.', + status=HTTP_200_OK + ) diff --git a/DJANGO-CRYPTOREADER/requirements.txt b/DJANGO-CRYPTOREADER/requirements.txt index f6e35fe201e2b12fdc8beaa39463a6e5c3a7fee5..ba2c2008c968074224395973124086c2af623eea 100644 GIT binary patch delta 100 zcmdnTw1Rm;gncqY8W3hO*aD#;gB}o@f=ONmE{0@=B8Eza0)`TXe1>!&I}ymv0E&Rr i8Z%e`)fr6mPZduF3MT@kiy2aZBuLT-C}lKp Date: Thu, 22 Sep 2022 19:05:25 +0330 Subject: [PATCH 3/7] Add order api --- .../DjangoCryptoReader/urls.py | 1 + DJANGO-CRYPTOREADER/account/models.py | 6 +- DJANGO-CRYPTOREADER/order/__init__.py | 0 DJANGO-CRYPTOREADER/order/admin.py | 3 + DJANGO-CRYPTOREADER/order/apps.py | 6 ++ .../order/migrations/__init__.py | 0 DJANGO-CRYPTOREADER/order/models.py | 67 +++++++++++++++++++ DJANGO-CRYPTOREADER/order/serializers.py | 10 +++ DJANGO-CRYPTOREADER/order/tests.py | 3 + DJANGO-CRYPTOREADER/order/urls.py | 6 ++ DJANGO-CRYPTOREADER/order/utils/utility.py | 43 ++++++++++++ DJANGO-CRYPTOREADER/order/views.py | 8 +++ 12 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 DJANGO-CRYPTOREADER/order/__init__.py create mode 100644 DJANGO-CRYPTOREADER/order/admin.py create mode 100644 DJANGO-CRYPTOREADER/order/apps.py create mode 100644 DJANGO-CRYPTOREADER/order/migrations/__init__.py create mode 100644 DJANGO-CRYPTOREADER/order/models.py create mode 100644 DJANGO-CRYPTOREADER/order/serializers.py create mode 100644 DJANGO-CRYPTOREADER/order/tests.py create mode 100644 DJANGO-CRYPTOREADER/order/urls.py create mode 100644 DJANGO-CRYPTOREADER/order/utils/utility.py create mode 100644 DJANGO-CRYPTOREADER/order/views.py diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py index a077d7b..93e7677 100644 --- a/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/urls.py @@ -19,4 +19,5 @@ urlpatterns = [ path('admin/', admin.site.urls), path('account/', include('account.urls')), + path('ordrer/', include('order.urls')), ] diff --git a/DJANGO-CRYPTOREADER/account/models.py b/DJANGO-CRYPTOREADER/account/models.py index a9b6a60..84f775d 100644 --- a/DJANGO-CRYPTOREADER/account/models.py +++ b/DJANGO-CRYPTOREADER/account/models.py @@ -26,9 +26,9 @@ def create_superuser(self, username, kucoin_pass_pharese, kucoin_api_key, kucoin ) user.save(using=self._db) user.set_password(password) - user.kucoin_pass_pharese = Cipher.encrypt_message(kucoin_pass_pharese) - user.kucoin_api_key = Cipher.encrypt_message(kucoin_api_key) - user.kucoin_api_secret = Cipher.encrypt_message(kucoin_api_secret) + user.kucoin_pass_pharese = encrypt_message(kucoin_pass_pharese) + user.kucoin_api_key = encrypt_message(kucoin_api_key) + user.kucoin_api_secret = encrypt_message(kucoin_api_secret) user.is_staff = True user.is_superuser = True user.save() diff --git a/DJANGO-CRYPTOREADER/order/__init__.py b/DJANGO-CRYPTOREADER/order/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/DJANGO-CRYPTOREADER/order/admin.py b/DJANGO-CRYPTOREADER/order/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/DJANGO-CRYPTOREADER/order/apps.py b/DJANGO-CRYPTOREADER/order/apps.py new file mode 100644 index 0000000..42888e4 --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class OrderConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'order' diff --git a/DJANGO-CRYPTOREADER/order/migrations/__init__.py b/DJANGO-CRYPTOREADER/order/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/DJANGO-CRYPTOREADER/order/models.py b/DJANGO-CRYPTOREADER/order/models.py new file mode 100644 index 0000000..9c59d5e --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/models.py @@ -0,0 +1,67 @@ +from asyncio.constants import ACCEPT_RETRY_DELAY +from django.db import models + + +class Order(models.Model): + ACTIVE = 'active' + DONE = 'done' + ORDER_STATUS_CHOICES = ( + (ACTIVE, 'پرداخت نشده'), + (DONE, 'در انتظار ایجاد محتوا'), + ) + + BUY = 'buy' + SELL = 'sell' + ORDER_SIDE_CHOICES = ( + (BUY, 'خرید'), + (SELL, 'فروش'), + ) + + LIMIT = 'limit' + MARKET = 'market' + LIMIT_STOP = 'limit_stop' + MARKET_STOP = 'market_stop' + ORDER_TYPE_CHOICES = ((LIMIT, 'لیمیت'), (MARKET, 'مارکت'), + (MARKET_STOP, 'لیمیت استاپ'), + (LIMIT_STOP, 'مارکت استاپ')) + + TRADE = 'trades' + MARGIN_TRADE = 'margin_trade' + ORDER_TRADE_TYPE_CHOICES = ((TRADE, 'ترید'), + (MARGIN_TRADE, 'مارجین ترید')) + + status = models.CharField( + verbose_name='وضعیت', + max_length=64, + choices=ORDER_STATUS_CHOICES, + default=ACTIVE, + ) + symbol = models.CharField(max_length=64, null=True, + blank=True, verbose_name='نام ارز') + side = models.ChoiceField( + verbose_name='وضعیت خرید', + max_length=64, + choices=ORDER_SIDE_CHOICES, + default=BUY, + ) + type = models.ChoiceField( + verbose_name='نوع سفارش', + max_length=64, + choices=ORDER_TYPE_CHOICES, + default=LIMIT, + ) + tradeType = models.ChoiceField( + verbose_name='نوع سفارش', + max_length=64, + choices=ORDER_TRADE_TYPE_CHOICES, + default=TRADE, + ) + startAt = models.DateTimeField(blank=True, null=True) + endAt = models.DateTimeField(blank=True, null=True) + + def __str__(self) -> str: + return f'symbol = {self.symbol}' + + class Meta: + verbose_name = 'Order' + verbose_name_plural = 'Orders' diff --git a/DJANGO-CRYPTOREADER/order/serializers.py b/DJANGO-CRYPTOREADER/order/serializers.py new file mode 100644 index 0000000..e1757d9 --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/serializers.py @@ -0,0 +1,10 @@ +from pyexpat import model +from .models import Order +from rest_framework.serializers import ModelSerializer + + +class OrderSerializer(ModelSerializer): + + class Meta: + model = Order + fields = '__all__' diff --git a/DJANGO-CRYPTOREADER/order/tests.py b/DJANGO-CRYPTOREADER/order/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/DJANGO-CRYPTOREADER/order/urls.py b/DJANGO-CRYPTOREADER/order/urls.py new file mode 100644 index 0000000..1ac5911 --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/urls.py @@ -0,0 +1,6 @@ +from django.urls import path, include +from .views import OrderView + +urlpatterns = [ + path('order-list/', OrderView.as_view({'post': 'create', 'get': 'list'})), +] diff --git a/DJANGO-CRYPTOREADER/order/utils/utility.py b/DJANGO-CRYPTOREADER/order/utils/utility.py new file mode 100644 index 0000000..f5dcc51 --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/utils/utility.py @@ -0,0 +1,43 @@ +import time + +class CallAPI(): + """ + every thing base on this documentation: + https://www.kucoin.com/support/900006465403-KuCoin-API-key-upgrade-operation-guide + """ + def __init__(self, user, endpoint, http_method, query_params, sandbox): + self.user = user + self.endpoint = endpoint + self.http_method = http_method + self.query_params = query_params + self.sandbox = sandbox + + def create_signature(self): + """ + Use API-Secret to encrypt the prehash string + {timestamp + method + endpoint + body} with sha256 HMAC. + The request body is a JSON string and needs to be the same as the parameters passed by the API + """ + + def create_header(self): + """ + All private REST requests must contain the following headers: + KC-API-KEY The API key as a string. + KC-API-SIGN The base64-encoded signature (see Signing a Message). + KC-API-TIMESTAMP A timestamp for your request. + KC-API-PASSPHRASE The passphrase you specified when creating the API key. + KC-API-KEY-VERSION You can check the version of API key on the page of API Management + + """ + return { + # "KC-API-SIGN": + "KC-API-TIMESTAMP": str(int(time.time() * 1000)), + "KC-API-KEY": self.user.get('kucoin_api_key'), + "KC-API-PASSPHRASE": self.user.get('kucoin_pass_pharese'), + "KC-API-KEY-VERSION": "2" + } + + def create_request(self): + if self.sandbox: + return "https://openapi-sandbox.kucoin.com" + self.endpoint + return "https://api.kucoin.com" + self.endpoint diff --git a/DJANGO-CRYPTOREADER/order/views.py b/DJANGO-CRYPTOREADER/order/views.py new file mode 100644 index 0000000..8376f92 --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/views.py @@ -0,0 +1,8 @@ + +from rest_framework.viewsets import ModelViewSet +from .serializers import OrderSerializer + + +class CampaignViewSet(ModelViewSet): + serializer_class = OrderSerializer + From dc060854001b5779ed86e877598ee24ec365fdc0 Mon Sep 17 00:00:00 2001 From: Elo-No Date: Thu, 22 Sep 2022 23:32:03 +0330 Subject: [PATCH 4/7] Fix auth api --- .../DjangoCryptoReader/settings.py | 1 + DJANGO-CRYPTOREADER/account/models.py | 27 ++++---- DJANGO-CRYPTOREADER/account/serializers.py | 65 ++++++++++++++----- DJANGO-CRYPTOREADER/account/urls.py | 2 +- .../utils/{cryptography.py => utility.py} | 19 +++--- DJANGO-CRYPTOREADER/account/views.py | 54 +++++++-------- 6 files changed, 101 insertions(+), 67 deletions(-) rename DJANGO-CRYPTOREADER/account/utils/{cryptography.py => utility.py} (50%) diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py index 2b03ffc..c7ee3e3 100644 --- a/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py @@ -40,6 +40,7 @@ 'django.contrib.staticfiles', 'rest_framework', 'account', + 'order', ] MIDDLEWARE = [ diff --git a/DJANGO-CRYPTOREADER/account/models.py b/DJANGO-CRYPTOREADER/account/models.py index 84f775d..8f1ecc7 100644 --- a/DJANGO-CRYPTOREADER/account/models.py +++ b/DJANGO-CRYPTOREADER/account/models.py @@ -1,6 +1,6 @@ from django.db import models from django.contrib.auth.models import AbstractBaseUser, BaseUserManager -from .utils.cryptography import encrypt_message,decrypt_message +from .utils.utility import encrypt_message, decrypt_message class CustomManager(BaseUserManager): @@ -9,13 +9,13 @@ def create_user(self, username, kucoin_pass_pharese, kucoin_api_key, kucoin_api_ raise ValueError("Username is Required.") user = self.model( username=username, + kucoin_pass_pharese=encrypt_message(kucoin_pass_pharese), + kucoin_api_key=encrypt_message(kucoin_api_key), + kucoin_api_secret=encrypt_message(kucoin_api_secret), + ) - user.save(using=self._db) user.set_password(password) - user.kucoin_pass_pharese = encrypt_message(kucoin_pass_pharese) - user.kucoin_api_key = encrypt_message(kucoin_api_key) - user.kucoin_api_secret = encrypt_message(kucoin_api_secret) - user.save() + user.save(using=self._db) return user def create_superuser(self, username, kucoin_pass_pharese, kucoin_api_key, kucoin_api_secret, password=None): @@ -23,15 +23,15 @@ def create_superuser(self, username, kucoin_pass_pharese, kucoin_api_key, kucoin raise ValueError("Username is required.") user = self.model( username=username, + kucoin_pass_pharese=encrypt_message(kucoin_pass_pharese), + kucoin_api_key=encrypt_message(kucoin_api_key), + kucoin_api_secret=encrypt_message(kucoin_api_secret), + is_staff=True, + is_superuser=True, + ) - user.save(using=self._db) user.set_password(password) - user.kucoin_pass_pharese = encrypt_message(kucoin_pass_pharese) - user.kucoin_api_key = encrypt_message(kucoin_api_key) - user.kucoin_api_secret = encrypt_message(kucoin_api_secret) - user.is_staff = True - user.is_superuser = True - user.save() + user.save(using=self._db) return user @@ -64,6 +64,7 @@ class User(AbstractBaseUser): def __str__(self) -> str: return f'user name = {self.username}' + class Meta: verbose_name = 'User' verbose_name_plural = 'Users' diff --git a/DJANGO-CRYPTOREADER/account/serializers.py b/DJANGO-CRYPTOREADER/account/serializers.py index 65e41c1..919194d 100644 --- a/DJANGO-CRYPTOREADER/account/serializers.py +++ b/DJANGO-CRYPTOREADER/account/serializers.py @@ -1,23 +1,29 @@ -from .utils.cryptography import encrypt_message, decrypt_message -from rest_framework.serializers import ModelSerializer +from .utils.utility import encrypt_message, decrypt_message +from rest_framework import serializers from django.contrib.auth import authenticate from rest_framework.exceptions import ValidationError +from .utils.utility import encrypt_message, decrypt_message from .models import User -class RegisterSerializer(ModelSerializer): +class RegisterSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('username', 'password', 'kucoin_api_secret', 'kucoin_api_key', 'kucoin_pass_pharese') - # def save(self): - # username = self.validated_data['username'] - # password = encrypt_message(str(self.validated_data['password'])) - # kucoin_api_secret = decrypt_message( - # self.validated_data['password']) - # return super().save(**self.validated_data) + def create(self, validated_data): + user = super().create({ + 'username': self.validated_data['username'], + 'kucoin_api_secret': encrypt_message(str(self.validated_data['kucoin_api_secret'])), + 'kucoin_api_key': encrypt_message(str(self.validated_data['kucoin_api_key'])), + 'kucoin_pass_pharese': encrypt_message(str(self.validated_data['kucoin_pass_pharese'])), + } + ) + user.set_password(validated_data['password']) + user.save() + return user def validate(self, attrs): if not attrs.get('username'): @@ -34,17 +40,40 @@ def validate(self, attrs): return super().validate(attrs) -class LoginSerializer(ModelSerializer): - class Meta: - model = User - fields = ('username',) + +class LoginSerializer(serializers.Serializer): + """ + This serializer defines two fields used for authentication: username and password. + It will try to authenticate the user with username/password when validated. + """ + username = serializers.CharField( + label="Username", + write_only=True + ) + password = serializers.CharField( + label="Password", + style={'input_type': 'password'}, # This will be used when the DRF browsable API is enabled + trim_whitespace=False, + write_only=True + ) def validate(self, attrs): + # Take username and password from request username = attrs.get('username') password = attrs.get('password') - if not User.objects.filter(username=username): - raise ValueError("you dont register with this user name") - user = authenticate(username=username, password=password) - if user: - return user.tokens + if username and password: + # Try to authenticate the user using Django auth framework. + user = authenticate(request=self.context.get('request'), + username=username, password=password) + if not user: + # If we don't have a regular user, raise a ValidationError + msg = 'Access denied: wrong username or password.' + raise serializers.ValidationError(msg, code='authorization') + else: + msg = 'Both "username" and "password" are required.' + raise serializers.ValidationError(msg, code='authorization') + # We have a valid user, put it in the serializer's validated_data. + # It will be used in the view. + attrs['user'] = user + return attrs diff --git a/DJANGO-CRYPTOREADER/account/urls.py b/DJANGO-CRYPTOREADER/account/urls.py index 9aee171..ee9a0e0 100644 --- a/DJANGO-CRYPTOREADER/account/urls.py +++ b/DJANGO-CRYPTOREADER/account/urls.py @@ -2,6 +2,6 @@ from .views import RegisterView, LoginView urlpatterns = [ - path('sign-up/', RegisterView.as_view()), + path('sign-up/', RegisterView.as_view({'post': 'create'})), path('sign-in/', LoginView.as_view()), ] diff --git a/DJANGO-CRYPTOREADER/account/utils/cryptography.py b/DJANGO-CRYPTOREADER/account/utils/utility.py similarity index 50% rename from DJANGO-CRYPTOREADER/account/utils/cryptography.py rename to DJANGO-CRYPTOREADER/account/utils/utility.py index 1014e88..f076703 100644 --- a/DJANGO-CRYPTOREADER/account/utils/cryptography.py +++ b/DJANGO-CRYPTOREADER/account/utils/utility.py @@ -1,5 +1,6 @@ import re from cryptography.fernet import Fernet +from decouple import config def generate_key(): @@ -8,15 +9,15 @@ def generate_key(): """ key = Fernet.generate_key() - with open("random-key.txt", "wb") as key_file: - key_file.write(key) + # with open("random-key.txt", "wb") as key_file: + # key_file.write(key) def load_key(): """ Load the previously generated key """ - return open("random-key.txt", "rb").read() + return config('key') def encrypt_message(message): @@ -24,12 +25,11 @@ def encrypt_message(message): Encrypts a message """ key = load_key() - encoded_message = message.encode() f = Fernet(key) - encrypted_message = f.encrypt(encoded_message) + encrypted_message = f.encrypt(bytes(message, encoding='utf8')) - print(encrypted_message) - return encrypted_message + # print(encrypted_message.decode("utf-8")) + return encrypted_message.decode("utf-8") def decrypt_message(encrypted_message): @@ -38,5 +38,6 @@ def decrypt_message(encrypted_message): """ key = load_key() f = Fernet(key) - decrypted_message = f.decrypt(encrypted_message) - return decrypted_message + decrypted_message = f.decrypt(bytes(encrypted_message, encoding='utf8')) + # print(decrypted_message.decode("utf-8")) + return decrypted_message.decode("utf-8") diff --git a/DJANGO-CRYPTOREADER/account/views.py b/DJANGO-CRYPTOREADER/account/views.py index ec9a0dd..a92b81b 100644 --- a/DJANGO-CRYPTOREADER/account/views.py +++ b/DJANGO-CRYPTOREADER/account/views.py @@ -1,39 +1,41 @@ -from django.shortcuts import render from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED from rest_framework.response import Response from rest_framework.generics import CreateAPIView from rest_framework.views import APIView +from rest_framework.viewsets import ModelViewSet from .models import User +from django.contrib.auth import login +from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED , HTTP_202_ACCEPTED from .serializers import RegisterSerializer, LoginSerializer +from rest_framework.exceptions import NotFound -class RegisterView(CreateAPIView): - serializer_class = RegisterSerializer +class RegisterView(ModelViewSet): + + def get_queryset(self): + try: + user = User.objects.get(username=self.request.user.username) + except User.DoesNotExist: + raise NotFound('User not found.') + + def get_serializer_class(self): + if self.action in ['create']: + return RegisterSerializer + + def perform_create(self, serializer): + serializer = serializer.save(data=self.request.data) + return serializer + - def create(self, request, *args, **kwargs): - serializer = self.serializer_class(data=request.data) - serializer.is_valid(raise_exception=True) - serializer.save() - return Response( - data='registeration done successfully.', - status=HTTP_201_CREATED - ) class LoginView(APIView): - # def get_serializer_context(self): - # """ - # Extra context provided to the serializer class. - # """ - # return { - # 'username': self.request.data['username'], - # 'password': self.request.data['password'], - # } - - def post(self, request, *args, **kwargs): - serializer = LoginSerializer(data=request.data) + # This view should be accessible also for unauthenticated users. + # permission_classes = (permissions.AllowAny,) + + def post(self, request, format=None): + serializer = LoginSerializer(data=self.request.data, context={ 'request': self.request }) serializer.is_valid(raise_exception=True) - return Response( - data='login done successfully.', - status=HTTP_200_OK - ) + user = serializer.validated_data['user'] + login(request, user) + return Response(None, status=HTTP_202_ACCEPTED) From d4e9d394dd5dce8701caefe2a7a99bf124a97adb Mon Sep 17 00:00:00 2001 From: Elo-No Date: Fri, 23 Sep 2022 16:02:02 +0330 Subject: [PATCH 5/7] Fix open order api --- .../order/migrations/0001_initial.py | 28 ++++++++ DJANGO-CRYPTOREADER/order/models.py | 69 ++++--------------- DJANGO-CRYPTOREADER/order/serializers.py | 2 +- DJANGO-CRYPTOREADER/order/urls.py | 7 +- DJANGO-CRYPTOREADER/order/utils/utility.py | 31 +++++++-- DJANGO-CRYPTOREADER/order/views.py | 32 +++++++-- 6 files changed, 100 insertions(+), 69 deletions(-) create mode 100644 DJANGO-CRYPTOREADER/order/migrations/0001_initial.py diff --git a/DJANGO-CRYPTOREADER/order/migrations/0001_initial.py b/DJANGO-CRYPTOREADER/order/migrations/0001_initial.py new file mode 100644 index 0000000..df27e12 --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# Generated by Django 4.1.1 on 2022-09-23 12:13 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Order', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('symbol', models.CharField(blank=True, max_length=64, null=True, verbose_name='symbol')), + ('autoDeposit', models.BooleanField(default=False, verbose_name='auto deposit ?')), + ('isOpen', models.BooleanField(default=False, verbose_name='is open ?')), + ], + options={ + 'verbose_name': 'Order', + 'verbose_name_plural': 'Orders', + }, + ), + ] diff --git a/DJANGO-CRYPTOREADER/order/models.py b/DJANGO-CRYPTOREADER/order/models.py index 9c59d5e..a901ff2 100644 --- a/DJANGO-CRYPTOREADER/order/models.py +++ b/DJANGO-CRYPTOREADER/order/models.py @@ -1,67 +1,24 @@ -from asyncio.constants import ACCEPT_RETRY_DELAY + from django.db import models +import uuid class Order(models.Model): - ACTIVE = 'active' - DONE = 'done' - ORDER_STATUS_CHOICES = ( - (ACTIVE, 'پرداخت نشده'), - (DONE, 'در انتظار ایجاد محتوا'), - ) - - BUY = 'buy' - SELL = 'sell' - ORDER_SIDE_CHOICES = ( - (BUY, 'خرید'), - (SELL, 'فروش'), - ) - - LIMIT = 'limit' - MARKET = 'market' - LIMIT_STOP = 'limit_stop' - MARKET_STOP = 'market_stop' - ORDER_TYPE_CHOICES = ((LIMIT, 'لیمیت'), (MARKET, 'مارکت'), - (MARKET_STOP, 'لیمیت استاپ'), - (LIMIT_STOP, 'مارکت استاپ')) + """ + based on this docs: just define some fileds not all of them + https://docs.kucoin.com/futures/#get-position-list + """ - TRADE = 'trades' - MARGIN_TRADE = 'margin_trade' - ORDER_TRADE_TYPE_CHOICES = ((TRADE, 'ترید'), - (MARGIN_TRADE, 'مارجین ترید')) - - status = models.CharField( - verbose_name='وضعیت', - max_length=64, - choices=ORDER_STATUS_CHOICES, - default=ACTIVE, - ) - symbol = models.CharField(max_length=64, null=True, - blank=True, verbose_name='نام ارز') - side = models.ChoiceField( - verbose_name='وضعیت خرید', - max_length=64, - choices=ORDER_SIDE_CHOICES, - default=BUY, - ) - type = models.ChoiceField( - verbose_name='نوع سفارش', - max_length=64, - choices=ORDER_TYPE_CHOICES, - default=LIMIT, - ) - tradeType = models.ChoiceField( - verbose_name='نوع سفارش', - max_length=64, - choices=ORDER_TRADE_TYPE_CHOICES, - default=TRADE, - ) - startAt = models.DateTimeField(blank=True, null=True) - endAt = models.DateTimeField(blank=True, null=True) + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + symbol = models.CharField(max_length=64, null=True,blank=True, verbose_name='symbol') + autoDeposit = models.BooleanField(default=False, verbose_name='auto deposit ?') + isOpen = models.BooleanField(default=False, verbose_name='is open ?') def __str__(self) -> str: - return f'symbol = {self.symbol}' + return f'id = {self.id} , symbol = {self.symbol}' class Meta: verbose_name = 'Order' verbose_name_plural = 'Orders' + + diff --git a/DJANGO-CRYPTOREADER/order/serializers.py b/DJANGO-CRYPTOREADER/order/serializers.py index e1757d9..8b3640e 100644 --- a/DJANGO-CRYPTOREADER/order/serializers.py +++ b/DJANGO-CRYPTOREADER/order/serializers.py @@ -3,7 +3,7 @@ from rest_framework.serializers import ModelSerializer -class OrderSerializer(ModelSerializer): +class OpenOrderSerializer(ModelSerializer): class Meta: model = Order diff --git a/DJANGO-CRYPTOREADER/order/urls.py b/DJANGO-CRYPTOREADER/order/urls.py index 1ac5911..b44356b 100644 --- a/DJANGO-CRYPTOREADER/order/urls.py +++ b/DJANGO-CRYPTOREADER/order/urls.py @@ -1,6 +1,9 @@ from django.urls import path, include -from .views import OrderView +from .views import OpenOrderView urlpatterns = [ - path('order-list/', OrderView.as_view({'post': 'create', 'get': 'list'})), + path('open-position/', + OpenOrderView.as_view({'post': 'create', 'get': 'list'})), + # path('list-order/', OrderView.as_view({'post': 'create', 'get': 'list'})), + ] diff --git a/DJANGO-CRYPTOREADER/order/utils/utility.py b/DJANGO-CRYPTOREADER/order/utils/utility.py index f5dcc51..c33a2b3 100644 --- a/DJANGO-CRYPTOREADER/order/utils/utility.py +++ b/DJANGO-CRYPTOREADER/order/utils/utility.py @@ -1,10 +1,19 @@ import time +import base64 +import hashlib +import hmac +import time +import urllib.parse +import requests +from account.utils.utility import encrypt_message + class CallAPI(): """ every thing base on this documentation: https://www.kucoin.com/support/900006465403-KuCoin-API-key-upgrade-operation-guide """ + def __init__(self, user, endpoint, http_method, query_params, sandbox): self.user = user self.endpoint = endpoint @@ -18,6 +27,12 @@ def create_signature(self): {timestamp + method + endpoint + body} with sha256 HMAC. The request body is a JSON string and needs to be the same as the parameters passed by the API """ + api_secret = encrypt_message(self.user.get('kucoin_api_secret')) + str_to_sign = str(time.time() * 1000) + self.method + \ + self.endpoint + '?' + urllib.parse.urlencode(self.params) + signature = base64.b64encode( + hmac.new(api_secret.encode('utf-8'), str_to_sign.encode('utf-8'), hashlib.sha256).digest()) + return signature def create_header(self): """ @@ -30,14 +45,20 @@ def create_header(self): """ return { - # "KC-API-SIGN": + "KC-API-SIGN": self.create_signature(), "KC-API-TIMESTAMP": str(int(time.time() * 1000)), - "KC-API-KEY": self.user.get('kucoin_api_key'), - "KC-API-PASSPHRASE": self.user.get('kucoin_pass_pharese'), + "KC-API-KEY": encrypt_message(self.user.get('kucoin_api_key')), + "KC-API-PASSPHRASE": encrypt_message(self.user.get('kucoin_pass_pharese')), "KC-API-KEY-VERSION": "2" } def create_request(self): if self.sandbox: - return "https://openapi-sandbox.kucoin.com" + self.endpoint - return "https://api.kucoin.com" + self.endpoint + base_url = "https://openapi-sandbox.kucoin.com" + self.endpoint + base_url = "https://api.kucoin.com" + self.endpoint + + response = requests.request( + self.http_method, base_url, headers=self.create_header(), params=self.params) + if response.status_code != 200: + raise Exception('Error Happned') + return response.json() diff --git a/DJANGO-CRYPTOREADER/order/views.py b/DJANGO-CRYPTOREADER/order/views.py index 8376f92..ca008aa 100644 --- a/DJANGO-CRYPTOREADER/order/views.py +++ b/DJANGO-CRYPTOREADER/order/views.py @@ -1,8 +1,30 @@ - +from rest_framework.response import Response +from rest_framework.status import HTTP_200_OK from rest_framework.viewsets import ModelViewSet -from .serializers import OrderSerializer +from .serializers import OpenOrderSerializer +from .models import Order +from .utils.utility import CallAPI +from account.models import User +from rest_framework.exceptions import NotFound + + +class OpenOrderView(ModelViewSet): + + def get_queryset(self): + return Order.objects.filter(isOpen=True) + + def get_serializer_class(self): + if self.action in ['create']: + return OpenOrderSerializer + def perform_create(self, serializer): + # data = self.request.data + user = self.request.user + data = CallAPI(user, '/api/v1/positions', 'GET', None, True) + data.create_request() -class CampaignViewSet(ModelViewSet): - serializer_class = OrderSerializer - + if data: + serializer = serializer.save(data=data) + # return serializer + return Response('done', status=HTTP_200_OK) + return Response('error') From 48213c855f69a33767857f1763d91d9b03be7885 Mon Sep 17 00:00:00 2001 From: Elo-No Date: Sat, 24 Sep 2022 10:58:34 +0330 Subject: [PATCH 6/7] Add periodic task --- .../DjangoCryptoReader/celery.py | 17 ++++++++++++ .../DjangoCryptoReader/settings.py | 11 ++++++++ DJANGO-CRYPTOREADER/account/views.py | 8 +++--- .../order/migrations/0002_orderdetail.py | 26 +++++++++++++++++++ DJANGO-CRYPTOREADER/order/models.py | 23 ++++++++++++++-- DJANGO-CRYPTOREADER/order/tasks.py | 26 +++++++++++++++++++ 6 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 DJANGO-CRYPTOREADER/DjangoCryptoReader/celery.py create mode 100644 DJANGO-CRYPTOREADER/order/migrations/0002_orderdetail.py create mode 100644 DJANGO-CRYPTOREADER/order/tasks.py diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/celery.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/celery.py new file mode 100644 index 0000000..a96e0d4 --- /dev/null +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/celery.py @@ -0,0 +1,17 @@ +# django_celery/celery.py + +import os +from celery import Celery +from django.conf import settings + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DjangoCryptoReader.settings") +app = Celery("DjangoCryptoReader") +app.config_from_object(settings, namespace="CELERY") + +app.conf.beat_schedule = { + 'track_order':{ + 'task':'order.tasks.refresh_orders', + 'schedule':30, + } +} +app.autodiscover_tasks() \ No newline at end of file diff --git a/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py b/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py index c7ee3e3..675e0c1 100644 --- a/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py +++ b/DJANGO-CRYPTOREADER/DjangoCryptoReader/settings.py @@ -125,3 +125,14 @@ # https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + +#celery config + +# BROKER_URL = 'redis://localhost:6379' +# CELERY_RESULT_BACKEND = 'redis://localhost:6379' +CELERY_BROKER_URL = 'http://localhost:6379' +CELERY_ACCEPT_CONTENT = ['application/json'] +CELERY_TASK_SERIALIZER = 'json' +CELERY_RESULT_SERIALIZER = 'json' +CELERY_TIMEZONE = 'Asia/Tehran' \ No newline at end of file diff --git a/DJANGO-CRYPTOREADER/account/views.py b/DJANGO-CRYPTOREADER/account/views.py index a92b81b..7ade12e 100644 --- a/DJANGO-CRYPTOREADER/account/views.py +++ b/DJANGO-CRYPTOREADER/account/views.py @@ -1,11 +1,10 @@ -from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED from rest_framework.response import Response from rest_framework.generics import CreateAPIView from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet from .models import User from django.contrib.auth import login -from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED , HTTP_202_ACCEPTED +from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_202_ACCEPTED from .serializers import RegisterSerializer, LoginSerializer from rest_framework.exceptions import NotFound @@ -27,14 +26,13 @@ def perform_create(self, serializer): return serializer - - class LoginView(APIView): # This view should be accessible also for unauthenticated users. # permission_classes = (permissions.AllowAny,) def post(self, request, format=None): - serializer = LoginSerializer(data=self.request.data, context={ 'request': self.request }) + serializer = LoginSerializer(data=self.request.data, context={ + 'request': self.request}) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] login(request, user) diff --git a/DJANGO-CRYPTOREADER/order/migrations/0002_orderdetail.py b/DJANGO-CRYPTOREADER/order/migrations/0002_orderdetail.py new file mode 100644 index 0000000..fb510b5 --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/migrations/0002_orderdetail.py @@ -0,0 +1,26 @@ +# Generated by Django 4.0.7 on 2022-09-24 07:25 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='OrderDetail', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('symbol', models.CharField(blank=True, max_length=64, null=True, verbose_name='symbol')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), + ], + options={ + 'verbose_name': 'OrderDetail', + 'verbose_name_plural': 'OrdersDetail', + }, + ), + ] diff --git a/DJANGO-CRYPTOREADER/order/models.py b/DJANGO-CRYPTOREADER/order/models.py index a901ff2..7ecdf44 100644 --- a/DJANGO-CRYPTOREADER/order/models.py +++ b/DJANGO-CRYPTOREADER/order/models.py @@ -10,8 +10,10 @@ class Order(models.Model): """ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - symbol = models.CharField(max_length=64, null=True,blank=True, verbose_name='symbol') - autoDeposit = models.BooleanField(default=False, verbose_name='auto deposit ?') + symbol = models.CharField(max_length=64, null=True, + blank=True, verbose_name='symbol') + autoDeposit = models.BooleanField( + default=False, verbose_name='auto deposit ?') isOpen = models.BooleanField(default=False, verbose_name='is open ?') def __str__(self) -> str: @@ -22,3 +24,20 @@ class Meta: verbose_name_plural = 'Orders' +class OrderDetail(models.Model): + """ + based on this docs:just define osme fileds not all of them + https://docs.kucoin.com/#list-orders + """ + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + symbol = models.CharField(max_length=64, null=True, + blank=True, verbose_name='symbol') + created_at = models.DateTimeField( + auto_now_add=True, verbose_name='created at') + + def __str__(self) -> str: + return f'id = {self.id} , symbol = {self.symbol}' + + class Meta: + verbose_name = 'OrderDetail' + verbose_name_plural = 'OrdersDetail' diff --git a/DJANGO-CRYPTOREADER/order/tasks.py b/DJANGO-CRYPTOREADER/order/tasks.py new file mode 100644 index 0000000..2bd264a --- /dev/null +++ b/DJANGO-CRYPTOREADER/order/tasks.py @@ -0,0 +1,26 @@ +from django.conf import settings +from django.core.cache import cache +from django.core.cache.backends.base import DEFAULT_TIMEOUT +from account.models import User +from .models import OrderDetail +from celery import shared_task +from utils.utility import CallAPI + + +@shared_task +def refresh_orders(): + """ + Just track active order + """ + users = User.objects.all() + for user in users: + obj = OrderDetail() + try: + active_orders = CallAPI( + (user, '/api/v1/positions', 'GET', {'status': 'active'}, True)) + active_order_response = active_orders.create_request() + obj.id = active_order_response['id'] + obj.symbol = active_order_response['symbol'] + obj.save() + except Exception as e: + raise Exception(e) From 14d18e56770bb8719d0e728aa4183b31609301e3 Mon Sep 17 00:00:00 2001 From: Elo-No Date: Sat, 24 Sep 2022 10:59:01 +0330 Subject: [PATCH 7/7] Updated requirements --- DJANGO-CRYPTOREADER/requirements.txt | Bin 424 -> 1578 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/DJANGO-CRYPTOREADER/requirements.txt b/DJANGO-CRYPTOREADER/requirements.txt index ba2c2008c968074224395973124086c2af623eea..9d422ae057db68209b0768cf842d8377bb8923ff 100644 GIT binary patch literal 1578 zcmZWp+j5&w4AgUG`YCu~+}s}WmLDO29TIbifx7m`x82nq87Cd)craQ?tCe*A{wb`r zPaEtR&z-Go?dONxSYe~>tg(aDwsrdkHezxM`^h>hEwc%@7P#JKyffBM;BK$5{N5u^ zjq~UTW_oZGqrD+ULB7~Qn#urYxbqH8D^;V$gG4B7j3?J#k9tJW!_iLh#0Z2QsCN;doY6cHtA8@ z(X~Fj5(BT0Gj+2-^L$NUFW$UO-KnLQ9;=QfI46GJvfDutb-fC9IAs|Yg2{V4c%yrJK?5~ z656%p9+K}2=DO`(!I-hNJIudM@qd9E?@U@X$D#NUiXCCCT=!tc+O*3@L@#`{A~J8j G*xrAi1Lu1H delta 51 zcmV-30L=fY45$MF|NfC2Ad!kTlPm!qlR^S4la>M!1u+0F05Ovr13!}n1SXTN1W1!m J1tgP@1s