init
This commit is contained in:
commit
85c76a2bc6
13 changed files with 591 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
.idea
|
||||
.env
|
||||
media
|
||||
/clients/
|
||||
10
Dockerfile
Normal file
10
Dockerfile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
FROM debian:12
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
WORKDIR /app
|
||||
#RUN date
|
||||
RUN apt update
|
||||
RUN apt install gnupg2 netcat-traditional libssl-dev libcrypto++-dev lsb-release python3-pip -y
|
||||
RUN apt install binutils libproj-dev gdal-bin -y
|
||||
COPY requirements.txt /app/requirements.txt
|
||||
RUN pip3 install --break-system-packages -r requirements.txt
|
||||
#ENTRYPOINT ["./run.sh"]
|
||||
22
manage.py
Executable file
22
manage.py
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'main.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
19
requirements.in
Normal file
19
requirements.in
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Django
|
||||
python-decouple
|
||||
psycopg[binary,pool]
|
||||
django-jalali-date
|
||||
django-crispy-forms
|
||||
crispy_bootstrap5
|
||||
djangorestframework
|
||||
django-filter
|
||||
django-cors-headers
|
||||
gunicorn
|
||||
gevent
|
||||
drf-spectacular
|
||||
pillow
|
||||
requests
|
||||
django-oauth-toolkit
|
||||
redis
|
||||
celery
|
||||
httpx
|
||||
django-redis
|
||||
184
requirements.txt
Normal file
184
requirements.txt
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
#
|
||||
# This file is autogenerated by pip-compile with Python 3.11
|
||||
# by the following command:
|
||||
#
|
||||
# pip-compile
|
||||
#
|
||||
amqp==5.3.1
|
||||
# via kombu
|
||||
anyio==4.8.0
|
||||
# via httpx
|
||||
asgiref==3.8.1
|
||||
# via
|
||||
# django
|
||||
# django-cors-headers
|
||||
async-timeout==5.0.1
|
||||
# via redis
|
||||
attrs==24.3.0
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
billiard==4.2.1
|
||||
# via celery
|
||||
celery==5.4.0
|
||||
# via -r requirements.in
|
||||
certifi==2024.12.14
|
||||
# via
|
||||
# httpcore
|
||||
# httpx
|
||||
# requests
|
||||
cffi==1.17.1
|
||||
# via cryptography
|
||||
charset-normalizer==3.4.0
|
||||
# via requests
|
||||
click==8.1.7
|
||||
# via
|
||||
# celery
|
||||
# click-didyoumean
|
||||
# click-plugins
|
||||
# click-repl
|
||||
click-didyoumean==0.3.1
|
||||
# via celery
|
||||
click-plugins==1.1.1
|
||||
# via celery
|
||||
click-repl==0.3.0
|
||||
# via celery
|
||||
crispy-bootstrap5==2024.10
|
||||
# via -r requirements.in
|
||||
cryptography==44.0.0
|
||||
# via jwcrypto
|
||||
django==5.1.4
|
||||
# via
|
||||
# -r requirements.in
|
||||
# crispy-bootstrap5
|
||||
# django-cors-headers
|
||||
# django-crispy-forms
|
||||
# django-filter
|
||||
# django-jalali-date
|
||||
# django-oauth-toolkit
|
||||
# django-redis
|
||||
# djangorestframework
|
||||
# drf-spectacular
|
||||
django-cors-headers==4.6.0
|
||||
# via -r requirements.in
|
||||
django-crispy-forms==2.3
|
||||
# via
|
||||
# -r requirements.in
|
||||
# crispy-bootstrap5
|
||||
django-filter==24.3
|
||||
# via -r requirements.in
|
||||
django-jalali-date==1.1.3
|
||||
# via -r requirements.in
|
||||
django-oauth-toolkit==3.0.1
|
||||
# via -r requirements.in
|
||||
django-redis==5.4.0
|
||||
# via -r requirements.in
|
||||
djangorestframework==3.15.2
|
||||
# via
|
||||
# -r requirements.in
|
||||
# drf-spectacular
|
||||
drf-spectacular==0.28.0
|
||||
# via -r requirements.in
|
||||
gevent==24.11.1
|
||||
# via -r requirements.in
|
||||
greenlet==3.1.1
|
||||
# via gevent
|
||||
gunicorn==23.0.0
|
||||
# via -r requirements.in
|
||||
h11==0.14.0
|
||||
# via httpcore
|
||||
httpcore==1.0.7
|
||||
# via httpx
|
||||
httpx==0.28.1
|
||||
# via -r requirements.in
|
||||
idna==3.10
|
||||
# via
|
||||
# anyio
|
||||
# httpx
|
||||
# requests
|
||||
inflection==0.5.1
|
||||
# via drf-spectacular
|
||||
jalali-core==1.0.0
|
||||
# via jdatetime
|
||||
jdatetime==5.0.0
|
||||
# via django-jalali-date
|
||||
jsonschema==4.23.0
|
||||
# via drf-spectacular
|
||||
jsonschema-specifications==2024.10.1
|
||||
# via jsonschema
|
||||
jwcrypto==1.5.6
|
||||
# via django-oauth-toolkit
|
||||
kombu==5.4.2
|
||||
# via celery
|
||||
oauthlib==3.2.2
|
||||
# via django-oauth-toolkit
|
||||
packaging==24.2
|
||||
# via gunicorn
|
||||
pillow==11.0.0
|
||||
# via -r requirements.in
|
||||
prompt-toolkit==3.0.48
|
||||
# via click-repl
|
||||
psycopg[binary,pool]==3.2.3
|
||||
# via -r requirements.in
|
||||
psycopg-binary==3.2.3
|
||||
# via psycopg
|
||||
psycopg-pool==3.2.4
|
||||
# via psycopg
|
||||
pycparser==2.22
|
||||
# via cffi
|
||||
python-dateutil==2.9.0.post0
|
||||
# via celery
|
||||
python-decouple==3.8
|
||||
# via -r requirements.in
|
||||
pyyaml==6.0.2
|
||||
# via drf-spectacular
|
||||
redis==5.2.1
|
||||
# via
|
||||
# -r requirements.in
|
||||
# django-redis
|
||||
referencing==0.35.1
|
||||
# via
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
requests==2.32.3
|
||||
# via
|
||||
# -r requirements.in
|
||||
# django-oauth-toolkit
|
||||
rpds-py==0.22.3
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
six==1.17.0
|
||||
# via python-dateutil
|
||||
sniffio==1.3.1
|
||||
# via anyio
|
||||
sqlparse==0.5.3
|
||||
# via django
|
||||
typing-extensions==4.12.2
|
||||
# via
|
||||
# anyio
|
||||
# jwcrypto
|
||||
# psycopg
|
||||
# psycopg-pool
|
||||
tzdata==2024.2
|
||||
# via
|
||||
# celery
|
||||
# kombu
|
||||
uritemplate==4.1.1
|
||||
# via drf-spectacular
|
||||
urllib3==2.2.3
|
||||
# via requests
|
||||
vine==5.1.0
|
||||
# via
|
||||
# amqp
|
||||
# celery
|
||||
# kombu
|
||||
wcwidth==0.2.13
|
||||
# via prompt-toolkit
|
||||
zope-event==5.0
|
||||
# via gevent
|
||||
zope-interface==7.2
|
||||
# via gevent
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
# setuptools
|
||||
8
run.sh
Executable file
8
run.sh
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
while ! nc -z $DB_HOST 5432 ; do
|
||||
echo "APP Waiting for the DB Server"
|
||||
sleep 3
|
||||
done
|
||||
#python3 manage.py collectstatic --noinput
|
||||
python3 manage.py migrate
|
||||
gunicorn main.wsgi:application --bind 0.0.0.0:8000 -w 4
|
||||
125
templates/base.html
Normal file
125
templates/base.html
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
{% load static %}
|
||||
{#{% load view_breadcrumbs %}#}
|
||||
|
||||
|
||||
<!doctype html>
|
||||
<html lang="fa-ir" dir="rtl">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<title>{% block title %}welcome{% endblock %}</title>
|
||||
<link rel="manifest" href="{% static 'manifest.json' %}">
|
||||
|
||||
<link href="{% static 'bootstrap-5.3.0-dist/css/bootstrap.rtl.min.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'bootstrap-icons-1.11.3/font/bootstrap-icons.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'fonts/vazirmatn-v33.003/misc/UI-Farsi-Digits/Vazirmatn-UI-FD-font-face.css' %}"
|
||||
rel="stylesheet">
|
||||
<link href="{% static 'fonts/Pelak/fonts.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'main.css' %}" rel="stylesheet">
|
||||
<script src="{% static 'jquery-3.6.0.min.js' %}"></script>
|
||||
|
||||
{# <link rel="stylesheet"#}
|
||||
{# href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css"/>#}
|
||||
<!-- Or for RTL support -->
|
||||
<link rel="stylesheet"
|
||||
href="{% static 'select2-bootstrap-5-theme-1.3.0/select2-bootstrap-5-theme.rtl.min.css' %}"/>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="{% static 'jalalidatepicker/jalalidatepicker.css' %}">
|
||||
<script src="{% static 'jalalidatepicker/jalalidatepicker.js' %}"></script>
|
||||
<style>
|
||||
@media (min-width: 576px) {
|
||||
.h-sm-100 {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="row vh-100 overflow-auto">
|
||||
{# {% include "include/sidebar.html" %}#}
|
||||
<div class="col d-flex flex-column h-sm-100">
|
||||
<div class="m-0 p-0 w-100 " style="background-color: green; height: 3px;"></div>
|
||||
<main class="row overflow-auto pb-3">
|
||||
<div class="col pt-2">
|
||||
{% include "include/top_bar.html" %}
|
||||
{% include "include/messages.html" %}
|
||||
{# {% block breadcrumbs %}#}
|
||||
{# {% render_breadcrumbs %}#}
|
||||
{# {% endblock %}#}
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="grid">
|
||||
<div class="d-flex justify-content-start">
|
||||
<h4 class="m-3">
|
||||
{% block page_title %}
|
||||
{% endblock %}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="grid">
|
||||
<div class="d-flex justify-content-end mt-2">
|
||||
{% block page_action %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card bg-light">
|
||||
<div class="card-body">
|
||||
<div class="col-md-12 col-lg-12">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{# {% include 'include/footer.html' %}#}
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="row bg-light py-3 mt-auto small">
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1">
|
||||
کلیه حقوق متعلق به
|
||||
<a class="text-decoration-none" href="/">بیلبورد</a>
|
||||
است.
|
||||
</div>
|
||||
{# <div class="">#}
|
||||
{# توسعه#}
|
||||
{# <a href="https://gooyal.com" class="text-decoration-none" target="_blank"#}
|
||||
{# rel="noopener noreferrer">#}
|
||||
{# گویال#}
|
||||
{# <img src="{% static 'image/gooyal_logo_gray.png' %}" width="28" height="21">#}
|
||||
{# </a>#}
|
||||
{# </div>#}
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
jalaliDatepicker.startWatch();
|
||||
</script>
|
||||
|
||||
<script src="{% static 'bootstrap-5.3.0-dist/js/bootstrap.bundle.min.js' %}"></script>
|
||||
<script src="{% static 'jquery.formset.js' %}"></script>
|
||||
</html>
|
||||
12
templates/core/home.html
Normal file
12
templates/core/home.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load jalali_tags %}
|
||||
|
||||
{% block title %}IPG: Home{% endblock %}
|
||||
{% block page_title %}IPG: Home{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
IPG
|
||||
{% endblock %}
|
||||
33
templates/include/filter_action.html
Normal file
33
templates/include/filter_action.html
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{% load crispy_forms_tags %}
|
||||
|
||||
<button type="button" class="btn btn-primary me-2" data-bs-toggle="modal" data-bs-target="#filterModal">
|
||||
|
||||
<span class="bi bi-funnel-fill"></span>
|
||||
|
||||
</button>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="filterModal" tabindex="-1" aria-labelledby="exampleModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<form method="get">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">محدود کردن نتایج</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||
aria-label="بستن"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
{{ filter.form | crispy }}
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{# <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>#}
|
||||
<input type="submit" class="btn btn-primary" value="اعمال">
|
||||
{# <button type="button" class="btn btn-primary"></button>#}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
9
templates/include/messages.html
Normal file
9
templates/include/messages.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
{# <li{% if message.tags %} class="{{ message.tags }}"{% endif %}></li>#}
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<span> {{ message }} </span>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
21
templates/include/paginator.html
Normal file
21
templates/include/paginator.html
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{% load tags %}
|
||||
|
||||
<nav class="d-flex justify-content-center" aria-label="Page navigation example">
|
||||
<ul class="pagination">
|
||||
{% if is_paginated %}
|
||||
{% get_proper_elided_page_range paginator page_obj.number as page_range %}
|
||||
{% for i in page_range %}
|
||||
{% if page_obj.number == i %}
|
||||
<li class="page-item"><span class="page-link"><strong>( {{ i }} )</strong></span></li>
|
||||
{% elif i == '…' %}
|
||||
<li class="page-item"><span class="page-link">{{ i }}</span></li>
|
||||
{% else %}
|
||||
<li class="page-item"><a class="page-link" href="?{% get_filter_link request 'page' i %}">{{ i }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
<p class="p-2 mb-0"><span class="fw-bolder text-decoration-underline">{{ paginator.count }}</span> داده یافت شد.
|
||||
</p>
|
||||
|
||||
</nav>
|
||||
21
templates/include/top_bar.html
Normal file
21
templates/include/top_bar.html
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{% load static %}
|
||||
|
||||
|
||||
<div class="card bg-light title">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col d-flex justify-content-start">
|
||||
<div class="bi p-1"><img src="{% static 'image/logo.png' %}" width="21" height="auto"></div>
|
||||
{# <img class="bi bi-speedometer p-1"></img>#}
|
||||
<div class="p-1"><a class="text-decoration-none" href="/">dashboard</a></div>
|
||||
</div>
|
||||
|
||||
<div class="col d-flex justify-content-end">
|
||||
<div class="bi p-1"><img src="{% static 'image/logo.png' %}" width="21" height="auto"></div>
|
||||
{# <img class="bi bi-speedometer p-1"></img>#}
|
||||
<div class="p-1"><a class="text-decoration-none" href="#">dashboard</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
123
utils/wallet_client.py
Normal file
123
utils/wallet_client.py
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
import time
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.db import models
|
||||
from httpx import Request
|
||||
|
||||
from gooyal_wallet_client import AuthenticatedClient
|
||||
from gooyal_wallet_client.models import MyWallet, UserTransaction, ApplicationDeposit, ApplicationWithdraw
|
||||
from gooyal_wallet_client.api.wallet import (wallet_api_application_deposit_create,
|
||||
wallet_api_application_deposit_verify_retrieve,
|
||||
wallet_api_application_withdraw_create,
|
||||
wallet_api_application_withdraw_verify_retrieve)
|
||||
from gooyal_wallet_client.types import Response
|
||||
|
||||
|
||||
class ContentTypeChoices(models.IntegerChoices):
|
||||
IMAGE = 1, 'image'
|
||||
VOICE = 2, 'voice'
|
||||
VIDEO = 3, 'video'
|
||||
|
||||
|
||||
def login_as_client_credentials():
|
||||
access_token = cache.get('ads_access_token')
|
||||
# expires_in = self.auth_data.get('expires_in')
|
||||
# created_at = self.auth_data.get('created_at')
|
||||
#
|
||||
# if access_token and expires_in > time.time() - created_at:
|
||||
# return self.auth_data
|
||||
if access_token:
|
||||
print('already in cache')
|
||||
return access_token
|
||||
|
||||
print('not in cache')
|
||||
|
||||
data = {
|
||||
"grant_type": 'client_credentials',
|
||||
"scope": settings.SCOPES,
|
||||
}
|
||||
auth = (settings.CLIENT_ID, settings.CLIENT_SECRET)
|
||||
|
||||
response = requests.post(f'{settings.BASE_OAUTH2_PROVIDER_PUBLIC_URL}/token/',
|
||||
data=data,
|
||||
auth=auth)
|
||||
print(response.content)
|
||||
|
||||
auth_data = response.json()
|
||||
if 'access_token' in auth_data:
|
||||
auth_data['created_at'] = time.time()
|
||||
cache.set('ads_access_token', auth_data, timeout=auth_data.get('expires_in') - 5)
|
||||
|
||||
return auth_data
|
||||
|
||||
|
||||
def log_request(request: Request):
|
||||
print(request.headers['authorization'])
|
||||
print(
|
||||
f"Request event hook: {request.method} {request.url} {request.method} {request.headers} - Waiting for response")
|
||||
|
||||
|
||||
def log_response(response):
|
||||
request = response.request
|
||||
print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}")
|
||||
|
||||
|
||||
def get_client():
|
||||
access_token = login_as_client_credentials()['access_token']
|
||||
client = AuthenticatedClient(base_url="https://wallet.gooyal.com", token=access_token,
|
||||
httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}},
|
||||
)
|
||||
return client
|
||||
|
||||
|
||||
def deposit_to_user_wallet_submit(data):
|
||||
class Tmp():
|
||||
def to_dict(self):
|
||||
return data
|
||||
|
||||
deposit_data = Tmp()
|
||||
client = get_client()
|
||||
response: ApplicationDeposit = wallet_api_application_deposit_create.sync(client=client, body=deposit_data)
|
||||
print(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def deposit_to_user_wallet_verify(uuid):
|
||||
client = get_client()
|
||||
response: ApplicationDeposit = wallet_api_application_deposit_verify_retrieve.sync(uuid=uuid, client=client)
|
||||
print(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def withdraw_from_user_wallet_submit(data):
|
||||
class Tmp():
|
||||
def to_dict(self):
|
||||
return data
|
||||
|
||||
withdraw_data = Tmp()
|
||||
client = get_client()
|
||||
response: ApplicationWithdraw = wallet_api_application_withdraw_create.sync(client=client, body=withdraw_data)
|
||||
print(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def withdraw_from_user_wallet_verify(uuid):
|
||||
client = get_client()
|
||||
response: ApplicationWithdraw = wallet_api_application_withdraw_verify_retrieve.sync(uuid=uuid, client=client)
|
||||
print(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
sample_data = {
|
||||
"uuid": "3fa85f64-5717-4562-b3fc-2c963f66afb1",
|
||||
"payee_id": "5d66d02e-6087-4b0a-bb0c-291d5c11755a",
|
||||
"payee_type": 1,
|
||||
"amount": 2000,
|
||||
"details": "string",
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue