1 Commits

Author SHA1 Message Date
gitea a0955be848 Initial commit 2025-06-25 15:40:43 +03:00
847 changed files with 164 additions and 103215 deletions
-33
View File
@@ -1,33 +0,0 @@
# Git
.git
.gitignore
# Docker
.dockerignore
docker-compose.yml
docker-compose.dev.yml
docker-compose-deploy.yml
docker-compose with volume.yml
dockerfile
*.tar
# Python
.venv
__pycache__
*.pyc
# Database
db.sqlite3
*.bak
# IDE
.idea
# Environment files
.env
production.env
# Other
gemini.cmd - Shortcut.lnk
images/
-41
View File
@@ -1,41 +0,0 @@
DB_USER="postgres"
DB_PASSWORD="admin"
DB_HOST="localhost"
DB_PORT=5432
DB_NAME="depot"
TEST_DB_NAME="depot_test"
SECRET_KEY='7b112605-9074-4195-98e9-7add8d57942d'
CONFIG_ENV='config.DevelopmentConfig'
JWT_EXPIRATION_DELTA=2
EPAY_SECURITY_KEY='VX6FIDVFI5MSP39UYMDWI47DX37T7H8ZT8AAC4UYS1IGCT9YFMJWJ98AH4YHJ3VY'
EPAY_CLIENT_ID='D056898459'
INVOICE_EXPIRE_PERIOD=3
OWNCLOUD_URL='https://cloud.kikimor.com'
OWNCLOUD_USER='kikimor'
OWNCLOUD_PASSWORD='ShuShunka1!'
OWNCLOUD_DAMAGES_FOLDER='damages/'
EMAIL_HOST="smtp.gmail.com"
EMAIL_PORT=587
EMAIL_HOST_USER="kikimor.eood@gmail.com"
EMAIL_HOST_PASSWORD="mjra fwsq iyaq yzai"
EMAIL_USE_TLS=True
ADMIN_USER_EMAIL="kikimor@gmail.com"
ADMIN_USER_NAME="kikimor"
ADMIN_USER_PASSWORD="shushunka1"
POSTGRES_USER=$DB_USER
POSTGRES_PASSWORD=$DB_PASSWORD
POSTGRES_DB=$DB_NAME
MINIO_ENDPOINT="localhost:9000"
MINIO_ACCESS_KEY="kikimor"
MINIO_SECRET_KEY="shushunka1"
MINIO_BUCKET_NAME="damages"
AWS_S3_CUSTOM_DOMAIN='localhost:9000' # For browser acce
AWS_S3_URL_PROTOCOL='http'
MINIO_SERVER_URL="http://localhost:9000"
+162
View File
@@ -0,0 +1,162 @@
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
-30
View File
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="FacetManager">
<facet type="django" name="Django">
<configuration>
<option name="rootFolder" value="$MODULE_DIR$" />
<option name="settingsModule" value="DepoT/settings.py" />
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
<option name="environment" value="&lt;map/&gt;" />
<option name="doNotUseTestRunner" value="false" />
<option name="trackFilePattern" value="migrations" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/../DepoT\templates" />
</list>
</option>
</component>
</module>
-20
View File
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="dataSourceStorageLocal" created-in="PY-242.23339.19">
<data-source name="depot@localhost" uuid="2186be09-0cb1-4210-bad0-d279af5e6702">
<database-info product="PostgreSQL" version="17.4" jdbc-version="4.2" driver-name="PostgreSQL JDBC Driver" driver-version="42.7.3" dbms="POSTGRES" exact-version="17.4" exact-driver-version="42.7">
<identifier-quote-string>&quot;</identifier-quote-string>
</database-info>
<case-sensitivity plain-identifiers="lower" quoted-identifiers="exact" />
<secret-storage>master_key</secret-storage>
<user-name>postgres</user-name>
<schema-mapping>
<introspection-scope>
<node kind="database" qname="@">
<node kind="schema" qname="@" />
</node>
</introspection-scope>
</schema-mapping>
</data-source>
</component>
</project>
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="depot@localhost" uuid="2186be09-0cb1-4210-bad0-d279af5e6702">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://localhost:5432/depot</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>
File diff suppressed because it is too large Load Diff
@@ -1,2 +0,0 @@
#n:information_schema
!<md> [null, 0, null, null, -2147483648, -2147483648]
@@ -1,2 +0,0 @@
#n:pg_catalog
!<md> [null, 0, null, null, -2147483648, -2147483648]
@@ -1,2 +0,0 @@
#n:public
!<md> [1114, 0, null, null, -2147483648, -2147483648]
-12
View File
@@ -1,12 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredIdentifiers">
<list>
<option value="object.*" />
</list>
</option>
</inspection_tool>
</profile>
</component>
-6
View File
@@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.13 (DepoT)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (depot_django)" project-jdk-type="Python SDK" />
</project>
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/DepoT.iml" filepath="$PROJECT_DIR$/.idea/DepoT.iml" />
</modules>
</component>
</project>
Generated
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
-450
View File
@@ -1,450 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="7410a44d-51b9-408b-85ad-4fa46776b372" name="Changes" comment="commit unversioned files ;)">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/booking/models.py" beforeDir="false" afterPath="$PROJECT_DIR$/booking/models.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/booking/tests.py" beforeDir="false" afterPath="$PROJECT_DIR$/booking/tests.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/booking/views/client_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/booking/views/client_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/containers/tests.py" beforeDir="false" afterPath="$PROJECT_DIR$/containers/tests.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/readme.md" beforeDir="false" afterPath="$PROJECT_DIR$/readme.md" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ChangesViewManager" show_ignored="true" />
<component name="DjangoConsoleOptions" custom-start-script="import sys; print('Python %s on %s' % (sys.version, sys.platform))&#10;import django; print('Django %s' % django.get_version())&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;if 'setup' in dir(django): django.setup()&#10;import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)">
<option name="myCustomStartScript" value="import sys; print('Python %s on %s' % (sys.version, sys.platform))&#10;import django; print('Django %s' % django.get_version())&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;if 'setup' in dir(django): django.setup()&#10;import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="CSS File" />
<option value="JavaScript File" />
<option value="HTML File" />
<option value="Python Script" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 6
}</component>
<component name="ProjectId" id="2yxmkOyUBM7hzsgEZWENDFkS6jw" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"ASKED_MARK_IGNORED_FILES_AS_EXCLUDED": "true",
"DefaultHtmlFileTemplate": "HTML File",
"Django Server.DepoT.executor": "Run",
"Django tests.Test: booking.tests.BookingViewsTestCase.executor": "Run",
"Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_list_view.executor": "Debug",
"Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_all_rights__expect_OK.executor": "Profiler",
"Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_no_rights__expect_forbidden.executor": "Debug",
"Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_update_view.executor": "Debug",
"Django tests.Test: preinfo.test_views.PreinfoViewsTest.executor": "Run",
"RunOnceActivity.OpenDjangoStructureViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"RunOnceActivity.pycharm.django.structure.promotion.once.per.project": "true",
"django.template.preview.state": "SHOW_EDITOR",
"git-widget-placeholder": "deploy__branch",
"ignore.virus.scanning.warn.message": "true",
"last_opened_file_path": "C:/dev_projects/python/django/depot_django/containers",
"list.type.of.created.stylesheet": "CSS",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"settings.editor.selected.configurable": "preferences.editor",
"vue.rearranger.settings.migration": "true"
},
"keyToStringList": {
"DatabaseDriversLRU": [
"postgresql"
]
}
}]]></component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="C:\dev_projects\python\django\depot_django\containers" />
<recent name="C:\dev_projects\python\Django\DepoT\DepoT\settings" />
<recent name="C:\dev_projects\python\Django\DepoT" />
<recent name="C:\dev_projects\python\Django\DepoT\minio_backend" />
<recent name="C:\dev_projects\python\Django\DepoT\templates\employee" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="C:\dev_projects\python\Django\DepoT\images" />
<recent name="C:\dev_projects\python\Django\DepoT\unused templates" />
<recent name="C:\dev_projects\python\Django\DepoT\DepoT" />
<recent name="C:\dev_projects\python\Django\DepoT" />
<recent name="C:\dev_projects\python\Django\DepoT\templates\employee" />
</key>
</component>
<component name="RunManager" selected="Django tests.Test: preinfo.test_views.PreinfoViewsTest">
<configuration name="Test: booking.tests.BookingViewsTestCase" type="DjangoTestsConfigurationType" temporary="true">
<module name="DepoT" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="DepoT.settings.development" />
</envs>
<option name="SDK_HOME" value="$PROJECT_DIR$/.venv/Scripts/python.exe" />
<option name="SDK_NAME" value="Python 3.13 (depot_django)" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="TARGET" value="booking.tests.BookingViewsTestCase" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method v="2" />
</configuration>
<configuration name="Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_all_rights__expect_OK" type="DjangoTestsConfigurationType" temporary="true">
<module name="DepoT" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="TARGET" value="booking.tests.BookingViewsTestCase.test_booking_list_view__user_all_rights__expect_OK" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method v="2" />
</configuration>
<configuration name="Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_no_rights__expect_forbidden" type="DjangoTestsConfigurationType" temporary="true">
<module name="DepoT" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="DepoT.settings.development" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="TARGET" value="booking.tests.BookingViewsTestCase.test_booking_list_view__user_no_rights__expect_forbidden" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method v="2" />
</configuration>
<configuration name="Test: booking.tests.BookingViewsTestCase.test_booking_update_view" type="DjangoTestsConfigurationType" temporary="true">
<module name="DepoT" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="DepoT.settings.development" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="TARGET" value="booking.tests.BookingViewsTestCase.test_booking_update_view" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method v="2" />
</configuration>
<configuration name="Test: preinfo.test_views.PreinfoViewsTest" type="DjangoTestsConfigurationType" temporary="true">
<module name="DepoT" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="DepoT.settings.development" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="TARGET" value="preinfo.test_views.PreinfoViewsTest" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method v="2" />
</configuration>
<configuration name="DepoT" type="Python.DjangoServer" factoryName="Django server">
<module name="DepoT" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="DepoT.settings.development" />
</envs>
<option name="SDK_HOME" value="" />
<option name="SDK_NAME" value="Python 3.13 (depot_django)" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="launchJavascriptDebuger" value="false" />
<option name="port" value="8000" />
<option name="host" value="" />
<option name="additionalOptions" value="" />
<option name="browserUrl" value="" />
<option name="runTestServer" value="false" />
<option name="runNoReload" value="false" />
<option name="useCustomRunCommand" value="false" />
<option name="customRunCommand" value="" />
<method v="2" />
</configuration>
<list>
<item itemvalue="Django Server.DepoT" />
<item itemvalue="Django tests.Test: preinfo.test_views.PreinfoViewsTest" />
<item itemvalue="Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_update_view" />
<item itemvalue="Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_all_rights__expect_OK" />
<item itemvalue="Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_no_rights__expect_forbidden" />
<item itemvalue="Django tests.Test: booking.tests.BookingViewsTestCase" />
</list>
<recent_temporary>
<list>
<item itemvalue="Django tests.Test: preinfo.test_views.PreinfoViewsTest" />
<item itemvalue="Django tests.Test: booking.tests.BookingViewsTestCase" />
<item itemvalue="Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_update_view" />
<item itemvalue="Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_all_rights__expect_OK" />
<item itemvalue="Django tests.Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_no_rights__expect_forbidden" />
</list>
</recent_temporary>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-js-predefined-d6986cc7102b-5c90d61e3bab-JavaScript-PY-242.23339.19" />
<option value="bundled-python-sdk-0029f7779945-399fe30bd8c1-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-242.23339.19" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="7410a44d-51b9-408b-85ad-4fa46776b372" name="Changes" comment="" />
<created>1750784740296</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1750784740296</updated>
<workItem from="1750784741367" duration="240087000" />
<workItem from="1752078951079" duration="106000" />
<workItem from="1752079161329" duration="189445000" />
<workItem from="1753174764499" duration="271000" />
<workItem from="1753175068058" duration="4635000" />
<workItem from="1753179863298" duration="8357000" />
<workItem from="1753197869497" duration="98156000" />
<workItem from="1753637487803" duration="71422000" />
<workItem from="1754046655407" duration="19056000" />
<workItem from="1754068089083" duration="32822000" />
<workItem from="1754408990802" duration="13021000" />
</task>
<task id="LOCAL-00001" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1750855057151</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1750855057151</updated>
</task>
<task id="LOCAL-00002" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1750855273832</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1750855273832</updated>
</task>
<task id="LOCAL-00003" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1750942491703</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1750942491703</updated>
</task>
<task id="LOCAL-00004" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1750942543055</created>
<option name="number" value="00004" />
<option name="presentableId" value="LOCAL-00004" />
<option name="project" value="LOCAL" />
<updated>1750942543055</updated>
</task>
<task id="LOCAL-00005" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1750942560128</created>
<option name="number" value="00005" />
<option name="presentableId" value="LOCAL-00005" />
<option name="project" value="LOCAL" />
<updated>1750942560128</updated>
</task>
<task id="LOCAL-00006" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1751295996186</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1751295996186</updated>
</task>
<task id="LOCAL-00007" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1751359397230</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1751359397230</updated>
</task>
<task id="LOCAL-00008" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1751443902965</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1751443902965</updated>
</task>
<task id="LOCAL-00009" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1751557411675</created>
<option name="number" value="00009" />
<option name="presentableId" value="LOCAL-00009" />
<option name="project" value="LOCAL" />
<updated>1751557411675</updated>
</task>
<task id="LOCAL-00010" summary="commit unversioned files ;)">
<option name="closed" value="true" />
<created>1751618076902</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1751618076902</updated>
</task>
<task id="LOCAL-00011" summary="commit unversioned files ;)">
<option name="closed" value="true" />
<created>1751877829547</created>
<option name="number" value="00011" />
<option name="presentableId" value="LOCAL-00011" />
<option name="project" value="LOCAL" />
<updated>1751877829547</updated>
</task>
<option name="localTasksCounter" value="12" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA." />
<MESSAGE value="commit unversioned files ;)" />
<option name="LAST_COMMIT_MESSAGE" value="commit unversioned files ;)" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/DepoT/mixins/crudListViewMixin.py</url>
<line>7</line>
<option name="timeStamp" value="55" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/preinfo/test_views.py</url>
<line>50</line>
<option name="timeStamp" value="130" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/preinfo/test_views.py</url>
<line>94</line>
<option name="timeStamp" value="138" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/preinfo/test_views.py</url>
<line>101</line>
<option name="timeStamp" value="139" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/preinfo/test_views.py</url>
<line>107</line>
<option name="timeStamp" value="140" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/preinfo/test_views.py</url>
<line>111</line>
<option name="timeStamp" value="141" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/preinfo/test_views.py</url>
<line>117</line>
<option name="timeStamp" value="142" />
</line-breakpoint>
<line-breakpoint enabled="true" type="javascript">
<url>file://$PROJECT_DIR$/static/js/container_validation.js</url>
<line>4</line>
<option name="timeStamp" value="95" />
</line-breakpoint>
</breakpoints>
<default-breakpoints>
<breakpoint type="python-exception">
<properties notifyOnTerminate="true" exception="BaseException">
<option name="notifyOnTerminate" value="true" />
</properties>
</breakpoint>
</default-breakpoints>
</breakpoint-manager>
</component>
<component name="com.intellij.coverage.CoverageDataManagerImpl">
<SUITE FILE_PATH="coverage/DepoT$Test__booking_tests_BookingViewsTestCase_test_booking_list_view__user_no_rights__expect_forbidden.coverage" NAME="Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_no_rights__expect_forbidden Coverage Results" MODIFIED="1754372596969" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
<SUITE FILE_PATH="coverage/depot_django$Test__booking_tests_BookingViewsTestCase_test_booking_update_view.coverage" NAME="Test: booking.tests.BookingViewsTestCase.test_booking_update_view Coverage Results" MODIFIED="1754420837053" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
<SUITE FILE_PATH="coverage/depot_django$Test__booking_tests_BookingViewsTestCase.coverage" NAME="Test: booking.tests.BookingViewsTestCase Coverage Results" MODIFIED="1754420864513" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
<SUITE FILE_PATH="coverage/depot_django$Test__preinfo_test_views_PreinfoViewsTest.coverage" NAME="Test: preinfo.test_views.PreinfoViewsTest Coverage Results" MODIFIED="1754425958620" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
<SUITE FILE_PATH="coverage/DepoT$Test__booking_tests_BookingViewsTestCase_test_booking_list_view.coverage" NAME="Test: booking.tests.BookingViewsTestCase.test_booking_list_view Coverage Results" MODIFIED="1754333059580" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
<SUITE FILE_PATH="coverage/DepoT$Test__booking_tests_BookingViewsTestCase.coverage" NAME="Test: booking.tests.BookingViewsTestCase Coverage Results" MODIFIED="1754386070100" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
<SUITE FILE_PATH="coverage/DepoT$Test__booking_tests_BookingViewsTestCase_test_booking_list_view__user_all_rights__expect_OK.coverage" NAME="Test: booking.tests.BookingViewsTestCase.test_booking_list_view__user_all_rights__expect_OK Coverage Results" MODIFIED="1754372722226" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
</component>
</project>
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-16
View File
@@ -1,16 +0,0 @@
"""
ASGI config for DepoT project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DepoT.settings")
application = get_asgi_application()
-15
View File
@@ -1,15 +0,0 @@
from common.models import LinesModel
class LineFilterFormMixin:
def get_form(self, form_class=None):
form = super().get_form(form_class)
user = self.request.user
if user.line:
form.fields['line'].queryset = form.fields['line'].queryset.filter(pk=user.line.pk)
form.fields['line'].initial = user.line
form.fields['line'].widget.attrs['readonly'] = True
else:
form.fields['line'].queryset = LinesModel.objects.filter(company=user.company)
form.fields['line'].widget.attrs['readonly'] = False
return form
-21
View File
@@ -1,21 +0,0 @@
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
class CRUDListViewMixin:
...
# def post(self, request, *args, **kwargs):
# if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
# object_id = request.POST.get('object_id')
# obj = get_object_or_404(self.model, id=object_id)
# return JsonResponse(self.get_object_data(obj))
# else:
# return self.handle_form_submission(request, *args, **kwargs)
# def get_object_data(self, obj):
# """Override this method in child views to specify which data to return"""
# raise NotImplementedError
#
# def handle_form_submission(self, request, *args, **kwargs):
# """Override this method in child views to handle form submission"""
# raise NotImplementedError
View File
View File
-188
View File
@@ -1,188 +0,0 @@
"""
Django settings for DepoT project.
Generated by 'django-admin startproject' using Django 5.2.3.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""
from pathlib import Path
import os
import environ
BASE_DIR = Path(__file__).resolve().parent.parent.parent
env = environ.Env()
env.read_env(os.path.join(BASE_DIR, '.env'))
SECRET_KEY = "django-insecure-g%187p84o9^rr)3#9@r3n^o2v1i%@6=+puxm7hlodg+kbsk%n#"
DEBUG = True
ALLOWED_HOSTS = ['192.168.24.43', '127.0.0.1', 'localhost', ]
PROJECT_APPS = [
'accounts',
"booking",
"common",
"containers",
'preinfo',
'payments',
]
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
"damages_api",
] + PROJECT_APPS
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "DepoT.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / 'templates']
,
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "DepoT.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
# DATABASES = {
# "default": {
# "ENGINE": "django.db.backends.sqlite3",
# "NAME": BASE_DIR / "db.sqlite3",
# }
# }
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": env("DB_NAME"),
"USER": env("DB_USER"),
"PASSWORD": env("DB_PASSWORD"),
"HOST": env("DB_HOST"),
"PORT": env("DB_PORT"),
}
}
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
AUTH_USER_MODEL = 'accounts.DepotUser'
LOGIN_URL = '/user/login/'
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
]
# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = "static/"
STATICFILES_DIRS = [
BASE_DIR / 'static'
]
TEMP_FILE_FOLDER = "/tmp/damages_photos"
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
OWNCLOUD_URL = env('OWNCLOUD_URL')
OWNCLOUD_USER = env('OWNCLOUD_USER')
OWNCLOUD_PASSWORD = env('OWNCLOUD_PASSWORD')
OWNCLOUD_DAMAGES_FOLDER = env('OWNCLOUD_DAMAGES_FOLDER')
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = env("EMAIL_HOST", cast=str, default=None)
EMAIL_PORT = env("EMAIL_PORT", cast=str, default='587') # Recommended
EMAIL_HOST_USER = env("EMAIL_HOST_USER", cast=str, default=None)
EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD", cast=str, default=None)
EMAIL_USE_TLS = env("EMAIL_USE_TLS", cast=bool, default=True) # Use EMAIL_PORT 587 for TLS
EMAIL_USE_SSL = env("EMAIL_USE_SSL", cast=bool, default=False) # EUse MAIL_PORT 465 for SSL
ADMIN_USER_NAME=env("ADMIN_USER_NAME")
ADMIN_USER_PASSWORD=env("ADMIN_USER_PASSWORD")
ADMIN_USER_EMAIL=env("ADMIN_USER_EMAIL")
MANAGERS=[]
ADMINS=[]
if all([ADMIN_USER_NAME, ADMIN_USER_EMAIL]):
ADMINS +=[
(f'{ADMIN_USER_NAME}', f'{ADMIN_USER_EMAIL}')
]
MANAGERS=ADMINS
MINIO_ENDPOINT = env('MINIO_ENDPOINT')
AWS_S3_CUSTOM_DOMAIN = env('AWS_S3_CUSTOM_DOMAIN')
MINIO_SERVER_URL = env('MINIO_SERVER_URL')
AWS_S3_URL_PROTOCOL = env('AWS_S3_URL_PROTOCOL')
MINIO_ACCESS_KEY = env('MINIO_ACCESS_KEY')
MINIO_SECRET_KEY = env('MINIO_SECRET_KEY')
MINIO_BUCKET_NAME = env('MINIO_BUCKET_NAME')
MINIO_SECURE = False # Set to True if using HTTPS
-247
View File
@@ -1,247 +0,0 @@
"""
Django settings for DepoT project.
Generated by 'django-admin startproject' using Django 5.2.3.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""
from pathlib import Path
import os
import environ
from minio_backend.storage import MinioStaticStorage, MinioMediaStorage
BASE_DIR = Path(__file__).resolve().parent.parent.parent
env = environ.Env()
env.read_env(os.path.join(BASE_DIR, 'production.env'))
SECRET_KEY = "django-insecure-g%187p84o9^rr)3#9@r3n^o2v1i%@6=+puxm7hlodg+kbsk%n#"
DEBUG = False
ALLOWED_HOSTS = ['192.168.24.43', '127.0.0.1', 'localhost', 'depot.kikimor.com', ]
CSRF_TRUSTED_ORIGINS = ['https://depot.kikimor.com']
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
USE_X_FORWARDED_HOST = True
PROJECT_APPS = [
'accounts',
"booking",
"common",
"containers",
'preinfo',
'payments',
]
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
"damages_api",
"django_minio_backend",
"minio_backend",
] + PROJECT_APPS
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "DepoT.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / 'templates']
,
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "DepoT.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
# DATABASES = {
# "default": {
# "ENGINE": "django.db.backends.sqlite3",
# "NAME": BASE_DIR / "db.sqlite3",
# }
# }
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": env("DB_NAME"),
"USER": env("DB_USER"),
"PASSWORD": env("DB_PASSWORD"),
"HOST": env("DB_HOST"),
"PORT": env("DB_PORT"),
}
}
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
AUTH_USER_MODEL = 'accounts.DepotUser'
LOGIN_URL = '/user/login/'
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
]
# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = "static/"
STATICFILES_DIRS = [
BASE_DIR / 'static'
]
STATIC_ROOT = BASE_DIR / 'staticfiles'
TEMP_FILE_FOLDER = "/tmp/damages_photos"
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
OWNCLOUD_URL = env('OWNCLOUD_URL')
OWNCLOUD_USER = env('OWNCLOUD_USER')
OWNCLOUD_PASSWORD = env('OWNCLOUD_PASSWORD')
OWNCLOUD_DAMAGES_FOLDER = env('OWNCLOUD_DAMAGES_FOLDER')
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = env("EMAIL_HOST", cast=str, default=None)
EMAIL_PORT = env("EMAIL_PORT", cast=str, default='587') # Recommended
EMAIL_HOST_USER = env("EMAIL_HOST_USER", cast=str, default=None)
EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD", cast=str, default=None)
EMAIL_USE_TLS = env("EMAIL_USE_TLS", cast=bool, default=True) # Use EMAIL_PORT 587 for TLS
EMAIL_USE_SSL = env("EMAIL_USE_SSL", cast=bool, default=False) # EUse MAIL_PORT 465 for SSL
ADMIN_USER_NAME=env("ADMIN_USER_NAME")
ADMIN_USER_PASSWORD=env("ADMIN_USER_PASSWORD")
ADMIN_USER_EMAIL=env("ADMIN_USER_EMAIL")
MANAGERS=[]
ADMINS=[]
if all([ADMIN_USER_NAME, ADMIN_USER_EMAIL]):
ADMINS +=[
(f'{ADMIN_USER_NAME}', f'{ADMIN_USER_EMAIL}')
]
MANAGERS=ADMINS
MINIO_ENDPOINT = env('MINIO_ENDPOINT')
AWS_S3_CUSTOM_DOMAIN = env('AWS_S3_CUSTOM_DOMAIN')
MINIO_SERVER_URL = env('MINIO_SERVER_URL')
MINIO_EXTERNAL_ENDPOINT = AWS_S3_CUSTOM_DOMAIN
MINIO_EXTERNAL_ENDPOINT_USE_HTTPS = True
AWS_S3_URL_PROTOCOL = env('AWS_S3_URL_PROTOCOL')
MINIO_ACCESS_KEY = env('MINIO_ACCESS_KEY')
MINIO_SECRET_KEY = env('MINIO_SECRET_KEY')
MINIO_BUCKET_NAME = env('MINIO_BUCKET_NAME')
MINIO_SECURE = False # Set to True if using HTTPS
MINIO_USE_HTTPS = False # Add this line
MINIO_STATIC_BUCKET = env('MINIO_STATIC_BUCKET_NAME')
# django-minio-backend settings
MINIO_STORAGE_ENDPOINT = AWS_S3_CUSTOM_DOMAIN
MINIO_STORAGE_PORT = 443 if MINIO_SECURE else 80 # Add this line
MINIO_STORAGE_ACCESS_KEY = env('MINIO_ACCESS_KEY')
MINIO_STORAGE_SECRET_KEY = env('MINIO_SECRET_KEY')
MINIO_STORAGE_USE_HTTPS = True
MINIO_STORAGE_MEDIA_BUCKET_NAME = env('MINIO_BUCKET_NAME') # For user-uploaded media
MINIO_STORAGE_STATIC_BUCKET_NAME = env('MINIO_STATIC_BUCKET_NAME') # For static files
MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True
MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True
MINIO_STORAGE_AUTO_CREATE_POLICY = True
MINIO_STORAGE_MEDIA_BASE_URL = f'{AWS_S3_URL_PROTOCOL}://{AWS_S3_CUSTOM_DOMAIN}/{env("MINIO_BUCKET_NAME")}/'
MINIO_STORAGE_STATIC_BASE_URL = f'{AWS_S3_URL_PROTOCOL}://{AWS_S3_CUSTOM_DOMAIN}/{env("MINIO_STATIC_BUCKET_NAME")}/'
MINIO_PRIVATE_BUCKETS = [] # If you have any private buckets
MINIO_PUBLIC_BUCKETS = [
env('MINIO_BUCKET_NAME'), # Just the bucket name as a string
env('MINIO_STATIC_BUCKET_NAME') # Just the bucket name as a string
]
MINIO_POLICY_ACTIONS = {
'GET': ['get_object'],
'PUT': ['put_object'],
'DELETE': ['delete_object'],
'LIST': ['list_multipart_uploads',
'list_parts',
'list_objects'],
}
STORAGES = {
"default": {
"BACKEND": "minio_backend.storage.MinioMediaStorage",
},
"staticfiles": {
"BACKEND": "minio_backend.storage.MinioStaticStorage",
},
}
DEFAULT_FILE_STORAGE = 'minio_backend.storage.MinioMediaStorage'
STATICFILES_STORAGE = 'minio_backend.storage.MinioStaticStorage'
STATIC_URL = f'{AWS_S3_URL_PROTOCOL}://{AWS_S3_CUSTOM_DOMAIN}/{env("MINIO_STATIC_BUCKET_NAME")}/'
STATICFILES_LOCATION = 'static'
MEDIA_ROOT = BASE_DIR / 'mediafiles'
MEDIA_URL = f'{AWS_S3_URL_PROTOCOL}://{AWS_S3_CUSTOM_DOMAIN}/{env("MINIO_BUCKET_NAME")}/'
-31
View File
@@ -1,31 +0,0 @@
"""
URL configuration for DepoT project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
# from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path('', include('common.urls')),
path('user/', include('accounts.urls')),
path('preinfo/', include('preinfo.urls')),
path('container/', include('containers.urls')),
path('booking/', include('booking.urls')),
path('payment/', include('payments.urls')),
path('api/damages/', include('damages_api.urls')),
path('api/common/', include('common_api.urls')),
]
-16
View File
@@ -1,16 +0,0 @@
"""
WSGI config for DepoT project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DepoT.settings")
application = get_wsgi_application()
-5
View File
@@ -1,5 +0,0 @@
FROM minio/mc:latest
RUN test -f init_minio_buckets.sh && echo "init_minio_buckets.sh found in build context!" || (echo "init_minio_buckets.sh NOT found in build context!" && exit 1)
COPY init_minio_buckets.sh /usr/local/bin/init_minio_buckets.sh
RUN chmod +x /usr/local/bin/init_minio_buckets.sh
ENTRYPOINT ["/usr/local/bin/init_minio_buckets.sh"]
-5
View File
@@ -1,5 +0,0 @@
FROM alpine/git
WORKDIR /build_context
COPY . .
RUN ls -la
CMD ["echo", "Build context listed."]
+2
View File
@@ -0,0 +1,2 @@
# depot_django
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-31
View File
@@ -1,31 +0,0 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import DepotUser
@admin.register(DepotUser)
class DepotUserAdmin(UserAdmin):
fieldsets = UserAdmin.fieldsets + (
('Additional Info', {'fields': (
'phone_number',
'company',
'line',
'company_permissions',
'user_type',
)}),
)
list_display = ('username', 'email', 'user_type', 'company', 'line', 'is_active', 'is_staff', 'is_superuser')
search_fields = ('username', 'email')
list_filter = ('user_type', 'is_active', 'is_staff', 'is_superuser')
add_fieldsets = UserAdmin.add_fieldsets + (
('Additional Info', {'fields': (
'email',
'phone_number',
'company',
'line',
'company_permissions',
'user_type',
)}),
)
-6
View File
@@ -1,6 +0,0 @@
from django.apps import AppConfig
class UsersConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "accounts"
-15
View File
@@ -1,15 +0,0 @@
from django.contrib.auth.backends import ModelBackend
class CompanyUserBackend(ModelBackend):
def get_user_permissions(self, user_obj, obj=None):
if not user_obj.is_active or user_obj.is_anonymous:
return set()
if user_obj.is_superuser:
return super().get_user_permissions(user_obj, obj)
perms = super().get_user_permissions(user_obj, obj)
if user_obj.company and user_obj.company.is_client:
perms = {p for p in perms if p.startswith('accounts.client_')}
return perms
-96
View File
@@ -1,96 +0,0 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.views import PasswordChangeView
from django.core.exceptions import ValidationError
from django.forms import CharField
from django.forms.models import ModelForm
from django.forms.widgets import PasswordInput
class LoginForm(AuthenticationForm):
field_order = ['username', 'password']
class Meta:
model = get_user_model()
class RegisterForm(ModelForm):
password1 = CharField(label='Password', widget=PasswordInput)
password2 = CharField(label='Confirm Password', widget=PasswordInput)
field_order = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
class Meta:
model = get_user_model()
fields = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['password1'].widget.attrs.update({'autocomplete': 'new-password'})
self.fields['password2'].widget.attrs.update({'autocomplete': 'new-password'})
self.fields['user_type'].widget.attrs['readonly'] = True
self.fields['company_permissions'].widget.attrs['disabled'] = True
self.fields['employee_permissions'].widget.attrs['disabled'] = True
if self.data.get('user_type') in ( 'EM', 'BS'):
self.fields['company_permissions'].required = False
if self.data.get('user_type') in ('CL', 'CA', 'BS'):
self.fields['company_permissions'].required = False
def clean(self):
cleaned_data = super().clean()
password1 = cleaned_data.get('password1')
password2 = cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return cleaned_data
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
class UserEditForm(ModelForm):
password1 = CharField(required=False, label='Password', widget=PasswordInput)
password2 = CharField(required=False, label='Confirm Password', widget=PasswordInput)
field_order = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
class Meta:
model = get_user_model()
fields = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['user_type'].widget.attrs['readonly'] = True
self.fields['company_permissions'].widget.attrs['disabled'] = True
self.fields['employee_permissions'].widget.attrs['disabled'] = True
if self.data.get('user_type') in ( 'EM', 'BS'):
self.fields['company_permissions'].required = False
if self.data.get('user_type') in ('CL', 'CA', 'BS'):
self.fields['company_permissions'].required = False
def clean(self):
cleaned_data = super().clean()
password1 = cleaned_data.get('password1')
password2 = cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return cleaned_data
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
class UserChangePasswordForm(PasswordChangeView):
old_password = CharField(widget=PasswordInput())
new_password = CharField(widget=PasswordInput())
confirm_password = CharField(widget=PasswordInput())
-182
View File
@@ -1,182 +0,0 @@
# Generated by Django 5.2.3 on 2025-06-27 11:42
import django.contrib.auth.models
import django.contrib.auth.validators
import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
("common", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="ClientPermission",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
],
options={
"permissions": (
("can_book_container", "Can book container"),
("can_view_bookings", "Can view bookings"),
("can_manage_company_users", "Can manage company users"),
),
"managed": True,
"default_permissions": (),
},
),
migrations.CreateModel(
name="DepotUser",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("password", models.CharField(max_length=128, verbose_name="password")),
(
"last_login",
models.DateTimeField(
blank=True, null=True, verbose_name="last login"
),
),
(
"is_superuser",
models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
(
"username",
models.CharField(
error_messages={
"unique": "A user with that username already exists."
},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[
django.contrib.auth.validators.UnicodeUsernameValidator()
],
verbose_name="username",
),
),
(
"first_name",
models.CharField(
blank=True, max_length=150, verbose_name="first name"
),
),
(
"last_name",
models.CharField(
blank=True, max_length=150, verbose_name="last name"
),
),
(
"is_staff",
models.BooleanField(
default=False,
help_text="Designates whether the user can log into this admin site.",
verbose_name="staff status",
),
),
(
"is_active",
models.BooleanField(
default=True,
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
verbose_name="active",
),
),
(
"date_joined",
models.DateTimeField(
default=django.utils.timezone.now, verbose_name="date joined"
),
),
(
"phone_number",
models.CharField(blank=True, max_length=15, null=True),
),
("email", models.EmailField(max_length=254, unique=True)),
("new_field1", models.BooleanField(default=False)),
("is_company_admin", models.BooleanField(default=False)),
(
"company",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="user_lines",
to="common.companymodel",
),
),
(
"groups",
models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.group",
verbose_name="groups",
),
),
(
"line",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="user_lines",
to="common.linesmodel",
),
),
(
"user_permissions",
models.ManyToManyField(
blank=True,
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.permission",
verbose_name="user permissions",
),
),
(
"company_permissions",
models.ManyToManyField(to="accounts.clientpermission"),
),
],
options={
"verbose_name": "user",
"verbose_name_plural": "users",
"abstract": False,
},
managers=[
("objects", django.contrib.auth.models.UserManager()),
],
),
]
@@ -1,23 +0,0 @@
# Generated by Django 5.2.3 on 2025-07-02 08:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="clientpermission",
name="codename",
field=models.CharField(default="", max_length=100),
),
migrations.AddField(
model_name="clientpermission",
name="name",
field=models.CharField(default="", max_length=255),
),
]
@@ -1,35 +0,0 @@
# Generated by Django 5.2.3 on 2025-07-02 12:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0002_clientpermission_codename_clientpermission_name"),
]
operations = [
migrations.RemoveField(
model_name="depotuser",
name="is_company_admin",
),
migrations.RemoveField(
model_name="depotuser",
name="new_field1",
),
migrations.AddField(
model_name="depotuser",
name="user_type",
field=models.CharField(
choices=[
("BS", "Barrier Staff"),
("CA", "Company Admin"),
("EM", "Employee"),
("CL", "Client"),
],
default="CL",
max_length=2,
),
),
]
@@ -1,43 +0,0 @@
# Generated by Django 5.2.3 on 2025-07-03 08:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0003_remove_depotuser_is_company_admin_and_more"),
]
operations = [
migrations.CreateModel(
name="EmployeePermission",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("codename", models.CharField(default="", max_length=100)),
("name", models.CharField(default="", max_length=255)),
],
options={
"permissions": (
("can_manage_containers", "Can manage containers"),
("can_view_reports", "Can view reports"),
("can_handle_operations", "Can handle operations"),
),
"managed": True,
"default_permissions": (),
},
),
migrations.AddField(
model_name="depotuser",
name="employee_permissions",
field=models.ManyToManyField(blank=True, to="accounts.employeepermission"),
),
]
@@ -1,32 +0,0 @@
# Generated by Django 5.2.3 on 2025-07-03 14:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0004_employeepermission_depotuser_employee_permissions"),
]
operations = [
migrations.AlterModelManagers(
name="depotuser",
managers=[],
),
migrations.AlterField(
model_name="depotuser",
name="user_type",
field=models.CharField(
choices=[
("BS", "Barrier Staff"),
("CA", "Company Admin"),
("EM", "Employee"),
("CL", "Client"),
("AD", "Admin"),
],
default="CL",
max_length=2,
),
),
]
@@ -1,29 +0,0 @@
# Generated by Django 5.2.3 on 2025-07-09 12:51
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("accounts", "0005_alter_depotuser_managers_alter_depotuser_user_type"),
]
operations = [
migrations.AlterModelOptions(
name="clientpermission",
options={
"default_permissions": (),
"managed": True,
"permissions": (
("can_view_booking", "Can view booking"),
("can_manage_booking", "Can book container"),
("can_view_preinfo", "Can view preinfo"),
("can_manage_preinfo", "Can manage preinfo"),
("can_view_payment", "Can view payment"),
("can_manage_payment", "Can manage payment"),
("can_manage_company_users", "Can manage company users"),
),
},
),
]
@@ -1,12 +0,0 @@
# Generated by Django 5.2.3 on 2025-07-25 16:20
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("accounts", "0006_alter_clientpermission_options"),
]
operations = []
@@ -1,46 +0,0 @@
from django.db import migrations
def create_permissions(apps, schema_editor):
EmployeePermission = apps.get_model('accounts', 'EmployeePermission')
ClientPermission = apps.get_model('accounts', 'ClientPermission')
employee_permissions = [
(1, 'can_manage_containers', 'Can manage containers'),
(2, 'can_view_reports', 'Can view reports'),
(3, 'can_handle_operations', 'Can handle operations'),
(4, 'can_view_payments', 'Can view payments'),
(5, 'can_manage_payments', 'Can Manage payments'),
]
for _id, codename, name in employee_permissions:
EmployeePermission.objects.create(id=_id, codename=codename, name=name)
client_permissions = [
(1, 'can_view_booking', 'Can view booking'),
(2, 'can_manage_booking', 'Can book container'),
(3, 'can_view_preinfo', 'Can view preinfo'),
(4, 'can_manage_preinfo', 'Can manage preinfo'),
(5, 'can_view_payment', 'Can view payment'),
(6, 'can_manage_payment', 'Can manage payment'),
(7, 'can_manage_company_users', 'Can manage company users'),
]
for _id, codename, name in client_permissions:
ClientPermission.objects.create(id=_id, codename=codename, name=name)
def reverse_permissions(apps, schema_editor):
EmployeePermission = apps.get_model('accounts', 'EmployeePermission')
ClientPermission = apps.get_model('accounts', 'ClientPermission')
EmployeePermission.objects.all().delete()
ClientPermission.objects.all().delete()
class Migration(migrations.Migration):
dependencies = [
('accounts', '0007_auto_20250725_1920'), # Adjust this to your last migration
]
operations = [
migrations.RunPython(create_permissions, reverse_permissions),
]
@@ -1,29 +0,0 @@
from django.db import migrations
from django.conf import settings
from django.contrib.auth.hashers import make_password
def create_superuser(apps, schema_editor):
User = apps.get_model('accounts', 'DepotUser')
if not User.objects.filter(email=settings.ADMIN_USER_EMAIL).exists():
user = User.objects.create(
email=settings.ADMIN_USER_EMAIL,
username=settings.ADMIN_USER_NAME,
is_staff=True,
is_superuser=True,
is_active=True,
user_type='AD',
password=make_password(settings.ADMIN_USER_PASSWORD)
)
def reverse_superuser(apps, schema_editor):
User = apps.get_model('accounts', 'DepotUser')
User.objects.filter(email=settings.ADMIN_USER_EMAIL).delete()
class Migration(migrations.Migration):
dependencies = [
('accounts', '0008_populate_permissions'),
]
operations = [
migrations.RunPython(create_superuser, reverse_superuser),
]
View File
-117
View File
@@ -1,117 +0,0 @@
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import AbstractUser
from django.db import models
class ClientPermission(models.Model):
codename = models.CharField(max_length=100, default='')
name = models.CharField(max_length=255, default='')
class Meta:
managed = True
default_permissions = ()
permissions = (
('can_view_booking', 'Can view booking'),
('can_manage_booking', 'Can book container'),
('can_view_preinfo', 'Can view preinfo'),
('can_manage_preinfo', 'Can manage preinfo'),
('can_view_payment', 'Can view payment'),
('can_manage_payment', 'Can manage payment'),
('can_manage_company_users', 'Can manage company users'),
)
def __str__(self):
return self.name
class EmployeePermission(models.Model):
codename = models.CharField(max_length=100, default='')
name = models.CharField(max_length=255, default='')
class Meta:
managed = True
default_permissions = ()
permissions = (
('can_manage_containers', 'Can manage containers'),
('can_view_reports', 'Can view reports'),
('can_handle_operations', 'Can handle operations'),
('can_view_payments', 'Can view payments'),
('can_manage_payments', 'Can manage payments'),
)
def __str__(self):
return self.name
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
extra_fields.setdefault('user_type', 'AD') # Set user_type to admin
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self.create_user(email, password, **extra_fields)
class DepotUser(AbstractUser):
class UserType(models.TextChoices):
BARRIER_STAFF = 'BS', 'Barrier Staff'
COMPANY_ADMIN = 'CA', 'Company Admin'
EMPLOYEE = 'EM', 'Employee'
CLIENT = 'CL', 'Client',
ADMIN = 'AD', 'Admin'
objects = CustomUserManager()
user_type = models.CharField(
max_length=2,
choices=UserType.choices,
default=UserType.CLIENT
)
phone_number = models.CharField(max_length=15, blank=True, null=True)
email = models.EmailField(unique=True, blank=False, null=False)
company = models.ForeignKey(
'common.CompanyModel',
on_delete=models.CASCADE,
related_name='user_lines',
blank=True,
null=True
)
line = models.ForeignKey(
'common.LinesModel',
on_delete=models.CASCADE,
related_name='user_lines',
blank=True,
null=True
)
company_permissions = models.ManyToManyField('ClientPermission')
employee_permissions = models.ManyToManyField('EmployeePermission', blank=True)
def has_company_perm(self, perm_codename):
if self.is_superuser:
return True
return self.company_permissions.filter(codename=perm_codename).exists()
def has_employee_perm(self, perm_codename):
if self.is_superuser:
return True
return self.employee_permissions.filter(codename=perm_codename).exists()
-11
View File
@@ -1,11 +0,0 @@
from django import template
register = template.Library()
@register.filter
def has_company_perm(user, perm_codename):
return user.has_company_perm(perm_codename)
@register.filter
def has_employee_perm(user, perm_codename):
return user.has_employee_perm(perm_codename)
-3
View File
@@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.
-19
View File
@@ -1,19 +0,0 @@
from django.contrib.auth.views import LogoutView
from django.urls import path, include
from django.contrib.auth import views as auth_views
from accounts import views
from accounts.views import CustomPasswordChangeView
urlpatterns = [
path('', include([
path('', views.UserListView.as_view(), name='user_list'),
path('register/', views.RegisterView.as_view(), name='user_register'),
path('login/', views.DepotLoginView.as_view(), name='login'),
# path('relogin/', auth_views.logout_then_login, name='relogin'),
path('relogin/', LogoutView.as_view(next_page='login'), name='relogin'),
path('change-password/', CustomPasswordChangeView.as_view(), name='change_password'),
path('<int:pk>/update/', views.UserUpdateView.as_view(), name='user_update'),
path('<int:pk>/active/', views.UserActiveView.as_view(), name='user_active'),
])),
]
-190
View File
@@ -1,190 +0,0 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.views import LoginView, PasswordChangeView
from django.http import HttpResponseForbidden, JsonResponse
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.views import View
from django.views.generic import TemplateView, FormView, ListView, UpdateView
from rest_framework.generics import get_object_or_404
from accounts.forms import LoginForm, RegisterForm, UserChangePasswordForm, UserEditForm
from accounts.models import DepotUser
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin, UserPassesTestMixin
# Create your views here.
class DepotLoginView(LoginView):
template_name = 'registration/login.html'
# success_url = reverse_lazy('dashboard')
form_class = LoginForm
next_page = reverse_lazy('dashboard')
def is_company_admin(user):
return user.is_authenticated and user.is_company_admin
class RegisterView(LoginRequiredMixin, UserPassesTestMixin, FormView):
template_name = 'registration/register.html'
form_class = RegisterForm
success_url = reverse_lazy('dashboard')
def test_func(self):
user = self.request.user
return user.is_superuser or user.user_type == DepotUser.UserType.COMPANY_ADMIN
def form_valid(self, form):
user = form.save(commit=False)
user_type = form.cleaned_data['user_type']
user.save()
if user_type == DepotUser.UserType.CLIENT:
user.employee_permissions.clear()
user.company_permissions.set(form.cleaned_data['company_permissions'])
elif user_type == DepotUser.UserType.EMPLOYEE:
user.company_permissions.clear()
user.employee_permissions.set(form.cleaned_data['employee_permissions'])
return super().form_valid(form)
def get_form(self, form_class = None):
form = super().get_form(form_class)
user: DepotUser = self.request.user
if user.is_superuser:
# Superuser can manage all permissions and user types
form.fields['user_type'].widget.attrs['disabled'] = False
form.fields['company_permissions'].widget.attrs['disabled'] = False
form.fields['employee_permissions'].widget.attrs['disabled'] = False
# Show relevant permissions based on selected user type
if form.initial.get('user_type') == DepotUser.UserType.CLIENT:
form.fields['employee_permissions'].widget.attrs['disabled'] = True
elif form.initial.get('user_type') == DepotUser.UserType.EMPLOYEE:
form.fields['company_permissions'].widget.attrs['disabled'] = True
elif user.user_type == DepotUser.UserType.COMPANY_ADMIN:
form.fields['company'].queryset = form.fields['company'].queryset.filter(pk=user.company.pk)
form.fields['company'].initial = user.company
form.fields['company'].widget.readonly = True # form.fields['line'].widget.attrs['disabled'] = True
form.fields['line'].queryset = form.fields['line'].queryset.filter(company=user.company.pk)
form.fields['user_type'].choices = [
(DepotUser.UserType.CLIENT, 'Client')
]
form.fields['user_type'].initial = DepotUser.UserType.CLIENT
form.fields['company_permissions'].widget.attrs['disabled'] = False
form.fields['employee_permissions'].widget.attrs['disabled'] = True
return form
class UserListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
template_name = 'registration/user-list.html'
model = get_user_model()
context_object_name = 'objects'
paginate_by = 20
def test_func(self):
user = self.request.user
return user.is_superuser or user.user_type == DepotUser.UserType.COMPANY_ADMIN
def get_queryset(self):
queryset = super().get_queryset()
user = self.request.user
data_filter = self.request.GET.get('filter')
if data_filter != 'all':
queryset = queryset.filter(is_active=True)
if user.is_superuser:
return queryset.all()
elif user.user_type == DepotUser.UserType.COMPANY_ADMIN:
return queryset.filter(company=user.company)
else:
return queryset.none()
class UserUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
template_name = 'registration/register.html'
form_class = UserEditForm
model = get_user_model()
success_url = reverse_lazy('user_list')
def test_func(self):
user = self.request.user
return user.is_superuser or user.user_type == DepotUser.UserType.COMPANY_ADMIN
def form_valid(self, form):
user = form.save(commit=False)
user_type = form.cleaned_data['user_type']
user.save()
# Clear irrelevant permissions based on user type
if user_type == DepotUser.UserType.CLIENT:
user.employee_permissions.clear()
user.company_permissions.set(form.cleaned_data['company_permissions'])
elif user_type == DepotUser.UserType.EMPLOYEE:
user.company_permissions.clear()
user.employee_permissions.set(form.cleaned_data['employee_permissions'])
return super().form_valid(form)
def get_form(self, form_class = None):
form = super().get_form(form_class)
user: DepotUser = self.request.user
if user.is_superuser:
# Superuser can manage all permissions and user types
form.fields['user_type'].widget.attrs['disabled'] = False
form.fields['company_permissions'].widget.attrs['disabled'] = False
form.fields['employee_permissions'].widget.attrs['disabled'] = False
# Show relevant permissions based on selected user type
if form.initial.get('user_type') == DepotUser.UserType.CLIENT:
form.fields['employee_permissions'].widget.attrs['disabled'] = True
elif form.initial.get('user_type') == DepotUser.UserType.EMPLOYEE:
form.fields['company_permissions'].widget.attrs['disabled'] = True
elif user.user_type == DepotUser.UserType.COMPANY_ADMIN:
form.fields['company'].queryset = form.fields['company'].queryset.filter(pk=user.company.pk)
form.fields['company'].initial = user.company
form.fields['company'].widget.readonly = True
form.fields['line'].queryset = form.fields['line'].queryset.filter(company=user.company.pk)
form.fields['user_type'].choices = [
(DepotUser.UserType.CLIENT, 'Client')
]
form.fields['user_type'].initial = DepotUser.UserType.CLIENT
form.fields['company_permissions'].widget.attrs['disabled'] = False
form.fields['employee_permissions'].widget.attrs['disabled'] = True
return form
class UserActiveView(LoginRequiredMixin, UserPassesTestMixin, View):
success_url = reverse_lazy('user_list')
def test_func(self):
user = self.request.user
return user.is_superuser or user.user_type == DepotUser.UserType.COMPANY_ADMIN
def post(self, request, pk, *args, **kwargs):
user = request.user
target_user = get_object_or_404(get_user_model(), pk=pk)
if target_user == user:
return HttpResponseForbidden("You cannot change your own active status.")
target_user.is_active = not target_user.is_active
target_user.save()
return JsonResponse({'success': True, 'is_active': target_user.is_active})
class CustomPasswordChangeView(LoginRequiredMixin, PasswordChangeView):
template_name = 'registration/change_password.html'
def get_success_url(self):
next_url = self.request.GET.get('next') or self.request.POST.get('next')
return next_url or reverse_lazy('dashboard')
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More