diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..621ddc5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,89 @@
+# Created by https://www.gitignore.io
+
+### OSX ###
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear on external disk
+.Spotlight-V100
+.Trashes
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# 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/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+*.pot
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+
+### Django ###
+*.log
+*.pot
+*.pyc
+__pycache__/
+local_settings.py
+
+.env
+db.sqlite3
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..d29904c
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,39 @@
+stages:
+ - test
+ - deploy
+
+before_script:
+ - apk update
+ - apk add pkgconfig
+ - apk add mariadb-connector-c-dev build-base
+
+
+test:
+ stage: test
+ image: python:3.9-alpine
+ script:
+ - pip install --upgrade pip
+ - pip install django
+ - pip install -r requirements.txt
+ - pip install python-dotenv
+ - python manage.py test
+
+deploy:
+ stage: deploy
+ image: python:3.9-alpine
+ before_script:
+ - apk add --no-cache openssh-client
+ - eval $(ssh-agent -s)
+ - echo "$SSH_PRIVATE_KEY" | ssh-add -
+ - ssh -o StrictHostKeyChecking=no $SSH_USER@$SERVER_IP echo "SSH-connection successful."
+ script:
+ - mkdir deploy
+ - cp -r core deploy/
+ - cp -r server deploy/
+ - cp manage.py requirements.txt test.rest docker-compose.yml Dockerfile deploy/
+ - ls deploy/
+ - scp -r deploy $SSH_USER@$SERVER_IP:$DEPLOY_PATH/
+ - ssh $SSH_USER@$SERVER_IP "cd $DEPLOY_PATH/deploy && docker compose down"
+ - ssh $SSH_USER@$SERVER_IP "cd $DEPLOY_PATH/deploy && docker compose up -d"
+ only:
+ - main
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..476a243
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,19 @@
+FROM python:3.9
+
+# Set environment variables
+ENV PYTHONDONTWRITEBYTECODE 1
+ENV PYTHONUNBUFFERED 1
+ENV PYTHONPATH=/code:/code/CLINET_APPS
+
+# Set work directory
+WORKDIR /code
+
+# Update pip
+RUN pip install --upgrade pip
+
+# Install dependencies
+COPY requirements.txt /code/
+RUN pip install -r requirements.txt
+
+# Copy project
+COPY . /code/
\ No newline at end of file
diff --git a/REDME.md b/REDME.md
new file mode 100644
index 0000000..debad18
--- /dev/null
+++ b/REDME.md
@@ -0,0 +1,7 @@
+python3 manage.py runserver 0.0.0.0:8000
+
+pm2 start "python3 manage.py runserver 0.0.0.0:8000 " --name "serverDjango"
+
+pm2 start "npm run dev -- --host 0.0.0.0 " --name "vue"
+
+npm run dev -- --host 0.0.0.0
diff --git a/core/__init__.py b/core/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/core/admin.py b/core/admin.py
new file mode 100644
index 0000000..424f49f
--- /dev/null
+++ b/core/admin.py
@@ -0,0 +1,11 @@
+from django.contrib import admin
+
+from core.models.customer import Customer
+from core.models.role import Role
+# from .model import user
+from core.models.AssignedRule import AssignedRule
+
+
+admin.site.register(Role)
+admin.site.register(AssignedRule)
+admin.site.register(Customer)
diff --git a/core/asgi.py b/core/asgi.py
new file mode 100644
index 0000000..a6b478a
--- /dev/null
+++ b/core/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for server 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.2/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
+
+application = get_asgi_application()
diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py
new file mode 100644
index 0000000..6984443
--- /dev/null
+++ b/core/migrations/0001_initial.py
@@ -0,0 +1,47 @@
+# Generated by Django 5.0 on 2025-04-12 14:25
+
+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='Role',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=100, unique=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Customer',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('profile_img', models.CharField(max_length=255)),
+ ('profile_glb', models.CharField(max_length=255)),
+ ('mobile_number', models.CharField(max_length=15)),
+ ('verification_sms_code', models.CharField(blank=True, max_length=6)),
+ ('verification_email_code', models.CharField(blank=True, max_length=6)),
+ ('is_sms_verified', models.BooleanField(default=False)),
+ ('is_email_verified', models.BooleanField(default=False)),
+ ('sms_time_for_valid', models.DateTimeField(blank=True, null=True)),
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='AssignedRule',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ('role', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.role')),
+ ],
+ ),
+ ]
diff --git a/core/migrations/0002_alter_customer_profile_glb_and_more.py b/core/migrations/0002_alter_customer_profile_glb_and_more.py
new file mode 100644
index 0000000..b8c7b08
--- /dev/null
+++ b/core/migrations/0002_alter_customer_profile_glb_and_more.py
@@ -0,0 +1,23 @@
+# Generated by Django 5.0 on 2025-04-12 14:28
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='customer',
+ name='profile_glb',
+ field=models.CharField(blank=True, max_length=255),
+ ),
+ migrations.AlterField(
+ model_name='customer',
+ name='profile_img',
+ field=models.CharField(blank=True, max_length=255),
+ ),
+ ]
diff --git a/core/migrations/__init__.py b/core/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/core/models/AssignedRule.py b/core/models/AssignedRule.py
new file mode 100644
index 0000000..7f2b8d0
--- /dev/null
+++ b/core/models/AssignedRule.py
@@ -0,0 +1,9 @@
+# models.py
+from django.contrib.auth.models import User
+from .role import Role
+from django.db import models
+
+class AssignedRule(models.Model):
+ user = models.ForeignKey(User, on_delete=models.CASCADE)
+ role = models.ForeignKey(Role, on_delete=models.CASCADE)
+ # Add any other fields you need
diff --git a/core/models/customer.py b/core/models/customer.py
new file mode 100644
index 0000000..db1d551
--- /dev/null
+++ b/core/models/customer.py
@@ -0,0 +1,23 @@
+
+
+from django.db import models
+from django.contrib.auth.models import User
+
+
+class Customer(models.Model):
+ user = models.OneToOneField(User, on_delete=models.CASCADE)
+
+
+ mobile_number = models.CharField(max_length=15) # Adjust max length as per your needs
+ profile_img = models.CharField(max_length=255,blank=True) # Adjust max length as per your needs
+ profile_glb = models.CharField(max_length=255,blank=True) # Adjust max length as per your needs
+
+ verification_sms_code = models.CharField(blank=True,max_length=6) # Adjust max length as per your needs
+ verification_email_code = models.CharField(blank=True,max_length=6) # Adjust max length as per your needs
+
+ is_sms_verified = models.BooleanField(default=False)
+ is_email_verified = models.BooleanField(default=False)
+ sms_time_for_valid = models.DateTimeField(blank=True, null=True)
+
+ def __str__(self):
+ return self.user.username
\ No newline at end of file
diff --git a/core/models/role.py b/core/models/role.py
new file mode 100644
index 0000000..b931b79
--- /dev/null
+++ b/core/models/role.py
@@ -0,0 +1,6 @@
+from django.db import models
+
+class Role(models.Model):
+ name = models.CharField(max_length=100, unique=True)
+
+
diff --git a/core/serializers/CustomerSerializer.py b/core/serializers/CustomerSerializer.py
new file mode 100644
index 0000000..e6281ff
--- /dev/null
+++ b/core/serializers/CustomerSerializer.py
@@ -0,0 +1,7 @@
+from rest_framework import serializers
+from ..models.customer import Customer
+
+class CustomerSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Customer
+ fields = '__all__'
diff --git a/core/serializers/UserSerializer.py b/core/serializers/UserSerializer.py
new file mode 100644
index 0000000..5abea61
--- /dev/null
+++ b/core/serializers/UserSerializer.py
@@ -0,0 +1,8 @@
+from rest_framework import serializers
+# from ..models.user import User
+from django.contrib.auth.models import User
+
+class UserSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = User
+ fields = ['id', 'username', 'email' , 'password' ]
diff --git a/core/serializers/__init__.py b/core/serializers/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/core/settings.py b/core/settings.py
new file mode 100644
index 0000000..78425cc
--- /dev/null
+++ b/core/settings.py
@@ -0,0 +1,161 @@
+"""
+Django settings for server project.
+
+Generated by 'django-admin startproject' using Django 4.2.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/4.2/ref/settings/
+"""
+
+from pathlib import Path
+import os
+from dotenv import load_dotenv
+import sys
+
+# Load environment variables from .env file
+load_dotenv()
+# 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.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'django-insecure-q1-xt8(+yr^6iye@sa3@miqn&(#-be96ild1s!o)wlmwqrzd3-'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+# ALLOWED_HOSTS = ['0.0.0.0']
+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',
+ 'rest_framework.authtoken',
+ 'core',
+ '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',
+
+]
+CORS_ALLOW_ALL_ORIGINS = True # If this is used then `CORS_ALLOWED_ORIGINS` will not have any effect
+
+ROOT_URLCONF = 'core.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 = 'core.wsgi.application'
+
+
+
+# Database
+# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
+
+if 'test' in sys.argv:
+ DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': BASE_DIR / 'db.sqlite3',
+ }
+ }
+else:
+ DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.mysql',
+ 'NAME': 'core1',
+ 'USER': 'root',
+ 'PASSWORD': '',
+ 'HOST': 'localhost',
+ 'PORT': '3306',
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/4.2/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.2/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.2/howto/static-files/
+
+STATIC_URL = 'static/'
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
+
+
+EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
+EMAIL_HOST = 'smtp.ionos.de'
+EMAIL_PORT = 465
+EMAIL_USE_SSL = True
+EMAIL_HOST_USER = 'mail@clinet.club'
+EMAIL_HOST_PASSWORD = 'uzudzsd78786d7asd56gasdbsad'
+DEFAULT_FROM_EMAIL = 'mail@clinet.club'
+
diff --git a/core/templates/emails/verification_email_template.html b/core/templates/emails/verification_email_template.html
new file mode 100644
index 0000000..2825d19
--- /dev/null
+++ b/core/templates/emails/verification_email_template.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ Hallo, Willkommen bei WZK. Ihr E-Mail-Bestätigungscode lautet:
+ {{ verification_code }}
+
+
diff --git a/core/templates/emails/verification_email_template2.html b/core/templates/emails/verification_email_template2.html
new file mode 100644
index 0000000..d057067
--- /dev/null
+++ b/core/templates/emails/verification_email_template2.html
@@ -0,0 +1,764 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WZK Bestätigungscode,
+
+
+ Hallo, Willkommen bei WZK. Ihr
+ E-Mail-Bestätigungscode lautet
+
+
+ Before we get started, we'll need to verify your
+ email.
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FUN FACT #16
+
+ |
+
+
+
+
+ In Hearthstone, using the Hunter card Animal Companion
+ against Kel'Thuzad will summon his cat Mr.
+ Bigglesworth rather than the usual beasts.
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+ 444 De Haro Street, Suite 200, San Francisco, CA 94107
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
diff --git a/core/tests/__init__.py b/core/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/core/tests/test_signup.py b/core/tests/test_signup.py
new file mode 100644
index 0000000..01cdc16
--- /dev/null
+++ b/core/tests/test_signup.py
@@ -0,0 +1,57 @@
+from django.urls import reverse
+from rest_framework.test import APITestCase, APIClient
+from rest_framework import status
+from django.contrib.auth.models import User
+from rest_framework.authtoken.models import Token
+
+class PatientSignUpTest(APITestCase):
+ def setUp(self):
+ self.client = APIClient()
+ self.signup_url = reverse('signup') # Ensure you have named your URL in urls.py
+
+ # def test_signup_valid(self):
+ # """
+ # Ensure we can create a new user and patient with valid data.
+ # """
+ # data = {
+ # 'fallnumber': '123',
+ # 'username': 'newuser2',
+ # 'password': 'newpassword123',
+ # 'email': 'user2@example.com',
+ # 'birthday': '1990-10-10',
+ # 'mobile_number': '1234567890'
+ # }
+ # response = self.client.post(self.signup_url, data, format='json')
+ # self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+ # self.assertIn('token', response.data)
+ # self.assertEqual(User.objects.count(), 1)
+ # self.assertEqual(Token.objects.count(), 1)
+
+ def test_signup_invalid_user_data(self):
+ """
+ Ensure user data is validated.
+ """
+ data = {
+ 'username': 'newuser', # Missing password and email
+ 'birthday': '2000-01-01',
+ 'mobile_number': '1234567890'
+ }
+ response = self.client.post(self.signup_url, data, format='json')
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+ self.assertEqual(User.objects.count(), 0)
+
+ def test_signup_invalid_patient_data(self):
+ """
+ Ensure patient data is validated and no user is created if patient data is invalid.
+ """
+ data = {
+ 'username': 'newuser',
+ 'password': 'newpassword123',
+ 'email': 'user@example.com',
+ 'birthday': 'not-a-date', # Invalid date format
+ 'mobile_number': '1234567890'
+ }
+ response = self.client.post(self.signup_url, data, format='json')
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+ self.assertEqual(User.objects.count(), 0)
+
diff --git a/core/urls.py b/core/urls.py
new file mode 100644
index 0000000..88e78ea
--- /dev/null
+++ b/core/urls.py
@@ -0,0 +1,31 @@
+from django.urls import re_path
+from django.contrib import admin
+from django.urls import path
+
+from .views import userView
+from django.urls import include, path
+
+urlpatterns = [
+
+ path('admin/', admin.site.urls),
+
+
+ # re_path(r'^signup/$', userView.signup, name="signup"),
+
+ re_path('signup', userView.signup , name="signup"),
+ re_path('login', userView.login),
+ re_path('getInfo', userView.getInfo),
+
+ re_path('sendSmsVerification', userView.sendSmsVerification),
+ re_path('sendEmailVerification', userView.sendEmailVerification),
+ re_path('submitEmailVerification', userView.submitEmailVerification),
+ re_path('submitSmsVerification', userView.submitSmsVerification),
+
+ re_path('sendForgetPasswordCode', userView.sendForgetPasswordCode),
+ re_path('sendCodeAndNewPassword', userView.sendCodeAndNewPassword),
+
+
+
+
+
+]
diff --git a/core/views.py b/core/views.py
new file mode 100644
index 0000000..cb89600
--- /dev/null
+++ b/core/views.py
@@ -0,0 +1,58 @@
+from django.contrib.auth import get_user_model
+from rest_framework.authtoken.models import Token
+from rest_framework.decorators import api_view, authentication_classes, permission_classes
+from rest_framework.authentication import SessionAuthentication, TokenAuthentication
+from rest_framework.permissions import IsAuthenticated
+from rest_framework.response import Response
+from rest_framework import status
+
+# from .models.user import User
+from django.contrib.auth.models import User
+
+from .serializers.UserSerializer import UserSerializer
+
+# from .serializers.user import UserSerializer
+
+
+
+# utils.py
+from .models.AssignedRule import AssignedRule
+
+def user_has_role(user, role_name):
+ return AssignedRule.objects.filter(user=user, role__name=role_name).exists()
+
+
+
+@api_view(['POST'])
+def signup(request):
+ serializer = UserSerializer(data=request.data)
+ if serializer.is_valid():
+ user = serializer.save()
+ user.set_password(request.data['password'])
+ user.save()
+ token = Token.objects.create(user=user)
+ return Response({'token': token.key, 'user': serializer.data})
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+@api_view(['POST'])
+def login(request):
+ try:
+ user = get_user_model().objects.get(email=request.data['email'])
+ except get_user_model().DoesNotExist:
+ return Response("User not found", status=status.HTTP_404_NOT_FOUND)
+
+ if not user.check_password(request.data['password']):
+ return Response("Invalid password", status=status.HTTP_401_UNAUTHORIZED)
+
+ token, created = Token.objects.get_or_create(user=user)
+ serializer = UserSerializer(user)
+ return Response({'token': token.key, 'user': serializer.data})
+
+@api_view(['GET'])
+@authentication_classes([SessionAuthentication, TokenAuthentication])
+@permission_classes([IsAuthenticated])
+def test_token(request):
+ if not user_has_role(request.user, 'admin'):
+ return Response({'message': 'No access'}, status=status.HTTP_403_FORBIDDEN)
+
+ return Response({'message': 'User has admin role'})
diff --git a/core/views/__init__.py b/core/views/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/core/views/userView.py b/core/views/userView.py
new file mode 100644
index 0000000..a7086b1
--- /dev/null
+++ b/core/views/userView.py
@@ -0,0 +1,353 @@
+from pickle import TRUE
+import random
+from datetime import datetime, timedelta
+
+
+from django.contrib.auth import get_user_model
+from rest_framework.authtoken.models import Token
+from rest_framework.decorators import api_view, authentication_classes, permission_classes
+from rest_framework.authentication import SessionAuthentication, TokenAuthentication
+from rest_framework.permissions import IsAuthenticated
+from rest_framework.response import Response
+from rest_framework import status
+
+from django.contrib.auth.models import User
+
+from core.models.customer import Customer
+from core.serializers.UserSerializer import UserSerializer
+from core.serializers.CustomerSerializer import CustomerSerializer
+
+# utils.py
+from core.models.AssignedRule import AssignedRule
+
+
+from django.core.mail import EmailMultiAlternatives
+from django.template.loader import render_to_string
+from django.utils.html import strip_tags
+from django.conf import settings
+from django.utils.dateparse import parse_date
+
+
+
+import requests
+import json
+
+def send_sms(to_number, code):
+ username = "09399112092"
+ password = "Dadechin123!@##!"
+ from_number = "+983000505"
+ pattern_code = "lgfrblbdppyn202"
+
+ url = "https://ippanel.com/patterns/pattern"
+ to = [to_number]
+ input_data = {"code": code}
+
+ params = {
+ "username": username,
+ "password": password,
+ "from": from_number,
+ "to": json.dumps(to),
+ "input_data": json.dumps(input_data),
+ "pattern_code": pattern_code
+ }
+
+ try:
+ response = requests.post(url, params=params, data=input_data)
+ return response.text
+ except Exception as e:
+ return f"Error: {e}"
+
+
+def user_has_role(user, role_name):
+ return AssignedRule.objects.filter(user=user, role__name=role_name).exists()
+
+
+@api_view(['POST'])
+def signup(request):
+ # Check if username already exists
+ if User.objects.filter(username=request.data['username']).exists():
+ return Response({'username': ['A user with that username already exists.']}, status=status.HTTP_400_BAD_REQUEST)
+
+ # Ensure mobile number is provided
+ if 'mobile_number' not in request.data:
+ return Response({'mobile_number': ['This field is required.']}, status=status.HTTP_400_BAD_REQUEST)
+
+
+ # Proceed with user creation
+ user_serializer = UserSerializer(data=request.data)
+ if user_serializer.is_valid():
+ user = user_serializer.save()
+ user.set_password(request.data['password'])
+ user.save()
+
+ customer_data = {
+ 'user': user.id,
+ 'mobile_number': request.data['mobile_number'], # Ensure mobile number is provided
+ }
+ customer_serializer = CustomerSerializer(data=customer_data)
+ if customer_serializer.is_valid():
+ customer_serializer.save()
+ token = Token.objects.create(user=user)
+ return Response({'token': token.key, 'user': customer_serializer.data}, status=status.HTTP_201_CREATED)
+ else:
+ # If customer data is invalid, delete the created user
+ user.delete()
+ return Response(customer_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+ else:
+ return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+@api_view(['POST'])
+def sendForgetPasswordCode(request):
+ try:
+
+
+ # Retrieve the associated customer object
+ customer = Customer.objects.get(mobile_number=request.data['mobile_number'])
+
+
+ # Generate a random verification code
+ verification_code = str(random.randint(100000, 999999))
+
+ # Update user's verification_code and sms_time_for_valid
+ customer.verification_email_code = verification_code
+ customer.verification_sms_code = verification_code
+ customer.save()
+
+ sendEmail(customer.user.email,verification_code)
+
+ return Response({"message": ("Email verification code sent successfully. " + customer.user.email)})
+
+ except Customer.DoesNotExist:
+ # If no customer object exists for the user, return an error response
+ return Response({'error': 'No customer data found for this user'}, status=404)
+
+
+
+
+
+from django.contrib.auth.hashers import make_password
+
+@api_view(['POST'])
+def sendCodeAndNewPassword(request):
+ try:
+ # Retrieve the associated customer object
+ customer = Customer.objects.get(mobile_number=request.data['mobile_number'], verification_sms_code=request.data['verification_sms_code'])
+
+ if customer:
+ # Update the user's password
+ customer.user.password = make_password(request.data['password'])
+ customer.user.save()
+ return Response({"message": "Password has been changed successfully."})
+ else:
+ return Response({"message": "Wrong mobile number or verification code."})
+
+ except Customer.DoesNotExist:
+ # If no customer object exists for the user, return an error response
+ return Response({'message': 'No customer data found for this user'}, status=404)
+
+
+
+
+@api_view(['POST'])
+def login(request):
+ try:
+ customer = Customer.objects.get(mobile_number=request.data['mobile_number'])
+ except get_user_model().DoesNotExist:
+ return Response("User not found", status=status.HTTP_404_NOT_FOUND)
+
+ if not customer.user.check_password(request.data['password']):
+ return Response("Invalid password", status=status.HTTP_401_UNAUTHORIZED)
+
+ token, created = Token.objects.get_or_create(user=customer.user)
+ serializer = UserSerializer(customer.user)
+ return Response({'token': token.key, 'user': serializer.data})
+
+
+
+
+
+@api_view(['GET'])
+@authentication_classes([SessionAuthentication, TokenAuthentication])
+@permission_classes([IsAuthenticated])
+def sendSmsVerification(request):
+ # Retrieve the current user
+ user = request.user
+
+ # Assuming a OneToOneField relation between User and Customer
+ try:
+ # Retrieve the associated customer object
+ customer = Customer.objects.get(user=user)
+
+
+ # Generate a random verification code
+ verification_code = str(random.randint(100000, 999999))
+
+ # Update user's verification_code and sms_time_for_valid
+ customer.verification_sms_code = verification_code
+ customer.sms_time_for_valid = datetime.now() + timedelta(minutes=10) # Set validity time to now + 10 minutes
+ customer.save()
+
+ sms_response = send_sms(customer.mobile_number, verification_code)
+
+ # Send SMS with verification code (implement this part according to your SMS service provider's API)
+ # send_sms(user.mobile_number, verification_code) # You need to implement this function
+
+ return Response({
+ "message": "SMS verification code sent successfully.",
+ "sms_response": sms_response
+ })
+
+ except Customer.DoesNotExist:
+ # If no customer object exists for the user, return an error response
+ return Response({'error': 'No customer data found for this user'}, status=404)
+
+
+
+@api_view(['GET'])
+@authentication_classes([SessionAuthentication, TokenAuthentication])
+@permission_classes([IsAuthenticated])
+def getInfo(request):
+ # Retrieve the current user
+ user = request.user
+
+ # Assuming a OneToOneField relation between User and Customer
+ try:
+ # Retrieve the associated customer object
+ customer = Customer.objects.get(user=user)
+
+ # Serialize the customer data
+ serializer = CustomerSerializer(customer)
+
+ # Return the serialized customer data
+ return Response(serializer.data)
+ except Customer.DoesNotExist:
+ return Response({'error': 'No customer data found for this user'}, status=404)
+
+ # If no customer object exists for the user, return an error response
+
+
+
+
+@api_view(['GET'])
+@authentication_classes([SessionAuthentication, TokenAuthentication])
+@permission_classes([IsAuthenticated])
+def sendEmailVerification(request):
+ # Retrieve the current user
+ user = request.user
+
+ # Assuming a OneToOneField relation between User and Customer
+ try:
+ # Retrieve the associated customer object
+ customer = Customer.objects.get(user=user)
+
+
+ # Generate a random verification code
+ verification_code = str(random.randint(100000, 999999))
+
+ # Update user's verification_code and sms_time_for_valid
+ customer.verification_email_code = verification_code
+ customer.save()
+
+ sendEmail(user.email,verification_code)
+
+ return Response({"message": ("Email verification code sent successfully. " + user.email)})
+
+ except Customer.DoesNotExist:
+ # If no customer object exists for the user, return an error response
+ return Response({'error': 'No customer data found for this user'}, status=404)
+
+
+
+
+def sendEmail(email, verification_code):
+ subject = 'WZK Bestätigungscode'
+ context = {'verification_code': verification_code}
+
+ # Render HTML content from a template
+ # html_content = render_to_string('core/templates/emails/email_template.html', context)
+ html_content = render_to_string('emails/verification_email_template2.html', context)
+
+ # Create a plain text version of the email (optional)
+ text_content = strip_tags(html_content)
+
+ email_from = settings.DEFAULT_FROM_EMAIL
+ recipient_list = [email]
+
+ try:
+ # Create an EmailMultiAlternatives object
+ msg = EmailMultiAlternatives(subject, text_content, email_from, recipient_list)
+
+ # Attach the HTML content to the email
+ msg.attach_alternative(html_content, "text/html")
+
+ # Send the email
+ msg.send()
+
+ print("Email has been sent! ")
+ return True
+ except Exception as e:
+ print(f"Error sending email: {e}")
+ return False
+
+
+
+
+@api_view(['POST'])
+@authentication_classes([SessionAuthentication, TokenAuthentication])
+@permission_classes([IsAuthenticated])
+def submitEmailVerification(request):
+ try:
+ user = request.user
+
+ customer = Customer.objects.get(user=user)
+
+ if customer.verification_email_code == request.data['verification_email_code'] :
+ customer.is_email_verified = True
+ customer.save()
+ return Response({"message": "Email Verified!"})
+ # else :
+ # return Response({"message": customer.verification_email_code})
+
+
+
+ except get_user_model().DoesNotExist:
+ return Response("Not verified 1", status=status.HTTP_404_NOT_FOUND)
+ return Response("Not verified ", status=status.HTTP_404_NOT_FOUND)
+
+
+
+
+@api_view(['POST'])
+@authentication_classes([SessionAuthentication, TokenAuthentication])
+@permission_classes([IsAuthenticated])
+def submitSmsVerification(request):
+ try:
+ user = request.user
+
+ customer = Customer.objects.get(user=user)
+
+ if customer.verification_sms_code == request.data['verification_sms_code'] :
+ customer.is_sms_verified = True
+ customer.save()
+ return Response({"message": "SMS Verified!"})
+ # else :
+ # return Response({"message": customer.verification_email_code})
+
+
+
+ except get_user_model().DoesNotExist:
+ return Response("Not verified 1", status=status.HTTP_404_NOT_FOUND)
+ return Response("Not verified ", status=status.HTTP_404_NOT_FOUND)
+
+
+
+
+
+@api_view(['GET'])
+@authentication_classes([SessionAuthentication, TokenAuthentication])
+@permission_classes([IsAuthenticated])
+def test_token(request):
+ if not user_has_role(request.user, 'admin'):
+ return Response({'message': 'No access'}, status=status.HTTP_403_FORBIDDEN)
+
+ return Response({'message': 'User has admin role'})
diff --git a/core/wsgi.py b/core/wsgi.py
new file mode 100644
index 0000000..e6e1fe9
--- /dev/null
+++ b/core/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for server 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.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
+
+application = get_wsgi_application()
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..a032143
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,30 @@
+version: "3.6"
+
+services:
+ db:
+ image: mysql:latest
+ environment:
+ MYSQL_ROOT_PASSWORD: CLINET999zztt
+ MYSQL_DATABASE: mysql_clinet
+ MYSQL_USER: clinet_dbadmin_pg
+ MYSQL_PASSWORD: CLINET999zztt
+ volumes:
+ - mysql_data:/var/lib/mysql_test_newplatform/data
+
+ web:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ command: sh -c "sleep 20 && python manage.py runserver 0.0.0.0:55"
+ volumes:
+ - .:/code
+ ports:
+ - "55:55"
+ depends_on:
+ - db
+ environment:
+ DJANGO_SETTINGS_MODULE: core.settings
+ MYSQL_UNIX_PORT: /var/run/mysqld/mysqld.sock
+
+volumes:
+ mysql_data:
diff --git a/manage.py b/manage.py
new file mode 100644
index 0000000..f2a662c
--- /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', 'core.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..fca4b01
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,7 @@
+djangorestframework==3.15.1
+django-cors-headers==4.3.1
+pymysql==1.1.0
+python-dotenv==1.0.1
+mysqlclient==2.1.1
+
+py -m pip install Django==5.2
diff --git a/server/views.py b/server/views.py
new file mode 100644
index 0000000..6ec0936
--- /dev/null
+++ b/server/views.py
@@ -0,0 +1,49 @@
+from rest_framework.decorators import api_view, authentication_classes, permission_classes
+from rest_framework.authentication import SessionAuthentication, TokenAuthentication
+from rest_framework.permissions import IsAuthenticated
+from rest_framework.response import Response
+from rest_framework import status
+
+from django.shortcuts import get_object_or_404
+from django.contrib.auth.models import User
+from rest_framework.authtoken.models import Token
+# from models.user import User
+# from .models.serializers import UserSerializer
+
+from .models.user import UserSerializer
+
+
+# utils.py
+from .models.AssignedRule import AssignedRule
+
+def user_has_role(user, role_name):
+ return AssignedRule.objects.filter(user=user, role__name=role_name).exists()
+
+
+
+@api_view(['POST'])
+def signup(request):
+ serializer = UserSerializer(data=request.data)
+ if serializer.is_valid():
+ serializer.save()
+ user = User.objects.get(username=request.data['username'])
+ user.set_password(request.data['password'])
+ user.save()
+ token = Token.objects.create(user=user)
+ return Response({'token': token.key, 'user': serializer.data})
+ return Response(serializer.errors, status=status.HTTP_200_OK)
+
+@api_view(['POST'])
+def login(request):
+ user = get_object_or_404(User, username=request.data['username'])
+ if not user.check_password(request.data['password']):
+ return Response("missing user", status=status.HTTP_404_NOT_FOUND)
+ token, created = Token.objects.get_or_create(user=user)
+ serializer = UserSerializer(user)
+ return Response({'token': token.key, 'user': serializer.data})
+
+@api_view(['GET'])
+@authentication_classes([SessionAuthentication, TokenAuthentication])
+@permission_classes([IsAuthenticated])
+def test_token(request):
+ return Response("passed!")
\ No newline at end of file
diff --git a/test.rest b/test.rest
new file mode 100644
index 0000000..21e69bd
--- /dev/null
+++ b/test.rest
@@ -0,0 +1,71 @@
+# https://marketplace.visualstudio.com/items?itemName=humao.rest-client
+
+POST http://127.0.0.1:8000/signup
+Content-Type: application/json
+
+{ "username": "adam3", "password": "Pass1234!", "email": "adam2@mail.com" , "mobile_number":"09140086509" }
+
+###
+
+POST http://127.0.0.1:8000/login
+Content-Type: application/json
+
+{ "mobile_number":"09140086509", "password": "Pass1234!" }
+
+###
+
+GET http://127.0.0.1:8000/sendSmsVerification
+Content-Type: application/json
+Authorization: token cb8c2ef7913df31085e749398f22da5b43f419b2
+
+###
+
+POST http://127.0.0.1:8000/submitSmsVerification
+Content-Type: application/json
+Authorization: token cb8c2ef7913df31085e749398f22da5b43f419b2
+
+{ "verification_sms_code": "807806" }
+
+###
+
+GET http://127.0.0.1:8000/test_token
+Content-Type: application/json
+Authorization: token c362581117e209735d412226e54596867e370892
+# Authorization: token 53e2b003a92e22aca85c95088a438ece8d9a5dfb
+
+
+###
+
+GET http://127.0.0.1:8000/getInfo
+Content-Type: application/json
+Authorization: token 3d5ab31449b6a075e3967559526d5e31977431a1
+# Authorization: token 53e2b003a92e22aca85c95088a438ece8d9a5dfb
+
+
+###
+GET http://127.0.0.1:8000/templatequestions
+Content-Type: application/json
+Authorization: token c362581117e209735d412226e54596867e370892
+
+
+###
+GET http://127.0.0.1:8000/templatequestionscgm
+Content-Type: application/json
+Authorization: token c362581117e209735d412226e54596867e370892
+
+
+###
+GET http://127.0.0.1:8000/templatepages
+Content-Type: application/json
+Authorization: token c362581117e209735d412226e54596867e370892
+
+
+###
+
+ POST http://127.0.0.1:8000/savetemplateform
+Content-Type: application/json
+Authorization: token c362581117e209735d412226e54596867e370892
+
+{ "question_id": "1", "answer_text": "answer1" }
+
+###
\ No newline at end of file