commit 456b5cdf3cdcc57d9696d67a46d686618f143614 Author: Swydk Date: Thu Aug 29 14:21:58 2024 +0500 start project diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8d2d2c1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +.venv/ +venv/ +__pycache__/ +*.pyc +*.pyo +.git/ +.idea/ +.DS_Store diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c2ed311 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +# Используйте официальный образ Python в качестве базового +FROM python:3.11-slim + +# Установите рабочую директорию +WORKDIR /app + +# Скопируйте файл зависимостей и установите их +COPY requirements.txt requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +# Скопируйте все файлы в рабочую директорию +COPY . . + +# Выполните миграции при запуске контейнера +CMD ["sh", "-c", "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..ddbb8f0 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +McDuckMist + +Чат-бот с WebApp + +Содержание +[Установка](#установка) +[Использование](#использование) +[Требования](#требования) + + + +[Установка](#установка) +Установка + +```bash +git clone https://git.wizardstech.ru/Sanzhar.swydk/McDuck.git +``` + +```bash +docker-compose up --build +``` + + + +[Использование](#использование) +Использование + +После запуска перейдите по пути http://127.0.0.1:8000/api/ можно посмотреть, добавить, удалить и изменить данные. +Сможете посмотреть все ссылки/пути для API, а также вот несколько эндпоинтов которые есть в проекте. +/api/users/get_datetime/ +/api/users/get_referrals/ +/api/balance/add_for_balance/ +/api/levels/create_new_levels/ + +Требования + +```markdown + + +- Docker +- Postgresql +- Django +- Python 3.10+ +- Библотеки указаны в requirements.txt +``` \ No newline at end of file diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/__pycache__/__init__.cpython-310.pyc b/backend/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..b331fa2 Binary files /dev/null and b/backend/__pycache__/__init__.cpython-310.pyc differ diff --git a/backend/__pycache__/__init__.cpython-311.pyc b/backend/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..22abbbc Binary files /dev/null and b/backend/__pycache__/__init__.cpython-311.pyc differ diff --git a/backend/__pycache__/settings.cpython-310.pyc b/backend/__pycache__/settings.cpython-310.pyc new file mode 100644 index 0000000..9c26f27 Binary files /dev/null and b/backend/__pycache__/settings.cpython-310.pyc differ diff --git a/backend/__pycache__/settings.cpython-311.pyc b/backend/__pycache__/settings.cpython-311.pyc new file mode 100644 index 0000000..a286bbb Binary files /dev/null and b/backend/__pycache__/settings.cpython-311.pyc differ diff --git a/backend/__pycache__/urls.cpython-310.pyc b/backend/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000..d40eec7 Binary files /dev/null and b/backend/__pycache__/urls.cpython-310.pyc differ diff --git a/backend/__pycache__/urls.cpython-311.pyc b/backend/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000..c4e0295 Binary files /dev/null and b/backend/__pycache__/urls.cpython-311.pyc differ diff --git a/backend/__pycache__/wsgi.cpython-310.pyc b/backend/__pycache__/wsgi.cpython-310.pyc new file mode 100644 index 0000000..2d7b01d Binary files /dev/null and b/backend/__pycache__/wsgi.cpython-310.pyc differ diff --git a/backend/__pycache__/wsgi.cpython-311.pyc b/backend/__pycache__/wsgi.cpython-311.pyc new file mode 100644 index 0000000..8ada061 Binary files /dev/null and b/backend/__pycache__/wsgi.cpython-311.pyc differ diff --git a/backend/asgi.py b/backend/asgi.py new file mode 100644 index 0000000..cb37c7d --- /dev/null +++ b/backend/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for backend 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/5.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') + +application = get_asgi_application() diff --git a/backend/settings.py b/backend/settings.py new file mode 100644 index 0000000..e53d5ea --- /dev/null +++ b/backend/settings.py @@ -0,0 +1,163 @@ +""" +Django settings for backend project. + +Generated by 'django-admin startproject' using Django 5.0.6. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.0/ref/settings/ +""" + +from pathlib import Path + +# 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/5.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-xbb0o#ev2jhjdsgy7ugsrp__1r8ssq_)*o(%w6$+&+w!g_%*7(' + +# 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', + 'main', + 'users', + 'tapdata', + 'stacking', + 'rest_framework', + 'corsheaders', +] + +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', + 'corsheaders.middleware.CorsMiddleware', + +] + +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES':[ + 'rest_framework.permissions.AllowAny' + ] +} + +CORS_ALLOWED_ORIGINS = [ + 'https://pizzafresca.ru', #TODOPROJECT CHANGE IT + + # другие источники, если необходимо +] + + +ROOT_URLCONF = 'backend.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 = 'backend.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/5.0/ref/settings/#databases + +""" DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'mcduck', # Поставлено как пример + 'USER': 'postgres', + 'PASSWORD': 'swydk', # Поставлено как пример + 'HOST': 'localhost', + 'PORT': '5432', + } +} """ +import os +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'mydatabase', + 'USER': 'myuser', + 'PASSWORD': 'mypassword', + 'HOST': 'db', + 'PORT': '5432', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.0/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/5.0/topics/i18n/ + +LANGUAGE_CODE = 'ru' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.0/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +AUTH_USER_MODEL = 'users.User' + +TURCODE_API_KEY = "3feeee2c981eab39c2ff8b2ecc9fad18" diff --git a/backend/urls.py b/backend/urls.py new file mode 100644 index 0000000..9fec010 --- /dev/null +++ b/backend/urls.py @@ -0,0 +1,25 @@ +""" +URL configuration for backend project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.0/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, include + +urlpatterns = [ + path('admin/', admin.site.urls), + path('',include("main.urls")), +] + + diff --git a/backend/wsgi.py b/backend/wsgi.py new file mode 100644 index 0000000..83e5322 --- /dev/null +++ b/backend/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for backend 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/5.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') + +application = get_wsgi_application() diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..08eaabc --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +version: '3.10' + +services: + db: + image: postgres:15 + volumes: + - postgres_data:/var/lib/postgresql/data + environment: + POSTGRES_DB: mydatabase + POSTGRES_USER: myuser + POSTGRES_PASSWORD: mypassword + + web: + build: . + command: ["sh", "-c", "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"] + volumes: + - .:/app + ports: + - "8000:8000" + depends_on: + - db + +volumes: + postgres_data: diff --git a/main/__init__.py b/main/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/main/__pycache__/__init__.cpython-310.pyc b/main/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..2b16b69 Binary files /dev/null and b/main/__pycache__/__init__.cpython-310.pyc differ diff --git a/main/__pycache__/__init__.cpython-311.pyc b/main/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..4009006 Binary files /dev/null and b/main/__pycache__/__init__.cpython-311.pyc differ diff --git a/main/__pycache__/admin.cpython-310.pyc b/main/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000..4270c10 Binary files /dev/null and b/main/__pycache__/admin.cpython-310.pyc differ diff --git a/main/__pycache__/admin.cpython-311.pyc b/main/__pycache__/admin.cpython-311.pyc new file mode 100644 index 0000000..325f89a Binary files /dev/null and b/main/__pycache__/admin.cpython-311.pyc differ diff --git a/main/__pycache__/apps.cpython-310.pyc b/main/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000..6bd50b4 Binary files /dev/null and b/main/__pycache__/apps.cpython-310.pyc differ diff --git a/main/__pycache__/apps.cpython-311.pyc b/main/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000..e71938e Binary files /dev/null and b/main/__pycache__/apps.cpython-311.pyc differ diff --git a/main/__pycache__/models.cpython-310.pyc b/main/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000..81d95fd Binary files /dev/null and b/main/__pycache__/models.cpython-310.pyc differ diff --git a/main/__pycache__/models.cpython-311.pyc b/main/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..737f8ff Binary files /dev/null and b/main/__pycache__/models.cpython-311.pyc differ diff --git a/main/__pycache__/urls.cpython-310.pyc b/main/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000..07999e2 Binary files /dev/null and b/main/__pycache__/urls.cpython-310.pyc differ diff --git a/main/__pycache__/urls.cpython-311.pyc b/main/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000..f1ea609 Binary files /dev/null and b/main/__pycache__/urls.cpython-311.pyc differ diff --git a/main/admin.py b/main/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/main/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/main/apps.py b/main/apps.py new file mode 100644 index 0000000..167f044 --- /dev/null +++ b/main/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MainConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'main' diff --git a/main/models.py b/main/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/main/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/main/tests.py b/main/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/main/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/main/urls.py b/main/urls.py new file mode 100644 index 0000000..470b3f6 --- /dev/null +++ b/main/urls.py @@ -0,0 +1,31 @@ +# urls.py +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from users.views import UserViewSet, DailyRewardViewSet, DailyRewardsListViewSet, BalanceViewSet, LevelsViewSet +from tapdata.views import FarmingViewSet +from stacking.views import UserStakeViewSet, StakeViewSet + + +""" from tapdata.views import TapDataViewSet +from stacking.views import UserStakeViewSet, StakeViewSet """ + + + + +router = DefaultRouter() +router.register(r'users', UserViewSet) +router.register(r'dailyreward', DailyRewardViewSet) +router.register(r'dailyrewardlist', DailyRewardsListViewSet) +router.register(r'balance', BalanceViewSet) +router.register(r'levels', LevelsViewSet) +router.register(r'farming', FarmingViewSet) +router.register(r'stacking', UserStakeViewSet) +router.register(r'stake', StakeViewSet) + + + + + +urlpatterns = [ + path('api/', include(router.urls)), +] diff --git a/main/views.py b/main/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/main/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..eb6431e --- /dev/null +++ b/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', 'backend.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/requirements.txt b/requirements.txt new file mode 100644 index 0000000..833d898 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,15 @@ +asgiref==3.8.1 +certifi==2024.7.4 +charset-normalizer==3.3.2 +Django==5.0.6 +django-cors-headers==4.4.0 +djangorestframework==3.15.2 +gunicorn==23.0.0 +idna==3.7 +packaging==24.1 +pillow==10.4.0 +psycopg2-binary==2.9.9 +requests==2.32.3 +sqlparse==0.5.1 +typing_extensions==4.12.2 +urllib3==2.2.2 diff --git a/stacking/__init__.py b/stacking/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/stacking/__pycache__/__init__.cpython-310.pyc b/stacking/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..ca865fa Binary files /dev/null and b/stacking/__pycache__/__init__.cpython-310.pyc differ diff --git a/stacking/__pycache__/__init__.cpython-311.pyc b/stacking/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..2ddebeb Binary files /dev/null and b/stacking/__pycache__/__init__.cpython-311.pyc differ diff --git a/stacking/__pycache__/admin.cpython-310.pyc b/stacking/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000..cd65a64 Binary files /dev/null and b/stacking/__pycache__/admin.cpython-310.pyc differ diff --git a/stacking/__pycache__/admin.cpython-311.pyc b/stacking/__pycache__/admin.cpython-311.pyc new file mode 100644 index 0000000..5d51bc3 Binary files /dev/null and b/stacking/__pycache__/admin.cpython-311.pyc differ diff --git a/stacking/__pycache__/apps.cpython-310.pyc b/stacking/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000..7ef275a Binary files /dev/null and b/stacking/__pycache__/apps.cpython-310.pyc differ diff --git a/stacking/__pycache__/apps.cpython-311.pyc b/stacking/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000..6735f11 Binary files /dev/null and b/stacking/__pycache__/apps.cpython-311.pyc differ diff --git a/stacking/__pycache__/models.cpython-310.pyc b/stacking/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000..7438c17 Binary files /dev/null and b/stacking/__pycache__/models.cpython-310.pyc differ diff --git a/stacking/__pycache__/models.cpython-311.pyc b/stacking/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..0fe0964 Binary files /dev/null and b/stacking/__pycache__/models.cpython-311.pyc differ diff --git a/stacking/__pycache__/serializers.cpython-310.pyc b/stacking/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000..58060f5 Binary files /dev/null and b/stacking/__pycache__/serializers.cpython-310.pyc differ diff --git a/stacking/__pycache__/serializers.cpython-311.pyc b/stacking/__pycache__/serializers.cpython-311.pyc new file mode 100644 index 0000000..a1b7738 Binary files /dev/null and b/stacking/__pycache__/serializers.cpython-311.pyc differ diff --git a/stacking/__pycache__/views.cpython-310.pyc b/stacking/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000..ee604dc Binary files /dev/null and b/stacking/__pycache__/views.cpython-310.pyc differ diff --git a/stacking/__pycache__/views.cpython-311.pyc b/stacking/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000..e94a0c5 Binary files /dev/null and b/stacking/__pycache__/views.cpython-311.pyc differ diff --git a/stacking/admin.py b/stacking/admin.py new file mode 100644 index 0000000..55cb117 --- /dev/null +++ b/stacking/admin.py @@ -0,0 +1,12 @@ + +from django.contrib import admin +from .models import Stake, UserStake + +admin.site.register(Stake) +admin.site.register(UserStake) + + + + + + diff --git a/stacking/apps.py b/stacking/apps.py new file mode 100644 index 0000000..d5e8041 --- /dev/null +++ b/stacking/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class StackingConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'stacking' diff --git a/stacking/migrations/0001_initial.py b/stacking/migrations/0001_initial.py new file mode 100644 index 0000000..23488b9 --- /dev/null +++ b/stacking/migrations/0001_initial.py @@ -0,0 +1,35 @@ +# Generated by Django 5.0.6 on 2024-08-26 11:46 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('users', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='UserStake', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('amount', models.DecimalField(decimal_places=4, max_digits=30, verbose_name='Сумма')), + ('percent', models.IntegerField(blank=True, null=True, verbose_name='Процент бонусов')), + ('is_active', models.BooleanField(default=True, verbose_name='Автивен')), + ('start_date', models.DateTimeField(auto_now=True, verbose_name='Время начала')), + ('duration', models.IntegerField(blank=True, null=True, verbose_name='Длительность в днях')), + ('balance', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.balance')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Пользовательский Stake', + 'verbose_name_plural': 'Пользовательские Stake', + }, + ), + ] diff --git a/stacking/migrations/0002_stake_remove_userstake_duration_and_more.py b/stacking/migrations/0002_stake_remove_userstake_duration_and_more.py new file mode 100644 index 0000000..b4bfebd --- /dev/null +++ b/stacking/migrations/0002_stake_remove_userstake_duration_and_more.py @@ -0,0 +1,40 @@ +# Generated by Django 5.0.6 on 2024-08-29 07:41 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('stacking', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Stake', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('stake_type', models.CharField(choices=[('DAY1', '1 день'), ('WEEK1', '1 неделя'), ('WEEK2', '2 недели'), ('MONTH1', '1 месяц'), ('MONTH3', '3 месяца'), ('MONTH6', '6 месяцев'), ('YEAR1', '1 год')], default='DAY1', max_length=250, verbose_name='Тип')), + ('percent', models.IntegerField(blank=True, null=True, verbose_name='Процент бонусов')), + ], + options={ + 'verbose_name': 'Stake', + 'verbose_name_plural': 'Stake', + }, + ), + migrations.RemoveField( + model_name='userstake', + name='duration', + ), + migrations.RemoveField( + model_name='userstake', + name='percent', + ), + migrations.AddField( + model_name='userstake', + name='stake', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='stacking.stake'), + preserve_default=False, + ), + ] diff --git a/stacking/migrations/__init__.py b/stacking/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/stacking/migrations/__pycache__/0001_initial.cpython-310.pyc b/stacking/migrations/__pycache__/0001_initial.cpython-310.pyc new file mode 100644 index 0000000..160c052 Binary files /dev/null and b/stacking/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/stacking/migrations/__pycache__/0001_initial.cpython-311.pyc b/stacking/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..0e0111c Binary files /dev/null and b/stacking/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/stacking/migrations/__pycache__/0002_stake_remove_userstake_duration_and_more.cpython-310.pyc b/stacking/migrations/__pycache__/0002_stake_remove_userstake_duration_and_more.cpython-310.pyc new file mode 100644 index 0000000..60c5ec0 Binary files /dev/null and b/stacking/migrations/__pycache__/0002_stake_remove_userstake_duration_and_more.cpython-310.pyc differ diff --git a/stacking/migrations/__pycache__/0002_stake_remove_userstake_duration_and_more.cpython-311.pyc b/stacking/migrations/__pycache__/0002_stake_remove_userstake_duration_and_more.cpython-311.pyc new file mode 100644 index 0000000..28e05d0 Binary files /dev/null and b/stacking/migrations/__pycache__/0002_stake_remove_userstake_duration_and_more.cpython-311.pyc differ diff --git a/stacking/migrations/__pycache__/__init__.cpython-310.pyc b/stacking/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..34c2008 Binary files /dev/null and b/stacking/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/stacking/migrations/__pycache__/__init__.cpython-311.pyc b/stacking/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..f9acddf Binary files /dev/null and b/stacking/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/stacking/models.py b/stacking/models.py new file mode 100644 index 0000000..9dbf2b4 --- /dev/null +++ b/stacking/models.py @@ -0,0 +1,50 @@ +from django.db import models +from django.contrib.auth.models import User +from django.utils import timezone +from django.conf import settings + +from django.utils.translation import gettext_lazy as _ +from users.models import Balance + +class Stake(models.Model): + class StakeEnum(models.TextChoices): + DAY1 = 'DAY1', _('1 день') + WEEK1 = 'WEEK1', _('1 неделя') + WEEK2 = 'WEEK2', _('2 недели') + MONTH1 = 'MONTH1', _('1 месяц') + MONTH3 = 'MONTH3', _('3 месяца') + MONTH6 = 'MONTH6', _('6 месяцев') + YEAR1 = 'YEAR1', _('1 год') + + + + + stake_type = models.CharField('Тип', choices=StakeEnum.choices,default=StakeEnum.DAY1, max_length=250) + percent = models.IntegerField('Процент бонусов', null=True, blank=True) + + + + def __str__(self): + return f"{self.stake_type} - {self.percent}%" + + class Meta: + verbose_name = 'Stake' + verbose_name_plural = 'Stake' + +class UserStake(models.Model): + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + balance = models.ForeignKey(Balance, on_delete=models.CASCADE) + stake = models.ForeignKey(Stake, on_delete=models.CASCADE) + amount = models.DecimalField('Сумма',max_digits=30, decimal_places=4) + is_active = models.BooleanField('Автивен', default=True) + start_date = models.DateTimeField('Время начала', auto_now=True) + + + + + def __str__(self): + return f"{self.user.username} - {self.amount} коинов" + + class Meta: + verbose_name = 'Пользовательский Stake' + verbose_name_plural = 'Пользовательские Stake' diff --git a/stacking/serializers.py b/stacking/serializers.py new file mode 100644 index 0000000..5f220d7 --- /dev/null +++ b/stacking/serializers.py @@ -0,0 +1,14 @@ +from rest_framework import serializers +from .models import UserStake, Stake + +class UserStakeSerializer(serializers.ModelSerializer): + class Meta: + model = UserStake + fields = '__all__' + +class StakeSerializer(serializers.ModelSerializer): + class Meta: + model = Stake + fields = '__all__' + + diff --git a/stacking/tests.py b/stacking/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/stacking/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/stacking/views.py b/stacking/views.py new file mode 100644 index 0000000..87eff80 --- /dev/null +++ b/stacking/views.py @@ -0,0 +1,14 @@ +from rest_framework import viewsets +from .models import UserStake, Stake +from .serializers import UserStakeSerializer, StakeSerializer + + + +class UserStakeViewSet(viewsets.ModelViewSet): + queryset = UserStake.objects.all() + serializer_class = UserStakeSerializer +class StakeViewSet(viewsets.ModelViewSet): + queryset = Stake.objects.all() + serializer_class = StakeSerializer + + diff --git a/static/media/levels/character1.jpg b/static/media/levels/character1.jpg new file mode 100644 index 0000000..833069d Binary files /dev/null and b/static/media/levels/character1.jpg differ diff --git a/static/media/levels/character2.jpg b/static/media/levels/character2.jpg new file mode 100644 index 0000000..4325465 Binary files /dev/null and b/static/media/levels/character2.jpg differ diff --git a/static/media/levels/character3.jpg b/static/media/levels/character3.jpg new file mode 100644 index 0000000..b88a100 Binary files /dev/null and b/static/media/levels/character3.jpg differ diff --git a/static/media/levels/character4.jpg b/static/media/levels/character4.jpg new file mode 100644 index 0000000..23d8f15 Binary files /dev/null and b/static/media/levels/character4.jpg differ diff --git a/static/media/levels/character5.jpg b/static/media/levels/character5.jpg new file mode 100644 index 0000000..b09edfa Binary files /dev/null and b/static/media/levels/character5.jpg differ diff --git a/static/media/levels/character6.jpg b/static/media/levels/character6.jpg new file mode 100644 index 0000000..2a64c09 Binary files /dev/null and b/static/media/levels/character6.jpg differ diff --git a/static/media/levels/character7.jpg b/static/media/levels/character7.jpg new file mode 100644 index 0000000..3ef321d Binary files /dev/null and b/static/media/levels/character7.jpg differ diff --git a/static/media/user_photo/Снимок_экрана_2024-07-26_123831.png b/static/media/user_photo/Снимок_экрана_2024-07-26_123831.png new file mode 100644 index 0000000..988a6fc Binary files /dev/null and b/static/media/user_photo/Снимок_экрана_2024-07-26_123831.png differ diff --git a/tapdata/__init__.py b/tapdata/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tapdata/__pycache__/__init__.cpython-310.pyc b/tapdata/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..5b71220 Binary files /dev/null and b/tapdata/__pycache__/__init__.cpython-310.pyc differ diff --git a/tapdata/__pycache__/__init__.cpython-311.pyc b/tapdata/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..6beffc1 Binary files /dev/null and b/tapdata/__pycache__/__init__.cpython-311.pyc differ diff --git a/tapdata/__pycache__/admin.cpython-310.pyc b/tapdata/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000..e84bc14 Binary files /dev/null and b/tapdata/__pycache__/admin.cpython-310.pyc differ diff --git a/tapdata/__pycache__/admin.cpython-311.pyc b/tapdata/__pycache__/admin.cpython-311.pyc new file mode 100644 index 0000000..490c8c0 Binary files /dev/null and b/tapdata/__pycache__/admin.cpython-311.pyc differ diff --git a/tapdata/__pycache__/apps.cpython-310.pyc b/tapdata/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000..6b0e05c Binary files /dev/null and b/tapdata/__pycache__/apps.cpython-310.pyc differ diff --git a/tapdata/__pycache__/apps.cpython-311.pyc b/tapdata/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000..4f9cb54 Binary files /dev/null and b/tapdata/__pycache__/apps.cpython-311.pyc differ diff --git a/tapdata/__pycache__/models.cpython-310.pyc b/tapdata/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000..5dc7358 Binary files /dev/null and b/tapdata/__pycache__/models.cpython-310.pyc differ diff --git a/tapdata/__pycache__/models.cpython-311.pyc b/tapdata/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..d451cae Binary files /dev/null and b/tapdata/__pycache__/models.cpython-311.pyc differ diff --git a/tapdata/__pycache__/serializers.cpython-310.pyc b/tapdata/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000..788bd04 Binary files /dev/null and b/tapdata/__pycache__/serializers.cpython-310.pyc differ diff --git a/tapdata/__pycache__/serializers.cpython-311.pyc b/tapdata/__pycache__/serializers.cpython-311.pyc new file mode 100644 index 0000000..c5e5403 Binary files /dev/null and b/tapdata/__pycache__/serializers.cpython-311.pyc differ diff --git a/tapdata/__pycache__/views.cpython-310.pyc b/tapdata/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000..5d5ae6e Binary files /dev/null and b/tapdata/__pycache__/views.cpython-310.pyc differ diff --git a/tapdata/__pycache__/views.cpython-311.pyc b/tapdata/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000..d7e4b40 Binary files /dev/null and b/tapdata/__pycache__/views.cpython-311.pyc differ diff --git a/tapdata/admin.py b/tapdata/admin.py new file mode 100644 index 0000000..083278b --- /dev/null +++ b/tapdata/admin.py @@ -0,0 +1,13 @@ + +from django.contrib import admin +from .models import Farming, Prizes + +admin.site.register(Farming) +admin.site.register(Prizes) + + + + + + + diff --git a/tapdata/apps.py b/tapdata/apps.py new file mode 100644 index 0000000..d7b51a8 --- /dev/null +++ b/tapdata/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TapdataConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'tapdata' diff --git a/tapdata/migrations/0001_initial.py b/tapdata/migrations/0001_initial.py new file mode 100644 index 0000000..b9ef175 --- /dev/null +++ b/tapdata/migrations/0001_initial.py @@ -0,0 +1,50 @@ +# Generated by Django 5.0.6 on 2024-08-26 11:44 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Prizes', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('prize_type', models.CharField(choices=[('CN', 'Coins'), ('AL', 'Acceleration'), ('AC', 'Auto_collection')], max_length=250, verbose_name='Тип приза')), + ('time', models.IntegerField(blank=True, null=True, verbose_name='Время награды в днях')), + ('coins', models.BigIntegerField(blank=True, null=True, verbose_name='Количество MCDK (Необязательно)')), + ('percent', models.IntegerField(blank=True, null=True, verbose_name='Процент (Необязательно)')), + ], + options={ + 'verbose_name': 'Приз', + 'verbose_name_plural': 'Призы', + }, + ), + migrations.CreateModel( + name='Farming', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('coins_per_min', models.BigIntegerField(blank=True, default=1, verbose_name='Монет за мин')), + ('coins', models.BigIntegerField(blank=True, default=0, verbose_name='Количество MCDK')), + ('start_time', models.DateTimeField(blank=True, null=True, verbose_name='Время и дата начала фарминга')), + ('percent', models.IntegerField(default=0, verbose_name='Дополнительные проценты фарминга')), + ('is_auto_collection_active', models.BooleanField(default=False, verbose_name='Автосбор активен')), + ('auto_collection_end_time', models.DateTimeField(blank=True, null=True, verbose_name='Время окончания автосбора')), + ('bonus_multiplier', models.FloatField(blank=True, default=1.0, verbose_name='Множитель скорости фарминга')), + ('bonus_end_time', models.DateTimeField(blank=True, null=True, verbose_name='Время окончания бонуса')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Данные фарминга', + 'verbose_name_plural': 'Данные фармингов', + }, + ), + ] diff --git a/tapdata/migrations/__init__.py b/tapdata/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tapdata/migrations/__pycache__/0001_initial.cpython-310.pyc b/tapdata/migrations/__pycache__/0001_initial.cpython-310.pyc new file mode 100644 index 0000000..1c763ec Binary files /dev/null and b/tapdata/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/tapdata/migrations/__pycache__/0001_initial.cpython-311.pyc b/tapdata/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..e91d527 Binary files /dev/null and b/tapdata/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/tapdata/migrations/__pycache__/__init__.cpython-310.pyc b/tapdata/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..5908776 Binary files /dev/null and b/tapdata/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/tapdata/migrations/__pycache__/__init__.cpython-311.pyc b/tapdata/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..27fde5a Binary files /dev/null and b/tapdata/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/tapdata/models.py b/tapdata/models.py new file mode 100644 index 0000000..3d59104 --- /dev/null +++ b/tapdata/models.py @@ -0,0 +1,73 @@ +from django.db import models +from users.models import User +from django.utils import timezone +from datetime import timedelta +from django.utils.translation import gettext_lazy as _ + +class Farming(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + coins_per_min = models.BigIntegerField('Монет за мин', default=1, blank=True) + coins = models.BigIntegerField('Количество MCDK', default=0, blank=True) + start_time = models.DateTimeField('Время и дата начала фарминга', null=True, blank=True) + percent = models.IntegerField("Дополнительные проценты фарминга", default=0) + is_auto_collection_active = models.BooleanField('Автосбор активен', default=False) + auto_collection_end_time = models.DateTimeField('Время окончания автосбора', null=True, blank=True) + bonus_multiplier = models.FloatField('Множитель скорости фарминга', default=1.0, blank=True) + bonus_end_time = models.DateTimeField('Время окончания бонуса', null=True, blank=True) + + def __str__(self): + return f'{self.user.username} имеет {self.coins} MCDK' + + class Meta: + verbose_name = 'Данные фарминга' + verbose_name_plural = 'Данные фармингов' + + def apply_auto_collection(self, duration_days): + self.is_auto_collection_active = True + self.auto_collection_end_time = timezone.now() + timedelta(days=duration_days) + self.save() + + def apply_bonus_multiplier(self, percent, duration_days): + self.bonus_multiplier = 1 + (percent / 100) + self.bonus_end_time = timezone.now() + timedelta(days=duration_days) + self.save() + + def update_farming(self): + current_time = timezone.now() + + # Обновление авто-сбора + if self.is_auto_collection_active and self.auto_collection_end_time < current_time: + self.is_auto_collection_active = False + self.auto_collection_end_time = None + self.save() + + # Обновление бонусного множителя + if self.bonus_multiplier > 1.0 and self.bonus_end_time < current_time: + self.bonus_multiplier = 1.0 + self.bonus_end_time = None + self.save() + + # Обновление монет с учетом бонусного множителя + self.coins += self.coins_per_min * self.bonus_multiplier + self.save() + +# Призы с колеса фортуны +class Prizes(models.Model): + class PrizeTypeEnum(models.TextChoices): + COINS = 'CN', _('Coins') + ACCELERATION = 'AL', _('Acceleration') + AUTO_COLLECTION = 'AC', _('Auto_collection') + + prize_type = models.CharField('Тип приза', choices=PrizeTypeEnum.choices, max_length=250) + time = models.IntegerField('Время награды в днях', null=True, blank=True) + coins = models.BigIntegerField('Количество MCDK (Необязательно)', null=True, blank=True) + percent = models.IntegerField('Процент (Необязательно)', null=True, blank=True) + + + + def __str__(self): + return f'Тип приза - {self.prize_type}' + + class Meta: + verbose_name = 'Приз' + verbose_name_plural = 'Призы' diff --git a/tapdata/serializers.py b/tapdata/serializers.py new file mode 100644 index 0000000..a81b75f --- /dev/null +++ b/tapdata/serializers.py @@ -0,0 +1,14 @@ +from rest_framework import serializers +from .models import Farming, Prizes + +class FarmingSerializer(serializers.ModelSerializer): + class Meta: + model = Farming + fields = '__all__' + +class PrizesSerializer(serializers.ModelSerializer): + class Meta: + model = Prizes + fields = '__all__' + + diff --git a/tapdata/tests.py b/tapdata/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/tapdata/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/tapdata/views.py b/tapdata/views.py new file mode 100644 index 0000000..5fc6517 --- /dev/null +++ b/tapdata/views.py @@ -0,0 +1,14 @@ +from rest_framework import viewsets +from .models import Farming, Prizes +from .serializers import FarmingSerializer, PrizesSerializer + + + +class FarmingViewSet(viewsets.ModelViewSet): + queryset = Farming.objects.all() + serializer_class = FarmingSerializer + +class PrizesViewSet(viewsets.ModelViewSet): + queryset = Prizes.objects.all() + serializer_class = PrizesSerializer + diff --git a/users/__init__.py b/users/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/users/__pycache__/__init__.cpython-310.pyc b/users/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..e7ba4ef Binary files /dev/null and b/users/__pycache__/__init__.cpython-310.pyc differ diff --git a/users/__pycache__/__init__.cpython-311.pyc b/users/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..4306163 Binary files /dev/null and b/users/__pycache__/__init__.cpython-311.pyc differ diff --git a/users/__pycache__/admin.cpython-310.pyc b/users/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000..5614c39 Binary files /dev/null and b/users/__pycache__/admin.cpython-310.pyc differ diff --git a/users/__pycache__/admin.cpython-311.pyc b/users/__pycache__/admin.cpython-311.pyc new file mode 100644 index 0000000..27ddbf2 Binary files /dev/null and b/users/__pycache__/admin.cpython-311.pyc differ diff --git a/users/__pycache__/apps.cpython-310.pyc b/users/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000..5212b70 Binary files /dev/null and b/users/__pycache__/apps.cpython-310.pyc differ diff --git a/users/__pycache__/apps.cpython-311.pyc b/users/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000..c6ba6ea Binary files /dev/null and b/users/__pycache__/apps.cpython-311.pyc differ diff --git a/users/__pycache__/models.cpython-310.pyc b/users/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000..9fd7871 Binary files /dev/null and b/users/__pycache__/models.cpython-310.pyc differ diff --git a/users/__pycache__/models.cpython-311.pyc b/users/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..9a93396 Binary files /dev/null and b/users/__pycache__/models.cpython-311.pyc differ diff --git a/users/__pycache__/serializers.cpython-310.pyc b/users/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000..118d3a0 Binary files /dev/null and b/users/__pycache__/serializers.cpython-310.pyc differ diff --git a/users/__pycache__/serializers.cpython-311.pyc b/users/__pycache__/serializers.cpython-311.pyc new file mode 100644 index 0000000..7bee99f Binary files /dev/null and b/users/__pycache__/serializers.cpython-311.pyc differ diff --git a/users/__pycache__/tasks.cpython-310.pyc b/users/__pycache__/tasks.cpython-310.pyc new file mode 100644 index 0000000..faf7766 Binary files /dev/null and b/users/__pycache__/tasks.cpython-310.pyc differ diff --git a/users/__pycache__/tasks.cpython-311.pyc b/users/__pycache__/tasks.cpython-311.pyc new file mode 100644 index 0000000..fc538b5 Binary files /dev/null and b/users/__pycache__/tasks.cpython-311.pyc differ diff --git a/users/__pycache__/views.cpython-310.pyc b/users/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000..71bec3b Binary files /dev/null and b/users/__pycache__/views.cpython-310.pyc differ diff --git a/users/__pycache__/views.cpython-311.pyc b/users/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000..177c610 Binary files /dev/null and b/users/__pycache__/views.cpython-311.pyc differ diff --git a/users/admin.py b/users/admin.py new file mode 100644 index 0000000..dce53ac --- /dev/null +++ b/users/admin.py @@ -0,0 +1,16 @@ + +from django.contrib import admin +from .models import DailyReward, DailyRewardsList, User, Levels, Balance + +admin.site.register(User) +admin.site.register(Balance) +admin.site.register(Levels) +admin.site.register(DailyReward) +admin.site.register(DailyRewardsList) + + + + + + + diff --git a/users/apps.py b/users/apps.py new file mode 100644 index 0000000..e3318e8 --- /dev/null +++ b/users/apps.py @@ -0,0 +1,11 @@ +from django.apps import AppConfig + + +class UsersConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'users' + + + def ready(self): + from users.tasks import start_scheduler + start_scheduler() \ No newline at end of file diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py new file mode 100644 index 0000000..adf8efe --- /dev/null +++ b/users/migrations/0001_initial.py @@ -0,0 +1,123 @@ +# Generated by Django 5.0.6 on 2024-08-26 11:43 + +import django.contrib.auth.models +import django.contrib.auth.validators +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='DailyRewardsList', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('active_day', models.IntegerField(blank=True, verbose_name='Активный день')), + ('month_max_day', models.CharField(choices=[('До 28', 'До 28'), ('До 29', 'До 29'), ('До 30', 'До 30'), ('До 31', 'До 31')], max_length=250, verbose_name='Длительность месяца')), + ], + options={ + 'verbose_name': 'Список наград', + 'verbose_name_plural': 'Список наград', + }, + ), + 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')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('photo', models.ImageField(upload_to='static/media/user_photo/', verbose_name='Аватарка пользователя')), + ('tg_id', models.CharField(blank=True, max_length=250, verbose_name='Telegram ID')), + ('tg_username', models.CharField(blank=True, max_length=250, verbose_name='Имя пользователя')), + ('name', models.CharField(blank=True, max_length=300, verbose_name='Имя')), + ('referral_code', models.CharField(blank=True, max_length=250, null=True, unique=True, verbose_name='Код рефферала')), + ('coins_for_referral', models.BigIntegerField(blank=True, default=0, verbose_name='Монеты полученные от рефералов')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('referred_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='referrals', to=settings.AUTH_USER_MODEL)), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + name='Balance', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(verbose_name='Имя баланса')), + ('wallet', models.CharField(blank=True, max_length=350, null=True, verbose_name='Кошелек')), + ('currency', models.CharField(blank=True, max_length=250, verbose_name='Валюта')), + ('balance', models.BigIntegerField(default=0, verbose_name='Количество монет/Сумма')), + ('color', models.CharField(choices=[('Yl', 'Yellow'), ('BK', 'Black'), ('GR', 'Grey'), ('BL', 'Blue')], default='Yl', max_length=250, verbose_name='Цвет')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Баланс пользователя', + 'verbose_name_plural': 'Балансы пользователей', + }, + ), + migrations.CreateModel( + name='DailyReward', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('day', models.IntegerField(verbose_name='День')), + ('reward_amount', models.IntegerField(verbose_name='Сумма награды')), + ('claimed', models.BooleanField(default=False, verbose_name='Была ли награда получена')), + ('claim_date', models.DateTimeField(blank=True, null=True, verbose_name='Время получения награды')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Ежедневная награда', + 'verbose_name_plural': 'Ежедневные награды', + }, + ), + migrations.CreateModel( + name='Levels', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, max_length=300, verbose_name='Имя')), + ('level', models.IntegerField(verbose_name='Уровень')), + ('photo', models.ImageField(upload_to='static/media/levels/', verbose_name='Фото уровня')), + ('need_coins', models.IntegerField(verbose_name='Количество нужных монет')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Уровень', + 'verbose_name_plural': 'Уровни', + }, + ), + migrations.CreateModel( + name='Transaction', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Сумма')), + ('currency', models.CharField(max_length=10, verbose_name='Валюта')), + ('status', models.CharField(default='Pending', max_length=50, verbose_name='Статус')), + ('transaction_id', models.CharField(max_length=100, unique=True, verbose_name='ID транзакции')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/users/migrations/__pycache__/0001_initial.cpython-310.pyc b/users/migrations/__pycache__/0001_initial.cpython-310.pyc new file mode 100644 index 0000000..225d14d Binary files /dev/null and b/users/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/users/migrations/__pycache__/0001_initial.cpython-311.pyc b/users/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..1332502 Binary files /dev/null and b/users/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/users/migrations/__pycache__/__init__.cpython-310.pyc b/users/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..a46b7f2 Binary files /dev/null and b/users/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/users/migrations/__pycache__/__init__.cpython-311.pyc b/users/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..ecf1be1 Binary files /dev/null and b/users/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/users/models.py b/users/models.py new file mode 100644 index 0000000..bfb990e --- /dev/null +++ b/users/models.py @@ -0,0 +1,111 @@ +from django.contrib.auth.models import AbstractUser +from django.db import models +from django.utils.translation import gettext_lazy as _ +from django.utils import timezone +from django.db.models.signals import post_save +from django.dispatch import receiver + + +# Users model +class User(AbstractUser): + photo = models.ImageField('Аватарка пользователя', upload_to='static/media/user_photo/') + tg_id = models.CharField('Telegram ID', max_length=250, blank=True) + tg_username = models.CharField('Имя пользователя', max_length=250, blank=True) + name = models.CharField('Имя', max_length=300, blank=True) + referral_code = models.CharField('Код рефферала', max_length=250, unique=True, blank=True, null=True) + referred_by = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='referrals') + coins_for_referral = models.BigIntegerField("Монеты полученные от рефералов", default=0, blank=True) + + + def __str__(self): + return self.tg_username + + +# Уровни пользователя +class Levels(models.Model): + + user = models.ForeignKey(User, on_delete=models.CASCADE) + name = models.CharField('Имя',max_length=300, blank=True) + level = models.IntegerField("Уровень") + photo = models.ImageField('Фото уровня', upload_to='static/media/levels/') + need_coins = models.IntegerField("Количество нужных монет") + + + def __str__(self): + return f"Пользователь {self.user.username} - {self.name} {self.level}" + class Meta: + verbose_name = 'Уровень' + verbose_name_plural = 'Уровни' + + +#Баланс пользователя +class Balance(models.Model): + class ColorEnum(models.TextChoices): + YELLOW = 'Yl', _('Yellow') + BLACK = 'BK', _('Black') + GREY = 'GR', _('Grey') + BLUE = 'BL', _('Blue') + + user = models.ForeignKey(User, on_delete=models.CASCADE) + name = models.CharField("Имя баланса") + wallet = models.CharField('Кошелек', max_length=350, blank=True, null=True) + currency = models.CharField('Валюта', max_length=250, blank=True) + balance = models.BigIntegerField("Количество монет/Сумма", default=0) + color = models.CharField('Цвет', choices=ColorEnum.choices, default=ColorEnum.YELLOW, max_length=250) + + + def __str__(self): + return f"Сумма {self.balance} {self.currency} - {self.user.username}" + + class Meta: + verbose_name = 'Баланс пользователя' + verbose_name_plural = 'Балансы пользователей' + + + +# Ежедневная награда +class DailyReward(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + day = models.IntegerField("День") + reward_amount = models.IntegerField("Сумма награды") + claimed = models.BooleanField('Была ли награда получена',default=False) + claim_date = models.DateTimeField('Время получения награды',null=True, blank=True) + + def __str__(self): + return f"День {self.day} - {self.user.username}" + + class Meta: + verbose_name = 'Ежедневная награда' + verbose_name_plural = 'Ежедневные награды' + + +# Список ежедневных наград +class DailyRewardsList(models.Model): + class MonthEnum(models.TextChoices): + TO28 = 'До 28', _('До 28') + TO29 = 'До 29', _('До 29') + TO30 = 'До 30', _('До 30') + TO31 = 'До 31', _('До 31') + + active_day = models.IntegerField('Активный день', blank=True) + month_max_day = models.CharField('Длительность месяца', choices=MonthEnum.choices, max_length=250) + + def __str__(self): + return f"Месяц с {self.month_max_day} днями - Активный день: {self.active_day}" + + class Meta: + verbose_name = 'Список наград' + verbose_name_plural = 'Список наград' + +from django.db import models + +class Transaction(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + amount = models.DecimalField("Сумма", max_digits=10, decimal_places=2) + currency = models.CharField("Валюта", max_length=10) + status = models.CharField("Статус", max_length=50, default="Pending") + transaction_id = models.CharField("ID транзакции", max_length=100, unique=True) + created_at = models.DateTimeField("Дата создания", auto_now_add=True) + + def __str__(self): + return f"Транзакция {self.transaction_id} пользователя {self.user.username}" diff --git a/users/serializers.py b/users/serializers.py new file mode 100644 index 0000000..386bd10 --- /dev/null +++ b/users/serializers.py @@ -0,0 +1,27 @@ +from rest_framework import serializers +from .models import User, DailyReward, DailyRewardsList, Balance, Levels + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = '__all__' + +class DailyRewardSerializer(serializers.ModelSerializer): + class Meta: + model = DailyReward + fields = '__all__' + +class DailyRewardsListSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = '__all__' + +class BalanceSerializer(serializers.ModelSerializer): + class Meta: + model = Balance + fields = '__all__' + +class LevelsSerializer(serializers.ModelSerializer): + class Meta: + model = Levels + fields = '__all__' diff --git a/users/tasks.py b/users/tasks.py new file mode 100644 index 0000000..22d283b --- /dev/null +++ b/users/tasks.py @@ -0,0 +1,66 @@ +import threading +import time +import datetime +from .models import DailyRewardsList, DailyReward, User + +def calculate_reward(day): + if day == 1: + return 20 + elif day == 2: + return 50 + elif day == 3: + return 100 + elif day == 4: + return 150 + elif day == 5: + return 200 + elif day == 6: + return 250 + elif day == 7: + return 300 + elif day == 8: + return 350 + elif day == 9: + return 400 + elif day == 10: + return 500 + else: + return 500 + (day - 10) * 100 + +def my_scheduled_job(): + # Удаляем старые записи списка наград + DailyRewardsList.objects.all().delete() + + # Определяем максимальное количество дней в текущем месяце + now = datetime.datetime.now() + next_month = now.month + 1 if now.month < 12 else 1 + next_year = now.year if now.month < 12 else now.year + 1 + max_day = (datetime.date(next_year, next_month, 1) - datetime.date(now.year, now.month, 1)).days + + # Создаем новый DailyRewardsList + month_max_day = f'До {max_day}' + new_daily_rewards_list = DailyRewardsList.objects.create(active_day=1, month_max_day=month_max_day) + + # Очищаем предыдущие награды + DailyReward.objects.all().delete() + + # Создаем новые ежедневные награды для каждого пользователя + users = User.objects.all() + for user in users: + for day in range(1, max_day + 1): + reward_amount = calculate_reward(day) + DailyReward.objects.create(user=user, day=day, reward_amount=reward_amount) + +def run_scheduler(): + while True: + now = datetime.datetime.now() + # Проверяем, что текущее время 00:05 + + if now.day == 1 and now.hour == 21 and now.minute == 5: + my_scheduled_job() + # Ждем 60 секунд, чтобы избежать повторного выполнения задачи в эту же минуту + time.sleep(60) + +def start_scheduler(): + thread = threading.Thread(target=run_scheduler, daemon=True) + thread.start() diff --git a/users/tests.py b/users/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/users/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/users/views.py b/users/views.py new file mode 100644 index 0000000..06a773d --- /dev/null +++ b/users/views.py @@ -0,0 +1,167 @@ +from .models import User, DailyReward, DailyRewardsList, Balance, Levels +from .serializers import UserSerializer, DailyRewardSerializer, DailyRewardsListSerializer, BalanceSerializer, LevelsSerializer +from rest_framework import status, viewsets +from rest_framework.decorators import action +from rest_framework.response import Response + + +class UserViewSet(viewsets.ModelViewSet): + queryset = User.objects.all() + serializer_class = UserSerializer + + @action(detail=True, methods=['get']) + def get_datetime(self, request): + # Получаем текущие дату и время + current_datetime = timezone.now() + return Response({'datetime': current_datetime}) + + + @action(detail=True, methods=['get']) + def get_referrals(self, request, pk=None): + user = self.get_object() + + # Процентные ставки для каждого уровня + referral_percentages = { + 1: 0.10, # 10% за рефералы 1 уровня + 2: 0.06, # 6% за рефералы 2 уровня + 3: 0.03, # 3% за рефералы 3 уровня + 4: 0.01, # 1% за рефералы 4 уровня + } + + # Рефералы по уровням + level_1_referrals = user.referrals.all() + level_2_referrals = User.objects.filter(referred_by__in=level_1_referrals) + level_3_referrals = User.objects.filter(referred_by__in=level_2_referrals) + level_4_referrals = User.objects.filter(referred_by__in=level_3_referrals) + + referral_levels = { + 1: level_1_referrals, + 2: level_2_referrals, + 3: level_3_referrals, + 4: level_4_referrals, + } + + total_coins = 0 + for level, referrals in referral_levels.items(): + # Фильтруем баланс рефералов, у которых валюта 'MCDC' + coins = Balance.objects.filter(user__in=referrals, currency='MCDC').aggregate(total=Sum('balance'))['total'] or 0 + bonus_coins = coins * referral_percentages[level] + total_coins += bonus_coins + + # Вычитаем уже полученные бонусы + total_coins -= user.coins_for_referral + + response_data = { + "total_coins": total_coins, + "level_1_referrals": list(level_1_referrals.values('tg_username', 'tg_id', 'name', 'photo', 'coins_for_referral')), + "level_2_referrals": list(level_2_referrals.values('tg_username', 'tg_id', 'name', 'photo', 'coins_for_referral')), + "level_3_referrals": list(level_3_referrals.values('tg_username', 'tg_id', 'name', 'photo', 'coins_for_referral')), + "level_4_referrals": list(level_4_referrals.values('tg_username', 'tg_id', 'name', 'photo', 'coins_for_referral')), + } + print(response_data) # TODOPROJECT remove it + return Response({'status': '200', 'data': response_data}) + + +class DailyRewardViewSet(viewsets.ModelViewSet): + queryset = DailyReward.objects.all() + serializer_class = DailyRewardSerializer + + +class DailyRewardsListViewSet(viewsets.ModelViewSet): + queryset = DailyRewardsList.objects.all() + serializer_class = DailyRewardsListSerializer + +class BalanceViewSet(viewsets.ModelViewSet): + queryset = Balance.objects.all() + serializer_class = BalanceSerializer + + @action(detail=True, methods=['post']) + def add_for_balance(self, request, pk=None): + user = self.get_object().user + amount = request.data.get("amount") + currency = request.data.get("currency") + + if not amount or not currency: + return Response({"status": "error", "message": "Пожалуйста, укажите сумму и валюту"}, status=status.HTTP_400_BAD_REQUEST) + + # Создаем новую транзакцию в базе данных + with db_transaction.atomic(): + transaction = Transaction.objects.create( + user=user, + amount=amount, + currency=currency, + status="Pending" + ) + + # Формирование данных для запроса + data = { + "amount": amount, + "currency": currency, + "user_id": user.id, + "transaction_id": transaction.id + } + + # Отправка POST-запроса к API Turcode + try: + response = requests.post( + "https://api.turcode.cc/v1/payment", + json=data, + headers={"Authorization": f"Bearer {settings.TURCODE_API_KEY}"} + ) + + # Обработка ответа от API + if response.status_code == 200: + transaction.status = "Success" + transaction.save() + + # Обновление баланса пользователя + user_balance = self.get_object() + user_balance.balance += int(amount) + user_balance.save() + + return Response({"status": "success", "message": "Баланс успешно пополнен"}, status=status.HTTP_200_OK) + else: + transaction.status = "Failed" + transaction.save() + return Response({"status": "error", "message": "Не удалось выполнить платеж"}, status=status.HTTP_400_BAD_REQUEST) + + except requests.RequestException as e: + transaction.status = "Error" + transaction.save() + return Response({"status": "error", "message": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + +class LevelsViewSet(viewsets.ModelViewSet): + queryset = Levels.objects.all() + serializer_class = LevelsSerializer + + @action(detail=True, methods=['post']) + def create_new_levels(self, request, pk=None): + user = self.get_object() + levels = [] + + # Задаем названия и изображения для каждого уровня + level_data = [ + {"name": "Huey", "coins": 0, "image": "static/media/levels/character1.jpg"}, + {"name": "Dewey", "coins": 10000, "image": "static/media/levels/character2.jpg"}, + {"name": "Donald Duck", "coins": 20000, "image": "static/media/levels/character3.jpg"}, + {"name": "Launchpad", "coins": 30000, "image": "static/media/levels/character4.jpg"}, + {"name": "Gearloose", "coins": 40000, "image": "static/media/levels/character5.jpg"}, + {"name": "Magica", "coins": 50000, "image": "static/media/levels/character6.jpg"}, + {"name": "Scrooge", "coins": 60000, "image": "static/media/levels/character7.jpg"}, + ] + + for i, data in enumerate(level_data, start=1): + level = Levels( + user=user, + name=data["name"], + level=i, + photo=data["image"], + need_coins=data["coins"] + ) + levels.append(level) + + # Сохраняем все созданные объекты в базе данных + Levels.objects.bulk_create(levels) + + return Response({'status': '200', 'message': f'Created {len(levels)} levels for user {user.username}.'}) \ No newline at end of file