auth and simple info

This commit is contained in:
mi1468 2025-04-13 11:58:48 +03:30
parent 89f462bf9f
commit 3f47437822
31 changed files with 1939 additions and 0 deletions

89
.gitignore vendored Normal file
View File

@ -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

39
.gitlab-ci.yml Normal file
View File

@ -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

19
Dockerfile Normal file
View File

@ -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/

7
REDME.md Normal file
View File

@ -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

0
core/__init__.py Normal file
View File

11
core/admin.py Normal file
View File

@ -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)

16
core/asgi.py Normal file
View File

@ -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()

View File

@ -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')),
],
),
]

View File

@ -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),
),
]

View File

View File

@ -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

23
core/models/customer.py Normal file
View File

@ -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

6
core/models/role.py Normal file
View File

@ -0,0 +1,6 @@
from django.db import models
class Role(models.Model):
name = models.CharField(max_length=100, unique=True)

View File

@ -0,0 +1,7 @@
from rest_framework import serializers
from ..models.customer import Customer
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = '__all__'

View File

@ -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' ]

View File

161
core/settings.py Normal file
View File

@ -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'

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<style>
.verification-code {
background-color: orange;
color: black;
text-align: center;
}
</style>
</head>
<body>
<p>Hallo, Willkommen bei WZK. Ihr E-Mail-Bestätigungscode lautet:</p>
<p class="verification-code">{{ verification_code }}</p>
</body>
</html>

View File

@ -0,0 +1,764 @@
<head>
<title></title>
<!--[if !mso]><!-- -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
#outlook a {
padding: 0;
}
.ReadMsgBody {
width: 100%;
}
.ExternalClass {
width: 100%;
}
.ExternalClass * {
line-height: 100%;
}
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
p {
display: block;
margin: 13px 0;
}
</style>
<!--[if !mso]><!-->
<style type="text/css">
@media only screen and (max-width: 480px) {
@-ms-viewport {
width: 320px;
}
@viewport {
width: 320px;
}
}
</style>
<!--<![endif]-->
<!--[if mso]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG />
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
<!--[if lte mso 11]>
<style type="text/css">
.outlook-group-fix {
width: 100% !important;
}
</style>
<![endif]-->
<!--[if !mso]><!-->
<link
href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700"
rel="stylesheet"
type="text/css"
/>
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);
</style>
<!--<![endif]-->
<style type="text/css">
@media only screen and (min-width: 480px) {
.mj-column-per-100,
* [aria-labelledby="mj-column-per-100"] {
width: 100% !important;
}
}
</style>
</head>
<body style="background: #f9f9f9">
<div style="background-color: #f9f9f9">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="640" align="center" style="width:640px;">
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<style type="text/css">
html,
body,
* {
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
a {
color: #ffd512;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
<div style="margin: 0px auto; max-width: 640px; background: transparent">
<table
role="presentation"
cellpadding="0"
cellspacing="0"
style="font-size: 0px; width: 100%; background: transparent"
align="center"
border="0"
>
<tbody>
<tr>
<td
style="
text-align: center;
vertical-align: top;
direction: ltr;
font-size: 0px;
padding: 40px 0px;
"
>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;width:640px;">
<![endif]-->
<div
aria-labelledby="mj-column-per-100"
class="mj-column-per-100 outlook-group-fix"
style="
vertical-align: top;
display: inline-block;
direction: ltr;
font-size: 13px;
text-align: left;
width: 100%;
"
>
<table
role="presentation"
cellpadding="0"
cellspacing="0"
width="100%"
border="0"
>
<tbody>
<tr>
<td
style="
word-break: break-word;
font-size: 0px;
padding: 0px;
"
align="center"
>
<table
role="presentation"
cellpadding="0"
cellspacing="0"
style="border-collapse: collapse; border-spacing: 0px"
align="center"
border="0"
></table>
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="640" align="center" style="width:640px;">
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div
style="
max-width: 640px;
margin: 0 auto;
box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.1);
border-radius: 4px;
overflow: hidden;
"
>
<div
style="
margin: 0px auto;
max-width: 640px;
background: #ffd512
url(https://wappapi.wz-kliniken.de/wzkregister/assets/login/login.jpg)
top center / cover no-repeat;
"
>
<!--[if mso | IE]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:640px;">
<v:fill origin="0.5, 0" position="0.5,0" type="tile" src="https://wappapi.wz-kliniken.de/wzkregister/assets/login/login.jpg" />
<v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0">
<![endif]-->
<table
role="presentation"
cellpadding="0"
cellspacing="0"
style="
height: 230px;
font-size: 0px;
width: 100%;
background: #ffd512
url(https://wappapi.wz-kliniken.de/wzkregister/assets/login/login.jpg)
top center / cover no-repeat;
filter: blur(5px); /* Adjust the blur radius as needed */
"
align="center"
border="0"
background="https://wappapi.wz-kliniken.de/wzkregister/assets/login/login.jpg"
>
<tbody>
<tr>
<td
style="
text-align: center;
vertical-align: top;
direction: ltr;
font-size: 0px;
padding: 57px;
"
>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:undefined;width:640px;">
<![endif]-->
<div
style="
cursor: auto;
color: white;
font-family: Whitney, Helvetica Neue, Helvetica, Arial,
Lucida Grande, sans-serif;
font-size: 36px;
font-weight: 600;
line-height: 36px;
text-align: center;
"
></div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
<!--[if mso | IE]>
</v:textbox>
</v:rect>
<![endif]-->
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="640" align="center" style="width:640px;">
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin: 0px auto; max-width: 640px; background: #ffffff">
<table
role="presentation"
cellpadding="0"
cellspacing="0"
style="font-size: 0px; width: 100%; background: #ffffff"
align="center"
border="0"
>
<tbody>
<tr>
<td
style="
text-align: center;
vertical-align: top;
direction: ltr;
font-size: 0px;
padding: 40px 70px;
"
>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;width:640px;">
<![endif]-->
<div
aria-labelledby="mj-column-per-100"
class="mj-column-per-100 outlook-group-fix"
style="
vertical-align: top;
display: inline-block;
direction: ltr;
font-size: 13px;
text-align: left;
width: 100%;
"
>
<table
role="presentation"
cellpadding="0"
cellspacing="0"
width="100%"
border="0"
>
<tbody>
<tr>
<td
style="
word-break: break-word;
font-size: 0px;
padding: 0px 0px 20px;
"
align="left"
>
<div
style="
cursor: auto;
color: #737f8d;
font-family: Whitney, Helvetica Neue, Helvetica,
Arial, Lucida Grande, sans-serif;
font-size: 16px;
line-height: 24px;
text-align: left;
"
>
<p>
<!-- <img
src="https://cdn.discordapp.com/email_assets/127c95bbea39cd4bc1ad87d1500ae27d.png"
alt="Party Wumpus"
title="None"
width="500"
style="height: auto"
/> -->
</p>
<h2
style="
font-family: Whitney, Helvetica Neue, Helvetica,
Arial, Lucida Grande, sans-serif;
font-weight: 500;
font-size: 20px;
color: #4f545c;
letter-spacing: 0.27px;
"
>
WZK Bestätigungscode,
</h2>
<p>
Hallo, Willkommen bei WZK. Ihr
E-Mail-Bestätigungscode lautet
</p>
<p>
Before we get started, we'll need to verify your
email.
</p>
</div>
</td>
</tr>
<tr>
<td
style="
word-break: break-word;
font-size: 0px;
padding: 10px 25px;
"
align="center"
>
<table
role="presentation"
cellpadding="0"
cellspacing="0"
style="border-collapse: separate"
align="center"
border="0"
>
<tbody>
<tr>
<td
style="
background: #ffd512;
border: none;
border-radius: 3px;
color: white;
cursor: auto;
padding: 15px 19px;
"
align="center"
valign="middle"
bgcolor="#7289DA"
>
<a
href="#"
style="
color: black;
text-decoration: none;
line-height: 100%;
background: #ffd512;
color: white;
font-family: Ubuntu, Helvetica, Arial,
sans-serif;
font-size: 15px;
font-weight: normal;
text-transform: none;
margin: 0px;
"
target="_blank"
><p style="color: black">
{{ verification_code }}
</p>
</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="640" align="center" style="width:640px;">
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
</div>
<div style="margin: 0px auto; max-width: 640px; background: transparent">
<table
role="presentation"
cellpadding="0"
cellspacing="0"
style="font-size: 0px; width: 100%; background: transparent"
align="center"
border="0"
>
<tbody>
<tr>
<td
style="
text-align: center;
vertical-align: top;
direction: ltr;
font-size: 0px;
padding: 0px;
"
>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;width:640px;">
<![endif]-->
<div
aria-labelledby="mj-column-per-100"
class="mj-column-per-100 outlook-group-fix"
style="
vertical-align: top;
display: inline-block;
direction: ltr;
font-size: 13px;
text-align: left;
width: 100%;
"
>
<table
role="presentation"
cellpadding="0"
cellspacing="0"
width="100%"
border="0"
>
<tbody>
<tr>
<td style="word-break: break-word; font-size: 0px">
<div style="font-size: 1px; line-height: 12px">
&nbsp;
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="640" align="center" style="width:640px;">
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div
style="
margin: 0 auto;
max-width: 640px;
background: #ffffff;
box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.1);
border-radius: 4px;
overflow: hidden;
"
>
<table
cellpadding="0"
cellspacing="0"
style="font-size: 0px; width: 100%; background: #ffffff"
align="center"
border="0"
>
<tbody>
<tr>
<td
style="
text-align: center;
vertical-align: top;
font-size: 0px;
padding: 0px;
"
>
<!--[if mso | IE]>
<table border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;width:640px;">
<![endif]-->
<div
aria-labelledby="mj-column-per-100"
class="mj-column-per-100 outlook-group-fix"
style="
vertical-align: top;
display: inline-block;
direction: ltr;
font-size: 13px;
text-align: left;
width: 100%;
"
>
<table
role="presentation"
cellpadding="0"
cellspacing="0"
width="100%"
border="0"
>
<tbody>
<tr>
<td
style="
word-break: break-word;
font-size: 0px;
padding: 30px 70px 0px 70px;
"
align="center"
>
<div
style="
cursor: auto;
color: #43b581;
font-family: Whitney, Helvetica Neue, Helvetica,
Arial, Lucida Grande, sans-serif;
font-size: 18px;
font-weight: bold;
line-height: 16px;
text-align: center;
"
>
FUN FACT #16
</div>
</td>
</tr>
<tr>
<td
style="
word-break: break-word;
font-size: 0px;
padding: 14px 70px 30px 70px;
"
align="center"
>
<div
style="
cursor: auto;
color: #737f8d;
font-family: Whitney, Helvetica Neue, Helvetica,
Arial, Lucida Grande, sans-serif;
font-size: 16px;
line-height: 22px;
text-align: center;
"
>
In Hearthstone, using the Hunter card Animal Companion
against Kel'Thuzad will summon his cat Mr.
Bigglesworth rather than the usual beasts.
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="640" align="center" style="width:640px;">
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin: 0px auto; max-width: 640px; background: transparent">
<table
role="presentation"
cellpadding="0"
cellspacing="0"
style="font-size: 0px; width: 100%; background: transparent"
align="center"
border="0"
>
<tbody>
<tr>
<td
style="
text-align: center;
vertical-align: top;
direction: ltr;
font-size: 0px;
padding: 20px 0px;
"
>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;width:640px;">
<![endif]-->
<div
aria-labelledby="mj-column-per-100"
class="mj-column-per-100 outlook-group-fix"
style="
vertical-align: top;
display: inline-block;
direction: ltr;
font-size: 13px;
text-align: left;
width: 100%;
"
>
<table
role="presentation"
cellpadding="0"
cellspacing="0"
width="100%"
border="0"
>
<tbody>
<tr>
<td
style="
word-break: break-word;
font-size: 0px;
padding: 0px;
"
align="center"
>
<div
style="
cursor: auto;
color: #99aab5;
font-family: Whitney, Helvetica Neue, Helvetica,
Arial, Lucida Grande, sans-serif;
font-size: 12px;
line-height: 24px;
text-align: center;
"
>
Sent by Discord •
<a
href="https://blog.discordapp.com/"
style="color: #1eb0f4; text-decoration: none"
target="_blank"
>check our blog</a
>
<a
href="https://twitter.com/discordapp"
style="color: #1eb0f4; text-decoration: none"
target="_blank"
>@discordapp</a
>
</div>
</td>
</tr>
<tr>
<td
style="
word-break: break-word;
font-size: 0px;
padding: 0px;
"
align="center"
>
<div
style="
cursor: auto;
color: #99aab5;
font-family: Whitney, Helvetica Neue, Helvetica,
Arial, Lucida Grande, sans-serif;
font-size: 12px;
line-height: 24px;
text-align: center;
"
>
444 De Haro Street, Suite 200, San Francisco, CA 94107
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
</div>
</body>

0
core/tests/__init__.py Normal file
View File

57
core/tests/test_signup.py Normal file
View File

@ -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)

31
core/urls.py Normal file
View File

@ -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),
]

58
core/views.py Normal file
View File

@ -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'})

0
core/views/__init__.py Normal file
View File

353
core/views/userView.py Normal file
View File

@ -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'})

16
core/wsgi.py Normal file
View File

@ -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()

30
docker-compose.yml Normal file
View File

@ -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:

22
manage.py Normal file
View File

@ -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()

7
requirements.txt Normal file
View File

@ -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

49
server/views.py Normal file
View File

@ -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!")

71
test.rest Normal file
View File

@ -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" }
###