mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2026-10-23 09:57:57 +00:00
Compare commits
255
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11b2b25adc | ||
|
|
63b0a42eca | ||
|
|
ed8cf4b4f8 | ||
|
|
b1cda5e7dc | ||
|
|
2c8de913f8 | ||
|
|
98f6aaf01f | ||
|
|
170aa903c7 | ||
|
|
16f8756b74 | ||
|
|
2f74aa36a9 | ||
|
|
f849003142 | ||
|
|
2562515574 | ||
|
|
93b509b256 | ||
|
|
9c93a35093 | ||
|
|
d77d59a793 | ||
|
|
110a6fb0ee | ||
|
|
83787c7c67 | ||
|
|
24bcb10d76 | ||
|
|
a3cdf50cb7 | ||
|
|
cfd02e8c30 | ||
|
|
0fb76d712d | ||
|
|
5e708c16fe | ||
|
|
fe11f35b32 | ||
|
|
3200f60821 | ||
|
|
24521c4223 | ||
|
|
e8127970f6 | ||
|
|
07d4a83cf9 | ||
|
|
ce1f6341b7 | ||
|
|
2a62787c3b | ||
|
|
91dea22f45 | ||
|
|
ef28c75f9b | ||
|
|
c007ac584f | ||
|
|
d2d83549b2 | ||
|
|
506974afc8 | ||
|
|
95f8cfbfdf | ||
|
|
8b00cda23d | ||
|
|
12cc88a50e | ||
|
|
2172051093 | ||
|
|
a6a573957c | ||
|
|
d6fb5f48d9 | ||
|
|
b0011eb7cc | ||
|
|
99af65a300 | ||
|
|
0c9b40132a | ||
|
|
3b295ea79f | ||
|
|
5ffe18ede3 | ||
|
|
a3a61b4923 | ||
|
|
39d5fc1869 | ||
|
|
05a6ad2d84 | ||
|
|
5649d24724 | ||
|
|
bbeece9e03 | ||
|
|
596562f6dc | ||
|
|
10de8f69c9 | ||
|
|
8a6b1cc900 | ||
|
|
d16ae66252 | ||
|
|
e966f95463 | ||
|
|
2714255dd1 | ||
|
|
39a0b131b8 | ||
|
|
4f778f7904 | ||
|
|
7e9bc397a9 | ||
|
|
7bfc14f0d9 | ||
|
|
d2e084d3e4 | ||
|
|
f81714a525 | ||
|
|
f3282a680b | ||
|
|
7b57277a7f | ||
|
|
fdd2e23669 | ||
|
|
d70ab09960 | ||
|
|
297a2fe5ad | ||
|
|
33b4f13ec8 | ||
|
|
310233c519 | ||
|
|
15621124ad | ||
|
|
7fc1918de0 | ||
|
|
f6fa74897a | ||
|
|
dd6886ff2b | ||
|
|
649191f3f4 | ||
|
|
183f6b4475 | ||
|
|
8f601b26ae | ||
|
|
918b15c315 | ||
|
|
1830d92cbd | ||
|
|
44124b9964 | ||
|
|
454ded627f | ||
|
|
f1484e125b | ||
|
|
df4d2e3c1f | ||
|
|
872d231f72 | ||
|
|
cc4c8254f6 | ||
|
|
039c95aa56 | ||
|
|
e1f50decfa | ||
|
|
11712bedf3 | ||
|
|
e6642b5a15 | ||
|
|
954aa422a2 | ||
|
|
15a48e4884 | ||
|
|
d768da70f2 | ||
|
|
9b0e1791da | ||
|
|
44b5937f7a | ||
|
|
edddc2f457 | ||
|
|
88730a2b2b | ||
|
|
3df34c0017 | ||
|
|
7dd309e0e3 | ||
|
|
4552a7fc93 | ||
|
|
740135051d | ||
|
|
3222aa4a66 | ||
|
|
6602414779 | ||
|
|
7291447c5a | ||
|
|
d437b21dc3 | ||
|
|
e06642225a | ||
|
|
c06086f899 | ||
|
|
e775561a89 | ||
|
|
241f1ce427 | ||
|
|
d883bd2d9a | ||
|
|
cd800ff8b8 | ||
|
|
05a9f04ac8 | ||
|
|
dcc9077392 | ||
|
|
681d1e5791 | ||
|
|
bf505a65bf | ||
|
|
6bf32d27c7 | ||
|
|
ac63d4cdc7 | ||
|
|
150027fb71 | ||
|
|
e8ee74d0d7 | ||
|
|
5f2e06edf9 | ||
|
|
99ad17f0f9 | ||
|
|
ee7b365527 | ||
|
|
275984954e | ||
|
|
6f7fb2bdcd | ||
|
|
1e2b859b92 | ||
|
|
4cc52a1c07 | ||
|
|
7461af20dd | ||
|
|
f65a7d2933 | ||
|
|
fce720237f | ||
|
|
5e0a4e6bd1 | ||
|
|
f9776e60cf | ||
|
|
7e63abb2fb | ||
|
|
a245545811 | ||
|
|
4cb5814cd3 | ||
|
|
9e06ea4d71 | ||
|
|
cff87c4ecd | ||
|
|
1541c374ed | ||
|
|
c493bd57e1 | ||
|
|
bf43e62b17 | ||
|
|
5a780eeb17 | ||
|
|
038b8ef6e3 | ||
|
|
3b3f8c0104 | ||
|
|
2770cf8774 | ||
|
|
bea3ccfbbc | ||
|
|
492e538eb8 | ||
|
|
d3057beb54 | ||
|
|
19fa53c981 | ||
|
|
d2cc02fb60 | ||
|
|
4cbbfd8136 | ||
|
|
6c859a25d2 | ||
|
|
d1a6d3e715 | ||
|
|
1ea1f42169 | ||
|
|
d4fe3b3fc3 | ||
|
|
b44bc5d5cc | ||
|
|
9aa6c487ed | ||
|
|
42e4d75d70 | ||
|
|
a358cd2e7a | ||
|
|
641a665beb | ||
|
|
49326e983f | ||
|
|
881d88c8d8 | ||
|
|
35ab3df7c1 | ||
|
|
cbade0a87d | ||
|
|
4c6ef17525 | ||
|
|
ffca6996fd | ||
|
|
a3f88c774c | ||
|
|
ec38b82a7b | ||
|
|
9b5f863577 | ||
|
|
54ce5b022d | ||
|
|
dae9cb6323 | ||
|
|
270753cfd7 | ||
|
|
6b1cb3a84e | ||
|
|
ebd4b293e9 | ||
|
|
87bb1a2709 | ||
|
|
663e8972c4 | ||
|
|
8ff9f921e8 | ||
|
|
6d2d2b558a | ||
|
|
5aa3d3774d | ||
|
|
221f3bae4f | ||
|
|
62621c1a15 | ||
|
|
756e947c8a | ||
|
|
db02a28b4d | ||
|
|
afc087ff08 | ||
|
|
ee433a5c8c | ||
|
|
3ab0f179d8 | ||
|
|
25ef549417 | ||
|
|
084d39096c | ||
|
|
eca84b4e75 | ||
|
|
aefa866ae7 | ||
|
|
557ef4cd33 | ||
|
|
eea6302dda | ||
|
|
c0fafd3f7c | ||
|
|
f7290419d2 | ||
|
|
0fd2066c4a | ||
|
|
cb54311a7b | ||
|
|
ca71632755 | ||
|
|
ebf335eabd | ||
|
|
f383f6d14d | ||
|
|
5663a287f9 | ||
|
|
a7028fa64c | ||
|
|
0750509a85 | ||
|
|
4d9ebe729e | ||
|
|
bb8cc33d53 | ||
|
|
e933cacdcf | ||
|
|
3719498c2f | ||
|
|
c7470302bd | ||
|
|
5e9e83cb74 | ||
|
|
4cef58580e | ||
|
|
0ba09cbf8b | ||
|
|
28a2cb5d75 | ||
|
|
4961a192ea | ||
|
|
8ab47f3835 | ||
|
|
8112fb81a2 | ||
|
|
2c3c862c4a | ||
|
|
93f5d83825 | ||
|
|
ea60ac3d7b | ||
|
|
0748695f23 | ||
|
|
a201692c0c | ||
|
|
fd6c1d1442 | ||
|
|
ed57ce6e91 | ||
|
|
33453b193f | ||
|
|
b0972f1a0a | ||
|
|
7437403756 | ||
|
|
4d2f6f57f4 | ||
|
|
24d990592d | ||
|
|
5b7b7ff689 | ||
|
|
6fccacd085 | ||
|
|
51fa61dbc6 | ||
|
|
4867a5f858 | ||
|
|
687b6a5c6d | ||
|
|
e6ed1772f7 | ||
|
|
1f0a14fee4 | ||
|
|
eb70828ae0 | ||
|
|
220a03cc46 | ||
|
|
39b1e76bb5 | ||
|
|
83fc634d25 | ||
|
|
35b434bc3d | ||
|
|
749ee5457f | ||
|
|
d539073f29 | ||
|
|
66e1bb0f28 | ||
|
|
577f91b796 | ||
|
|
7ed37c30e1 | ||
|
|
c2f63ccc72 | ||
|
|
970a41c895 | ||
|
|
3fd29b3905 | ||
|
|
7f7fef3f89 | ||
|
|
90ee8023e6 | ||
|
|
c486d558ad | ||
|
|
85569af770 | ||
|
|
f97bb08c5c | ||
|
|
6f6e3f7e7b | ||
|
|
26b2d153fd | ||
|
|
2577f2dcac | ||
|
|
e4b69a406f | ||
|
|
2fdce34ffc | ||
|
|
2bf9dea771 | ||
|
|
847c078735 | ||
|
|
14e70a63b8 | ||
|
|
05872b5170 |
@@ -0,0 +1,40 @@
|
|||||||
|
NODE_ENV=dev
|
||||||
|
PORT=5000
|
||||||
|
DB_HOST=
|
||||||
|
DB_PASS=
|
||||||
|
DB_USER=postgres
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_NAME=
|
||||||
|
MIGRATIONS_RUN=true
|
||||||
|
SWAGGER_API_DOCS_PATH="/api-docs"
|
||||||
|
|
||||||
|
JWT_ACCESS_TOKEN_SECRET=your_access_token_secret
|
||||||
|
JWT_ACCESS_TOKEN_EXPIRY=1d
|
||||||
|
JWT_REFRESH_TOKEN_SECRET=your_refresh_token_secret
|
||||||
|
JWT_REFRESH_TOKEN_EXPIRY=1d
|
||||||
|
USE_MOCK=true
|
||||||
|
|
||||||
|
|
||||||
|
OCI_TENANCY_ID=
|
||||||
|
OCI_USER_ID=
|
||||||
|
OCI_FINGERPRINT=
|
||||||
|
OCI_PRIVATE_KEY=
|
||||||
|
OCI_PASSPHRASE=""
|
||||||
|
OCI_NAMESPACE=
|
||||||
|
OCI_REGION=
|
||||||
|
|
||||||
|
|
||||||
|
MAIL_HOST=smtp.gmail.com
|
||||||
|
MAIL_USER=[email protected]
|
||||||
|
MAIL_PASSWORD=
|
||||||
|
MAIL_PORT=587
|
||||||
|
MAIL_FROM=UBA
|
||||||
|
|
||||||
|
|
||||||
|
BRANCH_IO_URL=https://api2.branch.io/v1/url
|
||||||
|
BRANCH_IO_KEY=
|
||||||
|
ZOD_BASE_URL=http://localhost:5001
|
||||||
|
ANDROID_PACKAGE_NAME=com.zod
|
||||||
|
IOS_PACKAGE_NAME=com.zod
|
||||||
|
ANDRIOD_JUNIOR_DEEPLINK_PATH=zodbank://juniors/qr-code/validate
|
||||||
|
IOS_JUNIOR_DEEPLINK_PATH=zodbank://juniors/qr-code/validate
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/** @type {import('eslint').Linter.Config} */
|
||||||
|
module.exports = {
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
project: 'tsconfig.json',
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
sourceType: 'module',
|
||||||
|
},
|
||||||
|
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||||
|
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', 'plugin:security/recommended'],
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
jest: true,
|
||||||
|
},
|
||||||
|
ignorePatterns: ['.eslintrc.js', 'node_modules', 'dist', 'coverage', 'jest*\\.ts', 'typeorm*\\.ts'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/interface-name-prefix': 'off',
|
||||||
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'warn',
|
||||||
|
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' },
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-inferrable-types': 'off',
|
||||||
|
'func-names': ['error', 'as-needed'],
|
||||||
|
'no-underscore-dangle': ['error'],
|
||||||
|
'require-await': ['error'],
|
||||||
|
'no-console': ['error'],
|
||||||
|
'no-multi-assign': ['error'],
|
||||||
|
'no-magic-numbers': ['error', { ignoreArrayIndexes: true}],
|
||||||
|
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 1, maxBOF: 0 }],
|
||||||
|
'max-len': [
|
||||||
|
'error',
|
||||||
|
{ code: 120, tabWidth: 2, ignoreUrls: true, ignoreStrings: true, ignoreTemplateLiterals: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['*spec.ts'],
|
||||||
|
rules: {
|
||||||
|
'no-magic-numbers': ['off'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
name: CI Zod
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
- main
|
||||||
|
|
||||||
|
env:
|
||||||
|
NODE_ENV: development
|
||||||
|
TAG: dev
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
install_dependencies:
|
||||||
|
name: Install Dependencies
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 22.4.1
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Cache Node Modules
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: node_modules
|
||||||
|
key: ${{ runner.os }}-node_modules-${{ hashFiles('**/package-lock.json') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-node_modules-
|
||||||
|
|
||||||
|
run_tests:
|
||||||
|
name: Run Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: install_dependencies
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 22.4.1
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Run Lint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
- name: Run Tests with Coverage
|
||||||
|
run: npm run test:cov
|
||||||
|
|
||||||
|
build_app:
|
||||||
|
name: Build Application
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: run_tests
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 22.4.1
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Build Application
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Upload Build Artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: dist/
|
||||||
+55
-22
@@ -1,24 +1,57 @@
|
|||||||
/static
|
# compiled output
|
||||||
/media
|
/dist
|
||||||
.idea/
|
/node_modules
|
||||||
*.pyc
|
/build
|
||||||
media/
|
|
||||||
*.name
|
# Logs
|
||||||
*.iml
|
logs
|
||||||
*.log
|
*.log
|
||||||
*.xml
|
npm-debug.log*
|
||||||
*.pyo
|
pnpm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.idea
|
|
||||||
venv/*
|
# Tests
|
||||||
static/*
|
/coverage
|
||||||
*.pem
|
/.nyc_output
|
||||||
*.sqlite3
|
|
||||||
/migrations/__pycache__/
|
# IDEs and editors
|
||||||
/__pycache__/
|
/.idea
|
||||||
/*.pyc
|
.project
|
||||||
*/__pycache__/*.pyc
|
.classpath
|
||||||
__pycache__/
|
.c9/
|
||||||
*.env
|
*.launch
|
||||||
ve/*
|
.settings/
|
||||||
celerybeat-schedule
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# temp directory
|
||||||
|
.temp
|
||||||
|
.tmp
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
|
||||||
|
zod-certs
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"printWidth": 120
|
||||||
|
}
|
||||||
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.organizeImports": "explicit"
|
||||||
|
}
|
||||||
|
}
|
||||||
-11
@@ -1,11 +0,0 @@
|
|||||||
FROM python:3.9
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
|
||||||
RUN mkdir /usr/src/app
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
COPY . .
|
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get install wkhtmltopdf -y
|
|
||||||
RUN apt install -y gdal-bin python3-gdal
|
|
||||||
RUN pip install -r requirements.txt
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Base image
|
||||||
|
FROM node:22.4.1-alpine
|
||||||
|
RUN apk update && \
|
||||||
|
apk upgrade && \
|
||||||
|
apk add ca-certificates curl && \
|
||||||
|
update-ca-certificates
|
||||||
|
|
||||||
|
#saudi timezone
|
||||||
|
ENV TZ=Asia/Riyadh
|
||||||
|
|
||||||
|
# Create app directory
|
||||||
|
RUN mkdir /app && chown node:node /app
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# finally switch user to node
|
||||||
|
USER node
|
||||||
|
|
||||||
|
|
||||||
|
# A wildcard is used to ensure both package.json, package-lock.json and package-lock.json are copied
|
||||||
|
COPY --chown=node:node package*.json ./
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Install app dependencies
|
||||||
|
RUN npm install --frozen-lockfile
|
||||||
|
# Bundle app source
|
||||||
|
COPY --chown=node:node . .
|
||||||
|
|
||||||
|
# Creates a "dist" folder with the production build
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Start the server using the production build
|
||||||
|
CMD [ "node", "dist/main" ]
|
||||||
@@ -1 +1,99 @@
|
|||||||
# ZODBank-Backend
|
<p align="center">
|
||||||
|
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||||
|
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||||
|
|
||||||
|
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||||
|
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||||
|
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
|
||||||
|
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||||
|
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||||
|
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||||
|
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
|
||||||
|
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||||
|
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
|
||||||
|
</p>
|
||||||
|
<!--[](https://opencollective.com/nest#backer)
|
||||||
|
[](https://opencollective.com/nest#sponsor)-->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compile and run the project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# development
|
||||||
|
$ npm run start
|
||||||
|
|
||||||
|
# watch mode
|
||||||
|
$ npm run start:dev
|
||||||
|
|
||||||
|
# production mode
|
||||||
|
$ npm run start:prod
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# unit tests
|
||||||
|
$ npm run test
|
||||||
|
|
||||||
|
# e2e tests
|
||||||
|
$ npm run test:e2e
|
||||||
|
|
||||||
|
# test coverage
|
||||||
|
$ npm run test:cov
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
|
||||||
|
|
||||||
|
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install -g mau
|
||||||
|
$ mau deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
Check out a few resources that may come in handy when working with NestJS:
|
||||||
|
|
||||||
|
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
|
||||||
|
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
|
||||||
|
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
|
||||||
|
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
|
||||||
|
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
|
||||||
|
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
|
||||||
|
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
|
||||||
|
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||||
|
|
||||||
|
## Stay in touch
|
||||||
|
|
||||||
|
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
|
||||||
|
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||||
|
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
"""Account admin"""
|
|
||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
"""Import django app"""
|
|
||||||
from .models import UserEmailOtp, DefaultTaskImages, UserNotification, UserDelete, UserDeviceDetails
|
|
||||||
# Register your models here.
|
|
||||||
|
|
||||||
@admin.register(UserDelete)
|
|
||||||
class UserDeleteAdmin(admin.ModelAdmin):
|
|
||||||
"""User profile admin"""
|
|
||||||
list_display = ['user', 'old_email', 'd_email']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return delete user"""
|
|
||||||
return self.user
|
|
||||||
@admin.register(UserNotification)
|
|
||||||
class UserNotificationAdmin(admin.ModelAdmin):
|
|
||||||
"""User profile admin"""
|
|
||||||
list_display = ['user', 'push_notification', 'email_notification', 'sms_notification']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return image url"""
|
|
||||||
return self.image_url
|
|
||||||
@admin.register(DefaultTaskImages)
|
|
||||||
class DefaultTaskImagesAdmin(admin.ModelAdmin):
|
|
||||||
"""User profile admin"""
|
|
||||||
list_display = ['task_name', 'image_url']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return image url"""
|
|
||||||
return self.image_url
|
|
||||||
|
|
||||||
@admin.register(UserEmailOtp)
|
|
||||||
class UserEmailOtpAdmin(admin.ModelAdmin):
|
|
||||||
"""User Email otp admin"""
|
|
||||||
list_display = ['email']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return object in email and otp format"""
|
|
||||||
return self.email + '-' + self.otp
|
|
||||||
|
|
||||||
@admin.register(UserDeviceDetails)
|
|
||||||
class UserDeviceDetailsAdmin(admin.ModelAdmin):
|
|
||||||
"""User profile admin"""
|
|
||||||
list_display = ['user', 'device_id']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return user email"""
|
|
||||||
return self.user.email
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
"""Account app file"""
|
|
||||||
"""Import Django"""
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class AccountConfig(AppConfig):
|
|
||||||
"""default configurations"""
|
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
|
||||||
name = 'account'
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
"""middleware file"""
|
|
||||||
"""Django import"""
|
|
||||||
from rest_framework import status
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from rest_framework.renderers import JSONRenderer
|
|
||||||
"""App django"""
|
|
||||||
from account.utils import custom_error_response
|
|
||||||
from account.models import UserDeviceDetails
|
|
||||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
|
||||||
|
|
||||||
# Custom middleware
|
|
||||||
# when user login with
|
|
||||||
# multiple device simultaneously
|
|
||||||
# It restricted login in
|
|
||||||
# multiple devices only
|
|
||||||
# user can login in single
|
|
||||||
# device at a time"""
|
|
||||||
class CustomMiddleware(object):
|
|
||||||
"""Custom middleware"""
|
|
||||||
def __init__(self, get_response):
|
|
||||||
"""response"""
|
|
||||||
self.get_response = get_response
|
|
||||||
|
|
||||||
def __call__(self, request):
|
|
||||||
# Code to be executed before the view is called
|
|
||||||
response = self.get_response(request)
|
|
||||||
# Code to be executed after the view is called
|
|
||||||
device_id = request.META.get('HTTP_DEVICE_ID')
|
|
||||||
if request.user.is_authenticated:
|
|
||||||
"""device details"""
|
|
||||||
device_details = UserDeviceDetails.objects.filter(user=request.user, device_id=device_id).last()
|
|
||||||
if device_id and not device_details:
|
|
||||||
custom_error = custom_error_response(ERROR_CODE['2037'], response_status=status.HTTP_404_NOT_FOUND)
|
|
||||||
response = Response(custom_error.data, status=status.HTTP_404_NOT_FOUND)
|
|
||||||
# Set content type header to "application/json"
|
|
||||||
response['Content-Type'] = 'application/json'
|
|
||||||
# Render the response as JSON
|
|
||||||
renderer = JSONRenderer()
|
|
||||||
response.content = renderer.render(response.data)
|
|
||||||
return response
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-23 12:05
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='UserEmailOtp',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('email', models.EmailField(max_length=254)),
|
|
||||||
('otp', models.CharField(max_length=10)),
|
|
||||||
('is_verified', models.BooleanField(default=False)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('expired_at', models.DateTimeField(blank=True, null=True)),
|
|
||||||
('is_active', models.BooleanField(default=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'user_email_otp',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='UserPhoneOtp',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('country_code', models.IntegerField()),
|
|
||||||
('phone', models.CharField(max_length=17)),
|
|
||||||
('otp', models.CharField(max_length=10)),
|
|
||||||
('is_verified', models.BooleanField(default=False)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('expired_at', models.DateTimeField(blank=True, null=True)),
|
|
||||||
('is_active', models.BooleanField(default=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'user_phone_otp',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='UserProfile',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('user_type', models.CharField(blank=True, choices=[('1', 'junior'), ('2', 'guardian'), ('3', 'superuser')], default=None, max_length=15, null=True)),
|
|
||||||
('is_verified', models.BooleanField(default=False)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('is_active', models.BooleanField(default=False)),
|
|
||||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_profile', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'user_profile',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-29 12:10
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('account', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='useremailotp',
|
|
||||||
name='user_type',
|
|
||||||
field=models.CharField(blank=True, choices=[('1', 'junior'), ('2', 'guardian'), ('3', 'superuser')], default=None, max_length=15, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-07 10:23
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('account', '0002_useremailotp_user_type'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='DefaultTaskImages',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('task_name', models.CharField(max_length=15)),
|
|
||||||
('image_url', models.URLField(blank=True, default=None, null=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'default_task_image',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-10 09:24
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
('account', '0003_defaulttaskimages'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='UserDelete',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('old_email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Original Email')),
|
|
||||||
('d_email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Dummy Email')),
|
|
||||||
('is_active', models.BooleanField(default=True)),
|
|
||||||
('reason', models.TextField(blank=True, max_length=500, null=True, verbose_name='Reason for Leaving')),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='delete_information_set', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'user_delete_information',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-10 12:40
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
('account', '0004_userdelete'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='UserNotification',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('push_notification', models.BooleanField(default=True)),
|
|
||||||
('email_notification', models.BooleanField(default=True)),
|
|
||||||
('sms_notification', models.BooleanField(default=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='user_notification', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'user_notification',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-11 11:26
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('account', '0005_usernotification'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='useremailotp',
|
|
||||||
options={'verbose_name': 'User Email OTP', 'verbose_name_plural': 'User Email OTP'},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='usernotification',
|
|
||||||
options={'verbose_name': 'User Notification', 'verbose_name_plural': 'User Notification'},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-14 09:34
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('account', '0006_alter_useremailotp_options_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='defaulttaskimages',
|
|
||||||
options={'verbose_name': 'Default Task images', 'verbose_name_plural': 'Default Task images'},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='userdelete',
|
|
||||||
options={'verbose_name': 'Deleted User', 'verbose_name_plural': 'Deleted User'},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-14 11:08
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
('account', '0007_alter_defaulttaskimages_options_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='UserDeviceDetails',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('device_id', models.CharField(max_length=500)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='user_device_details', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'User Device Details',
|
|
||||||
'verbose_name_plural': 'User Device Details',
|
|
||||||
'db_table': 'user_device_details',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-20 11:38
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('account', '0008_userdevicedetails'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='userdevicedetails',
|
|
||||||
name='device_id',
|
|
||||||
field=models.CharField(blank=True, max_length=500, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
"""Account module file"""
|
|
||||||
"""Django import"""
|
|
||||||
from django.db import models
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
"""App import"""
|
|
||||||
from base.constants import USER_TYPE
|
|
||||||
# Create your models here.
|
|
||||||
|
|
||||||
class UserProfile(models.Model):
|
|
||||||
"""
|
|
||||||
User details
|
|
||||||
"""
|
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_profile')
|
|
||||||
user_type = models.CharField(max_length=15, choices=USER_TYPE, null=True, blank=True, default=None)
|
|
||||||
is_verified = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
# OTP validity
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
is_active = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
""" Meta information """
|
|
||||||
db_table = 'user_profile'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""return phone as an object"""
|
|
||||||
return f'{self.user}'
|
|
||||||
|
|
||||||
class UserPhoneOtp(models.Model):
|
|
||||||
"""
|
|
||||||
This class is used to verify user email and their contact no.
|
|
||||||
"""
|
|
||||||
"""user details"""
|
|
||||||
country_code = models.IntegerField()
|
|
||||||
phone = models.CharField(max_length=17)
|
|
||||||
"""otp details"""
|
|
||||||
otp = models.CharField(max_length=10)
|
|
||||||
is_verified = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
# OTP validity
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
expired_at = models.DateTimeField(blank=True, null=True)
|
|
||||||
is_active = models.BooleanField(default=True)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
""" Meta information """
|
|
||||||
db_table = 'user_phone_otp'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""return phone as an object"""
|
|
||||||
return self.phone
|
|
||||||
|
|
||||||
class UserEmailOtp(models.Model):
|
|
||||||
"""
|
|
||||||
This class is used to verify user email and their contact no.
|
|
||||||
"""
|
|
||||||
"""user details"""
|
|
||||||
email = models.EmailField()
|
|
||||||
"""otp details"""
|
|
||||||
otp = models.CharField(max_length=10)
|
|
||||||
is_verified = models.BooleanField(default=False)
|
|
||||||
user_type = models.CharField(max_length=15, choices=USER_TYPE, null=True, blank=True, default=None)
|
|
||||||
|
|
||||||
# OTP validity
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
expired_at = models.DateTimeField(blank=True, null=True)
|
|
||||||
is_active = models.BooleanField(default=True)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
""" Meta information """
|
|
||||||
db_table = 'user_email_otp'
|
|
||||||
verbose_name = 'User Email OTP'
|
|
||||||
verbose_name_plural = 'User Email OTP'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""return phone as an object"""
|
|
||||||
return self.email
|
|
||||||
|
|
||||||
class DefaultTaskImages(models.Model):
|
|
||||||
"""Default images upload in oss bucket"""
|
|
||||||
|
|
||||||
task_name = models.CharField(max_length=15)
|
|
||||||
image_url = models.URLField(null=True, blank=True, default=None)
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
""" Meta information """
|
|
||||||
db_table = 'default_task_image'
|
|
||||||
verbose_name = 'Default Task images'
|
|
||||||
verbose_name_plural = 'Default Task images'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""return phone as an object"""
|
|
||||||
return self.task_name
|
|
||||||
|
|
||||||
class UserDelete(models.Model):
|
|
||||||
"""
|
|
||||||
User delete information
|
|
||||||
"""
|
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='delete_information_set')
|
|
||||||
"""Old email"""
|
|
||||||
old_email = models.EmailField(blank=True, null=True, verbose_name='Original Email')
|
|
||||||
"""Dummy email"""
|
|
||||||
d_email = models.EmailField(blank=True, null=True, verbose_name='Dummy Email')
|
|
||||||
is_active = models.BooleanField(default=True)
|
|
||||||
"""reason for leaving"""
|
|
||||||
reason = models.TextField(max_length=500, blank=True, null=True, verbose_name='Reason for Leaving')
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
""" Meta information """
|
|
||||||
db_table = 'user_delete_information'
|
|
||||||
verbose_name = 'Deleted User'
|
|
||||||
verbose_name_plural = 'Deleted User'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.user.email
|
|
||||||
|
|
||||||
|
|
||||||
class UserNotification(models.Model):
|
|
||||||
"""
|
|
||||||
User notification details
|
|
||||||
"""
|
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='user_notification')
|
|
||||||
"""Push Notification"""
|
|
||||||
push_notification = models.BooleanField(default=True)
|
|
||||||
"""Email Notification"""
|
|
||||||
email_notification = models.BooleanField(default=True)
|
|
||||||
"""SMS Notification"""
|
|
||||||
sms_notification = models.BooleanField(default=True)
|
|
||||||
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
""" Meta information """
|
|
||||||
db_table = 'user_notification'
|
|
||||||
verbose_name = 'User Notification'
|
|
||||||
verbose_name_plural = 'User Notification'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.user.email
|
|
||||||
|
|
||||||
|
|
||||||
class UserDeviceDetails(models.Model):
|
|
||||||
"""
|
|
||||||
User notification details
|
|
||||||
"""
|
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='user_device_details')
|
|
||||||
"""Device ID"""
|
|
||||||
device_id = models.CharField(max_length=500, null=True, blank=True)
|
|
||||||
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
""" Meta information """
|
|
||||||
db_table = 'user_device_details'
|
|
||||||
verbose_name = 'User Device Details'
|
|
||||||
verbose_name_plural = 'User Device Details'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.user.email
|
|
||||||
@@ -1,378 +0,0 @@
|
|||||||
"""Account serializer"""
|
|
||||||
"""Django Import"""
|
|
||||||
# Import Refresh token of jwt
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from rest_framework_simplejwt.tokens import RefreshToken
|
|
||||||
import secrets
|
|
||||||
"""App import"""
|
|
||||||
# Import guardian's model,
|
|
||||||
# Import junior's model,
|
|
||||||
# Import account's model,
|
|
||||||
# Import constant from
|
|
||||||
# base package,
|
|
||||||
# Import messages from
|
|
||||||
# base package,
|
|
||||||
# Import some functions
|
|
||||||
# from utils file"""
|
|
||||||
|
|
||||||
from guardian.models import Guardian
|
|
||||||
from junior.models import Junior
|
|
||||||
from account.models import UserEmailOtp, DefaultTaskImages, UserDelete, UserNotification, UserPhoneOtp
|
|
||||||
from base.constants import GUARDIAN, JUNIOR, SUPERUSER, NUMBER
|
|
||||||
from base.messages import ERROR_CODE, SUCCESS_CODE, STATUS_CODE_ERROR
|
|
||||||
from .utils import delete_user_account_condition_social, delete_user_account_condition
|
|
||||||
|
|
||||||
# In this serializer file
|
|
||||||
# define google login serializer
|
|
||||||
# update junior profile,
|
|
||||||
# update guardian profile,
|
|
||||||
# super admin serializer,
|
|
||||||
# reset password,
|
|
||||||
# forgot password,
|
|
||||||
# change password,
|
|
||||||
# basic junior serializer,
|
|
||||||
# basic guardian serializer,
|
|
||||||
# user delete account serializer,
|
|
||||||
# user notification serializer,
|
|
||||||
# update user notification serializer,
|
|
||||||
# default task's images serializer,
|
|
||||||
# upload default task's images serializer,
|
|
||||||
# email verification serializer,
|
|
||||||
# phone otp serializer
|
|
||||||
|
|
||||||
# create all serializer here
|
|
||||||
class GoogleLoginSerializer(serializers.Serializer):
|
|
||||||
"""google login serializer"""
|
|
||||||
access_token = serializers.CharField(max_length=5000, required=True)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""meta class"""
|
|
||||||
fields = ('access_token',)
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateJuniorProfileImageSerializer(serializers.ModelSerializer):
|
|
||||||
"""update junior image"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = Junior
|
|
||||||
fields = ['id', 'image']
|
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
|
||||||
"""update image """
|
|
||||||
junior_image = validated_data.get('image', instance.image)
|
|
||||||
instance.image = junior_image
|
|
||||||
instance.save()
|
|
||||||
return instance
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateGuardianImageSerializer(serializers.ModelSerializer):
|
|
||||||
"""update guardian image"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = Guardian
|
|
||||||
fields = ['id','image']
|
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
|
||||||
"""update image """
|
|
||||||
instance.image = validated_data.get('image', instance.image)
|
|
||||||
instance.save()
|
|
||||||
return instance
|
|
||||||
|
|
||||||
|
|
||||||
class ResetPasswordSerializer(serializers.Serializer):
|
|
||||||
"""Reset Password after verification"""
|
|
||||||
verification_code = serializers.CharField(max_length=10)
|
|
||||||
password = serializers.CharField(required=True)
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = User
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
verification_code = validated_data.pop('verification_code')
|
|
||||||
password = validated_data.pop('password')
|
|
||||||
# fetch email otp object of the user
|
|
||||||
user_opt_details = UserEmailOtp.objects.filter(otp=verification_code, is_verified=True).last()
|
|
||||||
if user_opt_details:
|
|
||||||
user_details = User.objects.filter(email=user_opt_details.email).last()
|
|
||||||
if user_details:
|
|
||||||
if user_details.check_password(password):
|
|
||||||
raise serializers.ValidationError({"details":ERROR_CODE['2001'],"code":"400", "status":"failed"})
|
|
||||||
user_details.set_password(password)
|
|
||||||
user_details.save()
|
|
||||||
return {'password':password}
|
|
||||||
return user_opt_details
|
|
||||||
return ''
|
|
||||||
|
|
||||||
class ChangePasswordSerializer(serializers.Serializer):
|
|
||||||
"""Update Password after verification"""
|
|
||||||
current_password = serializers.CharField(max_length=100)
|
|
||||||
new_password = serializers.CharField(required=True)
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = User
|
|
||||||
|
|
||||||
def validate_current_password(self, value):
|
|
||||||
user = self.context
|
|
||||||
# check old password
|
|
||||||
if self.context.password not in ('', None) and user.check_password(value):
|
|
||||||
return value
|
|
||||||
raise serializers.ValidationError(ERROR_CODE['2015'])
|
|
||||||
def create(self, validated_data):
|
|
||||||
new_password = validated_data.pop('new_password')
|
|
||||||
current_password = validated_data.pop('current_password')
|
|
||||||
"""Check new password is different from current password"""
|
|
||||||
if new_password == current_password:
|
|
||||||
raise serializers.ValidationError({"details": ERROR_CODE['2026']})
|
|
||||||
user_details = User.objects.filter(email=self.context).last()
|
|
||||||
if user_details:
|
|
||||||
user_details.set_password(new_password)
|
|
||||||
user_details.save()
|
|
||||||
return {'password':new_password}
|
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ForgotPasswordSerializer(serializers.Serializer):
|
|
||||||
"""Forget password serializer"""
|
|
||||||
email = serializers.EmailField()
|
|
||||||
|
|
||||||
|
|
||||||
class AdminLoginSerializer(serializers.ModelSerializer):
|
|
||||||
"""admin login serializer"""
|
|
||||||
email = serializers.EmailField(required=True)
|
|
||||||
password = serializers.CharField(required=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
"""
|
|
||||||
meta class
|
|
||||||
"""
|
|
||||||
model = User
|
|
||||||
fields = ('email', 'password')
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
user = User.objects.filter(email__iexact=attrs['email'], is_superuser=True
|
|
||||||
).only('id', 'first_name', 'last_name', 'email',
|
|
||||||
'username', 'is_active', 'is_superuser').first()
|
|
||||||
|
|
||||||
if not user or not user.check_password(attrs['password']):
|
|
||||||
raise serializers.ValidationError({'details': ERROR_CODE['2002']})
|
|
||||||
|
|
||||||
self.context.update({'user': user})
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
"""
|
|
||||||
used to return the user object after validation
|
|
||||||
"""
|
|
||||||
return self.context['user']
|
|
||||||
|
|
||||||
|
|
||||||
class SuperUserSerializer(serializers.ModelSerializer):
|
|
||||||
"""Super admin serializer"""
|
|
||||||
user_type = serializers.SerializerMethodField('get_user_type')
|
|
||||||
auth_token = serializers.SerializerMethodField('get_auth_token')
|
|
||||||
refresh_token = serializers.SerializerMethodField('get_refresh_token')
|
|
||||||
|
|
||||||
def get_auth_token(self, obj):
|
|
||||||
refresh = RefreshToken.for_user(obj)
|
|
||||||
access_token = str(refresh.access_token)
|
|
||||||
return access_token
|
|
||||||
|
|
||||||
def get_refresh_token(self, obj):
|
|
||||||
refresh = RefreshToken.for_user(obj)
|
|
||||||
refresh_token = str(refresh)
|
|
||||||
return refresh_token
|
|
||||||
|
|
||||||
def get_user_type(self, obj):
|
|
||||||
"""user type"""
|
|
||||||
return str(NUMBER['three'])
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = User
|
|
||||||
fields = ['id', 'auth_token', 'refresh_token', 'username', 'email', 'first_name',
|
|
||||||
'last_name', 'is_active', 'user_type']
|
|
||||||
|
|
||||||
|
|
||||||
class GuardianSerializer(serializers.ModelSerializer):
|
|
||||||
"""guardian serializer"""
|
|
||||||
user_type = serializers.SerializerMethodField('get_user_type')
|
|
||||||
email = serializers.SerializerMethodField('get_auth')
|
|
||||||
first_name = serializers.SerializerMethodField('get_first_name')
|
|
||||||
last_name = serializers.SerializerMethodField('get_last_name')
|
|
||||||
auth_token = serializers.SerializerMethodField('get_auth_token')
|
|
||||||
refresh_token = serializers.SerializerMethodField('get_refresh_token')
|
|
||||||
|
|
||||||
def get_auth_token(self, obj):
|
|
||||||
refresh = RefreshToken.for_user(obj.user)
|
|
||||||
access_token = str(refresh.access_token)
|
|
||||||
return access_token
|
|
||||||
|
|
||||||
def get_refresh_token(self, obj):
|
|
||||||
refresh = RefreshToken.for_user(obj.user)
|
|
||||||
refresh_token = str(refresh)
|
|
||||||
return refresh_token
|
|
||||||
|
|
||||||
def get_user_type(self, obj):
|
|
||||||
"""user type"""
|
|
||||||
if self.context.get('user_type', ''):
|
|
||||||
return self.context.get('user_type')
|
|
||||||
# remove the below code once user_type can be passed
|
|
||||||
# from everywhere from where this serializer is being called
|
|
||||||
else:
|
|
||||||
email_verified = UserEmailOtp.objects.filter(
|
|
||||||
email=obj.user.username
|
|
||||||
).last()
|
|
||||||
if email_verified and email_verified.user_type is not None:
|
|
||||||
return email_verified.user_type
|
|
||||||
return str(NUMBER['two'])
|
|
||||||
|
|
||||||
def get_auth(self, obj):
|
|
||||||
"""user email address"""
|
|
||||||
return obj.user.username
|
|
||||||
|
|
||||||
def get_first_name(self, obj):
|
|
||||||
"""user first name"""
|
|
||||||
return obj.user.first_name
|
|
||||||
|
|
||||||
def get_last_name(self, obj):
|
|
||||||
"""user last name"""
|
|
||||||
return obj.user.last_name
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = Guardian
|
|
||||||
fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code',
|
|
||||||
'phone', 'family_name', 'gender', 'dob', 'referral_code', 'is_active',
|
|
||||||
'is_complete_profile', 'passcode', 'image', 'created_at', 'updated_at', 'user_type', 'country_name']
|
|
||||||
|
|
||||||
|
|
||||||
class JuniorSerializer(serializers.ModelSerializer):
|
|
||||||
"""junior serializer"""
|
|
||||||
user_type = serializers.SerializerMethodField('get_user_type')
|
|
||||||
email = serializers.SerializerMethodField('get_auth')
|
|
||||||
first_name = serializers.SerializerMethodField('get_first_name')
|
|
||||||
last_name = serializers.SerializerMethodField('get_last_name')
|
|
||||||
auth_token = serializers.SerializerMethodField('get_auth_token')
|
|
||||||
refresh_token = serializers.SerializerMethodField('get_refresh_token')
|
|
||||||
|
|
||||||
def get_auth_token(self, obj):
|
|
||||||
refresh = RefreshToken.for_user(obj.auth)
|
|
||||||
access_token = str(refresh.access_token)
|
|
||||||
return access_token
|
|
||||||
|
|
||||||
def get_refresh_token(self, obj):
|
|
||||||
refresh = RefreshToken.for_user(obj.auth)
|
|
||||||
refresh_token = str(refresh)
|
|
||||||
return refresh_token
|
|
||||||
|
|
||||||
def get_user_type(self, obj):
|
|
||||||
email_verified = UserEmailOtp.objects.filter(email=obj.auth.username).last()
|
|
||||||
if email_verified and email_verified.user_type is not None:
|
|
||||||
return email_verified.user_type
|
|
||||||
return str(NUMBER['one'])
|
|
||||||
|
|
||||||
def get_auth(self, obj):
|
|
||||||
return obj.auth.username
|
|
||||||
|
|
||||||
def get_first_name(self, obj):
|
|
||||||
return obj.auth.first_name
|
|
||||||
|
|
||||||
def get_last_name(self, obj):
|
|
||||||
return obj.auth.last_name
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = Junior
|
|
||||||
fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code',
|
|
||||||
'phone', 'gender', 'dob', 'guardian_code', 'referral_code','is_active', 'is_password_set',
|
|
||||||
'is_complete_profile', 'created_at', 'image', 'updated_at', 'user_type', 'country_name','is_invited']
|
|
||||||
|
|
||||||
class EmailVerificationSerializer(serializers.ModelSerializer):
|
|
||||||
"""Email verification serializer"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = UserEmailOtp
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DefaultTaskImagesSerializer(serializers.ModelSerializer):
|
|
||||||
"""Update Password after verification"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = DefaultTaskImages
|
|
||||||
fields = ['id', 'task_name', 'image_url']
|
|
||||||
def create(self, validated_data):
|
|
||||||
# create default task object
|
|
||||||
data = DefaultTaskImages.objects.create(**validated_data)
|
|
||||||
return data
|
|
||||||
|
|
||||||
class DefaultTaskImagesDetailsSerializer(serializers.ModelSerializer):
|
|
||||||
"""Update Password after verification"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = DefaultTaskImages
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
class UserDeleteSerializer(serializers.ModelSerializer):
|
|
||||||
"""User Delete Serializer"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta Information"""
|
|
||||||
model = UserDelete
|
|
||||||
fields = ['id','reason']
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = self.context['user']
|
|
||||||
user_type = str(self.context['user_type'])
|
|
||||||
data = validated_data.get('reason')
|
|
||||||
passwd = self.context['password']
|
|
||||||
signup_method = self.context['signup_method']
|
|
||||||
random_num = secrets.randbelow(10001)
|
|
||||||
user_tb = User.objects.filter(id=user.id).last()
|
|
||||||
user_type_datas = UserEmailOtp.objects.filter(email=user.email).last()
|
|
||||||
# check password and sign up method
|
|
||||||
if user_tb and user_tb.check_password(passwd) and signup_method == str(NUMBER['one']):
|
|
||||||
user_type_data = user_type_datas.user_type
|
|
||||||
instance = delete_user_account_condition(user, user_type_data, user_type, user_tb, data, random_num)
|
|
||||||
return instance
|
|
||||||
elif user_tb and passwd is None and signup_method in ['2','3']:
|
|
||||||
inst = delete_user_account_condition_social(user, user_type, user_tb, data, random_num)
|
|
||||||
return inst
|
|
||||||
else:
|
|
||||||
raise serializers.ValidationError({"details": ERROR_CODE['2031'], "code": "400", "status": "failed"})
|
|
||||||
|
|
||||||
|
|
||||||
class UserNotificationSerializer(serializers.ModelSerializer):
|
|
||||||
"""User Notification serializer"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = UserNotification
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateUserNotificationSerializer(serializers.ModelSerializer):
|
|
||||||
"""Update User Notification serializer"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = UserNotification
|
|
||||||
fields = ['push_notification', 'email_notification', 'sms_notification']
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
instance = UserNotification.objects.filter(user=self.context).last()
|
|
||||||
if instance:
|
|
||||||
# change notification status
|
|
||||||
instance.push_notification = validated_data.get('push_notification',instance.push_notification)
|
|
||||||
instance.email_notification = validated_data.get('email_notification', instance.email_notification)
|
|
||||||
instance.sms_notification = validated_data.get('sms_notification', instance.sms_notification)
|
|
||||||
instance.save()
|
|
||||||
else:
|
|
||||||
instance = UserNotification.objects.create(user=self.context)
|
|
||||||
return instance
|
|
||||||
|
|
||||||
class UserPhoneOtpSerializer(serializers.ModelSerializer):
|
|
||||||
"""User Phone serializers"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = UserPhoneOtp
|
|
||||||
fields = '__all__'
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<!DOCTYPE HTML>
|
|
||||||
{% block subject %}DinDin{% endblock %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% block html %}
|
|
||||||
<html lang="en" style="height: 100%;">
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type"
|
|
||||||
content="text/html; charset=UTF-8">
|
|
||||||
<meta name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
|
||||||
<title>Zod Bank | OTP</title>
|
|
||||||
<style type="text/css">
|
|
||||||
@media all and (max-width: 599px) {
|
|
||||||
.block {
|
|
||||||
display: block !important;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.top-space {
|
|
||||||
padding: 15px 0 0 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body style="margin: 0; padding: 0; background: #f7f8f9; height: 100%;">
|
|
||||||
<!-- begin template body -->
|
|
||||||
<table style="background:#f7f8f9; border: 0; border-collapse: separate; border-spacing: 0px; margin: auto; width: 100%; font-family: Arial, Helvetica, sans-serif; height: 100%;" aria-describedby="email-data-wrapper">
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0;">
|
|
||||||
<table style="background-color: white; border-collapse: separate; border-spacing: 0px; border: 1px solid #e4e8eb; width: 100%; max-width: 600px; margin-right:auto; margin-left: auto;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;" aria-describedby="email-data-wrapper">
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 41px 30px 40px; height: 39px; background: url({% static 'images/backgrounds/email_template.png' %}) left center no-repeat; background-size: cover;">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% block plain %}
|
|
||||||
{% endblock %}
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px;">
|
|
||||||
<p style="margin: 0; font-size: 14px; line-height: 20px; color: #505050; font-weight: 400;">-</p>
|
|
||||||
<p style="margin: 0; font-size: 14px; line-height: 20px; color: #505050; font-weight: 400;">Cheers!</p>
|
|
||||||
<p style="margin: 0 0 30px; font-size: 14px; line-height: 20px; color: #505050; font-weight: 700;">Zod Bank Team</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<!-- end template body -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{% extends "templated_email/email_base.email" %}
|
|
||||||
|
|
||||||
{% block subject %}
|
|
||||||
OTP Verification
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block plain %}
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 15px;">
|
|
||||||
<p style="margin: 0; font-size: 16px; line-height: 20px; padding: 36px 0 0; font-weight: 500; color: #1f2532;">
|
|
||||||
Hi User,
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 22px;">
|
|
||||||
<p style="margin: 0;font-size: 14px; font-weight: 400; line-height: 21px; color: #1f2532;">
|
|
||||||
You are receiving this email for email verification. Please use <b>{{ otp }} </b>as the verification code for your email address & username.
|
|
||||||
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{% extends "templated_email/email_base.email" %}
|
|
||||||
|
|
||||||
{% block subject %}
|
|
||||||
Password Reset Verification Code
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block plain %}
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 15px;">
|
|
||||||
<p style="margin: 0; font-size: 16px; line-height: 20px; padding: 36px 0 0; font-weight: 500; color: #1f2532;">
|
|
||||||
Hi User,
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 22px;">
|
|
||||||
<p style="margin: 0;font-size: 14px; font-weight: 400; line-height: 21px; color: #1f2532;">
|
|
||||||
You are receiving this email for reset password verification. Please use <b>{{ verification_code }} </b>as the verification code.
|
|
||||||
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{% extends "templated_email/email_base.email" %}
|
|
||||||
|
|
||||||
{% block subject %}
|
|
||||||
Approval Email
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block plain %}
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 15px;">
|
|
||||||
<p style="margin: 0; font-size: 16px; line-height: 20px; padding: 36px 0 0; font-weight: 500; color: #1f2532;">
|
|
||||||
Hello,
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 22px;">
|
|
||||||
<p style="margin: 0;font-size: 14px; font-weight: 400; line-height: 21px; color: #1f2532;">
|
|
||||||
Please approve {{full_name}} for accessing the Zod bank platform as a junior.
|
|
||||||
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{% extends "templated_email/email_base.email" %}
|
|
||||||
|
|
||||||
{% block subject %}
|
|
||||||
Invitation Email
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block plain %}
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 15px;">
|
|
||||||
<p style="margin: 0; font-size: 16px; line-height: 20px; padding: 36px 0 0; font-weight: 500; color: #1f2532;">
|
|
||||||
Hi {{full_name}},
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 22px;">
|
|
||||||
<p style="margin: 0;font-size: 14px; font-weight: 400; line-height: 21px; color: #1f2532;">
|
|
||||||
You are receiving this email for joining the ZOD bank platform. Please use <b>{{ url }} </b> link to join the platform.
|
|
||||||
<br> Your credentials are:- username = <b>{{email}}</b> and password <b>{{password}}</b><br> <br>Below are the steps to complete the account and how to use this platform.
|
|
||||||
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{% extends "templated_email/email_base.email" %}
|
|
||||||
|
|
||||||
{% block subject %}
|
|
||||||
{{subject}}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block plain %}
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 15px;">
|
|
||||||
<p style="margin: 0; font-size: 16px; line-height: 20px; padding: 36px 0 0; font-weight: 500; color: #1f2532;">
|
|
||||||
Hi {{name}},
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 27px 22px;">
|
|
||||||
<p style="margin: 0;font-size: 14px; font-weight: 400; line-height: 21px; color: #1f2532;">
|
|
||||||
<b>{{name}}</b> have some queries and need some support. Please support them by using their email address <b> {{sender}}</b>. <br> <br> <b>Queries are:- </b> <br> {{ message }}
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
"""Test cases file of account"""
|
|
||||||
"""Django import"""
|
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
""" Urls files"""
|
|
||||||
"""Django import"""
|
|
||||||
from django.urls import path, include
|
|
||||||
"""Third party import"""
|
|
||||||
from rest_framework import routers
|
|
||||||
# Import view functions
|
|
||||||
# UserLogin views,
|
|
||||||
# SendPhoneOtp views,
|
|
||||||
# UserPhoneVerification views,
|
|
||||||
# UserEmailVerification views,
|
|
||||||
# ReSendEmailOtp views,
|
|
||||||
# ForgotPasswordAPIView views,
|
|
||||||
# ResetPasswordAPIView views,
|
|
||||||
# ChangePasswordAPIView views,
|
|
||||||
# UpdateProfileImage views,
|
|
||||||
# GoogleLoginViewSet views,
|
|
||||||
# SigninWithApple views,
|
|
||||||
# ProfileAPIViewSet views,
|
|
||||||
# UploadImageAPIViewSet views,
|
|
||||||
# DefaultImageAPIViewSet views,
|
|
||||||
# DeleteUserProfileAPIViewSet views,
|
|
||||||
# UserNotificationAPIViewSet views,
|
|
||||||
# UpdateUserNotificationAPIViewSet views,
|
|
||||||
# SendSupportEmail views,
|
|
||||||
# LogoutAPIView views,
|
|
||||||
# AccessTokenAPIView views"""
|
|
||||||
from .views import (UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVerification, ReSendEmailOtp,
|
|
||||||
ForgotPasswordAPIView, ResetPasswordAPIView, ChangePasswordAPIView, UpdateProfileImage,
|
|
||||||
GoogleLoginViewSet, SigninWithApple, ProfileAPIViewSet, UploadImageAPIViewSet,
|
|
||||||
DefaultImageAPIViewSet, DeleteUserProfileAPIViewSet, UserNotificationAPIViewSet,
|
|
||||||
UpdateUserNotificationAPIViewSet, SendSupportEmail, LogoutAPIView, AccessTokenAPIView,
|
|
||||||
AdminLoginViewSet)
|
|
||||||
"""Router"""
|
|
||||||
router = routers.SimpleRouter()
|
|
||||||
|
|
||||||
"""API End points with router"""
|
|
||||||
router.register('user', UserLogin, basename='user')
|
|
||||||
"""super admin login"""
|
|
||||||
router.register('admin', AdminLoginViewSet, basename='admin')
|
|
||||||
"""google login end point"""
|
|
||||||
router.register('google-login', GoogleLoginViewSet, basename='admin')
|
|
||||||
router.register('send-phone-otp', SendPhoneOtp, basename='send-phone-otp')
|
|
||||||
router.register('user-phone-verification', UserPhoneVerification, basename='user-phone-verification')
|
|
||||||
"""email verification end point"""
|
|
||||||
router.register('user-email-verification', UserEmailVerification, basename='user-email-verification')
|
|
||||||
"""Resend email otp end point"""
|
|
||||||
router.register('resend-email-otp', ReSendEmailOtp, basename='resend-email-otp')
|
|
||||||
"""Profile end point"""
|
|
||||||
router.register('profile', ProfileAPIViewSet, basename='profile')
|
|
||||||
"""Upload default task image end point"""
|
|
||||||
router.register('upload-default-task-image', UploadImageAPIViewSet, basename='upload-default-task-image')
|
|
||||||
"""Fetch default task image end point"""
|
|
||||||
router.register('default-task-image', DefaultImageAPIViewSet, basename='default-task-image')
|
|
||||||
"""Delete user account"""
|
|
||||||
router.register('delete', DeleteUserProfileAPIViewSet, basename='delete')
|
|
||||||
"""user account notification"""
|
|
||||||
router.register('user-notification', UserNotificationAPIViewSet, basename='user-notification')
|
|
||||||
"""update user account notification"""
|
|
||||||
router.register('update-user-notification', UpdateUserNotificationAPIViewSet, basename='update-user-notification')
|
|
||||||
"""Define url pattern"""
|
|
||||||
urlpatterns = [
|
|
||||||
path('api/v1/', include(router.urls)),
|
|
||||||
path('api/v1/forgot-password/', ForgotPasswordAPIView.as_view()),
|
|
||||||
path('api/v1/reset-password/', ResetPasswordAPIView.as_view()),
|
|
||||||
path('api/v1/change-password/', ChangePasswordAPIView.as_view()),
|
|
||||||
path('api/v1/update-profile-image/', UpdateProfileImage.as_view()),
|
|
||||||
path('api/v1/apple-login/', SigninWithApple.as_view(), name='signup_with_apple'),
|
|
||||||
path('api/v1/send-support-email/', SendSupportEmail.as_view(), name='send-support-email'),
|
|
||||||
path('api/v1/logout/', LogoutAPIView.as_view(), name='logout'),
|
|
||||||
path('api/v1/generate-token/', AccessTokenAPIView.as_view(), name='generate-token')
|
|
||||||
]
|
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
"""Account utils"""
|
|
||||||
from celery import shared_task
|
|
||||||
|
|
||||||
"""Import django"""
|
|
||||||
from django.conf import settings
|
|
||||||
from rest_framework import viewsets, status
|
|
||||||
from rest_framework.response import Response
|
|
||||||
"""Third party Django app"""
|
|
||||||
from templated_email import send_templated_mail
|
|
||||||
import jwt
|
|
||||||
import string
|
|
||||||
from datetime import datetime
|
|
||||||
from calendar import timegm
|
|
||||||
from uuid import uuid4
|
|
||||||
# Import secrets module for generating random number
|
|
||||||
import secrets
|
|
||||||
from rest_framework import serializers
|
|
||||||
# Django App Import
|
|
||||||
# Import models from junior App,
|
|
||||||
# Import models from guardian App,
|
|
||||||
# Import models from account App,
|
|
||||||
# Import messages from base package"""
|
|
||||||
from junior.models import Junior
|
|
||||||
from guardian.models import Guardian
|
|
||||||
from account.models import UserDelete, UserDeviceDetails
|
|
||||||
from base.messages import ERROR_CODE
|
|
||||||
from django.utils import timezone
|
|
||||||
from base.constants import NUMBER
|
|
||||||
from junior.models import JuniorPoints
|
|
||||||
# Define delete
|
|
||||||
# user account condition,
|
|
||||||
# Define delete
|
|
||||||
# user account
|
|
||||||
# condition for social
|
|
||||||
# login account,
|
|
||||||
# Update junior account,
|
|
||||||
# Update guardian account,
|
|
||||||
# Define custom email for otp verification,
|
|
||||||
# Define support email for user's query,
|
|
||||||
# Define custom success response,
|
|
||||||
# Define custom error response,
|
|
||||||
# Generate access token,
|
|
||||||
# refresh token by using jwt,
|
|
||||||
# Define function for generating
|
|
||||||
# guardian code, junior code,
|
|
||||||
# referral code,
|
|
||||||
# Define function for generating
|
|
||||||
# alphanumeric code
|
|
||||||
# otp expiry
|
|
||||||
def delete_user_account_condition(user, user_type_data, user_type, user_tb, data, random_num):
|
|
||||||
"""delete user account"""
|
|
||||||
if user_type == '1' and user_type_data == '1':
|
|
||||||
junior_account_update(user_tb)
|
|
||||||
elif user_type == '2' and user_type_data == '2':
|
|
||||||
guardian_account_update(user_tb)
|
|
||||||
else:
|
|
||||||
raise serializers.ValidationError({"details": ERROR_CODE['2030'], "code": "400", "status": "failed"})
|
|
||||||
user_tb.email = str(random_num) + str('@D_') + '{}'.format(user_tb.username).lower()
|
|
||||||
user_tb.username = str(random_num) + str('@D_') + '{}'.format(user_tb.username).lower()
|
|
||||||
d_email = user_tb.email
|
|
||||||
o_mail = user.email
|
|
||||||
# update user email with dummy email
|
|
||||||
user_tb.save()
|
|
||||||
"""create object in user delete model"""
|
|
||||||
instance = UserDelete.objects.create(user=user_tb, d_email=d_email, old_email=o_mail,
|
|
||||||
is_active=True, reason=data)
|
|
||||||
|
|
||||||
return instance
|
|
||||||
|
|
||||||
def delete_user_account_condition_social(user, user_type,user_tb, data, random_num):
|
|
||||||
"""delete user account"""
|
|
||||||
if user_type == '1':
|
|
||||||
junior_account_update(user_tb)
|
|
||||||
elif user_type == '2':
|
|
||||||
guardian_account_update(user_tb)
|
|
||||||
else:
|
|
||||||
raise serializers.ValidationError({"details": ERROR_CODE['2030'], "code": "400", "status": "failed"})
|
|
||||||
user_tb.email = str(random_num) + str('@D_') + '{}'.format(user_tb.username).lower()
|
|
||||||
user_tb.username = str(random_num) + str('@D_') + '{}'.format(user_tb.username).lower()
|
|
||||||
dummy_email = user_tb.email
|
|
||||||
old_mail = user.email
|
|
||||||
# update user email with dummy email
|
|
||||||
user_tb.save()
|
|
||||||
"""create object in user delete model"""
|
|
||||||
instance_data = UserDelete.objects.create(user=user_tb, d_email=dummy_email, old_email=old_mail,
|
|
||||||
is_active=True, reason=data)
|
|
||||||
|
|
||||||
return instance_data
|
|
||||||
def junior_account_update(user_tb):
|
|
||||||
"""junior account delete"""
|
|
||||||
junior_data = Junior.objects.filter(auth__email=user_tb.email).first()
|
|
||||||
if junior_data:
|
|
||||||
# Update junior account
|
|
||||||
junior_data.is_active = False
|
|
||||||
junior_data.is_verified = False
|
|
||||||
junior_data.guardian_code = '{}'
|
|
||||||
junior_data.guardian_code_status = str(NUMBER['one'])
|
|
||||||
junior_data.save()
|
|
||||||
JuniorPoints.objects.filter(junior=junior_data).delete()
|
|
||||||
|
|
||||||
def guardian_account_update(user_tb):
|
|
||||||
"""update guardian account after delete the user account"""
|
|
||||||
guardian_data = Guardian.objects.filter(user__email=user_tb.email).first()
|
|
||||||
if guardian_data:
|
|
||||||
# Update guardian account
|
|
||||||
guardian_data.is_active = False
|
|
||||||
guardian_data.is_verified = False
|
|
||||||
guardian_data.save()
|
|
||||||
jun_data = Junior.objects.filter(guardian_code__icontains=str(guardian_data.guardian_code))
|
|
||||||
"""Disassociate relation between guardian and junior"""
|
|
||||||
for data in jun_data:
|
|
||||||
data.guardian_code.remove(guardian_data.guardian_code)
|
|
||||||
data.save()
|
|
||||||
@shared_task()
|
|
||||||
def send_otp_email(recipient_email, otp):
|
|
||||||
"""Send otp on email with template"""
|
|
||||||
from_email = settings.EMAIL_FROM_ADDRESS
|
|
||||||
recipient_list = [recipient_email]
|
|
||||||
"""Send otp on email"""
|
|
||||||
send_templated_mail(
|
|
||||||
template_name='email_otp_verification.email',
|
|
||||||
from_email=from_email,
|
|
||||||
recipient_list=recipient_list,
|
|
||||||
context={
|
|
||||||
'otp': otp
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return otp
|
|
||||||
|
|
||||||
@shared_task
|
|
||||||
def user_device_details(user, device_id):
|
|
||||||
"""
|
|
||||||
Used to store the device id of the user
|
|
||||||
user: user object
|
|
||||||
device_id: string
|
|
||||||
return
|
|
||||||
"""
|
|
||||||
device_details, created = UserDeviceDetails.objects.get_or_create(user=user)
|
|
||||||
if device_details:
|
|
||||||
device_details.device_id = device_id
|
|
||||||
device_details.save()
|
|
||||||
|
|
||||||
|
|
||||||
def send_support_email(name, sender, subject, message):
|
|
||||||
"""Send otp on email with template"""
|
|
||||||
to_email = [settings.EMAIL_FROM_ADDRESS]
|
|
||||||
from_email = settings.DEFAULT_ADDRESS
|
|
||||||
"""Send support email to zod bank support team"""
|
|
||||||
send_templated_mail(
|
|
||||||
template_name='support_mail.email',
|
|
||||||
from_email=from_email,
|
|
||||||
recipient_list=to_email,
|
|
||||||
context={
|
|
||||||
'name': name.title(),
|
|
||||||
'sender': sender,
|
|
||||||
'subject': subject,
|
|
||||||
'message': message
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return name
|
|
||||||
|
|
||||||
|
|
||||||
def custom_response(detail, data=None, response_status=status.HTTP_200_OK, count=None):
|
|
||||||
"""Custom response code"""
|
|
||||||
if not data:
|
|
||||||
"""when data is none"""
|
|
||||||
data = None
|
|
||||||
return Response({"data": data, "message": detail, "status": "success", "code": response_status, "count": count})
|
|
||||||
|
|
||||||
|
|
||||||
def custom_error_response(detail, response_status):
|
|
||||||
"""
|
|
||||||
function is used for getting same global error response for all
|
|
||||||
:param detail: error message .
|
|
||||||
:param response_status: http status.
|
|
||||||
:return: Json response
|
|
||||||
"""
|
|
||||||
if not detail:
|
|
||||||
"""when details is empty"""
|
|
||||||
detail = {}
|
|
||||||
return Response({"error": detail, "status": "failed", "code": response_status})
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_data(attrs):
|
|
||||||
"""
|
|
||||||
used to decode token
|
|
||||||
"""
|
|
||||||
user_data = jwt.decode(jwt=attrs['token'], options={'verify_signature': False},
|
|
||||||
algorithms=['RS256'])
|
|
||||||
return user_data
|
|
||||||
|
|
||||||
|
|
||||||
def generate_jwt_token(token_type: str, now_time: int, data: dict = dict):
|
|
||||||
"""
|
|
||||||
used to generate jwt token
|
|
||||||
"""
|
|
||||||
if type(data) == type:
|
|
||||||
data = {}
|
|
||||||
"""Update data dictionary"""
|
|
||||||
data.update({
|
|
||||||
'token_type': token_type,
|
|
||||||
'iss': 'your_site_url',
|
|
||||||
'iat': timegm(datetime.utcnow().utctimetuple()),
|
|
||||||
'jti': uuid4().hex
|
|
||||||
})
|
|
||||||
"""Access and Refresh token"""
|
|
||||||
TOKEN_TYPE = ["access", "refresh"]
|
|
||||||
if token_type == TOKEN_TYPE[1]:
|
|
||||||
"""Refresh token"""
|
|
||||||
exp = now_time + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME']
|
|
||||||
else:
|
|
||||||
"""access token"""
|
|
||||||
exp = now_time + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME']
|
|
||||||
|
|
||||||
data.update({
|
|
||||||
"exp": timegm(exp.utctimetuple())
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
signing_key = secrets.token_hex(32)
|
|
||||||
|
|
||||||
return jwt.encode(payload=data, key=signing_key,
|
|
||||||
algorithm='HS256')
|
|
||||||
|
|
||||||
|
|
||||||
def get_token(data: dict = dict):
|
|
||||||
""" create access and refresh token """
|
|
||||||
now_time = datetime.utcnow()
|
|
||||||
"""generate access token"""
|
|
||||||
access = generate_jwt_token('access', now_time, data)
|
|
||||||
"""generate refresh token"""
|
|
||||||
refresh = generate_jwt_token('refresh', now_time, data)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'access': access,
|
|
||||||
'refresh': refresh
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def generate_alphanumeric_code(length):
|
|
||||||
"""Generate alphanumeric code"""
|
|
||||||
alphabet = string.ascii_letters + string.digits
|
|
||||||
code = ''.join(secrets.choice(alphabet) for _ in range(length))
|
|
||||||
return code
|
|
||||||
|
|
||||||
|
|
||||||
def generate_code(value, user_id):
|
|
||||||
"""generate referral, junior and guardian code"""
|
|
||||||
code = value + str(user_id).zfill(3)
|
|
||||||
return code
|
|
||||||
|
|
||||||
|
|
||||||
OTP_EXPIRY = timezone.now() + timezone.timedelta(days=1)
|
|
||||||
@@ -1,602 +0,0 @@
|
|||||||
"""Account view """
|
|
||||||
import threading
|
|
||||||
|
|
||||||
from notifications.utils import remove_fcm_token
|
|
||||||
|
|
||||||
# django imports
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from rest_framework import viewsets, status, views
|
|
||||||
from rest_framework.decorators import action
|
|
||||||
import logging
|
|
||||||
from django.utils import timezone
|
|
||||||
import jwt
|
|
||||||
from django.contrib.auth import logout
|
|
||||||
from django.contrib.auth import authenticate, login
|
|
||||||
from rest_framework.permissions import IsAuthenticated
|
|
||||||
from templated_email import send_templated_mail
|
|
||||||
import google.oauth2.credentials
|
|
||||||
import google.auth.transport.requests
|
|
||||||
from rest_framework import status
|
|
||||||
import requests
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from rest_framework import mixins
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
# local imports
|
|
||||||
from guardian.models import Guardian
|
|
||||||
from junior.models import Junior, JuniorPoints
|
|
||||||
from guardian.utils import upload_image_to_alibaba
|
|
||||||
from account.models import UserDeviceDetails, UserPhoneOtp, UserEmailOtp, DefaultTaskImages, UserNotification
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer,
|
|
||||||
ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer,
|
|
||||||
GoogleLoginSerializer, UpdateGuardianImageSerializer, UpdateJuniorProfileImageSerializer,
|
|
||||||
DefaultTaskImagesSerializer, DefaultTaskImagesDetailsSerializer, UserDeleteSerializer,
|
|
||||||
UserNotificationSerializer, UpdateUserNotificationSerializer, UserPhoneOtpSerializer,
|
|
||||||
AdminLoginSerializer)
|
|
||||||
from rest_framework_simplejwt.tokens import RefreshToken
|
|
||||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
|
||||||
from base.constants import NUMBER, ZOD, JUN, GRD, USER_TYPE_FLAG
|
|
||||||
from guardian.tasks import generate_otp
|
|
||||||
from account.utils import (send_otp_email, send_support_email, custom_response, custom_error_response,
|
|
||||||
generate_code, OTP_EXPIRY, user_device_details)
|
|
||||||
from junior.serializers import JuniorProfileSerializer
|
|
||||||
from guardian.serializers import GuardianProfileSerializer
|
|
||||||
|
|
||||||
class GoogleLoginMixin(object):
|
|
||||||
"""google login mixin"""
|
|
||||||
@staticmethod
|
|
||||||
def google_login(request):
|
|
||||||
"""google login function"""
|
|
||||||
access_token = request.data.get('access_token')
|
|
||||||
user_type = request.data.get('user_type')
|
|
||||||
if not access_token:
|
|
||||||
return Response({'error': 'Access token is required.'}, status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Validate the access token and obtain the user's email and name
|
|
||||||
credentials = google.oauth2.credentials.Credentials.from_authorized_user_info(
|
|
||||||
info={
|
|
||||||
'access_token': access_token,
|
|
||||||
'token_uri': 'https://oauth2.googleapis.com/token',
|
|
||||||
'client_id': settings.GOOGLE_CLIENT_ID,
|
|
||||||
'client_secret': settings.GOOGLE_CLIENT_SECRET,
|
|
||||||
'refresh_token': None,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
user_info_endpoint = f'https://www.googleapis.com/oauth2/v3/userinfo?access_token={access_token}'
|
|
||||||
headers = {'Authorization': f'Bearer {credentials.token}'}
|
|
||||||
response = requests.get(user_info_endpoint, headers=headers)
|
|
||||||
response.raise_for_status()
|
|
||||||
user_info = response.json()
|
|
||||||
email = user_info['email']
|
|
||||||
first_name = user_info['given_name']
|
|
||||||
last_name = user_info['family_name']
|
|
||||||
profile_picture = user_info['picture']
|
|
||||||
except Exception as e:
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
# Check if the user exists in your database or create a new user
|
|
||||||
# ...
|
|
||||||
user_data = User.objects.filter(email__iexact=email)
|
|
||||||
if user_data.exists():
|
|
||||||
if str(user_type) == '1':
|
|
||||||
junior_query = Junior.objects.filter(auth=user_data.last()).last()
|
|
||||||
serializer = JuniorSerializer(junior_query)
|
|
||||||
if str(user_type) == '2':
|
|
||||||
guardian_query = Guardian.objects.filter(user=user_data.last()).last()
|
|
||||||
serializer = GuardianSerializer(guardian_query)
|
|
||||||
return custom_response(SUCCESS_CODE['3003'], serializer.data,
|
|
||||||
response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
if not User.objects.filter(email__iexact=email).exists():
|
|
||||||
user_obj = User.objects.create(username=email, email=email, first_name=first_name, last_name=last_name)
|
|
||||||
if str(user_type) == '1':
|
|
||||||
junior_query = Junior.objects.create(auth=user_obj, is_verified=True, is_active=True,
|
|
||||||
image=profile_picture, signup_method='2',
|
|
||||||
junior_code=generate_code(JUN, user_obj.id),
|
|
||||||
referral_code=generate_code(ZOD, user_obj.id)
|
|
||||||
)
|
|
||||||
serializer = JuniorSerializer(junior_query)
|
|
||||||
position = Junior.objects.all().count()
|
|
||||||
JuniorPoints.objects.create(junior=junior_query, position=position)
|
|
||||||
if str(user_type) == '2':
|
|
||||||
guardian_query = Guardian.objects.create(user=user_obj, is_verified=True, is_active=True,
|
|
||||||
image=profile_picture,signup_method='2',
|
|
||||||
guardian_code=generate_code(GRD, user_obj.id),
|
|
||||||
referral_code=generate_code(ZOD, user_obj.id)
|
|
||||||
)
|
|
||||||
serializer = GuardianSerializer(guardian_query)
|
|
||||||
# Return a JSON response with the user's email and name
|
|
||||||
return custom_response(SUCCESS_CODE['3003'], serializer.data,
|
|
||||||
response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class GoogleLoginViewSet(GoogleLoginMixin, viewsets.GenericViewSet):
|
|
||||||
"""Google login viewset"""
|
|
||||||
serializer_class = GoogleLoginSerializer
|
|
||||||
|
|
||||||
def create(self, request):
|
|
||||||
"""create method"""
|
|
||||||
serializer = self.get_serializer(data=request.data)
|
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
return self.google_login(request)
|
|
||||||
|
|
||||||
class SigninWithApple(views.APIView):
|
|
||||||
"""This API is for sign in with Apple for app."""
|
|
||||||
def post(self, request):
|
|
||||||
token = request.data.get("access_token")
|
|
||||||
user_type = request.data.get("user_type")
|
|
||||||
try:
|
|
||||||
decoded_data = jwt.decode(token, options={"verify_signature": False})
|
|
||||||
user_data = {"email": decoded_data.get('email'), "username": decoded_data.get('email'), "is_active": True}
|
|
||||||
if decoded_data.get("email"):
|
|
||||||
try:
|
|
||||||
user = User.objects.get(email=decoded_data.get("email"))
|
|
||||||
if str(user_type) == '1':
|
|
||||||
junior_query = Junior.objects.filter(auth=user).last()
|
|
||||||
serializer = JuniorSerializer(junior_query)
|
|
||||||
if str(user_type) == '2':
|
|
||||||
guardian_query = Guardian.objects.filter(user=user).last()
|
|
||||||
serializer = GuardianSerializer(guardian_query)
|
|
||||||
return custom_response(SUCCESS_CODE['3003'], serializer.data,
|
|
||||||
response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
except User.DoesNotExist:
|
|
||||||
user = User.objects.create(**user_data)
|
|
||||||
if str(user_type) == '1':
|
|
||||||
junior_query = Junior.objects.create(auth=user, is_verified=True, is_active=True,
|
|
||||||
signup_method='3',
|
|
||||||
junior_code=generate_code(JUN, user.id),
|
|
||||||
referral_code=generate_code(ZOD, user.id))
|
|
||||||
serializer = JuniorSerializer(junior_query)
|
|
||||||
position = Junior.objects.all().count()
|
|
||||||
JuniorPoints.objects.create(junior=junior_query, position=position)
|
|
||||||
if str(user_type) == '2':
|
|
||||||
guardian_query = Guardian.objects.create(user=user, is_verified=True, is_active=True,
|
|
||||||
signup_method='3',
|
|
||||||
guardian_code=generate_code(GRD, user.id),
|
|
||||||
referral_code=generate_code(ZOD, user.id))
|
|
||||||
serializer = GuardianSerializer(guardian_query)
|
|
||||||
return custom_response(SUCCESS_CODE['3003'], serializer.data,
|
|
||||||
response_status=status.HTTP_200_OK)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(e)
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateProfileImage(views.APIView):
|
|
||||||
"""Update profile image"""
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
def put(self, request, format=None):
|
|
||||||
try:
|
|
||||||
image = request.data['image']
|
|
||||||
if image and image.size == NUMBER['zero']:
|
|
||||||
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
filename = f"images/{image.name}"
|
|
||||||
image_url = upload_image_to_alibaba(image, filename)
|
|
||||||
image_data = image_url
|
|
||||||
if str(request.data['user_type']) == '1':
|
|
||||||
junior_query = Junior.objects.filter(auth=request.user).last()
|
|
||||||
serializer = UpdateJuniorProfileImageSerializer(junior_query,
|
|
||||||
data={'image':image_data}, partial=True)
|
|
||||||
elif str(request.data['user_type']) == '2':
|
|
||||||
guardian_query = Guardian.objects.filter(user=request.user).last()
|
|
||||||
serializer = UpdateGuardianImageSerializer(guardian_query,
|
|
||||||
data={'image':image_data}, partial=True)
|
|
||||||
if serializer.is_valid():
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(SUCCESS_CODE['3017'], serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(e)
|
|
||||||
return custom_error_response(ERROR_CODE['2036'],response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class ChangePasswordAPIView(views.APIView):
|
|
||||||
"""change password"""
|
|
||||||
serializer_class = ChangePasswordSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
def post(self, request):
|
|
||||||
serializer = ChangePasswordSerializer(context=request.user, data=request.data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(SUCCESS_CODE['3007'], response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class ResetPasswordAPIView(views.APIView):
|
|
||||||
"""Reset password"""
|
|
||||||
def post(self, request):
|
|
||||||
serializer = ResetPasswordSerializer(data=request.data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(SUCCESS_CODE['3006'], response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class ForgotPasswordAPIView(views.APIView):
|
|
||||||
"""Forgot password"""
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
serializer = ForgotPasswordSerializer(data=request.data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
email = serializer.validated_data['email']
|
|
||||||
try:
|
|
||||||
User.objects.get(email=email)
|
|
||||||
except User.DoesNotExist:
|
|
||||||
return custom_error_response(ERROR_CODE['2004'], response_status=status.HTTP_404_NOT_FOUND)
|
|
||||||
verification_code = generate_otp()
|
|
||||||
# Send the verification code to the user's email
|
|
||||||
from_email = settings.EMAIL_FROM_ADDRESS
|
|
||||||
recipient_list = [email]
|
|
||||||
send_templated_mail(
|
|
||||||
template_name='email_reset_verification.email',
|
|
||||||
from_email=from_email,
|
|
||||||
recipient_list=recipient_list,
|
|
||||||
context={
|
|
||||||
'verification_code': verification_code
|
|
||||||
}
|
|
||||||
)
|
|
||||||
expiry = OTP_EXPIRY
|
|
||||||
user_data, created = UserEmailOtp.objects.get_or_create(email=email)
|
|
||||||
if created:
|
|
||||||
user_data.expired_at = expiry
|
|
||||||
user_data.save()
|
|
||||||
if user_data:
|
|
||||||
user_data.otp = verification_code
|
|
||||||
user_data.expired_at = expiry
|
|
||||||
user_data.save()
|
|
||||||
return custom_response(SUCCESS_CODE['3015'],
|
|
||||||
response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class SendPhoneOtp(viewsets.ModelViewSet):
|
|
||||||
"""Send otp on phone"""
|
|
||||||
serializer_class = UserPhoneOtpSerializer
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
otp = generate_otp()
|
|
||||||
phone_number = self.request.data['phone']
|
|
||||||
if phone_number.isdigit() and len(phone_number) == 10:
|
|
||||||
phone_otp, created = UserPhoneOtp.objects.get_or_create(country_code=self.request.data['country_code'],
|
|
||||||
phone=self.request.data['phone'])
|
|
||||||
if phone_otp:
|
|
||||||
phone_otp.otp = otp
|
|
||||||
phone_otp.save()
|
|
||||||
return custom_response(None, {'phone_otp':otp}, response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(ERROR_CODE['2020'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class UserPhoneVerification(viewsets.ModelViewSet):
|
|
||||||
"""Send otp on phone"""
|
|
||||||
serializer_class = UserPhoneOtpSerializer
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
try:
|
|
||||||
phone_data = UserPhoneOtp.objects.filter(phone=self.request.GET.get('phone'),
|
|
||||||
otp=self.request.GET.get('otp')).last()
|
|
||||||
if phone_data:
|
|
||||||
phone_data.is_verified = True
|
|
||||||
phone_data.save()
|
|
||||||
return custom_response(SUCCESS_CODE['3012'], response_status=status.HTTP_200_OK)
|
|
||||||
else:
|
|
||||||
return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
except Exception:
|
|
||||||
return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class UserLogin(viewsets.ViewSet):
|
|
||||||
"""User login"""
|
|
||||||
@action(methods=['post'], detail=False)
|
|
||||||
def login(self, request):
|
|
||||||
username = request.data.get('username')
|
|
||||||
password = request.data.get('password')
|
|
||||||
user_type = request.data.get('user_type')
|
|
||||||
device_id = request.META.get('HTTP_DEVICE_ID')
|
|
||||||
user = authenticate(request, username=username, password=password)
|
|
||||||
|
|
||||||
try:
|
|
||||||
if user is not None:
|
|
||||||
login(request, user)
|
|
||||||
if user_type == USER_TYPE_FLAG["TWO"]:
|
|
||||||
guardian_data = Guardian.objects.filter(user__username=username, is_verified=True).last()
|
|
||||||
if guardian_data:
|
|
||||||
serializer = GuardianSerializer(
|
|
||||||
guardian_data, context={'user_type': user_type}
|
|
||||||
).data
|
|
||||||
else:
|
|
||||||
return custom_error_response(
|
|
||||||
ERROR_CODE["2070"],
|
|
||||||
response_status=status.HTTP_401_UNAUTHORIZED
|
|
||||||
)
|
|
||||||
elif user_type == USER_TYPE_FLAG["FIRST"]:
|
|
||||||
junior_data = Junior.objects.filter(auth__username=username, is_verified=True).last()
|
|
||||||
if junior_data:
|
|
||||||
serializer = JuniorSerializer(
|
|
||||||
junior_data, context={'user_type': user_type}
|
|
||||||
).data
|
|
||||||
else:
|
|
||||||
return custom_error_response(
|
|
||||||
ERROR_CODE["2071"],
|
|
||||||
response_status=status.HTTP_401_UNAUTHORIZED
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return custom_error_response(
|
|
||||||
ERROR_CODE["2069"],
|
|
||||||
response_status=status.HTTP_401_UNAUTHORIZED
|
|
||||||
)
|
|
||||||
# storing device id in using thread so the time would be reduced
|
|
||||||
threading.Thread(target=user_device_details, args=(user, device_id))
|
|
||||||
return custom_response(SUCCESS_CODE['3003'], serializer, response_status=status.HTTP_200_OK)
|
|
||||||
else:
|
|
||||||
return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_401_UNAUTHORIZED)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(e)
|
|
||||||
email_verified = UserEmailOtp.objects.filter(email=username).last()
|
|
||||||
refresh = RefreshToken.for_user(user)
|
|
||||||
access_token = str(refresh.access_token)
|
|
||||||
refresh_token = str(refresh)
|
|
||||||
data = {
|
|
||||||
"auth_token":access_token,
|
|
||||||
"refresh_token":refresh_token,
|
|
||||||
"is_profile_complete": False,
|
|
||||||
"user_type": user_type,
|
|
||||||
}
|
|
||||||
is_verified = False
|
|
||||||
if email_verified:
|
|
||||||
is_verified = email_verified.is_verified
|
|
||||||
if not is_verified:
|
|
||||||
otp = generate_otp()
|
|
||||||
email_verified.otp = otp
|
|
||||||
email_verified.save()
|
|
||||||
data.update({"email_otp":otp})
|
|
||||||
send_otp_email.delay(username, otp)
|
|
||||||
return custom_response(
|
|
||||||
ERROR_CODE['2024'],
|
|
||||||
{"email_otp": otp, "is_email_verified": is_verified},
|
|
||||||
response_status=status.HTTP_200_OK
|
|
||||||
)
|
|
||||||
data.update({"is_email_verified": is_verified})
|
|
||||||
return custom_response(
|
|
||||||
SUCCESS_CODE['3003'],
|
|
||||||
data,
|
|
||||||
response_status=status.HTTP_200_OK
|
|
||||||
)
|
|
||||||
|
|
||||||
@action(methods=['post'], detail=False)
|
|
||||||
def admin_login(self, request):
|
|
||||||
email = request.data.get('email')
|
|
||||||
password = request.data.get('password')
|
|
||||||
user = User.objects.filter(email__iexact=email, is_superuser=True
|
|
||||||
).only('id', 'first_name', 'last_name', 'email',
|
|
||||||
'username', 'is_active', 'is_superuser').first()
|
|
||||||
|
|
||||||
if not user or not user.check_password(password):
|
|
||||||
return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
serializer = SuperUserSerializer(user)
|
|
||||||
return custom_response(SUCCESS_CODE['3003'], serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class AdminLoginViewSet(viewsets.GenericViewSet):
|
|
||||||
"""
|
|
||||||
admin login api
|
|
||||||
"""
|
|
||||||
serializer_class = AdminLoginSerializer
|
|
||||||
|
|
||||||
@action(methods=['post'], url_name='login', url_path='login', detail=False)
|
|
||||||
def admin_login(self, request, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
:param request:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
serializer = self.serializer_class(data=request.data)
|
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
user = serializer.save()
|
|
||||||
refresh = RefreshToken.for_user(user)
|
|
||||||
access_token = str(refresh.access_token)
|
|
||||||
refresh_token = str(refresh)
|
|
||||||
data = {"auth_token": access_token, "refresh_token": refresh_token, "username": user.username,
|
|
||||||
"email": user.email, "first_name": user.first_name, "last_name": user.last_name,
|
|
||||||
"is_active": user.is_active, "user_type": '3', "is_superuser": user.is_superuser}
|
|
||||||
return custom_response(None, data)
|
|
||||||
|
|
||||||
|
|
||||||
class UserEmailVerification(viewsets.ModelViewSet):
|
|
||||||
"""User Email verification"""
|
|
||||||
serializer_class = EmailVerificationSerializer
|
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
try:
|
|
||||||
user_obj = User.objects.filter(username=self.request.GET.get('email')).last()
|
|
||||||
email_data = UserEmailOtp.objects.filter(email=self.request.GET.get('email'),
|
|
||||||
otp=self.request.GET.get('otp')).last()
|
|
||||||
if email_data:
|
|
||||||
input_datetime_str = str(email_data.expired_at)
|
|
||||||
input_format = "%Y-%m-%d %H:%M:%S.%f%z"
|
|
||||||
output_format = "%Y-%m-%d %H:%M:%S.%f"
|
|
||||||
input_datetime = datetime.strptime(input_datetime_str, input_format)
|
|
||||||
output_datetime_str = input_datetime.strftime(output_format)
|
|
||||||
format_str = "%Y-%m-%d %H:%M:%S.%f"
|
|
||||||
datetime_obj = datetime.strptime(output_datetime_str, format_str)
|
|
||||||
if datetime.today() > datetime_obj:
|
|
||||||
return custom_error_response(ERROR_CODE["2029"], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
email_data.is_verified = True
|
|
||||||
email_data.save()
|
|
||||||
if email_data.user_type == '1':
|
|
||||||
junior_data = Junior.objects.filter(auth__email=self.request.GET.get('email')).last()
|
|
||||||
if junior_data:
|
|
||||||
junior_data.is_verified = True
|
|
||||||
junior_data.save()
|
|
||||||
else:
|
|
||||||
guardian_data = Guardian.objects.filter(user__email=self.request.GET.get('email')).last()
|
|
||||||
if guardian_data:
|
|
||||||
guardian_data.is_verified = True
|
|
||||||
guardian_data.save()
|
|
||||||
refresh = RefreshToken.for_user(user_obj)
|
|
||||||
access_token = str(refresh.access_token)
|
|
||||||
refresh_token = str(refresh)
|
|
||||||
return custom_response(SUCCESS_CODE['3011'], {"auth_token":access_token,
|
|
||||||
"refresh_token":refresh_token},
|
|
||||||
response_status=status.HTTP_200_OK)
|
|
||||||
else:
|
|
||||||
return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(e)
|
|
||||||
return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class ReSendEmailOtp(viewsets.ModelViewSet):
|
|
||||||
"""Send otp on phone"""
|
|
||||||
serializer_class = EmailVerificationSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
otp = generate_otp()
|
|
||||||
if User.objects.filter(email=request.data['email']):
|
|
||||||
expiry = OTP_EXPIRY
|
|
||||||
email_data, created = UserEmailOtp.objects.get_or_create(email=request.data['email'])
|
|
||||||
if created:
|
|
||||||
email_data.expired_at = expiry
|
|
||||||
email_data.save()
|
|
||||||
if email_data:
|
|
||||||
email_data.otp = otp
|
|
||||||
email_data.expired_at = expiry
|
|
||||||
email_data.save()
|
|
||||||
send_otp_email(request.data['email'], otp)
|
|
||||||
return custom_response(SUCCESS_CODE['3016'], response_status=status.HTTP_200_OK)
|
|
||||||
else:
|
|
||||||
return custom_error_response(ERROR_CODE["2023"], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class ProfileAPIViewSet(viewsets.ModelViewSet):
|
|
||||||
"""Profile viewset"""
|
|
||||||
serializer_class = JuniorProfileSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
"""profile view"""
|
|
||||||
if str(self.request.GET.get('user_type')) == '1':
|
|
||||||
junior_data = Junior.objects.filter(auth=self.request.user).last()
|
|
||||||
if junior_data:
|
|
||||||
serializer = JuniorProfileSerializer(junior_data)
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
elif str(self.request.GET.get('user_type')) == '2':
|
|
||||||
guardian_data = Guardian.objects.filter(user=self.request.user).last()
|
|
||||||
if guardian_data:
|
|
||||||
serializer = GuardianProfileSerializer(guardian_data)
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
class UploadImageAPIViewSet(viewsets.ModelViewSet):
|
|
||||||
"""upload task image"""
|
|
||||||
serializer_class = DefaultTaskImagesSerializer
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
"""upload images"""
|
|
||||||
image_data = request.data['image_url']
|
|
||||||
filename = f"default_task_images/{image_data.name}"
|
|
||||||
if image_data.size == NUMBER['zero']:
|
|
||||||
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
image = upload_image_to_alibaba(image_data, filename)
|
|
||||||
image_data = image
|
|
||||||
request.data['image_url'] = image_data
|
|
||||||
serializer = DefaultTaskImagesSerializer(data=request.data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.error, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class DefaultImageAPIViewSet(viewsets.ModelViewSet):
|
|
||||||
"""Profile viewset"""
|
|
||||||
serializer_class = DefaultTaskImagesDetailsSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
"""profile view"""
|
|
||||||
queryset = DefaultTaskImages.objects.all()
|
|
||||||
serializer = DefaultTaskImagesSerializer(queryset, many=True)
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteUserProfileAPIViewSet(viewsets.GenericViewSet):
|
|
||||||
""" Delete user API view set """
|
|
||||||
|
|
||||||
@action(detail=False, methods=['POST'], url_path='user-account',serializer_class=UserDeleteSerializer,
|
|
||||||
permission_classes=[IsAuthenticated])
|
|
||||||
def account(self, request):
|
|
||||||
user_type = str(request.data['user_type'])
|
|
||||||
password = request.data.get('password')
|
|
||||||
signup_method = str(request.data.get('signup_method'))
|
|
||||||
serializer = self.get_serializer(data=request.data, context={'request': request, 'user': request.user,
|
|
||||||
'user_type': user_type,
|
|
||||||
'password': password,
|
|
||||||
'signup_method':signup_method})
|
|
||||||
if serializer.is_valid():
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(SUCCESS_CODE['3005'], response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class UserNotificationAPIViewSet(viewsets.ModelViewSet):
|
|
||||||
"""notification viewset"""
|
|
||||||
serializer_class = UserNotificationSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
"""profile view"""
|
|
||||||
queryset = self.queryset.filter(user=request.user)
|
|
||||||
serializer = UserNotificationSerializer(queryset, many=True)
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateUserNotificationAPIViewSet(viewsets.ModelViewSet):
|
|
||||||
"""Update notification viewset"""
|
|
||||||
serializer_class = UpdateUserNotificationSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
"""profile view"""
|
|
||||||
serializer = UpdateUserNotificationSerializer(data=request.data,
|
|
||||||
context=request.user)
|
|
||||||
if serializer.is_valid():
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.error, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class SendSupportEmail(views.APIView):
|
|
||||||
"""support email api"""
|
|
||||||
permission_classes = (IsAuthenticated,)
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
name = request.data.get('name')
|
|
||||||
sender = request.data.get('email')
|
|
||||||
subject = request.data.get('subject')
|
|
||||||
message = request.data.get('message')
|
|
||||||
if name and sender and subject and message:
|
|
||||||
try:
|
|
||||||
send_support_email(name, sender, subject, message)
|
|
||||||
return custom_response(SUCCESS_CODE['3019'], response_status=status.HTTP_200_OK)
|
|
||||||
except Exception as e:
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
else:
|
|
||||||
return custom_error_response(ERROR_CODE['2033'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class LogoutAPIView(views.APIView):
|
|
||||||
"""Log out API"""
|
|
||||||
permission_classes = (IsAuthenticated,)
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
remove_fcm_token(
|
|
||||||
request.auth.payload['user_id'],
|
|
||||||
request.META['HTTP_AUTHORIZATION'].split(" ")[1],
|
|
||||||
request.data.get('registration_id', ""))
|
|
||||||
logout(request)
|
|
||||||
request.session.flush()
|
|
||||||
return custom_response(SUCCESS_CODE['3020'], response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class AccessTokenAPIView(views.APIView):
|
|
||||||
"""generate access token API"""
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
# Assuming you have a refresh_token string
|
|
||||||
refresh_token = request.data['refresh_token']
|
|
||||||
# Create a RefreshToken instance from the refresh token string
|
|
||||||
refresh = RefreshToken(refresh_token)
|
|
||||||
# Generate a new access token
|
|
||||||
access_token = str(refresh.access_token)
|
|
||||||
data = {"auth_token": access_token}
|
|
||||||
return custom_response(None, data, response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
"""
|
|
||||||
This is init module of the Project Zod Bank
|
|
||||||
"""
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
"""
|
|
||||||
Common send_mail function
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from django.core.mail import EmailMultiAlternatives
|
|
||||||
|
|
||||||
|
|
||||||
def send_mail(subject, message, from_email, recipient_list, html_message=None, cc=None,
|
|
||||||
fail_silently=False):
|
|
||||||
"""
|
|
||||||
Send Email
|
|
||||||
:param subject:
|
|
||||||
:param message:
|
|
||||||
:param from_email:
|
|
||||||
:param recipient_list:
|
|
||||||
:param html_message:
|
|
||||||
:param cc:
|
|
||||||
:param fail_silently:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
mail = EmailMultiAlternatives(subject, message, from_email, recipient_list, cc)
|
|
||||||
if html_message:
|
|
||||||
mail.attach_alternative(html_message, 'text/html')
|
|
||||||
|
|
||||||
return mail.send(fail_silently)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(e)
|
|
||||||
return False
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
"""
|
|
||||||
This module contains constants used throughout the project
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
|
|
||||||
# GOOGLE_URL used for interact with google server to verify user existence.
|
|
||||||
#GOOGLE_URL = "https://www.googleapis.com/plus/v1/"
|
|
||||||
|
|
||||||
# Define Code prefix word
|
|
||||||
# for guardian code,
|
|
||||||
# junior code,
|
|
||||||
# referral code"""
|
|
||||||
ZOD = 'ZOD'
|
|
||||||
JUN = 'JUN'
|
|
||||||
GRD = 'GRD'
|
|
||||||
# Define number variable
|
|
||||||
# from zero to
|
|
||||||
# twenty and
|
|
||||||
# some standard
|
|
||||||
# number"""
|
|
||||||
NUMBER = {
|
|
||||||
'point_zero': 0.0, 'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6, 'seven': 7,
|
|
||||||
'eight': 8, 'nine': 9, 'ten': 10, 'eleven': 11, 'twelve': 12, 'thirteen': 13, 'fourteen': 14, 'fifteen': 15,
|
|
||||||
'sixteen': 16, 'seventeen': 17, 'eighteen': 18, 'nineteen': 19, 'twenty': 20,
|
|
||||||
'twenty_one': 21, 'twenty_two': 22,'twenty_three': 23, 'twenty_four': 24, 'twenty_five': 25,
|
|
||||||
'thirty': 30, 'forty': 40, 'fifty': 50, 'sixty': 60, 'seventy': 70, 'eighty': 80, 'ninty': 90,
|
|
||||||
'ninety_nine': 99, 'hundred': 100, 'thirty_six_hundred': 3600
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Super Admin string constant for 'role'
|
|
||||||
SUPER_ADMIN = "Super Admin"
|
|
||||||
|
|
||||||
# Define jwt_token_expiration time in minutes for now token will expire after 3 days
|
|
||||||
JWT_TOKEN_EXPIRATION = 3 * 24 * 60
|
|
||||||
|
|
||||||
# Define common file extention
|
|
||||||
FILE_EXTENSION = ("gif", "jpeg", "jpg", "png", "svg")
|
|
||||||
|
|
||||||
# Define file size in bytes(5MB = 5 * 1024 * 1024)
|
|
||||||
FILE_SIZE = 5 * 1024 * 1024
|
|
||||||
|
|
||||||
# String constant for configurable date for allocation lock period
|
|
||||||
ALLOCATION_LOCK_DATE = 1
|
|
||||||
|
|
||||||
"""user type"""
|
|
||||||
USER_TYPE = (
|
|
||||||
('1', 'junior'),
|
|
||||||
('2', 'guardian'),
|
|
||||||
('3', 'superuser')
|
|
||||||
)
|
|
||||||
|
|
||||||
USER_TYPE_FLAG = {
|
|
||||||
"FIRST" : "1",
|
|
||||||
"TWO" : "2",
|
|
||||||
"THREE": "3"
|
|
||||||
}
|
|
||||||
|
|
||||||
"""gender"""
|
|
||||||
GENDERS = (
|
|
||||||
('1', 'Male'),
|
|
||||||
('2', 'Female')
|
|
||||||
)
|
|
||||||
# Task status"""
|
|
||||||
TASK_STATUS = (
|
|
||||||
('1', 'pending'),
|
|
||||||
('2', 'in-progress'),
|
|
||||||
('3', 'rejected'),
|
|
||||||
('4', 'requested'),
|
|
||||||
('5', 'completed'),
|
|
||||||
('6', 'expired')
|
|
||||||
)
|
|
||||||
# sign up method
|
|
||||||
SIGNUP_METHODS = (
|
|
||||||
('1', 'manual'),
|
|
||||||
('2', 'google'),
|
|
||||||
('3', 'apple')
|
|
||||||
)
|
|
||||||
# guardian code status
|
|
||||||
GUARDIAN_CODE_STATUS = (
|
|
||||||
('1', 'no guardian code'),
|
|
||||||
('2', 'exist guardian code'),
|
|
||||||
('3', 'request for guardian code')
|
|
||||||
)
|
|
||||||
# article status
|
|
||||||
ARTICLE_STATUS = (
|
|
||||||
('1', 'read'),
|
|
||||||
('2', 'in_progress'),
|
|
||||||
('3', 'completed')
|
|
||||||
)
|
|
||||||
# relationship
|
|
||||||
RELATIONSHIP = (
|
|
||||||
('1', 'parent'),
|
|
||||||
('2', 'legal_guardian')
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
Define task status
|
|
||||||
in a number"""
|
|
||||||
PENDING = 1
|
|
||||||
IN_PROGRESS = 2
|
|
||||||
REJECTED = 3
|
|
||||||
REQUESTED = 4
|
|
||||||
COMPLETED = 5
|
|
||||||
EXPIRED = 6
|
|
||||||
TASK_POINTS = 5
|
|
||||||
# duplicate name used defined in constant PROJECT_NAME
|
|
||||||
PROJECT_NAME = 'Zod Bank'
|
|
||||||
# define user type constant
|
|
||||||
GUARDIAN = 'guardian'
|
|
||||||
JUNIOR = 'junior'
|
|
||||||
SUPERUSER = 'superuser'
|
|
||||||
# numbers used as a constant
|
|
||||||
|
|
||||||
# Define the byte into kb
|
|
||||||
BYTE_IMAGE_SIZE = 1024
|
|
||||||
|
|
||||||
# validate file size
|
|
||||||
MAX_FILE_SIZE = 1024 * 1024 * 5
|
|
||||||
|
|
||||||
ARTICLE_SURVEY_POINTS = 5
|
|
||||||
MAX_ARTICLE_CARD = 6
|
|
||||||
|
|
||||||
# min and max survey
|
|
||||||
MIN_ARTICLE_SURVEY = 5
|
|
||||||
MAX_ARTICLE_SURVEY = 10
|
|
||||||
|
|
||||||
# already register
|
|
||||||
Already_register_user = "duplicate key value violates unique constraint"
|
|
||||||
|
|
||||||
ARTICLE_CARD_IMAGE_FOLDER = 'article-card-images'
|
|
||||||
|
|
||||||
DATE_FORMAT = '%Y-%m-%d'
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
"""
|
|
||||||
This module contains constants used throughout the project
|
|
||||||
"""
|
|
||||||
from zod_bank.settings import BUCKET_NAME
|
|
||||||
|
|
||||||
# Define S3 folder url
|
|
||||||
S3_FOLDER_DIR = {
|
|
||||||
'user_image': 'user_image/',
|
|
||||||
}
|
|
||||||
|
|
||||||
# S3 bucket url
|
|
||||||
S3_URL = "https://"+BUCKET_NAME+".s3.amazonaws.com/"
|
|
||||||
|
|
||||||
S3_FOLDER_URL = {
|
|
||||||
'user_image_file': S3_URL+S3_FOLDER_DIR['user_image'],
|
|
||||||
}
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
"""
|
|
||||||
This module contains all the messages used all across the project
|
|
||||||
"""
|
|
||||||
|
|
||||||
ERROR_CODE_REQUIRED = {
|
|
||||||
# Error code for email address
|
|
||||||
"1000": ["Required email address not found."],
|
|
||||||
# Error code for password
|
|
||||||
"1001": ["Required password not found."],
|
|
||||||
# Error code for Required Post parameters
|
|
||||||
"1002": ["Required POST parameters not found."],
|
|
||||||
# Error code for Required Get parameters
|
|
||||||
"1003": ["Required GET parameters not found."],
|
|
||||||
# Error code for Required Headers
|
|
||||||
"1004": ["Required headers were not found."],
|
|
||||||
# Error code for Required Put parameters
|
|
||||||
"1005": ["Required PUT parameters not found."],
|
|
||||||
# Error code for Required query parameters
|
|
||||||
"1006": ["Required query parameters is not valid."],
|
|
||||||
# Error code for Required Head parameters
|
|
||||||
"1008": ["Required HEAD parameters not found."]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Error code
|
|
||||||
ERROR_CODE = {
|
|
||||||
"2000": "Invalid email address. Please enter a registered email.",
|
|
||||||
"2001": "This is your existing password. Please choose other one",
|
|
||||||
"2002": "Invalid username or password.",
|
|
||||||
"2003": "An account already exists with this email address.",
|
|
||||||
"2004": "User not found.",
|
|
||||||
"2005": "Your account has been activated.",
|
|
||||||
"2006": "Your account is not activated.",
|
|
||||||
"2007": "Your account already activated.",
|
|
||||||
"2008": "The OTP entered is not correct.",
|
|
||||||
"2009": "The user provided cannot be found or the reset password token has become invalid/timed out.",
|
|
||||||
"2010": "Invalid Link.",
|
|
||||||
"2011": "Your profile has not been completed yet.",
|
|
||||||
"2012": "Phone number already used",
|
|
||||||
"2013": "Invalid token.",
|
|
||||||
"2014": "Your old password doesn't match.",
|
|
||||||
"2015": "Invalid old password.",
|
|
||||||
"2016": "Invalid search.",
|
|
||||||
"2017": "{model} object with {pk} does not exist",
|
|
||||||
"2018": "Attached File not found",
|
|
||||||
"2019": "Invalid Referral code",
|
|
||||||
"2020": "Enter valid mobile number",
|
|
||||||
"2021": "Already register",
|
|
||||||
"2022": "Invalid Guardian code",
|
|
||||||
"2023": "Invalid user",
|
|
||||||
# email not verified
|
|
||||||
"2024": "Email not verified",
|
|
||||||
"2025": "Invalid input. Expected a list of strings.",
|
|
||||||
# check old and new password
|
|
||||||
"2026": "New password should not same as old password",
|
|
||||||
"2027": "data should contain `identityToken`",
|
|
||||||
"2028": "You are not authorized person to sign up on this platform",
|
|
||||||
"2029": "Validity of otp verification has expired. Please request a new one.",
|
|
||||||
"2030": "Use correct user type and token",
|
|
||||||
# invalid password
|
|
||||||
"2031": "Invalid password",
|
|
||||||
"2032": "Failed to send email",
|
|
||||||
"2033": "Missing required fields",
|
|
||||||
"2034": "Junior is not associated",
|
|
||||||
# image size
|
|
||||||
"2035": "Image should not be 0 kb",
|
|
||||||
"2036": "Choose valid user",
|
|
||||||
# log in multiple device msg
|
|
||||||
"2037": "You are already log in another device",
|
|
||||||
"2038": "Choose valid action for task",
|
|
||||||
# card length limit
|
|
||||||
"2039": "Add at least one article card or maximum 6",
|
|
||||||
"2040": "Add at least 5 article survey or maximum 10",
|
|
||||||
# add article msg
|
|
||||||
"2041": "Article with given id doesn't exist.",
|
|
||||||
"2042": "Article Card with given id doesn't exist.",
|
|
||||||
"2043": "Article Survey with given id doesn't exist.",
|
|
||||||
"2044": "Task does not exist",
|
|
||||||
"2045": "Invalid guardian",
|
|
||||||
# past due date
|
|
||||||
"2046": "Due date must be future date",
|
|
||||||
# invalid junior id msg
|
|
||||||
"2047": "Invalid Junior ID ",
|
|
||||||
"2048": "Choose right file for image",
|
|
||||||
# task request
|
|
||||||
"2049": "This task is already requested ",
|
|
||||||
"2059": "Already exist junior",
|
|
||||||
# task status
|
|
||||||
"2060": "Task does not exist or not in pending state",
|
|
||||||
"2061": "Please insert image or check the image is valid or not.",
|
|
||||||
# email not null
|
|
||||||
"2062": "Please enter email address",
|
|
||||||
"2063": "Unauthorized access.",
|
|
||||||
"2064": "To change your password first request an OTP and get it verify then change your password.",
|
|
||||||
"2065": "Passwords do not match. Please try again.",
|
|
||||||
"2066": "Task does not exist or not in expired state",
|
|
||||||
"2067": "Action not allowed. User type missing.",
|
|
||||||
"2068": "No guardian associated with this junior",
|
|
||||||
"2069": "Invalid user type",
|
|
||||||
"2070": "You did not find as a guardian",
|
|
||||||
"2071": "You did not find as a junior"
|
|
||||||
|
|
||||||
}
|
|
||||||
"""Success message code"""
|
|
||||||
SUCCESS_CODE = {
|
|
||||||
"3000": "ok",
|
|
||||||
# Success code for password
|
|
||||||
"3001": "Sign up successfully",
|
|
||||||
# Success code for Thank you
|
|
||||||
"3002": "Thank you for contacting us! Our Consumer Experience Team will reach out to you shortly.",
|
|
||||||
# Success code for account activation
|
|
||||||
"3003": "Log in successful",
|
|
||||||
# Success code for password reset
|
|
||||||
"3004": "Password reset link has been sent to your email address",
|
|
||||||
# Success code for link verified
|
|
||||||
"3005": "Your account is deleted successfully.",
|
|
||||||
# Success code for password reset
|
|
||||||
"3006": "Password reset successful. You can now log in with your new password.",
|
|
||||||
# Success code for password update
|
|
||||||
"3007": "Your password has been changed successfully.",
|
|
||||||
# Success code for valid link
|
|
||||||
"3008": "You have a valid link.",
|
|
||||||
# Success code for logged out
|
|
||||||
"3009": "You have successfully logged out!",
|
|
||||||
# Success code for check all fields
|
|
||||||
"3010": "All fields are valid",
|
|
||||||
"3011": "Email OTP Verified successfully",
|
|
||||||
"3012": "Phone OTP Verified successfully",
|
|
||||||
"3013": "Valid Guardian code",
|
|
||||||
"3014": "Password has been updated successfully.",
|
|
||||||
"3015": "Verification code has been sent on your email.",
|
|
||||||
"3016": "An OTP has been sent on your email.",
|
|
||||||
"3017": "Profile image update successfully",
|
|
||||||
"3018": "Task created successfully",
|
|
||||||
"3019": "Support Email sent successfully",
|
|
||||||
"3020": "Logged out successfully.",
|
|
||||||
"3021": "Add junior successfully",
|
|
||||||
"3022": "Remove junior successfully",
|
|
||||||
"3023": "Junior is approved successfully",
|
|
||||||
"3024": "Junior request is rejected successfully",
|
|
||||||
"3025": "Task is approved successfully",
|
|
||||||
"3026": "Task is rejected successfully",
|
|
||||||
"3027": "Article has been created successfully.",
|
|
||||||
"3028": "Article has been updated successfully.",
|
|
||||||
"3029": "Article has been deleted successfully.",
|
|
||||||
"3030": "Article Card has been removed successfully.",
|
|
||||||
"3031": "Article Survey has been removed successfully.",
|
|
||||||
"3032": "Task request sent successfully",
|
|
||||||
"3033": "Valid Referral code",
|
|
||||||
"3034": "Invite guardian successfully",
|
|
||||||
"3035": "Task started successfully",
|
|
||||||
"3036": "Task reassign successfully",
|
|
||||||
"3037": "Profile has been updated successfully.",
|
|
||||||
"3038": "Status has been changed successfully.",
|
|
||||||
# notification read
|
|
||||||
"3039": "Notification read successfully",
|
|
||||||
# start article
|
|
||||||
"3040": "Start article successfully",
|
|
||||||
# complete article
|
|
||||||
"3041": "Article completed successfully",
|
|
||||||
# submit assessment successfully
|
|
||||||
"3042": "Assessment completed successfully",
|
|
||||||
# read article
|
|
||||||
"3043": "Read article card successfully",
|
|
||||||
# remove guardian code request
|
|
||||||
"3044": "Remove guardian code request successfully",
|
|
||||||
|
|
||||||
}
|
|
||||||
"""status code error"""
|
|
||||||
STATUS_CODE_ERROR = {
|
|
||||||
# Status code for Invalid Input
|
|
||||||
"4001": ["Invalid input."],
|
|
||||||
# Status code for Authentication credentials
|
|
||||||
"4002": ["Authentication credentials were not provided."],
|
|
||||||
# Status code for Permission
|
|
||||||
"4003": ["You do not have permission to perform this action."],
|
|
||||||
# Status code for not found
|
|
||||||
"4004": ["Not found."],
|
|
||||||
# Status code for method not allowed
|
|
||||||
"4005": ["Method not allowed."]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
"""
|
|
||||||
Custom routers for job sourcing .
|
|
||||||
"""
|
|
||||||
# third party imports
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
|
|
||||||
|
|
||||||
class OptionalSlashRouter(DefaultRouter):
|
|
||||||
"""
|
|
||||||
optional slash router class
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
explicitly appending '/' in urls if '/' doesn't exists for making common url patterns .
|
|
||||||
"""
|
|
||||||
super(OptionalSlashRouter, self).__init__()
|
|
||||||
self.trailing_slash = '/?'
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
"""
|
|
||||||
web_admin tasks file
|
|
||||||
"""
|
|
||||||
# third party imports
|
|
||||||
from celery import shared_task
|
|
||||||
from templated_email import send_templated_mail
|
|
||||||
|
|
||||||
# django imports
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
|
||||||
def send_email_otp(email, verification_code):
|
|
||||||
"""
|
|
||||||
used to send otp on email
|
|
||||||
:param email: e-mail
|
|
||||||
:param verification_code: otp
|
|
||||||
"""
|
|
||||||
from_email = settings.EMAIL_FROM_ADDRESS
|
|
||||||
recipient_list = [email]
|
|
||||||
send_templated_mail(
|
|
||||||
template_name='email_reset_verification.email',
|
|
||||||
from_email=from_email,
|
|
||||||
recipient_list=recipient_list,
|
|
||||||
context={
|
|
||||||
'verification_code': verification_code
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
"""
|
|
||||||
This file used for file uploaded
|
|
||||||
"""
|
|
||||||
import datetime
|
|
||||||
# python imports
|
|
||||||
import logging
|
|
||||||
import mimetypes
|
|
||||||
import os
|
|
||||||
|
|
||||||
import boto3
|
|
||||||
from django.core.files.storage import FileSystemStorage
|
|
||||||
# django imports
|
|
||||||
from django.utils.crypto import get_random_string
|
|
||||||
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_200_OK
|
|
||||||
|
|
||||||
from base import constants
|
|
||||||
from base.constants import NUMBER
|
|
||||||
# local import
|
|
||||||
from zod_bank.settings import base_settings as settings
|
|
||||||
from zod_bank.settings.base_settings import BASE_DIR
|
|
||||||
|
|
||||||
|
|
||||||
def image_upload(folder, file_name, data):
|
|
||||||
"""
|
|
||||||
Function to upload files
|
|
||||||
:param folder:folder location string
|
|
||||||
:param file_name:file_name without ext string
|
|
||||||
:param data:data file obj
|
|
||||||
:return:Dictionary
|
|
||||||
"""
|
|
||||||
status = HTTP_400_BAD_REQUEST
|
|
||||||
img_name = None
|
|
||||||
error = None
|
|
||||||
try:
|
|
||||||
s3_client = boto3.client('s3',
|
|
||||||
aws_access_key_id=settings.AWS_ACCESS_KEY,
|
|
||||||
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
|
|
||||||
region_name=settings.AWS_DEFAULT_REGION
|
|
||||||
)
|
|
||||||
|
|
||||||
bucket_name = settings.BUCKET_NAME
|
|
||||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/tmp')
|
|
||||||
fss = FileSystemStorage()
|
|
||||||
file = fss.save('tmp/' + str(file_name), data)
|
|
||||||
fss.url(file)
|
|
||||||
tmp_file = os.path.join(MEDIA_ROOT, str(file_name))
|
|
||||||
s3_client.upload_file(
|
|
||||||
tmp_file, bucket_name, folder + str(file_name),
|
|
||||||
ExtraArgs={'ACL': 'public-read', 'ContentType': data.content_type}
|
|
||||||
)
|
|
||||||
os.unlink(tmp_file)
|
|
||||||
img_name = file_name
|
|
||||||
status = HTTP_200_OK
|
|
||||||
except Exception as e:
|
|
||||||
error = e
|
|
||||||
logging.error(e)
|
|
||||||
return status, error, img_name
|
|
||||||
|
|
||||||
|
|
||||||
def file_delete(folder, file_name):
|
|
||||||
"""
|
|
||||||
To delete common file
|
|
||||||
:param folder: folder name str
|
|
||||||
:param file_name: file_name string type
|
|
||||||
"""
|
|
||||||
status = HTTP_400_BAD_REQUEST
|
|
||||||
error = None
|
|
||||||
try:
|
|
||||||
s3_client = boto3.client('s3',
|
|
||||||
aws_access_key_id=settings.AWS_ACCESS_KEY,
|
|
||||||
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
|
|
||||||
region_name=settings.AWS_DEFAULT_REGION
|
|
||||||
)
|
|
||||||
|
|
||||||
s3_client.delete_object(Bucket=settings.BUCKET_NAME, Key=str(folder) + str(file_name))
|
|
||||||
status = HTTP_200_OK
|
|
||||||
except Exception as e:
|
|
||||||
error = e
|
|
||||||
return status, error
|
|
||||||
|
|
||||||
|
|
||||||
def get_aws_obj(folder, file_name):
|
|
||||||
"""
|
|
||||||
To get aws file obj
|
|
||||||
:param folder: folder string type
|
|
||||||
:param file_name: file_name string type
|
|
||||||
"""
|
|
||||||
status = HTTP_400_BAD_REQUEST
|
|
||||||
obj = None
|
|
||||||
try:
|
|
||||||
s3_client = boto3.client('s3',
|
|
||||||
aws_access_key_id=settings.AWS_ACCESS_KEY,
|
|
||||||
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
|
|
||||||
region_name=settings.AWS_DEFAULT_REGION
|
|
||||||
)
|
|
||||||
file_name = folder + file_name
|
|
||||||
obj = s3_client.get_object(Bucket=settings.BUCKET_NAME, Key=file_name)
|
|
||||||
status = HTTP_200_OK
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(e)
|
|
||||||
return status, obj
|
|
||||||
|
|
||||||
|
|
||||||
def upload_image(post_data, folder):
|
|
||||||
"""
|
|
||||||
:param post_data:
|
|
||||||
:param folder: string type
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
upload_obj = None
|
|
||||||
# Check Post data
|
|
||||||
if post_data:
|
|
||||||
date_now = datetime.datetime.now()
|
|
||||||
file_extension = os.path.splitext(str(post_data.name))
|
|
||||||
file_extension = file_extension[constants.NUMBER['one']].split(".")[constants.NUMBER['one']].lower()
|
|
||||||
rand = get_random_string(NUMBER['twelve'])
|
|
||||||
image_name = str(rand) + date_now.strftime("%s") + "." + file_extension
|
|
||||||
upload_obj = image_upload(folder, image_name, post_data)
|
|
||||||
return upload_obj
|
|
||||||
|
|
||||||
|
|
||||||
def upload_voice_kit_image(post_data, folder, image_dir):
|
|
||||||
"""
|
|
||||||
:param post_data:
|
|
||||||
:param folder: string type
|
|
||||||
:param image_dir: image_dir
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
upload_obj = None
|
|
||||||
# Check Post data
|
|
||||||
if post_data:
|
|
||||||
date_now = datetime.datetime.now()
|
|
||||||
file_extension = os.path.splitext(str(post_data))
|
|
||||||
file_extension = file_extension[constants.NUMBER['one']].split(".")[constants.NUMBER['one']].lower()
|
|
||||||
rand = get_random_string(NUMBER['twelve'])
|
|
||||||
image_name = str(rand) + date_now.strftime("%s") + "." + file_extension
|
|
||||||
upload_obj = voice_kit_image_upload(folder, image_name, post_data, image_dir)
|
|
||||||
return upload_obj
|
|
||||||
|
|
||||||
|
|
||||||
def voice_kit_image_upload(folder, file_name, data, image_dir):
|
|
||||||
"""
|
|
||||||
Function to upload files
|
|
||||||
:param folder:folder location string
|
|
||||||
:param file_name:file_name without ext string
|
|
||||||
:param data:data file obj
|
|
||||||
:return:Dictionary
|
|
||||||
"""
|
|
||||||
status = HTTP_400_BAD_REQUEST
|
|
||||||
img_name = None
|
|
||||||
error = None
|
|
||||||
try:
|
|
||||||
s3_client = boto3.client('s3',
|
|
||||||
aws_access_key_id=settings.AWS_ACCESS_KEY,
|
|
||||||
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
|
|
||||||
region_name=settings.AWS_DEFAULT_REGION
|
|
||||||
)
|
|
||||||
|
|
||||||
bucket_name = settings.BUCKET_NAME
|
|
||||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/tmp')
|
|
||||||
fss = FileSystemStorage()
|
|
||||||
with open(image_dir+data, 'rb') as f:
|
|
||||||
file = fss.save('tmp/' + str(file_name), f)
|
|
||||||
fss.url(file)
|
|
||||||
tmp_file = os.path.join(MEDIA_ROOT, str(file_name))
|
|
||||||
s3_client.upload_file(
|
|
||||||
tmp_file, bucket_name, folder + str(file_name),
|
|
||||||
ExtraArgs={'ACL': 'public-read', 'ContentType': mimetypes.guess_type(file_name)[0]}
|
|
||||||
)
|
|
||||||
os.unlink(tmp_file)
|
|
||||||
img_name = file_name
|
|
||||||
status = HTTP_200_OK
|
|
||||||
except Exception as e:
|
|
||||||
error = e
|
|
||||||
logging.error(e)
|
|
||||||
return status, error, img_name
|
|
||||||
|
|
||||||
Binary file not shown.
@@ -1,39 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
services:
|
|
||||||
nginx:
|
|
||||||
image: nginx:latest
|
|
||||||
container_name: nginx
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- "8000:8000"
|
|
||||||
volumes:
|
|
||||||
- ./nginx:/etc/nginx/conf.d
|
|
||||||
- .:/usr/src/app
|
|
||||||
depends_on:
|
|
||||||
- web
|
|
||||||
web:
|
|
||||||
build: .
|
|
||||||
container_name: django
|
|
||||||
restart: always
|
|
||||||
command: bash -c "pip install -r requirements.txt && python manage.py collectstatic --noinput && python manage.py migrate && gunicorn zod_bank.wsgi -b 0.0.0.0:8000 -t 300 --log-level=info"
|
|
||||||
volumes:
|
|
||||||
- .:/usr/src/app
|
|
||||||
|
|
||||||
broker:
|
|
||||||
image: rabbitmq:3.7
|
|
||||||
container_name: rabbitmq
|
|
||||||
volumes:
|
|
||||||
- .:/usr/src/app
|
|
||||||
ports:
|
|
||||||
- 5673:5673
|
|
||||||
|
|
||||||
worker:
|
|
||||||
build: .
|
|
||||||
image: celery
|
|
||||||
container_name: dev_celery
|
|
||||||
restart: "always"
|
|
||||||
command: bash -c " celery -A zod_bank.celery worker --concurrency=1 -B -l DEBUG -E"
|
|
||||||
volumes:
|
|
||||||
- .:/usr/src/app
|
|
||||||
depends_on:
|
|
||||||
- broker
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
"""Guardian admin"""
|
|
||||||
"""Third party Django app"""
|
|
||||||
from django.contrib import admin
|
|
||||||
"""Import Django app"""
|
|
||||||
from .models import Guardian, JuniorTask
|
|
||||||
# Register your models here.
|
|
||||||
@admin.register(Guardian)
|
|
||||||
class GuardianAdmin(admin.ModelAdmin):
|
|
||||||
"""Junior Admin"""
|
|
||||||
list_display = ['user', 'family_name']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return email id"""
|
|
||||||
return self.user__email
|
|
||||||
|
|
||||||
@admin.register(JuniorTask)
|
|
||||||
class TaskAdmin(admin.ModelAdmin):
|
|
||||||
"""Junior Admin"""
|
|
||||||
list_display = ['id', 'task_name', 'task_status', 'junior', 'due_date', 'points', 'created_at', 'updated_at']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return email id"""
|
|
||||||
return str(self.task_name) + str(self.points)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
"""Guardian app file"""
|
|
||||||
"""Third party Django app"""
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class CustodianConfig(AppConfig):
|
|
||||||
"""Guardian config"""
|
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
|
||||||
name = 'guardian'
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-23 12:05
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
import django.contrib.postgres.fields
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Guardian',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('country_code', models.IntegerField(blank=True, null=True)),
|
|
||||||
('phone', models.CharField(blank=True, default=None, max_length=31, null=True)),
|
|
||||||
('family_name', models.CharField(blank=True, default=None, max_length=50, null=True)),
|
|
||||||
('gender', models.CharField(blank=True, choices=[('1', 'Male'), ('2', 'Female')], default=None, max_length=15, null=True)),
|
|
||||||
('dob', models.DateField(blank=True, default=None, max_length=15, null=True)),
|
|
||||||
('guardian_code', models.CharField(blank=True, default=None, max_length=10, null=True)),
|
|
||||||
('junior_code', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, default=None, max_length=10, null=True), null=True, size=None)),
|
|
||||||
('referral_code', models.CharField(blank=True, default=None, max_length=10, null=True)),
|
|
||||||
('referral_code_used', models.CharField(blank=True, default=None, max_length=10, null=True)),
|
|
||||||
('is_active', models.BooleanField(default=True)),
|
|
||||||
('is_complete_profile', models.BooleanField(default=False)),
|
|
||||||
('passcode', models.IntegerField(blank=True, default=None, null=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='guardian_profile', to=settings.AUTH_USER_MODEL, verbose_name='Email')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Guardian',
|
|
||||||
'db_table': 'guardians',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-27 06:15
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='junior_code',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-27 13:59
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0002_remove_guardian_junior_code'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='country_name',
|
|
||||||
field=models.CharField(blank=True, default=None, max_length=30, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-28 06:52
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0003_guardian_country_name'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='image',
|
|
||||||
field=models.ImageField(blank=True, default=None, null=True, upload_to='images/'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-29 06:14
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0004_guardian_image'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='image',
|
|
||||||
field=models.ImageField(blank=True, default=None, null=True, upload_to=''),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-29 12:10
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0005_alter_guardian_image'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='is_verified',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-30 10:53
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0006_guardian_is_verified'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='country_name',
|
|
||||||
field=models.CharField(blank=True, default=None, max_length=100, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-04 09:24
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0006_alter_junior_country_name'),
|
|
||||||
('guardian', '0007_alter_guardian_country_name'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='JuniorTask',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('task_name', models.CharField(max_length=100)),
|
|
||||||
('task_description', models.CharField(max_length=500)),
|
|
||||||
('points', models.IntegerField(default=5)),
|
|
||||||
('due_date', models.DateField(blank=True, null=True)),
|
|
||||||
('image', models.ImageField(blank=True, default=None, null=True, upload_to='')),
|
|
||||||
('task_status', models.CharField(blank=True, choices=[('1', 'pending'), ('2', 'in-progress'), ('3', 'rejected'), ('4', 'requested'), ('5', 'completed')], default='pending', max_length=15, null=True)),
|
|
||||||
('is_active', models.BooleanField(default=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('guardian', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='guardian', to='guardian.guardian', verbose_name='Guardian')),
|
|
||||||
('junior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior', to='junior.junior', verbose_name='Junior')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Junior Task',
|
|
||||||
'db_table': 'junior_task',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-04 12:56
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0008_juniortask'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='image',
|
|
||||||
field=models.URLField(blank=True, default=None, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-04 13:41
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0009_alter_juniortask_image'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='task_status',
|
|
||||||
field=models.CharField(choices=[('1', 'pending'), ('2', 'in-progress'), ('3', 'rejected'), ('4', 'requested'), ('5', 'completed')], default='pending', max_length=15),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-05 11:17
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0010_alter_juniortask_task_status'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='default_image',
|
|
||||||
field=models.ImageField(blank=True, default=None, null=True, upload_to=''),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='is_approved',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='task_status',
|
|
||||||
field=models.CharField(choices=[('1', 'pending'), ('2', 'in-progress'), ('3', 'rejected'), ('4', 'requested'), ('5', 'completed')], default=1, max_length=15),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-06 05:12
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0011_juniortask_default_image_juniortask_is_approved_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='default_image',
|
|
||||||
field=models.URLField(blank=True, default=None, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-06 06:40
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0012_alter_juniortask_default_image'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='image',
|
|
||||||
field=models.URLField(blank=True, default=None, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-11 11:26
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0013_alter_guardian_image'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='signup_method',
|
|
||||||
field=models.CharField(choices=[('1', 'manual'), ('2', 'google'), ('3', 'apple')], default='1', max_length=31),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-14 09:34
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0014_guardian_signup_method'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='guardian',
|
|
||||||
options={'verbose_name': 'Guardian', 'verbose_name_plural': 'Guardian'},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='juniortask',
|
|
||||||
options={'verbose_name': 'Junior Task', 'verbose_name_plural': 'Junior Task'},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-18 07:17
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0015_alter_guardian_options_alter_juniortask_options'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='completed_on',
|
|
||||||
field=models.DateTimeField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='rejected_on',
|
|
||||||
field=models.DateTimeField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='requested_on',
|
|
||||||
field=models.DateTimeField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-24 13:21
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0016_juniortask_completed_on_juniortask_rejected_on_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='is_invited',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='is_password_set',
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-24 13:23
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0017_juniortask_is_invited_juniortask_is_password_set'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='is_invited',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='is_password_set',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-24 13:23
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0018_remove_juniortask_is_invited_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='is_invited',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='guardian',
|
|
||||||
name='is_password_set',
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-25 07:44
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0019_guardian_is_invited_guardian_is_password_set'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='juniortask',
|
|
||||||
name='task_status',
|
|
||||||
field=models.CharField(choices=[('1', 'pending'), ('2', 'in-progress'), ('3', 'rejected'), ('4', 'requested'), ('5', 'completed'), ('6', 'expired')], default=1, max_length=15),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
"""Guardian model file"""
|
|
||||||
"""Third party Django app"""
|
|
||||||
from django.db import models
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
"""Import Django app"""
|
|
||||||
from base.constants import GENDERS, TASK_STATUS, PENDING, TASK_POINTS, SIGNUP_METHODS
|
|
||||||
"""import Junior model"""
|
|
||||||
import junior.models
|
|
||||||
"""Add user model"""
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
# Define junior model with
|
|
||||||
# various fields like
|
|
||||||
# phone, country code,
|
|
||||||
# country name,
|
|
||||||
# gender,
|
|
||||||
# date of birth,
|
|
||||||
# profile image,
|
|
||||||
# signup method,
|
|
||||||
# guardian code,
|
|
||||||
# referral code,
|
|
||||||
# referral code that used by the guardian
|
|
||||||
# is invited guardian
|
|
||||||
# profile is active or not
|
|
||||||
# profile is complete or not
|
|
||||||
# passcode
|
|
||||||
# guardian is verified or not
|
|
||||||
"""Define junior task model"""
|
|
||||||
# define name of the Task
|
|
||||||
# task description
|
|
||||||
# points of the task
|
|
||||||
# default image of the task
|
|
||||||
# image uploaded by junior
|
|
||||||
# task status
|
|
||||||
# task approved or not
|
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
|
|
||||||
class Guardian(models.Model):
|
|
||||||
"""Guardian model"""
|
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='guardian_profile', verbose_name='Email')
|
|
||||||
"""Contact details"""
|
|
||||||
country_code = models.IntegerField(blank=True, null=True)
|
|
||||||
phone = models.CharField(max_length=31, null=True, blank=True, default=None)
|
|
||||||
"""country name of the guardian"""
|
|
||||||
country_name = models.CharField(max_length=100, null=True, blank=True, default=None)
|
|
||||||
"""Image info"""
|
|
||||||
image = models.URLField(null=True, blank=True, default=None)
|
|
||||||
"""Personal info"""
|
|
||||||
family_name = models.CharField(max_length=50, null=True, blank=True, default=None)
|
|
||||||
"""gender of the guardian"""
|
|
||||||
gender = models.CharField(choices=GENDERS, max_length=15, null=True, blank=True, default=None)
|
|
||||||
"""date of birth of the guardian"""
|
|
||||||
dob = models.DateField(max_length=15, null=True, blank=True, default=None)
|
|
||||||
# invited junior"""
|
|
||||||
is_invited = models.BooleanField(default=False)
|
|
||||||
# Profile activity"""
|
|
||||||
is_password_set = models.BooleanField(default=True)
|
|
||||||
"""Profile activity"""
|
|
||||||
is_active = models.BooleanField(default=True)
|
|
||||||
"""guardian is verified or not"""
|
|
||||||
is_verified = models.BooleanField(default=False)
|
|
||||||
"""guardian profile is complete or not"""
|
|
||||||
is_complete_profile = models.BooleanField(default=False)
|
|
||||||
"""passcode of the guardian profile"""
|
|
||||||
passcode = models.IntegerField(null=True, blank=True, default=None)
|
|
||||||
"""Sign up method"""
|
|
||||||
signup_method = models.CharField(max_length=31, choices=SIGNUP_METHODS, default='1')
|
|
||||||
"""Guardian Codes"""
|
|
||||||
guardian_code = models.CharField(max_length=10, null=True, blank=True, default=None)
|
|
||||||
"""Referral code"""
|
|
||||||
referral_code = models.CharField(max_length=10, null=True, blank=True, default=None)
|
|
||||||
"""Referral code that is used by guardian while signup"""
|
|
||||||
referral_code_used = models.CharField(max_length=10, null=True, blank=True, default=None)
|
|
||||||
"""Profile created and updated time"""
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
""" Meta class """
|
|
||||||
db_table = 'guardians'
|
|
||||||
"""verbose name of the model"""
|
|
||||||
verbose_name = 'Guardian'
|
|
||||||
"""change another name"""
|
|
||||||
verbose_name_plural = 'Guardian'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return email id"""
|
|
||||||
return f'{self.user}'
|
|
||||||
|
|
||||||
class JuniorTask(models.Model):
|
|
||||||
"""Junior Task details model"""
|
|
||||||
guardian = models.ForeignKey(Guardian, on_delete=models.CASCADE, related_name='guardian', verbose_name='Guardian')
|
|
||||||
"""task details"""
|
|
||||||
task_name = models.CharField(max_length=100)
|
|
||||||
"""task description"""
|
|
||||||
task_description = models.CharField(max_length=500)
|
|
||||||
"""points of the task"""
|
|
||||||
points = models.IntegerField(default=TASK_POINTS)
|
|
||||||
"""last date of the task"""
|
|
||||||
due_date = models.DateField(auto_now_add=False, null=True, blank=True)
|
|
||||||
"""Images of task that is upload by guardian"""
|
|
||||||
default_image = models.URLField(null=True, blank=True, default=None)
|
|
||||||
"""image that is uploaded by junior"""
|
|
||||||
image = models.URLField(null=True, blank=True, default=None)
|
|
||||||
"""associated junior with the task"""
|
|
||||||
junior = models.ForeignKey('junior.Junior', on_delete=models.CASCADE, related_name='junior', verbose_name='Junior')
|
|
||||||
"""task status"""
|
|
||||||
task_status = models.CharField(choices=TASK_STATUS, max_length=15, default=PENDING)
|
|
||||||
"""task is active or not"""
|
|
||||||
is_active = models.BooleanField(default=True)
|
|
||||||
"""Task is approved or not"""
|
|
||||||
is_approved = models.BooleanField(default=False)
|
|
||||||
"""request task on particular date"""
|
|
||||||
requested_on = models.DateTimeField(auto_now_add=False, null=True, blank=True)
|
|
||||||
"""reject task on particular date"""
|
|
||||||
rejected_on = models.DateTimeField(auto_now_add=False, null=True, blank=True)
|
|
||||||
"""complete task on particular date"""
|
|
||||||
completed_on = models.DateTimeField(auto_now_add=False, null=True, blank=True)
|
|
||||||
"""Profile created and updated time"""
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
""" Meta class """
|
|
||||||
db_table = 'junior_task'
|
|
||||||
"""verbose name of the model"""
|
|
||||||
verbose_name = 'Junior Task'
|
|
||||||
verbose_name_plural = 'Junior Task'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return email id"""
|
|
||||||
return f'{self.task_name}'
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,464 +0,0 @@
|
|||||||
"""Serializer of Guardian"""
|
|
||||||
# third party imports
|
|
||||||
import logging
|
|
||||||
from rest_framework import serializers
|
|
||||||
# Import Refresh token of jwt
|
|
||||||
from rest_framework_simplejwt.tokens import RefreshToken
|
|
||||||
from django.db import transaction
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from datetime import datetime, time
|
|
||||||
import pytz
|
|
||||||
from django.utils import timezone
|
|
||||||
# Import guardian's model,
|
|
||||||
# Import junior's model,
|
|
||||||
# Import account's model,
|
|
||||||
# Import constant from
|
|
||||||
# base package,
|
|
||||||
# Import messages from
|
|
||||||
# base package,
|
|
||||||
# Import some functions
|
|
||||||
# local imports
|
|
||||||
from .models import Guardian, JuniorTask
|
|
||||||
from account.models import UserProfile, UserEmailOtp, UserNotification
|
|
||||||
from account.utils import generate_code
|
|
||||||
from junior.serializers import JuniorDetailSerializer
|
|
||||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
|
||||||
from base.constants import NUMBER, JUN, ZOD, GRD, Already_register_user
|
|
||||||
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship
|
|
||||||
from .utils import real_time, convert_timedelta_into_datetime, update_referral_points
|
|
||||||
# notification's constant
|
|
||||||
from notifications.constants import TASK_POINTS, TASK_REJECTED
|
|
||||||
# send notification function
|
|
||||||
from notifications.utils import send_notification
|
|
||||||
|
|
||||||
|
|
||||||
# In this serializer file
|
|
||||||
# define user serializer,
|
|
||||||
# create guardian serializer,
|
|
||||||
# task serializer,
|
|
||||||
# guardian serializer,
|
|
||||||
# task details serializer,
|
|
||||||
# top junior serializer,
|
|
||||||
# guardian profile serializer,
|
|
||||||
# approve junior serializer,
|
|
||||||
# approve task serializer,
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
"""User serializer"""
|
|
||||||
auth_token = serializers.SerializerMethodField('get_auth_token')
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = User
|
|
||||||
fields = ['id', 'email', 'password', 'auth_token']
|
|
||||||
|
|
||||||
def get_auth_token(self, obj):
|
|
||||||
"""generate auth token"""
|
|
||||||
refresh = RefreshToken.for_user(obj)
|
|
||||||
access_token = str(refresh.access_token)
|
|
||||||
return access_token
|
|
||||||
def create(self, validated_data):
|
|
||||||
"""fetch data"""
|
|
||||||
email = validated_data.get('email')
|
|
||||||
user_type = self.context
|
|
||||||
password = validated_data.get('password')
|
|
||||||
try:
|
|
||||||
"""Create user profile"""
|
|
||||||
user = User.objects.create_user(username=email, email=email, password=password)
|
|
||||||
UserNotification.objects.get_or_create(user=user)
|
|
||||||
if user_type == str(NUMBER['one']):
|
|
||||||
# create junior profile
|
|
||||||
junior = Junior.objects.create(auth=user, junior_code=generate_code(JUN, user.id),
|
|
||||||
referral_code=generate_code(ZOD, user.id))
|
|
||||||
position = Junior.objects.all().count()
|
|
||||||
JuniorPoints.objects.create(junior=junior, position=position)
|
|
||||||
if user_type == str(NUMBER['two']):
|
|
||||||
# create guardian profile
|
|
||||||
Guardian.objects.create(user=user, guardian_code=generate_code(GRD, user.id),
|
|
||||||
referral_code=generate_code(ZOD, user.id))
|
|
||||||
return user
|
|
||||||
except Exception as e:
|
|
||||||
"""Error handling"""
|
|
||||||
logging.error(e)
|
|
||||||
otp = UserEmailOtp.objects.filter(email=email).last()
|
|
||||||
otp_verified = False
|
|
||||||
if otp and otp.is_verified:
|
|
||||||
otp_verified = True
|
|
||||||
raise serializers.ValidationError({"details": ERROR_CODE['2021'], "otp_verified":bool(otp_verified),
|
|
||||||
"code": 400, "status":"failed",
|
|
||||||
})
|
|
||||||
|
|
||||||
# update guardian profile
|
|
||||||
class CreateGuardianSerializer(serializers.ModelSerializer):
|
|
||||||
"""Create guardian serializer"""
|
|
||||||
"""Basic info"""
|
|
||||||
first_name = serializers.SerializerMethodField('get_first_name')
|
|
||||||
last_name = serializers.SerializerMethodField('get_last_name')
|
|
||||||
email = serializers.SerializerMethodField('get_email')
|
|
||||||
"""Contact details"""
|
|
||||||
phone = serializers.CharField(max_length=20, required=False)
|
|
||||||
country_code = serializers.IntegerField(required=False)
|
|
||||||
# basic info
|
|
||||||
family_name = serializers.CharField(max_length=100, required=False)
|
|
||||||
dob = serializers.DateField(required=False)
|
|
||||||
# code info
|
|
||||||
referral_code = serializers.CharField(max_length=100, required=False)
|
|
||||||
# image info
|
|
||||||
image = serializers.URLField(required=False)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = Guardian
|
|
||||||
fields = ['id', 'first_name', 'last_name', 'email', 'phone', 'family_name', 'gender', 'country_code',
|
|
||||||
'dob', 'referral_code', 'passcode', 'is_complete_profile', 'referral_code_used',
|
|
||||||
'country_name', 'image']
|
|
||||||
|
|
||||||
def get_first_name(self,obj):
|
|
||||||
"""first name of guardian"""
|
|
||||||
return obj.user.first_name
|
|
||||||
|
|
||||||
def get_last_name(self,obj):
|
|
||||||
"""last name of guardian"""
|
|
||||||
return obj.user.last_name
|
|
||||||
|
|
||||||
def get_email(self,obj):
|
|
||||||
"""emailof guardian"""
|
|
||||||
return obj.user.email
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
"""Create guardian profile"""
|
|
||||||
user = User.objects.filter(username=self.context['user']).last()
|
|
||||||
if user:
|
|
||||||
"""Save first and last name of guardian"""
|
|
||||||
if self.context.get('first_name') != '' and self.context.get('first_name') is not None:
|
|
||||||
user.first_name = self.context.get('first_name')
|
|
||||||
if self.context.get('last_name') != '' and self.context.get('last_name') is not None:
|
|
||||||
user.last_name = self.context.get('last_name')
|
|
||||||
user.save()
|
|
||||||
"""Create guardian data"""
|
|
||||||
guardian = Guardian.objects.filter(user=self.context['user']).last()
|
|
||||||
if guardian:
|
|
||||||
"""update details according to the data get from request"""
|
|
||||||
guardian.gender = validated_data.get('gender',guardian.gender)
|
|
||||||
guardian.family_name = validated_data.get('family_name', guardian.family_name)
|
|
||||||
guardian.dob = validated_data.get('dob',guardian.dob)
|
|
||||||
"""Update country code and phone number"""
|
|
||||||
guardian.phone = validated_data.get('phone', guardian.phone)
|
|
||||||
guardian.country_code = validated_data.get('country_code', guardian.country_code)
|
|
||||||
guardian.passcode = validated_data.get('passcode', guardian.passcode)
|
|
||||||
guardian.country_name = validated_data.get('country_name', guardian.country_name)
|
|
||||||
guardian.image = validated_data.get('image', guardian.image)
|
|
||||||
"""Complete profile of the junior if below all data are filled"""
|
|
||||||
complete_profile_field = all([guardian.gender, guardian.country_name,
|
|
||||||
guardian.dob, user.first_name,
|
|
||||||
guardian.image])
|
|
||||||
guardian.is_complete_profile = False
|
|
||||||
if complete_profile_field:
|
|
||||||
guardian.is_complete_profile = True
|
|
||||||
referral_code_used = validated_data.get('referral_code_used')
|
|
||||||
update_referral_points(guardian.referral_code, referral_code_used)
|
|
||||||
guardian.referral_code_used = validated_data.get('referral_code_used', guardian.referral_code_used)
|
|
||||||
guardian.save()
|
|
||||||
return guardian
|
|
||||||
|
|
||||||
def save(self, **kwargs):
|
|
||||||
"""Save the data into junior table"""
|
|
||||||
with transaction.atomic():
|
|
||||||
instance = super().save(**kwargs)
|
|
||||||
return instance
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TaskSerializer(serializers.ModelSerializer):
|
|
||||||
"""Task serializer"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = JuniorTask
|
|
||||||
fields = ['id', 'task_name','task_description','points', 'due_date', 'junior', 'default_image']
|
|
||||||
|
|
||||||
def validate_due_date(self, value):
|
|
||||||
"""validation on due date"""
|
|
||||||
if value < datetime.today().date():
|
|
||||||
raise serializers.ValidationError({"details": ERROR_CODE['2046'],
|
|
||||||
"code": 400, "status": "failed",
|
|
||||||
})
|
|
||||||
return value
|
|
||||||
def create(self, validated_data):
|
|
||||||
"""create default task image data"""
|
|
||||||
validated_data['guardian'] = Guardian.objects.filter(user=self.context['user']).last()
|
|
||||||
# update image of the task
|
|
||||||
images = self.context['image']
|
|
||||||
validated_data['default_image'] = images
|
|
||||||
instance = JuniorTask.objects.create(**validated_data)
|
|
||||||
return instance
|
|
||||||
|
|
||||||
class GuardianDetailSerializer(serializers.ModelSerializer):
|
|
||||||
"""junior serializer"""
|
|
||||||
|
|
||||||
email = serializers.SerializerMethodField('get_auth')
|
|
||||||
first_name = serializers.SerializerMethodField('get_first_name')
|
|
||||||
last_name = serializers.SerializerMethodField('get_last_name')
|
|
||||||
|
|
||||||
def get_auth(self, obj):
|
|
||||||
"""user email address"""
|
|
||||||
return obj.user.username
|
|
||||||
|
|
||||||
def get_first_name(self, obj):
|
|
||||||
"""user first name"""
|
|
||||||
return obj.user.first_name
|
|
||||||
|
|
||||||
def get_last_name(self, obj):
|
|
||||||
"""user last name"""
|
|
||||||
return obj.user.last_name
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = Guardian
|
|
||||||
fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob',
|
|
||||||
'guardian_code','is_active', 'is_complete_profile', 'created_at', 'image',
|
|
||||||
'updated_at']
|
|
||||||
class TaskDetailsSerializer(serializers.ModelSerializer):
|
|
||||||
"""Task detail serializer"""
|
|
||||||
|
|
||||||
junior = JuniorDetailSerializer()
|
|
||||||
remaining_time = serializers.SerializerMethodField('get_remaining_time')
|
|
||||||
is_expired = serializers.SerializerMethodField('get_is_expired')
|
|
||||||
|
|
||||||
def get_remaining_time(self, obj):
|
|
||||||
""" remaining time to complete task"""
|
|
||||||
due_date_datetime = datetime.combine(obj.due_date, datetime.max.time())
|
|
||||||
# fetch real time
|
|
||||||
# current_datetime = real_time()
|
|
||||||
# new code
|
|
||||||
due_date_datetime = due_date_datetime.astimezone(pytz.utc)
|
|
||||||
current_datetime = timezone.now().astimezone(pytz.utc)
|
|
||||||
# Perform the subtraction
|
|
||||||
if due_date_datetime > current_datetime:
|
|
||||||
time_difference = due_date_datetime - current_datetime
|
|
||||||
time_only = convert_timedelta_into_datetime(time_difference)
|
|
||||||
return str(time_difference.days) + ' days ' + str(time_only)
|
|
||||||
return str(NUMBER['zero']) + ' days ' + '00:00:00:00000'
|
|
||||||
|
|
||||||
def get_is_expired(self, obj):
|
|
||||||
""" task expired or not"""
|
|
||||||
if obj.due_date < datetime.today().date():
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = JuniorTask
|
|
||||||
fields = ['id', 'guardian', 'task_name', 'task_description', 'points', 'due_date','default_image', 'image',
|
|
||||||
'requested_on', 'rejected_on', 'completed_on', 'is_expired',
|
|
||||||
'junior', 'task_status', 'is_active', 'remaining_time', 'created_at','updated_at']
|
|
||||||
|
|
||||||
class TaskDetailsjuniorSerializer(serializers.ModelSerializer):
|
|
||||||
"""Task detail serializer"""
|
|
||||||
|
|
||||||
guardian = GuardianDetailSerializer()
|
|
||||||
remaining_time = serializers.SerializerMethodField('get_remaining_time')
|
|
||||||
|
|
||||||
def get_remaining_time(self, obj):
|
|
||||||
""" remaining time to complete task"""
|
|
||||||
due_date_datetime = datetime.combine(obj.due_date, datetime.max.time())
|
|
||||||
# fetch real time
|
|
||||||
# current_datetime = real_time()
|
|
||||||
# new code
|
|
||||||
due_date_datetime = due_date_datetime.astimezone(pytz.utc)
|
|
||||||
current_datetime = timezone.now().astimezone(pytz.utc)
|
|
||||||
# Perform the subtraction
|
|
||||||
if due_date_datetime > current_datetime:
|
|
||||||
time_difference = due_date_datetime - current_datetime
|
|
||||||
time_only = convert_timedelta_into_datetime(time_difference)
|
|
||||||
return str(time_difference.days) + ' days ' + str(time_only)
|
|
||||||
return str(NUMBER['zero']) + ' days ' + '00:00:00:00000'
|
|
||||||
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = JuniorTask
|
|
||||||
fields = ['id', 'guardian', 'task_name', 'task_description', 'points', 'due_date','default_image', 'image',
|
|
||||||
'requested_on', 'rejected_on', 'completed_on',
|
|
||||||
'junior', 'task_status', 'is_active', 'remaining_time', 'created_at','updated_at']
|
|
||||||
|
|
||||||
class TopJuniorSerializer(serializers.ModelSerializer):
|
|
||||||
"""Top junior serializer"""
|
|
||||||
junior = JuniorDetailSerializer()
|
|
||||||
position = serializers.IntegerField()
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = JuniorPoints
|
|
||||||
fields = ['id', 'junior', 'total_points', 'position', 'created_at', 'updated_at']
|
|
||||||
|
|
||||||
def to_representation(self, instance):
|
|
||||||
"""Convert instance to representation"""
|
|
||||||
representation = super().to_representation(instance)
|
|
||||||
representation['position'] = instance.position
|
|
||||||
return representation
|
|
||||||
|
|
||||||
|
|
||||||
class GuardianProfileSerializer(serializers.ModelSerializer):
|
|
||||||
"""junior serializer"""
|
|
||||||
|
|
||||||
email = serializers.SerializerMethodField('get_auth')
|
|
||||||
first_name = serializers.SerializerMethodField('get_first_name')
|
|
||||||
last_name = serializers.SerializerMethodField('get_last_name')
|
|
||||||
total_count = serializers.SerializerMethodField('get_total_count')
|
|
||||||
complete_field_count = serializers.SerializerMethodField('get_complete_field_count')
|
|
||||||
notification_count = serializers.SerializerMethodField('get_notification_count')
|
|
||||||
|
|
||||||
def get_auth(self, obj):
|
|
||||||
"""user email address"""
|
|
||||||
return obj.user.username
|
|
||||||
|
|
||||||
def get_first_name(self, obj):
|
|
||||||
"""user first name"""
|
|
||||||
return obj.user.first_name
|
|
||||||
|
|
||||||
def get_last_name(self, obj):
|
|
||||||
"""user last name"""
|
|
||||||
return obj.user.last_name
|
|
||||||
|
|
||||||
def get_total_count(self, obj):
|
|
||||||
"""total fields count"""
|
|
||||||
return NUMBER['five']
|
|
||||||
|
|
||||||
def get_complete_field_count(self, obj):
|
|
||||||
"""total filled fields count"""
|
|
||||||
total_field_list = [obj.user.first_name, obj.country_name,
|
|
||||||
obj.gender, obj.dob, obj.image]
|
|
||||||
# count total complete field
|
|
||||||
total_complete_field = [data for data in total_field_list if data != '' and data is not None]
|
|
||||||
return len(total_complete_field)
|
|
||||||
|
|
||||||
def get_notification_count(self, obj):
|
|
||||||
"""total notification count"""
|
|
||||||
return 0
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = Guardian
|
|
||||||
fields = ['id', 'email', 'first_name', 'last_name', 'country_name','country_code', 'phone', 'gender', 'dob',
|
|
||||||
'guardian_code', 'notification_count', 'total_count', 'complete_field_count', 'referral_code',
|
|
||||||
'is_active', 'is_complete_profile', 'created_at', 'image', 'signup_method',
|
|
||||||
'updated_at', 'passcode']
|
|
||||||
|
|
||||||
|
|
||||||
class ApproveJuniorSerializer(serializers.ModelSerializer):
|
|
||||||
"""approve junior serializer"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = Junior
|
|
||||||
fields = ['id', 'guardian_code']
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
"""update guardian code"""
|
|
||||||
instance = self.context['junior']
|
|
||||||
instance.guardian_code = [self.context['guardian_code']]
|
|
||||||
instance.guardian_code_approved = True
|
|
||||||
instance.guardian_code_status = str(NUMBER['two'])
|
|
||||||
instance.save()
|
|
||||||
return instance
|
|
||||||
|
|
||||||
|
|
||||||
class ApproveTaskSerializer(serializers.ModelSerializer):
|
|
||||||
"""approve task serializer"""
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = JuniorTask
|
|
||||||
fields = ['id', 'task_status', 'is_approved']
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
"""update task status """
|
|
||||||
with transaction.atomic():
|
|
||||||
instance = self.context['task_instance']
|
|
||||||
junior = self.context['junior']
|
|
||||||
junior_details = Junior.objects.filter(id=junior).last()
|
|
||||||
junior_data, created = JuniorPoints.objects.get_or_create(junior=junior_details)
|
|
||||||
if self.context['action'] == str(NUMBER['one']):
|
|
||||||
# approve the task
|
|
||||||
instance.task_status = str(NUMBER['five'])
|
|
||||||
instance.is_approved = True
|
|
||||||
# update total task point
|
|
||||||
junior_data.total_points = junior_data.total_points + instance.points
|
|
||||||
# update complete time of task
|
|
||||||
# instance.completed_on = real_time()
|
|
||||||
instance.completed_on = timezone.now().astimezone(pytz.utc)
|
|
||||||
send_notification.delay(TASK_POINTS, None, junior_details.auth.id, {})
|
|
||||||
else:
|
|
||||||
# reject the task
|
|
||||||
instance.task_status = str(NUMBER['three'])
|
|
||||||
instance.is_approved = False
|
|
||||||
# update reject time of task
|
|
||||||
# instance.rejected_on = real_time()
|
|
||||||
instance.rejected_on = timezone.now().astimezone(pytz.utc)
|
|
||||||
send_notification.delay(TASK_REJECTED, None, junior_details.auth.id, {})
|
|
||||||
instance.save()
|
|
||||||
junior_data.save()
|
|
||||||
return junior_details
|
|
||||||
|
|
||||||
class GuardianDetailListSerializer(serializers.ModelSerializer):
|
|
||||||
"""Guardian serializer"""
|
|
||||||
|
|
||||||
first_name = serializers.SerializerMethodField('get_first_name')
|
|
||||||
last_name = serializers.SerializerMethodField('get_last_name')
|
|
||||||
email = serializers.SerializerMethodField('get_email')
|
|
||||||
image = serializers.SerializerMethodField('get_image')
|
|
||||||
guardian_id = serializers.SerializerMethodField('get_guardian_id')
|
|
||||||
guardian_code = serializers.SerializerMethodField('get_guardian_code')
|
|
||||||
gender = serializers.SerializerMethodField('get_gender')
|
|
||||||
phone = serializers.SerializerMethodField('get_phone')
|
|
||||||
country_name = serializers.SerializerMethodField('get_country_name')
|
|
||||||
dob = serializers.SerializerMethodField('get_dob')
|
|
||||||
guardian_code_status = serializers.SerializerMethodField('get_guardian_code_status')
|
|
||||||
# code info
|
|
||||||
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
"""Meta info"""
|
|
||||||
model = JuniorGuardianRelationship
|
|
||||||
fields = ['guardian_id', 'first_name', 'last_name', 'email', 'relationship', 'image', 'dob',
|
|
||||||
'guardian_code', 'gender', 'phone', 'country_name', 'created_at', 'guardian_code_status',
|
|
||||||
'updated_at']
|
|
||||||
|
|
||||||
def get_guardian_id(self,obj):
|
|
||||||
"""first name of guardian"""
|
|
||||||
return obj.guardian.id
|
|
||||||
def get_first_name(self,obj):
|
|
||||||
"""first name of guardian"""
|
|
||||||
return obj.guardian.user.first_name
|
|
||||||
|
|
||||||
def get_last_name(self,obj):
|
|
||||||
"""last name of guardian"""
|
|
||||||
return obj.guardian.user.last_name
|
|
||||||
|
|
||||||
def get_email(self,obj):
|
|
||||||
"""email of guardian"""
|
|
||||||
return obj.guardian.user.email
|
|
||||||
|
|
||||||
def get_image(self,obj):
|
|
||||||
"""guardian image"""
|
|
||||||
return obj.guardian.image
|
|
||||||
|
|
||||||
def get_guardian_code(self,obj):
|
|
||||||
""" guardian code"""
|
|
||||||
return obj.guardian.guardian_code
|
|
||||||
|
|
||||||
def get_gender(self,obj):
|
|
||||||
""" guardian gender"""
|
|
||||||
return obj.guardian.gender
|
|
||||||
|
|
||||||
def get_phone(self,obj):
|
|
||||||
"""guardian phone"""
|
|
||||||
return obj.guardian.phone
|
|
||||||
|
|
||||||
def get_country_name(self,obj):
|
|
||||||
""" guardian country name """
|
|
||||||
return obj.guardian.country_name
|
|
||||||
|
|
||||||
def get_dob(self,obj):
|
|
||||||
"""guardian dob """
|
|
||||||
return obj.guardian.dob
|
|
||||||
|
|
||||||
def get_guardian_code_status(self,obj):
|
|
||||||
"""guardian code status"""
|
|
||||||
return obj.junior.guardian_code_status
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
"""task files"""
|
|
||||||
"""Django import"""
|
|
||||||
import secrets
|
|
||||||
def generate_otp():
|
|
||||||
"""generate random otp"""
|
|
||||||
digits = "0123456789"
|
|
||||||
return "".join(secrets.choice(digits) for _ in range(6))
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
"""Test file of Guardian"""
|
|
||||||
"""Third party Django app"""
|
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
""" Urls files"""
|
|
||||||
"""Django import"""
|
|
||||||
from django.urls import path, include
|
|
||||||
from .views import (SignupViewset, UpdateGuardianProfile, AllTaskListAPIView, CreateTaskAPIView, TaskListAPIView,
|
|
||||||
SearchTaskListAPIView, TopJuniorListAPIView, ApproveJuniorAPIView, ApproveTaskAPIView,
|
|
||||||
GuardianListAPIView)
|
|
||||||
"""Third party import"""
|
|
||||||
from rest_framework import routers
|
|
||||||
|
|
||||||
"""Define Router"""
|
|
||||||
router = routers.SimpleRouter()
|
|
||||||
|
|
||||||
# API End points with router
|
|
||||||
# in this file
|
|
||||||
# we define various api end point
|
|
||||||
# that is covered in this guardian
|
|
||||||
# section API:- like
|
|
||||||
# sign-up, create guardian profile,
|
|
||||||
# create-task,
|
|
||||||
# all task list, top junior,
|
|
||||||
# filter-task"""
|
|
||||||
"""Sign up API"""
|
|
||||||
router.register('sign-up', SignupViewset, basename='sign-up')
|
|
||||||
# Create guardian profile API"""
|
|
||||||
router.register('create-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile')
|
|
||||||
# Create Task API"""
|
|
||||||
router.register('create-task', CreateTaskAPIView, basename='create-task')
|
|
||||||
# All Task list API"""
|
|
||||||
router.register('all-task-list', AllTaskListAPIView, basename='all-task-list')
|
|
||||||
# Task list bases on the status API"""
|
|
||||||
router.register('task-list', TaskListAPIView, basename='task-list')
|
|
||||||
# Leaderboard API"""
|
|
||||||
router.register('top-junior', TopJuniorListAPIView, basename='top-junior')
|
|
||||||
# Search Task list on the bases of status, due date, and task title API"""
|
|
||||||
router.register('filter-task', SearchTaskListAPIView, basename='filter-task')
|
|
||||||
# Approve junior API"""
|
|
||||||
router.register('approve-junior', ApproveJuniorAPIView, basename='approve-junior')
|
|
||||||
# Approve junior API"""
|
|
||||||
router.register('approve-task', ApproveTaskAPIView, basename='approve-task')
|
|
||||||
# guardian list API"""
|
|
||||||
router.register('guardian-list', GuardianListAPIView, basename='guardian-list')
|
|
||||||
# Define Url pattern"""
|
|
||||||
urlpatterns = [
|
|
||||||
path('api/v1/', include(router.urls)),
|
|
||||||
]
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
"""Utiles file of guardian"""
|
|
||||||
"""Django import"""
|
|
||||||
import oss2
|
|
||||||
"""Import setting"""
|
|
||||||
from django.conf import settings
|
|
||||||
import logging
|
|
||||||
import requests
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
"""Import tempfile"""
|
|
||||||
import tempfile
|
|
||||||
# Import date time module's function
|
|
||||||
from datetime import datetime, time
|
|
||||||
# import Number constant
|
|
||||||
from base.constants import NUMBER
|
|
||||||
# Import Junior's model
|
|
||||||
from junior.models import Junior, JuniorPoints
|
|
||||||
# Import guardian's model
|
|
||||||
from .models import JuniorTask
|
|
||||||
# Import app from celery
|
|
||||||
from zod_bank.celery import app
|
|
||||||
# notification's constant
|
|
||||||
from notifications.constants import REFERRAL_POINTS
|
|
||||||
# send notification function
|
|
||||||
from notifications.utils import send_notification
|
|
||||||
# Define upload image on
|
|
||||||
# ali baba cloud
|
|
||||||
# firstly save image
|
|
||||||
# in temporary file
|
|
||||||
# then check bucket name
|
|
||||||
# then upload on ali baba
|
|
||||||
# bucket and reform the image url"""
|
|
||||||
# fetch real time data without depend on system time
|
|
||||||
# convert time delta into date time object
|
|
||||||
# update junior total points
|
|
||||||
# update referral points
|
|
||||||
# if any one use referral code of the junior
|
|
||||||
# junior earn 5 points
|
|
||||||
|
|
||||||
def upload_image_to_alibaba(image, filename):
|
|
||||||
"""upload image on oss alibaba bucket"""
|
|
||||||
# Save the image object to a temporary file
|
|
||||||
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
|
||||||
"""write image in temporary file"""
|
|
||||||
if type(image) == bytes:
|
|
||||||
temp_file.write(image)
|
|
||||||
else:
|
|
||||||
temp_file.write(image.read())
|
|
||||||
"""auth of bucket"""
|
|
||||||
auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET)
|
|
||||||
"""fetch bucket details"""
|
|
||||||
bucket = oss2.Bucket(auth, settings.ALIYUN_OSS_ENDPOINT, settings.ALIYUN_OSS_BUCKET_NAME)
|
|
||||||
# Upload the temporary file to Alibaba OSS
|
|
||||||
bucket.put_object_from_file(filename, temp_file.name)
|
|
||||||
"""create perfect url for image"""
|
|
||||||
new_filename = filename.replace(' ', '%20')
|
|
||||||
return f"https://{settings.ALIYUN_OSS_BUCKET_NAME}.{settings.ALIYUN_OSS_ENDPOINT}/{new_filename}"
|
|
||||||
|
|
||||||
|
|
||||||
def real_time():
|
|
||||||
"""fetch real time from world time api"""
|
|
||||||
url = time_url
|
|
||||||
response = requests.get(url)
|
|
||||||
if response.status_code == 200:
|
|
||||||
data = response.json()
|
|
||||||
time_str = data['datetime']
|
|
||||||
realtime = datetime.fromisoformat(time_str.replace('Z', '+00:00')).replace(tzinfo=None)
|
|
||||||
return realtime
|
|
||||||
else:
|
|
||||||
logging.error("Could not fetch error")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def convert_timedelta_into_datetime(time_difference):
|
|
||||||
"""convert date time"""
|
|
||||||
# convert timedelta into datetime format
|
|
||||||
hours = time_difference.seconds // NUMBER['thirty_six_hundred']
|
|
||||||
minutes = (time_difference.seconds // NUMBER['sixty']) % NUMBER['sixty']
|
|
||||||
seconds = time_difference.seconds % NUMBER['sixty']
|
|
||||||
microseconds = time_difference.microseconds
|
|
||||||
# Create a new time object with the extracted time components
|
|
||||||
time_only = time(hours, minutes, seconds, microseconds)
|
|
||||||
return time_only
|
|
||||||
|
|
||||||
def update_referral_points(referral_code, referral_code_used):
|
|
||||||
"""Update benefit of referral points"""
|
|
||||||
junior_queryset = Junior.objects.filter(referral_code=referral_code_used).last()
|
|
||||||
if junior_queryset and junior_queryset.referral_code != referral_code:
|
|
||||||
# create data if junior points is not exist
|
|
||||||
junior_query, created = JuniorPoints.objects.get_or_create(junior=junior_queryset)
|
|
||||||
if junior_query:
|
|
||||||
# update junior total points and referral points
|
|
||||||
junior_query.total_points = junior_query.total_points + NUMBER['five']
|
|
||||||
junior_query.referral_points = junior_query.referral_points + NUMBER['five']
|
|
||||||
junior_query.save()
|
|
||||||
send_notification.delay(REFERRAL_POINTS, None, junior_queryset.auth.id, {})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
|
||||||
def update_expired_task_status(data=None):
|
|
||||||
"""
|
|
||||||
Update task of the status if due date is in past
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
task_status = [str(NUMBER['one']), str(NUMBER['two']), str(NUMBER['four'])]
|
|
||||||
JuniorTask.objects.filter(due_date__lt=datetime.today().date(),
|
|
||||||
task_status__in=task_status).update(task_status=str(NUMBER['six']))
|
|
||||||
except ObjectDoesNotExist as e:
|
|
||||||
logging.error(str(e))
|
|
||||||
@@ -1,346 +0,0 @@
|
|||||||
"""Views of Guardian"""
|
|
||||||
|
|
||||||
# django imports
|
|
||||||
# Import IsAuthenticated
|
|
||||||
# Import viewsets and status
|
|
||||||
# Import PageNumberPagination
|
|
||||||
# Import User
|
|
||||||
# Import timezone
|
|
||||||
from rest_framework.permissions import IsAuthenticated
|
|
||||||
from rest_framework import viewsets, status
|
|
||||||
from rest_framework.pagination import PageNumberPagination
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
|
|
||||||
from rest_framework.filters import SearchFilter
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
# Import guardian's model,
|
|
||||||
# Import junior's model,
|
|
||||||
# Import account's model,
|
|
||||||
# Import constant from
|
|
||||||
# base package,
|
|
||||||
# Import messages from
|
|
||||||
# base package,
|
|
||||||
# Import some functions
|
|
||||||
# from utils file
|
|
||||||
# Import account's serializer
|
|
||||||
# Import account's task
|
|
||||||
# Import notification constant
|
|
||||||
# Import send_notification function
|
|
||||||
from .serializers import (UserSerializer, CreateGuardianSerializer, TaskSerializer, TaskDetailsSerializer,
|
|
||||||
TopJuniorSerializer, ApproveJuniorSerializer, ApproveTaskSerializer,
|
|
||||||
GuardianDetailListSerializer)
|
|
||||||
from .models import Guardian, JuniorTask
|
|
||||||
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship
|
|
||||||
from account.models import UserEmailOtp, UserNotification
|
|
||||||
from .tasks import generate_otp
|
|
||||||
from account.utils import custom_response, custom_error_response, OTP_EXPIRY, send_otp_email
|
|
||||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
|
||||||
from base.constants import NUMBER, GUARDIAN_CODE_STATUS
|
|
||||||
from .utils import upload_image_to_alibaba
|
|
||||||
from notifications.constants import REGISTRATION, TASK_CREATED, LEADERBOARD_RANKING
|
|
||||||
from notifications.utils import send_notification
|
|
||||||
|
|
||||||
""" Define APIs """
|
|
||||||
# Define Signup API,
|
|
||||||
# update guardian profile,
|
|
||||||
# list of all task
|
|
||||||
# list of task according to the status of the task
|
|
||||||
# create task API
|
|
||||||
# search task by name of the task API
|
|
||||||
# top junior API,
|
|
||||||
# approve junior API
|
|
||||||
# approve task API
|
|
||||||
# Create your views here.
|
|
||||||
# create approve task API
|
|
||||||
class SignupViewset(viewsets.ModelViewSet):
|
|
||||||
"""Signup view set"""
|
|
||||||
queryset = User.objects.all()
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
"""Create user profile"""
|
|
||||||
if request.data['user_type'] in [str(NUMBER['one']), str(NUMBER['two'])]:
|
|
||||||
serializer = UserSerializer(context=request.data['user_type'], data=request.data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
user = serializer.save()
|
|
||||||
"""Generate otp"""
|
|
||||||
otp = generate_otp()
|
|
||||||
# expire otp after 1 day
|
|
||||||
expiry = OTP_EXPIRY
|
|
||||||
# create user email otp object
|
|
||||||
UserEmailOtp.objects.create(email=request.data['email'], otp=otp,
|
|
||||||
user_type=str(request.data['user_type']), expired_at=expiry)
|
|
||||||
"""Send email to the register user"""
|
|
||||||
send_otp_email(request.data['email'], otp)
|
|
||||||
# send push notification for registration
|
|
||||||
send_notification.delay(REGISTRATION, None, user.id, {})
|
|
||||||
return custom_response(SUCCESS_CODE['3001'],
|
|
||||||
response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
else:
|
|
||||||
return custom_error_response(ERROR_CODE['2028'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class UpdateGuardianProfile(viewsets.ViewSet):
|
|
||||||
"""Update guardian profile"""
|
|
||||||
serializer_class = CreateGuardianSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
"""Create guardian profile"""
|
|
||||||
try:
|
|
||||||
data = request.data
|
|
||||||
image = request.data.get('image')
|
|
||||||
image_url = ''
|
|
||||||
if image:
|
|
||||||
if image and image.size == NUMBER['zero']:
|
|
||||||
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
filename = f"images/{image.name}"
|
|
||||||
# upload image on ali baba
|
|
||||||
image_url = upload_image_to_alibaba(image, filename)
|
|
||||||
data = {"image":image_url}
|
|
||||||
serializer = CreateGuardianSerializer(context={"user":request.user,
|
|
||||||
"first_name":request.data.get('first_name'),
|
|
||||||
"last_name": request.data.get('last_name'),
|
|
||||||
"image":image_url},
|
|
||||||
data=data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
"""save serializer"""
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
except Exception as e:
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class AllTaskListAPIView(viewsets.ModelViewSet):
|
|
||||||
"""Update guardian profile"""
|
|
||||||
serializer_class = TaskDetailsSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
"""Create guardian profile"""
|
|
||||||
queryset = JuniorTask.objects.filter(guardian__user=request.user)
|
|
||||||
# use TaskDetailsSerializer serializer
|
|
||||||
serializer = TaskDetailsSerializer(queryset, many=True)
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class TaskListAPIView(viewsets.ModelViewSet):
|
|
||||||
"""Update guardian profile"""
|
|
||||||
serializer_class = TaskDetailsSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
filter_backends = (SearchFilter,)
|
|
||||||
search_fields = ['task_name', ]
|
|
||||||
pagination_class = PageNumberPagination
|
|
||||||
http_method_names = ('get',)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = JuniorTask.objects.filter(guardian__user=self.request.user
|
|
||||||
).prefetch_related('junior', 'junior__auth'
|
|
||||||
).order_by('due_date', 'created_at')
|
|
||||||
|
|
||||||
queryset = self.filter_queryset(queryset)
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
"""Create guardian profile"""
|
|
||||||
status_value = self.request.GET.get('status')
|
|
||||||
queryset = self.get_queryset()
|
|
||||||
if status_value and status_value != '0':
|
|
||||||
queryset = queryset.filter(task_status=status_value)
|
|
||||||
paginator = self.pagination_class()
|
|
||||||
# use Pagination
|
|
||||||
paginated_queryset = paginator.paginate_queryset(queryset, request)
|
|
||||||
# use TaskDetailsSerializer serializer
|
|
||||||
serializer = self.serializer_class(paginated_queryset, many=True)
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class CreateTaskAPIView(viewsets.ModelViewSet):
|
|
||||||
"""create task for junior"""
|
|
||||||
serializer_class = TaskSerializer
|
|
||||||
queryset = JuniorTask.objects.all()
|
|
||||||
http_method_names = ('post', )
|
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
try:
|
|
||||||
image = request.data['default_image']
|
|
||||||
junior = request.data['junior']
|
|
||||||
allowed_extensions = ['.jpg', '.jpeg', '.png']
|
|
||||||
if not any(extension in str(image) for extension in allowed_extensions):
|
|
||||||
return custom_error_response(ERROR_CODE['2048'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
if not junior.isnumeric():
|
|
||||||
"""junior value must be integer"""
|
|
||||||
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
data = request.data
|
|
||||||
if 'https' in str(image):
|
|
||||||
image_data = image
|
|
||||||
else:
|
|
||||||
filename = f"images/{image}"
|
|
||||||
if image and image.size == NUMBER['zero']:
|
|
||||||
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
image_url = upload_image_to_alibaba(image, filename)
|
|
||||||
image_data = image_url
|
|
||||||
data.pop('default_image')
|
|
||||||
# use TaskSerializer serializer
|
|
||||||
serializer = TaskSerializer(context={"user":request.user, "image":image_data}, data=data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
# save serializer
|
|
||||||
serializer.save()
|
|
||||||
junior_id = Junior.objects.filter(id=junior).last()
|
|
||||||
send_notification.delay(TASK_CREATED, None, junior_id.auth.id, {})
|
|
||||||
return custom_response(SUCCESS_CODE['3018'], serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
except Exception as e:
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class SearchTaskListAPIView(viewsets.ModelViewSet):
|
|
||||||
"""Update guardian profile"""
|
|
||||||
serializer_class = TaskDetailsSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
pagination_class = PageNumberPagination
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
"""Get the queryset for the view"""
|
|
||||||
title = self.request.GET.get('title')
|
|
||||||
# fetch junior query
|
|
||||||
junior_queryset = JuniorTask.objects.filter(guardian__user=self.request.user, task_name__icontains=title)\
|
|
||||||
.order_by('due_date', 'created_at')
|
|
||||||
return junior_queryset
|
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
"""Create guardian profile"""
|
|
||||||
try:
|
|
||||||
queryset = self.get_queryset()
|
|
||||||
paginator = self.pagination_class()
|
|
||||||
# use pagination
|
|
||||||
paginated_queryset = paginator.paginate_queryset(queryset, request)
|
|
||||||
# use TaskSerializer serializer
|
|
||||||
serializer = TaskDetailsSerializer(paginated_queryset, many=True)
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
except Exception as e:
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class TopJuniorListAPIView(viewsets.ModelViewSet):
|
|
||||||
"""Top juniors list"""
|
|
||||||
queryset = JuniorPoints.objects.all()
|
|
||||||
serializer_class = TopJuniorSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
|
|
||||||
def get_serializer_context(self):
|
|
||||||
# context list
|
|
||||||
context = super().get_serializer_context()
|
|
||||||
context.update({'view': self})
|
|
||||||
return context
|
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
"""Fetch junior list of those who complete their tasks"""
|
|
||||||
try:
|
|
||||||
junior_total_points = self.get_queryset().order_by('-total_points')
|
|
||||||
# Update the position field for each JuniorPoints object
|
|
||||||
for index, junior in enumerate(junior_total_points):
|
|
||||||
junior.position = index + 1
|
|
||||||
send_notification.delay(LEADERBOARD_RANKING, None, junior.junior.auth.id, {})
|
|
||||||
junior.save()
|
|
||||||
serializer = self.get_serializer(junior_total_points[:NUMBER['fifteen']], many=True)
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
except Exception as e:
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class ApproveJuniorAPIView(viewsets.ViewSet):
|
|
||||||
"""approve junior by guardian"""
|
|
||||||
serializer_class = ApproveJuniorSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
"""Get the queryset for the view"""
|
|
||||||
guardian = Guardian.objects.filter(user__email=self.request.user).last()
|
|
||||||
# fetch junior query
|
|
||||||
junior_queryset = Junior.objects.filter(id=self.request.data.get('junior_id')).last()
|
|
||||||
return guardian, junior_queryset
|
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
""" junior list"""
|
|
||||||
try:
|
|
||||||
queryset = self.get_queryset()
|
|
||||||
# action 1 is use for approve and 2 for reject
|
|
||||||
if request.data['action'] == '1':
|
|
||||||
# use ApproveJuniorSerializer serializer
|
|
||||||
serializer = ApproveJuniorSerializer(context={"guardian_code": queryset[0].guardian_code,
|
|
||||||
"junior": queryset[1], "action": request.data['action']},
|
|
||||||
data=request.data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
# save serializer
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(SUCCESS_CODE['3023'], serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
else:
|
|
||||||
queryset[1].guardian_code = None
|
|
||||||
queryset[1].guardian_code_status = str(NUMBER['one'])
|
|
||||||
queryset[1].save()
|
|
||||||
return custom_response(SUCCESS_CODE['3024'], response_status=status.HTTP_200_OK)
|
|
||||||
except Exception as e:
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class ApproveTaskAPIView(viewsets.ViewSet):
|
|
||||||
"""approve junior by guardian"""
|
|
||||||
serializer_class = ApproveTaskSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
"""Get the queryset for the view"""
|
|
||||||
guardian = Guardian.objects.filter(user__email=self.request.user).last()
|
|
||||||
# task query
|
|
||||||
task_queryset = JuniorTask.objects.filter(id=self.request.data.get('task_id'),
|
|
||||||
guardian=guardian,
|
|
||||||
junior=self.request.data.get('junior_id')).last()
|
|
||||||
return guardian, task_queryset
|
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
""" junior list"""
|
|
||||||
# action 1 is use for approve and 2 for reject
|
|
||||||
try:
|
|
||||||
queryset = self.get_queryset()
|
|
||||||
# use ApproveJuniorSerializer serializer
|
|
||||||
serializer = ApproveTaskSerializer(context={"guardian_code": queryset[0].guardian_code,
|
|
||||||
"task_instance": queryset[1],
|
|
||||||
"action": str(request.data['action']),
|
|
||||||
"junior": self.request.data['junior_id']},
|
|
||||||
data=request.data)
|
|
||||||
unexpected_task_status = [str(NUMBER['five']), str(NUMBER['six'])]
|
|
||||||
if (str(request.data['action']) == str(NUMBER['one']) and serializer.is_valid()
|
|
||||||
and queryset[1] and queryset[1].task_status not in unexpected_task_status):
|
|
||||||
# save serializer
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(SUCCESS_CODE['3025'], response_status=status.HTTP_200_OK)
|
|
||||||
elif (str(request.data['action']) == str(NUMBER['two']) and serializer.is_valid()
|
|
||||||
and queryset[1] and queryset[1].task_status not in unexpected_task_status):
|
|
||||||
# save serializer
|
|
||||||
serializer.save()
|
|
||||||
return custom_response(SUCCESS_CODE['3026'], response_status=status.HTTP_200_OK)
|
|
||||||
else:
|
|
||||||
return custom_response(ERROR_CODE['2038'], response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
except Exception as e:
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
class GuardianListAPIView(viewsets.ModelViewSet):
|
|
||||||
"""Guardian list of assosicated junior"""
|
|
||||||
|
|
||||||
serializer_class = GuardianDetailListSerializer
|
|
||||||
permission_classes = [IsAuthenticated]
|
|
||||||
http_method_names = ('get',)
|
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
|
||||||
""" junior list"""
|
|
||||||
try:
|
|
||||||
guardian_data = JuniorGuardianRelationship.objects.filter(junior__auth__email=self.request.user)
|
|
||||||
# fetch junior object
|
|
||||||
if guardian_data:
|
|
||||||
# use GuardianDetailListSerializer serializer
|
|
||||||
serializer = GuardianDetailListSerializer(guardian_data, many=True)
|
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
|
||||||
return custom_response({"status": GUARDIAN_CODE_STATUS[1][0]}, response_status=status.HTTP_200_OK)
|
|
||||||
except Exception as e:
|
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import type { Config as JestConfig } from 'jest';
|
||||||
|
import { pathsToModuleNameMapper } from 'ts-jest';
|
||||||
|
import { compilerOptions as tsConfigCompilerOptions } from './tsconfig.json';
|
||||||
|
|
||||||
|
type ArrayElement<A> = A extends readonly (infer T)[] ? T : never;
|
||||||
|
type JestProjectConfig = Exclude<ArrayElement<JestConfig['projects']>, string>;
|
||||||
|
|
||||||
|
const baseJestConfig: JestConfig = {
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
const baseJestProjectConfig: JestProjectConfig = {
|
||||||
|
testEnvironment: 'node',
|
||||||
|
transform: {
|
||||||
|
'^.+\\.(t|j)s$': 'ts-jest',
|
||||||
|
},
|
||||||
|
moduleNameMapper: pathsToModuleNameMapper(tsConfigCompilerOptions.paths, { prefix: '<rootDir>' }),
|
||||||
|
globalSetup: '<rootDir>/test/global-setup.ts',
|
||||||
|
};
|
||||||
|
const projects: { name?: string; rootDir: string }[] = [{ rootDir: '.' }];
|
||||||
|
|
||||||
|
export function buildJestConfig(config?: {
|
||||||
|
jestConfigs?: JestConfig;
|
||||||
|
jestProjectConfigs?: JestProjectConfig;
|
||||||
|
}): JestConfig {
|
||||||
|
return {
|
||||||
|
...baseJestConfig,
|
||||||
|
...config?.jestConfigs,
|
||||||
|
projects: projects.map(({ name, rootDir }) => ({
|
||||||
|
...baseJestProjectConfig,
|
||||||
|
...config?.jestProjectConfigs,
|
||||||
|
...(name && { displayName: name }),
|
||||||
|
rootDir,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import type { Config } from 'jest';
|
||||||
|
import { buildJestConfig } from './jest.base.config';
|
||||||
|
|
||||||
|
const config: Config = buildJestConfig({
|
||||||
|
jestProjectConfigs: {
|
||||||
|
testRegex: '.*\\.spec\\.ts$',
|
||||||
|
coveragePathIgnorePatterns: ['__testing__', 'entities', '<rootDir>/src/db', 'index.ts'],
|
||||||
|
},
|
||||||
|
jestConfigs: {
|
||||||
|
coverageDirectory: 'coverage',
|
||||||
|
collectCoverageFrom: ['<rootDir>/src/**/*.(t|j)s'],
|
||||||
|
coverageReporters: ['clover', 'json', 'lcov', 'text', 'text-summary', 'cobertura'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default config;
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
"""Junior admin"""
|
|
||||||
"""Third party Django app"""
|
|
||||||
from django.contrib import admin
|
|
||||||
"""Import Django app"""
|
|
||||||
from .models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle,
|
|
||||||
JuniorArticleCard)
|
|
||||||
# Register your models here.
|
|
||||||
@admin.register(JuniorArticle)
|
|
||||||
class JuniorArticleAdmin(admin.ModelAdmin):
|
|
||||||
"""Junior Admin"""
|
|
||||||
list_display = ['junior', 'article', 'status', 'is_completed']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return email id"""
|
|
||||||
return self.junior__auth__email
|
|
||||||
|
|
||||||
@admin.register(JuniorArticleCard)
|
|
||||||
class JuniorArticleCardAdmin(admin.ModelAdmin):
|
|
||||||
"""Junior Admin"""
|
|
||||||
list_display = ['junior', 'article', 'article_card', 'is_read']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return email id"""
|
|
||||||
return self.junior__auth__email
|
|
||||||
@admin.register(Junior)
|
|
||||||
class JuniorAdmin(admin.ModelAdmin):
|
|
||||||
"""Junior Admin"""
|
|
||||||
list_display = ['auth', 'guardian_code']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return email id"""
|
|
||||||
return self.auth__email
|
|
||||||
|
|
||||||
@admin.register(JuniorPoints)
|
|
||||||
class JuniorPointsAdmin(admin.ModelAdmin):
|
|
||||||
"""Junior Points Admin"""
|
|
||||||
list_display = ['junior', 'total_points', 'position']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return email id"""
|
|
||||||
return self.junior.auth.email
|
|
||||||
|
|
||||||
@admin.register(JuniorGuardianRelationship)
|
|
||||||
class JuniorGuardianRelationshipAdmin(admin.ModelAdmin):
|
|
||||||
"""Junior Admin"""
|
|
||||||
list_display = ['guardian', 'junior', 'relationship']
|
|
||||||
|
|
||||||
@admin.register(JuniorArticlePoints)
|
|
||||||
class JuniorArticlePointsAdmin(admin.ModelAdmin):
|
|
||||||
"""Junior Admin"""
|
|
||||||
list_display = ['junior', 'article', 'question', 'submitted_answer', 'is_answer_correct']
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
"""App file"""
|
|
||||||
"""Import AppConfig"""
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
class JuniorConfig(AppConfig):
|
|
||||||
"""Junior config"""
|
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
|
||||||
name = 'junior'
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-23 12:05
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
import django.contrib.postgres.fields
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Junior',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('phone', models.CharField(blank=True, default=None, max_length=31, null=True)),
|
|
||||||
('country_code', models.IntegerField(blank=True, null=True)),
|
|
||||||
('gender', models.CharField(blank=True, choices=[('1', 'Male'), ('2', 'Female')], default=None, max_length=10, null=True)),
|
|
||||||
('dob', models.DateField(blank=True, default=None, max_length=15, null=True)),
|
|
||||||
('junior_code', models.CharField(blank=True, default=None, max_length=10, null=True)),
|
|
||||||
('guardian_code', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, default=None, max_length=10, null=True), null=True, size=None)),
|
|
||||||
('referral_code', models.CharField(blank=True, default=None, max_length=10, null=True)),
|
|
||||||
('referral_code_used', models.CharField(blank=True, default=None, max_length=10, null=True)),
|
|
||||||
('is_active', models.BooleanField(default=True)),
|
|
||||||
('is_complete_profile', models.BooleanField(default=False)),
|
|
||||||
('passcode', models.IntegerField(blank=True, default=None, null=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('auth', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_profile', to=settings.AUTH_USER_MODEL, verbose_name='Email')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Junior',
|
|
||||||
'db_table': 'junior',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-27 13:59
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='junior',
|
|
||||||
name='country_name',
|
|
||||||
field=models.CharField(blank=True, default=None, max_length=30, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-28 10:16
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0002_junior_country_name'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='junior',
|
|
||||||
name='image',
|
|
||||||
field=models.ImageField(blank=True, default=None, null=True, upload_to='images/'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-29 06:14
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0003_junior_image'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='junior',
|
|
||||||
name='image',
|
|
||||||
field=models.ImageField(blank=True, default=None, null=True, upload_to=''),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-29 12:10
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0004_alter_junior_image'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='junior',
|
|
||||||
name='is_verified',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-06-30 10:53
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0005_junior_is_verified'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='junior',
|
|
||||||
name='country_name',
|
|
||||||
field=models.CharField(blank=True, default=None, max_length=100, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-06 12:18
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0006_alter_junior_country_name'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='junior',
|
|
||||||
name='image',
|
|
||||||
field=models.URLField(blank=True, default=None, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-09 12:40
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0007_alter_junior_image'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='JuniorPoints',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('total_task_points', models.IntegerField(blank=True, default=0, null=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('junior', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='junior_points', to='junior.junior')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Junior Task Points',
|
|
||||||
'db_table': 'junior_task_points',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-10 07:36
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0008_juniorpoints'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='juniorpoints',
|
|
||||||
name='position',
|
|
||||||
field=models.IntegerField(blank=True, default=99999, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-11 11:26
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0009_juniorpoints_position'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='junior',
|
|
||||||
name='signup_method',
|
|
||||||
field=models.CharField(choices=[('1', 'manual'), ('2', 'google'), ('3', 'apple')], default='1', max_length=31),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-12 06:52
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0010_junior_signup_method'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='junior',
|
|
||||||
name='relationship',
|
|
||||||
field=models.CharField(blank=True, choices=[('1', 'parent'), ('2', 'legal_guardian')], default='1', max_length=31, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-12 10:51
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0011_junior_relationship'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='junior',
|
|
||||||
name='is_invited',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-14 09:34
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0012_junior_is_invited'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='junior',
|
|
||||||
options={'verbose_name': 'Junior', 'verbose_name_plural': 'Junior'},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='juniorpoints',
|
|
||||||
options={'verbose_name': 'Junior Task Points', 'verbose_name_plural': 'Junior Task Points'},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-18 09:28
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0013_alter_junior_options_alter_juniorpoints_options'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='junior',
|
|
||||||
name='is_password_set',
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-19 09:40
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0014_junior_is_password_set'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RenameField(
|
|
||||||
model_name='juniorpoints',
|
|
||||||
old_name='total_task_points',
|
|
||||||
new_name='total_points',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-19 11:00
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0015_rename_total_task_points_juniorpoints_total_points'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='juniorpoints',
|
|
||||||
name='referral_points',
|
|
||||||
field=models.IntegerField(blank=True, default=0, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-07-25 07:44
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('guardian', '0020_alter_juniortask_task_status'),
|
|
||||||
('junior', '0016_juniorpoints_referral_points'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='JuniorGuardianRelationship',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('relationship', models.CharField(blank=True, choices=[('1', 'parent'), ('2', 'legal_guardian')], default='1', max_length=31, null=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('guardian', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='guardian_relation', to='guardian.guardian', verbose_name='Guardian')),
|
|
||||||
('junior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_relation', to='junior.junior', verbose_name='Junior')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Junior Guardian Relation',
|
|
||||||
'verbose_name_plural': 'Junior Guardian Relation',
|
|
||||||
'db_table': 'junior_guardian_relation',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-08-02 11:27
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0017_juniorguardianrelationship'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='junior',
|
|
||||||
name='relationship',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='junior',
|
|
||||||
name='guardian_code_approved',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-08-07 13:29
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('web_admin', '0004_alter_surveyoption_survey'),
|
|
||||||
('junior', '0018_remove_junior_relationship_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='JuniorArticlePoints',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('earn_points', models.IntegerField(blank=True, default=5, null=True)),
|
|
||||||
('is_attempt', models.BooleanField(default=False)),
|
|
||||||
('is_answer_correct', models.BooleanField(default=False)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_articles', to='web_admin.article')),
|
|
||||||
('junior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_details', to='junior.junior', verbose_name='Junior')),
|
|
||||||
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='questions', to='web_admin.articlesurvey')),
|
|
||||||
('submitted_answer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submitted_answer', to='web_admin.surveyoption')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-08-08 05:43
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('junior', '0019_juniorarticlepoints'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='junior',
|
|
||||||
name='guardian_code_status',
|
|
||||||
field=models.CharField(blank=True, choices=[('1', 'no guardian code'), ('2', 'exist guardian code'), ('3', 'request for guardian code')], default='1', max_length=31, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-08-08 09:45
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('web_admin', '0004_alter_surveyoption_survey'),
|
|
||||||
('junior', '0020_junior_guardian_code_status'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='juniorarticlepoints',
|
|
||||||
name='submitted_answer',
|
|
||||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='submitted_answer', to='web_admin.surveyoption'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-08-09 09:34
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('web_admin', '0004_alter_surveyoption_survey'),
|
|
||||||
('junior', '0021_alter_juniorarticlepoints_submitted_answer'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='JuniorArticle',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('is_completed', models.BooleanField(default=False)),
|
|
||||||
('status', models.CharField(blank=True, choices=[('1', 'read'), ('2', 'in_progress'), ('3', 'completed')], default='1', max_length=10, null=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_articles_details', to='web_admin.article')),
|
|
||||||
('junior', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_article', to='junior.junior', verbose_name='Junior')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2023-08-09 10:47
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('web_admin', '0004_alter_surveyoption_survey'),
|
|
||||||
('junior', '0022_juniorarticle'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='JuniorArticleCard',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('is_read', models.BooleanField(default=False)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_articles_detail', to='web_admin.article')),
|
|
||||||
('article_card', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_article_card', to='web_admin.articlecard')),
|
|
||||||
('junior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_article_card', to='junior.junior', verbose_name='Junior')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user